You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

1697 lines
74KB

  1. <?php
  2. /**
  3. * Copyright distrib (2018)
  4. *
  5. * contact@opendistrib.net
  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 backend\controllers\BackendController;
  39. use common\helpers\GlobalParam;
  40. use common\models\DeliveryNote;
  41. use common\models\Distribution;
  42. use common\models\Document;
  43. use common\models\PointSale;
  44. use common\models\Product;
  45. use common\models\Producer;
  46. use common\models\Order;
  47. use common\models\ProductCategory;
  48. use common\models\User;
  49. use common\models\Subscription;
  50. use common\helpers\Price;
  51. use common\models\PointSaleDistribution;
  52. use common\models\UserProducer;
  53. use DateTime;
  54. class DistributionController extends BackendController
  55. {
  56. public function behaviors()
  57. {
  58. return [
  59. 'access' => [
  60. 'class' => AccessControl::className(),
  61. 'rules' => [
  62. [
  63. 'actions' => ['report-cron', 'report-terredepains'],
  64. 'allow' => true,
  65. 'roles' => ['?']
  66. ],
  67. [
  68. 'allow' => true,
  69. 'roles' => ['@'],
  70. 'matchCallback' => function ($rule, $action) {
  71. return User::getCurrentStatus() == USER::STATUS_ADMIN
  72. || User::getCurrentStatus() == USER::STATUS_PRODUCER;
  73. }
  74. ]
  75. ],
  76. ],
  77. ];
  78. }
  79. public function actionIndex($date = '', $idOrderUpdate = 0)
  80. {
  81. $this->checkProductsPointsSale();
  82. $format = 'Y-m-d';
  83. $theDate = '';
  84. $dateObject = DateTime::createFromFormat($format, $date);
  85. if ($dateObject && $dateObject->format($format) === $date) {
  86. $theDate = $date;
  87. }
  88. $orderUpdate = null;
  89. if($idOrderUpdate) {
  90. $orderUpdate = Order::searchOne(['id' => $idOrderUpdate]);
  91. }
  92. return $this->render('index', [
  93. 'date' => $theDate,
  94. 'orderUpdate' => $orderUpdate
  95. ]);
  96. }
  97. public function actionAjaxInfos($date = '')
  98. {
  99. \Yii::$app->response->format = \yii\web\Response::FORMAT_JSON;
  100. $json = [
  101. 'distribution' => [],
  102. 'products' => []
  103. ];
  104. $format = 'Y-m-d';
  105. $dateObject = DateTime::createFromFormat($format, $date);
  106. $producer = GlobalParam::getCurrentProducer();
  107. $json['producer'] = [
  108. 'credit' => $producer->credit,
  109. 'tiller' => $producer->tiller,
  110. 'option_display_export_grid' => $producer->option_display_export_grid
  111. ];
  112. $json['means_payment'] = MeanPayment::getAll();
  113. $distributionsArray = Distribution::searchAll([
  114. 'active' => 1
  115. ], [
  116. 'conditions' => [
  117. 'date > :date_begin',
  118. 'date < :date_end'
  119. ],
  120. 'params' => [
  121. ':date_begin' => date(
  122. 'Y-m-d',
  123. strtotime('-1 month')
  124. ),
  125. ':date_end' => date(
  126. 'Y-m-d',
  127. strtotime('+3 month')
  128. ),
  129. ],
  130. ]);
  131. $json['distributions'] = $distributionsArray;
  132. if ($dateObject && $dateObject->format($format) === $date) {
  133. // distribution
  134. $distribution = Distribution::initDistribution($date);
  135. $json['distribution'] = [
  136. 'id' => $distribution->id,
  137. 'active' => $distribution->active,
  138. 'url_report' => Yii::$app->urlManagerBackend->createUrl(
  139. ['distribution/report', 'date' => $distribution->date]
  140. ),
  141. 'url_report_grid' => Yii::$app->urlManagerBackend->createUrl(
  142. ['distribution/report-grid', 'date' => $distribution->date]
  143. ),
  144. ];
  145. // commandes
  146. $ordersArray = Order::searchAll([
  147. 'distribution.id' => $distribution->id,
  148. ], [
  149. 'orderby' => 'user.lastname ASC, user.name ASC'
  150. ]);
  151. // montant et poids des commandes
  152. $revenues = 0;
  153. $weight = 0;
  154. if ($ordersArray) {
  155. foreach ($ordersArray as $order) {
  156. if (is_null($order->date_delete)) {
  157. $revenues += $order->getAmountWithTax();
  158. $weight += $order->weight;
  159. }
  160. }
  161. }
  162. $json['distribution']['revenues'] = Price::format($revenues);
  163. $json['distribution']['weight'] = number_format($weight, 2);
  164. // products
  165. $productsQuery = Product::find()
  166. ->orWhere(['id_producer' => GlobalParam::getCurrentProducerId(),])
  167. ->joinWith([
  168. 'taxRate',
  169. 'productDistribution' => function ($query) use ($distribution) {
  170. $query->andOnCondition(
  171. 'product_distribution.id_distribution = ' . $distribution->id
  172. );
  173. }
  174. ])
  175. ->orderBy('product_distribution.active DESC, order ASC');
  176. $productsArray = $productsQuery->asArray()->all();
  177. $potentialRevenues = 0;
  178. $potentialWeight = 0;
  179. foreach ($productsArray as &$theProduct) {
  180. $quantityOrder = Order::getProductQuantity($theProduct['id'], $ordersArray);
  181. $theProduct['quantity_ordered'] = $quantityOrder;
  182. if (!isset($theProduct['productDistribution'][0])) {
  183. $theProductObject = (object)$theProduct;
  184. $theProduct['productDistribution'][0] = $distribution->linkProduct($theProductObject);
  185. }
  186. if (!is_numeric($theProduct['productDistribution'][0]['quantity_max'])) {
  187. $theProduct['quantity_remaining'] = null;
  188. } else {
  189. $theProduct['quantity_remaining'] = $theProduct['productDistribution'][0]['quantity_max'] - $quantityOrder;
  190. }
  191. $theProduct['quantity_form'] = 0;
  192. if ($theProduct['productDistribution'][0]['active'] && $theProduct['productDistribution'][0]['quantity_max']) {
  193. $potentialRevenues += $theProduct['productDistribution'][0]['quantity_max'] * $theProduct['price'];
  194. $potentialWeight += $theProduct['productDistribution'][0]['quantity_max'] * $theProduct['weight'] / 1000;
  195. }
  196. if (!isset($theProduct['taxRate'])) {
  197. $theProduct['taxRate'] = $producer->taxRate;
  198. }
  199. }
  200. $json['distribution']['potential_revenues'] = Price::format($potentialRevenues);
  201. $json['distribution']['potential_weight'] = number_format($potentialWeight, 2);
  202. $json['products'] = $productsArray;
  203. // orders as array
  204. $ordersArrayObject = $ordersArray;
  205. if ($ordersArray) {
  206. foreach ($ordersArray as &$order) {
  207. $productOrderArray = [];
  208. foreach ($order->productOrder as $productOrder) {
  209. $productOrderArray[$productOrder->id_product] = [
  210. 'quantity' => $productOrder->quantity * Product::$unitsArray[$productOrder->unit]['coefficient'],
  211. 'unit' => $productOrder->unit,
  212. 'price' => number_format($productOrder->price, 3),
  213. 'price_with_tax' => Price::getPriceWithTax($productOrder->price, $productOrder->taxRate->value),
  214. ];
  215. }
  216. foreach ($productsArray as $product) {
  217. if (!isset($productOrderArray[$product['id']])) {
  218. $productOrderArray[$product['id']] = [
  219. 'quantity' => 0,
  220. 'unit' => $product['unit'],
  221. 'price' => number_format($product['price'], 3),
  222. 'price_with_tax' => Price::getPriceWithTax($product['price'], $product['taxRate']['value']),
  223. ];
  224. }
  225. }
  226. $creditHistoryArray = [];
  227. foreach ($order->creditHistory as $creditHistory) {
  228. $creditHistoryArray[] = [
  229. 'date' => date('d/m/Y H:i:s', strtotime($creditHistory->date)),
  230. 'user' => $creditHistory->user->getUsername(),
  231. 'user_action' => $creditHistory->strUserAction(),
  232. 'wording' => $creditHistory->getStrWording(),
  233. 'debit' => ($creditHistory->isTypeDebit() ? '-&nbsp;' . $creditHistory->getAmount(
  234. Order::AMOUNT_TOTAL,
  235. true
  236. ) : ''),
  237. 'credit' => ($creditHistory->isTypeCredit() ? '+&nbsp;' . $creditHistory->getAmount(
  238. Order::AMOUNT_TOTAL,
  239. true
  240. ) : '')
  241. ];
  242. }
  243. $arrayCreditUser = [];
  244. if (isset($order->user) && isset($order->user->userProducer) && isset($order->user->userProducer[0])) {
  245. $arrayCreditUser['credit'] = $order->user->userProducer[0]->credit;
  246. }
  247. $oneProductUnactivated = false;
  248. foreach ($order->productOrder as $productOrder) {
  249. foreach ($productsArray as $product) {
  250. if ($productOrder->id_product == $product['id'] && !$product['productDistribution'][0]['active']) {
  251. $oneProductUnactivated = true;
  252. }
  253. }
  254. }
  255. $order = array_merge($order->getAttributes(), [
  256. 'selected' => false,
  257. 'weight' => $order->weight,
  258. 'amount' => Price::numberTwoDecimals($order->getAmountWithTax(Order::AMOUNT_TOTAL)),
  259. 'amount_paid' => Price::numberTwoDecimals($order->getAmount(Order::AMOUNT_PAID)),
  260. 'amount_remaining' => Price::numberTwoDecimals($order->getAmount(Order::AMOUNT_REMAINING)),
  261. 'amount_surplus' => Price::numberTwoDecimals($order->getAmount(Order::AMOUNT_SURPLUS)),
  262. 'user' => (isset($order->user)) ? array_merge(
  263. $order->user->getAttributes(),
  264. $arrayCreditUser
  265. ) : null,
  266. 'pointSale' => $order->pointSale ? ['id' => $order->pointSale->id, 'name' => $order->pointSale->name] : null,
  267. 'productOrder' => $productOrderArray,
  268. 'creditHistory' => $creditHistoryArray,
  269. 'oneProductUnactivated' => $oneProductUnactivated
  270. ]);
  271. }
  272. }
  273. $json['orders'] = $ordersArray;
  274. // points de vente
  275. $pointsSaleArray = PointSale::find()
  276. ->joinWith([
  277. 'pointSaleDistribution' => function ($q) use ($distribution) {
  278. $q->where(['id_distribution' => $distribution->id]);
  279. }
  280. ])
  281. ->where([
  282. 'id_producer' => GlobalParam::getCurrentProducerId(),
  283. ])
  284. ->asArray()
  285. ->all();
  286. $idPointSaleDefault = 0;
  287. foreach ($pointsSaleArray as $pointSale) {
  288. if ($pointSale['default']) {
  289. $idPointSaleDefault = $pointSale['id'];
  290. }
  291. }
  292. $json['points_sale'] = $pointsSaleArray;
  293. // bons de livraison
  294. $deliveryNotesArray = DeliveryNote::searchAll([
  295. 'distribution.date' => $date,
  296. ]);
  297. $deliveryNotesByPointSaleArray = [];
  298. foreach ($deliveryNotesArray as $deliveryNote) {
  299. if (isset($deliveryNote->orders[0])) {
  300. $deliveryNotesByPointSaleArray[$deliveryNote->orders[0]->id_point_sale] =
  301. $deliveryNote->getAttributes();
  302. }
  303. }
  304. $json['delivery_notes'] = $deliveryNotesByPointSaleArray;
  305. // order create
  306. $productOrderArray = [];
  307. foreach ($productsArray as $product) {
  308. $productOrderArray[$product['id']] = [
  309. 'quantity' => 0,
  310. 'unit' => $product['unit'],
  311. 'price' => Price::getPriceWithTax($product['price'], $product['taxRate']['value']),
  312. ];
  313. }
  314. $json['order_create'] = [
  315. 'id_point_sale' => $idPointSaleDefault,
  316. 'id_user' => 0,
  317. 'username' => '',
  318. 'comment' => '',
  319. 'productOrder' => $productOrderArray
  320. ];
  321. // utilisateurs
  322. $usersArray = User::findBy()->all();
  323. $json['users'] = $usersArray;
  324. // une production de la semaine activée ou non
  325. $oneDistributionWeekActive = false;
  326. $week = sprintf('%02d', date('W', strtotime($date)));
  327. $start = strtotime(date('Y', strtotime($date)) . 'W' . $week);
  328. $dateMonday = date('Y-m-d', strtotime('Monday', $start));
  329. $dateTuesday = date('Y-m-d', strtotime('Tuesday', $start));
  330. $dateWednesday = date('Y-m-d', strtotime('Wednesday', $start));
  331. $dateThursday = date('Y-m-d', strtotime('Thursday', $start));
  332. $dateFriday = date('Y-m-d', strtotime('Friday', $start));
  333. $dateSaturday = date('Y-m-d', strtotime('Saturday', $start));
  334. $dateSunday = date('Y-m-d', strtotime('Sunday', $start));
  335. $weekDistribution = Distribution::find()
  336. ->andWhere([
  337. 'id_producer' => GlobalParam::getCurrentProducerId(),
  338. 'active' => 1,
  339. ])
  340. ->andWhere([
  341. 'or',
  342. ['date' => $dateMonday],
  343. ['date' => $dateTuesday],
  344. ['date' => $dateWednesday],
  345. ['date' => $dateThursday],
  346. ['date' => $dateFriday],
  347. ['date' => $dateSaturday],
  348. ['date' => $dateSunday],
  349. ])
  350. ->one();
  351. if ($weekDistribution) {
  352. $oneDistributionWeekActive = true;
  353. }
  354. $json['one_distribution_week_active'] = $oneDistributionWeekActive;
  355. // tiller
  356. if ($producer->tiller) {
  357. $tiller = new Tiller();
  358. $json['tiller_is_synchro'] = (int)$tiller->isSynchro($date);
  359. }
  360. // abonnements manquants
  361. $arraySubscriptions = Subscription::searchByDate($date);
  362. $json['missing_subscriptions'] = [];
  363. if ($distribution->active) {
  364. foreach ($arraySubscriptions as $subscription) {
  365. if (!$subscription->hasOrderAlreadyExist($ordersArrayObject)
  366. && $subscription->productSubscription && count($subscription->productSubscription)
  367. && $subscription->id_point_sale && $subscription->id_point_sale > 0) {
  368. $json['missing_subscriptions'][] = [
  369. 'username' => $subscription->getUsername()
  370. ];
  371. }
  372. }
  373. }
  374. }
  375. return $json;
  376. }
  377. public function actionAjaxPointSaleFavorite($idUser)
  378. {
  379. \Yii::$app->response->format = \yii\web\Response::FORMAT_JSON;
  380. $user = User::findOne(['id' => $idUser]);
  381. $favoritePointSale = $user->getFavoritePointSale();
  382. $idFavoritePointSale = 0;
  383. if ($favoritePointSale) {
  384. $idFavoritePointSale = $favoritePointSale->id;
  385. }
  386. return [
  387. 'id_favorite_point_sale' => $idFavoritePointSale
  388. ];
  389. }
  390. public function actionAjaxUpdateProductOrder(
  391. $idDistribution,
  392. $idUser = false,
  393. $idPointSale = false,
  394. $idOrder = false
  395. ) {
  396. \Yii::$app->response->format = \yii\web\Response::FORMAT_JSON;
  397. $distribution = Distribution::findOne($idDistribution);
  398. $user = User::findOne($idUser);
  399. $pointSale = PointSale::findOne($idPointSale);
  400. $productsArray = Product::find()
  401. ->where([
  402. 'id_producer' => GlobalParam::getCurrentProducerId(),
  403. ])->joinWith([
  404. 'productPrice',
  405. 'productDistribution' => function ($q) use ($distribution) {
  406. $q->where(['id_distribution' => $distribution->id]);
  407. }
  408. ])->all();
  409. $productOrderArray = [];
  410. foreach ($productsArray as $product) {
  411. $priceArray = $product->getPriceArray($user, $pointSale);
  412. $productOrderArray[$product['id']] = [
  413. 'quantity' => 0,
  414. 'unit' => $product->unit,
  415. 'unit_coefficient' => Product::$unitsArray[$product->unit]['coefficient'],
  416. 'prices' => $priceArray,
  417. 'active' => $product->productDistribution[0]->active
  418. && (!$pointSale || $product->isAvailableOnPointSale($pointSale))
  419. ];
  420. }
  421. return $productOrderArray;
  422. }
  423. /**
  424. * Génére un PDF récapitulatif des des commandes d'un producteur pour une
  425. * date donnée (Méthode appelable via CRON)
  426. *
  427. * @param string $date
  428. * @param boolean $save
  429. * @param integer $idProducer
  430. * @param string $key
  431. * @return PDF|null
  432. */
  433. public function actionReportCron($date = '', $save = false, $idProducer = 0, $key = '')
  434. {
  435. if ($key == '64ac0bdab7e9f5e48c4d991ec5201d57') {
  436. $this->actionReport($date, $save, $idProducer);
  437. }
  438. }
  439. /**
  440. * Génére un PDF récapitulatif des commandes d'un producteur pour une
  441. * date donnée.
  442. *
  443. * @param string $date
  444. * @param boolean $save
  445. * @param integer $idProducer
  446. * @return PDF|null
  447. */
  448. public function actionReport($date = '', $save = false, $idProducer = 0, $type = "pdf")
  449. {
  450. if (!Yii::$app->user->isGuest) {
  451. $idProducer = GlobalParam::getCurrentProducerId();
  452. }
  453. $ordersArray = Order::searchAll(
  454. [
  455. 'distribution.date' => $date,
  456. 'distribution.id_producer' => $idProducer
  457. ],
  458. [
  459. 'orderby' => 'user.lastname ASC, user.name ASC, comment_point_sale ASC',
  460. 'conditions' => 'date_delete IS NULL'
  461. ]
  462. );
  463. $distribution = Distribution::searchOne([
  464. 'id_producer' => $idProducer
  465. ], [
  466. 'conditions' => 'date LIKE :date',
  467. 'params' => [':date' => $date]
  468. ]);
  469. if ($distribution) {
  470. $selectedProductsArray = ProductDistribution::searchByDistribution($distribution->id);
  471. $pointsSaleArray = PointSale::searchAll([
  472. 'point_sale.id_producer' => $idProducer
  473. ]);
  474. foreach ($pointsSaleArray as $pointSale) {
  475. $pointSale->initOrders($ordersArray);
  476. }
  477. // produits
  478. $productsArray = Product::find()
  479. ->joinWith([
  480. 'productDistribution' => function ($q) use ($distribution) {
  481. $q->where(['id_distribution' => $distribution->id]);
  482. }
  483. ])
  484. ->where([
  485. 'id_producer' => $idProducer,
  486. ])
  487. ->orderBy('order ASC')
  488. ->all();
  489. if ($type == 'pdf') {
  490. $viewPdf = 'report';
  491. $orientationPdf = Pdf::ORIENT_PORTRAIT;
  492. $producer = GlobalParam::getCurrentProducer();
  493. if ($producer->slug == 'bourlinguepacotille') {
  494. $viewPdf = 'report-bourlingue';
  495. $orientationPdf = Pdf::ORIENT_LANDSCAPE;
  496. }
  497. // get your HTML raw content without any layouts or scripts
  498. $content = $this->renderPartial($viewPdf, [
  499. 'date' => $date,
  500. 'distribution' => $distribution,
  501. 'selectedProductsArray' => $selectedProductsArray,
  502. 'pointsSaleArray' => $pointsSaleArray,
  503. 'productsArray' => $productsArray,
  504. 'ordersArray' => $ordersArray,
  505. 'producer' => Producer::searchOne(['id' => $idProducer])
  506. ]);
  507. $dateStr = date('d/m/Y', strtotime($date));
  508. if ($save) {
  509. $destination = Pdf::DEST_FILE;
  510. } else {
  511. $destination = Pdf::DEST_BROWSER;
  512. }
  513. $pdf = new Pdf([
  514. // set to use core fonts only
  515. 'mode' => Pdf::MODE_UTF8,
  516. // A4 paper format
  517. 'format' => Pdf::FORMAT_A4,
  518. // portrait orientation
  519. 'orientation' => $orientationPdf,
  520. // stream to browser inline
  521. 'destination' => $destination,
  522. 'filename' => Yii::getAlias(
  523. '@app/web/pdf/Commandes-' . $date . '-' . $idProducer . '.pdf'
  524. ),
  525. // your html content input
  526. 'content' => $content,
  527. // format content from your own css file if needed or use the
  528. // enhanced bootstrap css built by Krajee for mPDF formatting
  529. //'cssFile' => Yii::getAlias('@web/css/distribution/report.css'),
  530. // any css to be embedded if required
  531. 'cssInline' => '
  532. table {
  533. border-spacing : 0px ;
  534. border-collapse : collapse ;
  535. width: 100% ;
  536. }
  537. table tr th,
  538. table tr td {
  539. padding: 0px ;
  540. margin: 0px ;
  541. border: solid 1px #e0e0e0 ;
  542. padding: 3px 8px ;
  543. vertical-align : top;
  544. page-break-inside: avoid !important;
  545. color: black;
  546. }
  547. table tr th {
  548. font-size: 13px ;
  549. }
  550. table tr td {
  551. font-size: 13px ;
  552. }
  553. ',
  554. // set mPDF properties on the fly
  555. //'options' => ['title' => 'Krajee Report Title'],
  556. // call mPDF methods on the fly
  557. 'methods' => [
  558. 'SetHeader' => ['Commandes du ' . $dateStr],
  559. 'SetFooter' => ['{PAGENO}'],
  560. ]
  561. ]);
  562. // return the pdf output as per the destination setting
  563. return $pdf->render();
  564. } elseif ($type == 'csv') {
  565. $datas = [];
  566. $optionCsvExportAllProducts = Producer::getConfig('option_csv_export_all_products');
  567. $optionCsvExportByPiece = Producer::getConfig('option_csv_export_by_piece');
  568. // produits en colonne
  569. $productsNameArray = ['', 'Commentaire'];
  570. $productsIndexArray = [];
  571. $productsHasQuantity = [];
  572. $cpt = 2;
  573. foreach ($productsArray as $product) {
  574. $productsHasQuantity[$product->id] = 0;
  575. foreach (Product::$unitsArray as $unit => $dataUnit) {
  576. $quantity = Order::getProductQuantity($product->id, $ordersArray, true, $unit);
  577. if ($quantity) {
  578. $productsHasQuantity[$product->id] += $quantity;
  579. }
  580. }
  581. if ($productsHasQuantity[$product->id] > 0 || $optionCsvExportAllProducts) {
  582. $productName = $product->getNameExport();
  583. if ($optionCsvExportByPiece) {
  584. $productUnit = 'piece';
  585. } else {
  586. $productUnit = $product->unit;
  587. }
  588. $productName .= ' (' . Product::strUnit($productUnit, 'wording_short', true) . ')';
  589. $productsNameArray[] = $productName;
  590. $productsIndexArray[$product->id] = $cpt++;
  591. }
  592. }
  593. $datas[] = $productsNameArray;
  594. // points de vente
  595. foreach ($pointsSaleArray as $pointSale) {
  596. if (count($pointSale->orders)) {
  597. // listing commandes
  598. $datas[] = ['> ' . $pointSale->name];
  599. foreach ($pointSale->orders as $order) {
  600. $orderLine = [$order->getStrUser(), $order->getCommentReport()];
  601. if ($optionCsvExportByPiece) {
  602. foreach ($order->productOrder as $productOrder) {
  603. $orderLine[$productsIndexArray[$productOrder->id_product]] = Order::getProductQuantityPieces(
  604. $productOrder->id_product,
  605. [$order]
  606. );
  607. }
  608. } else {
  609. foreach ($productsIndexArray as $idProduct => $indexProduct) {
  610. $orderLine[$indexProduct] = '';
  611. }
  612. foreach ($order->productOrder as $productOrder) {
  613. if (strlen($orderLine[$productsIndexArray[$productOrder->id_product]])) {
  614. $orderLine[$productsIndexArray[$productOrder->id_product]] .= ' + ';
  615. }
  616. $orderLine[$productsIndexArray[$productOrder->id_product]] .= $productOrder->quantity;
  617. if ($productOrder->product->unit != $productOrder->unit) {
  618. $orderLine[$productsIndexArray[$productOrder->id_product]] .= Product::strUnit(
  619. $productOrder->unit,
  620. 'wording_short',
  621. true
  622. );
  623. }
  624. }
  625. }
  626. $datas[] = $this->_lineOrderReportCSV($orderLine, $cpt);
  627. }
  628. // total point de vente
  629. if ($optionCsvExportByPiece) {
  630. $totalsPointSaleArray = $this->_totalReportPiecesCSV(
  631. 'Total',
  632. $pointSale->orders,
  633. $productsArray,
  634. $productsIndexArray
  635. );
  636. } else {
  637. $totalsPointSaleArray = $this->_totalReportCSV(
  638. 'Total',
  639. $pointSale->orders,
  640. $productsArray,
  641. $productsIndexArray
  642. );
  643. }
  644. $datas[] = $this->_lineOrderReportCSV($totalsPointSaleArray, $cpt);
  645. $datas[] = [];
  646. }
  647. }
  648. // global
  649. if ($optionCsvExportByPiece) {
  650. $totalsGlobalArray = $this->_totalReportPiecesCSV(
  651. '> Totaux',
  652. $ordersArray,
  653. $productsArray,
  654. $productsIndexArray
  655. );
  656. } else {
  657. $totalsGlobalArray = $this->_totalReportCSV(
  658. '> Totaux',
  659. $ordersArray,
  660. $productsArray,
  661. $productsIndexArray
  662. );
  663. }
  664. $datas[] = $this->_lineOrderReportCSV($totalsGlobalArray, $cpt);
  665. CSV::downloadSendHeaders('Commandes_' . $date . '.csv');
  666. echo CSV::array2csv($datas);
  667. die();
  668. }
  669. }
  670. return null;
  671. }
  672. public function actionReportGrid($date = '', $save = false, $idProducer = 0, $type = "pdf")
  673. {
  674. if (!Yii::$app->user->isGuest) {
  675. $idProducer = GlobalParam::getCurrentProducerId();
  676. }
  677. $distribution = Distribution::searchOne([
  678. 'id_producer' => $idProducer
  679. ], [
  680. 'conditions' => 'date LIKE :date',
  681. 'params' => [':date' => $date]
  682. ]);
  683. if ($distribution) {
  684. $ordersArray = Order::searchAll(
  685. [
  686. 'distribution.date' => $date,
  687. 'distribution.id_producer' => $idProducer
  688. ],
  689. [
  690. 'orderby' => 'user.lastname ASC, user.name ASC, comment_point_sale ASC',
  691. 'conditions' => 'date_delete IS NULL'
  692. ]
  693. );
  694. $selectedProductsArray = ProductDistribution::searchByDistribution($distribution->id);
  695. $pointsSaleArray = PointSale::searchAll([
  696. 'point_sale.id_producer' => $idProducer
  697. ]);
  698. foreach ($pointsSaleArray as $pointSale) {
  699. $pointSale->initOrders($ordersArray);
  700. }
  701. $ordersByPage = 22;
  702. $nbPages = ceil(count($ordersArray) / $ordersByPage);
  703. $ordersArrayPaged = [];
  704. foreach ($pointsSaleArray as $pointSale) {
  705. $index = 0;
  706. $indexPage = 0;
  707. foreach ($pointSale->orders as $order) {
  708. if (!isset($ordersArrayPaged[$pointSale->id])) {
  709. $ordersArrayPaged[$pointSale->id] = [];
  710. }
  711. if (!isset($ordersArrayPaged[$pointSale->id][$indexPage])) {
  712. $ordersArrayPaged[$pointSale->id][$indexPage] = [];
  713. }
  714. $ordersArrayPaged[$pointSale->id][$indexPage][] = $order;
  715. $index++;
  716. if ($index == $ordersByPage) {
  717. $index = 0;
  718. $indexPage++;
  719. }
  720. }
  721. }
  722. // catégories
  723. $categoriesArray = ProductCategory::searchAll(
  724. ['id_producer' => $idProducer],
  725. ['orderby' => 'product_category.position ASC']
  726. );
  727. array_unshift($categoriesArray, null);
  728. // produits
  729. $productsArray = Product::find()
  730. ->joinWith([
  731. 'productDistribution' => function ($q) use ($distribution) {
  732. $q->where(['id_distribution' => $distribution->id]);
  733. }
  734. ])
  735. ->where([
  736. 'id_producer' => $idProducer,
  737. ])
  738. ->orderBy('order ASC')
  739. ->all();
  740. $viewPdf = 'report-grid';
  741. $orientationPdf = Pdf::ORIENT_PORTRAIT;
  742. $producer = GlobalParam::getCurrentProducer();
  743. if ($producer->slug == 'bourlinguepacotille') {
  744. $viewPdf = 'report-bourlingue';
  745. $orientationPdf = Pdf::ORIENT_LANDSCAPE;
  746. }
  747. // get your HTML raw content without any layouts or scripts
  748. $content = $this->renderPartial($viewPdf, [
  749. 'date' => $date,
  750. 'distribution' => $distribution,
  751. 'selectedProductsArray' => $selectedProductsArray,
  752. 'pointsSaleArray' => $pointsSaleArray,
  753. 'categoriesArray' => $categoriesArray,
  754. 'productsArray' => $productsArray,
  755. 'ordersArray' => $ordersArrayPaged,
  756. 'producer' => Producer::searchOne(['id' => $idProducer])
  757. ]);
  758. $dateStr = date('d/m/Y', strtotime($date));
  759. if ($save) {
  760. $destination = Pdf::DEST_FILE;
  761. } else {
  762. $destination = Pdf::DEST_BROWSER;
  763. }
  764. $pdf = new Pdf([
  765. // set to use core fonts only
  766. 'mode' => Pdf::MODE_UTF8,
  767. // A4 paper format
  768. 'format' => Pdf::FORMAT_A4,
  769. // portrait orientation
  770. 'orientation' => $orientationPdf,
  771. // stream to browser inline
  772. 'destination' => $destination,
  773. 'filename' => Yii::getAlias(
  774. '@app/web/pdf/Commandes-' . $date . '-' . $idProducer . '.pdf'
  775. ),
  776. // your html content input
  777. 'content' => $content,
  778. // format content from your own css file if needed or use the
  779. // enhanced bootstrap css built by Krajee for mPDF formatting
  780. //'cssFile' => Yii::getAlias('@web/css/distribution/report.css'),
  781. // any css to be embedded if required
  782. 'cssInline' => '
  783. table {
  784. border-spacing : 0px ;
  785. border-collapse : collapse ;
  786. width: 100% ;
  787. }
  788. table tr th,
  789. table tr td {
  790. padding: 0px ;
  791. margin: 0px ;
  792. border: solid 1px #e0e0e0 ;
  793. padding: 3px ;
  794. vertical-align : top;
  795. page-break-inside: avoid !important;
  796. }
  797. table tr th {
  798. font-size: 10px ;
  799. }
  800. table tr td {
  801. font-size: 10px ;
  802. }
  803. table thead tr {
  804. line-height: 220px;
  805. text-align:left;
  806. }
  807. .th-user,
  808. .td-nb-products {
  809. /* width: 35px ; */
  810. text-align: center ;
  811. }
  812. .th-user {
  813. padding: 10px ;
  814. }
  815. .category-name {
  816. font-weight: bold ;
  817. }
  818. ',
  819. // set mPDF properties on the fly
  820. //'options' => ['title' => 'Krajee Report Title'],
  821. // call mPDF methods on the fly
  822. 'methods' => [
  823. 'SetHeader' => ['Commandes du ' . $dateStr],
  824. 'SetFooter' => ['{PAGENO}'],
  825. ]
  826. ]);
  827. // return the pdf output as per the destination setting
  828. return $pdf->render();
  829. }
  830. }
  831. /**
  832. * Génère un export des commandes au format CSV à destination du Google Drive
  833. * de Terre de pains.
  834. *
  835. * @param type $date
  836. * @return CSV
  837. */
  838. public function actionReportTerredepains($date, $key)
  839. {
  840. if ($key == 'ef572cc148c001f0180c4a624189ed30') {
  841. $producer = Producer::searchOne([
  842. 'producer.slug' => 'terredepains'
  843. ]);
  844. $idProducer = $producer->id;
  845. $ordersArray = Order::searchAll(
  846. [
  847. 'distribution.date' => $date,
  848. 'distribution.id_producer' => $idProducer
  849. ],
  850. [
  851. 'orderby' => 'user.lastname ASC, user.name ASC, comment_point_sale ASC',
  852. 'conditions' => 'date_delete IS NULL'
  853. ]
  854. );
  855. $distribution = Distribution::searchOne([
  856. 'distribution.id_producer' => $idProducer
  857. ], [
  858. 'conditions' => 'date LIKE :date',
  859. 'params' => [
  860. ':date' => $date,
  861. ]
  862. ]);
  863. if ($distribution) {
  864. $selectedProductsArray = ProductDistribution::searchByDistribution($distribution->id);
  865. $pointsSaleArray = PointSale::searchAll([
  866. 'point_sale.id_producer' => $idProducer
  867. ]);
  868. foreach ($pointsSaleArray as $pointSale) {
  869. $pointSale->initOrders($ordersArray);
  870. }
  871. // produits
  872. $productsArray = Product::find()
  873. ->joinWith([
  874. 'productDistribution' => function ($q) use ($distribution) {
  875. $q->where(['id_distribution' => $distribution->id]);
  876. }
  877. ])
  878. ->where([
  879. 'id_producer' => $idProducer,
  880. ])
  881. ->orderBy('order ASC')
  882. ->all();
  883. $datas = [];
  884. // produits en colonne
  885. $productsNameArray = [''];
  886. $productsIndexArray = [];
  887. $productsHasQuantity = [];
  888. $cpt = 1;
  889. foreach ($productsArray as $product) {
  890. $theUnit = Product::strUnit($product->unit, 'wording_short', true);
  891. $theUnit = ($theUnit == 'p.') ? '' : ' (' . $theUnit . ')';
  892. $productsNameArray[] = $product->name . $theUnit;
  893. $productsIndexArray[$product->id] = $cpt++;
  894. }
  895. $productsNameArray[] = 'Total';
  896. $datas[] = $productsNameArray;
  897. // global
  898. $totalsGlobalArray = $this->_totalReportCSV(
  899. '> Totaux',
  900. $ordersArray,
  901. $productsArray,
  902. $productsIndexArray
  903. );
  904. $datas[] = $this->_lineOrderReportCSV($totalsGlobalArray, $cpt - 1, true);
  905. $datas[] = [];
  906. // points de vente
  907. foreach ($pointsSaleArray as $pointSale) {
  908. if (count($pointSale->orders)) {
  909. // listing commandes
  910. /*foreach ($pointSale->orders as $order) {
  911. $orderLine = [$order->getStrUser()];
  912. foreach ($productsIndexArray as $idProduct => $indexProduct) {
  913. $orderLine[$indexProduct] = '';
  914. }
  915. foreach ($order->productOrder as $productOrder) {
  916. if (strlen($orderLine[$productsIndexArray[$productOrder->id_product]])) {
  917. $orderLine[$productsIndexArray[$productOrder->id_product]] .= ' + ';
  918. }
  919. $orderLine[$productsIndexArray[$productOrder->id_product]] .= $productOrder->quantity;
  920. if ($productOrder->product->unit != $productOrder->unit) {
  921. $orderLine[$productsIndexArray[$productOrder->id_product]] .= Product::strUnit($productOrder->unit, 'wording_short', true);
  922. }
  923. }
  924. $datas[] = $this->_lineOrderReportCSV($orderLine, $cpt - 1, true);
  925. }*/
  926. // total point de vente
  927. $totalsPointSaleArray = $this->_totalReportCSV(
  928. '> ' . $pointSale->name,
  929. $pointSale->orders,
  930. $productsArray,
  931. $productsIndexArray
  932. );
  933. $datas[] = $this->_lineOrderReportCSV($totalsPointSaleArray, $cpt - 1, true);
  934. }
  935. }
  936. CSV::downloadSendHeaders('Commandes_' . $date . '.csv');
  937. echo CSV::array2csv($datas);
  938. die();
  939. }
  940. return null;
  941. }
  942. }
  943. public function _totalReportCSV($label, $ordersArray, $productsArray, $productsIndexArray)
  944. {
  945. $totalsPointSaleArray = [$label];
  946. foreach ($productsArray as $product) {
  947. foreach (Product::$unitsArray as $unit => $dataUnit) {
  948. $quantity = Order::getProductQuantity($product->id, $ordersArray, false, $unit);
  949. if ($quantity) {
  950. $index = $productsIndexArray[$product->id];
  951. if (!isset($totalsPointSaleArray[$index])) {
  952. $totalsPointSaleArray[$index] = '';
  953. }
  954. if (strlen($totalsPointSaleArray[$index])) {
  955. $totalsPointSaleArray[$index] .= ' + ';
  956. }
  957. $totalsPointSaleArray[$index] .= $quantity;
  958. if ($product->unit != $unit) {
  959. $totalsPointSaleArray[$index] .= '' . Product::strUnit($unit, 'wording_short', true);
  960. }
  961. }
  962. }
  963. }
  964. return $totalsPointSaleArray;
  965. }
  966. public function _totalReportPiecesCSV($label, $ordersArray, $productsArray, $productsIndexArray)
  967. {
  968. $totalsPointSaleArray = [$label];
  969. foreach ($productsArray as $product) {
  970. $quantity = 0;
  971. foreach (Product::$unitsArray as $unit => $dataUnit) {
  972. $quantityProduct = Order::getProductQuantity($product->id, $ordersArray, false, $unit);
  973. if ($unit == 'piece') {
  974. $quantity += $quantityProduct;
  975. } else {
  976. if ($product->weight > 0) {
  977. $quantity += ($quantityProduct * $dataUnit['coefficient']) / $product->weight;
  978. }
  979. }
  980. }
  981. if ($quantity) {
  982. $index = $productsIndexArray[$product->id];
  983. $totalsPointSaleArray[$index] = $quantity;
  984. }
  985. }
  986. return $totalsPointSaleArray;
  987. }
  988. public function _lineOrderReportCSV($orderLine, $cptMax, $showTotal = false)
  989. {
  990. $line = [];
  991. $cptTotal = 0;
  992. for ($i = 0; $i <= $cptMax; $i++) {
  993. if (isset($orderLine[$i]) && $orderLine[$i]) {
  994. $line[] = $orderLine[$i];
  995. if (is_numeric($orderLine[$i])) {
  996. $cptTotal += $orderLine[$i];
  997. }
  998. } else {
  999. $line[] = '';
  1000. }
  1001. }
  1002. if ($cptTotal > 0 && $showTotal) {
  1003. $line[] = $cptTotal;
  1004. }
  1005. return $line;
  1006. }
  1007. public function actionAjaxProcessProductQuantityMax($idDistribution, $idProduct, $quantityMax)
  1008. {
  1009. \Yii::$app->response->format = \yii\web\Response::FORMAT_JSON;
  1010. $productDistribution = ProductDistribution::searchOne([
  1011. 'id_distribution' => $idDistribution,
  1012. 'id_product' => $idProduct,
  1013. ]);
  1014. $productDistribution->quantity_max = (!$quantityMax) ? null : (float)$quantityMax;
  1015. $productDistribution->save();
  1016. return ['success'];
  1017. }
  1018. public function actionAjaxProcessActiveProduct($idDistribution, $idProduct, $active)
  1019. {
  1020. \Yii::$app->response->format = \yii\web\Response::FORMAT_JSON;
  1021. $productDistribution = ProductDistribution::searchOne([
  1022. 'id_distribution' => $idDistribution,
  1023. 'id_product' => $idProduct,
  1024. ]);
  1025. $productDistribution->active = $active;
  1026. $productDistribution->save();
  1027. return ['success'];
  1028. }
  1029. public function actionAjaxProcessActivePointSale($idDistribution, $idPointSale, $delivery)
  1030. {
  1031. \Yii::$app->response->format = \yii\web\Response::FORMAT_JSON;
  1032. $pointSaleDistribution = PointSaleDistribution::searchOne([
  1033. 'id_distribution' => $idDistribution,
  1034. 'id_point_sale' => $idPointSale,
  1035. ]);
  1036. $pointSaleDistribution->delivery = $delivery;
  1037. $pointSaleDistribution->save();
  1038. return ['success'];
  1039. }
  1040. /**
  1041. * Active/désactive un jour de distribution.
  1042. *
  1043. * @param integer $idDistribution
  1044. * @param string $date
  1045. * @param boolean $active
  1046. * @return array
  1047. */
  1048. public function actionAjaxProcessActiveDistribution($idDistribution = 0, $date = '', $active)
  1049. {
  1050. \Yii::$app->response->format = \yii\web\Response::FORMAT_JSON;
  1051. if ($idDistribution) {
  1052. $distribution = Distribution::searchOne([
  1053. 'id' => $idDistribution
  1054. ]);
  1055. }
  1056. $format = 'Y-m-d';
  1057. $dateObject = DateTime::createFromFormat($format, $date);
  1058. if ($dateObject && $dateObject->format($format) === $date) {
  1059. $distribution = Distribution::initDistribution($date);
  1060. }
  1061. if ($distribution) {
  1062. $distribution->active($active);
  1063. return ['success'];
  1064. }
  1065. return ['error'];
  1066. }
  1067. /**
  1068. * Change l'état d'une semaine de production (activé, désactivé).
  1069. *
  1070. * @param string $date
  1071. * @param integer $active
  1072. */
  1073. public function actionAjaxProcessActiveWeekDistribution($date, $active)
  1074. {
  1075. \Yii::$app->response->format = \yii\web\Response::FORMAT_JSON;
  1076. $week = sprintf('%02d', date('W', strtotime($date)));
  1077. $start = strtotime(date('Y', strtotime($date)) . 'W' . $week);
  1078. $dateMonday = date('Y-m-d', strtotime('Monday', $start));
  1079. $dateTuesday = date('Y-m-d', strtotime('Tuesday', $start));
  1080. $dateWednesday = date('Y-m-d', strtotime('Wednesday', $start));
  1081. $dateThursday = date('Y-m-d', strtotime('Thursday', $start));
  1082. $dateFriday = date('Y-m-d', strtotime('Friday', $start));
  1083. $dateSaturday = date('Y-m-d', strtotime('Saturday', $start));
  1084. $dateSunday = date('Y-m-d', strtotime('Sunday', $start));
  1085. $pointsSaleArray = PointSale::searchAll();
  1086. $activeMonday = false;
  1087. $activeTuesday = false;
  1088. $activeWednesday = false;
  1089. $activeThursday = false;
  1090. $activeFriday = false;
  1091. $activeSaturday = false;
  1092. $activeSunday = false;
  1093. foreach ($pointsSaleArray as $pointSale) {
  1094. if ($pointSale->delivery_monday) {
  1095. $activeMonday = true;
  1096. }
  1097. if ($pointSale->delivery_tuesday) {
  1098. $activeTuesday = true;
  1099. }
  1100. if ($pointSale->delivery_wednesday) {
  1101. $activeWednesday = true;
  1102. }
  1103. if ($pointSale->delivery_thursday) {
  1104. $activeThursday = true;
  1105. }
  1106. if ($pointSale->delivery_friday) {
  1107. $activeFriday = true;
  1108. }
  1109. if ($pointSale->delivery_saturday) {
  1110. $activeSaturday = true;
  1111. }
  1112. if ($pointSale->delivery_sunday) {
  1113. $activeSunday = true;
  1114. }
  1115. }
  1116. if ($activeMonday || !$active) {
  1117. $this->actionAjaxProcessActiveDistribution(0, $dateMonday, $active);
  1118. }
  1119. if ($activeTuesday || !$active) {
  1120. $this->actionAjaxProcessActiveDistribution(0, $dateTuesday, $active);
  1121. }
  1122. if ($activeWednesday || !$active) {
  1123. $this->actionAjaxProcessActiveDistribution(0, $dateWednesday, $active);
  1124. }
  1125. if ($activeThursday || !$active) {
  1126. $this->actionAjaxProcessActiveDistribution(0, $dateThursday, $active);
  1127. }
  1128. if ($activeFriday || !$active) {
  1129. $this->actionAjaxProcessActiveDistribution(0, $dateFriday, $active);
  1130. }
  1131. if ($activeSaturday || !$active) {
  1132. $this->actionAjaxProcessActiveDistribution(0, $dateSaturday, $active);
  1133. }
  1134. if ($activeSunday || !$active) {
  1135. $this->actionAjaxProcessActiveDistribution(0, $dateSunday, $active);
  1136. }
  1137. return ['success'];
  1138. }
  1139. /**
  1140. * Ajoute les commandes récurrentes pour une date donnée.
  1141. *
  1142. * @param string $date
  1143. */
  1144. public function actionAjaxProcessAddSubscriptions($date)
  1145. {
  1146. \Yii::$app->response->format = \yii\web\Response::FORMAT_JSON;
  1147. Subscription::addAll($date, true);
  1148. return ['success'];
  1149. }
  1150. /**
  1151. * Synchronise les commandes avec la plateforme Tiller pour une date donnée.
  1152. *
  1153. * @param string $date
  1154. */
  1155. public function actionAjaxProcessSynchroTiller($date)
  1156. {
  1157. \Yii::$app->response->format = \yii\web\Response::FORMAT_JSON;
  1158. $return = [];
  1159. $producerTiller = Producer::getConfig('tiller');
  1160. if ($producerTiller) {
  1161. $tiller = new Tiller();
  1162. $isSynchro = $tiller->isSynchro($date);
  1163. if (!$isSynchro) {
  1164. $orders = Order::searchAll([
  1165. 'distribution.date' => $date,
  1166. 'order.tiller_synchronization' => 1
  1167. ], [
  1168. 'conditions' => 'date_delete IS NULL'
  1169. ]);
  1170. $strDate = date('Y-m-d\T12:i:s+0000', strtotime($date) + 1);
  1171. if ($orders && count($orders)) {
  1172. foreach ($orders as $order) {
  1173. $lines = [];
  1174. foreach ($order->productOrder as $productOrder) {
  1175. $lines[] = [
  1176. 'name' => $productOrder->product->name,
  1177. 'price' => $productOrder->getPriceWithTax() * 100 * $productOrder->quantity,
  1178. 'tax' => $productOrder->taxRate->value * 100,
  1179. 'date' => $strDate,
  1180. 'quantity' => $productOrder->quantity
  1181. ];
  1182. }
  1183. $typePaymentTiller = '';
  1184. if ($order->mean_payment == MeanPayment::MONEY) {
  1185. $typePaymentTiller = 'CASH';
  1186. }
  1187. if ($order->mean_payment == MeanPayment::CREDIT_CARD
  1188. || $order->mean_payment == MeanPayment::CREDIT
  1189. || $order->mean_payment == MeanPayment::TRANSFER
  1190. || $order->mean_payment == MeanPayment::OTHER) {
  1191. $typePaymentTiller = 'CARD';
  1192. }
  1193. if ($order->mean_payment == MeanPayment::CHEQUE) {
  1194. $typePaymentTiller = 'BANK_CHECK';
  1195. }
  1196. if (!strlen($typePaymentTiller) || !$order->mean_payment) {
  1197. $typePaymentTiller = 'CASH';
  1198. }
  1199. $returnTiller = $tiller->postOrder([
  1200. 'externalId' => $order->id,
  1201. 'type' => 1,
  1202. 'status' => 'IN_PROGRESS',
  1203. 'openDate' => $strDate,
  1204. 'closeDate' => $strDate,
  1205. 'lines' => $lines,
  1206. 'payments' => [
  1207. [
  1208. 'type' => $typePaymentTiller,
  1209. 'amount' => $order->getAmountWithTax(
  1210. Order::AMOUNT_TOTAL
  1211. ) * 100,
  1212. 'status' => 'ACCEPTED',
  1213. 'date' => $strDate
  1214. ]
  1215. ]
  1216. ]);
  1217. $returnTillerObject = json_decode($returnTiller);
  1218. $order->tiller_external_id = '' . $returnTillerObject->id;
  1219. $order->save();
  1220. $return[] = $returnTiller;
  1221. }
  1222. }
  1223. }
  1224. }
  1225. return $return;
  1226. }
  1227. public function actionAjaxValidateDeliveryNotes($idOrders)
  1228. {
  1229. \Yii::$app->response->format = \yii\web\Response::FORMAT_JSON;
  1230. if (strlen($idOrders)) {
  1231. $idOrders = json_decode($idOrders, true);
  1232. if (is_array($idOrders) && count($idOrders) > 0) {
  1233. foreach ($idOrders as $idOrder) {
  1234. $order = Order::searchOne([
  1235. 'id' => (int)$idOrder
  1236. ]);
  1237. if ($order && $order->distribution->id_producer == GlobalParam::getCurrentProducerId()) {
  1238. $deliveryNote = DeliveryNote::searchOne([
  1239. 'id' => (int)$order->id_delivery_note
  1240. ]);
  1241. if ($deliveryNote && $deliveryNote->isStatusDraft()) {
  1242. $deliveryNote->changeStatus(Document::STATUS_VALID);
  1243. $deliveryNote->save();
  1244. }
  1245. }
  1246. }
  1247. return [
  1248. 'return' => 'success',
  1249. 'alert' => [
  1250. 'type' => 'success',
  1251. 'message' => 'Bon(s) de livraison validé(s)'
  1252. ]
  1253. ];
  1254. }
  1255. }
  1256. return [
  1257. 'return' => 'error',
  1258. 'alert' => [
  1259. 'type' => 'danger',
  1260. 'message' => 'Une erreur est survenue lors de la validation des bons de livraison'
  1261. ]
  1262. ];
  1263. }
  1264. public function actionAjaxGenerateDeliveryNoteEachUser($idOrders)
  1265. {
  1266. \Yii::$app->response->format = \yii\web\Response::FORMAT_JSON;
  1267. if (strlen($idOrders)) {
  1268. $idOrders = json_decode($idOrders, true);
  1269. if (is_array($idOrders) && count($idOrders) > 0) {
  1270. foreach ($idOrders as $idOrder) {
  1271. $order = Order::searchOne([
  1272. 'id' => (int)$idOrder
  1273. ]);
  1274. if ($order && $order->distribution->id_producer == GlobalParam::getCurrentProducerId(
  1275. ) && $order->id_user) {
  1276. $deliveryNote = null;
  1277. $idDeliveryNote = $order->id_delivery_note;
  1278. if ($idDeliveryNote) {
  1279. $deliveryNote = DeliveryNote::searchOne([
  1280. 'id' => (int)$idDeliveryNote
  1281. ]);
  1282. }
  1283. // on regénére le document si c'est un brouillon
  1284. if ($deliveryNote && $deliveryNote->isStatusDraft()) {
  1285. $deliveryNote->delete();
  1286. $deliveryNote = null;
  1287. }
  1288. if (!$deliveryNote) {
  1289. $deliveryNote = new DeliveryNote();
  1290. $deliveryNote->initTaxCalculationMethod();
  1291. $deliveryNote->id_producer = GlobalParam::getCurrentProducerId();
  1292. $deliveryNote->id_user = $order->id_user;
  1293. $deliveryNote->name = 'Bon de livraison ' . $order->getUsername() . ' (' . date(
  1294. 'd/m/Y',
  1295. strtotime(
  1296. $order->distribution->date
  1297. )
  1298. ) . ')';
  1299. $deliveryNote->address = $order->user->getFullAddress();
  1300. $deliveryNote->save();
  1301. }
  1302. if ($deliveryNote) {
  1303. $order->id_delivery_note = $deliveryNote->id;
  1304. $order->save();
  1305. // init invoice prices
  1306. $user = User::searchOne([
  1307. 'id' => $deliveryNote->id_user
  1308. ]);
  1309. $userProducer = UserProducer::searchOne([
  1310. 'id_user' => $deliveryNote->id_user,
  1311. 'id_producer' => GlobalParam::getCurrentProducerId()
  1312. ]);
  1313. $order->initInvoicePrices([
  1314. 'user' => $user,
  1315. 'user_producer' => $userProducer,
  1316. 'point_sale' => $order->pointSale
  1317. ]);
  1318. }
  1319. }
  1320. }
  1321. }
  1322. return [
  1323. 'return' => 'success',
  1324. 'alert' => [
  1325. 'type' => 'success',
  1326. 'message' => 'Bon(s) de livraison généré(s)'
  1327. ]
  1328. ];
  1329. }
  1330. return [
  1331. 'return' => 'error',
  1332. 'alert' => [
  1333. 'type' => 'danger',
  1334. 'message' => 'Une erreur est survenue lors de la génération du bon de livraison.'
  1335. ]
  1336. ];
  1337. }
  1338. public function actionAjaxGenerateDeliveryNote($idOrders)
  1339. {
  1340. \Yii::$app->response->format = \yii\web\Response::FORMAT_JSON;
  1341. if (strlen($idOrders)) {
  1342. $idOrders = json_decode($idOrders, true);
  1343. if (is_array($idOrders) && count($idOrders) > 0) {
  1344. // récupération première commande pour obtenir des infos
  1345. reset($idOrders);
  1346. $firstOrder = Order::searchOne([
  1347. 'id' => (int)$idOrders[key($idOrders)]
  1348. ]);
  1349. // deliveryNote existant
  1350. $deliveryNote = null;
  1351. $isUpdate = false;
  1352. $i = 0;
  1353. $ordersArray = Order::searchAll([
  1354. 'id' => $idOrders,
  1355. ]);
  1356. do {
  1357. $order = $ordersArray[$i];
  1358. if ($order->distribution->id_producer == GlobalParam::getCurrentProducerId(
  1359. ) && $order->id_delivery_note > 0) {
  1360. $deliveryNote = DeliveryNote::searchOne([
  1361. 'id' => $order->id_delivery_note
  1362. ]);
  1363. $isUpdate = true;
  1364. }
  1365. $i++;
  1366. } while ($deliveryNote == null && isset($ordersArray[$i]));
  1367. if ($deliveryNote && $deliveryNote->status == Document::STATUS_VALID) {
  1368. return [
  1369. 'return' => 'error',
  1370. 'alert' => [
  1371. 'type' => 'danger',
  1372. 'message' => 'Vous ne pouvez pas modifier un bon de livraison déjà validé.'
  1373. ]
  1374. ];
  1375. }
  1376. if ($firstOrder) {
  1377. // génération du BL
  1378. if (!$deliveryNote) {
  1379. $deliveryNote = new DeliveryNote;
  1380. $deliveryNote->initTaxCalculationMethod();
  1381. $deliveryNote->name = 'Bon de livraison ' . $firstOrder->pointSale->name . ' (' . date(
  1382. 'd/m/Y',
  1383. strtotime(
  1384. $firstOrder->distribution->date
  1385. )
  1386. ) . ')';
  1387. $deliveryNote->id_producer = GlobalParam::getCurrentProducerId();
  1388. if ($firstOrder->pointSale->id_user) {
  1389. $deliveryNote->id_user = $firstOrder->pointSale->id_user;
  1390. $user = User::searchOne([
  1391. 'id' => $deliveryNote->id_user
  1392. ]);
  1393. $userProducer = UserProducer::searchOne([
  1394. 'id_user' => $deliveryNote->id_user,
  1395. 'id_producer' => GlobalParam::getCurrentProducerId(
  1396. )
  1397. ]);
  1398. } else {
  1399. $user = new User;
  1400. $user->type = User::TYPE_LEGAL_PERSON;
  1401. $user->name_legal_person = $firstOrder->pointSale->name;
  1402. $user->address = $firstOrder->pointSale->address;
  1403. $user->id_producer = 0;
  1404. $user->setPassword(Password::generate());
  1405. $user->generateAuthKey();
  1406. $user->email = '';
  1407. if (!strlen($user->email)) {
  1408. $user->username = 'inconnu@opendistrib.net';
  1409. }
  1410. $user->save();
  1411. $userProducer = new UserProducer;
  1412. $userProducer->id_user = $user->id;
  1413. $userProducer->id_producer = GlobalParam::getCurrentProducerId();
  1414. $userProducer->credit = 0;
  1415. $userProducer->active = 1;
  1416. $userProducer->save();
  1417. $firstOrder->pointSale->id_user = $user->id;
  1418. $firstOrder->pointSale->save();
  1419. $deliveryNote->id_user = $user->id;
  1420. }
  1421. $deliveryNote->address = $user->getFullAddress();
  1422. $deliveryNote->save();
  1423. } else {
  1424. // réinitialisation des order.id_delivery_note
  1425. Order::updateAll([
  1426. 'id_delivery_note' => null
  1427. ], [
  1428. 'id_delivery_note' => $deliveryNote->id
  1429. ]);
  1430. }
  1431. if (!isset($user) || !$user) {
  1432. $user = User::searchOne([
  1433. 'id' => $deliveryNote->id_user
  1434. ]);
  1435. $userProducer = UserProducer::searchOne([
  1436. 'id_user' => $deliveryNote->id_user,
  1437. 'id_producer' => GlobalParam::getCurrentProducerId(
  1438. )
  1439. ]);
  1440. }
  1441. // affectation du BL aux commandes
  1442. foreach ($idOrders as $idOrder) {
  1443. $order = Order::searchOne([
  1444. 'id' => (int)$idOrder
  1445. ]);
  1446. if ($order && $order->distribution->id_producer == GlobalParam::getCurrentProducerId()) {
  1447. $order->id_delivery_note = $deliveryNote->id;
  1448. $order->save();
  1449. }
  1450. // init invoice price
  1451. $order = Order::searchOne(['id' => $idOrder]);
  1452. if ($order) {
  1453. $order->initInvoicePrices([
  1454. 'user' => $user,
  1455. 'user_producer' => $userProducer,
  1456. 'point_sale' => $firstOrder->pointSale
  1457. ]);
  1458. }
  1459. }
  1460. return [
  1461. 'return' => 'success',
  1462. 'alert' => [
  1463. 'type' => 'success',
  1464. 'message' => 'Bon de livraison ' . ($isUpdate ? 'modifié' : 'généré')
  1465. ]
  1466. ];
  1467. }
  1468. }
  1469. }
  1470. return [
  1471. 'return' => 'error',
  1472. 'alert' => [
  1473. 'type' => 'danger',
  1474. 'message' => 'Une erreur est survenue lors de la génération du bon de livraison.'
  1475. ]
  1476. ];
  1477. }
  1478. }