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.

1116 linhas
37KB

  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 common\models;
  38. use common\helpers\Debug;
  39. use common\helpers\GlobalParam;
  40. use common\helpers\Price;
  41. use common\logic\Producer\Producer\ProducerModel;
  42. use common\logic\User\CreditHistory\CreditHistoryModel;
  43. use common\logic\User\User\UserModel;
  44. use common\models\Producer;
  45. use Yii;
  46. use yii\helpers\Html;
  47. use common\components\ActiveRecordCommon;
  48. use yii\web\NotFoundHttpException;
  49. /**
  50. * This is the model class for table "order".
  51. *
  52. * @property integer $id
  53. * @property integer $id_user
  54. * @property string $date
  55. * @property string $date_update
  56. * @property integer $id_point_sale
  57. * @property integer $id_distribution
  58. * @property boolean $auto_payment
  59. * @property integer $id_subscription
  60. */
  61. class Order extends ActiveRecordCommon
  62. {
  63. var $amount = 0;
  64. var $amount_with_tax = 0;
  65. var $amount_vat = [];
  66. var $invoice_amount = 0;
  67. var $invoice_amount_with_tax = 0;
  68. var $invoice_amount_vat = [];
  69. var $paid_amount = 0;
  70. var $weight = 0;
  71. const ORIGIN_AUTO = 'auto';
  72. const ORIGIN_USER = 'user';
  73. const ORIGIN_ADMIN = 'admin';
  74. const PAYMENT_PAID = 'paid';
  75. const PAYMENT_UNPAID = 'unpaid';
  76. const PAYMENT_SURPLUS = 'surplus';
  77. const INVOICE_AMOUNT_TOTAL = 'invoice-total';
  78. const AMOUNT_TOTAL = 'total';
  79. const AMOUNT_PAID = 'paid';
  80. const AMOUNT_REMAINING = 'remaining';
  81. const AMOUNT_SURPLUS = 'surplus';
  82. const STATE_OPEN = 'open';
  83. const STATE_PREPARATION = 'preparation';
  84. const STATE_DELIVERED = 'delivered';
  85. /**
  86. * @inheritdoc
  87. */
  88. public static function tableName()
  89. {
  90. return 'order';
  91. }
  92. /**
  93. * @inheritdoc
  94. */
  95. public function rules()
  96. {
  97. return [
  98. [['id_user', 'date', 'status'], 'required', 'message' => ''],
  99. [
  100. [
  101. 'id_user',
  102. 'id_point_sale',
  103. 'id_distribution',
  104. 'id_subscription',
  105. 'id_invoice',
  106. 'id_quotation',
  107. 'id_delivery_note'
  108. ],
  109. 'integer'
  110. ],
  111. [['auto_payment', 'tiller_synchronization', 'delivery_home'], 'boolean'],
  112. [['status', 'reference', 'delivery_address', 'online_payment_url', 'tiller_external_id'], 'string'],
  113. [['date', 'date_update', 'comment', 'comment_point_sale', 'mean_payment', 'tiller_external_id'], 'safe']
  114. ];
  115. }
  116. /**
  117. * @inheritdoc
  118. */
  119. public function attributeLabels()
  120. {
  121. return [
  122. 'id' => 'ID',
  123. 'id_user' => 'Id User',
  124. 'date' => 'Date',
  125. 'date_update' => 'Date de modification',
  126. 'id_point_sale' => 'Point de vente',
  127. 'id_distribution' => 'Date de distribution',
  128. 'id_subscription' => 'Abonnement',
  129. 'status' => 'Statut',
  130. 'id_invoice' => 'Facture',
  131. 'id_quotation' => 'Devis',
  132. 'id_delivery_note' => 'Bon de livraison',
  133. 'reference' => 'Référence',
  134. 'delivery_home' => 'Livraison à domicile',
  135. 'delivery_address' => 'Adresse de livraison',
  136. 'online_payment_url' => 'URL de paiement',
  137. 'tiller_external_id' => 'Tiller : externalId',
  138. ];
  139. }
  140. /*
  141. * Relations
  142. */
  143. public function getUser()
  144. {
  145. return $this->hasOne(UserModel::className(), ['id' => 'id_user']);
  146. }
  147. public function getProductOrder()
  148. {
  149. return $this->hasMany(ProductOrder::className(), ['id_order' => 'id'])
  150. ->orderBy(['product.order' => SORT_ASC])
  151. ->joinWith('product');
  152. }
  153. public function getDistribution()
  154. {
  155. return $this->hasOne(Distribution::className(), ['id' => 'id_distribution'])
  156. ->with('producer');
  157. }
  158. public function getDistributionOject(): ?Distribution
  159. {
  160. return $this->distribution;
  161. }
  162. public function getPointSale()
  163. {
  164. return $this->hasOne(PointSale::className(), ['id' => 'id_point_sale'])
  165. ->with('userPointSale');
  166. }
  167. public function getCreditHistory()
  168. {
  169. return $this->hasMany(CreditHistoryModel::class, ['id_order' => 'id']);
  170. }
  171. public function getSubscription()
  172. {
  173. return $this->hasOne(Subscription::className(), ['id' => 'id_subscription'])
  174. ->with('productSubscription');
  175. }
  176. public function getInvoice()
  177. {
  178. return $this->hasOne(Invoice::className(), ['id' => 'id_invoice']);
  179. }
  180. public function getQuotation()
  181. {
  182. return $this->hasOne(Quotation::className(), ['id' => 'id_quotation']);
  183. }
  184. public function getDeliveryNote()
  185. {
  186. return $this->hasOne(DeliveryNote::className(), ['id' => 'id_delivery_note']);
  187. }
  188. /**
  189. * Retourne les options de base nécessaires à la fonction de recherche.
  190. *
  191. * @return array
  192. */
  193. public static function defaultOptionsSearch()
  194. {
  195. return [
  196. 'with' => [
  197. 'productOrder',
  198. 'productOrder.product',
  199. 'creditHistory',
  200. 'creditHistory.userAction',
  201. 'pointSale'
  202. ],
  203. 'join_with' => ['distribution', 'user', 'user.userProducer'],
  204. 'orderby' => 'order.date ASC',
  205. 'attribute_id_producer' => 'distribution.id_producer'
  206. ];
  207. }
  208. /**
  209. * Initialise le montant total, le montant déjà payé et le poids de la
  210. * commande.
  211. */
  212. public function init($taxCalculationMethod = Document::TAX_CALCULATION_METHOD_DEFAULT)
  213. {
  214. $this->initAmount($taxCalculationMethod);
  215. $this->initPaidAmount();
  216. return $this;
  217. }
  218. /**
  219. * Initialise le montant de la commande.
  220. *
  221. */
  222. public function initAmount($taxCalculationMethod = Document::TAX_CALCULATION_METHOD_DEFAULT)
  223. {
  224. $this->amount = 0;
  225. $this->amount_with_tax = 0;
  226. $this->amount_vat = [];
  227. $this->invoice_amount = 0;
  228. $this->invoice_amount_with_tax = 0;
  229. $this->invoice_amount_vat = [];
  230. $this->weight = 0;
  231. if (isset($this->productOrder)) {
  232. foreach ($this->productOrder as $productOrder) {
  233. $this->addAmount(self::AMOUNT_TOTAL, $productOrder, $taxCalculationMethod);
  234. $this->addAmount(self::INVOICE_AMOUNT_TOTAL, $productOrder, $taxCalculationMethod);
  235. $this->addWeight($productOrder);
  236. }
  237. }
  238. }
  239. public function addWeight($productOrder)
  240. {
  241. if ($productOrder->unit == 'piece') {
  242. if (isset($productOrder->product)) {
  243. $this->weight += ($productOrder->quantity * $productOrder->product->weight) / 1000;
  244. }
  245. } else {
  246. $this->weight += $productOrder->quantity;
  247. }
  248. }
  249. public function addAmount($typeTotal, $productOrder, $taxCalculationMethod)
  250. {
  251. $fieldNameAmount = $this->getFieldNameAmount($typeTotal);
  252. $fieldNameAmountWithTax = $this->getFieldNameAmount($typeTotal, 'with_tax');
  253. $price = $productOrder->getPriceByTypeTotal($typeTotal);
  254. $this->$fieldNameAmount += $price * $productOrder->quantity;
  255. $this->$fieldNameAmountWithTax += Price::getPriceWithTax(
  256. $price,
  257. $productOrder->taxRate->value,
  258. $taxCalculationMethod
  259. ) * $productOrder->quantity;
  260. $this->addVat($typeTotal, $price * $productOrder->quantity, $productOrder->taxRate, $taxCalculationMethod);
  261. }
  262. public function addVat($typeTotal, $priceTotalWithoutTax, $taxRate, $taxCalculationMethod)
  263. {
  264. $fieldName = $this->getFieldNameAmount($typeTotal, 'vat');
  265. if(!isset($this->$fieldName[$taxRate->id])) {
  266. $this->$fieldName[$taxRate->id] = 0;
  267. }
  268. $this->$fieldName[$taxRate->id] += Price::getVat($priceTotalWithoutTax, $taxRate->value, $taxCalculationMethod);
  269. }
  270. public function getTotalVat($typeTotal = self::AMOUNT_TOTAL)
  271. {
  272. $fieldName = $this->getFieldNameAmount($typeTotal, 'vat');
  273. $totalVat = 0;
  274. foreach($this->$fieldName as $vat) {
  275. $totalVat += $vat;
  276. }
  277. return $totalVat;
  278. }
  279. public function getFieldNameAmount($typeTotal = self::AMOUNT_TOTAL, $typeField = '')
  280. {
  281. $fieldName = 'amount';
  282. if($typeTotal == self::INVOICE_AMOUNT_TOTAL) {
  283. $fieldName = 'invoice_amount';
  284. }
  285. if($typeField == 'vat') {
  286. $fieldName = $fieldName.'_vat';
  287. }
  288. elseif($typeField == 'with_tax') {
  289. $fieldName = $fieldName.'_with_tax';
  290. }
  291. return $fieldName;
  292. }
  293. /**
  294. * Initialise le montant payé de la commande et le retourne.
  295. *
  296. * @return float
  297. */
  298. public function initPaidAmount()
  299. {
  300. if (isset($this->creditHistory)) {
  301. $history = $this->creditHistory;
  302. } else {
  303. $history = CreditHistoryModel::find()
  304. ->where(['id_order' => $this->id])
  305. ->all();
  306. }
  307. $this->paid_amount = 0;
  308. if (count($history)) {
  309. foreach ($history as $ch) {
  310. if ($ch->type == CreditHistoryModel::TYPE_PAYMENT) {
  311. $this->paid_amount += $ch->amount;
  312. } elseif ($ch->type == CreditHistoryModel::TYPE_REFUND) {
  313. $this->paid_amount -= $ch->amount;
  314. }
  315. }
  316. }
  317. }
  318. public function delete($force = false)
  319. {
  320. // remboursement si l'utilisateur a payé pour cette commande
  321. $amountPaid = $this->getAmount(Order::AMOUNT_PAID);
  322. if ($amountPaid > 0.01) {
  323. $this->saveCreditHistory(
  324. CreditHistoryModel::TYPE_REFUND,
  325. $amountPaid,
  326. GlobalParam::getCurrentProducerId(),
  327. $this->id_user,
  328. UserModel::getCurrentId()
  329. );
  330. }
  331. // delete
  332. if (ProducerModel::getConfig('option_behavior_cancel_order') == ProducerModel::BEHAVIOR_DELETE_ORDER_DELETE ||
  333. (ProducerModel::getConfig(
  334. 'option_behavior_cancel_order'
  335. ) == ProducerModel::BEHAVIOR_DELETE_ORDER_STATUS && strlen($this->date_delete)) ||
  336. $force) {
  337. ProductOrder::deleteAll(['id_order' => $this->id]);
  338. return parent::delete();
  339. } // status 'delete'
  340. elseif (ProducerModel::getConfig('option_behavior_cancel_order') == ProducerModel::BEHAVIOR_DELETE_ORDER_STATUS) {
  341. $this->date_delete = date('Y-m-d H:i:s');
  342. return $this->save();
  343. }
  344. }
  345. /**
  346. * Changement de statut d'une commande
  347. *
  348. * @param $newStatus
  349. */
  350. public function changeOrderStatus($newStatus, $origin)
  351. {
  352. $orderStatusArray = GlobalParam::get('orderStatus');
  353. switch ($newStatus) {
  354. case 'new-order' :
  355. $this->addOrderStatusHistory($newStatus, $origin);
  356. $this->status = $newStatus;
  357. $this->save();
  358. break;
  359. case 'waiting-paiement-on-delivery':
  360. if (in_array($newStatus, $orderStatusArray[$this->status]['nextStatusAllow'])) {
  361. $this->addOrderStatusHistory($newStatus, $origin);
  362. $this->status = $newStatus;
  363. $this->save();
  364. }
  365. break;
  366. case 'waiting-paiement-by-credit':
  367. if (in_array($newStatus, $orderStatusArray[$this->status]['nextStatusAllow'])) {
  368. $this->addOrderStatusHistory($newStatus, $origin);
  369. $this->status = $newStatus;
  370. $this->save();
  371. }
  372. break;
  373. case 'paid-by-credit':
  374. if (in_array($newStatus, $orderStatusArray[$this->status]['nextStatusAllow'])) {
  375. $this->addOrderStatusHistory($newStatus, $origin);
  376. $this->status = $newStatus;
  377. $this->save();
  378. }
  379. break;
  380. case 'waiting-delevery' :
  381. if (in_array($newStatus, $orderStatusArray[$this->status]['nextStatusAllow'])) {
  382. $this->addOrderStatusHistory($newStatus, $origin);
  383. $this->status = $newStatus;
  384. $this->save();
  385. }
  386. break;
  387. case 'delivered':
  388. if (in_array($newStatus, $orderStatusArray[$this->status]['nextStatusAllow'])) {
  389. $this->addOrderStatusHistory($newStatus, $origin);
  390. $this->status = $newStatus;
  391. $this->save();
  392. }
  393. break;
  394. case 'refunded':
  395. if (in_array($newStatus, $orderStatusArray[$this->status]['nextStatusAllow'])) {
  396. $this->addOrderStatusHistory($newStatus, $origin);
  397. $this->status = $newStatus;
  398. $this->save();
  399. }
  400. break;
  401. case 'cancel':
  402. if (in_array($newStatus, $orderStatusArray[$this->status]['nextStatusAllow'])) {
  403. $this->addOrderStatusHistory($newStatus, $origin);
  404. $this->status = $newStatus;
  405. $this->save();
  406. }
  407. break;
  408. default:
  409. throw new NotFoundHttpException('Statut de commande inconnu.');
  410. break;
  411. }
  412. }
  413. public function addOrderStatusHistory($newStatus, $origin)
  414. {
  415. $orderStatusHistory = new OrderStatusHistory();
  416. $orderStatusHistory->id_user = UserModel::getCurrentId();
  417. $orderStatusHistory->id_order = $this->id;
  418. $orderStatusHistory->status = $newStatus;
  419. $orderStatusHistory->origin = $origin;
  420. $orderStatusHistory->date = date('Y-m-d H:i:s');
  421. $orderStatusHistory->save();
  422. }
  423. /**
  424. * Retourne le montant de la commande (total, payé, restant, ou en surplus).
  425. *
  426. * @param boolean $format
  427. * @return float
  428. */
  429. public function getAmount($type = self::AMOUNT_TOTAL, $format = false)
  430. {
  431. $amount = $this->amount;
  432. if ($type == self::INVOICE_AMOUNT_TOTAL && $this->invoice_amount) {
  433. $amount = $this->invoice_amount;
  434. }
  435. return $this->_getAmountGeneric($type, $amount, $format);
  436. }
  437. public function getAmountWithTax($type = self::AMOUNT_TOTAL, $format = false)
  438. {
  439. $amount = $this->amount + $this->getTotalVat($type);
  440. if ($type == self::INVOICE_AMOUNT_TOTAL && $this->invoice_amount) {
  441. $amount = $this->invoice_amount + $this->getTotalVat($type);
  442. }
  443. return $this->_getAmountGeneric($type, $amount, $format);
  444. }
  445. protected function _getAmountGeneric($type, $amountOrder, $format)
  446. {
  447. switch ($type) {
  448. case self::AMOUNT_TOTAL :
  449. case self::INVOICE_AMOUNT_TOTAL :
  450. $amount = $amountOrder;
  451. break;
  452. case self::AMOUNT_PAID :
  453. $this->initPaidAmount();
  454. $amount = $this->paid_amount;
  455. break;
  456. case self::AMOUNT_REMAINING :
  457. $amount = $this->getAmountWithTax(self::AMOUNT_TOTAL)
  458. - $this->getAmountWithTax(self::AMOUNT_PAID);
  459. break;
  460. case self::AMOUNT_SURPLUS :
  461. $amount = $this->getAmountWithTax(self::AMOUNT_PAID)
  462. - $this->getAmountWithTax(self::AMOUNT_TOTAL);
  463. break;
  464. }
  465. if ($format) {
  466. return Price::format($amount);
  467. } else {
  468. return $amount;
  469. }
  470. }
  471. /**
  472. * Retourne les informations relatives à la commande au format JSON.
  473. *
  474. * @return string
  475. */
  476. public function getDataJson()
  477. {
  478. $order = Order::searchOne(['order.id' => $this->id]);
  479. $jsonOrder = [];
  480. if ($order) {
  481. $jsonOrder = [
  482. 'products' => [],
  483. 'amount' => $order->amount,
  484. 'str_amount' => $order->getAmountWithTax(self::AMOUNT_TOTAL, true),
  485. 'paid_amount' => $order->getAmount(self::AMOUNT_PAID),
  486. 'comment' => $order->comment,
  487. ];
  488. foreach ($order->productOrder as $productOrder) {
  489. $jsonOrder['products'][$productOrder->id_product] = $productOrder->quantity;
  490. }
  491. }
  492. return json_encode($jsonOrder);
  493. }
  494. /**
  495. * Enregistre un modèle de type CreditHistory.
  496. *
  497. * @param string $type
  498. * @param float $montant
  499. * @param integer $idProducer
  500. * @param integer $idUser
  501. * @param integer $idUserAction
  502. */
  503. public function saveCreditHistory($type, $amount, $idProducer, $idUser, $idUserAction)
  504. {
  505. $creditHistoryService = Yii::$app->logic->getCreditHistoryContainer()->getService();
  506. $creditHistory = new CreditHistory;
  507. $creditHistory->id_user = $idUser;
  508. $creditHistory->id_order = $this->id;
  509. $creditHistory->amount = round($amount, 2);
  510. $creditHistory->type = $type;
  511. $creditHistory->id_producer = $idProducer;
  512. $creditHistory->id_user_action = $idUserAction;
  513. $creditHistory->populateRelation('order', $this);
  514. $creditHistory->populateRelation('user', UserModel::find()->where(['id' => $this->id_user])->one());
  515. $creditHistoryService->save($creditHistory);
  516. }
  517. /**
  518. * Ajuste le crédit pour que la commande soit payée.
  519. *
  520. * @return boolean
  521. */
  522. public function processCredit()
  523. {
  524. if ($this->id_user) {
  525. $paymentStatus = $this->getPaymentStatus();
  526. echo $paymentStatus;
  527. if ($paymentStatus == self::PAYMENT_PAID) {
  528. return true;
  529. } elseif ($paymentStatus == self::PAYMENT_SURPLUS) {
  530. $type = CreditHistoryModel::TYPE_REFUND;
  531. $amount = $this->getAmount(self::AMOUNT_SURPLUS);
  532. } elseif ($paymentStatus == self::PAYMENT_UNPAID) {
  533. $type = CreditHistoryModel::TYPE_PAYMENT;
  534. $amount = $this->getAmount(self::AMOUNT_REMAINING);
  535. }
  536. $this->saveCreditHistory(
  537. $type,
  538. $amount,
  539. GlobalParam::getCurrentProducerId(),
  540. $this->id_user,
  541. UserModel::getCurrentId()
  542. );
  543. }
  544. }
  545. public function setTillerSynchronization()
  546. {
  547. $order = Order::searchOne(['id' => $this->id]);
  548. $paymentStatus = $order->getPaymentStatus();
  549. if ($paymentStatus == self::PAYMENT_PAID) {
  550. $order->tiller_synchronization = 1;
  551. } else {
  552. $order->tiller_synchronization = 0;
  553. }
  554. $order->save();
  555. return $order;
  556. }
  557. /**
  558. * Retourne le statut de paiement de la commande (payée, surplus, ou impayée).
  559. *
  560. * @return string
  561. */
  562. public function getPaymentStatus()
  563. {
  564. // payé
  565. if ($this->getAmountWithtax() - $this->getAmount(self::AMOUNT_PAID) < 0.01 &&
  566. $this->getAmountWithtax() - $this->getAmount(self::AMOUNT_PAID) > -0.01) {
  567. return self::PAYMENT_PAID;
  568. } // à rembourser
  569. elseif ($this->getAmountWithtax() - $this->getAmount(self::AMOUNT_PAID) <= -0.01) {
  570. return self::PAYMENT_SURPLUS;
  571. } // reste à payer
  572. elseif ($this->getAmountWithtax() - $this->getAmount(self::AMOUNT_PAID) >= 0.01) {
  573. return self::PAYMENT_UNPAID;
  574. }
  575. }
  576. /**
  577. * Retourne le résumé du panier au format HTML.
  578. *
  579. * @return string
  580. */
  581. public function getCartSummary($htmlFormat = true)
  582. {
  583. if (!isset($this->productOrder)) {
  584. $this->productOrder = productOrder::find()->where(['id_order' => $this->id])->all();
  585. }
  586. $html = '';
  587. $count = count($this->productOrder);
  588. $i = 0;
  589. foreach ($this->productOrder as $p) {
  590. if (isset($p->product)) {
  591. $html .= Html::encode($p->product->name) . ' (' . $p->quantity . '&nbsp;' . Product::strUnit(
  592. $p->unit,
  593. 'wording_short',
  594. true
  595. ) . ')';
  596. if (++$i != $count) {
  597. if ($htmlFormat) {
  598. $html .= '<br />';
  599. } else {
  600. $html .= "\n";
  601. }
  602. }
  603. }
  604. }
  605. return $html;
  606. }
  607. /**
  608. * Retourne le résumé du point de vente lié à la commande au format HTML.
  609. *
  610. * @return string
  611. */
  612. public function getPointSaleSummary()
  613. {
  614. $html = '';
  615. if (isset($this->pointSale)) {
  616. $html .= '<span class="name-point-sale">' .
  617. Html::encode($this->pointSale->name) .
  618. '</span>' .
  619. '<br /><span class="locality">'
  620. . Html::encode($this->pointSale->locality)
  621. . '</span>';
  622. if (strlen($this->comment_point_sale)) {
  623. $html .= '<div class="comment"><span>'
  624. . Html::encode($this->comment_point_sale)
  625. . '</span></div>';
  626. }
  627. } else {
  628. $html .= 'Point de vente supprimé';
  629. }
  630. return $html;
  631. }
  632. /**
  633. * Retourne le résumé du paiement (montant, statut).
  634. *
  635. * @return string
  636. */
  637. public function getAmountSummary()
  638. {
  639. $html = '';
  640. $creditActive = ProducerModel::getConfig('credit');
  641. $html .= $this->getAmountWithTax(self::AMOUNT_TOTAL, true);
  642. if ($creditActive) {
  643. $html .= '<br />';
  644. if ($this->paid_amount) {
  645. if ($this->getPaymentStatus() == Order::PAYMENT_PAID) {
  646. $html .= '<span class="label label-success">Payée</span>';
  647. } elseif ($this->getPaymentStatus() == Order::PAYMENT_UNPAID) {
  648. $html .= '<span class="label label-danger">Non payée</span><br />
  649. Reste <strong>' . $this->getAmount(
  650. Order::AMOUNT_REMAINING,
  651. true
  652. ) . '</strong> à payer';
  653. } elseif ($this->getPaymentStatus() == Order::PAYMENT_SURPLUS) {
  654. $html .= '<span class="label label-success">Payée</span>';
  655. }
  656. } else {
  657. $html .= '<span class="label label-default">Non réglé</span>';
  658. }
  659. }
  660. return $html;
  661. }
  662. /**
  663. * Retourne une chaine de caractère décrivant l'utilisateur lié à la commande.
  664. *
  665. * @return string
  666. */
  667. public function getStrUser()
  668. {
  669. if (isset($this->user)) {
  670. if (isset($this->user->name_legal_person) && strlen($this->user->name_legal_person)) {
  671. return Html::encode($this->user->name_legal_person);
  672. } else {
  673. $strUser = $this->user->lastname;
  674. if($this->user->lastname && $this->user->name) {
  675. $strUser .= ' '.$this->user->name;
  676. }
  677. return Html::encode($strUser);
  678. }
  679. } elseif (strlen($this->username)) {
  680. return Html::encode($this->username);
  681. } else {
  682. return 'Client introuvable';
  683. }
  684. }
  685. /**
  686. * Retourne l'état de la commande (livrée, modifiable ou en préparation)
  687. *
  688. * @return string
  689. */
  690. public function getState()
  691. {
  692. $orderDate = strtotime($this->distribution->date);
  693. $today = strtotime(date('Y-m-d'));
  694. $todayHour = date('G');
  695. $dayDistribution = strtolower(date('l', strtotime($this->distribution->date)));
  696. $orderDelay = ProducerModel::getConfig(
  697. 'order_delay',
  698. $this->distribution->id_producer
  699. );
  700. $orderDelaySpecific = ProducerModel::getConfig(
  701. 'order_delay_' . $dayDistribution,
  702. $this->distribution->id_producer
  703. );
  704. if ($orderDelaySpecific) {
  705. $orderDelay = $orderDelaySpecific;
  706. }
  707. $orderDeadline = ProducerModel::getConfig(
  708. 'order_deadline',
  709. $this->distribution->id_producer
  710. );
  711. $orderDeadlineSpecific = ProducerModel::getConfig(
  712. 'order_deadline_' . $dayDistribution,
  713. $this->distribution->id_producer
  714. );
  715. if ($orderDeadlineSpecific) {
  716. $orderDeadline = $orderDeadlineSpecific;
  717. }
  718. $nbDays = (int)round((($orderDate - $today) / (24 * 60 * 60)));
  719. if ($nbDays <= 0) {
  720. return self::STATE_DELIVERED;
  721. } elseif ($nbDays >= $orderDelay &&
  722. ($nbDays != $orderDelay ||
  723. ($nbDays == $orderDelay && $todayHour < $orderDeadline))) {
  724. return self::STATE_OPEN;
  725. }
  726. return self::STATE_PREPARATION;
  727. }
  728. /**
  729. * Retourne l'origine de la commande (client, automatique ou admin) sous forme
  730. * texte ou HTML.
  731. *
  732. * @param boolean $with_label
  733. * @return string
  734. */
  735. public function getStrOrigin($withLabel = false)
  736. {
  737. $classLabel = '';
  738. $str = '';
  739. if ($this->origin == self::ORIGIN_USER) {
  740. $classLabel = 'success';
  741. $str = 'Client';
  742. } elseif ($this->origin == self::ORIGIN_AUTO) {
  743. $classLabel = 'default';
  744. $str = 'Auto';
  745. } elseif ($this->origin == self::ORIGIN_ADMIN) {
  746. $classLabel = 'warning';
  747. $str = 'Vous';
  748. }
  749. if ($withLabel) {
  750. return '<span class="label label-' . $classLabel . '">'
  751. . $str . '</span>';
  752. } else {
  753. return $str;
  754. }
  755. }
  756. /**
  757. * Retourne l'historique de la commande (ajoutée, modifiée, supprimée) au
  758. * format HTML.
  759. *
  760. * @return string
  761. */
  762. public function getStrHistory()
  763. {
  764. $arr = [
  765. 'class' => 'create',
  766. 'glyphicon' => 'plus',
  767. 'str' => 'Ajoutée',
  768. 'date' => $this->date
  769. ];
  770. if (!is_null($this->date_update)) {
  771. $arr = [
  772. 'class' => 'update',
  773. 'glyphicon' => 'pencil',
  774. 'str' => 'Modifiée',
  775. 'date' => $this->date_update
  776. ];
  777. }
  778. if (!is_null($this->date_delete)) {
  779. $arr = [
  780. 'class' => 'delete',
  781. 'glyphicon' => 'remove',
  782. 'str' => 'Annulée',
  783. 'date' => $this->date_delete
  784. ];
  785. }
  786. $html = '<div class="small"><span class="' . $arr['class'] . '">'
  787. . '<span class="glyphicon glyphicon-' . $arr['glyphicon'] . '"></span> '
  788. . $arr['str'] . '</span> le <strong>'
  789. . date('d/m/Y à G\hi', strtotime($arr['date'])) . '</strong></div>';
  790. return $html;
  791. }
  792. /**
  793. * Retourne une classe identifiant l'historique de la commande (ajoutée,
  794. * modifiée, supprimée).
  795. *
  796. * @return string
  797. */
  798. public function getClassHistory()
  799. {
  800. if (!is_null($this->date_delete)) {
  801. return 'commande-delete';
  802. }
  803. if (!is_null($this->date_update)) {
  804. return 'commande-update';
  805. }
  806. return 'commande-create';
  807. }
  808. /**
  809. * Retourne la quantité d'un produit donné de plusieurs commandes.
  810. *
  811. * @param integer $idProduct
  812. * @param array $orders
  813. * @param boolean $ignoreCancel
  814. *
  815. * @return integer
  816. */
  817. public static function getProductQuantity($idProduct, $orders, $ignoreCancel = false, $unit = null)
  818. {
  819. $quantity = 0;
  820. if (isset($orders) && is_array($orders) && count($orders)) {
  821. foreach ($orders as $c) {
  822. if (is_null($c->date_delete) || $ignoreCancel) {
  823. foreach ($c->productOrder as $po) {
  824. if ($po->id_product == $idProduct &&
  825. ((is_null($unit) && $po->product->unit == $po->unit) || (!is_null($unit) && strlen(
  826. $unit
  827. ) && $po->unit == $unit))) {
  828. $quantity += $po->quantity;
  829. }
  830. }
  831. }
  832. }
  833. }
  834. return $quantity;
  835. }
  836. public static function getProductQuantityPieces($idProduct, $orders)
  837. {
  838. $quantity = 0;
  839. if (isset($orders) && is_array($orders) && count($orders)) {
  840. foreach ($orders as $c) {
  841. if (is_null($c->date_delete)) {
  842. foreach ($c->productOrder as $po) {
  843. if ($po->id_product == $idProduct) {
  844. if ($po->unit == 'piece') {
  845. $quantity += $po->quantity;
  846. } else {
  847. if (isset($po->product) && $po->product->weight > 0) {
  848. $quantity += ($po->quantity * Product::$unitsArray[$po->unit]['coefficient']) / $po->product->weight;
  849. }
  850. }
  851. }
  852. }
  853. }
  854. }
  855. }
  856. return $quantity;
  857. }
  858. /**
  859. * Recherche et initialise des commandes.
  860. *
  861. * @param array $params
  862. * @param array $conditions
  863. * @param string $orderby
  864. * @param integer $limit
  865. * @return array
  866. */
  867. public static function searchBy($params = [], $options = [])
  868. {
  869. $orders = parent::searchBy($params, $options);
  870. /*
  871. * Initialisation des commandes
  872. */
  873. if (is_array($orders)) {
  874. if (count($orders)) {
  875. foreach ($orders as $order) {
  876. if (is_a($order, 'common\models\Order')) {
  877. $order->init();
  878. }
  879. }
  880. return $orders;
  881. }
  882. } else {
  883. $order = $orders;
  884. if (is_a($order, 'common\models\Order')) {
  885. return $order->init();
  886. } // count
  887. else {
  888. return $order;
  889. }
  890. }
  891. return false;
  892. }
  893. /**
  894. * Retourne le nombre de produits commandés
  895. *
  896. * @return integer
  897. */
  898. public function countProducts()
  899. {
  900. $count = 0;
  901. if ($this->productOrder && is_array($this->productOrder)) {
  902. return count($this->productOrder);
  903. }
  904. return 0;
  905. }
  906. /**
  907. * Retourne un bloc html présentant une date.
  908. *
  909. * @return string
  910. */
  911. public function getBlockDate()
  912. {
  913. return '<div class="block-date">
  914. <div class="day">' . strftime('%A', strtotime($this->distribution->date)) . '</div>
  915. <div class="num">' . date('d', strtotime($this->distribution->date)) . '</div>
  916. <div class="month">' . strftime('%B', strtotime($this->distribution->date)) . '</div>
  917. </div>';
  918. }
  919. public function getUsername()
  920. {
  921. $username = '';
  922. if ($this->user) {
  923. $username = $this->user->getUsername();
  924. }
  925. if (strlen($this->username)) {
  926. $username = $this->username;
  927. }
  928. return $username;
  929. }
  930. public function initInvoicePrices($params = [])
  931. {
  932. foreach ($this->productOrder as $productOrder) {
  933. if ($productOrder->product) {
  934. $productOrder->invoice_price = $productOrder->product->getPrice([
  935. 'user' => isset($params['user']) ? $params['user'] : null,
  936. 'user_producer' => isset($params['user_producer']) ? $params['user_producer'] : null,
  937. 'point_sale' => isset($params['point_sale']) ? $params['point_sale'] : null,
  938. 'quantity' => $productOrder->quantity
  939. ]);
  940. $productOrder->save();
  941. }
  942. }
  943. }
  944. public function initReference()
  945. {
  946. $idProducer = GlobalParam::getCurrentProducerId();
  947. $producer = ProducerModel::findOne($idProducer);
  948. if (!$this->reference && $producer->option_order_reference_type == ProducerModel::ORDER_REFERENCE_TYPE_YEARLY) {
  949. $lastOrder = Order::find()->innerJoinWith('distribution', true)
  950. ->where(['>=', 'distribution.date', date('Y') . '-01-01'])
  951. ->andWhere([
  952. 'distribution.id_producer' => $producer->id
  953. ])
  954. ->andWhere(['not', ['order.reference' => null]])
  955. ->orderBy('order.reference DESC')
  956. ->one();
  957. if ($lastOrder && $lastOrder->reference && strlen($lastOrder->reference) > 0) {
  958. $pattern = '#A([0-9]+)C([0-9]+)#';
  959. preg_match($pattern, $lastOrder->reference, $matches, PREG_OFFSET_CAPTURE);
  960. $sizeNumReference = strlen($matches[2][0]);
  961. $numReference = ((int)$matches[2][0]) + 1;
  962. $numReference = str_pad($numReference, $sizeNumReference, '0', STR_PAD_LEFT);
  963. $this->reference = 'A' . $matches[1][0] . 'C' . $numReference;
  964. } else {
  965. $this->reference = 'A' . date('y') . 'C0001';
  966. }
  967. $this->save();
  968. }
  969. }
  970. public function getCommentReport()
  971. {
  972. $comment = '';
  973. $hasComment = false;
  974. if ($this->comment && strlen($this->comment) > 0) {
  975. $hasComment = true;
  976. $comment .= $this->comment;
  977. }
  978. if ($this->delivery_home && $this->delivery_address && strlen($this->delivery_address) > 0) {
  979. if ($hasComment) {
  980. $comment .= '<br /><br />';
  981. }
  982. $comment .= '<strong>Livraison à domicile :</strong><br />';
  983. $comment .= nl2br($this->delivery_address);
  984. }
  985. return $comment;
  986. }
  987. public function isLinkedToValidDocument()
  988. {
  989. return ($this->deliveryNote && $this->deliveryNote->isStatusValid())
  990. || ($this->quotation && $this->quotation->isStatusValid())
  991. || ($this->invoice && $this->invoice->isStatusValid());
  992. }
  993. }