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ů.

419 lines
17KB

  1. <?php
  2. namespace Lc\CaracoleBundle\Builder\Order;
  3. use Doctrine\ORM\EntityManagerInterface;
  4. use Lc\CaracoleBundle\Builder\File\DocumentBuilder;
  5. use Lc\CaracoleBundle\Event\Order\OrderShopChangeStatusEvent;
  6. use Lc\CaracoleBundle\Factory\File\DocumentFactory;
  7. use Lc\CaracoleBundle\Factory\Order\OrderPaymentFactory;
  8. use Lc\CaracoleBundle\Factory\Order\OrderProductReductionCatalogFactory;
  9. use Lc\CaracoleBundle\Factory\Order\OrderReductionCartFactory;
  10. use Lc\CaracoleBundle\Factory\Order\OrderReductionCreditFactory;
  11. use Lc\CaracoleBundle\Factory\Order\OrderShopFactory;
  12. use Lc\CaracoleBundle\Factory\Order\OrderStatusHistoryFactory;
  13. use Lc\CaracoleBundle\Model\File\DocumentInterface;
  14. use Lc\CaracoleBundle\Model\File\DocumentModel;
  15. use Lc\CaracoleBundle\Model\Order\OrderProductInterface;
  16. use Lc\CaracoleBundle\Model\Order\OrderReductionCartInterface;
  17. use Lc\CaracoleBundle\Model\Order\OrderReductionCreditInterface;
  18. use Lc\CaracoleBundle\Model\Order\OrderShopInterface;
  19. use Lc\CaracoleBundle\Model\Order\OrderStatusInterface;
  20. use Lc\CaracoleBundle\Model\Order\OrderStatusModel;
  21. use Lc\CaracoleBundle\Model\Product\ProductFamilyModel;
  22. use Lc\CaracoleBundle\Model\Reduction\ReductionCartInterface;
  23. use Lc\CaracoleBundle\Model\Reduction\ReductionCreditInterface;
  24. use Lc\CaracoleBundle\Model\Section\SectionInterface;
  25. use Lc\CaracoleBundle\Model\User\VisitorInterface;
  26. use Lc\CaracoleBundle\Repository\Order\OrderProductStore;
  27. use Lc\CaracoleBundle\Repository\Order\OrderShopStore;
  28. use Lc\CaracoleBundle\Repository\Order\OrderStatusStore;
  29. use Lc\CaracoleBundle\Repository\Product\ProductFamilyStore;
  30. use Lc\CaracoleBundle\Resolver\Price\PriceResolver;
  31. use Lc\CaracoleBundle\Solver\Price\PriceSolver;
  32. use Lc\SovBundle\Model\User\UserInterface;
  33. use Symfony\Component\EventDispatcher\EventDispatcherInterface;
  34. use Symfony\Component\HttpFoundation\Session\Flash\FlashBagInterface;
  35. class OrderShopBuilder
  36. {
  37. protected EntityManagerInterface $entityManager;
  38. protected OrderStatusStore $orderStatusStore;
  39. protected OrderProductStore $orderProductStore;
  40. protected OrderShopStore $orderShopStore;
  41. protected ProductFamilyStore $productFamilyStore;
  42. protected PriceSolver $priceSolver;
  43. protected OrderProductBuilder $orderProductBuilder;
  44. protected DocumentBuilder $documentBuilder;
  45. protected EventDispatcherInterface $eventDispatcher;
  46. protected FlashBagInterface $flashBag;
  47. public function __construct(
  48. EntityManagerInterface $entityManager,
  49. OrderShopStore $orderShopStore,
  50. OrderStatusStore $orderStatusStore,
  51. OrderProductStore $orderProductStore,
  52. ProductFamilyStore $productFamilyStore,
  53. OrderProductBuilder $orderProductBuilder,
  54. DocumentBuilder $documentBuilder,
  55. PriceSolver $priceSolver,
  56. EventDispatcherInterface $eventDispatcher,
  57. FlashBagInterface $flashBag
  58. ) {
  59. $this->entityManager = $entityManager;
  60. $this->orderShopStore = $orderShopStore;
  61. $this->orderStatusStore = $orderStatusStore;
  62. $this->orderProductStore = $orderProductStore;
  63. $this->productFamilyStore = $productFamilyStore;
  64. $this->orderProductBuilder = $orderProductBuilder;
  65. $this->documentBuilder = $documentBuilder;
  66. $this->priceSolver = $priceSolver;
  67. $this->eventDispatcher = $eventDispatcher;
  68. $this->flashBag = $flashBag;
  69. }
  70. public function create(
  71. SectionInterface $section,
  72. UserInterface $user = null,
  73. VisitorInterface $visitor = null
  74. ): OrderShopInterface {
  75. $orderShopFactory = new OrderShopFactory();
  76. $orderShop = $orderShopFactory->create($section, $user, $visitor);
  77. $this->setOrderStatus($orderShop, OrderStatusModel::ALIAS_CART);
  78. //TODO flush ???
  79. return $orderShop;
  80. }
  81. public function createIfNotExist(
  82. SectionInterface $section,
  83. UserInterface $user = null,
  84. VisitorInterface $visitor = null
  85. ): OrderShopInterface {
  86. $cart = $this->orderShopStore->getCartBy(
  87. [
  88. 'section' => $section,
  89. 'user' => $user,
  90. 'visitor' => $visitor
  91. ]
  92. );
  93. if (!$cart) {
  94. $cart = $this->create($section, $user, $visitor);
  95. }
  96. return $cart;
  97. }
  98. public function setOrderStatus(
  99. OrderShopInterface $orderShop,
  100. string $alias,
  101. bool $forceByAdmin = false
  102. ): OrderShopInterface {
  103. $orderStatus = $this->orderStatusStore->getRepositoryQuery()->findOneByAlias($alias);
  104. if ($orderStatus) {
  105. if ($orderShop->getOrderStatus() === null
  106. || $orderShop->getOrderStatus()->getNextStatusAllowed()->contains($orderStatus)) {
  107. $this->applyChangeOrderStatus($orderShop, $orderStatus, $forceByAdmin);
  108. }
  109. } else {
  110. throw new \ErrorException('La statut demandé n\'existe pas.');
  111. }
  112. return $orderShop;
  113. }
  114. public function applyChangeOrderStatus(
  115. OrderShopInterface $orderShop,
  116. OrderStatusInterface $orderStatus,
  117. bool $forceByAdmin = false
  118. ): void {
  119. $this->eventDispatcher->dispatch(
  120. new OrderShopChangeStatusEvent($orderShop, $orderStatus, $forceByAdmin),
  121. OrderShopChangeStatusEvent::PRE_CHANGE_STATUS
  122. );
  123. $orderShop->setOrderStatusProtected($orderStatus);
  124. $orderStatusHistoryFactory = new OrderStatusHistoryFactory();
  125. $orderStatusHistory = $orderStatusHistoryFactory->create($orderShop, $orderStatus);
  126. $orderShop->addOrderStatusHistory($orderStatusHistory);
  127. $this->eventDispatcher->dispatch(
  128. new OrderShopChangeStatusEvent($orderShop, $orderStatus, $forceByAdmin),
  129. OrderShopChangeStatusEvent::POST_CHANGE_STATUS
  130. );
  131. }
  132. public function addOrderProduct(
  133. OrderShopInterface $orderShop,
  134. OrderProductInterface $orderProductAdd,
  135. bool $persist = true
  136. ): bool {
  137. $return = false;
  138. if ($this->orderProductStore->isOrderProductAvailableAddCart($orderProductAdd, $orderShop)) {
  139. if ($orderProductAdd->getQuantityOrder() > 0) {
  140. $updated = false;
  141. $this->orderProductBuilder->init($orderProductAdd);
  142. $productFamily = $this->productFamilyStore->getOneBySlug(
  143. $orderProductAdd->getProduct()->getProductFamily()->getSlug()
  144. );
  145. if ($productFamily) {
  146. $reductionCatalog = $productFamily->getReductionCatalog();
  147. if ($reductionCatalog) {
  148. $orderProductReductionCatalogFactory = new OrderProductReductionCatalogFactory();
  149. $orderProductReductionCatalog = $orderProductReductionCatalogFactory->create(
  150. $reductionCatalog->getTitle(),
  151. $reductionCatalog->getValue(),
  152. $reductionCatalog->getUnit(),
  153. $reductionCatalog->getBehaviorTaxRate()
  154. );
  155. $orderProductAdd->setOrderProductReductionCatalog($orderProductReductionCatalog);
  156. }
  157. }
  158. foreach ($orderShop->getOrderProducts() as $orderProduct) {
  159. if ($orderProduct->getProduct()->getId() == $orderProductAdd->getProduct()->getId()
  160. && $orderProduct->getRedelivery() == $orderProductAdd->getRedelivery()
  161. && (string)$this->priceResolver->getPrice($orderProduct)
  162. == (string)$this->priceResolver->getPrice($orderProductAdd)
  163. && $orderProduct->getOrderProductReductionCatalog()->compare(
  164. $orderProductAdd->getOrderProductReductionCatalog()
  165. )) {
  166. $orderProduct->setQuantityOrder(
  167. $orderProduct->getQuantityOrder() + $orderProductAdd->getQuantityOrder()
  168. );
  169. if ($persist) {
  170. $this->entityManager->persist($orderProduct);
  171. }
  172. $updated = true;
  173. $return = true;
  174. break;
  175. }
  176. }
  177. if (!$updated) {
  178. $orderShop->addOrderProduct($orderProductAdd);
  179. if ($persist) {
  180. if (isset($orderProductReductionCatalog)) {
  181. $this->entityManager->create($orderProductReductionCatalog);
  182. }
  183. //TODO est-ce un update ou un create ???
  184. $this->entityManager->update($orderProductAdd);
  185. $this->entityManager->update($orderShop);
  186. }
  187. $return = true;
  188. }
  189. if ($persist) {
  190. $this->entityManager->flush();
  191. }
  192. // @TODO : dispatch event cart change
  193. //$this->eventCartChange($orderShop);
  194. }
  195. } else {
  196. // @TODO : retourner le message d'erreur et faire le addFlash dans le contrôleur
  197. /*$availableQuantity = $orderProductAdd->getProduct()->getAvailableQuantityInherited();
  198. $textError = "Le produit <strong>" . $orderProductAdd->getTitleOrderShop(
  199. ) . "</strong> n'est pas disponible";
  200. if ($availableQuantity !== false && $availableQuantity > 0) {
  201. $unit = '';
  202. if ($orderProductAdd->getProduct()->getProductFamily()->getBehaviorCountStock(
  203. ) == ProductFamily::BEHAVIOR_COUNT_STOCK_BY_MEASURE) {
  204. $unit = $orderProductAdd->getProduct()->getUnitInherited()->getUnitReference()->getUnit();
  205. }
  206. $textError .= ' dans cette quantité ';
  207. $user = $this->security->getUser();
  208. if ($user && $user->hasRole('ROLE_USER')) {
  209. $textError .= '<br />' . $availableQuantity . $unit . ' disponible(s) dont ' . $this->getQuantityOrderByProduct(
  210. $orderShop,
  211. $orderProductAdd->getProduct()
  212. ) . $unit . ' déjà dans votre panier.';
  213. }
  214. }
  215. $this->utils->addFlash('error', $textError);*/
  216. }
  217. return $return;
  218. }
  219. public function merge(
  220. OrderShopInterface $orderShop1,
  221. OrderShopInterface $orderShop2,
  222. $persist = true
  223. ): OrderShopInterface {
  224. if ($orderShop1 && $orderShop2) {
  225. foreach ($orderShop2->getOrderProducts() as $orderProduct) {
  226. $orderProductAlreadyInCart = $orderShop1->hasOrderProductAlreadyInCart($orderProduct);
  227. if ($orderProductAlreadyInCart) {
  228. if ($orderProduct->getQuantityOrder() > $orderProductAlreadyInCart->getQuantityOrder()) {
  229. $orderShop1->removeOrderProduct($orderProductAlreadyInCart);
  230. $this->addOrderProduct($orderShop1, $orderProduct);
  231. }
  232. } else {
  233. $this->addOrderProduct($orderShop1, $orderProduct);
  234. }
  235. if ($persist) {
  236. $this->entityManager->delete($orderProduct);
  237. }
  238. }
  239. if ($persist) {
  240. $this->entityManager->delete($orderShop2);
  241. $this->entityManager->update($orderShop1);
  242. $this->entityManager->flush();
  243. }
  244. return $orderShop1;
  245. }
  246. }
  247. public function addPayment(OrderShopInterface $orderShop, string $meanPayment, float $amount): OrderShopInterface
  248. {
  249. $orderPaymentFactory = new OrderPaymentFactory();
  250. $orderPayment = $orderPaymentFactory->create($orderShop, $meanPayment, $amount);
  251. $orderShop->addOrderPayment($orderPayment);
  252. if ($this->isOrderPaid($orderShop)) {
  253. $nextStatus = OrderStatusModel::ALIAS_PAID;
  254. } else {
  255. $nextStatus = OrderStatusModel::ALIAS_PARTIAL_PAYMENT;
  256. }
  257. if ($orderShop->getOrderStatus()->getAlias() != $nextStatus) {
  258. $orderShop = $this->changeOrderStatus($orderShop, $nextStatus);
  259. }
  260. $this->entityManager->create($orderPayment);
  261. $this->entityManager->update($orderShop);
  262. $this->entityManager->flush();
  263. return $orderShop;
  264. }
  265. public function createDocumentInvoice(OrderShopInterface $orderShop): DocumentInterface
  266. {
  267. $documentFactory = new DocumentFactory();
  268. $document = $documentFactory->create(DocumentModel::TYPE_INVOICE);
  269. $this->documentBuilder->initFromOrderShop($document, $orderShop);
  270. return $document;
  271. }
  272. public function addReductionCart(
  273. OrderShopInterface $orderShop,
  274. ReductionCartInterface $reductionCart
  275. ): ?OrderReductionCartInterface {
  276. $orderReductionCartFactory = new OrderReductionCartFactory();
  277. $orderReductionCart = $orderReductionCartFactory->create($orderShop, $reductionCart);
  278. $orderShop->addOrderReductionCart($orderReductionCart);
  279. if ($this->orderShopStore->isPositiveAmount($orderShop)
  280. && $this->isPositiveAmountRemainingToBePaid($orderShop)) {
  281. $this->entityManager->create($orderReductionCart);
  282. $this->entityManager->flush();
  283. return $orderReductionCart;
  284. } else {
  285. //TODO vérifier ce case ! Avec le null en valeur de retour
  286. $orderShop->removeOrderReductionCart($orderReductionCart);
  287. return null;
  288. }
  289. }
  290. // createOrderReductionCredit
  291. public function addReductionCredit(
  292. OrderShopInterface $orderShop,
  293. ReductionCreditInterface $reductionCredit
  294. ): ?OrderReductionCreditInterface {
  295. $orderReductionCreditFactory = new OrderReductionCreditFactory();
  296. $orderReductionCredit = $orderReductionCreditFactory->create($orderShop, $reductionCredit);
  297. $orderShop->addOrderReductionCredit($orderReductionCredit);
  298. if ($this->isOrderShopPositiveAmount($orderShop)
  299. && $this->isOrderShopPositiveAmountRemainingToBePaid($orderShop)) {
  300. $this->entityManager->create($orderReductionCredit);
  301. $this->entityManager->flush();
  302. return $orderReductionCredit;
  303. } else {
  304. $orderShop->removeOrderReductionCredit($orderReductionCredit);
  305. return null;
  306. }
  307. }
  308. public function deductAvailabilityProduct(OrderShopInterface $orderShop): void
  309. {
  310. foreach ($orderShop->getOrderProducts() as $orderProduct) {
  311. $this->applyDeductAvailabilityProduct($orderShop, $orderProduct);
  312. }
  313. }
  314. public function applyDeductAvailabilityProduct(
  315. OrderShopInterface $orderShop,
  316. OrderProductInterface $orderProduct
  317. ): void {
  318. switch ($orderProduct->getProduct()->getProductFamily()->getBehaviorCountStock()) {
  319. case ProductFamilyModel::BEHAVIOR_COUNT_STOCK_BY_MEASURE :
  320. //Disponibilité par unité de référence
  321. $oldAvailability = $orderProduct->getProduct()->getAvailableQuantityInherited();
  322. $newAvailability = $oldAvailability - ($orderProduct->getQuantityOrder(
  323. ) * ($orderProduct->getQuantityProduct() / $orderProduct->getUnit()->getCoefficient()));
  324. $productFamily = $orderProduct->getProduct()->getProductFamily();
  325. $productFamily->setAvailableQuantity($newAvailability);
  326. $productFamily->setUpdatedBy($orderShop->getUser());
  327. $this->entityManager->update($productFamily);
  328. break;
  329. case ProductFamilyModel::BEHAVIOR_COUNT_STOCK_BY_PRODUCT_FAMILY :
  330. $oldAvailability = $orderProduct->getProduct()->getAvailableQuantityInherited();
  331. $newAvailability = $oldAvailability - $orderProduct->getQuantityOrder();
  332. $productFamily = $orderProduct->getProduct()->getProductFamily();
  333. $productFamily->setAvailableQuantity($newAvailability);
  334. $productFamily->setUpdatedBy($orderShop->getUser());
  335. $this->entityManager->update($productFamily);
  336. break;
  337. case ProductFamilyModel::BEHAVIOR_COUNT_STOCK_BY_PRODUCT :
  338. $oldAvailability = $orderProduct->getProduct()->getAvailableQuantityInherited();
  339. $newAvailability = $oldAvailability - $orderProduct->getQuantityOrder();
  340. $product = $orderProduct->getProduct();
  341. $product->setAvailableQuantity($newAvailability);
  342. $product->setUpdatedBy($orderShop->getUser());
  343. $this->entityManager->update($product);
  344. break;
  345. }
  346. $this->entityManager->flush();
  347. }
  348. }