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.

Subscription.php 20KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497
  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\GlobalParam;
  39. use Yii;
  40. use common\components\ActiveRecordCommon;
  41. use common\models\Producer;
  42. use common\models\PointSale;
  43. use common\models\UserPointSale;
  44. use common\models\Order;
  45. use common\models\ProductOrder;
  46. use common\models\User;
  47. /**
  48. * This is the model class for table "commande_auto".
  49. *
  50. * @property integer $id
  51. * @property integer $id_user
  52. * @property integer $id_producer
  53. * @property integer $id_point_sale
  54. * @property string $date_begin
  55. * @property string $date_end
  56. * @property integer $monday
  57. * @property integer $tuesday
  58. * @property integer $wednesday
  59. * @property integer $thursday
  60. * @property integer $friday
  61. * @property integer $saturday
  62. * @property integer $sunday
  63. * @property integer $week_frequency
  64. * @property string $username
  65. * @property string $auto_payment
  66. * @property string $comment
  67. */
  68. class Subscription extends ActiveRecordCommon
  69. {
  70. /**
  71. * @inheritdoc
  72. */
  73. public static function tableName()
  74. {
  75. return 'subscription';
  76. }
  77. /**
  78. * @inheritdoc
  79. */
  80. public function rules()
  81. {
  82. return [
  83. [['id_producer', 'id_point_sale'], 'required'],
  84. [['id_user', 'id_producer', 'id_point_sale', 'monday', 'tuesday',
  85. 'wednesday', 'thursday', 'friday', 'saturday', 'sunday', 'week_frequency'], 'integer'],
  86. [['auto_payment'], 'boolean'],
  87. [['date_begin', 'date_end', 'username', 'comment'], 'safe'],
  88. ];
  89. }
  90. /**
  91. * @inheritdoc
  92. */
  93. public function attributeLabels()
  94. {
  95. return [
  96. 'id' => 'ID',
  97. 'id_user' => 'Utilisateur',
  98. 'id_producer' => 'Etablissement',
  99. 'id_point_sale' => 'Point de vente',
  100. 'date_begin' => 'Date de début',
  101. 'date_end' => 'Date de fin',
  102. 'monday' => 'Lundi',
  103. 'tuesday' => 'Mardi',
  104. 'wednesday' => 'Mercredi',
  105. 'thursday' => 'Jeudi',
  106. 'friday' => 'Vendredi',
  107. 'saturday' => 'Samedi',
  108. 'sunday' => 'Dimanche',
  109. 'week_frequency' => 'Périodicité',
  110. 'auto_payment' => 'Paiement automatique',
  111. 'comment' => 'Commentaire'
  112. ];
  113. }
  114. /*
  115. * Relations
  116. */
  117. public function getUser()
  118. {
  119. return $this->hasOne(User::className(), ['id' => 'id_user']);
  120. }
  121. public function getProducer()
  122. {
  123. return $this->hasOne(
  124. Producer::className(),
  125. ['id' => 'id_producer']
  126. );
  127. }
  128. public function getPointSale()
  129. {
  130. return $this->hasOne(
  131. PointSale::className(),
  132. ['id' => 'id_point_sale']
  133. );
  134. }
  135. public function getProductSubscription()
  136. {
  137. return $this->hasMany(
  138. ProductSubscription::className(),
  139. ['id_subscription' => 'id']
  140. )->with('product');
  141. }
  142. /**
  143. * Retourne les options de base nécessaires à la fonction de recherche.
  144. *
  145. * @return array
  146. */
  147. public static function defaultOptionsSearch()
  148. {
  149. return [
  150. 'with' => ['producer'],
  151. 'join_with' => ['user', 'productSubscription', 'productSubscription.product', 'pointSale'],
  152. 'orderby' => 'user.name ASC',
  153. 'attribute_id_producer' => 'subscription.id_producer'
  154. ];
  155. }
  156. /**
  157. * Ajoute la commande pour une date donnée.
  158. *
  159. * @param string $date
  160. */
  161. public function add($date)
  162. {
  163. // distribution
  164. $distribution = Distribution::searchOne([
  165. 'distribution.date' => date('Y-m-d', strtotime($date))
  166. ]);
  167. if ($distribution && $distribution->active && count($this->productSubscription) && $this->id_point_sale) {
  168. // commande
  169. $order = new Order;
  170. if (strlen($this->username)) {
  171. $order->username = $this->username;
  172. $order->id_user = 0;
  173. } else {
  174. $order->id_user = $this->id_user;
  175. }
  176. $order->date = date('Y-m-d H:i:s');
  177. $order->origin = Order::ORIGIN_AUTO;
  178. $order->id_point_sale = $this->id_point_sale;
  179. $order->id_distribution = $distribution->id;
  180. $order->id_subscription = $this->id;
  181. $order->status = 'tmp-order' ;
  182. if (strlen($this->comment)) {
  183. $order->comment = $this->comment;
  184. }
  185. $pointSale = PointSale::findOne($this->id_point_sale);
  186. if($pointSale) {
  187. $creditFunctioning = $pointSale->getCreditFunctioning();
  188. $order->auto_payment = 0;
  189. if ($order->id_user && Producer::getConfig('credit') && $pointSale->credit) {
  190. if ($creditFunctioning == Producer::CREDIT_FUNCTIONING_OPTIONAL) {
  191. $order->auto_payment = $this->auto_payment;
  192. } elseif ($creditFunctioning == Producer::CREDIT_FUNCTIONING_MANDATORY) {
  193. $order->auto_payment = 1;
  194. } elseif ($creditFunctioning == Producer::CREDIT_FUNCTIONING_USER) {
  195. $user = User::findOne($order->id_user);
  196. $userProducer = UserProducer::searchOne([
  197. 'id_user' => $order->id_user,
  198. 'id_producer' => $distribution->id_producer
  199. ]);
  200. if ($userProducer) {
  201. $order->auto_payment = $userProducer->credit_active;
  202. }
  203. }
  204. }
  205. $order->tiller_synchronization = $order->auto_payment ;
  206. $userPointSale = UserPointSale::searchOne([
  207. 'id_point_sale' => $this->id_point_sale,
  208. 'id_user' => $this->id_user
  209. ]);
  210. if ($userPointSale && strlen($userPointSale->comment)) {
  211. $order->comment_point_sale = $userPointSale->comment;
  212. }
  213. $order->save();
  214. // liaison utilisateur / point de vente
  215. if ($order->id_user) {
  216. $pointSale = PointSale::findOne($this->id_point_sale);
  217. $pointSale->linkUser($order->id_user);
  218. }
  219. // produits
  220. $amountTotal = 0;
  221. $productsAdd = false;
  222. foreach ($this->productSubscription as $productSubscription) {
  223. $productOrder = new ProductOrder;
  224. $productOrder->id_order = $order->id;
  225. $productOrder->id_product = $productSubscription->product->id;
  226. $productOrder->quantity = $productSubscription->quantity;
  227. $productOrder->price = $productSubscription->product->getPrice([
  228. 'id_user' => $this->id_user,
  229. 'id_point_sale' => $this->id_point_sale
  230. ]);
  231. $productOrder->unit = $productSubscription->product->unit;
  232. $productOrder->step = $productSubscription->product->step;
  233. $productOrder->id_tax_rate = $productSubscription->product->taxRate->id;
  234. $productOrder->save();
  235. $productsAdd = true;
  236. }
  237. if (!$productsAdd) {
  238. $order->delete();
  239. }
  240. $order->initReference() ;
  241. }
  242. }
  243. }
  244. /**
  245. * Ajoute les commandes pour une date donnée à partir des abonnements.
  246. *
  247. * @param string $date
  248. * @param boolean $force
  249. */
  250. public static function addAll($date, $force = false)
  251. {
  252. $distribution = Distribution::searchOne([
  253. 'date' => date('Y-m-d', strtotime($date)),
  254. 'id_producer' => GlobalParam::getCurrentProducerId(),
  255. ]);
  256. if ($distribution) {
  257. $arrayOrdersDistribution = Order::searchAll([
  258. Order::tableName() . '.id_distribution' => $distribution->id
  259. ]);
  260. $arraySubscriptions = self::searchByDate($date);
  261. foreach ($arraySubscriptions as $subscription) {
  262. if (!$subscription->hasOrderAlreadyExist($arrayOrdersDistribution)) {
  263. $subscription->add($date);
  264. }
  265. }
  266. }
  267. }
  268. /**
  269. * Informe s'il existe une commande correspond à l'abonnement courant.
  270. *
  271. * @param array $arrayOrders
  272. * @return boolean
  273. */
  274. public function hasOrderAlreadyExist($arrayOrders)
  275. {
  276. if (is_array($arrayOrders) && count($arrayOrders) > 0) {
  277. foreach ($arrayOrders as $order) {
  278. if ((($order->id_user > 0 && $order->id_user == $this->id_user) ||
  279. (!$order->id_user && $order->username == $this->username)) &&
  280. $order->id_point_sale == $this->id_point_sale) {
  281. return true;
  282. }
  283. }
  284. }
  285. return false;
  286. }
  287. /**
  288. * Retourne les abonnements pour une date donnée.
  289. *
  290. * @param string $date
  291. * @return array
  292. */
  293. public static function searchByDate($date)
  294. {
  295. $date = date('Y-m-d', strtotime($date));
  296. $subscriptions = Subscription::searchAll();
  297. $arrSubscriptions = [];
  298. foreach ($subscriptions as $s) {
  299. if ($date >= $s->date_begin &&
  300. (!$s->date_end || $date <= $s->date_end) &&
  301. $s->matchWith($date)) {
  302. $arrSubscriptions[] = $s;
  303. }
  304. }
  305. return $arrSubscriptions;
  306. }
  307. /**
  308. * Valide le fait qu'un abonnement est bien compatible avec une date donnée.
  309. *
  310. * @param string $date
  311. * @return boolean
  312. */
  313. public function matchWith($date)
  314. {
  315. $arrayDays = [
  316. 1 => 'monday',
  317. 2 => 'tuesday',
  318. 3 => 'wednesday',
  319. 4 => 'thursday',
  320. 5 => 'friday',
  321. 6 => 'saturday',
  322. 7 => 'sunday'
  323. ];
  324. $nbDays = (strtotime($date) - strtotime($this->date_begin)) / (24 * 60 * 60);
  325. if (round($nbDays) % ($this->week_frequency * 7) < 7) {
  326. $numDay = date('N', strtotime($date));
  327. $day = $arrayDays[$numDay];
  328. if ($this->$day) {
  329. return true;
  330. }
  331. }
  332. return false;
  333. }
  334. /**
  335. * Recherche les distributions futures où l'abonnement peut s'appliquer.
  336. *
  337. * @return array
  338. */
  339. public function searchMatchedIncomingDistributions()
  340. {
  341. $producer = GlobalParam::getCurrentProducer();
  342. $params = [
  343. ':date_earliest_order' => date('Y-m-d'),
  344. ':date_begin' => date('Y-m-d', strtotime($this->date_begin)),
  345. ':id_producer' => GlobalParam::getCurrentProducerId()
  346. ];
  347. $incomingDistributions = Distribution::find()
  348. ->where('id_producer = :id_producer')
  349. ->andWhere('date >= :date_begin')
  350. ->andWhere('date >= :date_earliest_order');
  351. if ($this->date_end) {
  352. $incomingDistributions->andWhere('date < :date_end');
  353. $params[':date_end'] = date('Y-m-d', strtotime($this->date_end));
  354. }
  355. $incomingDistributions->orderBy('date ASC');
  356. $incomingDistributions->params($params);
  357. $incomingDistributionsArray = $incomingDistributions->all();
  358. $incomingDistributions = Distribution::filterDistributionsByDateDelay($incomingDistributionsArray) ;
  359. $matchedIncomingDistributionsArray = [];
  360. foreach ($incomingDistributionsArray as $incomingDistribution) {
  361. if ($this->matchWith($incomingDistribution->date)) {
  362. $matchedIncomingDistributionsArray[] = $incomingDistribution;
  363. }
  364. }
  365. return $matchedIncomingDistributionsArray;
  366. }
  367. public function deleteOrdersIncomingDistributions()
  368. {
  369. $params = [
  370. ':id_producer' => GlobalParam::getCurrentProducerId(),
  371. ':date_today' => date('Y-m-d'),
  372. ':date_begin' => $this->date_begin,
  373. ':id_subscription' => $this->id
  374. ];
  375. $orderDeadline = Producer::getConfig('order_deadline');
  376. $hour = date('G');
  377. if ($hour >= $orderDeadline) {
  378. $conditionDistributionDate = 'distribution.date > :date_today';
  379. } else {
  380. $conditionDistributionDate = 'distribution.date >= :date_today';
  381. }
  382. $orders = Order::find()
  383. ->joinWith('distribution')
  384. ->where('distribution.id_producer = :id_producer')
  385. ->andWhere($conditionDistributionDate)
  386. ->andWhere('distribution.date >= :date_begin')
  387. ->andWhere('order.id_subscription = :id_subscription');
  388. if ($this->date_end) {
  389. $orders->andWhere('distribution.date <= :date_end');
  390. $params[':date_end'] = $this->date_end;
  391. }
  392. $orders->params($params);
  393. $ordersArray = $orders->all();
  394. $configCredit = Producer::getConfig('credit');
  395. if ($ordersArray && count($ordersArray)) {
  396. foreach ($ordersArray as $order) {
  397. $theOrder = Order::searchOne(['id' => $order->id]);
  398. // remboursement de la commande
  399. if ($theOrder->id_user && $theOrder->getAmount(Order::AMOUNT_PAID) && $configCredit) {
  400. $theOrder->saveCreditHistory(
  401. CreditHistory::TYPE_REFUND,
  402. $theOrder->getAmount(Order::AMOUNT_PAID),
  403. $theOrder->distribution->id_producer,
  404. $theOrder->id_user,
  405. User::getCurrentId()
  406. );
  407. }
  408. ProductOrder::deleteAll(['id_order' => $order->id]);
  409. $order->delete();
  410. }
  411. }
  412. }
  413. public function updateIncomingDistributions($update = false)
  414. {
  415. $matchedDistributionsArray = $this->searchMatchedIncomingDistributions();
  416. if ($update) {
  417. $this->deleteOrdersIncomingDistributions();
  418. }
  419. if (count($matchedDistributionsArray)) {
  420. foreach ($matchedDistributionsArray as $distribution) {
  421. $this->add($distribution->date);
  422. }
  423. }
  424. }
  425. public function getUsername()
  426. {
  427. if($this->user) {
  428. return $this->user->getUsername() ;
  429. }
  430. return $this->username ;
  431. }
  432. }