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

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