src/AtechNet/CoreBundle/Entity/OrderItem.php line 28

Open in your IDE?
  1. <?php
  2. namespace App\AtechNet\CoreBundle\Entity;
  3. use App\AtechNet\CoreBundle\Enum\ServicingPosition;
  4. use App\AtechNet\CoreBundle\Service\Order\OrderService;
  5. use Doctrine\Common\Collections\ArrayCollection;
  6. use Doctrine\ORM\Mapping\Column;
  7. use Doctrine\ORM\Mapping\Entity;
  8. use Doctrine\ORM\Mapping\HasLifecycleCallbacks;
  9. use Doctrine\ORM\Mapping\JoinColumn;
  10. use Doctrine\ORM\Mapping\PrePersist;
  11. use Doctrine\ORM\Mapping\PreUpdate;
  12. use Doctrine\ORM\Mapping\ManyToOne;
  13. use Doctrine\ORM\Mapping\OneToMany;
  14. use Doctrine\ORM\Mapping\OneToOne;
  15. use Doctrine\ORM\Mapping\OrderBy;
  16. use Doctrine\ORM\Mapping\Table as Table;
  17. use Symfony\Component\Validator\Constraints as Assert;
  18. /**
  19.  * OrderItem
  20.  *
  21.  * @Table(name="orders__items")
  22.  * @Entity(repositoryClass="App\AtechNet\CoreBundle\Repository\OrderItemRepository")
  23.  * @HasLifecycleCallbacks
  24.  */
  25. class OrderItem extends AbstractEntity
  26. {
  27.     /**
  28.      * @var Order
  29.      *
  30.      * @Assert\NotNull
  31.      *
  32.      * @ManyToOne(targetEntity="Order", inversedBy="orderItems")
  33.      * @JoinColumn(name="order_id", referencedColumnName="id")
  34.      */
  35.     private $order;
  36.     /**
  37.      * @var Product
  38.      *
  39.      * @ManyToOne(targetEntity="Product", inversedBy="orderItems")
  40.      * @JoinColumn(name="product_id", referencedColumnName="id")
  41.      */
  42.     private $product;
  43.     /**
  44.      * @var string
  45.      *
  46.      * @Column(name="custom_configuration", type="text", nullable=true)
  47.      */
  48.     private $customConfiguration;
  49.     /**
  50.      * @var string
  51.      *
  52.      * @Column(name="price", type="decimal", precision=12, scale=3)
  53.      */
  54.     private $price;
  55.     /**
  56.      * @var int
  57.      *
  58.      * @Column(name="quantity", type="integer")
  59.      */
  60.     private $quantity;
  61.     /**
  62.      * @var int
  63.      *
  64.      * @Column(name="position", type="integer")
  65.      */
  66.     private $position = 0;
  67.     /**
  68.      * @var bool
  69.      *
  70.      * @Column(name="from_timed_sale", type="boolean")
  71.      */
  72.     private $fromTimedSale = false;
  73.     /**
  74.      * @var ArrayCollection
  75.      *
  76.      * @OneToMany(targetEntity="OrderItemAttributeOption", mappedBy="orderItem", orphanRemoval=true, cascade={"persist", "remove"})
  77.      * @OrderBy({"created" = "ASC"})
  78.      **/
  79.     private $itemAttributes;
  80.     /**
  81.      * @var OrderItem|null
  82.      *
  83.      * @ManyToOne(targetEntity="OrderItem", inversedBy="children", cascade={"persist"})
  84.      * @JoinColumn(name="parent_id", referencedColumnName="id", onDelete="CASCADE", nullable=true)
  85.      */
  86.     private $parent;
  87.     /**
  88.      * @var ArrayCollection
  89.      *
  90.      * @OneToMany(targetEntity="OrderItem", mappedBy="parent", cascade={"persist", "remove"})
  91.      **/
  92.     private $children;
  93.     /**
  94.      * @var StockMovementItem|null
  95.      *
  96.      * @OneToOne(targetEntity="StockMovementItem", mappedBy="orderItem", cascade={"persist", "remove"})
  97.      */
  98.     private $stockMovementItem;
  99.     /**
  100.      * @var PersonalizationAttributeOptionCombination|null
  101.      *
  102.      * @ManyToOne(targetEntity="PersonalizationAttributeOptionCombination", inversedBy="orderItems")
  103.      * @JoinColumn(name="personalization_attribute_option_combination_id", referencedColumnName="id", nullable=true)
  104.      */
  105.     private ?PersonalizationAttributeOptionCombination $personalizationAttributeOptionCombination = null;
  106.     /**
  107.      * @var ProductContainer|null
  108.      *
  109.      * @ManyToOne(targetEntity="ProductContainer")
  110.      * @JoinColumn(name="product_container_id", referencedColumnName="id", nullable=true)
  111.      */
  112.     private $productContainer;
  113.     /**
  114.      * @var ProductVariation|null
  115.      *
  116.      * @Assert\NotNull
  117.      *
  118.      * @ManyToOne(targetEntity="ProductVariation", inversedBy="orderItems")
  119.      * @JoinColumn(name="product_variation_id", referencedColumnName="id", nullable=true)
  120.      */
  121.     private ?ProductVariation $productVariation = null;
  122.     /**
  123.      * @var ?ProductMarketplaceListing
  124.      *
  125.      * @ManyToOne(targetEntity="ProductMarketplaceListing", inversedBy="orderItems")
  126.      * @JoinColumn(name="marketplace_listing_id", referencedColumnName="id", nullable=true)
  127.      */
  128.     private ?ProductMarketplaceListing $productMarketplaceListing = null;
  129.     /**
  130.      * @var int|null
  131.      *
  132.      * @Column(name="product_model_variation_id", type="integer", nullable=true)
  133.      */
  134.     private ?int $productModelVariationId = null;
  135.     /**
  136.      * @var int|null
  137.      *
  138.      * @Column(name="product_model_variation_marketplace_listing_id", type="integer", nullable=true)
  139.      */
  140.     private ?int $productModelVariationMarketplaceListingId = null;
  141.     /**
  142.      * @var string|null
  143.      *
  144.      * @Column(name="vat_price_per_item", type="decimal", precision=12, scale=3, nullable=true)
  145.      */
  146.     private ?string $vatPricePerItem = null;
  147.     /**
  148.      * @var string|null
  149.      *
  150.      * @Column(name="total_vat_price", type="decimal", precision=12, scale=3, nullable=true)
  151.      */
  152.     private ?string $totalVatPrice = null;
  153.     /**
  154.      * @var string|null
  155.      *
  156.      * @Column(name="total_price", type="decimal", precision=12, scale=3, nullable=true)
  157.      */
  158.     private ?string $totalPrice = null;
  159.     /**
  160.      * @var string|null
  161.      *
  162.      * @Column(name="price_per_item", type="decimal", precision=12, scale=3, nullable=true)
  163.      */
  164.     private ?string $pricePerItemWithoutVat = null;
  165.     /**
  166.      * @var string|null
  167.      *
  168.      * @Column(name="price_per_item_with_vat", type="decimal", precision=12, scale=3, nullable=true)
  169.      */
  170.     private ?string $pricePerItemWithVat = null;
  171.     public function __construct()
  172.     {
  173.         parent::__construct();
  174.         $this->children = new ArrayCollection();
  175.         $this->itemAttributes = new ArrayCollection();
  176.     }
  177.     /**
  178.      * @return Order
  179.      */
  180.     public function getOrder()
  181.     {
  182.         return $this->order;
  183.     }
  184.     /**
  185.      * @param Order $order
  186.      */
  187.     public function setOrder($order)
  188.     {
  189.         $this->order = $order;
  190.     }
  191.     /**
  192.      * Set price
  193.      *
  194.      * @param string $price
  195.      * @return OrderItem
  196.      */
  197.     public function setPrice($price)
  198.     {
  199.         $this->price = $price;
  200.         return $this;
  201.     }
  202.     /**
  203.      * Get price
  204.      *
  205.      * @return string
  206.      */
  207.     public function getPrice()
  208.     {
  209.         if (in_array($this->order->getDomain()->getId(), [Domain::DOMAIN_ID_RT_HU, Domain::DOMAIN_ID_WS_HU])
  210.             && $this->order->getVat() == 0
  211.             && $this->price % 10 != 0) {
  212.             return ceil($this->price / 10) * 10;
  213.         }
  214.         return $this->price;
  215.     }
  216.     /**
  217.      * Set quantity
  218.      *
  219.      * @param int $quantity
  220.      * @return OrderItem
  221.      */
  222.     public function setQuantity($quantity)
  223.     {
  224.         $this->quantity = $quantity;
  225.         return $this;
  226.     }
  227.     /**
  228.      * Get quantity
  229.      *
  230.      * @return int
  231.      */
  232.     public function getQuantity()
  233.     {
  234.         return $this->quantity;
  235.     }
  236.     public function increaseQuantity($val = 1)
  237.     {
  238.         $this->quantity = $this->quantity + $val;
  239.     }
  240.     /**
  241.      * Set position
  242.      *
  243.      * @param int $position
  244.      * @return OrderItem
  245.      */
  246.     public function setPosition($position)
  247.     {
  248.         $this->position = $position;
  249.         return $this;
  250.     }
  251.     /**
  252.      * Get position
  253.      *
  254.      * @return int
  255.      */
  256.     public function getPosition()
  257.     {
  258.         return $this->position;
  259.     }
  260.     /**
  261.      * @return Product
  262.      */
  263.     public function getProduct()
  264.     {
  265.         return $this->product;
  266.     }
  267.     /**
  268.      * @param Product $product
  269.      */
  270.     public function setProduct($product)
  271.     {
  272.         $this->product = $product;
  273.     }
  274.     /**
  275.      * @return ArrayCollection
  276.      */
  277.     public function getItemAttributes()
  278.     {
  279.         return $this->itemAttributes;
  280.     }
  281.     /**
  282.      * @param ArrayCollection $itemAttributes
  283.      */
  284.     public function setItemAttributes($itemAttributes)
  285.     {
  286.         $this->itemAttributes = $itemAttributes;
  287.     }
  288.     /**
  289.      * @param OrderItemAttributeOption $itemAttributes
  290.      */
  291.     public function addItemAttribute(OrderItemAttributeOption $itemAttribute)
  292.     {
  293.         $this->itemAttributes->add($itemAttribute);
  294.     }
  295.     /**
  296.      * @return void
  297.      */
  298.     public function reMakeArrayCollectionsForOrderItems()
  299.     {
  300.         $this->children = new ArrayCollection();
  301.         $this->itemAttributes = new ArrayCollection();
  302.     }
  303.     /**
  304.      * @return OrderItem
  305.      */
  306.     public function getParent()
  307.     {
  308.         return $this->parent;
  309.     }
  310.     /**
  311.      * @param OrderItem|null $parent
  312.      */
  313.     public function setParent(?OrderItem $parent): void
  314.     {
  315.         $this->parent = $parent;
  316.     }
  317.     /**
  318.      * @return ArrayCollection
  319.      */
  320.     public function getChildren()
  321.     {
  322.         return $this->children;
  323.     }
  324.     /**
  325.      * @param ArrayCollection $children
  326.      */
  327.     public function setChildren($children)
  328.     {
  329.         $this->children = $children;
  330.     }
  331.     /**
  332.      * @return StockMovementItem|null
  333.      */
  334.     public function getStockMovementItem()
  335.     {
  336.         return $this->stockMovementItem;
  337.     }
  338.     /**
  339.      * @param StockMovementItem|null $stockMovementItem
  340.      */
  341.     public function setStockMovementItem(?StockMovementItem $stockMovementItem)
  342.     {
  343.         $this->stockMovementItem = $stockMovementItem;
  344.     }
  345.     /**
  346.      * @return PersonalizationAttributeOptionCombination|null
  347.      */
  348.     public function getPersonalizationAttributeOptionCombination(): ?PersonalizationAttributeOptionCombination
  349.     {
  350.         return $this->personalizationAttributeOptionCombination;
  351.     }
  352.     /**
  353.      * @param PersonalizationAttributeOptionCombination|null $personalizationAttributeOptionCombination
  354.      */
  355.     public function setPersonalizationAttributeOptionCombination(?PersonalizationAttributeOptionCombination $personalizationAttributeOptionCombination): void
  356.     {
  357.         $this->personalizationAttributeOptionCombination = $personalizationAttributeOptionCombination;
  358.     }
  359.     /**
  360.      * @return ProductContainer
  361.      */
  362.     public function getProductContainer()
  363.     {
  364.         return $this->productContainer;
  365.     }
  366.     /**
  367.      * @param ProductContainer|null $productContainer
  368.      */
  369.     public function setProductContainer(?ProductContainer $productContainer): void
  370.     {
  371.         $this->productContainer = $productContainer;
  372.     }
  373.     /**
  374.      * Returns attributeOption Ids for current OrderItem
  375.      *
  376.      * @return int|string
  377.      */
  378.     public function getItemAttributeIDs()
  379.     {
  380.         $itemAttributeOptions = $this->itemAttributes;
  381.         $ids = 'none';
  382.         if ($itemAttributeOptions->count() > 0) {
  383.             /**
  384.              * @var OrderItemAttributeOption $oiao
  385.              */
  386.             foreach ($itemAttributeOptions as $oiao) {
  387.                 if ($ids == 'none') {
  388.                     $ids = $oiao->getAttributeOption()->getId();
  389.                 } else {
  390.                     $ids .= ',' . $oiao->getAttributeOption()->getId();
  391.                 }
  392.             }
  393.         }
  394.         return $ids;
  395.     }
  396.     /**
  397.      * Returns the price of this OrderItem with attributes, on current domain, with VAT
  398.      *
  399.      * @return float
  400.      */
  401.     public function getItemPriceForOnePiece()
  402.     {
  403.         $price = $this->getPrice();
  404.         /**
  405.          * @var OrderItemAttributeOption $oiao
  406.          */
  407.         foreach ($this->getItemAttributes() as $oiao) {
  408.             $price = $price + $oiao->getPrice();
  409.         }
  410.         return round($price, 2);
  411.     }
  412.     /**
  413.      * Returns Full price of this OrderItem
  414.      *
  415.      * @return int
  416.      */
  417.     public function getItemFullPrice()
  418.     {
  419.         $fullPrice = $this->quantity * $this->getItemPriceForOnePiece();
  420.         return round($fullPrice, 2);
  421.     }
  422.     /**
  423.      * @return bool
  424.      */
  425.     public function isFromTimedSale()
  426.     {
  427.         return $this->fromTimedSale;
  428.     }
  429.     /**
  430.      * @param bool $fromTimedSale
  431.      */
  432.     public function setFromTimedSale($fromTimedSale)
  433.     {
  434.         $this->fromTimedSale = $fromTimedSale;
  435.     }
  436.     /**
  437.      * @return string|null
  438.      */
  439.     public function getCustomConfiguration(): ?string
  440.     {
  441.         return $this->customConfiguration;
  442.     }
  443.     /**
  444.      * @param string|null $customConfiguration
  445.      * @return void
  446.      */
  447.     public function setCustomConfiguration(?string $customConfiguration): void
  448.     {
  449.         $this->customConfiguration = $customConfiguration;
  450.     }
  451.     /**
  452.      * @return bool
  453.      */
  454.     public function isMainProduct(): bool
  455.     {
  456.         return in_array($this->getProduct()->getType()->getId(), ProductType::getMainProductTypeIds());
  457.     }
  458.     /**
  459.      * @return ProductVariation|null
  460.      */
  461.     public function getProductVariation(): ?ProductVariation
  462.     {
  463.         return $this->productVariation;
  464.     }
  465.     /**
  466.      * @param ProductVariation|null $productVariation
  467.      * @return void
  468.      */
  469.     public function setProductVariation(?ProductVariation $productVariation): void
  470.     {
  471.         $this->productVariation = $productVariation;
  472.     }
  473.     /**
  474.      * @return ProductMarketplaceListing|null
  475.      */
  476.     public function getProductMarketplaceListing(): ?ProductMarketplaceListing
  477.     {
  478.         return $this->productMarketplaceListing;
  479.     }
  480.     /**
  481.      * @param ProductMarketplaceListing|null $productMarketplaceListing
  482.      * @return void
  483.      */
  484.     public function setProductMarketplaceListing(?ProductMarketplaceListing $productMarketplaceListing): void
  485.     {
  486.         $this->productMarketplaceListing = $productMarketplaceListing;
  487.     }
  488.     public function getProductModelVariationId(): ?int
  489.     {
  490.         return $this->productModelVariationId;
  491.     }
  492.     public function setProductModelVariationId(?int $productModelVariationId): void
  493.     {
  494.         $this->productModelVariationId = $productModelVariationId;
  495.     }
  496.     public function getProductModelVariationMarketplaceListingId(): ?int
  497.     {
  498.         return $this->productModelVariationMarketplaceListingId;
  499.     }
  500.     public function setProductModelVariationMarketplaceListingId(?int $productModelVariationMarketplaceListingId): void
  501.     {
  502.         $this->productModelVariationMarketplaceListingId = $productModelVariationMarketplaceListingId;
  503.     }
  504.     public function getVatPricePerItem(): ?string
  505.     {
  506.         return $this->vatPricePerItem;
  507.     }
  508.     public function setVatPricePerItem(?string $vatPricePerItem): void
  509.     {
  510.         $this->vatPricePerItem = $vatPricePerItem;
  511.     }
  512.     public function getTotalVatPrice(): ?string
  513.     {
  514.         return $this->totalVatPrice;
  515.     }
  516.     public function setTotalVatPrice(?string $totalVatPrice): void
  517.     {
  518.         $this->totalVatPrice = $totalVatPrice;
  519.     }
  520.     public function getTotalPrice(): ?string
  521.     {
  522.         return $this->totalPrice;
  523.     }
  524.     public function setTotalPrice(?string $totalPrice): void
  525.     {
  526.         $this->totalPrice = $totalPrice;
  527.     }
  528.     public function getPricePerItemWithoutVat(): ?string
  529.     {
  530.         return $this->pricePerItemWithoutVat;
  531.     }
  532.     public function setPricePerItemWithoutVat(?string $pricePerItemWithoutVat): void
  533.     {
  534.         $this->pricePerItemWithoutVat = $pricePerItemWithoutVat;
  535.     }
  536.     public function getPricePerItemWithVat(): ?string
  537.     {
  538.         return $this->pricePerItemWithVat;
  539.     }
  540.     public function setPricePerItemWithVat(?string $pricePerItemWithVat): void
  541.     {
  542.         $this->pricePerItemWithVat = $pricePerItemWithVat;
  543.     }
  544.     public function recalculateVatFields(float $vatRate): void
  545.     {
  546.         $grossPerItem = (float) $this->price;
  547.         $quantity     = max(1, (int) $this->quantity);
  548.         $netPerItem   = $vatRate > 0 ? $grossPerItem / (1 + $vatRate / 100) : $grossPerItem;
  549.         $this->pricePerItemWithoutVat = (string) round($netPerItem, 3);
  550.         $this->pricePerItemWithVat    = (string) round($grossPerItem, 3);
  551.         $this->vatPricePerItem        = (string) round($grossPerItem - $netPerItem, 3);
  552.         $this->totalVatPrice          = (string) round(($grossPerItem - $netPerItem) * $quantity, 3);
  553.         $this->totalPrice             = (string) round($grossPerItem * $quantity, 3);
  554.     }
  555.     /**
  556.      * @PrePersist
  557.      * @PreUpdate
  558.      */
  559.     public function autoRecalculateVatFields(): void
  560.     {
  561.         $vat = $this->order?->getVat();
  562.         if ($vat !== null && $this->price !== null && $this->quantity) {
  563.             $this->recalculateVatFields((float) $vat);
  564.         }
  565.     }
  566.     private static function mapAttributeToComparison(AttributeOption $option)
  567.     {
  568.         $attribute = $option->getAttribute();
  569.         return [
  570.             'attributeId' => $attribute->getId(),
  571.             'attributeTitle' => $attribute->getTitle(),
  572.             'optionTitle' => $option->getTitle(),
  573.         ];
  574.     }
  575.     public function recommendedPosition(array $stockItems, array $variationOptions): ServicingPosition
  576.     {
  577.         $productOptionsComp = array_map(
  578.             fn (ProductAttribute $attr) => self::mapAttributeToComparison($attr->getOption()),
  579.             $this->getProduct()->getConfigurationAttributes());
  580.         $variationOptionsComp = array_map(
  581.             fn (AttributeOption $option) => self::mapAttributeToComparison($option),
  582.             $variationOptions);
  583.         $comparedOptions = $this->compareCommonOptions($productOptionsComp, $variationOptionsComp);
  584.         $attributeIds = array_map(
  585.             fn (OrderItemAttributeOption $option) => $option->getAttributeOption()->getAttribute()->getId(),
  586.             $this->itemAttributes->toArray()
  587.         );
  588.         // Quality may vary
  589.         $qualityMayVary = 'no';
  590.         if ( !is_null($this->order->getQualityMayVarySetting()) ) {
  591.             $qualityMayVary = $this->order->getQualityMayVarySetting()->getValue();
  592.         }
  593.         if ( $qualityMayVary == 'no' ) {
  594.             /** @var StockItem $stockItem */
  595.             foreach ( $this->getStockMovementItem()?->getItems() ?? [] as $stockItem ) {
  596.                 if (( StockItem::getQualityTitleChoices()[$stockItem->getQuality()] ?? '' ) !== ( $variationOptions[Attribute::ATTRIBUTE_ID_QUALITY] ?? null )?->getTitle() ) {
  597.                     // Quality Values
  598.                     $qualityA = StockItem::getQualityValue()[strtolower(( StockItem::getQualityTitleChoices()[$stockItem->getQuality()] ?? '' ))] ?? 0;
  599.                     $qualityB = StockItem::getQualityValue()[strtolower(( $variationOptions[Attribute::ATTRIBUTE_ID_QUALITY] ?? null )?->getTitle())] ?? 0;
  600.                     // Compare
  601.                     $comparison = $qualityA <=> $qualityB;
  602.                     if ( $comparison == 1 ) {
  603.                         return ServicingPosition::ADMIN_VARO;
  604.                     }
  605.                     if ( $comparison == -1 ) {
  606.                         return ServicingPosition::FOLIAZAS_VARO;
  607.                     }
  608.                 }
  609.             }
  610.         }
  611.         // ha NEW a quality akkor egybol CSOMAGOLAS, kivetel a fotermek
  612.         $product = $this->getProduct();
  613.         if ($product->getQualityStatus() === Product::QualityStatus_New && !$product->getType()->isMainProductType()) {
  614.             return ServicingPosition::CSOMAGOLAS;
  615.         }
  616.         // ha telleg valtozott a konfig (van variacio) es mas a variacio mint a konfig,  - CONFIG-VARO
  617.         if ($comparedOptions['differences'] !== []) {
  618.             return ServicingPosition::CONFIG_VARO;
  619.         }
  620.         // vagy billt kell festeni - CONFIG-VARO
  621.         if (in_array(184, $attributeIds)) {
  622.             return ServicingPosition::CONFIG_VARO;
  623.         }
  624.         // minden mas TELEPITES_VARO
  625.         return ServicingPosition::TELEPITES_VARO;
  626.     }
  627.     private function compareCommonOptions(array $prodOptions, array $varOptions): array
  628.     {
  629.         // Create lookups by attributeId
  630.         $prodLookup = [];
  631.         foreach ($prodOptions as $option) {
  632.             $prodLookup[$option['attributeId']] = $option;
  633.         }
  634.         $varLookup = [];
  635.         foreach ($varOptions as $option) {
  636.             $varLookup[$option['attributeId']] = $option;
  637.         }
  638.         // Find common attributeIds
  639.         $commonAttributeIds = array_intersect(array_keys($prodLookup), array_keys($varLookup));
  640.         // Compare optionTitles for common attributeIds
  641.         $differences = [];
  642.         foreach ($commonAttributeIds as $attributeId) {
  643.             $prodOption = $prodLookup[$attributeId];
  644.             $varOption = $varLookup[$attributeId];
  645.             if ($prodOption['optionTitle'] !== $varOption['optionTitle']) {
  646.                 $differences[] = [
  647.                     'attributeId' => $attributeId,
  648.                     'attributeTitle' => $prodOption['attributeTitle'],
  649.                     'prodOptionTitle' => $prodOption['optionTitle'],
  650.                     'varOptionTitle' => $varOption['optionTitle']
  651.                 ];
  652.             }
  653.         }
  654.         return [
  655.             'common_attribute_ids' => $commonAttributeIds,
  656.             'differences' => $differences
  657.         ];
  658.     }
  659. }