Você não pode selecionar mais de 25 tópicos Os tópicos devem começar com uma letra ou um número, podem incluir traços ('-') e podem ter até 35 caracteres.

1751 linhas
69KB

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