<?php
namespace Whater\Domain\Product\Model;
use BornFree\TacticianDomainEvent\Recorder\ContainsRecordedEvents;
use BornFree\TacticianDomainEvent\Recorder\EventRecorderCapabilities;
use Ramsey\Uuid\Uuid;
use Whater\Domain\Common\Exception\InvalidUUIDException;
use Whater\Domain\User\Model\User;
use Whater\Domain\Whater\Model\WhaterOrganization;
use Whater\Domain\Whater\Model\WhaterPoint;
use Doctrine\Common\Collections\ArrayCollection;
use Doctrine\Common\Collections\Collection;
use Whater\Domain\Product\Exception\InvalidProductShippingException;
use Whater\Domain\Product\Exception\InvalidProductTypeException;
/**
* Class Product
*
* @package Whater\Domain\Product\Model
*/
class Product implements ContainsRecordedEvents
{
use EventRecorderCapabilities;
public const PRODUCT_TYPE_WATER_SUPPLY = "PT_WATER_SUPPLY";
public const PRODUCT_TYPE_CATALOG = "PT_CATALOG";
public const PRODUCT_TYPE_WATERCOINS = "PT_WATERCOINS";
public const PRODUCT_TYPE_LICENSE = "PT_LICENSE";
public const PRODUCT_TYPE_DISCOUNT = "PT_DISCOUNT";
/**
* @var string
*/
private $uuid;
/**
* @var string
*/
private $productLabel;
/**
* @var string
*/
private $productSlug;
/**
* @var string
*/
private $productShortDescription;
/**
* @var string
*/
private $productDescription;
/**
* @var string
*/
private $productType;
/**
* @var float
*/
private $productPrice;
/**
* @var float
*/
private $productVatPercent;
/**
* @var bool
*/
private $isEnable;
/**
* @var bool
*/
private $isShippable;
/**
* @var float
*/
private $productWeight;
/**
* @var string
*/
private $productLength;
/**
* @var string
*/
private $productWidth;
/**
* @var string
*/
private $productHeight;
/**
* @var WhaterPoint
*/
private $whaterPoint;
/**
* @var WhaterOrganization
*/
private $whaterOrganization;
/**
* @var boolean
*/
private $isInternalProduct;
/**
* @var boolean
*/
private $acceptWhatercoins;
/**
* @var \DateTime
*/
private $createdAt;
/**
* @var null|\DateTime
*/
private $updatedAt;
/**
* @var Collection
*/
private $images;
/**
* @var Collection
*/
private $productVariations;
/**
* @var Collection
*/
private $productAttributes;
/**
* @var array
*/
private $tags;
/**
* @var ProductCategory
*/
private $productCategory;
/**
* @var float
*/
private $whaterCommisionPercent;
/**
* @var Collection
*/
private $countriesToRecommend;
/**
* @var Collection
*/
private $countryAreasToRecommend;
/**
* @var bool
*/
private $recommendToWaterStatusSuitable;
/**
* @var bool
*/
private $recommendToWaterStatusNotSuitable;
/**
* @var bool
*/
private $recommendToWaterStatusWithRestrictions;
/**
* @var bool
*/
private $recommendToWaterStatusUnknown;
/**
* @var int
*/
private $maxDiscountPercentageAllowed;
/**
* @var bool
*/
private $requiresShippingCosts;
/**
* @var string
*/
private $theThingsNetworkDeviceName;
/**
* @var int
*/
private $whaterSupplyMiliseconds;
/**
* @var Collection
*/
private $valorations;
/**
* @var float
*/
private $averageValorations;
/**
* @param string $productId
*/
public function __construct(
string $productId = null,
string $productLabel,
string $productType,
float $productPrice,
float $productVatPercent,
WhaterOrganization $whaterOrganization = null,
string $productShortDescription = null,
string $productDescription = null,
WhaterPoint $whaterPoint = null,
bool $isInternalProduct = false,
float $whaterCommisionPercent = null
) {
try {
$this->uuid = Uuid::fromString($productId ?: Uuid::uuid4())->toString();
} catch (\InvalidArgumentException $e) {
throw new InvalidUUIDException();
}
$this->productLabel = $productLabel;
$this->productSlug = $productLabel;
$this->productShortDescription = $productShortDescription;
$this->productDescription = $productDescription;
switch ($productType) {
case Product::PRODUCT_TYPE_CATALOG:
case Product::PRODUCT_TYPE_DISCOUNT:
case Product::PRODUCT_TYPE_LICENSE:
case Product::PRODUCT_TYPE_WATER_SUPPLY:
case Product::PRODUCT_TYPE_WATERCOINS:
$this->productType = $productType;
break;
default:
throw new InvalidProductTypeException();
}
$this->productPrice = $productPrice;
$this->productVatPercent = $productVatPercent;
$this->whaterCommisionPercent = $whaterCommisionPercent;
$this->isEnable = false;
$this->isShippable = ($this->productType == Product::PRODUCT_TYPE_CATALOG);
$this->recommendToWaterStatusSuitable = false;
$this->recommendToWaterStatusNotSuitable = false;
$this->recommendToWaterStatusWithRestrictions = false;
$this->recommendToWaterStatusUnknown = false;
$this->isInternalProduct = $isInternalProduct;
$this->whaterOrganization = $whaterOrganization;
if ($productType == Product::PRODUCT_TYPE_WATER_SUPPLY) {
$this->whaterPoint = $whaterPoint;
$this->acceptWhatercoins = true;
} else {
$this->acceptWhatercoins = false;
}
if (!$isInternalProduct && $whaterOrganization == null) {
throw new InvalidUUIDException();
}
$this->maxDiscountPercentageAllowed = 0;
$this->requiresShippingCosts = false;
$this->createdAt = new \DateTime();
$this->updatedAt = new \DateTime();
$this->images = new ArrayCollection();
$this->productVariations = new ArrayCollection();
$this->productAttributes = new ArrayCollection();
$this->countriesToRecommend = new ArrayCollection();
$this->countryAreasToRecommend = new ArrayCollection();
$this->valorations = new ArrayCollection();
$this->averageValorations = null;
}
public function editProduct(
string $productLabel,
float $productPrice,
float $productVatPercent,
string $productShortDescription = null,
string $productDescription = null,
bool $isEnable = false,
bool $acceptWhatercoins = false,
float $whaterCommisionPercent = null,
array $tags = null,
ProductCategory $productCategory = null,
bool $recommendToWaterStatusSuitable = false,
bool $recommendToWaterStatusNotSuitable = false,
bool $recommendToWaterStatusWithRestrictions = false,
bool $recommendToWaterStatusUnknown = false,
int $maxDiscountPercentageAllowed = null
) {
$this->productLabel = $productLabel;
$this->productShortDescription = $productShortDescription;
$this->productDescription = $productDescription;
$this->productPrice = $productPrice;
$this->productVatPercent = $productVatPercent;
$this->whaterCommisionPercent = $whaterCommisionPercent;
$this->acceptWhatercoins = $acceptWhatercoins;
$this->isEnable = $isEnable;
$this->tags = $tags;
$this->productCategory = $productCategory;
$this->recommendToWaterStatusSuitable = $recommendToWaterStatusSuitable;
$this->recommendToWaterStatusNotSuitable = $recommendToWaterStatusNotSuitable;
$this->recommendToWaterStatusWithRestrictions = $recommendToWaterStatusWithRestrictions;
$this->recommendToWaterStatusUnknown = $recommendToWaterStatusUnknown;
$this->maxDiscountPercentageAllowed = $maxDiscountPercentageAllowed;
$this->updatedAt = new \DateTime();
}
public function editShipmentData(
bool $isShippable = false,
bool $requiresShippingCosts = false,
float $productWeight = null,
float $productLength = null,
float $productWidth = null,
float $productHeight = null
) {
if ($this->productType() == Product::PRODUCT_TYPE_CATALOG) {
$this->isShippable = $isShippable;
} else {
$this->isShippable = false;
}
$this->requiresShippingCosts = $requiresShippingCosts;
$this->productWeight = $productWeight;
$this->productLength = $productLength;
$this->productWidth = $productWidth;
$this->productHeight = $productHeight;
if ($this->isShippable) {
$this->productWeight = $this->productWeight ?? 1;
$this->productLength = $this->productLength ?? 1;
$this->productWidth = $this->productWidth ?? 1;
$this->productHeight = $this->productHeight ?? 1;
}
}
public function editWhaterSupply(
string $theThingsNetworkDeviceName = null,
int $whaterSupplyMiliseconds = null
) {
if ($this->productType == Product::PRODUCT_TYPE_WATER_SUPPLY) {
$this->theThingsNetworkDeviceName = $theThingsNetworkDeviceName;
$this->whaterSupplyMiliseconds = $whaterSupplyMiliseconds;
if ($whaterSupplyMiliseconds < 10) {
$this->whaterSupplyMiliseconds = 10;
}
}
}
public function editZonesToRecommend(
ArrayCollection $countriesToRecommend,
ArrayCollection $countryAreasToRecommend
) {
$this->countriesToRecommend()->clear();
foreach ($countriesToRecommend as $country) {
$this->countriesToRecommend->add($country);
}
$this->countryAreasToRecommend()->clear();
foreach ($countryAreasToRecommend as $countryArea) {
$this->countryAreasToRecommend->add($countryArea);
}
$this->updatedAt = new \DateTime();
}
public function updateAverageValorations()
{
$numValorations = 0;
$sumValorations = 0;
foreach ($this->valorations() as $valoration) {
$numValorations++;
$sumValorations = $sumValorations + $valoration->rating();
}
if ($numValorations == 0) {
$this->averageValorations = null;
} else {
$this->averageValorations = round($sumValorations / $numValorations, 2);
}
}
/**
* @deprecated
*/
public function calculateWhatercoinsForDiscount(float $discountPercent, string $productVariationId = null)
{
$productPrice = $this->productPrice();
if ($productVariationId != null) {
foreach ($this->productVariations() as $productVariation) {
if ($productVariation->id() == $productVariationId) {
$productPrice = $productVariation->productVariationPrice();
break;
}
}
}
$discountInMoney = ($productPrice * $discountPercent / 100);
$discountInWhatercoins = $discountInMoney * 100;
if ($productPrice > 200) {
$realDiscount = 0.9;
} else if ($productPrice > 100) {
$realDiscount = 0.85;
} else if ($productPrice > 50) {
$realDiscount = 0.8;
} else {
$realDiscount = 0.75;
}
return round($discountInWhatercoins * $realDiscount, 2);
}
public function setAsInternalProduct(
bool $isInternalProduct
) {
$this->isInternalProduct = $isInternalProduct;
}
public function firstImage()
{
$firstImage = null;
foreach ($this->images() as $productImage) {
$firstImage = $productImage;
break;
}
return $firstImage;
}
/**
* @return string
*/
public function id(): string
{
return $this->uuid;
}
/**
* @return string
*/
public function productLabel(): string
{
return $this->productLabel;
}
/**
* @return string
*/
public function productSlug(): string
{
return $this->productSlug;
}
/**
* @return string
*/
public function theThingsNetworkDeviceName(): ?string
{
return $this->theThingsNetworkDeviceName;
}
/**
* @return int
*/ public function whaterSupplyMiliseconds(): ?int
{
return $this->whaterSupplyMiliseconds;
}
/**
* @return bool
*/
public function isEnable(): bool
{
return $this->isEnable;
}
/**
* @return bool
*/
public function isShippable(): bool
{
return $this->isShippable;
}
/**
* @return float
*/
public function productWeight(): ?float
{
return $this->productWeight;
}
/**
* @return float
*/
public function productLength(): ?float
{
return $this->productLength;
}
/**
* @return float
*/
public function productWidth(): ?float
{
return $this->productWidth;
}
/**
* @return float
*/
public function productHeight(): ?float
{
return $this->productHeight;
}
/**
* @return bool
*/
public function acceptWhatercoins(): bool
{
return $this->acceptWhatercoins;
}
/**
* @return float
*/
public function averageValorations(): ?float
{
return $this->averageValorations;
}
/**
* @return string
*/
public function productShortDescription(): ?string
{
return $this->productShortDescription;
}
/**
* @return string
*/
public function productDescription(): ?string
{
return $this->productDescription;
}
/**
* @return string
*/
public function productType(): string
{
return $this->productType;
}
/**
* @return float
*/
public function productPrice(): float
{
return $this->productPrice;
}
/**
* @return float
*/
public function productVatPercent(): float
{
return $this->productVatPercent;
}
/**
* @return float
*/
public function whaterCommisionPercent(): float
{
return $this->whaterCommisionPercent;
}
/**
* @return WhaterOrganization|null
*/
public function whaterOrganization(): ?WhaterOrganization
{
return $this->whaterOrganization;
}
/**
* @return bool
*/
public function isInternalProduct(): bool
{
return $this->isInternalProduct;
}
/**
* @return WhaterPoint|null
*/
public function whaterPoint(): ?WhaterPoint
{
return $this->whaterPoint;
}
/**
* @return \DateTime
*/
public function createdAt(): \DateTime
{
return $this->createdAt;
}
/**
* @return \DateTime|null
*/
public function updatedAt()
{
return $this->updatedAt;
}
public function images(): Collection
{
return $this->images;
}
public function productAttributes(): Collection
{
return $this->productAttributes;
}
public function productVariations(): Collection
{
return $this->productVariations;
}
public function countriesToRecommend(): Collection
{
return $this->countriesToRecommend;
}
public function countryAreasToRecommend(): Collection
{
return $this->countryAreasToRecommend;
}
public function tags(): ?array
{
return $this->tags;
}
public function productCategory(): ?ProductCategory
{
return $this->productCategory;
}
/**
* @return bool
*/
public function recommendToWaterStatusSuitable(): bool
{
return $this->recommendToWaterStatusSuitable;
}
/**
* @return bool
*/
public function recommendToWaterStatusNotSuitable(): bool
{
return $this->recommendToWaterStatusNotSuitable;
}
/**
* @return bool
*/
public function recommendToWaterStatusWithRestrictions(): bool
{
return $this->recommendToWaterStatusWithRestrictions;
}
/**
* @return bool
*/
public function recommendToWaterStatusUnknown(): bool
{
return $this->recommendToWaterStatusUnknown;
}
/**
* @return int
*/
public function maxDiscountPercentageAllowed(): int
{
return $this->maxDiscountPercentageAllowed;
}
/**
* @return bool
*/
public function requiresShippingCosts(): bool
{
return $this->requiresShippingCosts;
}
/**
* @return Collection
*/
public function valorations(): Collection
{
return $this->valorations;
}
/**
* @return bool
*/
public function equals(Product $product)
{
return $this->id() === $product->id();
}
}