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.

1071 lines
55KB

  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\Distribution;
  41. use common\models\Product;
  42. use common\models\Producer;
  43. use common\models\Order;
  44. use common\models\User;
  45. use common\models\Subscription;
  46. use common\helpers\Price;
  47. use common\models\PointSaleDistribution;
  48. use DateTime;
  49. class DistributionController extends BackendController
  50. {
  51. public function behaviors()
  52. {
  53. return [
  54. 'access' => [
  55. 'class' => AccessControl::className(),
  56. 'rules' => [
  57. [
  58. 'actions' => ['report-cron', 'report-terredepains'],
  59. 'allow' => true,
  60. 'roles' => ['?']
  61. ],
  62. [
  63. 'allow' => true,
  64. 'roles' => ['@'],
  65. 'matchCallback' => function ($rule, $action) {
  66. return User::getCurrentStatus() == USER::STATUS_ADMIN
  67. || User::getCurrentStatus() == USER::STATUS_PRODUCER;
  68. }
  69. ]
  70. ],
  71. ],
  72. ];
  73. }
  74. public function actionIndex($date = '')
  75. {
  76. $this->checkProductsPointsSale();
  77. $format = 'Y-m-d';
  78. $theDate = '';
  79. $dateObject = DateTime::createFromFormat($format, $date);
  80. if ($dateObject && $dateObject->format($format) === $date) {
  81. $theDate = $date;
  82. }
  83. return $this->render('index', [
  84. 'date' => $theDate
  85. ]);
  86. }
  87. public function actionAjaxInfos($date = '')
  88. {
  89. \Yii::$app->response->format = \yii\web\Response::FORMAT_JSON;
  90. $json = [
  91. 'distribution' => [],
  92. 'products' => []
  93. ];
  94. $format = 'Y-m-d';
  95. $dateObject = DateTime::createFromFormat($format, $date);
  96. $producer = GlobalParam::getCurrentProducer();
  97. $json['producer'] = [
  98. 'credit' => $producer->credit,
  99. 'tiller' => $producer->tiller
  100. ];
  101. $json['means_payment'] = MeanPayment::getAll();
  102. $distributionsArray = Distribution::searchAll([
  103. 'active' => 1
  104. ], [
  105. 'conditions' => ['date > :date_begin', 'date < :date_end'],
  106. 'params' => [':date_begin' => date('Y-m-d', strtotime('-1 month')), ':date_end' => date('Y-m-d', strtotime('+3 month')),],
  107. ]);
  108. $json['distributions'] = $distributionsArray;
  109. if ($dateObject && $dateObject->format($format) === $date) {
  110. // distribution
  111. $distribution = Distribution::initDistribution($date);
  112. $json['distribution'] = [
  113. 'id' => $distribution->id,
  114. 'active' => $distribution->active,
  115. 'url_report' => Yii::$app->urlManagerBackend->createUrl(['distribution/report', 'date' => $distribution->date])
  116. ];
  117. // commandes
  118. $ordersArray = Order::searchAll([
  119. 'distribution.id' => $distribution->id,
  120. ], [
  121. 'orderby' => 'user.lastname ASC, user.name ASC'
  122. ]);
  123. // montant et poids des commandes
  124. $revenues = 0;
  125. $weight = 0;
  126. if ($ordersArray) {
  127. foreach ($ordersArray as $order) {
  128. if (is_null($order->date_delete)) {
  129. $revenues += $order->getAmountWithTax();
  130. $weight += $order->weight;
  131. }
  132. }
  133. }
  134. $json['distribution']['revenues'] = Price::format($revenues);
  135. $json['distribution']['weight'] = number_format($weight, 2);
  136. // products
  137. $productsArray = Product::find()
  138. ->orWhere(['id_producer' => GlobalParam::getCurrentProducerId(),])
  139. ->joinWith(['productDistribution' => function ($query) use ($distribution) {
  140. $query->andOnCondition('product_distribution.id_distribution = ' . $distribution->id);
  141. }])
  142. ->orderBy('product_distribution.active DESC, order ASC')
  143. ->asArray()
  144. ->all();
  145. $potentialRevenues = 0;
  146. $potentialWeight = 0;
  147. foreach ($productsArray as &$theProduct) {
  148. $quantityOrder = Order::getProductQuantity($theProduct['id'], $ordersArray);
  149. $theProduct['quantity_ordered'] = $quantityOrder;
  150. if (!isset($theProduct['productDistribution'][0])) {
  151. $theProductObject = (object)$theProduct;
  152. $theProduct['productDistribution'][0] = $distribution->linkProduct($theProductObject);
  153. }
  154. if (!is_numeric($theProduct['productDistribution'][0]['quantity_max'])) {
  155. $theProduct['quantity_remaining'] = null;
  156. } else {
  157. $theProduct['quantity_remaining'] = $theProduct['productDistribution'][0]['quantity_max'] - $quantityOrder;
  158. }
  159. $theProduct['quantity_form'] = 0;
  160. if ($theProduct['productDistribution'][0]['active'] && $theProduct['productDistribution'][0]['quantity_max']) {
  161. $potentialRevenues += $theProduct['productDistribution'][0]['quantity_max'] * $theProduct['price'];
  162. $potentialWeight += $theProduct['productDistribution'][0]['quantity_max'] * $theProduct['weight'] / 1000;
  163. }
  164. }
  165. $json['distribution']['potential_revenues'] = Price::format($potentialRevenues);
  166. $json['distribution']['potential_weight'] = number_format($potentialWeight, 2);
  167. $json['products'] = $productsArray;
  168. // orders as array
  169. $ordersArrayObject = $ordersArray ;
  170. if ($ordersArray) {
  171. foreach ($ordersArray as &$order) {
  172. $productOrderArray = [];
  173. foreach ($order->productOrder as $productOrder) {
  174. $productOrderArray[$productOrder->id_product] = [
  175. 'quantity' => $productOrder->quantity * Product::$unitsArray[$productOrder->unit]['coefficient'],
  176. 'unit' => $productOrder->unit,
  177. ];
  178. }
  179. foreach ($productsArray as $product) {
  180. if (!isset($productOrderArray[$product['id']])) {
  181. $productOrderArray[$product['id']] = [
  182. 'quantity' => 0,
  183. 'unit' => $product['unit']
  184. ];
  185. }
  186. }
  187. $creditHistoryArray = [];
  188. foreach ($order->creditHistory as $creditHistory) {
  189. $creditHistoryArray[] = [
  190. 'date' => date('d/m/Y H:i:s', strtotime($creditHistory->date)),
  191. 'user_action' => $creditHistory->strUserAction(),
  192. 'wording' => $creditHistory->getStrWording(),
  193. 'debit' => ($creditHistory->isTypeDebit() ? '-&nbsp;' . $creditHistory->getAmount(Order::AMOUNT_TOTAL, true) : ''),
  194. 'credit' => ($creditHistory->isTypeCredit() ? '+&nbsp;' . $creditHistory->getAmount(Order::AMOUNT_TOTAL, true) : '')
  195. ];
  196. }
  197. $arrayCreditUser = [];
  198. if (isset($order->user) && isset($order->user->userProducer)) {
  199. $arrayCreditUser['credit'] = $order->user->userProducer[0]->credit;
  200. }
  201. $oneProductUnactivated = false;
  202. foreach ($order->productOrder as $productOrder) {
  203. foreach ($productsArray as $product) {
  204. if ($productOrder->id_product == $product['id'] && !$product['productDistribution'][0]['active']) {
  205. $oneProductUnactivated = true;
  206. }
  207. }
  208. }
  209. $order = array_merge($order->getAttributes(), [
  210. 'selected' => false,
  211. 'amount' => $order->getAmountWithTax(Order::AMOUNT_TOTAL),
  212. 'amount_paid' => $order->getAmount(Order::AMOUNT_PAID),
  213. 'amount_remaining' => $order->getAmount(Order::AMOUNT_REMAINING),
  214. 'amount_surplus' => $order->getAmount(Order::AMOUNT_SURPLUS),
  215. 'user' => (isset($order->user)) ? array_merge($order->user->getAttributes(), $arrayCreditUser) : null,
  216. 'pointSale' => ['id' => $order->pointSale->id, 'name' => $order->pointSale->name],
  217. 'productOrder' => $productOrderArray,
  218. 'creditHistory' => $creditHistoryArray,
  219. 'oneProductUnactivated' => $oneProductUnactivated
  220. ]);
  221. }
  222. }
  223. $json['orders'] = $ordersArray;
  224. // points de vente
  225. $pointsSaleArray = PointSale::find()
  226. ->joinWith(['pointSaleDistribution' => function ($q) use ($distribution) {
  227. $q->where(['id_distribution' => $distribution->id]);
  228. }])
  229. ->where([
  230. 'id_producer' => GlobalParam::getCurrentProducerId(),
  231. ])
  232. ->asArray()
  233. ->all();
  234. $idPointSaleDefault = 0;
  235. foreach ($pointsSaleArray as $pointSale) {
  236. if ($pointSale['default']) {
  237. $idPointSaleDefault = $pointSale['id'] ;
  238. }
  239. }
  240. $json['points_sale'] = $pointsSaleArray;
  241. // bons de livraison
  242. $deliveryNotesArray = DeliveryNote::searchAll([
  243. 'distribution.date' => $date,
  244. ]) ;
  245. $deliveryNotesByPointSaleArray = [] ;
  246. foreach($deliveryNotesArray as $deliveryNote) {
  247. if(isset($deliveryNote->orders[0])) {
  248. $deliveryNotesByPointSaleArray[$deliveryNote->orders[0]->id_point_sale] =
  249. $deliveryNote->getAttributes() ;
  250. }
  251. }
  252. $json['delivery_notes'] = $deliveryNotesByPointSaleArray ;
  253. // order create
  254. $productOrderArray = [];
  255. foreach ($productsArray as $product) {
  256. $productOrderArray[$product['id']] = [
  257. 'quantity' => 0,
  258. 'unit' => $product['unit']
  259. ];
  260. }
  261. $json['order_create'] = [
  262. 'id_point_sale' => $idPointSaleDefault,
  263. 'id_user' => 0,
  264. 'username' => '',
  265. 'comment' => '',
  266. 'productOrder' => $productOrderArray
  267. ];
  268. // utilisateurs
  269. $usersArray = User::findBy()->all();
  270. $json['users'] = $usersArray;
  271. // une production de la semaine activée ou non
  272. $oneDistributionWeekActive = false;
  273. $week = sprintf('%02d', date('W', strtotime($date)));
  274. $start = strtotime(date('Y', strtotime($date)) . 'W' . $week);
  275. $dateMonday = date('Y-m-d', strtotime('Monday', $start));
  276. $dateTuesday = date('Y-m-d', strtotime('Tuesday', $start));
  277. $dateWednesday = date('Y-m-d', strtotime('Wednesday', $start));
  278. $dateThursday = date('Y-m-d', strtotime('Thursday', $start));
  279. $dateFriday = date('Y-m-d', strtotime('Friday', $start));
  280. $dateSaturday = date('Y-m-d', strtotime('Saturday', $start));
  281. $dateSunday = date('Y-m-d', strtotime('Sunday', $start));
  282. $weekDistribution = Distribution::find()
  283. ->andWhere([
  284. 'id_producer' => GlobalParam::getCurrentProducerId(),
  285. 'active' => 1,
  286. ])
  287. ->andWhere(['or',
  288. ['date' => $dateMonday],
  289. ['date' => $dateTuesday],
  290. ['date' => $dateWednesday],
  291. ['date' => $dateThursday],
  292. ['date' => $dateFriday],
  293. ['date' => $dateSaturday],
  294. ['date' => $dateSunday],
  295. ])
  296. ->one();
  297. if ($weekDistribution) {
  298. $oneDistributionWeekActive = true;
  299. }
  300. $json['one_distribution_week_active'] = $oneDistributionWeekActive;
  301. // tiller
  302. if ($producer->tiller) {
  303. $tiller = new Tiller();
  304. $json['tiller_is_synchro'] = (int)$tiller->isSynchro($date);
  305. }
  306. }
  307. return $json;
  308. }
  309. public function actionAjaxPointSaleFavorite($idUser)
  310. {
  311. \Yii::$app->response->format = \yii\web\Response::FORMAT_JSON;
  312. $user = User::findOne(['id' => $idUser]);
  313. $favoritePointSale = $user->getFavoritePointSale();
  314. $idFavoritePointSale = 0;
  315. if ($favoritePointSale) {
  316. $idFavoritePointSale = $favoritePointSale->id;
  317. }
  318. return [
  319. 'id_favorite_point_sale' => $idFavoritePointSale
  320. ];
  321. }
  322. /**
  323. * Génére un PDF récapitulatif des des commandes d'un producteur pour une
  324. * date donnée (Méthode appelable via CRON)
  325. *
  326. * @param string $date
  327. * @param boolean $save
  328. * @param integer $idProducer
  329. * @param string $key
  330. * @return PDF|null
  331. */
  332. public function actionReportCron($date = '', $save = false, $idProducer = 0, $key = '')
  333. {
  334. if ($key == '64ac0bdab7e9f5e48c4d991ec5201d57') {
  335. $this->actionReport($date, $save, $idProducer);
  336. }
  337. }
  338. /**
  339. * Génére un PDF récapitulatif des commandes d'un producteur pour une
  340. * date donnée.
  341. *
  342. * @param string $date
  343. * @param boolean $save
  344. * @param integer $idProducer
  345. * @return PDF|null
  346. */
  347. public function actionReport($date = '', $save = false, $idProducer = 0, $type = "pdf")
  348. {
  349. if (!Yii::$app->user->isGuest) {
  350. $idProducer = GlobalParam::getCurrentProducerId();
  351. }
  352. $ordersArray = Order::searchAll([
  353. 'distribution.date' => $date,
  354. ],
  355. [
  356. 'orderby' => 'user.lastname ASC, user.name ASC, comment_point_sale ASC',
  357. 'conditions' => 'date_delete IS NULL'
  358. ]);
  359. $distribution = Distribution::searchOne([], [
  360. 'conditions' => 'date LIKE :date',
  361. 'params' => [':date' => $date]
  362. ]);
  363. if ($distribution) {
  364. $selectedProductsArray = ProductDistribution::searchByDistribution($distribution->id);
  365. $pointsSaleArray = PointSale::searchAll();
  366. foreach ($pointsSaleArray as $pointSale) {
  367. $pointSale->initOrders($ordersArray);
  368. }
  369. // produits
  370. $productsArray = Product::find()
  371. ->joinWith(['productDistribution' => function ($q) use ($distribution) {
  372. $q->where(['id_distribution' => $distribution->id]);
  373. }])
  374. ->where([
  375. 'id_producer' => GlobalParam::getCurrentProducerId(),
  376. ])
  377. ->orderBy('order ASC')
  378. ->all();
  379. if ($type == 'pdf') {
  380. // get your HTML raw content without any layouts or scripts
  381. $content = $this->renderPartial('report', [
  382. 'date' => $date,
  383. 'distribution' => $distribution,
  384. 'selectedProductsArray' => $selectedProductsArray,
  385. 'pointsSaleArray' => $pointsSaleArray,
  386. 'productsArray' => $productsArray,
  387. 'ordersArray' => $ordersArray
  388. ]);
  389. $dateStr = date('d/m/Y', strtotime($date));
  390. if ($save) {
  391. $destination = Pdf::DEST_FILE;
  392. } else {
  393. $destination = Pdf::DEST_BROWSER;
  394. }
  395. $pdf = new Pdf([
  396. // set to use core fonts only
  397. 'mode' => Pdf::MODE_UTF8,
  398. // A4 paper format
  399. 'format' => Pdf::FORMAT_A4,
  400. // portrait orientation
  401. 'orientation' => Pdf::ORIENT_PORTRAIT,
  402. // stream to browser inline
  403. 'destination' => $destination,
  404. 'filename' => Yii::getAlias('@app/web/pdf/Commandes-' . $date . '-' . $idProducer . '.pdf'),
  405. // your html content input
  406. 'content' => $content,
  407. // format content from your own css file if needed or use the
  408. // enhanced bootstrap css built by Krajee for mPDF formatting
  409. //'cssFile' => Yii::getAlias('@web/css/distribution/report.css'),
  410. // any css to be embedded if required
  411. 'cssInline' => '
  412. table {
  413. border-spacing : 0px ;
  414. border-collapse : collapse ;
  415. width: 100% ;
  416. }
  417. table tr th,
  418. table tr td {
  419. padding: 0px ;
  420. margin: 0px ;
  421. border: solid 1px #e0e0e0 ;
  422. padding: 3px 8px ;
  423. vertical-align : top;
  424. }
  425. table tr th {
  426. font-size: 13px ;
  427. }
  428. table tr td {
  429. font-size: 13px ;
  430. }
  431. ',
  432. // set mPDF properties on the fly
  433. //'options' => ['title' => 'Krajee Report Title'],
  434. // call mPDF methods on the fly
  435. 'methods' => [
  436. 'SetHeader' => ['Commandes du ' . $dateStr],
  437. 'SetFooter' => ['{PAGENO}'],
  438. ]
  439. ]);
  440. // return the pdf output as per the destination setting
  441. return $pdf->render();
  442. } elseif ($type == 'csv') {
  443. $datas = [];
  444. // produits en colonne
  445. $productsNameArray = [''];
  446. $productsIndexArray = [];
  447. $productsHasQuantity = [];
  448. $cpt = 1;
  449. foreach ($productsArray as $product) {
  450. $productsHasQuantity[$product->id] = 0;
  451. foreach (Product::$unitsArray as $unit => $dataUnit) {
  452. $quantity = Order::getProductQuantity($product->id, $ordersArray, true, $unit);
  453. if ($quantity) {
  454. $productsHasQuantity[$product->id] += $quantity;
  455. }
  456. }
  457. if ($productsHasQuantity[$product->id] > 0) {
  458. $productsNameArray[] = $product->name . ' (' . Product::strUnit($product->unit, 'wording_short', true) . ')';
  459. $productsIndexArray[$product->id] = $cpt++;
  460. }
  461. }
  462. $datas[] = $productsNameArray;
  463. // points de vente
  464. foreach ($pointsSaleArray as $pointSale) {
  465. if (count($pointSale->orders)) {
  466. // listing commandes
  467. $datas[] = ['> ' . $pointSale->name];
  468. foreach ($pointSale->orders as $order) {
  469. $orderLine = [$order->getStrUser()];
  470. foreach ($productsIndexArray as $idProduct => $indexProduct) {
  471. $orderLine[$indexProduct] = '';
  472. }
  473. foreach ($order->productOrder as $productOrder) {
  474. if (strlen($orderLine[$productsIndexArray[$productOrder->id_product]])) {
  475. $orderLine[$productsIndexArray[$productOrder->id_product]] .= ' + ';
  476. }
  477. $orderLine[$productsIndexArray[$productOrder->id_product]] .= $productOrder->quantity;
  478. if ($productOrder->product->unit != $productOrder->unit) {
  479. $orderLine[$productsIndexArray[$productOrder->id_product]] .= Product::strUnit($productOrder->unit, 'wording_short', true);
  480. }
  481. }
  482. $datas[] = $this->_lineOrderReportCSV($orderLine, $cpt);
  483. }
  484. // total point de vente
  485. $totalsPointSaleArray = $this->_totalReportCSV(
  486. 'Total',
  487. $pointSale->orders,
  488. $productsArray,
  489. $productsIndexArray
  490. );
  491. $datas[] = $this->_lineOrderReportCSV($totalsPointSaleArray, $cpt);
  492. $datas[] = [];
  493. }
  494. }
  495. // global
  496. $totalsGlobalArray = $this->_totalReportCSV(
  497. '> Totaux',
  498. $ordersArray,
  499. $productsArray,
  500. $productsIndexArray
  501. );
  502. $datas[] = $this->_lineOrderReportCSV($totalsGlobalArray, $cpt);
  503. CSV::downloadSendHeaders('Commandes_' . $date . '.csv');
  504. echo CSV::array2csv($datas);
  505. die();
  506. }
  507. }
  508. return null;
  509. }
  510. /**
  511. * Génère un export des commandes au format CSV à destination du Google Drive
  512. * de Terre de pains.
  513. *
  514. * @param type $date
  515. * @return CSV
  516. */
  517. public function actionReportTerredepains($date, $key)
  518. {
  519. if ($key == 'ef572cc148c001f0180c4a624189ed30') {
  520. $producer = Producer::searchOne([
  521. 'producer.slug' => 'terredepains'
  522. ]);
  523. $idProducer = $producer->id;
  524. $ordersArray = Order::searchAll([
  525. 'distribution.date' => $date,
  526. 'distribution.id_producer' => $idProducer
  527. ],
  528. [
  529. 'orderby' => 'user.lastname ASC, user.name ASC, comment_point_sale ASC',
  530. 'conditions' => 'date_delete IS NULL'
  531. ]);
  532. $distribution = Distribution::searchOne([
  533. 'distribution.id_producer' => $idProducer
  534. ], [
  535. 'conditions' => 'date LIKE :date',
  536. 'params' => [
  537. ':date' => $date,
  538. ]
  539. ]);
  540. if ($distribution) {
  541. $selectedProductsArray = ProductDistribution::searchByDistribution($distribution->id);
  542. $pointsSaleArray = PointSale::searchAll([
  543. 'point_sale.id_producer' => $idProducer
  544. ]);
  545. foreach ($pointsSaleArray as $pointSale) {
  546. $pointSale->initOrders($ordersArray);
  547. }
  548. // produits
  549. $productsArray = Product::find()
  550. ->joinWith(['productDistribution' => function ($q) use ($distribution) {
  551. $q->where(['id_distribution' => $distribution->id]);
  552. }])
  553. ->where([
  554. 'id_producer' => $idProducer,
  555. ])
  556. ->orderBy('order ASC')
  557. ->all();
  558. $datas = [];
  559. // produits en colonne
  560. $productsNameArray = [''];
  561. $productsIndexArray = [];
  562. $productsHasQuantity = [];
  563. $cpt = 1;
  564. foreach ($productsArray as $product) {
  565. $theUnit = Product::strUnit($product->unit, 'wording_short', true);
  566. $theUnit = ($theUnit == 'p.') ? '' : ' (' . $theUnit . ')';
  567. $productsNameArray[] = $product->name . $theUnit;
  568. $productsIndexArray[$product->id] = $cpt++;
  569. }
  570. $productsNameArray[] = 'Total';
  571. $datas[] = $productsNameArray;
  572. // global
  573. $totalsGlobalArray = $this->_totalReportCSV(
  574. '> Totaux',
  575. $ordersArray,
  576. $productsArray,
  577. $productsIndexArray
  578. );
  579. $datas[] = $this->_lineOrderReportCSV($totalsGlobalArray, $cpt - 1, true);
  580. $datas[] = [];
  581. // points de vente
  582. foreach ($pointsSaleArray as $pointSale) {
  583. if (count($pointSale->orders)) {
  584. // listing commandes
  585. $datas[] = ['> ' . $pointSale->name];
  586. foreach ($pointSale->orders as $order) {
  587. $orderLine = [$order->getStrUser()];
  588. foreach ($productsIndexArray as $idProduct => $indexProduct) {
  589. $orderLine[$indexProduct] = '';
  590. }
  591. foreach ($order->productOrder as $productOrder) {
  592. if (strlen($orderLine[$productsIndexArray[$productOrder->id_product]])) {
  593. $orderLine[$productsIndexArray[$productOrder->id_product]] .= ' + ';
  594. }
  595. $orderLine[$productsIndexArray[$productOrder->id_product]] .= $productOrder->quantity;
  596. if ($productOrder->product->unit != $productOrder->unit) {
  597. $orderLine[$productsIndexArray[$productOrder->id_product]] .= Product::strUnit($productOrder->unit, 'wording_short', true);
  598. }
  599. }
  600. $datas[] = $this->_lineOrderReportCSV($orderLine, $cpt - 1, true);
  601. }
  602. // total point de vente
  603. $totalsPointSaleArray = $this->_totalReportCSV(
  604. 'Total point de vente',
  605. $pointSale->orders,
  606. $productsArray,
  607. $productsIndexArray
  608. );
  609. $datas[] = $this->_lineOrderReportCSV($totalsPointSaleArray, $cpt - 1, true);
  610. $datas[] = [];
  611. }
  612. }
  613. CSV::downloadSendHeaders('Commandes_' . $date . '.csv');
  614. echo CSV::array2csv($datas);
  615. die();
  616. }
  617. return null;
  618. }
  619. }
  620. public function _totalReportCSV($label, $ordersArray, $productsArray, $productsIndexArray)
  621. {
  622. $totalsPointSaleArray = [$label];
  623. foreach ($productsArray as $product) {
  624. foreach (Product::$unitsArray as $unit => $dataUnit) {
  625. $quantity = Order::getProductQuantity($product->id, $ordersArray, false, $unit);
  626. if ($quantity) {
  627. $index = $productsIndexArray[$product->id];
  628. if (!isset($totalsPointSaleArray[$index])) {
  629. $totalsPointSaleArray[$index] = '';
  630. }
  631. if (strlen($totalsPointSaleArray[$index])) {
  632. $totalsPointSaleArray[$index] .= ' + ';
  633. }
  634. $totalsPointSaleArray[$index] .= $quantity;
  635. if ($product->unit != $unit) {
  636. $totalsPointSaleArray[$index] .= '' . Product::strUnit($unit, 'wording_short', true);
  637. }
  638. }
  639. }
  640. }
  641. return $totalsPointSaleArray;
  642. }
  643. public function _lineOrderReportCSV($orderLine, $cptMax, $showTotal = false)
  644. {
  645. $line = [];
  646. $cptTotal = 0;
  647. for ($i = 0; $i <= $cptMax; $i++) {
  648. if (isset($orderLine[$i]) && $orderLine[$i]) {
  649. $line[] = $orderLine[$i];
  650. $cptTotal += $orderLine[$i];
  651. } else {
  652. $line[] = '';
  653. }
  654. }
  655. if ($cptTotal > 0 && $showTotal) {
  656. $line[] = $cptTotal;
  657. }
  658. return $line;
  659. }
  660. public function actionAjaxProcessProductQuantityMax($idDistribution, $idProduct, $quantityMax)
  661. {
  662. \Yii::$app->response->format = \yii\web\Response::FORMAT_JSON;
  663. $productDistribution = ProductDistribution::searchOne([
  664. 'id_distribution' => $idDistribution,
  665. 'id_product' => $idProduct,
  666. ]);
  667. $productDistribution->quantity_max = (!$quantityMax) ? null : (int)$quantityMax;
  668. $productDistribution->save();
  669. return ['success'];
  670. }
  671. public function actionAjaxProcessActiveProduct($idDistribution, $idProduct, $active)
  672. {
  673. \Yii::$app->response->format = \yii\web\Response::FORMAT_JSON;
  674. $productDistribution = ProductDistribution::searchOne([
  675. 'id_distribution' => $idDistribution,
  676. 'id_product' => $idProduct,
  677. ]);
  678. $productDistribution->active = $active;
  679. $productDistribution->save();
  680. return ['success'];
  681. }
  682. public function actionAjaxProcessActivePointSale($idDistribution, $idPointSale, $delivery)
  683. {
  684. \Yii::$app->response->format = \yii\web\Response::FORMAT_JSON;
  685. $pointSaleDistribution = PointSaleDistribution::searchOne([
  686. 'id_distribution' => $idDistribution,
  687. 'id_point_sale' => $idPointSale,
  688. ]);
  689. $pointSaleDistribution->delivery = $delivery;
  690. $pointSaleDistribution->save();
  691. return ['success'];
  692. }
  693. /**
  694. * Active/désactive un jour de distribution.
  695. *
  696. * @param integer $idDistribution
  697. * @param string $date
  698. * @param boolean $active
  699. * @return array
  700. */
  701. public function actionAjaxProcessActiveDistribution($idDistribution = 0, $date = '', $active)
  702. {
  703. \Yii::$app->response->format = \yii\web\Response::FORMAT_JSON;
  704. if ($idDistribution) {
  705. $distribution = Distribution::searchOne([
  706. 'id' => $idDistribution
  707. ]);
  708. }
  709. $format = 'Y-m-d';
  710. $dateObject = DateTime::createFromFormat($format, $date);
  711. if ($dateObject && $dateObject->format($format) === $date) {
  712. $distribution = Distribution::initDistribution($date);
  713. }
  714. if ($distribution) {
  715. $distribution->active($active);
  716. return ['success'];
  717. }
  718. return ['error'];
  719. }
  720. /**
  721. * Change l'état d'une semaine de production (activé, désactivé).
  722. *
  723. * @param string $date
  724. * @param integer $active
  725. */
  726. public function actionAjaxProcessActiveWeekDistribution($date, $active)
  727. {
  728. \Yii::$app->response->format = \yii\web\Response::FORMAT_JSON;
  729. $week = sprintf('%02d', date('W', strtotime($date)));
  730. $start = strtotime(date('Y', strtotime($date)) . 'W' . $week);
  731. $dateMonday = date('Y-m-d', strtotime('Monday', $start));
  732. $dateTuesday = date('Y-m-d', strtotime('Tuesday', $start));
  733. $dateWednesday = date('Y-m-d', strtotime('Wednesday', $start));
  734. $dateThursday = date('Y-m-d', strtotime('Thursday', $start));
  735. $dateFriday = date('Y-m-d', strtotime('Friday', $start));
  736. $dateSaturday = date('Y-m-d', strtotime('Saturday', $start));
  737. $dateSunday = date('Y-m-d', strtotime('Sunday', $start));
  738. $pointsSaleArray = PointSale::searchAll();
  739. $activeMonday = false;
  740. $activeTuesday = false;
  741. $activeWednesday = false;
  742. $activeThursday = false;
  743. $activeFriday = false;
  744. $activeSaturday = false;
  745. $activeSunday = false;
  746. foreach ($pointsSaleArray as $pointSale) {
  747. if ($pointSale->delivery_monday) $activeMonday = true;
  748. if ($pointSale->delivery_tuesday) $activeTuesday = true;
  749. if ($pointSale->delivery_wednesday) $activeWednesday = true;
  750. if ($pointSale->delivery_thursday) $activeThursday = true;
  751. if ($pointSale->delivery_friday) $activeFriday = true;
  752. if ($pointSale->delivery_saturday) $activeSaturday = true;
  753. if ($pointSale->delivery_sunday) $activeSunday = true;
  754. }
  755. if ($activeMonday || !$active) {
  756. $this->actionAjaxProcessActiveDistribution(0, $dateMonday, $active);
  757. }
  758. if ($activeTuesday || !$active) {
  759. $this->actionAjaxProcessActiveDistribution(0, $dateTuesday, $active);
  760. }
  761. if ($activeWednesday || !$active) {
  762. $this->actionAjaxProcessActiveDistribution(0, $dateWednesday, $active);
  763. }
  764. if ($activeThursday || !$active) {
  765. $this->actionAjaxProcessActiveDistribution(0, $dateThursday, $active);
  766. }
  767. if ($activeFriday || !$active) {
  768. $this->actionAjaxProcessActiveDistribution(0, $dateFriday, $active);
  769. }
  770. if ($activeSaturday || !$active) {
  771. $this->actionAjaxProcessActiveDistribution(0, $dateSaturday, $active);
  772. }
  773. if ($activeSunday || !$active) {
  774. $this->actionAjaxProcessActiveDistribution(0, $dateSunday, $active);
  775. }
  776. return ['success'];
  777. }
  778. /**
  779. * Ajoute les commandes récurrentes pour une date donnée.
  780. *
  781. * @param string $date
  782. */
  783. public function actionAjaxProcessAddSubscriptions($date)
  784. {
  785. \Yii::$app->response->format = \yii\web\Response::FORMAT_JSON;
  786. Subscription::addAll($date, true);
  787. return ['success'];
  788. }
  789. /**
  790. * Synchronise les commandes avec la plateforme Tiller pour une date donnée.
  791. *
  792. * @param string $date
  793. */
  794. public function actionAjaxProcessSynchroTiller($date)
  795. {
  796. $producerTiller = Producer::getConfig('tiller');
  797. if ($producerTiller) {
  798. $tiller = new Tiller();
  799. $isSynchro = $tiller->isSynchro($date);
  800. if (!$isSynchro) {
  801. $orders = Order::searchAll([
  802. 'distribution.date' => $date,
  803. 'order.tiller_synchronization' => 1
  804. ]);
  805. $strDate = date('Y-m-d\T12:i:s+0000', strtotime($date) + 1);
  806. if ($orders && count($orders)) {
  807. foreach ($orders as $order) {
  808. $lines = [];
  809. foreach ($order->productOrder as $productOrder) {
  810. $lines[] = [
  811. 'name' => $productOrder->product->name,
  812. 'price' => $productOrder->price * 100 * $productOrder->quantity,
  813. 'tax' => 5.5,
  814. 'date' => $strDate,
  815. 'quantity' => $productOrder->quantity
  816. ];
  817. }
  818. $typePaymentTiller = '';
  819. if ($order->mean_payment == MeanPayment::MONEY
  820. || $order->mean_payment == MeanPayment::CREDIT
  821. || $order->mean_payment == MeanPayment::TRANSFER
  822. || $order->mean_payment == MeanPayment::OTHER) {
  823. $typePaymentTiller = 'CASH';
  824. }
  825. if ($order->mean_payment == MeanPayment::CREDIT_CARD) {
  826. $typePaymentTiller = 'CARD';
  827. }
  828. if ($order->mean_payment == MeanPayment::CHEQUE) {
  829. $typePaymentTiller = 'BANK_CHECK';
  830. }
  831. if (!strlen($typePaymentTiller) || !$order->mean_payment) {
  832. $typePaymentTiller = 'CASH';
  833. }
  834. $tiller->postOrder([
  835. 'externalId' => $order->id,
  836. 'type' => 1,
  837. 'status' => "CLOSED",
  838. 'openDate' => $strDate,
  839. 'closeDate' => $strDate,
  840. 'lines' => $lines,
  841. 'payments' => [[
  842. 'type' => $typePaymentTiller,
  843. 'amount' => $order->getAmountWithTax(Order::AMOUNT_TOTAL) * 100,
  844. 'status' => 'ACCEPTED',
  845. 'date' => $strDate
  846. ]]
  847. ]);
  848. }
  849. }
  850. }
  851. }
  852. }
  853. public function actionAjaxGenerateDeliveryNote($idOrders)
  854. {
  855. \Yii::$app->response->format = \yii\web\Response::FORMAT_JSON;
  856. if (strlen($idOrders)) {
  857. $idOrders = json_decode($idOrders, true);
  858. if (is_array($idOrders) && count($idOrders) > 0) {
  859. // récupération première commande pour obtenir des infos
  860. reset($idOrders) ;
  861. $firstOrder = Order::searchOne([
  862. 'id' => (int)$idOrders[key($idOrders)]
  863. ]);
  864. // deliveryNote existant
  865. $deliveryNote = null ;
  866. $isUpdate = false ;
  867. $i = 0 ;
  868. $ordersArray = Order::searchAll([
  869. 'id' => $idOrders,
  870. ]) ;
  871. do {
  872. $order = $ordersArray[$i] ;
  873. if($order->distribution->id_producer == GlobalParam::getCurrentProducerId() && $order->id_delivery_note > 0) {
  874. $deliveryNote = DeliveryNote::searchOne([
  875. 'id' => $order->id_delivery_note
  876. ]) ;
  877. $isUpdate = true ;
  878. }
  879. $i ++ ;
  880. } while($deliveryNote == null && isset($ordersArray[$i])) ;
  881. if($deliveryNote && $deliveryNote->status == Document::STATUS_VALID) {
  882. return [
  883. 'return' => 'error',
  884. 'alert' => 'Vous ne pouvez pas modifier un bon de livraison déjà validé.',
  885. ] ;
  886. }
  887. if ($firstOrder) {
  888. // génération du BL
  889. if(!$deliveryNote) {
  890. $deliveryNote = new DeliveryNote;
  891. $deliveryNote->name = 'Bon de livraison ' . $firstOrder->pointSale->name . ' (' . date('d/m/Y', strtotime($firstOrder->distribution->date)) . ')';
  892. $deliveryNote->id_user = 1;
  893. $deliveryNote->id_producer = GlobalParam::getCurrentProducerId();
  894. $deliveryNote->save();
  895. }
  896. else {
  897. // réinitialisation des order.id_delivery_order
  898. Order::updateAll([
  899. 'id_delivery_note' => null
  900. ], [
  901. 'id_delivery_note' => $deliveryNote->id
  902. ]) ;
  903. }
  904. // affectation du BL aux commandes
  905. foreach ($idOrders as $idOrder) {
  906. $order = Order::searchOne([
  907. 'id' => (int)$idOrder
  908. ]);
  909. if ($order && $order->distribution->id_producer == GlobalParam::getCurrentProducerId()) {
  910. $order->id_delivery_note = $deliveryNote->id;
  911. $order->save();
  912. }
  913. }
  914. return [
  915. 'return' => 'success',
  916. 'alert' => 'Bon de livraison '.($isUpdate ? 'modifié' : 'généré')
  917. ] ;
  918. }
  919. }
  920. }
  921. return [
  922. 'return' => 'error',
  923. 'alert' => 'Une erreur est survenue lors de la génération du bon de livraison.',
  924. ];
  925. }
  926. }