src/Domain/Product/Model/Product.php line 21

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 Ramsey\Uuid\Uuid;
  6. use Whater\Domain\Common\Exception\InvalidUUIDException;
  7. use Whater\Domain\Whater\Model\WhaterOrganization;
  8. use Whater\Domain\Whater\Model\WhaterPoint;
  9. use Doctrine\Common\Collections\ArrayCollection;
  10. use Doctrine\Common\Collections\Collection;
  11. use Whater\Domain\Product\Exception\InvalidProductTypeException;
  12. use Whater\Domain\User\Model\User;
  13. /**
  14. * Class Product
  15. *
  16. * @package Whater\Domain\Product\Model
  17. */
  18. class Product implements ContainsRecordedEvents
  19. {
  20. use EventRecorderCapabilities;
  21. public const PRODUCT_TYPE_WATER_SUPPLY = "PT_WATER_SUPPLY";
  22. public const PRODUCT_TYPE_CATALOG = "PT_CATALOG";
  23. public const PRODUCT_TYPE_WATERCOINS = "PT_WATERCOINS";
  24. public const PRODUCT_TYPE_LICENSE = "PT_LICENSE";
  25. public const PRODUCT_TYPE_DISCOUNT = "PT_DISCOUNT";
  26. public const PRODUCT_TYPE_SERVICE = "PT_SERVICE";
  27. /**
  28. * @var string
  29. */
  30. private $uuid;
  31. /**
  32. * @var string
  33. */
  34. private $productLabel;
  35. /**
  36. * @var string
  37. */
  38. private $productSlug;
  39. /**
  40. * @var string
  41. */
  42. private $productShortDescription;
  43. /**
  44. * @var string
  45. */
  46. private $productDescription;
  47. /**
  48. * @var string
  49. */
  50. private $productType;
  51. /**
  52. * @var float
  53. */
  54. private $productPrice;
  55. /**
  56. * @var float
  57. */
  58. private $productVatPercent;
  59. /**
  60. * @var bool
  61. */
  62. private $isEnable;
  63. /**
  64. * @var bool
  65. */
  66. private $isShippable;
  67. /**
  68. * @var string
  69. */
  70. private $freeShippableCode;
  71. /**
  72. * @var float
  73. */
  74. private $productWeight;
  75. /**
  76. * @var string
  77. */
  78. private $productLength;
  79. /**
  80. * @var string
  81. */
  82. private $productWidth;
  83. /**
  84. * @var string
  85. */
  86. private $productHeight;
  87. /**
  88. * @var WhaterPoint
  89. */
  90. private $whaterPoint;
  91. /**
  92. * @var WhaterOrganization
  93. */
  94. private $whaterOrganization;
  95. /**
  96. * @var boolean
  97. */
  98. private $isInternalProduct;
  99. /**
  100. * @var boolean
  101. */
  102. private $acceptWhatercoins;
  103. /**
  104. * @var \DateTime
  105. */
  106. private $createdAt;
  107. /**
  108. * @var null|\DateTime
  109. */
  110. private $updatedAt;
  111. /**
  112. * @var Collection
  113. */
  114. private $images;
  115. /**
  116. * @var Collection
  117. */
  118. private $productVariations;
  119. /**
  120. * @var Collection
  121. */
  122. private $productAttributes;
  123. /**
  124. * @var array
  125. */
  126. private $tags;
  127. /**
  128. * @var ProductCategory
  129. */
  130. private $productCategory;
  131. /**
  132. * @var float
  133. */
  134. private $whaterCommisionPercent;
  135. /**
  136. * @var Collection
  137. */
  138. private $countriesToRecommend;
  139. /**
  140. * @var Collection
  141. */
  142. private $countryAreasToRecommend;
  143. /**
  144. * @var bool
  145. */
  146. private $recommendToWaterStatusSuitable;
  147. /**
  148. * @var bool
  149. */
  150. private $recommendToWaterStatusNotSuitable;
  151. /**
  152. * @var bool
  153. */
  154. private $recommendToWaterStatusWithRestrictions;
  155. /**
  156. * @var bool
  157. */
  158. private $recommendToWaterStatusUnknown;
  159. /**
  160. * @var int
  161. */
  162. private $maxDiscountPercentageAllowed;
  163. /**
  164. * @var bool
  165. */
  166. private $requiresShippingCosts;
  167. /**
  168. * @var string
  169. */
  170. private $theThingsNetworkDeviceName;
  171. /**
  172. * @var int
  173. */
  174. private $whaterSupplyMiliseconds;
  175. /**
  176. * @var string
  177. */
  178. private $nfcReaderOnlineSerialNumber;
  179. /**
  180. * @var \Datetime
  181. */
  182. private $lastRequestToRegisterAnUserNfcAt;
  183. /**
  184. * @var User
  185. */
  186. private $lastRequestToRegisterAnUserNfcUser;
  187. /**
  188. * @var string
  189. */
  190. private $closcaFountainId;
  191. /**
  192. * @var Collection
  193. */
  194. private $valorations;
  195. /**
  196. * @var float
  197. */
  198. private $averageValorations;
  199. /**
  200. * @param string $productId
  201. */
  202. public function __construct(
  203. ?string $productId = null,
  204. string $productLabel,
  205. string $productType,
  206. float $productPrice,
  207. float $productVatPercent,
  208. ?WhaterOrganization $whaterOrganization = null,
  209. ?string $productShortDescription = null,
  210. ?string $productDescription = null,
  211. ?WhaterPoint $whaterPoint = null,
  212. bool $isInternalProduct = false,
  213. ?float $whaterCommisionPercent = null
  214. ) {
  215. try {
  216. $this->uuid = Uuid::fromString($productId ?: Uuid::uuid4())->toString();
  217. } catch (\InvalidArgumentException $e) {
  218. throw new InvalidUUIDException();
  219. }
  220. $this->productLabel = $productLabel;
  221. $this->productSlug = $productLabel;
  222. $this->productShortDescription = $productShortDescription;
  223. $this->productDescription = $productDescription;
  224. switch ($productType) {
  225. case Product::PRODUCT_TYPE_CATALOG:
  226. case Product::PRODUCT_TYPE_DISCOUNT:
  227. case Product::PRODUCT_TYPE_LICENSE:
  228. case Product::PRODUCT_TYPE_WATER_SUPPLY:
  229. case Product::PRODUCT_TYPE_WATERCOINS:
  230. case Product::PRODUCT_TYPE_SERVICE:
  231. $this->productType = $productType;
  232. break;
  233. default:
  234. throw new InvalidProductTypeException();
  235. }
  236. $this->productPrice = $productPrice;
  237. $this->productVatPercent = $productVatPercent;
  238. $this->whaterCommisionPercent = $whaterCommisionPercent;
  239. $this->isEnable = false;
  240. $this->isShippable = ($this->productType == Product::PRODUCT_TYPE_CATALOG);
  241. $this->recommendToWaterStatusSuitable = false;
  242. $this->recommendToWaterStatusNotSuitable = false;
  243. $this->recommendToWaterStatusWithRestrictions = false;
  244. $this->recommendToWaterStatusUnknown = false;
  245. $this->isInternalProduct = $isInternalProduct;
  246. $this->whaterOrganization = $whaterOrganization;
  247. if ($productType == Product::PRODUCT_TYPE_WATER_SUPPLY) {
  248. $this->whaterPoint = $whaterPoint;
  249. $this->acceptWhatercoins = true;
  250. } else {
  251. $this->acceptWhatercoins = false;
  252. }
  253. if (!$isInternalProduct && $whaterOrganization == null) {
  254. throw new InvalidUUIDException();
  255. }
  256. $this->maxDiscountPercentageAllowed = 0;
  257. $this->requiresShippingCosts = false;
  258. $this->createdAt = new \DateTime();
  259. $this->updatedAt = new \DateTime();
  260. $this->images = new ArrayCollection();
  261. $this->productVariations = new ArrayCollection();
  262. $this->productAttributes = new ArrayCollection();
  263. $this->countriesToRecommend = new ArrayCollection();
  264. $this->countryAreasToRecommend = new ArrayCollection();
  265. $this->valorations = new ArrayCollection();
  266. $this->averageValorations = null;
  267. }
  268. public function editProduct(
  269. string $productLabel,
  270. float $productPrice,
  271. float $productVatPercent,
  272. ?string $productShortDescription = null,
  273. ?string $productDescription = null,
  274. bool $isEnable = false,
  275. bool $acceptWhatercoins = false,
  276. ?float $whaterCommisionPercent = null,
  277. ?array $tags = null,
  278. ?ProductCategory $productCategory = null,
  279. bool $recommendToWaterStatusSuitable = false,
  280. bool $recommendToWaterStatusNotSuitable = false,
  281. bool $recommendToWaterStatusWithRestrictions = false,
  282. bool $recommendToWaterStatusUnknown = false,
  283. ?int $maxDiscountPercentageAllowed = null
  284. ) {
  285. $this->productLabel = $productLabel;
  286. $this->productShortDescription = $productShortDescription;
  287. $this->productDescription = $productDescription;
  288. $this->productPrice = $productPrice;
  289. $this->productVatPercent = $productVatPercent;
  290. $this->whaterCommisionPercent = $whaterCommisionPercent;
  291. $this->acceptWhatercoins = $acceptWhatercoins;
  292. $this->isEnable = $isEnable;
  293. $this->tags = $tags;
  294. $this->productCategory = $productCategory;
  295. $this->recommendToWaterStatusSuitable = $recommendToWaterStatusSuitable;
  296. $this->recommendToWaterStatusNotSuitable = $recommendToWaterStatusNotSuitable;
  297. $this->recommendToWaterStatusWithRestrictions = $recommendToWaterStatusWithRestrictions;
  298. $this->recommendToWaterStatusUnknown = $recommendToWaterStatusUnknown;
  299. $this->maxDiscountPercentageAllowed = $maxDiscountPercentageAllowed;
  300. $this->updatedAt = new \DateTime();
  301. }
  302. public function editShipmentData(
  303. bool $isShippable = false,
  304. bool $requiresShippingCosts = false,
  305. ?float $productWeight = null,
  306. ?float $productLength = null,
  307. ?float $productWidth = null,
  308. ?float $productHeight = null,
  309. ?string $freeShippableCode = null
  310. ) {
  311. if ($this->productType() == Product::PRODUCT_TYPE_CATALOG) {
  312. $this->isShippable = $isShippable;
  313. } else {
  314. $this->isShippable = false;
  315. }
  316. $this->requiresShippingCosts = $requiresShippingCosts;
  317. $this->productWeight = $productWeight;
  318. $this->productLength = $productLength;
  319. $this->productWidth = $productWidth;
  320. $this->productHeight = $productHeight;
  321. if ($this->isShippable) {
  322. $this->productWeight = $this->productWeight ?? 1;
  323. $this->productLength = $this->productLength ?? 1;
  324. $this->productWidth = $this->productWidth ?? 1;
  325. $this->productHeight = $this->productHeight ?? 1;
  326. }
  327. $this->freeShippableCode = $freeShippableCode;
  328. }
  329. public function editWhaterSupply(
  330. ?string $theThingsNetworkDeviceName = null,
  331. ?int $whaterSupplyMiliseconds = null,
  332. ?string $nfcReaderOnlineSerialNumber = null,
  333. ?string $closcaFountainId = null
  334. ) {
  335. if ($this->productType == Product::PRODUCT_TYPE_WATER_SUPPLY) {
  336. $this->theThingsNetworkDeviceName = $theThingsNetworkDeviceName;
  337. $this->whaterSupplyMiliseconds = $whaterSupplyMiliseconds;
  338. if ($whaterSupplyMiliseconds < 10) {
  339. $this->whaterSupplyMiliseconds = 10;
  340. }
  341. $this->nfcReaderOnlineSerialNumber = $nfcReaderOnlineSerialNumber;
  342. $this->closcaFountainId = $closcaFountainId;
  343. }
  344. }
  345. public function editZonesToRecommend(
  346. ArrayCollection $countriesToRecommend,
  347. ArrayCollection $countryAreasToRecommend
  348. ) {
  349. $this->countriesToRecommend()->clear();
  350. foreach ($countriesToRecommend as $country) {
  351. $this->countriesToRecommend->add($country);
  352. }
  353. $this->countryAreasToRecommend()->clear();
  354. foreach ($countryAreasToRecommend as $countryArea) {
  355. $this->countryAreasToRecommend->add($countryArea);
  356. }
  357. $this->updatedAt = new \DateTime();
  358. }
  359. public function updateAverageValorations()
  360. {
  361. $numValorations = 0;
  362. $sumValorations = 0;
  363. foreach ($this->valorations() as $valoration) {
  364. $numValorations++;
  365. $sumValorations = $sumValorations + $valoration->rating();
  366. }
  367. if ($numValorations == 0) {
  368. $this->averageValorations = null;
  369. } else {
  370. $this->averageValorations = round($sumValorations / $numValorations, 2);
  371. }
  372. }
  373. public function updateCloscaFountainId(
  374. ?string $closcaFountainId = null
  375. ) {
  376. $this->closcaFountainId = $closcaFountainId;
  377. return $this;
  378. }
  379. public function updateLastRequestToRegisterAnUserNfcAt(
  380. \Datetime $lastRequestToRegisterAnUserNfcAt,
  381. User $lastRequestToRegisterAnUserNfcUser
  382. ) {
  383. $this->lastRequestToRegisterAnUserNfcAt = $lastRequestToRegisterAnUserNfcAt;
  384. $this->lastRequestToRegisterAnUserNfcUser = $lastRequestToRegisterAnUserNfcUser;
  385. }
  386. /**
  387. * @deprecated
  388. */
  389. public function calculateWhatercoinsForDiscount(
  390. float $discountPercent,
  391. ?string $productVariationId = null
  392. ) {
  393. $productPrice = $this->productPrice();
  394. if ($productVariationId != null) {
  395. foreach ($this->productVariations() as $productVariation) {
  396. if ($productVariation->id() == $productVariationId) {
  397. $productPrice = $productVariation->productVariationPrice();
  398. break;
  399. }
  400. }
  401. }
  402. $discountInMoney = ($productPrice * $discountPercent / 100);
  403. $discountInWhatercoins = $discountInMoney * 100;
  404. if ($productPrice > 200) {
  405. $realDiscount = 0.9;
  406. } else if ($productPrice > 100) {
  407. $realDiscount = 0.85;
  408. } else if ($productPrice > 50) {
  409. $realDiscount = 0.8;
  410. } else {
  411. $realDiscount = 0.75;
  412. }
  413. return round($discountInWhatercoins * $realDiscount, 2);
  414. }
  415. public function setAsInternalProduct(
  416. bool $isInternalProduct
  417. ) {
  418. $this->isInternalProduct = $isInternalProduct;
  419. }
  420. public function firstImage()
  421. {
  422. $firstImage = null;
  423. foreach ($this->images() as $productImage) {
  424. $firstImage = $productImage;
  425. break;
  426. }
  427. return $firstImage;
  428. }
  429. /**
  430. * @return string
  431. */
  432. public function id(): string
  433. {
  434. return $this->uuid;
  435. }
  436. /**
  437. * @return string
  438. */
  439. public function productLabel(): string
  440. {
  441. return $this->productLabel;
  442. }
  443. /**
  444. * @return string
  445. */
  446. public function productSlug(): string
  447. {
  448. return $this->productSlug;
  449. }
  450. /**
  451. * @return string
  452. */
  453. public function theThingsNetworkDeviceName(): ?string
  454. {
  455. return $this->theThingsNetworkDeviceName;
  456. }
  457. /**
  458. * @return int
  459. */ public function whaterSupplyMiliseconds(): ?int
  460. {
  461. return $this->whaterSupplyMiliseconds;
  462. }
  463. /**
  464. * @return string
  465. */
  466. public function nfcReaderOnlineSerialNumber(): ?string
  467. {
  468. return $this->nfcReaderOnlineSerialNumber;
  469. }
  470. /**
  471. * @return \DateTime
  472. */
  473. public function lastRequestToRegisterAnUserNfcAt(): ?\DateTime
  474. {
  475. return $this->lastRequestToRegisterAnUserNfcAt;
  476. }
  477. /**
  478. * @return User
  479. */
  480. public function lastRequestToRegisterAnUserNfcUser(): ?User
  481. {
  482. return $this->lastRequestToRegisterAnUserNfcUser;
  483. }
  484. /**
  485. * @return string
  486. */
  487. public function closcaFountainId(): ?string
  488. {
  489. return $this->closcaFountainId;
  490. }
  491. /**
  492. * @return bool
  493. */
  494. public function isEnable(): bool
  495. {
  496. return $this->isEnable;
  497. }
  498. /**
  499. * @return bool
  500. */
  501. public function isShippable(): bool
  502. {
  503. return $this->isShippable;
  504. }
  505. /**
  506. * @return string
  507. */
  508. public function freeShippableCode(): ?string
  509. {
  510. return $this->freeShippableCode;
  511. }
  512. /**
  513. * @return float
  514. */
  515. public function productWeight(): ?float
  516. {
  517. return $this->productWeight;
  518. }
  519. /**
  520. * @return float
  521. */
  522. public function productLength(): ?float
  523. {
  524. return $this->productLength;
  525. }
  526. /**
  527. * @return float
  528. */
  529. public function productWidth(): ?float
  530. {
  531. return $this->productWidth;
  532. }
  533. /**
  534. * @return float
  535. */
  536. public function productHeight(): ?float
  537. {
  538. return $this->productHeight;
  539. }
  540. /**
  541. * @return bool
  542. */
  543. public function acceptWhatercoins(): bool
  544. {
  545. return $this->acceptWhatercoins;
  546. }
  547. /**
  548. * @return float
  549. */
  550. public function averageValorations(): ?float
  551. {
  552. return $this->averageValorations;
  553. }
  554. /**
  555. * @return string
  556. */
  557. public function productShortDescription(): ?string
  558. {
  559. return $this->productShortDescription;
  560. }
  561. /**
  562. * @return string
  563. */
  564. public function productDescription(): ?string
  565. {
  566. return $this->productDescription;
  567. }
  568. /**
  569. * @return string
  570. */
  571. public function productType(): string
  572. {
  573. return $this->productType;
  574. }
  575. /**
  576. * @return float
  577. */
  578. public function productPrice(): float
  579. {
  580. return $this->productPrice;
  581. }
  582. /**
  583. * @return float
  584. */
  585. public function productVatPercent(): float
  586. {
  587. return $this->productVatPercent;
  588. }
  589. /**
  590. * @return float
  591. */
  592. public function whaterCommisionPercent(): float
  593. {
  594. return $this->whaterCommisionPercent;
  595. }
  596. /**
  597. * @return WhaterOrganization|null
  598. */
  599. public function whaterOrganization(): ?WhaterOrganization
  600. {
  601. return $this->whaterOrganization;
  602. }
  603. /**
  604. * @return bool
  605. */
  606. public function isInternalProduct(): bool
  607. {
  608. return $this->isInternalProduct;
  609. }
  610. /**
  611. * @return WhaterPoint|null
  612. */
  613. public function whaterPoint(): ?WhaterPoint
  614. {
  615. return $this->whaterPoint;
  616. }
  617. /**
  618. * @return \DateTime
  619. */
  620. public function createdAt(): \DateTime
  621. {
  622. return $this->createdAt;
  623. }
  624. /**
  625. * @return \DateTime|null
  626. */
  627. public function updatedAt()
  628. {
  629. return $this->updatedAt;
  630. }
  631. public function images(): Collection
  632. {
  633. return $this->images;
  634. }
  635. public function productAttributes(): Collection
  636. {
  637. return $this->productAttributes;
  638. }
  639. public function productVariations(): Collection
  640. {
  641. return $this->productVariations;
  642. }
  643. public function countriesToRecommend(): Collection
  644. {
  645. return $this->countriesToRecommend;
  646. }
  647. public function countryAreasToRecommend(): Collection
  648. {
  649. return $this->countryAreasToRecommend;
  650. }
  651. public function tags(): ?array
  652. {
  653. return $this->tags;
  654. }
  655. public function productCategory(): ?ProductCategory
  656. {
  657. return $this->productCategory;
  658. }
  659. /**
  660. * @return bool
  661. */
  662. public function recommendToWaterStatusSuitable(): bool
  663. {
  664. return $this->recommendToWaterStatusSuitable;
  665. }
  666. /**
  667. * @return bool
  668. */
  669. public function recommendToWaterStatusNotSuitable(): bool
  670. {
  671. return $this->recommendToWaterStatusNotSuitable;
  672. }
  673. /**
  674. * @return bool
  675. */
  676. public function recommendToWaterStatusWithRestrictions(): bool
  677. {
  678. return $this->recommendToWaterStatusWithRestrictions;
  679. }
  680. /**
  681. * @return bool
  682. */
  683. public function recommendToWaterStatusUnknown(): bool
  684. {
  685. return $this->recommendToWaterStatusUnknown;
  686. }
  687. /**
  688. * @return int
  689. */
  690. public function maxDiscountPercentageAllowed(): int
  691. {
  692. return $this->maxDiscountPercentageAllowed;
  693. }
  694. /**
  695. * @return bool
  696. */
  697. public function requiresShippingCosts(): bool
  698. {
  699. return $this->requiresShippingCosts;
  700. }
  701. /**
  702. * @return Collection
  703. */
  704. public function valorations(): Collection
  705. {
  706. return $this->valorations;
  707. }
  708. /**
  709. * @return bool
  710. */
  711. public function equals(Product $product)
  712. {
  713. return $this->id() === $product->id();
  714. }
  715. }