Ви не можете вибрати більше 25 тем Теми мають розпочинатися з літери або цифри, можуть містити дефіси (-) і не повинні перевищувати 35 символів.

4 роки тому
2 місяці тому
4 роки тому
5 місяці тому
4 роки тому
4 роки тому
9 місяці тому
9 місяці тому
4 роки тому
4 роки тому
5 місяці тому
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901
  1. <?php
  2. /**
  3. * Copyright Guillaume Bourgeois (2018)
  4. *
  5. * contact@souke.fr
  6. *
  7. * Ce logiciel est un programme informatique servant à aider les producteurs
  8. * à distribuer leur production en circuits courts.
  9. *
  10. * Ce logiciel est régi par la licence CeCILL soumise au droit français et
  11. * respectant les principes de diffusion des logiciels libres. Vous pouvez
  12. * utiliser, modifier et/ou redistribuer ce programme sous les conditions
  13. * de la licence CeCILL telle que diffusée par le CEA, le CNRS et l'INRIA
  14. * sur le site "http://www.cecill.info".
  15. *
  16. * En contrepartie de l'accessibilité au code source et des droits de copie,
  17. * de modification et de redistribution accordés par cette licence, il n'est
  18. * offert aux utilisateurs qu'une garantie limitée. Pour les mêmes raisons,
  19. * seule une responsabilité restreinte pèse sur l'auteur du programme, le
  20. * titulaire des droits patrimoniaux et les concédants successifs.
  21. *
  22. * A cet égard l'attention de l'utilisateur est attirée sur les risques
  23. * associés au chargement, à l'utilisation, à la modification et/ou au
  24. * développement et à la reproduction du logiciel par l'utilisateur étant
  25. * donné sa spécificité de logiciel libre, qui peut le rendre complexe à
  26. * manipuler et qui le réserve donc à des développeurs et des professionnels
  27. * avertis possédant des connaissances informatiques approfondies. Les
  28. * utilisateurs sont donc invités à charger et tester l'adéquation du
  29. * logiciel à leurs besoins dans des conditions permettant d'assurer la
  30. * sécurité de leurs systèmes et ou de leurs données et, plus généralement,
  31. * à l'utiliser et l'exploiter dans les mêmes conditions de sécurité.
  32. *
  33. * Le fait que vous puissiez accéder à cet en-tête signifie que vous avez
  34. * pris connaissance de la licence CeCILL, et que vous en avez accepté les
  35. * termes.
  36. */
  37. namespace backend\controllers;
  38. use common\helpers\Ajax;
  39. use common\helpers\CSV;
  40. use common\helpers\GlobalParam;
  41. use common\helpers\MeanPayment;
  42. use common\helpers\Price;
  43. use domain\Document\DeliveryNote\DeliveryNote;
  44. use domain\Document\Document\Document;
  45. use domain\Document\Invoice\Invoice;
  46. use domain\Document\Quotation\Quotation;
  47. use domain\Feature\Feature\Feature;
  48. use domain\Order\Order\Order;
  49. use domain\Order\OrderStatus\OrderStatus;
  50. use domain\Order\ProductOrder\ProductOrder;
  51. use domain\Payment\Payment;
  52. use kartik\mpdf\Pdf;
  53. use domain\Product\Product\Product;
  54. use yii;
  55. use yii\base\UserException;
  56. use yii\filters\AccessControl;
  57. use yii\helpers\Html;
  58. use yii\web\NotFoundHttpException;
  59. class DocumentController extends BackendController
  60. {
  61. public function behaviors()
  62. {
  63. return [
  64. 'access' => [
  65. 'class' => AccessControl::class,
  66. 'rules' => [
  67. [
  68. 'allow' => true,
  69. 'roles' => ['@'],
  70. 'matchCallback' => function ($rule, $action) {
  71. return $this->getUserModule()
  72. ->getAuthorizationChecker()
  73. ->isGrantedAsProducer($this->getUserCurrent());
  74. }
  75. ]
  76. ],
  77. ],
  78. ];
  79. }
  80. public function actionGeneratePdfValidatedDocuments()
  81. {
  82. set_time_limit(0);
  83. $validatedDocumentsArray = array_merge(
  84. Quotation::find()->where(['status' => Document::STATUS_VALID])->all(),
  85. DeliveryNote::find()->where(['status' => Document::STATUS_VALID])->all(),
  86. Invoice::find()->where(['status' => Document::STATUS_VALID])->all()
  87. );
  88. foreach ($validatedDocumentsArray as $document) {
  89. if (!file_exists($document->getFilenameComplete())) {
  90. $document->generatePdf(Pdf::DEST_FILE);
  91. }
  92. }
  93. }
  94. public function actionCreate()
  95. {
  96. $documentModule = $this->getDocumentModule();
  97. $class = $this->getClass();
  98. $class = 'domain\\Document\\'.$class.'\\'.$class;
  99. $model = new $class();
  100. $documentModule->initTaxCalculationMethod($model);
  101. if ($model->load(\Yii::$app->request->post())) {
  102. $model->id_producer = GlobalParam::getCurrentProducerId();
  103. if ($model->save()) {
  104. $this->processInvoiceViaDeliveryNotes($model);
  105. $this->processInvoiceViaOrders($model);
  106. $this->setFlash('success', $this->getFlashMessage('create', $model));
  107. return $this->redirect(['/' . $this->getControllerUrl() . '/update', 'id' => $model->id]);
  108. } else {
  109. $this->setFlash('error', 'Un problème est survenu lors de la création du document.');
  110. }
  111. }
  112. return $this->render('/document/create', [
  113. 'title' => $this->getTitle('Ajouter'),
  114. 'typeDocument' => $this->getDocumentType(),
  115. 'model' => $model,
  116. ]);
  117. }
  118. public function processInvoiceViaDeliveryNotes($model)
  119. {
  120. $orderModule = $this->getOrderModule();
  121. $documentModule = $this->getDocumentModule();
  122. $deliveryNoteModule = $this->getDeliveryNoteModule();
  123. if ($documentModule->getClass($model) == 'Invoice') {
  124. if ($model->deliveryNotes && is_array($model->deliveryNotes) && count($model->deliveryNotes)) {
  125. foreach ($model->deliveryNotes as $key => $idDeliveryNote) {
  126. $deliveryNote = $deliveryNoteModule->findOneDeliveryNoteById($idDeliveryNote);
  127. $orderModule->assignAllOrdersInvoiceByDeliveryNote($model, $deliveryNote);
  128. }
  129. }
  130. }
  131. }
  132. public function processInvoiceViaOrders($model)
  133. {
  134. $orderModule = $this->getOrderModule();
  135. $documentModule = $this->getDocumentModule();
  136. if ($documentModule->getClass($model) == 'Invoice') {
  137. if ($model->ordersOnCreate && is_array($model->ordersOnCreate) && count($model->ordersOnCreate)) {
  138. foreach ($model->ordersOnCreate as $key => $idOrder) {
  139. $order = $orderModule->findOneOrderById($idOrder);
  140. $orderModule->updateOrderInvoice($order, $model);
  141. $orderModule->getBuilder()->updateOrderInvoicePrices($order,
  142. [
  143. 'user' => $model->user,
  144. 'user_producer' => $this->getUserProducerModule()->getRepository()
  145. ->findOneUserProducer($model->user),
  146. 'point_sale' => $order->pointSale
  147. ]);
  148. }
  149. }
  150. }
  151. }
  152. public function actionUpdate($id)
  153. {
  154. $documentModule = $this->getDocumentModule();
  155. $paymentManager = $this->getPaymentModule();
  156. $document = $this->findModel($id);
  157. if (!$document) {
  158. throw new yii\web\NotFoundHttpException('Le document n\'a pas été trouvé.');
  159. }
  160. if ($document && $document->load(\Yii::$app->request->post()) && $document->save()) {
  161. $this->setFlash('success', $this->getFlashMessage('update', $document));
  162. }
  163. $payment = null;
  164. if($documentModule->isDocumentInvoice($document) && $documentModule->isStatusValid($document)) {
  165. $payment = $paymentManager->instanciatePayment(
  166. Payment::TYPE_PAYMENT,
  167. number_format($documentModule->getAmountWithTax($document, Order::INVOICE_AMOUNT_TOTAL), 2),
  168. $this->getProducerCurrent(),
  169. null,
  170. null,
  171. MeanPayment::TRANSFER,
  172. null,
  173. null,
  174. null,
  175. $document
  176. );
  177. $payment->amount = number_format($payment->amount, 2);
  178. $posts = \Yii::$app->request->post();
  179. if(isset($posts['Payment']['date_transaction']) && $posts['Payment']['date_transaction']) {
  180. $posts['Payment']['date_transaction'] = date('Y-m-d', strtotime(str_replace('/', '-', $posts['Payment']['date_transaction'])));
  181. }
  182. if ($payment->load($posts) && $payment->save()) {
  183. $this->setFlash('success', 'Le règlement a bien été ajouté.');
  184. return $this->redirect(['invoice/update', 'id' => $document->id]);
  185. }
  186. else {
  187. if($payment->date_transaction) {
  188. $payment->date_transaction = date('d/m/Y', strtotime($payment->date_transaction));
  189. }
  190. }
  191. }
  192. return $this->render('/document/update', [
  193. 'title' => $this->getTitle('Modifier'),
  194. 'typeDocument' => $this->getDocumentType(),
  195. 'model' => $document,
  196. 'payment' => $payment
  197. ]);
  198. }
  199. public function actionDelete($id)
  200. {
  201. $documentModule = $this->getDocumentModule();
  202. $model = $this->findModel($id);
  203. if ($documentModule->isStatusValid($model)) {
  204. throw new UserException('Vous ne pouvez pas supprimer un document validé.');
  205. }
  206. $documentModule->delete($model);
  207. if ($this->getClass() == 'DeliveryNote') {
  208. Order::updateAll([
  209. 'order.id_delivery_note' => null
  210. ], [
  211. 'order.id_delivery_note' => $id
  212. ]);
  213. }
  214. if ($this->getClass() == 'Quotation') {
  215. Order::updateAll([
  216. 'order.id_quotation' => null
  217. ], [
  218. 'order.id_quotation' => $id
  219. ]);
  220. }
  221. if ($this->getClass() == 'Invoice') {
  222. Order::updateAll([
  223. 'order.id_invoice' => null
  224. ], [
  225. 'order.id_invoice' => $id
  226. ]);
  227. }
  228. $this->setFlash('success', $this->getFlashMessage('delete', $model));
  229. $this->redirect([$this->getControllerUrl() . '/index']);
  230. }
  231. public function actionExportCsvEvoliz(int $id)
  232. {
  233. if(!$this->getFeatureModule()->getChecker()->isEnabled(Feature::ALIAS_BRIDGE_EVOLIZ)) {
  234. throw new yii\web\UnauthorizedHttpException("Vous n'êtes pas autorisé à effectuer cette action.");
  235. }
  236. $documentModule = $this->getDocumentModule();
  237. $productOrderModule = $this->getProductOrderModule();
  238. $datas = [];
  239. $document = $this->findModel($id);
  240. // données
  241. $datas[] = [
  242. 'N° facture externe *',
  243. 'Date facture *',
  244. 'Client',
  245. 'Code client *',
  246. 'Total TVA',
  247. 'Total HT',
  248. 'Total TTC',
  249. 'Total réglé',
  250. 'Etat',
  251. 'Date Etat',
  252. 'Date de création',
  253. 'Objet',
  254. 'Date d\'échéance',
  255. 'Date d\'exécution',
  256. 'Taux de pénalité',
  257. 'Frais de recouvrement',
  258. 'Taux d\'escompte',
  259. 'Conditions de règlement *',
  260. 'Mode de paiement',
  261. 'Remise globale',
  262. 'Acompte',
  263. 'Nombre de relance',
  264. 'Commentaires',
  265. 'N° facture',
  266. 'Annulé',
  267. 'Catalogue',
  268. 'Réf.',
  269. 'Désignation *',
  270. 'Qté *',
  271. 'Unité',
  272. 'PU HT *',
  273. 'Remise',
  274. 'TVA',
  275. 'Total TVA',
  276. 'Total HT',
  277. 'Classification vente',
  278. 'Code Classification vente',
  279. ];
  280. foreach ($documentModule->getProductsOrders($document, true) as $productOrderArray) {
  281. foreach ($productOrderArray as $productOrder) {
  282. $price = $productOrder->getPrice();
  283. if ($documentModule->isInvoicePrice($document) && $productOrder->getInvoicePrice()) {
  284. $price = $productOrder->getInvoicePrice();
  285. }
  286. $typeTotal = $documentModule->isInvoicePrice($document) ? Order::INVOICE_AMOUNT_TOTAL : Order::AMOUNT_TOTAL;
  287. $priceTotal = $productOrderModule->getPriceByTypeTotal($productOrder, $typeTotal) * $productOrder->quantity;
  288. $tva = Price::getVat(
  289. $priceTotal,
  290. $productOrder->taxRate->value,
  291. $document->tax_calculation_method
  292. );
  293. $datas[] = [
  294. $document->reference, // N° facture externe *
  295. date('d/m/Y', strtotime($document->date)), // Date facture *
  296. '', // Client
  297. $document->user->evoliz_code, // Code client *
  298. '', // Total TVA
  299. '', // Total HT
  300. '', // Total TTC
  301. '', // Total réglé
  302. '', // Etat
  303. '', // Date Etat
  304. '', // Date de création
  305. $document->name, // Objet
  306. '', // Date d'échéance
  307. '', // Date d'exécution
  308. '', // Taux de pénalité
  309. '', // Frais de recouvrement
  310. '', // Taux d\'escompte
  311. 'A réception', // Conditions de règlement *
  312. '', // Mode de paiement
  313. '', // Remise globale
  314. '', // Acompte
  315. '', // Nombre de relance
  316. '', // Commentaires
  317. '', // N° facture
  318. '', // Annulé
  319. 'Non', // Catalogue
  320. '', // Réf.
  321. $productOrder->product->name, // Désignation *
  322. $productOrder->quantity, // Qté *
  323. '', // Product::strUnit($productOrder->unit, 'wording'), // Unité
  324. $price, // PU HT *
  325. '', // Remise
  326. $productOrder->taxRate->value * 100, // TVA
  327. $tva, // Total TVA
  328. $priceTotal, // Total HT
  329. '', // Classification vente
  330. '01', // Code Classification vente
  331. ];
  332. }
  333. }
  334. // nom fichier
  335. $reference = $document->id;
  336. if ($document->reference && strlen($document->reference)) {
  337. $reference = $document->reference;
  338. }
  339. // status
  340. $status = '';
  341. if ($documentModule->isStatusDraft($document)) {
  342. $status = 'brouillon_';
  343. }
  344. CSV::downloadSendHeaders(strtolower($this->getDocumentType()) . '_' . $status . $reference . '.csv');
  345. echo CSV::array2csv($datas);
  346. die();
  347. }
  348. public function actionDownload($id)
  349. {
  350. $documentModule = $this->getDocumentModule();
  351. $document = $this->findModel($id);
  352. return $documentModule->downloadPdf($document);
  353. }
  354. public function actionRegenerate($id)
  355. {
  356. $documentModule = $this->getDocumentModule();
  357. $document = $this->findModel($id);
  358. $documentModule->downloadPdf($document, true);
  359. $this->setFlash('success', 'Le document PDF a bien été regénéré.');
  360. return $this->redirect([$this->getControllerUrl() . '/update', 'id' => $id]);
  361. }
  362. public function actionSend(int $id, $backUpdateForm = false)
  363. {
  364. $documentModule = $this->getDocumentModule();
  365. $document = $this->findModel($id);
  366. if ($documentModule->sendDocument($document)) {
  367. $this->setFlash('success', $this->getFlashMessage('send', $document));
  368. } else {
  369. $this->setFlash('danger', $this->getFlashMessage('send', $document));
  370. }
  371. if ($backUpdateForm) {
  372. return $this->redirect([$this->getControllerUrl() . '/update', 'id' => $id]);
  373. } else {
  374. return $this->redirectReferer();
  375. }
  376. }
  377. public function actionAjaxUserInfos($typeAction, $idUser, $classDocument, $idDocument = false)
  378. {
  379. $userModule = $this->getUserModule();
  380. $documentModule = $this->getDocumentModule();
  381. $orderModule = $this->getOrderModule();
  382. $producerModule = $this->getProducerModule();
  383. $invoiceModule = $this->getInvoiceModule();
  384. $deliveryNoteModule = $this->getDeliveryNoteModule();
  385. \Yii::$app->response->format = \yii\web\Response::FORMAT_JSON;
  386. if ($idUser > 0) {
  387. $user = $userModule->findOneUserById($idUser);
  388. if ($user) {
  389. $document = null;
  390. if ($documentModule->isValidClass($classDocument) && $idDocument) {
  391. $document = $this->findModel($idDocument, $classDocument);
  392. }
  393. if ($document && $document->id_user == $user->id) {
  394. $address = $document->address;
  395. } else {
  396. $address = $userModule->getFullAddress($user);
  397. }
  398. $json = [
  399. 'return' => 'success',
  400. 'address' => $address
  401. ];
  402. if ($classDocument == 'Invoice') {
  403. $deliveryNotesCreateArray = DeliveryNote::searchAll([
  404. 'id_user' => $user->id,
  405. 'status' => Document::STATUS_VALID,
  406. 'ignore_when_invoicing' => null
  407. ], [
  408. 'orderby' => 'distribution.date ASC',
  409. 'join_with' => ['user AS user_delivery_note', 'orders', 'producer']
  410. ]);
  411. $invoice = $idDocument ? $invoiceModule->getRepository()->findOneInvoiceById($idDocument) : null;
  412. $deliveryNotesUpdateArray = $invoice ? $deliveryNoteModule->getRepository()->findDeliveryNotesByInvoice($invoice) : null;
  413. $json['delivery_note_create_array'] = $this->initDeliveryNoteArray('create', $deliveryNotesCreateArray);
  414. $json['delivery_note_update_array'] = $this->initDeliveryNoteArray('update', $deliveryNotesUpdateArray);
  415. $json['orders_create_array'] = [];
  416. $json['orders_update_array'] = [];
  417. if(!$producerModule->getConfig('option_invoice_only_based_on_delivery_notes')) {
  418. $json['orders_create_array'] = $this->initOrdersArray($orderModule->findOrdersByUserNotInvoiced($user));
  419. $json['orders_update_array'] = $document ? $this->initOrdersArray($orderModule->findOrdersByUserAndInvoice($user, $document)) : [];
  420. }
  421. }
  422. if ($classDocument == 'DeliveryNote') {
  423. $json['orders_create_array'] = $this->initOrdersArray($orderModule->findOrdersByUserNotLinkedDeliveryNote($user));
  424. $json['orders_update_array'] = $document ? $this->initOrdersArray($orderModule->findOrdersByUserAndDeliveryNote($user, $document)) : [];
  425. }
  426. if ($producerModule->getSolver()->getConfig('option_document_default_naming')
  427. && $typeAction == 'create'
  428. && ($classDocument == 'Invoice' || $classDocument == 'DeliveryNote')) {
  429. $json['name'] = $documentModule->getSolver()->getDefaultName($classDocument, $user);
  430. }
  431. return $json;
  432. }
  433. }
  434. return ['return' => 'error'];
  435. }
  436. public function initOrdersArray(array $ordersArray)
  437. {
  438. $orderModule = $this->getOrderModule();
  439. $ordersReturnArray = [];
  440. foreach($ordersArray as &$order) {
  441. $orderModule->initOrder($order);
  442. $ordersReturnArray[] = [
  443. 'id' => $order->id,
  444. 'date' => $order->distribution->date,
  445. 'name' => date('d/m/Y', strtotime($order->distribution->date)),
  446. 'amount_with_tax' => $orderModule->getOrderAmountWithTax($order, Order::INVOICE_AMOUNT_TOTAL)
  447. ];
  448. }
  449. return $ordersReturnArray;
  450. }
  451. public function initDeliveryNoteArray($type, $deliveryNoteArrayResults)
  452. {
  453. $deliveryNoteArray = [];
  454. $isCreate = false;
  455. if ($type == 'create') {
  456. $isCreate = true;
  457. }
  458. if ($deliveryNoteArrayResults) {
  459. foreach ($deliveryNoteArrayResults as $deliveryNote) {
  460. $deliveryNoteData = $this->addDeliveryNoteToArray($deliveryNote, $isCreate);
  461. if ($deliveryNoteData) {
  462. $deliveryNoteArray[] = $deliveryNoteData;
  463. }
  464. }
  465. }
  466. return $deliveryNoteArray;
  467. }
  468. public function addDeliveryNoteToArray($deliveryNote, $isCreate = true)
  469. {
  470. $deliveryNoteModule = $this->getDeliveryNoteModule();
  471. $deliveryNoteData = array_merge(
  472. $deliveryNote->getAttributes(),
  473. [
  474. 'url' => $this->getUrlManagerBackend()->createUrl(['delivery-note/update', 'id' => $deliveryNote->id]),
  475. 'total' => $deliveryNoteModule->getAmountWithTax($deliveryNote, Order::INVOICE_AMOUNT_TOTAL)
  476. ]
  477. );
  478. if (($isCreate && !$deliveryNoteModule->isInvoiced($deliveryNote)) || !$isCreate) {
  479. return $deliveryNoteData;
  480. }
  481. return false;
  482. }
  483. public function actionValidate($id, $backUpdateForm = false)
  484. {
  485. $documentModule = $this->getDocumentModule();
  486. $classDocument = $this->getClass();
  487. if ($id > 0 && $documentModule->isValidClass($classDocument)) {
  488. $document = $this->findModel($id);
  489. if ($document) {
  490. $documentModule->getManager()->validateDocument($document);
  491. // @TODO : gérer via un événement
  492. $documentModule->generatePdf($document, Pdf::DEST_FILE);
  493. $this->setFlash('success', $this->getFlashMessage('validate', $document));
  494. if ($backUpdateForm) {
  495. return $this->redirect([$this->getControllerUrl() . '/update', 'id' => $id]);
  496. } else {
  497. return $this->redirect([$this->getControllerUrl() . '/index']);
  498. }
  499. }
  500. }
  501. $this->setFlash('danger', 'Une erreur est survenue lors de la validation du document.');
  502. return $this->redirect([$this->getControllerUrl() . '/index']);
  503. }
  504. public function actionAjaxInit($idDocument, $classDocument)
  505. {
  506. \Yii::$app->response->format = \yii\web\Response::FORMAT_JSON;
  507. $orderModule = $this->getOrderModule();
  508. $productModule = $this->getProductModule();
  509. $documentModule = $this->getDocumentModule();
  510. $deliveryNoteModule = $this->getDeliveryNoteModule();
  511. $userProducerModule = $this->getUserProducerModule();
  512. $pointSaleModule = $this->getPointSaleModule();
  513. if ($idDocument > 0 && $documentModule->isValidClass($classDocument)) {
  514. $document = $this->findModel($idDocument, $classDocument);
  515. if ($document) {
  516. $ordersArray = [];
  517. $productsArray = $productModule->getRepository()->findProducts(true);
  518. foreach ($document->orders as $order) {
  519. $orderModule->initOrder($order);
  520. $productsOrderArray = [];
  521. foreach ($order->productOrder as $productOrder) {
  522. $productsOrderArray[$productOrder->id] = array_merge($productOrder->getAttributes(), [
  523. 'url_product' => $this->getUrlManagerBackend()->createUrl(['product/update', 'id' => $productOrder->id_product]),
  524. 'url_order' => $this->getUrlManagerBackend()->createUrl(['distribution/index', 'idOrderUpdate' => $productOrder->id_order])
  525. ]);
  526. }
  527. $ordersArray[$order->id] = array_merge(
  528. $order->getAttributes(),
  529. [
  530. 'username' => $orderModule->getOrderUsername($order),
  531. 'distribution_date' => isset($order->distribution) ? date(
  532. 'd/m/Y',
  533. strtotime(
  534. $order->distribution->date
  535. )
  536. ) : null,
  537. 'point_sale_name' => isset($order->pointSale) ? $order->pointSale->name : null,
  538. 'productOrder' => $productsOrderArray,
  539. ]
  540. );
  541. }
  542. $userProducer = $userProducerModule->findOneUserProducer($document->user);
  543. $pointSale = $pointSaleModule->findOnePointSaleByIdUser($document->user->id);
  544. $productsArray = yii\helpers\ArrayHelper::map(
  545. $productsArray,
  546. 'order',
  547. function ($product) use ($document, $userProducer, $pointSale, $productModule) {
  548. return array_merge($product->getAttributes(), [
  549. 'unit_coefficient' => $productModule->getSolver()->getUnitCoefficient($product),
  550. 'prices' => $productModule->getPriceArray($product, $userProducer->user, $pointSale),
  551. 'wording_unit' => $product->wording_unit,
  552. 'tax_rate' => $product->taxRate->value
  553. ]);
  554. }
  555. );
  556. return [
  557. 'return' => 'success',
  558. 'tax_rate_producer' => GlobalParam::getCurrentProducer()->taxRate->value,
  559. 'document' => array_merge($document->getAttributes(), [
  560. 'html_label' => $documentModule->getHtmlLabel($document),
  561. 'class' => $documentModule->getClass($document)
  562. ]),
  563. 'id_user' => $document->user->id,
  564. 'products' => $productsArray,
  565. 'orders' => $ordersArray,
  566. 'total' => ($documentModule->getClass($document) == 'Invoice' || $documentModule->getClass($document) == 'DeliveryNote') ? $documentModule->getAmount(
  567. $document,
  568. Order::INVOICE_AMOUNT_TOTAL
  569. ) : $documentModule->getAmount($document, Order::AMOUNT_TOTAL),
  570. 'total_with_tax' => ($documentModule->getClass($document) == 'Invoice' || $documentModule->getClass($document) == 'DeliveryNote') ? $documentModule->getAmountWithTax(
  571. $document,
  572. Order::INVOICE_AMOUNT_TOTAL
  573. ) : $documentModule->getAmountWithTax($document, Order::AMOUNT_TOTAL),
  574. 'invoice_url' => ($documentModule->getClass($document) == 'DeliveryNote' && $deliveryNoteModule->getInvoice($document)) ? $this->getUrlManagerBackend()->createUrl(['invoice/update', 'id' => $deliveryNoteModule->getInvoice($document)->id]) : null
  575. ];
  576. }
  577. }
  578. return ['return' => 'error'];
  579. }
  580. public function actionAjaxAddProduct($idDocument, $classDocument, $idProduct, $quantity, $price)
  581. {
  582. $orderModule = $this->getOrderModule();
  583. $documentModule = $this->getDocumentModule();
  584. $productModule = $this->getProductModule();
  585. $userCurrent = $this->getUserCurrent();
  586. if ($documentModule->isValidClass($classDocument)) {
  587. $document = $this->findModel($idDocument, $classDocument);
  588. $classDocumentComplete = $documentModule->getClass($document, true);
  589. $product = $productModule->findOneProductById($idProduct);
  590. if ($document && $product) {
  591. if (count($document->orders) == 0) {
  592. $order = new Order;
  593. $order->id_user = $document->id_user;
  594. $order->id_point_sale = null;
  595. $order->id_distribution = null;
  596. $order->origin = Order::ORIGIN_ADMIN;
  597. $order->date = date('Y-m-d H:i:s');
  598. $fieldIdDocument = 'id_' . $classDocumentComplete::tableName();
  599. $order->$fieldIdDocument = $document->id;
  600. $order->save();
  601. $orderModule->getManager()->changeOrderStatus($order, OrderStatus::ALIAS_ORDERED, $userCurrent);
  602. } else {
  603. $order = $document->orders[0];
  604. }
  605. if ($order) {
  606. $productOrder = new ProductOrder();
  607. $productOrder->id_order = $order->id;
  608. $productOrder->id_product = $idProduct;
  609. $quantity = $quantity / Product::$unitsArray[$product->unit]['coefficient'];
  610. $productOrder->quantity = $quantity;
  611. $productOrder->price = (float)$price;
  612. $productOrder->unit = $product->unit;
  613. $productOrder->step = $product->step;
  614. $productOrder->id_tax_rate = $product->taxRate->id;
  615. $productOrder->save();
  616. return Ajax::responseSuccess('Produit ajouté');
  617. }
  618. }
  619. }
  620. return Ajax::responseError('Une erreur est survenue lors de la suppression du produit.');
  621. }
  622. public function actionAjaxDeleteProductOrder($idProductOrder)
  623. {
  624. $productOrderModule = $this->getProductOrderModule();
  625. $productOrder = $productOrderModule->findOneProductOrderById($idProductOrder);
  626. if ($productOrder) {
  627. $productOrderModule->delete($productOrder);
  628. return Ajax::responseSuccess('Produit supprimé');
  629. }
  630. return Ajax::responseError('Une erreur est survenue lors de la suppression du produit.');
  631. }
  632. public function actionAjaxAddOrder($idDocument, $classDocument, $idOrder)
  633. {
  634. $documentModule = $this->getDocumentModule();
  635. $orderModule = $this->getOrderModule();
  636. $document = $documentModule->findOneDocumentByIdAndClass($idDocument, $classDocument);
  637. $order = $orderModule->findOneOrderById($idOrder);
  638. if ($document && $documentModule->isStatusDraft($document) && $order) {
  639. $orderModule->updateOrderDocument($order, $document);
  640. return Ajax::responseSuccess("Commande ajoutée à la facture.");
  641. }
  642. else {
  643. return Ajax::responseError("Une erreur est survenue lors de l'ajout de la commande.");
  644. }
  645. }
  646. public function actionAjaxDeleteOrder($idDocument, $classDocument, $idOrder)
  647. {
  648. $documentModule = $this->getDocumentModule();
  649. $orderModule = $this->getOrderModule();
  650. $document = $documentModule->findOneDocumentByIdAndClass($idDocument, $classDocument);
  651. $order = $orderModule->findOneOrderById($idOrder);
  652. if ($document && $documentModule->isStatusDraft($document)) {
  653. if($documentModule->isDocumentDeliveryNote($document)) {
  654. $orderModule->updateOrderDeliveryNote($order, null);
  655. }
  656. elseif($documentModule->isDocumentInvoice($document)) {
  657. $orderModule->updateOrderInvoice($order, null);
  658. }
  659. return Ajax::responseSuccess('Commande supprimée de la facture.');
  660. }
  661. else {
  662. return Ajax::responseError('Une erreur est survenue lors de la suppression de la commande.');
  663. }
  664. }
  665. public function actionAjaxIgnoreOrderWhenInvoicing($idDocument, $classDocument, $idOrder)
  666. {
  667. $documentModule = $this->getDocumentModule();
  668. $orderModule = $this->getOrderModule();
  669. $document = $documentModule->findOneDocumentByIdAndClass($idDocument, $classDocument);
  670. $order = $orderModule->findOneOrderById($idOrder);
  671. if ($document && $documentModule->isStatusDraft($document) && $order) {
  672. $orderModule->updateOrderIgnoreWhenInvoicing($order, true);
  673. return Ajax::responseSuccess("La commande sera maintenant ignorée au moment de la facturation.");
  674. }
  675. else {
  676. return Ajax::responseError("Une erreur est survenue.");
  677. }
  678. }
  679. public function actionAjaxUpdateProductOrderInvoicePrice($idProductOrder, $invoicePrice)
  680. {
  681. $productOrderModule = $this->getProductOrderModule();
  682. $productOrder = $productOrderModule->getRepository()->findOneProductOrderById((int) $idProductOrder);
  683. if($productOrder) {
  684. $productOrderModule->getBuilder()->updateProductOrderInvoicePriceByValue($productOrder, (float) $invoicePrice);
  685. return Ajax::responseSuccess("Prix mis à jour", [
  686. 'invoice_price' => $productOrder->invoice_price
  687. ]);
  688. }
  689. return Ajax::responseError("Une erreur est survenue.");
  690. }
  691. public function getClass()
  692. {
  693. $class = get_class($this);
  694. $class = str_replace('Controller', '', $class);
  695. $class = str_replace('backend\controllers\\', '', $class);
  696. return $class;
  697. }
  698. public function getDocumentType()
  699. {
  700. $class = $this->getClass();
  701. if ($class == 'Invoice') {
  702. $documentType = 'Facture';
  703. } elseif ($class == 'DeliveryNote') {
  704. $documentType = 'Bon de livraison';
  705. } elseif ($class == 'Quotation') {
  706. $documentType = 'Devis';
  707. }
  708. if (isset($documentType)) {
  709. return $documentType;
  710. }
  711. return '';
  712. }
  713. public function getFlashMessage(string $type, $model)
  714. {
  715. $class = $this->getClass();
  716. $message = $this->getDocumentType();
  717. $message .= ' <strong>' . Html::encode($model->name) . '</strong> ';
  718. if ($type == 'create') {
  719. $message .= 'ajouté';
  720. } elseif ($type == 'update') {
  721. $message .= 'modifié';
  722. } elseif ($type == 'delete') {
  723. $message .= 'supprimé';
  724. } elseif ($type == 'validate') {
  725. $message .= 'validé';
  726. } elseif ($type == 'send') {
  727. $message .= 'envoyé';
  728. }
  729. if ($class == 'Invoice') {
  730. $message .= 'e';
  731. }
  732. return $message;
  733. }
  734. protected function getTitle($prepend)
  735. {
  736. $class = $this->getClass();
  737. switch ($class) {
  738. case 'Invoice' :
  739. $title = $prepend . ' une facture';
  740. break;
  741. case 'DeliveryNote' :
  742. $title = $prepend . ' un bon de livraison';
  743. break;
  744. case 'Quotation' :
  745. $title = $prepend . ' un devis';
  746. break;
  747. }
  748. return $title;
  749. }
  750. public function getControllerUrl()
  751. {
  752. $path = strtolower($this->getClass());
  753. $path = str_replace('deliverynote', 'delivery-note', $path);
  754. return $path;
  755. }
  756. /**
  757. * Recherche un Document en fonction de son ID.
  758. *
  759. * @param integer $id
  760. * @return Document
  761. * @throws NotFoundHttpException si le modèle n'est pas trouvé
  762. */
  763. protected function findModel($idDocument, $classDocument = null)
  764. {
  765. $documentModule = $this->getDocumentModule();
  766. $model = $documentModule->findOneDocumentByIdAndClass($idDocument, $classDocument ?? $this->getClass());
  767. if ($model) {
  768. return $model;
  769. } else {
  770. throw new NotFoundHttpException('The requested page does not exist.');
  771. }
  772. }
  773. }