<?php
namespace App\Entity\PointsCatalog;
use App\Annotation\SiteAware;
use App\Entity\AbstractBase;
use App\Entity\Interfaces\SiteInterface;
use App\Entity\MiniAbstractBase;
use App\Entity\Traits\SiteTrait;
use App\Entity\User;
use App\Enum\CatalogOrderStatusEnum;
use App\Exception\CatalogOrderLineCannotBeCancelled;
use App\Exception\PointsLimitException;
use App\Repository\PointsCatalog\CatalogOrderGiftRepository;
use Doctrine\ORM\Mapping as ORM;
use Gedmo\Mapping\Annotation as Gedmo;
use Money\Currency;
use Money\Money;
/**
* @ORM\Table(name="vulco_points_catalog_order_gift", indexes={@ORM\Index(name="catalog_order_gift_site_idx", columns={"site"})})
* @ORM\Entity(repositoryClass=CatalogOrderGiftRepository::class)
* @Gedmo\SoftDeleteable(fieldName="removedAt", timeAware=false)
* @SiteAware(siteFieldName="site")
*/
class CatalogOrderGift extends AbstractBase implements SiteInterface
{
use SiteTrait;
/**
* @ORM\ManyToOne(targetEntity="App\Entity\PointsCatalog\CatalogOrder", inversedBy="gifts")
* @ORM\JoinColumn(name="order_id", referencedColumnName="id")
*/
private CatalogOrder $catalogOrder;
/**
* @ORM\ManyToOne(targetEntity="App\Entity\PointsCatalog\CatalogGift")
* @ORM\JoinColumn(name="gift_id", referencedColumnName="id")
*/
private ?CatalogGift $gift;
/**
* @ORM\ManyToOne(targetEntity="App\Entity\PointsCatalog\CatalogGiftProvider")
* @ORM\JoinColumn(name="provider_id", referencedColumnName="id")
*/
private ?CatalogGiftProvider $provider;
/**
* @ORM\ManyToOne(targetEntity="App\Entity\PointsCatalog\CatalogSize")
* @ORM\JoinColumn(name="size_id", referencedColumnName="id")
*/
private ?CatalogSize $size;
/**
* @ORM\Column(type="integer")
*/
private int $unitPointsValue;
/**
* @ORM\Column(type="integer")
*/
private int $units;
/**
* @ORM\Column(type="money", nullable=true)
*/
private ?Money $unitPrice;
/**
* @ORM\Column(type="integer")
*/
private int $state;
/**
* @ORM\Column(type="datetime", nullable=true)
*/
protected ?\DateTimeInterface $processedAt = null;
/**
* @ORM\Column(type="datetime", nullable=true)
*/
protected ?\DateTimeInterface $cancelledAt = null;
public function __construct(CatalogOrder $order, int $units, int $unitPointsValue, CatalogGift $gift = null, CatalogSize $size = null, CatalogGiftProvider $provider = null, $unitPrice = null, $state = CatalogOrderStatusEnum::PENDING)
{
$this->catalogOrder = $order;
$this->gift = $gift;
$this->unitPointsValue = $unitPointsValue;
$this->units = $units;
$this->unitPrice = $unitPrice;
$this->size = $size;
$this->provider = $provider;
$this->state = $state;
}
public static function makeCatalogGiftOrderLine(CatalogOrder $order, CatalogGift $gift, int $units, CatalogSize $size = null): self
{
return new self($order, $units, $gift->getPointsValue(), $gift, $size);
}
public static function makeDeliveryOrderLine(CatalogOrder $order, CatalogGiftProvider $provider): self
{
return new self($order, 1, $provider->getDeliveryManagementPoints(), null, null, $provider);
}
public function name(): string
{
$result = '';
if ($this->getGift()) {
$result = $this->getGift()->getName();
if ($this->getSize()) {
$result .= sprintf(' (%s)', $this->getSize()->getName());
}
} elseif (isset($this->provider)) {
$result = sprintf('Portes %s', $this->getProvider()->getName());
}
return $result;
}
public function getName(): string
{
return $this->name();
}
public function size(): ?CatalogSize
{
return $this->size;
}
public function getSize(): ?CatalogSize
{
return $this->size();
}
public function setSize(?CatalogSize $size): self
{
$this->size = $size;
return $this;
}
public function units(): int
{
return $this->units;
}
public function getUnits(): int
{
return $this->units();
}
public function setUnits(int $units): self
{
$this->units = $units;
return $this;
}
public function unitPointsValue(): int
{
return $this->unitPointsValue;
}
public function getUnitPointsValue(): int
{
return $this->unitPointsValue();
}
public function setUnitPointsValue(int $unitPointsValue): self
{
$this->unitPointsValue = $unitPointsValue;
return $this;
}
public function unitPrice(): Money
{
$result = new Money(0, new Currency(MiniAbstractBase::DEFAULT_EURO_CURRENCY));
if (isset($this->unitPrice)) {
$result = $result->add($this->unitPrice);
} elseif ($this->getGift()) {
$result = $result->add($this->getGift()->price());
}
return $result;
}
public function fixUnitPrice(): self
{
if ($this->getGift()) {
$this->unitPrice = $this->getGift()->price();
}
return $this;
}
public function getState(): int
{
return $this->state;
}
public function setState(int $state): self
{
$this->state = $state;
return $this;
}
public function gift(): ?CatalogGift
{
return $this->gift;
}
public function getGift(): ?CatalogGift
{
return $this->gift();
}
public function setGift(?CatalogGift $gift): self
{
$this->gift = $gift;
return $this;
}
public function provider(): ?CatalogGiftProvider
{
if ($this->provider) {
return $this->provider;
}
return $this->getGift() ? $this->getGift()->firstProvider() : null;
}
public function getProvider(): ?CatalogGiftProvider
{
return $this->provider();
}
public function setProvider(?CatalogGiftProvider $provider): self
{
$this->provider = $provider;
return $this;
}
public function catalogOrder(): CatalogOrder
{
return $this->catalogOrder;
}
public function getCatalogOrder(): CatalogOrder
{
return $this->catalogOrder();
}
public function setCatalogOrder(CatalogOrder $catalogOrder): self
{
$this->catalogOrder = $catalogOrder;
return $this;
}
public function totalPoints(): int
{
return $this->units() * $this->unitPointsValue();
}
public function totalPrice(): Money
{
return $this->unitPrice()->multiply($this->units());
}
public function isDeliveryOrderLine(): bool
{
return null !== $this->provider;
}
public function isPending(): bool
{
return CatalogOrderStatusEnum::PENDING === $this->state;
}
public function canBeProcessed(): bool
{
return !$this->isDeliveryOrderLine() && $this->isPending();
}
public function processedAt(): ?\DateTimeInterface
{
return $this->processedAt;
}
public function getProcessedAt(): ?\DateTimeInterface
{
return $this->processedAt();
}
public function setProcessedAt(?\DateTimeInterface $processedAt): self
{
$this->processedAt = $processedAt;
return $this;
}
public function process(): void
{
if (!$this->isProcessed()) {
$this->fixUnitPrice();
$this->processedAt = new \DateTimeImmutable();
$this->state = CatalogOrderStatusEnum::PROCESSED;
}
}
public function isProcessed(): bool
{
return CatalogOrderStatusEnum::PROCESSED === $this->state;
}
/**
* @throws CatalogOrderLineCannotBeCancelled|PointsLimitException
*/
public function cancel(string $reasonToCancelDescription): CatalogPointMovement
{
if (!$this->canBeCancelled()) {
throw new CatalogOrderLineCannotBeCancelled();
}
$this->state = CatalogOrderStatusEnum::CANCELLED;
$this->cancelledAt = new \DateTimeImmutable();
return $this->createReturnPointMovementWithDescriptionAndPoints($reasonToCancelDescription);
}
public function canBeCancelled(): bool
{
return CatalogOrderStatusEnum::PENDING === $this->state;
}
/**
* @throws PointsLimitException
*/
public function createReturnPointMovementWithDescriptionAndPoints(string $description): CatalogPointMovement
{
$pointMovement = new CatalogPointMovement();
$pointMovement
->setGarage($this->catalogOrder()->garage())
->setDescription($description)
->setDate($this->getCreatedAt())
->setUser($this->catalogOrder()->garage()->getOwner())
->setProvider($this->provider())
->setReturnMovement(true)
->setPoints($this->totalPoints(), true) // en las devoluciones de puntos no hay que controlar el límite de puntos (por que son puntos que ya habia ganado antes)
;
return $pointMovement;
}
public function isCancelled(): bool
{
return CatalogOrderStatusEnum::CANCELLED === $this->state;
}
public function cancelledAt(): ?\DateTimeInterface
{
return $this->cancelledAt;
}
public function getCancelledAt(): ?\DateTimeInterface
{
return $this->cancelledAt();
}
public function setCancelledAt(?\DateTimeInterface $cancelledAt): self
{
$this->cancelledAt = $cancelledAt;
return $this;
}
public function owner(): User
{
return $this->catalogOrder()->owner();
}
public function __toString(): string
{
return 'ID'.$this->id.' · OID'.$this->catalogOrder->id.' · GID'.$this->gift->id.' · '.$this->units;
}
}