<?php
namespace App\Entity\OnlineShop;
use App\Annotation\SiteAware;
use App\Entity\AbstractBase;
use App\Entity\Address;
use App\Entity\Garages\Garage;
use App\Entity\Interfaces\SiteInterface;
use App\Entity\Traits\GarageTrait;
use App\Entity\Traits\SiteTrait;
use App\Entity\User;
use App\Entity\Whatsapp\WhatsappOrder;
use App\Enum\OrderStatusTypeEnum;
use App\Repository\OnlineShop\OrderRepository;
use Doctrine\Common\Collections\ArrayCollection;
use Doctrine\Common\Collections\Collection;
use Doctrine\ORM\Mapping as ORM;
use Gedmo\Mapping\Annotation as Gedmo;
use Money\Currency;
use Money\Money;
use Symfony\Component\Security\Core\User\UserInterface;
use Tbbc\MoneyBundle\Formatter\MoneyFormatter;
/**
* @ORM\Table(name="vulco_order", indexes={@ORM\Index(name="order_site_idx", columns={"site"})})
*
* @ORM\Entity(repositoryClass=OrderRepository::class)
*
* @Gedmo\SoftDeleteable(fieldName="removedAt", timeAware=false)
*
* @SiteAware(siteFieldName="site")
*/
class Order extends AbstractBase implements SiteInterface
{
use GarageTrait;
use SiteTrait;
/**
* @ORM\Column(type="string", length=200)
*/
private string $reference;
/**
* @ORM\Column(type="integer")
*/
private int $state;
/**
* @ORM\Column(type="integer")
*/
private int $totalPriceAmount;
/**
* @ORM\Column(type="string")
*/
private string $totalPriceCurrency;
/**
* @ORM\Column(type="money", options={"default": "EUR 0"})
*/
private Money $totalRappel;
private bool $blocked = false;
/**
* @ORM\Column(type="datetime", nullable=true)
*/
private ?\DateTimeInterface $processedAt = null;
/**
* @ORM\Column(type="boolean", options={"default": 0})
*/
private bool $rebilled = false;
/**
* @ORM\ManyToOne(targetEntity="App\Entity\OnlineShop\Supplier")
*
* @ORM\JoinColumn(name="supplier_id", referencedColumnName="id", onDelete="SET NULL")
*/
private ?Supplier $supplier = null;
/**
* @ORM\OneToMany(targetEntity="App\Entity\OnlineShop\ProductOrder", mappedBy="order", cascade={"persist"}, orphanRemoval=true)
*/
private ?Collection $products;
/**
* @ORM\OneToMany(targetEntity="App\Entity\OnlineShop\OrderSupplierShippingCost", mappedBy="order", cascade={"persist", "remove"}, orphanRemoval=true)
*/
private ?Collection $shipments;
/**
* @ORM\OneToMany(targetEntity="App\Entity\OnlineShop\OrderFamilyDiscount", mappedBy="order", cascade={"persist", "remove"}, orphanRemoval=true)
*/
private ?Collection $discounts;
/**
* @ORM\ManyToOne(targetEntity="App\Entity\Garages\Garage", fetch="EAGER")
*
* @ORM\JoinColumn(name="garage_id", referencedColumnName="id")
*/
private ?Garage $garage = null;
/**
* @ORM\ManyToOne(targetEntity="App\Entity\User", fetch="EAGER")
*
* @ORM\JoinColumn(name="user_id", referencedColumnName="id")
*
* User who has placed the order (could be the associated but an admin too)
*/
private ?User $user = null;
/**
* @ORM\ManyToOne(targetEntity="App\Entity\User", fetch="EAGER")
*
* @ORM\JoinColumn(name="reopened_by_user_id", referencedColumnName="id")
*
* User who has reopened the order
*/
private ?User $reopenedByUser = null;
/**
* @ORM\ManyToOne(targetEntity="App\Entity\Address")
*
* @ORM\JoinColumn(name="address_id", referencedColumnName="id")
*/
private ?Address $shippingAddress = null;
/**
* @ORM\Column(type="text", length=10000, nullable=true)
*/
private ?string $commentUser = null;
/**
* @ORM\Column(type="text", length=10000, nullable=true)
*/
private ?string $commentAdmin = null;
/**
* @ORM\ManyToOne(targetEntity="App\Entity\Whatsapp\WhatsappOrder", cascade={"persist", "remove"})
* @ORM\JoinColumn(name="whatsapp_order_id", referencedColumnName="id", nullable=true)
*/
private ?WhatsappOrder $whatsappOrder = null;
public function __construct()
{
$this->products = new ArrayCollection();
$this->shipments = new ArrayCollection();
$this->discounts = new ArrayCollection();
$this->state = OrderStatusTypeEnum::PENDING;
}
public function getReference(): string
{
return $this->reference;
}
public function setReference(string $reference): self
{
$this->reference = $reference;
return $this;
}
public function getState(): int
{
return $this->state;
}
public function setState(int $state): self
{
$this->state = $state;
return $this;
}
public function getTotalPriceAmount(): int
{
return $this->totalPriceAmount;
}
public function setTotalPriceAmount(int $totalPriceAmount): self
{
$this->totalPriceAmount = $totalPriceAmount;
return $this;
}
public function getTotalPriceCurrency(): string
{
return $this->totalPriceCurrency;
}
public function setTotalPriceCurrency(string $totalPriceCurrency): self
{
$this->totalPriceCurrency = $totalPriceCurrency;
return $this;
}
public function getTotalRappel(): Money
{
return $this->totalRappel;
}
public function setTotalRappel(Money $totalRappel): self
{
$this->totalRappel = $totalRappel;
return $this;
}
public function getTotalRappelAsString(): string
{
$moneyFormatter = new MoneyFormatter(2);
return $moneyFormatter->localizedFormatMoney($this->totalRappel);
}
public function isBlocked(): bool
{
return $this->blocked;
}
public function getBlocked(): bool
{
return $this->isBlocked();
}
public function setBlocked(bool $blocked): self
{
$this->blocked = $blocked;
return $this;
}
public function getProcessedAt(): ?\DateTimeInterface
{
return $this->processedAt;
}
public function getProcessedAtAsString(): string
{
return $this->getDateTimeAsString($this->getProcessedAt());
}
public function setProcessedAt(?\DateTimeInterface $processedAt): self
{
$this->processedAt = $processedAt;
return $this;
}
public function isRebilled(): bool
{
return $this->rebilled;
}
public function setRebilled(bool $rebilled): self
{
$this->rebilled = $rebilled;
return $this;
}
public function getSupplier(): ?Supplier
{
return $this->supplier;
}
public function setSupplier(?Supplier $supplier): self
{
$this->supplier = $supplier;
return $this;
}
public function getProducts(): ?Collection
{
return $this->products;
}
public function setProducts(?Collection $products): self
{
$this->products = $products;
return $this;
}
public function addProduct(ProductOrder $product): self
{
if (!$this->products->contains($product)) {
$this->products->add($product);
$product->setOrder($this);
}
return $this;
}
public function removeProduct(ProductOrder $product): self
{
if ($this->products->contains($product)) {
$this->products->removeElement($product);
}
return $this;
}
public function getShipments(): ?Collection
{
return $this->shipments;
}
public function setShipments(?Collection $shipments): self
{
$this->shipments = $shipments;
return $this;
}
public function addShipment(OrderSupplierShippingCost $shipment): self
{
if (!$this->shipments->contains($shipment)) {
$this->shipments->add($shipment);
$shipment->setOrder($this);
if ($shipment->isBlocked()) {
$this->setBlocked(true);
}
}
return $this;
}
public function removeShipment(OrderSupplierShippingCost $shipment): self
{
if ($this->shipments->contains($shipment)) {
$this->shipments->removeElement($shipment);
}
return $this;
}
public function getDiscounts(): ?Collection
{
return $this->discounts;
}
public function setDiscounts(?Collection $discounts): self
{
$this->discounts = $discounts;
return $this;
}
public function addDiscount(OrderFamilyDiscount $discount): self
{
if (!$this->discounts->contains($discount)) {
$this->discounts->add($discount);
$discount->setOrder($this);
}
return $this;
}
public function removeDiscount(OrderFamilyDiscount $discount): self
{
if ($this->discounts->contains($discount)) {
$this->discounts->removeElement($discount);
}
return $this;
}
/**
* User who has placed the order (could be the associated but an admin too).
*/
public function getUser(): ?User
{
return $this->user;
}
public function setUser(?UserInterface $user): self
{
$this->user = $user;
return $this;
}
/**
* User who has reopened the order.
*/
public function getReopenedByUser(): ?User
{
return $this->reopenedByUser;
}
public function setReopenedByUser(?UserInterface $user): self
{
$this->reopenedByUser = $user;
return $this;
}
public function getShippingAddress(): ?Address
{
return $this->shippingAddress;
}
public function setShippingAddress(?Address $shippingAddress): self
{
$this->shippingAddress = $shippingAddress;
return $this;
}
public function getCommentUser(): ?string
{
return $this->commentUser;
}
public function setCommentUser(?string $commentUser): self
{
$this->commentUser = $commentUser;
return $this;
}
public function getCommentAdmin(): ?string
{
return $this->commentAdmin;
}
public function setCommentAdmin(?string $commentAdmin): self
{
$this->commentAdmin = $commentAdmin;
return $this;
}
public function getWhatsappOrder(): ?WhatsappOrder
{
return $this->whatsappOrder;
}
public function setWhatsappOrder(?WhatsappOrder $whatsappOrder): Order
{
$this->whatsappOrder = $whatsappOrder;
return $this;
}
public function getTotalPrice(): ?Money
{
if (!$this->totalPriceCurrency) {
return null;
}
if (!$this->totalPriceAmount) {
return new Money(0, new Currency($this->totalPriceCurrency));
}
return new Money($this->totalPriceAmount, new Currency($this->totalPriceCurrency));
}
public function setTotalPrice(Money $price): self
{
$this->totalPriceAmount = $price->getAmount();
$this->totalPriceCurrency = $price->getCurrency()->getCode();
return $this;
}
public function calculateTotalPrice(): Money
{
$totalPrice = new Money(0, new Currency(self::DEFAULT_EURO_CURRENCY));
foreach ($this->products as $productOrder) {
$totalPrice = $totalPrice->add($productOrder->getTotalPrice());
}
foreach ($this->getShipments() as $shipment) {
$totalPrice = $totalPrice->add($shipment->getPrice());
}
foreach ($this->getDiscounts() as $discount) {
$totalPrice = $totalPrice->subtract($discount->getPrice());
}
return $totalPrice;
}
public function calculateTotalRappel(): Money
{
$totalRappel = new Money(0, new Currency(self::DEFAULT_EURO_CURRENCY));
/** @var ProductOrder $productOrder */
foreach ($this->products as $productOrder) {
$rappelPercentage = $productOrder->getProduct()->getFamily()->getSupplier()->getRappelPercentage();
if ($productOrder->getProduct()->hasSpecialPriceActive()) {
$rappel = $productOrder->getProduct()->getSpecialPriceActive()->getPrice()->multiply($rappelPercentage / 100);
} else {
$rappel = $productOrder->getRatePrice()->multiply($rappelPercentage / 100);
}
$rappel = $rappel->multiply($productOrder->getQuantity());
$totalRappel = $totalRappel->add($rappel);
}
/** @var OrderFamilyDiscount $discount */
foreach ($this->getDiscounts() as $discount) {
$rappelPercentage = $discount->getFamily()->getSupplier()->getRappelPercentage();
$rappel = $discount->getPrice()->multiply($rappelPercentage / 100);
$totalRappel = $totalRappel->subtract($rappel);
}
return $totalRappel;
}
public function isPending(): bool
{
return OrderStatusTypeEnum::PENDING === $this->state;
}
public function isReturned(): bool
{
return OrderStatusTypeEnum::RETURNED === $this->state;
}
public function isProcessed(): bool
{
return OrderStatusTypeEnum::PROCESSED === $this->state;
}
}