<?php
/**
* @author Quentin CHATELAIN (contact@scaledev.fr)
* @copyright 2021 - ScaleDEV SAS, 12 RUE CHARLES MORET, 10120 ST ANDRE LES VERGERS
* @license commercial
*/
declare(strict_types=1);
namespace Bluue\SalesBundle\Entity;
use App\Entity\Traits\EntityManagerServiceEntity;
use App\Entity\User;
use App\Entity\Context;
use App\Entity\Currency;
use App\Services\SoftdeleteFilter;
use Bluue\SalesBundle\DoctrineExtensions\EditPricesWithTaxEntity;
use DateTime;
use Doctrine\ORM\NonUniqueResultException;
use Symfony\Component\Uid\Uuid;
use Doctrine\ORM\Mapping as ORM;
use Gedmo\Mapping\Annotation as Gedmo;
use Doctrine\Common\Collections\Criteria;
use Bluue\CustomersBundle\Entity\Customer;
use Doctrine\Common\Collections\Collection;
use Doctrine\Common\Collections\ArrayCollection;
use Symfony\Bridge\Doctrine\IdGenerator\UuidGenerator;
use Bluue\SalesBundle\Repository\DeliveryNoteRepository;
use App\DoctrineExtensions\Cancelable\Traits\UserCancelableEntity;
use App\DoctrineExtensions\Validatable\Traits\UserValidatableEntity;
use App\DoctrineExtensions\Timestampable\Traits\UserTimestampableEntity;
use App\DoctrineExtensions\SoftDeleteable\Traits\UserSoftDeleteableEntity;
use App\Entity\Establishment;
/**
* @ORM\Entity(repositoryClass=DeliveryNoteRepository::class)
* @ORM\Table(name="sales_bundle__delivery_note", indexes={
* @ORM\Index(name="deleted_at", columns={"deleted_at"}),
* @ORM\Index(name="created_at", columns={"created_at"}),
* @ORM\Index(name="updated_at", columns={"updated_at"})
* })
* @Gedmo\SoftDeleteable(fieldName="deletedAt", timeAware=false, hardDelete=false)
*/
class DeliveryNote
{
use UserValidatableEntity;
use UserCancelableEntity;
use UserTimestampableEntity;
use UserSoftDeleteableEntity;
use EditPricesWithTaxEntity;
use EntityManagerServiceEntity;
/**
* @ORM\Id
* @ORM\Column(type="uuid")
* @ORM\GeneratedValue(strategy="CUSTOM")
* @ORM\CustomIdGenerator(class=UuidGenerator::class)
*/
private ?Uuid $id = null;
/**
* @ORM\ManyToOne(targetEntity=Context::class)
*/
private ?Context $context = null;
/**
* @ORM\ManyToOne(targetEntity=Customer::class)
* @ORM\JoinColumn(nullable=false)
*/
private ?Customer $customer = null;
/**
* @ORM\ManyToOne(targetEntity=User::class)
*/
private ?User $commercial = null;
/**
* @ORM\ManyToOne(targetEntity=Customer::class)
*/
private ?Customer $invoice_address = null;
/**
* @ORM\ManyToOne(targetEntity=Customer::class)
*/
private ?Customer $delivery_address = null;
/**
* @ORM\ManyToOne(targetEntity=Customer::class)
*/
private ?Customer $invoiceContact = null;
/**
* @ORM\ManyToOne(targetEntity=Customer::class)
*/
private ?Customer $deliveryContact = null;
/**
* @ORM\ManyToOne(targetEntity=Order::class, inversedBy="delivery_notes")
*/
private ?Order $order = null;
/**
* @ORM\ManyToOne(targetEntity=Invoice::class, inversedBy="delivery_notes")
*/
private ?Invoice $invoice = null;
/**
* @ORM\Column(type="string", length=128, nullable="true")
*/
private ?string $reference = null;
/**
* @ORM\ManyToOne(targetEntity=Currency::class)
*/
private ?Currency $currency = null;
/**
* @ORM\Column(type="decimal", precision=20, scale=12)
*/
private ?string $currency_change_rate = null;
/**
* @ORM\ManyToOne(targetEntity=PaymentMethod::class)
*/
private ?PaymentMethod $payment_method = null;
/**
* @ORM\Column(type="boolean")
*/
private bool $reduced_vat = false;
/**
* @ORM\Column(type="decimal", precision=20, scale=6, nullable="true")
*/
private ?string $total_discount_untaxed = null;
/**
* @ORM\Column(type="decimal", precision=20, scale=6, nullable="true")
*/
private ?string $totalDiscount = null;
/**
* @ORM\Column(type="decimal", precision=20, scale=6, nullable="true")
*/
private ?string $total_amount_no_discount_untaxed = null;
/**
* @ORM\Column(type="decimal", precision=20, scale=6, nullable="true")
*/
private ?string $totalAmountNoDiscount = null;
/**
* @ORM\Column(type="decimal", precision=20, scale=6, nullable="true")
*/
private ?string $total_amount_untaxed = null;
/**
* @ORM\Column(type="decimal", precision=20, scale=6, nullable="true")
*/
private ?string $total_tax_amount = null;
/**
* @ORM\Column(type="decimal", precision=20, scale=6, nullable="true")
*/
private ?string $total_amount = null;
/**
* @ORM\Column(type="json")
*/
private array $options = [];
/**
* @ORM\OneToMany(
* targetEntity=DeliveryNoteLine::class,
* mappedBy="delivery_note",
* cascade={"persist", "remove"},
* fetch="EXTRA_LAZY"
* )
* @ORM\OrderBy({"position" = "ASC"})
*/
private Collection $lines;
/**
* @ORM\ManyToOne(targetEntity=Establishment::class)
*/
private ?Establishment $establishment = null;
public function __construct()
{
$this->lines = new ArrayCollection();
}
/**
* @return Uuid|null
*/
public function getId(): ?Uuid
{
return $this->id;
}
/**
* @return DeliveryNote
*/
public function setId(): self
{
$this->id = null;
return $this;
}
/**
* @return Context|null
*/
public function getContext(): ?Context
{
return $this->context;
}
/**
* @param Context|null $context
* @return DeliveryNote
*/
public function setContext(?Context $context): self
{
$this->context = $context;
return $this;
}
/**
* @return Customer|null
* @throws NonUniqueResultException
*/
public function getCustomer(): ?Customer
{
if ($this->em && $this->customer) {
SoftdeleteFilter::disable($this->em, [Customer::class]);
$customer = $this->em->getRepository(Customer::class)
->createQueryBuilder('c')
->where('c.id = :customerId')
->setParameter('customerId', $this->customer->getId()->toBinary())
->getQuery()
->getOneOrNullResult();
SoftdeleteFilter::enable($this->em, [Customer::class]);
return $customer;
}
return $this->customer;
}
/**
* @param Customer $customer
* @return DeliveryNote
*/
public function setCustomer(Customer $customer): self
{
if ($this->customer && $this->customer->getId() !== $customer->getId()) {
$this->setInvoiceContact(null)->setDeliveryContact(null);
}
$this->customer = $customer;
$this->setDeliveryAddress($customer);
return $this->setInvoiceAddress($customer);
}
/**
* @return User|null
* @throws NonUniqueResultException
*/
public function getCommercial(): ?User
{
if ($this->em && $this->commercial) {
SoftdeleteFilter::disable($this->em, [User::class]);
$commercial = $this->em->getRepository(User::class)
->createQueryBuilder('u')
->where('u.id = :commercialId')
->setParameter('commercialId', $this->commercial->getId()->toBinary())
->getQuery()
->getOneOrNullResult();
SoftdeleteFilter::enable($this->em, [User::class]);
return $commercial;
}
return $this->commercial;
}
/**
* @param User|null $commercial
* @return DeliveryNote
*/
public function setCommercial(?User $commercial): self
{
$this->commercial = $commercial;
return $this;
}
/**
* @return Customer|null
* @throws NonUniqueResultException
*/
public function getInvoiceAddress(): ?Customer
{
if ($this->em && $this->invoice_address) {
SoftdeleteFilter::disable($this->em, [Customer::class]);
$invoiceAddress = $this->em->getRepository(Customer::class)
->createQueryBuilder('c')
->where('c.id = :invoiceAddressId')
->setParameter('invoiceAddressId', $this->invoice_address->getId()->toBinary())
->getQuery()
->getOneOrNullResult();
SoftdeleteFilter::enable($this->em, [Customer::class]);
return $invoiceAddress;
}
return $this->invoice_address;
}
/**
* @param Customer|null $invoice_address
* @return DeliveryNote
*/
public function setInvoiceAddress(?Customer $invoice_address): DeliveryNote
{
$this->invoice_address = $invoice_address;
return $this;
}
/**
* @return Customer|null
* @throws NonUniqueResultException
*/
public function getDeliveryAddress(): ?Customer
{
if ($this->em && $this->delivery_address) {
SoftdeleteFilter::disable($this->em, [Customer::class]);
$deliveryAddress = $this->em->getRepository(Customer::class)
->createQueryBuilder('c')
->where('c.id = :deliveryAddressId')
->setParameter('deliveryAddressId', $this->delivery_address->getId()->toBinary())
->getQuery()
->getOneOrNullResult();
SoftdeleteFilter::enable($this->em, [Customer::class]);
return $deliveryAddress;
}
return $this->delivery_address;
}
/**
* @param Customer|null $delivery_address
* @return DeliveryNote
*/
public function setDeliveryAddress(?Customer $delivery_address): DeliveryNote
{
$this->delivery_address = $delivery_address;
return $this;
}
/**
* @return Customer|null
* @throws NonUniqueResultException
*/
public function getInvoiceContact(): ?Customer
{
if ($this->em && $this->invoiceContact) {
SoftdeleteFilter::disable($this->em, [Customer::class]);
$invoiceContact = $this->em->getRepository(Customer::class)
->createQueryBuilder('c')
->where('c.id = :invoiceContactId')
->setParameter('invoiceContactId', $this->invoiceContact->getId()->toBinary())
->getQuery()
->getOneOrNullResult();
SoftdeleteFilter::enable($this->em, [Customer::class]);
return $invoiceContact;
}
return $this->invoiceContact;
}
/**
* @param Customer|null $invoiceContact
* @return DeliveryNote
*/
public function setInvoiceContact(?Customer $invoiceContact): DeliveryNote
{
$this->invoiceContact = $invoiceContact;
return $this;
}
/**
* @return Customer|null
* @throws NonUniqueResultException
*/
public function getDeliveryContact(): ?Customer
{
if ($this->em && $this->deliveryContact) {
SoftdeleteFilter::disable($this->em, [Customer::class]);
$deliveryContact = $this->em->getRepository(Customer::class)
->createQueryBuilder('c')
->where('c.id = :deliveryContactId')
->setParameter('deliveryContactId', $this->deliveryContact->getId()->toBinary())
->getQuery()
->getOneOrNullResult();
SoftdeleteFilter::enable($this->em, [Customer::class]);
return $deliveryContact;
}
return $this->deliveryContact;
}
/**
* @param Customer|null $deliveryContact
* @return DeliveryNote
*/
public function setDeliveryContact(?Customer $deliveryContact): DeliveryNote
{
$this->deliveryContact = $deliveryContact;
return $this;
}
/**
* @return Order|null
* @throws NonUniqueResultException
*/
public function getOrder(): ?Order
{
if ($this->em && $this->order) {
SoftdeleteFilter::disable($this->em, [Order::class]);
$order = $this->em->getRepository(Order::class)
->createQueryBuilder('o')
->where('o.id = :orderId')
->setParameter('orderId', $this->order->getId()->toBinary())
->getQuery()
->getOneOrNullResult();
SoftdeleteFilter::enable($this->em, [Order::class]);
return $order;
}
return $this->order;
}
/**
* @param Order|null $order
* @return DeliveryNote
* @throws NonUniqueResultException
*/
public function setOrder(?Order $order): self
{
$this->order = $order;
if ($order) {
$this->setCustomer($order->getCustomer());
$this->setCommercial($order->getCommercial());
$this->setInvoiceAddress($order->getInvoiceAddress());
$this->setDeliveryAddress($order->getDeliveryAddress());
$this->setInvoiceContact($order->getInvoiceContact());
$this->setDeliveryContact($order->getDeliveryContact());
$this->setContext($order->getContext());
$this->setEstablishment($order->getEstablishment());
$this->setCurrency($order->getCurrency());
$this->setCurrencyChangeRate($order->getCurrencyChangeRate());
$this->setReducedVat($order->isReducedVat());
if (!empty($order->getOptions()['invoice_address'])) {
$this->addOptions([
'invoice_address' => $order->getOptions()['invoice_address']
]);
}
if (!empty($order->getOptions()['delivery_address'])) {
$this->addOptions([
'delivery_address' => $order->getOptions()['delivery_address']
]);
}
if (!empty($order->getOptions()['note'])) {
$this->addOptions([
'note' => $order->getOptions()['note']
]);
}
if (!empty($order->getOptions()['customerNote'])) {
$this->addOptions([
'customerNote' => $order->getOptions()['customerNote']
]);
}
}
return $this;
}
/**
* @return Invoice|null
* @throws NonUniqueResultException
*/
public function getInvoice(): ?Invoice
{
if ($this->em && $this->invoice) {
SoftdeleteFilter::disable($this->em, [Invoice::class]);
$invoice = $this->em->getRepository(Invoice::class)
->createQueryBuilder('i')
->where('i.id = :invoiceId')
->setParameter('invoiceId', $this->invoice->getId()->toBinary())
->getQuery()
->getOneOrNullResult();
SoftdeleteFilter::enable($this->em, [Invoice::class]);
return $invoice;
}
return $this->invoice;
}
/**
* @param Invoice|null $invoice
* @return DeliveryNote
*/
public function setInvoice(?Invoice $invoice): self
{
$this->invoice = $invoice;
return $this;
}
/**
* @return string|null
*/
public function getReference(): ?string
{
return $this->reference;
}
/**
* @param string|null $reference
* @return DeliveryNote
*/
public function setReference(?string $reference): self
{
$this->reference = $reference;
return $this;
}
/**
* @return Currency|null
*/
public function getCurrency(): ?Currency
{
return $this->currency;
}
/**
* @param Currency|null $currency
* @return DeliveryNote
*/
public function setCurrency(?Currency $currency): DeliveryNote
{
$this->currency = $currency;
return $this->setCurrencyChangeRate($currency->getChangeRate());
}
/**
* @return string|null
*/
public function getCurrencyChangeRate(): ?string
{
return $this->currency_change_rate;
}
/**
* @param string|null $currency_change_rate
* @return DeliveryNote
*/
public function setCurrencyChangeRate(?string $currency_change_rate): DeliveryNote
{
$this->currency_change_rate = $currency_change_rate;
return $this;
}
/**
* @return PaymentMethod|null
* @throws NonUniqueResultException
*/
public function getPaymentMethod(): ?PaymentMethod
{
if ($this->em && $this->payment_method) {
SoftdeleteFilter::disable($this->em, [PaymentMethod::class]);
$payment_method = $this->em->getRepository(PaymentMethod::class)
->createQueryBuilder('pm')
->where('pm.id = :paymentMethodId')
->setParameter('paymentMethodId', $this->payment_method->getId()->toBinary())
->getQuery()
->getOneOrNullResult();
SoftdeleteFilter::enable($this->em, [PaymentMethod::class]);
return $payment_method;
}
return $this->payment_method;
}
/**
* @param PaymentMethod|null $payment_method
*/
public function setPaymentMethod(?PaymentMethod $payment_method): void
{
$this->payment_method = $payment_method;
}
/**
* @return bool
*/
public function isReducedVat(): bool
{
return $this->reduced_vat;
}
/**
* @param bool $reduced_vat
* @return $this
*/
public function setReducedVat(bool $reduced_vat): self
{
$this->reduced_vat = $reduced_vat;
return $this;
}
/**
* @return string|null
*/
public function getTotalDiscountUntaxed(): ?string
{
return $this->total_discount_untaxed;
}
/**
* @param string|null $total_discount_untaxed
* @return DeliveryNote
*/
public function setTotalDiscountUntaxed(?string $total_discount_untaxed): DeliveryNote
{
$this->total_discount_untaxed = $total_discount_untaxed;
return $this;
}
/**
* @return string|null
*/
public function getTotalDiscount(): ?string
{
return $this->totalDiscount;
}
/**
* @param string|null $totalDiscount
* @return DeliveryNote
*/
public function setTotalDiscount(?string $totalDiscount): DeliveryNote
{
$this->totalDiscount = $totalDiscount;
return $this;
}
/**
* @return string|null
*/
public function getTotalAmountNoDiscountUntaxed(): ?string
{
return $this->total_amount_no_discount_untaxed;
}
/**
* @param string|null $total_amount_no_discount_untaxed
* @return DeliveryNote
*/
public function setTotalAmountNoDiscountUntaxed(?string $total_amount_no_discount_untaxed): DeliveryNote
{
$this->total_amount_no_discount_untaxed = $total_amount_no_discount_untaxed;
return $this;
}
/**
* @return string|null
*/
public function getTotalAmountNoDiscount(): ?string
{
return $this->totalAmountNoDiscount;
}
/**
* @param string|null $totalAmountNoDiscount
* @return DeliveryNote
*/
public function setTotalAmountNoDiscount(?string $totalAmountNoDiscount): DeliveryNote
{
$this->totalAmountNoDiscount = $totalAmountNoDiscount;
return $this;
}
/**
* @return string|null
*/
public function getTotalAmountUntaxed(): ?string
{
return $this->total_amount_untaxed;
}
/**
* @param string|null $total_amount_untaxed
* @return DeliveryNote
*/
public function setTotalAmountUntaxed(?string $total_amount_untaxed): DeliveryNote
{
$this->total_amount_untaxed = $total_amount_untaxed;
return $this;
}
/**
* @return string|null
*/
public function getTotalTaxAmount(): ?string
{
return $this->total_tax_amount;
}
/**
* @param string|null $total_tax_amount
* @return DeliveryNote
*/
public function setTotalTaxAmount(?string $total_tax_amount): DeliveryNote
{
$this->total_tax_amount = $total_tax_amount;
return $this;
}
/**
* @return string|null
*/
public function getTotalAmount(): ?string
{
return $this->total_amount;
}
/**
* @param string|null $total_amount
* @return DeliveryNote
*/
public function setTotalAmount(?string $total_amount): DeliveryNote
{
$this->total_amount = $total_amount;
return $this;
}
/**
* @return array
*/
public function getOptions(): array
{
return $this->options;
}
/**
* @param array $options
* @return DeliveryNote
*/
public function setOptions(array $options): self
{
$this->options = $options;
return $this;
}
/**
* @param array $options
* @return DeliveryNote
*/
public function addOptions(array $options): self
{
return $this->setOptions(array_merge($this->options, $options));
}
/**
* @return Collection|DeliveryNoteLine[]
*/
public function getLines(): Collection
{
return $this->getFilterLines();
}
/**
* @param bool $withGroups
* @param bool $all
* @param bool $withPacks
* @return Collection|DeliveryNoteLine[]
*/
public function getFilterLines(bool $withGroups = true, bool $all = false, bool $withPacks = true): Collection
{
if ($all) {
$lines = $this->lines;
$goodLines = [];
foreach ($lines as $line) {
if (!$line->getParent() && !$line->getPackParent()) {
$goodLines[] = $line;
foreach ($line->getChildrens() as $child) {
$goodLines[] = $child;
foreach ($child->getPackChildrens() as $grandChild) {
$goodLines[] = $grandChild;
}
}
foreach ($line->getPackChildrens() as $child) {
$goodLines[] = $child;
}
}
}
return new ArrayCollection($goodLines);
}
$criteria = Criteria::create();
if ($withGroups) {
$criteria
->where(Criteria::expr()->eq('parent', null))
->andWhere(Criteria::expr()->eq('packParent', null));
} else {
if ($withPacks) {
$criteria->andWhere(Criteria::expr()->eq('is_pack', true));
} else {
$criteria->andWhere(Criteria::expr()->eq('is_pack', false));
}
$criteria->where(Criteria::expr()->eq('is_group', false));
}
return $this->lines->matching($criteria);
}
/**
* @param DeliveryNoteLine $line
* @return DeliveryNote
*/
public function addLine(DeliveryNoteLine $line): self
{
if (!$this->lines->contains($line)) {
$this->lines[] = $line;
if ($line->getDeliveryNote() !== $this) {
$line->setDeliveryNote($this);
}
}
return $this;
}
/**
* @param DeliveryNoteLine $line
* @return DeliveryNote
*/
public function removeLine(DeliveryNoteLine $line): self
{
$this->lines->removeElement($line);
return $this;
}
/**
* @return Collection|DeliveryNoteLine[]
*/
public function getProductLines(): Collection
{
return $this->lines->filter(function (DeliveryNoteLine $deliveryNoteLine) {
return $deliveryNoteLine->isProduct();
});
}
/**
* @return bool
*/
public function isCancelable(): bool
{
return $this->getValidatedAt()
&& !$this->getCanceledAt()
&& !$this->getInvoice();
}
/**
* @return bool
*/
public function isInvoicable(): bool
{
return $this->isCancelable()
&& (
!$this->getOrder()
|| $this->getOrder()->isDeliveryNoteInvoicable()
)
;
}
/**
* @return Establishment|null
*/
public function getEstablishment(): ?Establishment
{
return $this->establishment;
}
/**
* @param Establishment|null $establishment
* @return $this
*/
public function setEstablishment(?Establishment $establishment): self
{
$this->establishment = $establishment;
return $this;
}
/**
* @return DeliveryNote
*/
public function duplicate(): DeliveryNote
{
if ($this->id) {
$clone = clone $this;
$clone->setId();
$clone->setCreatedAt(new DateTime());
$clone->setCreatedBy(null);
$clone->setUpdatedAt(new DateTime());
$clone->setUpdatedBy(null);
$clone->setValidatedAt(null);
$clone->setValidatedBy(null);
$clone->setCanceledAt(null);
$clone->setCanceledBy(null);
$clone->setContext(null);
$clone->setEstablishment(null);
$clone->setReference(null);
$clone->setOrder(null);
$clone->setInvoice(null);
$clone->addOptions([
'invoice_address' => null,
'delivery_address' => null
]);
$clone->lines = new ArrayCollection();
foreach ($this->getFilterLines() as $line) {
$clone_line = $line->duplicate($clone);
$clone->addLine($clone_line);
}
return $clone;
}
return $this;
}
}