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.

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