Ви не можете вибрати більше 25 тем Теми мають розпочинатися з літери або цифри, можуть містити дефіси (-) і не повинні перевищувати 35 символів.

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