src/Domain/Product/Model/CartOrder.php line 23

Open in your IDE?
  1. <?php
  2. namespace Whater\Domain\Product\Model;
  3. use BornFree\TacticianDomainEvent\Recorder\ContainsRecordedEvents;
  4. use BornFree\TacticianDomainEvent\Recorder\EventRecorderCapabilities;
  5. use Doctrine\Common\Collections\ArrayCollection;
  6. use Doctrine\Common\Collections\Collection;
  7. use Ramsey\Uuid\Uuid;
  8. use Whater\Domain\Common\Exception\InvalidUUIDException;
  9. use Whater\Domain\Product\Event\CartOrderStatusWasUpdated;
  10. use Whater\Domain\Product\Exception\InvalidCartOrderChangeUserException;
  11. use Whater\Domain\Product\Exception\InvalidCartOrderTypeException;
  12. use Whater\Domain\Product\Exception\InvalidOrderStatusException;
  13. use Whater\Domain\User\Model\OrganizationLicense;
  14. use Whater\Domain\User\Model\User;
  15. /**
  16. * Class CartOrder
  17. *
  18. * @package Whater\Domain\Product\Model
  19. */
  20. class CartOrder implements ContainsRecordedEvents
  21. {
  22. use EventRecorderCapabilities;
  23. public const ORDER_STATUS_PENDING = "PENDING";
  24. public const ORDER_STATUS_PAID = "PAID";
  25. public const ORDER_STATUS_INVALID_PAID = "INVALID_PAID";
  26. public const ORDER_STATUS_RETURNED = "RETURNED";
  27. public const ORDER_STATUS_CANCELED = "CANCELED";
  28. public const ORDER_STATUS_PARTIAL_RETURNED = "PARTIAL_RETURNED";
  29. public const ORDER_STATUS_ABANDONED = "ABANDONED";
  30. public const ORDER_TYPE_LICENSE = 'ORDER_TYPE_LICENSE';
  31. public const ORDER_TYPE_WHATERCOINS = 'ORDER_TYPE_WHATERCOINS';
  32. public const ORDER_TYPE_WHATER_REFILLS = 'ORDER_TYPE_WHATER_REFILLS';
  33. public const ORDER_TYPE_CATALOG_PRODUCT = 'ORDER_TYPE_CATALOG_PRODUCT';
  34. public const WHATER_REFILL_STATUS_PENDING = 'WHATER_REFILL_STATUS_PENDING';
  35. public const WHATER_REFILL_STATUS_SENT = 'WHATER_REFILL_STATUS_SENT';
  36. public const WHATER_REFILL_STATUS_SENT_CONFIRMED = 'WHATER_REFILL_STATUS_SENT_CONFIRMED';
  37. public const WHATER_REFILL_STATUS_NACK = 'WHATER_REFILL_STATUS_NACK';
  38. public const WHATER_REFILL_STATUS_ACK = 'WHATER_REFILL_STATUS_ACK';
  39. /**
  40. * @var string
  41. */
  42. private $uuid;
  43. /**
  44. * @var string
  45. */
  46. protected $cartOrderNumber;
  47. /**
  48. * @var string
  49. */
  50. private $cartOrderType;
  51. /**
  52. * @var string
  53. */
  54. private $status;
  55. /**
  56. * @var string
  57. */
  58. private $whaterRefillStatus;
  59. /**
  60. * @var int
  61. */
  62. private $numberOfWhaterRefillPurchased;
  63. /**
  64. * @var int
  65. */
  66. private $numberOfWhaterRefillPendingUse;
  67. /**
  68. * @var array
  69. */
  70. private $datesOfWhaterRefillUses;
  71. /**
  72. * @var string
  73. */
  74. private $invoiceNumber;
  75. /**
  76. * @var float
  77. */
  78. private $totalWhatercoins;
  79. /**
  80. * @var float
  81. */
  82. private $totalEuros;
  83. /**
  84. * @var float
  85. */
  86. private $totalShippingCost;
  87. /**
  88. * @var string
  89. */
  90. private $shippingCountry;
  91. /**
  92. * @var string
  93. */
  94. private $shippingAddress;
  95. /**
  96. * @var string
  97. */
  98. private $shippingPostalCode;
  99. /**
  100. * @var string
  101. */
  102. private $notes;
  103. /**
  104. * @var User
  105. */
  106. private $user;
  107. /**
  108. * @var OrganizationLicense
  109. */
  110. private $organizationLicense;
  111. /**
  112. * @var Collection
  113. */
  114. private $cartOrderItems;
  115. /**
  116. * @var \DateTime
  117. */
  118. private $invoiceDate;
  119. /**
  120. * @var \DateTime
  121. */
  122. private $purchaseDate;
  123. /**
  124. * @var \DateTime
  125. */
  126. private $createdAt;
  127. /**
  128. * @var null|\DateTime
  129. */
  130. private $updatedAt;
  131. /**
  132. * @var array
  133. */
  134. private $stripePaymentIntent;
  135. /**
  136. * @var array
  137. */
  138. private $stripeSubscription;
  139. /**
  140. * @param string $CartOrder
  141. */
  142. public function __construct(
  143. string $cartOrderId = null,
  144. string $cartOrderType,
  145. string $cartOrderNumber,
  146. User $user = null,
  147. string $notes = null,
  148. OrganizationLicense $organizationLicense = null
  149. ) {
  150. try {
  151. $this->uuid = Uuid::fromString($cartOrderId ?: Uuid::uuid4())->toString();
  152. } catch (\InvalidArgumentException $e) {
  153. throw new InvalidUUIDException();
  154. }
  155. switch ($cartOrderType) {
  156. case CartOrder::ORDER_TYPE_LICENSE:
  157. $this->cartOrderType = $cartOrderType;
  158. $this->organizationLicense = $organizationLicense;
  159. if ($organizationLicense == null) {
  160. throw new InvalidCartOrderTypeException();
  161. }
  162. break;
  163. case CartOrder::ORDER_TYPE_CATALOG_PRODUCT:
  164. case CartOrder::ORDER_TYPE_WHATER_REFILLS:
  165. case CartOrder::ORDER_TYPE_WHATERCOINS:
  166. $this->cartOrderType = $cartOrderType;
  167. break;
  168. default:
  169. throw new InvalidCartOrderTypeException();
  170. }
  171. $this->notes = $notes;
  172. $this->user = $user;
  173. $this->cartOrderNumber = $cartOrderNumber;
  174. $this->status = CartOrder::ORDER_STATUS_PENDING;
  175. $this->cartOrderItems = new ArrayCollection();
  176. $this->totalEuros = 0;
  177. $this->totalWhatercoins = 0;
  178. $this->totalShippingCost = 0;
  179. $this->numberOfWhaterRefillPurchased = 0;
  180. $this->numberOfWhaterRefillPendingUse = 0;
  181. $this->createdAt = new \DateTime();
  182. $this->updatedAt = new \DateTime();
  183. }
  184. public function updateStatus(
  185. string $status
  186. ) {
  187. if ($this->status() == CartOrder::ORDER_STATUS_PENDING) {
  188. switch ($status) {
  189. case CartOrder::ORDER_STATUS_PAID:
  190. $this->status = $status;
  191. $this->invoiceDate = new \DateTime();
  192. $this->record(new CartOrderStatusWasUpdated($this));
  193. break;
  194. case CartOrder::ORDER_STATUS_INVALID_PAID:
  195. $this->status = $status;
  196. $this->record(new CartOrderStatusWasUpdated($this));
  197. break;
  198. case CartOrder::ORDER_STATUS_ABANDONED:
  199. $this->status = $status;
  200. $this->record(new CartOrderStatusWasUpdated($this));
  201. break;
  202. case CartOrder::ORDER_STATUS_PENDING:
  203. break;
  204. default:
  205. throw new InvalidOrderStatusException();
  206. }
  207. } else if ($this->status() == CartOrder::ORDER_STATUS_INVALID_PAID) {
  208. switch ($status) {
  209. case CartOrder::ORDER_STATUS_PAID:
  210. $this->status = $status;
  211. $this->invoiceDate = new \DateTime();
  212. $this->record(new CartOrderStatusWasUpdated($this));
  213. break;
  214. case CartOrder::ORDER_STATUS_INVALID_PAID:
  215. $this->status = $status;
  216. $this->record(new CartOrderStatusWasUpdated($this));
  217. break;
  218. case CartOrder::ORDER_STATUS_ABANDONED:
  219. $this->status = $status;
  220. $this->record(new CartOrderStatusWasUpdated($this));
  221. break;
  222. case CartOrder::ORDER_STATUS_PENDING:
  223. break;
  224. default:
  225. throw new InvalidOrderStatusException();
  226. }
  227. } else if ($this->status() == CartOrder::ORDER_STATUS_PAID) {
  228. switch ($status) {
  229. case CartOrder::ORDER_STATUS_PARTIAL_RETURNED:
  230. case CartOrder::ORDER_STATUS_RETURNED:
  231. case CartOrder::ORDER_STATUS_CANCELED:
  232. $this->status = $status;
  233. $this->record(new CartOrderStatusWasUpdated($this));
  234. break;
  235. default:
  236. throw new InvalidOrderStatusException();
  237. }
  238. } else if ($this->status() == CartOrder::ORDER_STATUS_PARTIAL_RETURNED) {
  239. switch ($status) {
  240. case CartOrder::ORDER_STATUS_PARTIAL_RETURNED:
  241. case CartOrder::ORDER_STATUS_RETURNED:
  242. $this->status = $status;
  243. $this->record(new CartOrderStatusWasUpdated($this));
  244. break;
  245. default:
  246. throw new InvalidOrderStatusException();
  247. }
  248. }
  249. $this->updatedAt = new \DateTime();
  250. return $this;
  251. }
  252. public function updateShippingData(
  253. float $shippingCost = 0,
  254. string $shippingCountry = null,
  255. string $shippingAddress = null,
  256. string $shippingPostalCode = null
  257. ) {
  258. $this->totalShippingCost = $shippingCost;
  259. $this->shippingCountry = $shippingCountry;
  260. $this->shippingAddress = $shippingAddress;
  261. $this->shippingPostalCode = $shippingPostalCode;
  262. }
  263. public function updateWhaterRefillsData(
  264. int $numberOfWhaterRefillPendingUse,
  265. array $datesOfWhaterRefillUses
  266. ) {
  267. $this->numberOfWhaterRefillPendingUse = $numberOfWhaterRefillPendingUse;
  268. $this->datesOfWhaterRefillUses = $datesOfWhaterRefillUses;
  269. $this->updatedAt = new \DateTime();
  270. }
  271. public function updateTotal(
  272. float $totalEuros = null,
  273. float $totalWhatercoins = null
  274. ) {
  275. $acceptWhatercoins = true;
  276. $cartOrderItemsWhatercoins = 0;
  277. if ($totalEuros == null) {
  278. $t = 0;
  279. foreach ($this->cartOrderItems() as $cartOrderItem) {
  280. if ($cartOrderItem->product()->productType() == Product::PRODUCT_TYPE_WATER_SUPPLY) {
  281. $cartOrderItemsWhatercoins += $cartOrderItem->pricePerUnit() * $cartOrderItem->units();
  282. $acceptWhatercoins = true;
  283. } else {
  284. $t += $cartOrderItem->pricePerUnit() * $cartOrderItem->units();
  285. if (!$cartOrderItem->product()->acceptWhatercoins()) {
  286. $acceptWhatercoins = false;
  287. } else {
  288. if ($cartOrderItem->product()->productType() == Product::PRODUCT_TYPE_WATER_SUPPLY) {
  289. $cartOrderItemsWhatercoins += $cartOrderItem->pricePerUnit() * $cartOrderItem->units();
  290. } else if (array_key_exists('whatercoins_for_discount', $cartOrderItem->meta())) {
  291. $cartOrderItemsWhatercoins += $cartOrderItem->meta()['whatercoins_for_discount'] * $cartOrderItem->units();
  292. }
  293. }
  294. }
  295. }
  296. $this->totalEuros = $t;
  297. } else {
  298. $this->totalEuros = $totalEuros;
  299. }
  300. if ($acceptWhatercoins) {
  301. if ($totalWhatercoins == null) {
  302. $this->totalWhatercoins = $cartOrderItemsWhatercoins;
  303. } else {
  304. $this->totalWhatercoins = $totalWhatercoins;
  305. }
  306. } else {
  307. $this->totalWhatercoins = 0;
  308. }
  309. $this->updatedAt = new \DateTime();
  310. return $this;
  311. }
  312. public function updateStripeInfo(
  313. array $stripePaymentIntent,
  314. array $stripeSubscription = null
  315. ) {
  316. $this->stripePaymentIntent = $stripePaymentIntent;
  317. $this->stripeSubscription = $stripeSubscription;
  318. }
  319. public function updatePurchaseDate(
  320. \DateTime $purchaseDate
  321. ) {
  322. if ($this->purchaseDate == null) {
  323. $this->purchaseDate = $purchaseDate;
  324. }
  325. }
  326. public function updateWhaterRefillStatus(
  327. string $whaterRefillStatus
  328. ) {
  329. if ($this->cartOrderType() == CartOrder::ORDER_TYPE_WHATER_REFILLS) {
  330. switch ($whaterRefillStatus) {
  331. case CartOrder::WHATER_REFILL_STATUS_PENDING:
  332. case CartOrder::WHATER_REFILL_STATUS_SENT:
  333. case CartOrder::WHATER_REFILL_STATUS_SENT_CONFIRMED:
  334. case CartOrder::WHATER_REFILL_STATUS_ACK:
  335. case CartOrder::WHATER_REFILL_STATUS_NACK:
  336. $this->whaterRefillStatus = $whaterRefillStatus;
  337. }
  338. }
  339. }
  340. public function setUser(User $user)
  341. {
  342. if ($this->user == null) {
  343. $this->user = $user;
  344. } else {
  345. throw new InvalidCartOrderChangeUserException();
  346. }
  347. $this->updatedAt = new \DateTime();
  348. }
  349. /**
  350. * @return string
  351. */
  352. public function id(): string
  353. {
  354. return $this->uuid;
  355. }
  356. /**
  357. * @return string
  358. */
  359. public function cartOrderNumber(): string
  360. {
  361. return $this->cartOrderNumber;
  362. }
  363. /**
  364. * @return string
  365. */
  366. public function cartOrderType(): string
  367. {
  368. return $this->cartOrderType;
  369. }
  370. public function cartItem(int $index)
  371. {
  372. if (count($this->cartOrderItems()) >= $index) {
  373. return $this->cartOrderItems()->get($index);
  374. }
  375. return null;
  376. }
  377. public function cartItemValoration(int $index): ?ProductValoration
  378. {
  379. return $this->cartItem($index)->productValoration();
  380. }
  381. /**
  382. * @return string
  383. */
  384. public function status(): string
  385. {
  386. return $this->status;
  387. }
  388. /**
  389. * @return string
  390. */
  391. public function invoiceNumber(): ?string
  392. {
  393. return $this->invoiceNumber;
  394. }
  395. /**
  396. * @return User
  397. */
  398. public function user(): ?User
  399. {
  400. return $this->user;
  401. }
  402. /**
  403. * @return OrganizationLicense
  404. */
  405. public function organizationLicense(): ?OrganizationLicense
  406. {
  407. return $this->organizationLicense;
  408. }
  409. /**
  410. * @return array
  411. */
  412. public function stripePaymentIntent(): ?array
  413. {
  414. return $this->stripePaymentIntent;
  415. }
  416. /**
  417. * @return array
  418. */
  419. public function stripeSubscription(): ?array
  420. {
  421. return $this->stripeSubscription;
  422. }
  423. /**
  424. * @return float
  425. */
  426. public function totalEuros(): float
  427. {
  428. return $this->totalEuros;
  429. }
  430. /**
  431. * @return float
  432. */
  433. public function totalShippingCost(): float
  434. {
  435. return $this->totalShippingCost;
  436. }
  437. /**
  438. * @return string
  439. */
  440. public function shippingCountry(): ?string
  441. {
  442. return $this->shippingCountry;
  443. }
  444. /**
  445. * @return string
  446. */
  447. public function shippingAddress(): string
  448. {
  449. return $this->shippingAddress;
  450. }
  451. /**
  452. * @return string
  453. */
  454. public function shippingPostalCode(): string
  455. {
  456. return $this->shippingPostalCode;
  457. }
  458. public function shippingItems(): array
  459. {
  460. $shippingItems = [];
  461. foreach ($this->cartOrderItems() as $cartOrderItem) {
  462. $product = $cartOrderItem->product();
  463. $whaterCompany = $product->whaterOrganization();
  464. if (!array_key_exists($whaterCompany->slug(), $shippingItems)) {
  465. $shippingItems[$whaterCompany->slug()] = [];
  466. }
  467. $shippingItem = [
  468. 'isShippable' => $product->isShippable(),
  469. 'requiresShippingCosts' => $product->requiresShippingCosts(),
  470. 'productWeight' => $product->productWeight(),
  471. 'productLength' => $product->productLength(),
  472. 'productWidth' => $product->productWidth(),
  473. 'productHeight' => $product->productHeight(),
  474. 'itemDescription' => $cartOrderItem->itemDescription(),
  475. 'pricePerUnit' => $cartOrderItem->pricePerUnit(),
  476. 'units' => $cartOrderItem->units(),
  477. 'marketplaceCountry' => $whaterCompany->marketplaceCountry(),
  478. 'marketplacePostalCode' => $whaterCompany->marketplacePostalCode(),
  479. 'marketplaceAddress' => $whaterCompany->marketplaceAddress()
  480. ];
  481. array_push($shippingItems[$whaterCompany->slug()], $shippingItem);
  482. }
  483. return $shippingItems;
  484. }
  485. /**
  486. * @return float
  487. */
  488. public function totalWhatercoins(): float
  489. {
  490. return $this->totalWhatercoins;
  491. }
  492. public function taxesEuros(): float
  493. {
  494. $taxes = 0;
  495. foreach ($this->cartOrderItems() as $cartOrderItem) {
  496. $taxesPercent = $cartOrderItem->taxesPercent();
  497. $taxes += round(
  498. ($cartOrderItem->pricePerUnit() * $cartOrderItem->units()) * $taxesPercent / (100 + $taxesPercent),
  499. 2
  500. );
  501. }
  502. if ($this->totalWhatercoins() > 0) {
  503. // whatercoins do not include taxes!
  504. $taxes = 0;
  505. }
  506. return $taxes;
  507. }
  508. public function subTotalEuros(): float
  509. {
  510. return $this->totalEuros() - $this->taxesEuros();
  511. }
  512. /**
  513. * @return string|null
  514. */
  515. public function notes(): ?string
  516. {
  517. return $this->notes;
  518. }
  519. /**
  520. * @return Collection
  521. */
  522. public function cartOrderItems(): Collection
  523. {
  524. return $this->cartOrderItems;
  525. }
  526. /**
  527. * @return string
  528. */
  529. public function whaterRefillStatus(): ?string
  530. {
  531. return $this->whaterRefillStatus;
  532. }
  533. /**
  534. * @return int|null
  535. */
  536. public function numberOfWhaterRefillPurchased(): ?int
  537. {
  538. return $this->numberOfWhaterRefillPurchased;
  539. }
  540. /**
  541. * @return int|null
  542. */
  543. public function numberOfWhaterRefillPendingUse(): ?int
  544. {
  545. return $this->numberOfWhaterRefillPendingUse;
  546. }
  547. /**
  548. * @return array|null
  549. */
  550. public function datesOfWhaterRefillUses(): ?array
  551. {
  552. return $this->datesOfWhaterRefillUses;
  553. }
  554. /**
  555. * @return \DateTime|null
  556. */
  557. public function invoiceDate(): ?\DateTime
  558. {
  559. return $this->invoiceDate;
  560. }
  561. /**
  562. * @return \DateTime|null
  563. */
  564. public function purchaseDate(): ?\DateTime
  565. {
  566. return $this->purchaseDate;
  567. }
  568. /**
  569. * @return \DateTime
  570. */
  571. public function createdAt(): \DateTime
  572. {
  573. return $this->createdAt;
  574. }
  575. /**
  576. * @return \DateTime|null
  577. */
  578. public function updatedAt(): ?\DateTime
  579. {
  580. return $this->updatedAt;
  581. }
  582. }