src/Entity/Cart.php line 14

Open in your IDE?
  1. <?php
  2. namespace App\Entity;
  3. use Doctrine\ORM\Mapping as ORM;
  4. use Doctrine\Common\Collections\ArrayCollection;
  5. use App\Entity\Product;
  6. /**
  7. * @ORM\Table(name="carts")
  8. * @ORM\Entity(repositoryClass="App\Repository\CartRepository")
  9. * @ORM\HasLifecycleCallbacks()
  10. */
  11. class Cart
  12. {
  13. /**
  14. * @var int
  15. *
  16. * @ORM\Column(name="id", type="integer", nullable=false)
  17. * @ORM\Id
  18. * @ORM\GeneratedValue(strategy="IDENTITY")
  19. */
  20. private $id;
  21. /**
  22. * @var \App\Entity\Customer
  23. *
  24. * @ORM\ManyToOne(targetEntity="App\Entity\Customer")
  25. * @ORM\JoinColumn(name="customer_id", referencedColumnName="customers_id", nullable=true)
  26. */
  27. private $customer;
  28. /**
  29. * @var array
  30. *
  31. * @ORM\OneToMany(targetEntity="App\Entity\CartItem", mappedBy="cart", cascade={"persist", "remove"})
  32. */
  33. private $items = [];
  34. /**
  35. * @var \App\Entity\PriceGroup|null
  36. *
  37. * @ORM\ManyToOne(targetEntity="App\Entity\PriceGroup")
  38. * @ORM\JoinColumn(name="price_group_id", referencedColumnName="id", nullable=true, onDelete="SET NULL")
  39. */
  40. private $priceGroup;
  41. /**
  42. * @var \App\Entity\Address|null
  43. *
  44. * @ORM\ManyToOne(targetEntity="App\Entity\Address")
  45. * @ORM\JoinColumn(name="shipping_address_id", referencedColumnName="address_book_id", nullable=true, onDelete="SET NULL")
  46. */
  47. private $shippingAddress;
  48. /**
  49. * @var \App\Entity\Address|null
  50. *
  51. * @ORM\ManyToOne(targetEntity="App\Entity\Address")
  52. * @ORM\JoinColumn(name="billing_address_id", referencedColumnName="address_book_id", nullable=true, onDelete="SET NULL")
  53. */
  54. private $billingAddress;
  55. /**
  56. * @var \App\Entity\Carrier|null
  57. *
  58. * @ORM\ManyToOne(targetEntity="App\Entity\Carrier")
  59. * @ORM\JoinColumn(name="carrier_id", referencedColumnName="id", nullable=true, onDelete="SET NULL")
  60. */
  61. private $carrier;
  62. /**
  63. * @var \App\Entity\PaymentMean|null
  64. *
  65. * @ORM\ManyToOne(targetEntity="App\Entity\PaymentMean")
  66. * @ORM\JoinColumn(name="payment_mean_id", referencedColumnName="id", nullable=true)
  67. */
  68. private $paymentMean;
  69. /**
  70. * @var string|null
  71. *
  72. * @ORM\Column(name="shipping_infos", type="string", length=255, nullable=true)
  73. */
  74. private $shippingInfos;
  75. /**
  76. * @var string|null
  77. *
  78. * @ORM\Column(name="comment", type="text", length=1024, nullable=true)
  79. */
  80. private $comment;
  81. /**
  82. * @var \DateTime|null
  83. *
  84. * @ORM\Column(name="created_at", type="datetime", nullable=false)
  85. */
  86. private $createdAt;
  87. /**
  88. * @var \DateTime|null
  89. *
  90. * @ORM\Column(name="updated_at", type="datetime", nullable=true)
  91. */
  92. private $updatedAt;
  93. private $shippingRate;
  94. private $shippingRates = [];
  95. private $coupons = [];
  96. private $pickupStore = null;
  97. private $total = 0;
  98. public function __construct()
  99. {
  100. $this->items = new ArrayCollection();
  101. }
  102. public function getId() {
  103. return $this->id;
  104. }
  105. public function getCustomer(): ?\App\Entity\Customer {
  106. return $this->customer;
  107. }
  108. public function getItems($lang = 'fr') {
  109. if(empty($this->items))
  110. return $this->items;
  111. foreach($this->items as &$item){
  112. if($item->getProduct())
  113. $item->getProduct()->translate($lang);
  114. }
  115. return $this->items;
  116. }
  117. public function getShippingAddress(): ?\App\Entity\Address {
  118. if(empty($this->shippingAddress) && !empty($this->customer))
  119. return $this->getCustomer()->getDefaultAddress();
  120. return $this->shippingAddress;
  121. }
  122. public function getBillingAddress(): ?\App\Entity\Address {
  123. if(empty($this->billingAddress) && !empty($this->customer))
  124. return $this->getCustomer()->getDefaultAddress ();
  125. return $this->billingAddress;
  126. }
  127. public function getCarrier(): ?\App\Entity\Carrier {
  128. return $this->carrier;
  129. }
  130. public function getPaymentMean(): ?\App\Entity\PaymentMean {
  131. return $this->paymentMean;
  132. }
  133. public function getCreatedAt() {
  134. return $this->createdAt;
  135. }
  136. public function getUpdatedAt() {
  137. return $this->updatedAt;
  138. }
  139. public function getLanguageCode() {
  140. $customer = $this->getCustomer();
  141. if($customer){
  142. $address = $customer->getDefaultAddress();
  143. if(in_array($address->getCountry()->getIsoCode2(), ['FR','MQ','GP','FO','YT','NC','RE','GF']))
  144. return 'fr';
  145. return 'en';
  146. }
  147. return 'fr';
  148. }
  149. public function getPickupStore() {
  150. return $this->pickupStore;
  151. }
  152. public function getShippingInfos(): ?string {
  153. return $this->shippingInfos;
  154. }
  155. public function getComment(): ?string {
  156. return $this->comment;
  157. }
  158. public function getPaymentDiscount() {
  159. if(empty($this->paymentMean))
  160. return 0;
  161. $totalProduct = $this->getTotalProducts();
  162. if(($totalProduct > \App\Manager\OrderManager::DIRECT_PAYMENT_DISCOUNT_FROM) && $this->paymentMean->isDirect()){
  163. return \App\Manager\OrderManager::DIRECT_PAYMENT_DISCOUNT * $this->getTotalProducts() * -1;
  164. }
  165. return 0;
  166. }
  167. public function getShippingRate() {
  168. return $this->shippingRate;
  169. }
  170. public function getShippingRateByCarrier(Carrier $carrier) {
  171. foreach($this->getShippingRates() as $shippingRate){
  172. if($shippingRate->getCarrier() == $carrier){
  173. return $shippingRate;
  174. }
  175. }
  176. return null;
  177. }
  178. public function getShippingRates() {
  179. return $this->shippingRates;
  180. }
  181. public function getPriceGroup(): ?\App\Entity\PriceGroup {
  182. return $this->priceGroup;
  183. }
  184. public function setId($id) {
  185. $this->id = $id;
  186. }
  187. public function setCustomer(?\App\Entity\Customer $customer) {
  188. $this->customer = $customer;
  189. }
  190. public function setItems($items) {
  191. $this->items = $items;
  192. $this->init();
  193. }
  194. public function setShippingAddress(?\App\Entity\Address $shippingAddress): void {
  195. $this->shippingAddress = $shippingAddress;
  196. }
  197. public function setBillingAddress(?\App\Entity\Address $billingAddress): void {
  198. $this->billingAddress = $billingAddress;
  199. }
  200. public function setCreatedAt($createdAt) {
  201. $this->createdAt = $createdAt;
  202. }
  203. public function setUpdatedAt($updatedAt) {
  204. $this->updatedAt = $updatedAt;
  205. }
  206. public function setCarrier(?\App\Entity\Carrier $carrier): void {
  207. $this->carrier = $carrier;
  208. }
  209. public function setPaymentMean(?\App\Entity\PaymentMean $paymentMean): void {
  210. $this->paymentMean = $paymentMean;
  211. }
  212. public function setShippingInfos(?string $shippingInfos): void {
  213. $this->shippingInfos = $shippingInfos;
  214. }
  215. public function setPickupStore($pickupStore): void {
  216. $this->pickupStore = $pickupStore;
  217. if($pickupStore){
  218. $this->setShippingInfos($pickupStore->getId());
  219. }
  220. }
  221. public function setComment(?string $comment): void {
  222. $this->comment = $comment;
  223. }
  224. public function setShippingRate($shippingRate): void {
  225. $this->shippingRate = $shippingRate;
  226. }
  227. public function setShippingRates($shippingRates): void {
  228. $this->shippingRates = $shippingRates;
  229. }
  230. public function setPriceGroup(?\App\Entity\PriceGroup $priceGroup): void {
  231. $this->priceGroup = $priceGroup;
  232. }
  233. public function calculate() {
  234. foreach ($this->getItems() as $item){
  235. $this->total += $item->getTotalPrice();
  236. }
  237. return $this->total;
  238. }
  239. public function init() {
  240. $items = $this->getItems();
  241. foreach($this->items as $item){
  242. if($item->getProduct())
  243. $item->getProduct()->translate('fr');
  244. }
  245. return $this->calculate();
  246. }
  247. public function getTotalProducts($withDiscount = false)
  248. {
  249. $total = 0;
  250. $items = [];
  251. foreach($this->getItems() as $item)
  252. {
  253. $total += $item->getTotalPrice();
  254. }
  255. if($withDiscount){
  256. $total += $this->getTotalProductsDiscount();
  257. }
  258. return $total;
  259. }
  260. public function getTotalProductsDiscount()
  261. {
  262. if($this->isExpert()) {
  263. return $this->getTotalProducts() * 0.2 * -1;
  264. }
  265. $total = 0;
  266. if(empty($this->coupons))
  267. return 0;
  268. foreach($this->coupons as $coupon)
  269. {
  270. $total += $coupon->getMarketingRule()->getCartDiscount($this);
  271. }
  272. return $total;
  273. }
  274. public function getTotalProductsWithPaymentDiscount()
  275. {
  276. return $this->getTotalProducts()+$this->getPaymentDiscount();
  277. }
  278. public function getTotalShipping()
  279. {
  280. return $this->carrier ? $this->carrier->getPriceByCart($this) : 0;;
  281. }
  282. public function getTotalTax()
  283. {
  284. if(!$this->hasTax())
  285. return 0;
  286. $tax = 0;
  287. $tax += $this->getTotalProducts(true) * Product::VAT_RATE;
  288. $tax += $this->getTotalShipping() * Carrier::VAT_RATE;
  289. return $tax;
  290. }
  291. public function getTotal()
  292. {
  293. $total = $this->getTotalProducts();
  294. $total += $this->getTotalProductsDiscount();
  295. $total += $this->getPaymentDiscount();
  296. $total += $this->getTotalShipping();
  297. $total += $this->getTotalTax();
  298. return $total>0?$total:0;
  299. }
  300. public function getSoleilTotal()
  301. {
  302. $total = 0;
  303. foreach($this->getItems() as $item)
  304. {
  305. if($item->getProduct()->isSoleil()){
  306. $total += $item->getProduct()->getPrice() * $item->getQuantity();
  307. }
  308. }
  309. return $total;
  310. }
  311. public function getNonSoleilTotal()
  312. {
  313. $total = 0;
  314. foreach($this->getItems() as $item)
  315. {
  316. if($item->getProduct()->isNonSoleil()){
  317. $total += $item->getProduct()->getPrice() * $item->getQuantity();
  318. }
  319. }
  320. return $total;
  321. }
  322. public function getVivogTotal()
  323. {
  324. $total = 0;
  325. foreach($this->getItems() as $item)
  326. {
  327. if($item->getProduct()->isVivog()){
  328. $total += $item->getProduct()->getPrice() * $item->getQuantity();
  329. }
  330. }
  331. return $total;
  332. }
  333. public function getExpertTotal(PriceGroup $priceGroup, $withVat = true)
  334. {
  335. $total = 0;
  336. foreach($this->getItems() as $item)
  337. {
  338. if($item->getProduct()->isVivog()){
  339. $total += $item->getProduct()->getPrice(true, $priceGroup, $withVat) * $item->getQuantity();
  340. }
  341. }
  342. return $total;
  343. }
  344. public function hasProduct(Product $product)
  345. {
  346. if(empty($this->items))
  347. return false;
  348. foreach($this->items as $item){
  349. if($item->getProduct()->getId() == $product->getId())
  350. return true;
  351. }
  352. return false;
  353. }
  354. public function getProducts()
  355. {
  356. $products = [];
  357. foreach($this->getItems() as $item)
  358. {
  359. $products[] = $item->getProduct();
  360. }
  361. return $products;
  362. }
  363. public function hasTax()
  364. {
  365. try{
  366. $customer = $this->getCustomer();
  367. if($customer && $customer->hasNoTva())
  368. return false;
  369. $billingAddress = $this->getBillingAddress();
  370. if(empty($billingAddress))
  371. return false;
  372. $billingCountry = $billingAddress->getCountry();
  373. if($billingCountry->isDom())
  374. return false;
  375. if(!$billingCountry->isFrance() && $customer->getTva())
  376. return false;
  377. } catch (\Exception $ex) {
  378. }
  379. return true;
  380. }
  381. public function addItem(Product $product,$qty=1,$oa=null,$gid=null,$cid=null,$oc=null,$d=null)
  382. {
  383. if($this->hasProduct($product)){
  384. $qty = $this->getItemQuantityByProduct($product)+$qty;
  385. return $this->updateItem($product, $qty);
  386. }else{
  387. $item = new CartItem($product,$qty);
  388. $item->setCart($this);
  389. $item->setUnitPrice($product->getPrice(false, $this->getPriceGroup()));
  390. $this->items[] = $item;
  391. }
  392. }
  393. public function updateItem(Product $product,$qty)
  394. {
  395. foreach($this->items as &$item){
  396. if($item->getProduct()->getId() == $product->getId()){
  397. $item->setQuantity($qty);
  398. $item->setUnitPrice($product->getPrice(false, $this->getPriceGroup()));
  399. }
  400. }
  401. }
  402. public function removeItem(Product $product)
  403. {
  404. $result = false;
  405. $tab = [];
  406. foreach($this->items as &$item){
  407. if($item->getProduct()->getId() != $product->getId()){
  408. $tab[] = $item;
  409. $result = true;
  410. }
  411. }
  412. $this->setItems($tab);
  413. return $result;
  414. }
  415. public function getItemByProduct(Product $product)
  416. {
  417. foreach($this->items as $item){
  418. if($item->getProduct()->getId() == $product->getId())
  419. return $item;
  420. }
  421. return false;
  422. }
  423. public function getItemQuantityByProduct(Product $product)
  424. {
  425. $item = $this->getItemByProduct($product);
  426. return $item ? $item->getQuantity() : 0;
  427. }
  428. public function hasGift()
  429. {
  430. foreach($this->items as &$item){
  431. if($item->getProduct()->isGift()){
  432. return true;
  433. }
  434. }
  435. return false;
  436. }
  437. public function canAddGift()
  438. {
  439. foreach($this->items as &$item){
  440. if($item->getProduct()->isProduct()){
  441. return true;
  442. }
  443. }
  444. return false;
  445. }
  446. public function getCoupons() {
  447. return $this->coupons;
  448. }
  449. public function setCoupons($coupons): void {
  450. $this->coupons = $coupons;
  451. }
  452. public function hasCoupon(Coupon $coupon)
  453. {
  454. if(empty($this->coupons))
  455. return false;
  456. foreach($this->coupons as $c){
  457. if($coupon->getCode() == $c->getCode())
  458. return true;
  459. }
  460. return false;
  461. }
  462. public function addCoupon(Coupon $coupon)
  463. {
  464. if(!$this->hasCoupon($coupon)){
  465. $this->coupons[] = $coupon;
  466. return true;
  467. }
  468. return "Coupon déjà présent...";
  469. }
  470. public function removeCoupon(Coupon $coupon)
  471. {
  472. $result = false;
  473. $tab = [];
  474. if(empty($this->coupons))
  475. return false;
  476. foreach($this->coupons as &$c){
  477. if($coupon->getId() != $c->getId()){
  478. $tab[] = $coupon;
  479. $result = true;
  480. }
  481. }
  482. $this->setCoupons($tab);
  483. return $result;
  484. }
  485. public function hasSoleilDiscount(?Product $product = null)
  486. {
  487. if(!empty($product)) {
  488. if($product->isSoleil()) {
  489. $total = $this->getSoleilTotal() + $product->getPrice();
  490. return $total >= 100;
  491. }else if($product->isNonSoleil()) {
  492. $total = $this->getNonSoleilTotal() + $product->getPrice();
  493. return $total >= 100;
  494. }
  495. return false;
  496. }
  497. return $this->getNonSoleilTotal() >= 100 || $this->getSoleilTotal() >= 100;
  498. }
  499. public function applyDiscount(MarketingRule $discount)
  500. {
  501. if($discount->getType() == MarketingRule::TYPE_OFFERED) {
  502. if(true) { // pas de panaché
  503. $discountedProducts = $discount->getProductsDiscounted();
  504. foreach ($this->items as $item) {
  505. $qtyOffered = $discount->getNbProductsOffered($this, $item->getProduct());
  506. if($qtyOffered > 0) {
  507. $qtyRequired = $discount->getQtyRequested();
  508. $item->setQuantityOffered($qtyOffered);
  509. $item->setMarketingRule($discount);
  510. }
  511. }
  512. }else{ //panaché
  513. // $iterator = $this->items->getIterator();
  514. // $iterator->uasort(function ($a, $b) {
  515. // if ($a->getProduct()->getPrice() == $b->getProduct()->getPrice() ) {
  516. // return 0;
  517. // }
  518. // return ($a->getProduct()->getPrice() < $b->getProduct()->getPrice() ) ? -1 : 1;
  519. // });
  520. // $this->items = new ArrayCollection(iterator_to_array($iterator));
  521. // $qtyOffered = $discount->getNbProductsOffered($this);
  522. // $remainingFreeItems = $qtyOffered;
  523. // foreach ($this->items as $item) {
  524. // if ($remainingFreeItems > 0) {
  525. // $freeItemsOnThisLine = min($remainingFreeItems, $item->getQuantity());
  526. // $item->setQuantityOffered($freeItemsOnThisLine);
  527. // $item->setMarketingRule($discount);
  528. // $remainingFreeItems -= $freeItemsOnThisLine;
  529. // }
  530. // }
  531. }
  532. }
  533. }
  534. public function isExpert()
  535. {
  536. return $this->priceGroup && $this->priceGroup->getCode() == PriceGroup::CODE_EXPERT;
  537. }
  538. public function toArray()
  539. {
  540. $items = [];
  541. foreach ($this->getItems() as $item){
  542. $items[] = $item->toArray();
  543. }
  544. $coupons = [];
  545. foreach ($this->getCoupons() as $coupon){
  546. $coupons[] = $coupon->toArray();
  547. }
  548. return [
  549. 'id'=>$this->getId(),
  550. 'products'=>$items,
  551. 'totalProducts'=>$this->getTotalProducts(),
  552. 'totalProductsWithDiscount'=>$this->getTotalProducts(true),
  553. 'discount'=>$this->getTotalProductsDiscount(),
  554. 'total'=>$this->getTotal(),
  555. 'coupons'=>$coupons,
  556. 'customerId'=>!empty($this->customer)?$this->getCustomer()->getId():null,
  557. 'carrier'=>!empty($this->carrier)?$this->getCarrier()->toArray():null,
  558. 'createdAt'=>empty($this->createdAt)?null:$this->createdAt->format('Y-m-d H:i:s'),
  559. 'updatedAt'=>empty($this->updatedAt)?null:$this->updatedAt->format('Y-m-d H:i:s')
  560. ];
  561. }
  562. /**
  563. * @ORM\PostLoad
  564. */
  565. public function postLoad(\Doctrine\ORM\Event\LifecycleEventArgs $args) {
  566. if(!empty($this->shippingAddress)){
  567. $shippingRates = $args->getEntityManager()->getRepository('App:ShippingRate')->findBy([
  568. 'country' => $this->getShippingAddress()->getCountry()
  569. ]);
  570. $this->setShippingRates($shippingRates);
  571. if($this->carrier){
  572. $shippingRate = $this->getShippingRateByCarrier($this->carrier);
  573. $this->setShippingRate($shippingRate);
  574. }
  575. }else if(empty($this->shippingAddress) && !empty($this->customer)){
  576. $this->setShippingAddress($this->getCustomer()->getDefaultAddress());
  577. }
  578. $this->init();
  579. }
  580. /**
  581. * @ORM\PrePersist()
  582. */
  583. public function prePersist(\Doctrine\ORM\Event\LifecycleEventArgs $args) {
  584. $this->setCreatedAt(new \DateTime());
  585. }
  586. /**
  587. * @ORM\PreUpdate()
  588. */
  589. public function preUpdate(\Doctrine\ORM\Event\LifecycleEventArgs $args) {
  590. $this->setUpdatedAt(new \DateTime());
  591. }
  592. public function __toString() {
  593. return 'carttostring';
  594. }
  595. }