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.

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