Nelze vybrat více než 25 témat Téma musí začínat písmenem nebo číslem, může obsahovat pomlčky („-“) a může být dlouhé až 35 znaků.

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