src/Entity/Cart.php line 56

  1. <?php
  2. namespace App\Entity;
  3. use ApiPlatform\Doctrine\Orm\Filter\BooleanFilter;
  4. use ApiPlatform\Doctrine\Orm\Filter\DateFilter;
  5. use ApiPlatform\Doctrine\Orm\Filter\ExistsFilter;
  6. use ApiPlatform\Doctrine\Orm\Filter\OrderFilter;
  7. use ApiPlatform\Doctrine\Orm\Filter\SearchFilter;
  8. use ApiPlatform\Metadata\ApiFilter;
  9. use ApiPlatform\Metadata\ApiProperty;
  10. use ApiPlatform\Metadata\ApiResource;
  11. use ApiPlatform\Metadata\Delete;
  12. use ApiPlatform\Metadata\Get;
  13. use ApiPlatform\Metadata\GetCollection;
  14. use ApiPlatform\Metadata\Post;
  15. use ApiPlatform\Metadata\Put;
  16. use App\Controller\OrdersExporter;
  17. use App\Entity\Trait\IdTrait;
  18. use App\Entity\Trait\TimestampableTrait;
  19. use App\Entity\Trait\UuidTrait;
  20. use App\Enum\PaymentMethod;
  21. use App\Repository\CartRepository;
  22. use Doctrine\Common\Collections\ArrayCollection;
  23. use Doctrine\Common\Collections\Collection;
  24. use Doctrine\DBAL\Types\Types;
  25. use Doctrine\ORM\Mapping as ORM;
  26. use Symfony\Component\Serializer\Annotation\Groups;
  27. use Symfony\Component\Validator\Constraints as Assert;
  28. use Gedmo\Mapping\Annotation as Gedmo;
  29. #[ApiResource(
  30.     description'Carts',
  31.     operations: [
  32.         new GetCollection(),
  33.         new Post(),
  34.         new Get(),
  35.         new Put(),
  36.         new Delete(),
  37.     ],
  38.     normalizationContext: ['groups' => [
  39.         'read',
  40.         'read:' self::class,
  41.     ]],
  42.     denormalizationContext: ['groups' => ['write']],
  43.     order: ['createdAt' => 'desc'],
  44.     security'is_granted("' self::class . '")',
  45.     extraProperties: ['standard_put' => false],
  46. )]
  47. #[ApiFilter(DateFilter::class, properties: ['createdAt'])]
  48. #[ApiFilter(SearchFilter::class, properties: ['orderId' => 'ipartial''createdAt' => 'ipartial''fullName' => 'ipartial'])]
  49. #[ApiFilter(ExistsFilter::class, properties: ['orderId'])]
  50. #[ApiFilter(BooleanFilter::class, properties: ['orderId'])]
  51. #[ApiFilter(OrderFilter::class, properties: ['createdAt''totalPrice'])]
  52. #[ORM\Entity(repositoryClassCartRepository::class)]
  53. class Cart
  54. {
  55.     use IdTrait;
  56.     use UuidTrait;
  57.     use TimestampableTrait;
  58.     public const PAYU_STATUS_NEW         'NEW';
  59.     public const PAYU_STATUS_PENDING     'PENDING';
  60.     public const PAYU_STATUS_CANCELED     'CANCELED';
  61.     public const PAYU_STATUS_REJECTED    'REJECTED';
  62.     public const PAYU_STATUS_COMPLETED    'COMPLETED';
  63.     public const PAYU_STATUS_WAITING    'WAITING_FOR_CONFIRMATION';
  64.     #[ApiProperty(description'Creation date')]
  65.     #[Groups(['read:' self::class, 'write''read:list''read:stats''read:autocomplete''read:minimal'])]
  66.     #[Gedmo\Timestampable(on'create')]
  67.     #[ORM\Column(typeTypes::DATETIME_IMMUTABLE)]
  68.     protected \DateTimeImmutable $createdAt;
  69.     #[ApiProperty(description'Customer'writableLinkfalse)]
  70.     #[Groups(['read:' self::class, 'write'])]
  71.     #[ORM\ManyToOne]
  72.     private ?Customer $customer null;
  73.     #[ApiProperty(description'First name')]
  74.     #[Groups(['read:' self::class, 'write'])]
  75.     #[Assert\NotBlank(groups: ['step3''step4'])]
  76.     #[ORM\Column(length255nullabletrue)]
  77.     private ?string $firstName null;
  78.     #[ApiProperty(description'Last name')]
  79.     #[Groups(['read:' self::class, 'write'])]
  80.     #[Assert\NotBlank(groups: ['step3''step4'])]
  81.     #[ORM\Column(length255nullabletrue)]
  82.     private ?string $lastName null;
  83.     #[ApiProperty(description'Full name')]
  84.     #[Groups(['read:' self::class, 'write'])]
  85.     #[ORM\Column(length255nullabletrue)]
  86.     private ?string $fullName null;
  87.     #[ApiProperty(description'Phone number')]
  88.     #[Groups(['read:' self::class, 'write'])]
  89.     #[ORM\Column(length255nullabletrue)]
  90.     private ?string $phone null;
  91.     #[ApiProperty(description'Email')]
  92.     #[Groups(['read:' self::class, 'write'])]
  93.     #[Assert\NotBlank(groups: ['step3''step4'])]
  94.     #[ORM\Column(length255nullabletrue)]
  95.     private ?string $email null;
  96.     #[ApiProperty(description'Want fv')]
  97.     #[Groups(['read:' self::class, 'write'])]
  98.     #[ORM\Column(options: ['default' => false])]
  99.     private bool $wantFv false;
  100.     #[ApiProperty(description'Fv name')]
  101.     #[Groups(['read:' self::class, 'write'])]
  102.     #[Assert\When(
  103.         expression'this.isWantFv()',
  104.         constraints: [
  105.             new Assert\NotBlank()
  106.         ],
  107.         groups: ['step3''step4'],
  108.     )]
  109.     #[ORM\Column(length255nullabletrue)]
  110.     private ?string $fvName null;
  111.     #[ApiProperty(description'Fv nip')]
  112.     #[Groups(['read:' self::class, 'write'])]
  113.     #[Assert\When(
  114.         expression'this.isWantFv()',
  115.         constraints: [
  116.             new Assert\NotBlank()
  117.         ],
  118.         groups: ['step3''step4'],
  119.     )]
  120.     #[ORM\Column(length255nullabletrue)]
  121.     private ?string $fvNip null;
  122.     #[ApiProperty(description'Fv other tax id')]
  123.     #[Groups(['read:' self::class, 'write'])]
  124.     #[ORM\Column(length255nullabletrue)]
  125.     private ?string $fvOtherTaxId null;
  126.     #[ApiProperty(description'Fv city')]
  127.     #[Groups(['read:' self::class, 'write'])]
  128.     #[Assert\When(
  129.         expression'this.isWantFv()',
  130.         constraints: [
  131.             new Assert\NotBlank()
  132.         ],
  133.         groups: ['step3''step4'],
  134.     )]
  135.     #[ORM\Column(length255nullabletrue)]
  136.     private ?string $fvCity null;
  137.     #[ApiProperty(description'Fv street')]
  138.     #[Groups(['read:' self::class, 'write'])]
  139.     #[Assert\When(
  140.         expression'this.isWantFv()',
  141.         constraints: [
  142.             new Assert\NotBlank()
  143.         ],
  144.         groups: ['step3''step4'],
  145.     )]
  146.     #[ORM\Column(length255nullabletrue)]
  147.     private ?string $fvStreet null;
  148.     #[ApiProperty(description'Fv house number')]
  149.     #[Groups(['read:' self::class, 'write'])]
  150.     #[Assert\When(
  151.         expression'this.isWantFv()',
  152.         constraints: [
  153.             new Assert\NotBlank()
  154.         ],
  155.         groups: ['step3''step4'],
  156.     )]
  157.     #[ORM\Column(length255nullabletrue)]
  158.     private ?string $fvHouseNumber null;
  159.     #[ApiProperty(description'Fv apartment number')]
  160.     #[Groups(['read:' self::class, 'write'])]
  161.     #[ORM\Column(length255nullabletrue)]
  162.     private ?string $fvApartmentNumber null;
  163.     #[ApiProperty(description'Fv postal code')]
  164.     #[Groups(['read:' self::class, 'write'])]
  165.     #[Assert\When(
  166.         expression'this.isWantFv()',
  167.         constraints: [
  168.             new Assert\NotBlank()
  169.         ],
  170.         groups: ['step3''step4'],
  171.     )]
  172.     #[ORM\Column(length255nullabletrue)]
  173.     private ?string $fvPostalCode null;
  174.     #[ApiProperty(description'Client comment')]
  175.     #[Groups(['read:' self::class, 'write'])]
  176.     #[ORM\Column(length1024nullabletrue)]
  177.     private ?string $fvComment null;
  178.     #[ORM\OneToMany(mappedBy'parent'targetEntityCartProduct::class, cascade: ['persist''remove'], orphanRemovaltrue)]
  179.     private Collection $products;
  180.     #[ApiProperty(description'Country'writableLinkfalse)]
  181.     #[Groups(['read:' self::class, 'write'])]
  182.     #[ORM\ManyToOne(inversedBy'carts')]
  183.     private ?CartCountry $country null;
  184.     #[ApiProperty(description'Paid at')]
  185.     #[Groups(['read:' self::class, 'write'])]
  186.     #[ORM\Column(nullabletrue)]
  187.     private ?\DateTimeImmutable $paidAt null;
  188.     #[ApiProperty(description'PayU link')]
  189.     #[Groups(['read:' self::class, 'write'])]
  190.     #[ORM\Column(type'string'length1023nullabletrue)]
  191.     private ?string $payuLink null;
  192.     #[ApiProperty(description'PayU order id')]
  193.     #[Groups(['read:' self::class, 'write'])]
  194.     #[ORM\Column(type'string'length63nullabletrue)]
  195.     private ?string $payuOrderId null;
  196.     #[ApiProperty(description'PayU status')]
  197.     #[Groups(['read:' self::class, 'write'])]
  198.     #[ORM\Column(type'string'length31nullabletrue)]
  199.     private ?string $payuStatus self::PAYU_STATUS_NEW;
  200.     #[ApiProperty(description'Order id')]
  201.     #[Groups(['read:' self::class])]
  202.     #[ORM\Column(nullabletrue)]
  203.     private ?int $orderId null;
  204.     #[ApiProperty(description'Payment method'writableLinkfalse)]
  205.     #[Groups(['read:' self::class, 'write'])]
  206.     #[ORM\Column(
  207.         typeTypes::STRING,
  208.         length255,
  209.         enumTypePaymentMethod::class,
  210.         options: ['default' => PaymentMethod::PAYU]
  211.     )]
  212.     private PaymentMethod $paymentMethod PaymentMethod::PAYU;
  213.     #[ApiProperty(description'Total price')]
  214.     #[Groups(['read:' self::class])]
  215.     #[ORM\Column(nullabletrue)]
  216.     private ?float $totalPrice null;
  217.     #[ApiProperty(description'Admin comment')]
  218.     #[Groups(['read:' self::class, 'write'])]
  219.     #[ORM\Column(length4096nullabletrue)]
  220.     private ?string $adminComment null;
  221.     #[ApiProperty(description'Locale')]
  222.     #[Groups(['read:' self::class])]
  223.     #[ORM\Column(length255nullabletrueoptions: ['default' => 'pl'])]
  224.     private string $locale 'pl';
  225.     public function __construct()
  226.     {
  227.         $this->setUuid();
  228.         $this->products = new ArrayCollection();
  229.         $this->createdAt = new \DateTimeImmutable();
  230.         $this->updatedAt = new \DateTimeImmutable();
  231.     }
  232.     public function getCustomer(): ?Customer
  233.     {
  234.         return $this->customer;
  235.     }
  236.     public function setCustomer(?Customer $customer): self
  237.     {
  238.         $this->customer $customer;
  239.         return $this;
  240.     }
  241.     public function getFirstName(): ?string
  242.     {
  243.         return $this->firstName;
  244.     }
  245.     public function setFirstName(?string $firstName): self
  246.     {
  247.         $this->firstName $firstName;
  248.         $this->setFullName($this->getFirstName() . ' ' $this->getLastName());
  249.         return $this;
  250.     }
  251.     public function getLastName(): ?string
  252.     {
  253.         return $this->lastName;
  254.     }
  255.     public function setLastName(?string $lastName): self
  256.     {
  257.         $this->lastName $lastName;
  258.         $this->setFullName($this->getFirstName() . ' ' $this->getLastName());
  259.         return $this;
  260.     }
  261.     public function getFullName(): ?string
  262.     {
  263.         return $this->fullName;
  264.     }
  265.     public function setFullName(?string $fullName): self
  266.     {
  267.         $this->fullName $fullName;
  268.         return $this;
  269.     }
  270.     public function getPhone(): ?string
  271.     {
  272.         return $this->phone;
  273.     }
  274.     public function setPhone(?string $phone): static
  275.     {
  276.         $this->phone $phone;
  277.         return $this;
  278.     }
  279.     public function getEmail(): ?string
  280.     {
  281.         return $this->email;
  282.     }
  283.     public function setEmail(?string $email): self
  284.     {
  285.         $this->email $email;
  286.         return $this;
  287.     }
  288.     public function getIsWantFv(): bool
  289.     {
  290.         return $this->wantFv;
  291.     }
  292.     public function isWantFv(): bool
  293.     {
  294.         return $this->wantFv;
  295.     }
  296.     public function getWantFv(): bool
  297.     {
  298.         return $this->wantFv;
  299.     }
  300.     public function setWantFv(bool $wantFv): self
  301.     {
  302.         $this->wantFv $wantFv;
  303.         return $this;
  304.     }
  305.     public function getFvName(): ?string
  306.     {
  307.         return $this->fvName;
  308.     }
  309.     public function blabla(): ?string
  310.     {
  311.         return 'string';
  312.     }
  313.     public function setFvName(?string $fvName): self
  314.     {
  315.         $this->fvName $fvName;
  316.         return $this;
  317.     }
  318.     public function getFvNip(): ?string
  319.     {
  320.         return $this->fvNip;
  321.     }
  322.     public function setFvNip(?string $fvNip): self
  323.     {
  324.         $this->fvNip $fvNip;
  325.         return $this;
  326.     }
  327.     public function getFvOtherTaxId(): ?string
  328.     {
  329.         return $this->fvOtherTaxId;
  330.     }
  331.     public function setFvOtherTaxId(?string $fvOtherTaxId): self
  332.     {
  333.         $this->fvOtherTaxId $fvOtherTaxId;
  334.         return $this;
  335.     }
  336.     public function getFvCity(): ?string
  337.     {
  338.         return $this->fvCity;
  339.     }
  340.     public function setFvCity(?string $fvCity): self
  341.     {
  342.         $this->fvCity $fvCity;
  343.         return $this;
  344.     }
  345.     public function getFvStreet(): ?string
  346.     {
  347.         return $this->fvStreet;
  348.     }
  349.     public function setFvStreet(?string $fvStreet): self
  350.     {
  351.         $this->fvStreet $fvStreet;
  352.         return $this;
  353.     }
  354.     public function getFvHouseNumber(): ?string
  355.     {
  356.         return $this->fvHouseNumber;
  357.     }
  358.     public function setFvHouseNumber(?string $fvHouseNumber): self
  359.     {
  360.         $this->fvHouseNumber $fvHouseNumber;
  361.         return $this;
  362.     }
  363.     public function getFvApartmentNumber(): ?string
  364.     {
  365.         return $this->fvApartmentNumber;
  366.     }
  367.     public function setFvApartmentNumber(?string $fvApartmentNumber): self
  368.     {
  369.         $this->fvApartmentNumber $fvApartmentNumber;
  370.         return $this;
  371.     }
  372.     public function getFvPostalCode(): ?string
  373.     {
  374.         return $this->fvPostalCode;
  375.     }
  376.     public function setFvPostalCode(?string $fvPostalCode): self
  377.     {
  378.         $this->fvPostalCode $fvPostalCode;
  379.         return $this;
  380.     }
  381.     public function getFvComment(): ?string
  382.     {
  383.         return $this->fvComment;
  384.     }
  385.     public function setFvComment(?string $fvComment): self
  386.     {
  387.         $this->fvComment $fvComment;
  388.         return $this;
  389.     }
  390.     /**
  391.      * @return Collection<int, CartProduct>
  392.      */
  393.     public function getProducts(): Collection
  394.     {
  395.         return $this->products;
  396.     }
  397.     public function addProduct(CartProduct $product): self
  398.     {
  399.         if (!$this->products->contains($product)) {
  400.             $this->products->add($product);
  401.             $product->setParent($this);
  402.         }
  403.         return $this;
  404.     }
  405.     public function removeProduct(CartProduct $product): self
  406.     {
  407.         if ($this->products->removeElement($product)) {
  408.             // set the owning side to null (unless already changed)
  409.             if ($product->getParent() === $this) {
  410.                 $product->setParent(null);
  411.             }
  412.         }
  413.         return $this;
  414.     }
  415.     public function getCountry(): ?CartCountry
  416.     {
  417.         return $this->country;
  418.     }
  419.     public function setCountry(?CartCountry $country): self
  420.     {
  421.         $this->country $country;
  422.         if ($country) {
  423.             foreach ($this->getProducts() as $product) {
  424.                 $product->setVat($country->getRegion()?->getVat() ?? 0);
  425.             }
  426.         }
  427.         return $this;
  428.     }
  429.     public function addArticle(JournalArticle $article): self
  430.     {
  431.         $found null;
  432.         foreach ($this->products as $product) {
  433.             if ($product->getArticle() === $article) {
  434.                 $found $product;
  435.                 break;
  436.             }
  437.         }
  438.         if (!$found) {
  439.             $found = new CartProduct();
  440.             $found->setParent($this);
  441.             $found->setArticle($article);
  442.             $this->addProduct($found);
  443.         }
  444.         return $this;
  445.     }
  446.     public function addIssue(JournalIssue $issue): self
  447.     {
  448.         $found null;
  449.         foreach ($this->products as $product) {
  450.             if ($product->getIssue() === $issue) {
  451.                 $found $product;
  452.                 break;
  453.             }
  454.         }
  455.         if (!$found) {
  456.             $found = new CartProduct();
  457.             $found->setParent($this);
  458.             $found->setIssue($issue);
  459.             $this->addProduct($found);
  460.         }
  461.         return $this;
  462.     }
  463.     public function canAccessStep2(): bool
  464.     {
  465.         if ($this->getProducts()->isEmpty()) {
  466.             return false;
  467.         }
  468.         return true;
  469.     }
  470.     public function canAccessStep3(): bool
  471.     {
  472.         if ($this->getProducts()->isEmpty()) {
  473.             return false;
  474.         }
  475.         if (
  476.             !$this->getFirstName() ||
  477.             !$this->getLastName() ||
  478.             !$this->getEmail()
  479.         ) {
  480.             return false;
  481.         }
  482.         if (
  483.             $this->isWantFv() &&
  484.             (
  485.                 !$this->getFvName() ||
  486.                 !$this->getFvNip() ||
  487.                 !$this->getFvCity() ||
  488.                 !$this->getFvStreet() ||
  489.                 !$this->getFvHouseNumber() ||
  490.                 !$this->getFvPostalCode()
  491.             )
  492.         ) {
  493.             return false;
  494.         }
  495.         return true;
  496.     }
  497.     public function getPaidAt(): ?\DateTimeImmutable
  498.     {
  499.         return $this->paidAt;
  500.     }
  501.     public function setPaidAt(?\DateTimeImmutable $paidAt): static
  502.     {
  503.         $this->paidAt $paidAt;
  504.         return $this;
  505.     }
  506.     public function getPayuLink(): ?string
  507.     {
  508.         return $this->payuLink;
  509.     }
  510.     public function setPayuLink(?string $payuLink): self
  511.     {
  512.         $this->payuLink $payuLink;
  513.         return $this;
  514.     }
  515.     public function getPayuOrderId(): ?string
  516.     {
  517.         return $this->payuOrderId;
  518.     }
  519.     public function setPayuOrderId(?string $payuOrderId): self
  520.     {
  521.         $this->payuOrderId $payuOrderId;
  522.         return $this;
  523.     }
  524.     public function getPayuStatus(): ?string
  525.     {
  526.         return $this->payuStatus;
  527.     }
  528.     public function setPayuStatus(?string $payuStatus): self
  529.     {
  530.         $this->payuStatus $payuStatus;
  531.         return $this;
  532.     }
  533.     public function getOrderId(): ?int
  534.     {
  535.         return $this->orderId;
  536.     }
  537.     public function setOrderId(?int $orderId): self
  538.     {
  539.         $this->orderId $orderId;
  540.         return $this;
  541.     }
  542.     public function getPaymentMethod(): PaymentMethod
  543.     {
  544.         return $this->paymentMethod;
  545.     }
  546.     public function setPaymentMethod(PaymentMethod $paymentMethod): self
  547.     {
  548.         $this->paymentMethod $paymentMethod;
  549.         return $this;
  550.     }
  551.     public function getTotalPrice(): ?float
  552.     {
  553.         return $this->totalPrice;
  554.     }
  555.     public function setTotalPrice(?float $totalPrice): self
  556.     {
  557.         $this->totalPrice $totalPrice;
  558.         return $this;
  559.     }
  560.     public function getAdminComment(): ?string
  561.     {
  562.         return $this->adminComment;
  563.     }
  564.     public function setAdminComment(?string $adminComment): self
  565.     {
  566.         $this->adminComment $adminComment;
  567.         return $this;
  568.     }
  569.     public function getTotalPriceFront(): float
  570.     {
  571.         $total 0;
  572.         foreach ($this->products as $product) {
  573.             if ($product->getArticle()) {
  574.                 $total += $product->getArticle()->getPrice();
  575.             }
  576.             if ($product->getIssue()) {
  577.                 $total += $product->getIssue()->getPrice();
  578.             }
  579.         }
  580.         return round($total 10002);
  581.     }
  582.     #[ApiProperty(description'Total price cms')]
  583.     #[Groups(['read:' self::class])]
  584.     public function getTotalPriceCms(): float
  585.     {
  586.         $total 0;
  587.         foreach ($this->getProducts() as $product) {
  588.             if (!$product->getPrice()) {
  589.                 continue;
  590.             }
  591.             $total += $product->getPrice();
  592.         }
  593.         return round($total 10002);
  594.     }
  595.     public function getTotalPriceMinor(): int
  596.     {
  597.         $total 0;
  598.         foreach ($this->getProducts() as $product) {
  599.             if (!$product->getPrice()) {
  600.                 continue;
  601.             }
  602.             $total += $product->getPrice();
  603.         }
  604.         return intval(round($total 102));
  605.     }
  606.     public function getTotalVat(): float
  607.     {
  608.         $total $this->getTotalPriceFront();
  609.         $totalVat 0.0;
  610.         foreach ($this->getProducts() as $product) {
  611.             if (!$product->getVat()) {
  612.                 continue;
  613.             }
  614.             if ($product->getArticle()) {
  615.                 $productPrice $product->getArticle()->getPrice();
  616.             } else {
  617.                 $productPrice $product->getIssue()->getPrice();
  618.             }
  619.             $vatPercentage $product->getVat() / 100// Convert percentage to decimal
  620.             $productVat = (int)round($productPrice $vatPercentage);
  621.             $totalVat += $productVat;
  622.         }
  623.         return $totalVat 1000;
  624.     }
  625.     #[ApiProperty(description'Title')]
  626.     #[Groups(['read:' self::class])]
  627.     public function getTitle(): ?string
  628.     {
  629.         return strval($this->orderId);
  630.     }
  631.     #[ApiProperty(description'Buyer cms')]
  632.     #[Groups(['read:' self::class])]
  633.     public function getBuyerCms(): string
  634.     {
  635.        $buyer sprintf(
  636.            '%s (%s)',
  637.            $this->getFullName(),
  638.            $this->getEmail(),
  639.        );
  640.        if ($this->phone) {
  641.            $buyer .= sprintf(', tel: %s'$this->getPhone());
  642.        }
  643.        return $buyer;
  644.     }
  645.     public function getLocale(): string
  646.     {
  647.         return $this->locale;
  648.     }
  649.     public function setLocale(string $locale): static
  650.     {
  651.         $this->locale $locale;
  652.         return $this;
  653.     }
  654. }