<?php
declare(strict_types=1);
namespace App\Entity;
use DateTime;
use Doctrine\Common\Collections\ArrayCollection;
use Doctrine\Common\Collections\Collection;
use Doctrine\ORM\Mapping as ORM;
use Symfony\Component\Validator\Constraints as Assert;
/**
* @ORM\Table(name="`order`")
* @ORM\Entity(repositoryClass="App\Repository\OrderRepository")
*/
class Order
{
public const STATE_PENDING = 0;
public const STATE_ACCEPTED = 1;
public const STATE_PAID = 2;
public const STATE_PAYMENTPENDING = 3;
public const STATE_REFUNDED = 4;
public const STATE_CANCELED = 5;
public const PAYMENTMODE_CB = 0;
public const PAYMENTMODE_WIRE = 1;
public const PAYMENTMODE_OFFLINE = 2;
/**
* @ORM\Column(name="id", type="integer")
* @ORM\Id
* @ORM\GeneratedValue(strategy="AUTO")
*/
private $id;
/**
* @ORM\Column(type="string", length=10, nullable=false)
*/
private $reference;
/**
* @ORM\OneToOne(targetEntity="App\Entity\Payment")
*/
private $payment;
/**
* @ORM\OneToOne(targetEntity="App\Entity\UserSurvey", inversedBy="order", cascade={"persist","remove"})
* @ORM\JoinColumn(name="user_survey_id", referencedColumnName="id", onDelete="CASCADE")
*/
private $userSurvey;
/**
* @ORM\Column(type="decimal", precision=9, scale=3, nullable=false)
*/
private $amount;
/**
* @ORM\Column(type="decimal", precision=9, scale=3, nullable=false)
*/
private $amountNoDiscount;
/**
* @ORM\Column(type="string", length=3, nullable=false)
*/
private $currency;
/**
* @ORM\Column(type="smallint", nullable=true)
*/
private $paymentMode;
/**
* @ORM\Column(type="string", length=50, nullable=true)
*/
private $paymentProvider;
/**
* @ORM\Column(type="string", length=50, nullable=true)
*/
private $paymentStatus;
/**
* @ORM\Column(type="smallint", nullable=false)
*/
private $state;
private $stateLabel;
/**
* @Assert\NotBlank(groups={"order_confirm"})
* @Assert\NotNull(groups={"order_confirm"})
* @ORM\Column(type="boolean", nullable=false)
*/
private $isLegalNoticeValidated;
/**
* @ORM\Column(type="datetime", nullable=true)
*/
private $dateAdd;
/**
* @ORM\Column(type="datetime", nullable=true)
*/
private $dateUpdate;
/**
* @ORM\Column(type="datetime", nullable=true)
*/
private $dateLegalNoticeValidated;
/**
* @ORM\Column(type="datetime", nullable=true)
*/
private $datePayment;
/**
* @ORM\Column(type="datetime", nullable=true)
*/
private $dateCancel;
/**
* @ORM\Column(type="boolean", nullable=true)
*/
private $isCompletedOnce;
/**
* @ORM\ManyToMany(targetEntity="App\Entity\Discount", inversedBy="orders",cascade={"persist"})
* @ORM\JoinColumn(nullable=true)
*/
private $discounts;
/**
* @ORM\Column(type="decimal", precision=9, scale=3, nullable=false)
*/
private $discountAmount;
/**
* @ORM\Column(type="integer", nullable=true)
*/
private $bexioInvoiceId;
/**
* @ORM\OneToMany(targetEntity=OrderSupplement::class, mappedBy="relatedOrder", orphanRemoval=true,cascade={"persist"})
*/
private $orderSupplements;
/**
* @ORM\Column(type="integer", nullable=true)
*/
private $affiliationCount;
/**
* @ORM\Column(type="boolean", nullable=true)
*/
private $bexioIsPaid;
/**
* Order constructor.
*
* @throws \Exception
*/
public function __construct(float $amount,
UserSurvey $userSurvey,
string $currency = 'CHF',
bool $isLegalNoticeValidated = false,
int $state = Order::STATE_PENDING)
{
$this->reference = substr(md5($userSurvey->getId() . time()), 0, 10);
$this->amount = $amount;
$this->amountNoDiscount = $amount;
$this->userSurvey = $userSurvey;
$this->currency = $currency;
$this->isLegalNoticeValidated = $isLegalNoticeValidated;
$this->state = $state;
$this->dateAdd = new DateTime();
$this->dateUpdate = new DateTime();
$this->discounts = new ArrayCollection();
$this->discountAmount = 0;
$this->orderSupplements = new ArrayCollection();
}
public function getId(): ?int
{
return $this->id;
}
public function setId(?int $id): Order
{
$this->id = $id;
return $this;
}
public function getAmount(): float
{
return (float)$this->amount;
}
public function setAmount(float $amount): Order
{
$this->amount = $amount;
if (!is_null($this->userSurvey)) {
$this->userSurvey->setPrice($amount);
}
return $this;
}
public function getCurrency(): string
{
return $this->currency;
}
public function setCurrency(string $currency): Order
{
$this->currency = $currency;
return $this;
}
public function isLegalNoticeValidated(): bool
{
return $this->isLegalNoticeValidated;
}
public function getIsLegalNoticeValidated(): ?bool
{
return $this->isLegalNoticeValidated;
}
public function setIsLegalNoticeValidated(bool $isLegalNoticeValidated): Order
{
$this->isLegalNoticeValidated = $isLegalNoticeValidated;
return $this;
}
public function getDateLegalNoticeValidated(): DateTime
{
return $this->dateLegalNoticeValidated;
}
public function setDateLegalNoticeValidated(DateTime $dateLegalNoticeValidated): Order
{
$this->dateLegalNoticeValidated = $dateLegalNoticeValidated;
return $this;
}
public function getDatePayment(): ?DateTime
{
return $this->datePayment;
}
public function setDatePayment(?DateTime $datePayment): Order
{
$this->datePayment = $datePayment;
return $this;
}
public function getDateCancel(): ?DateTime
{
return $this->dateCancel;
}
public function setDateCancel(?DateTime $dateCancel): Order
{
$this->dateCancel = $dateCancel;
return $this;
}
public function getStateLabel(): string
{
switch ($this->getState()) {
case Order::STATE_PAID === $this->getState():
$this->setStateLabel('Payée');
break;
case Order::STATE_PAYMENTPENDING === $this->getState():
$this->setStateLabel('Paiement en cours');
break;
case Order::STATE_ACCEPTED === $this->getState():
$this->setStateLabel('Acceptée');
break;
case Order::STATE_PENDING === $this->getState():
$this->setStateLabel('En attente de d\'acceptation');
break;
case Order::STATE_REFUNDED === $this->getState():
$this->setStateLabel('Remboursée');
break;
case Order::STATE_CANCELED === $this->getState():
$this->setStateLabel('Annulée');
break;
default:
$this->setStateLabel('Commande créée');
}
return $this->stateLabel;
}
public function getState(): int
{
return $this->state;
}
public function setState(int $state): Order
{
$this->state = $state;
return $this;
}
private function setStateLabel(string $stateLabel): Order
{
$this->stateLabel = $stateLabel;
return $this;
}
public function getDateAdd(): ?DateTime
{
return $this->dateAdd;
}
public function setDateAdd(?DateTime $dateAdd): Order
{
$this->dateAdd = $dateAdd;
return $this;
}
public function getDateUpdate(): ?DateTime
{
return $this->dateUpdate;
}
public function setDateUpdate(?DateTime $dateUpdate): Order
{
$this->dateUpdate = $dateUpdate;
return $this;
}
public function getPayment(): ?Payment
{
return $this->payment;
}
public function setPayment(?Payment $payment): self
{
$this->payment = $payment;
return $this;
}
public function getReference(): ?string
{
return $this->reference;
}
public function setReference(string $reference): self
{
$this->reference = $reference;
return $this;
}
public function getPaymentMode(): ?int
{
return $this->paymentMode;
}
public function setPaymentMode(?int $paymentMode): self
{
$this->paymentMode = $paymentMode;
return $this;
}
public function getPaymentProvider(): ?string
{
return $this->paymentProvider;
}
public function setPaymentProvider(?string $paymentProvider): self
{
$this->paymentProvider = $paymentProvider;
return $this;
}
public function isPaid(): ?bool
{
if (2 == $this->state) {
return true;
}
return false;
}
public function isPaymentPending(): ?bool
{
if ($this->state < 2) {
return true;
}
return false;
}
public function isPaymentProcessing(): ?bool
{
if (3 == $this->state) {
return true;
}
return false;
}
public function getPaymentStatus(): ?string
{
return $this->paymentStatus;
}
/**
* Preferable d'utilisé UserSurvey setPaymentStatus,.
*/
public function setPaymentStatus(?string $paymentStatus): self
{
if ('payedout' == $paymentStatus || 'captured' == $paymentStatus) {
$this->setState(Order::STATE_PAID);
} elseif ('canceled' == $paymentStatus) {
$this->setState(Order::STATE_CANCELED);
} elseif ('pending' == $paymentStatus) {
$this->setState(Order::STATE_PAYMENTPENDING);
}
$this->paymentStatus = $paymentStatus;
return $this;
}
public function getIsCompletedOnce(): ?bool
{
return $this->isCompletedOnce;
}
public function setIsCompletedOnce(?bool $isCompletedOnce): self
{
$this->isCompletedOnce = $isCompletedOnce;
return $this;
}
public function addDiscount(Discount $discount): self
{
if (!$this->discounts->contains($discount)) {
$this->discounts[] = $discount;
}
return $this;
}
public function removeDiscount(Discount $discount): self
{
if ($this->discounts->contains($discount)) {
$this->discounts->removeElement($discount);
}
return $this;
}
public function getAmountNoDiscount(): ?float
{
return (float)$this->amountNoDiscount;
}
public function setAmountNoDiscount(float $amountNoDiscount): self
{
$this->amountNoDiscount = $amountNoDiscount;
return $this;
}
public function getBexioInvoiceId(): ?int
{
return $this->bexioInvoiceId;
}
public function setBexioInvoiceId(int $bexioInvoiceId): self
{
$this->bexioInvoiceId = $bexioInvoiceId;
return $this;
}
public function updateAmounts($price): void
{
$totalSupplements = 0;
$totalReductions = 0;
$priceModified = $price;
/*
* Les supplements sont appliqués sur le prix de base
*/
foreach ($this->getOrderSupplements() as $supplement) {
$supplementAmount = $supplement->calculateAmount($price);
$totalSupplements += $supplementAmount;
$priceModified += $supplementAmount;
}
/*
* Les réductions sont appliquées sur le prix avec les supplements
*/
foreach ($this->getDiscounts() as $discount) {
$reduction = 0;
if ('AFFILIATION' == $discount->getType() && $discount->getUser() == $this->getUserSurvey()->getUser()) {
// parrainage
if ($this->getAffiliationCount() > 0) {
for ($i = 1; $i <= $this->getAffiliationCount(); ++$i) {
if ($priceModified > 0) {
$reduction += $discount->calculateAmount($priceModified);
}
}
}
} else {
// dans tous les autres cas
$reduction = $discount->calculateAmount($priceModified);
}
$priceModified -= $reduction;
$totalReductions += $reduction;
}
if ($totalReductions > $price) {
$totalReductions = $price;
}
/*
* Ensuite, on ajoute les supplement et on déduit les réductions
*/
$this->setAmountNoDiscount($price);
$this->setDiscountAmount($totalReductions);
$this->setAmount(round($price + $totalSupplements - $totalReductions, 2));
}
/**
* @return Collection<int, OrderSupplement>
*/
public function getOrderSupplements(): Collection
{
return $this->orderSupplements;
}
/**
* @return Collection|Discount[]
*/
public function getDiscounts(): Collection
{
return $this->discounts;
}
public function getUserSurvey(): UserSurvey
{
return $this->userSurvey;
}
public function setUserSurvey(UserSurvey $userSurvey): Order
{
$this->userSurvey = $userSurvey;
return $this;
}
public function getAffiliationCount(): ?int
{
return $this->affiliationCount;
}
public function setAffiliationCount(?int $affiliationCount): self
{
$this->affiliationCount = $affiliationCount;
return $this;
}
public function getDiscountAmount(): float
{
return (float)$this->discountAmount;
}
public function setDiscountAmount(float $discountAmount): self
{
$this->discountAmount = $discountAmount;
return $this;
}
public function addOrderSupplement(OrderSupplement $orderSupplement): self
{
if (!$this->orderSupplements->contains($orderSupplement)) {
$this->orderSupplements[] = $orderSupplement;
$orderSupplement->setRelatedOrder($this);
}
return $this;
}
public function removeOrderSupplement(OrderSupplement $orderSupplement): self
{
if ($this->orderSupplements->removeElement($orderSupplement)) {
// set the owning side to null (unless already changed)
if ($orderSupplement->getRelatedOrder() === $this) {
$orderSupplement->setRelatedOrder(null);
}
}
return $this;
}
public function hasFidelity(): bool
{
foreach ($this->getDiscounts() as $discount) {
if ('FIDELITY' == $discount->getType()) {
return true;
}
}
return false;
}
public function hasAffiliation(): bool
{
foreach ($this->getDiscounts() as $discount) {
if ('AFFILIATION' == $discount->getType()) {
return true;
}
}
return false;
}
public function isBexioIsPaid(): ?bool
{
return $this->bexioIsPaid;
}
public function setBexioIsPaid(?bool $bexioIsPaid): self
{
$this->bexioIsPaid = $bexioIsPaid;
return $this;
}
}