src/AtechNet/CoreBundle/Entity/StockMovementItem.php line 29

Open in your IDE?
  1. <?php
  2. namespace App\AtechNet\CoreBundle\Entity;
  3. use App\AtechNet\CoreBundle\Repository\StockMovementItemRepository;
  4. use App\AtechNet\CoreBundle\Entity\PersonalizationAttributeOptionCombination;
  5. use Doctrine\Common\Collections\ArrayCollection;
  6. use Doctrine\ORM\Mapping\Column;
  7. use Doctrine\ORM\Mapping\Entity;
  8. use Doctrine\ORM\Mapping\JoinColumn;
  9. use Doctrine\ORM\Mapping\JoinTable;
  10. use Doctrine\ORM\Mapping\HasLifecycleCallbacks;
  11. use Doctrine\ORM\Mapping\ManyToMany;
  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\PrePersist;
  17. use Doctrine\ORM\Mapping\PreUpdate;
  18. use Doctrine\ORM\Mapping\Table as Table;
  19. /**
  20.  * StockMovementItem
  21.  *
  22.  * @Table(name="stock_movement_item")
  23.  * @Entity(repositoryClass=StockMovementItemRepository::class)
  24.  * @HasLifecycleCallbacks
  25.  */
  26. class StockMovementItem extends AbstractSignedEntity
  27. {
  28.     /**
  29.      * @var int
  30.      *
  31.      * @Column(name="sort_index", type="integer")
  32.      */
  33.     private $sortIndex = 0;
  34.     /**
  35.      * @var StockMovement
  36.      *
  37.      * @ManyToOne(targetEntity="StockMovement", inversedBy="movementItems", cascade={"persist"})
  38.      * @JoinColumn(name="stock_movement_id", referencedColumnName="id", nullable=false)
  39.      */
  40.     private $movement;
  41.     /**
  42.      * @var ArrayCollection
  43.      *
  44.      * @ManyToMany(targetEntity="AikenShipment", inversedBy="movementItems")
  45.      * @JoinTable(name="stock_movement_items_aiken_shipments")
  46.      * @OrderBy({"created" = "DESC"})
  47.      */
  48.     private $aikenShipments;
  49.     /**
  50.      * @var Product
  51.      *
  52.      * @ManyToOne(targetEntity="Product", inversedBy="stockMovementItems")
  53.      * @JoinColumn(name="product_id", referencedColumnName="id", nullable=true)
  54.      */
  55.     private $product;
  56.     /**
  57.      * @var int
  58.      *
  59.      * @Column(name="quantity", type="integer")
  60.      */
  61.     private $quantity;
  62.     /**
  63.      * @var float
  64.      *
  65.      * @Column(name="price", type="decimal", precision=12, scale=3)
  66.      */
  67.     private $price;
  68.     /**
  69.      * @var ArrayCollection
  70.      *
  71.      * @ManyToMany(targetEntity="StockItem", inversedBy="movementItems")
  72.      * @JoinTable(
  73.      *  name="stock_movement_items_stock_items",
  74.      *  joinColumns={
  75.      *      @JoinColumn(name="stockmovementitem_id", referencedColumnName="id", onDelete="CASCADE")
  76.      *  },
  77.      *  inverseJoinColumns={
  78.      *      @JoinColumn(name="stockitem_id", referencedColumnName="id")
  79.      *  })
  80.      * @OrderBy({"created" = "DESC"})
  81.      */
  82.     private $items;
  83.     /**
  84.      * @var OrderItem|null
  85.      *
  86.      * @OneToOne(targetEntity="OrderItem", inversedBy="stockMovementItem", cascade={"persist", "remove"})
  87.      * @JoinColumn(name="order_item_id", referencedColumnName="id", onDelete="CASCADE")
  88.      */
  89.     private ?OrderItem $orderItem;
  90.     /**
  91.      * @var OrderItemAttributeOption|null
  92.      *
  93.      * @OneToOne(targetEntity="OrderItemAttributeOption", inversedBy="stockMovementItem", cascade={"persist", "remove"})
  94.      * @JoinColumn(name="order_item_attribute_id", referencedColumnName="id", onDelete="CASCADE")
  95.      */
  96.     private ?OrderItemAttributeOption $orderItemAttribute;
  97.     /**
  98.      * @var DocumentItem
  99.      *
  100.      * @OneToOne(targetEntity="DocumentItem", inversedBy="stockMovementItem", cascade={"persist", "remove"})
  101.      * @JoinColumn(name="document_item_id", referencedColumnName="id", onDelete="CASCADE")
  102.      */
  103.     private $documentItem;
  104.     /**
  105.      * @var string
  106.      *
  107.      * @Column(name="averege_buying_price_per_item", type="decimal", precision=10, scale=2)
  108.      *
  109.      * Average buying price of product in time of stock movement item creation
  110.      */
  111.     private $averageBuyingPricePerItem = 0;
  112.     /**
  113.      * @var ArrayCollection
  114.      *
  115.      * @OneToMany(targetEntity="StockMovementItem", mappedBy="configChangeParentMovementItem", cascade={"persist"}, orphanRemoval=false)
  116.      * @OrderBy({"created" = "DESC"})
  117.      */
  118.     private $configChangeChildMovementItems;
  119.     /**
  120.      * @var StockMovementItem
  121.      *
  122.      * @ManyToOne(targetEntity="StockMovementItem", inversedBy="configChangeChildMovementItems", cascade={"persist"})
  123.      * @JoinColumn(name="config_change_parent_movement_item_id", referencedColumnName="id", nullable=true)
  124.      */
  125.     private $configChangeParentMovementItem;
  126.     /**
  127.      * @var int|null
  128.      *
  129.      * @Column(name="product_model_variation_id", type="integer", nullable=true)
  130.      */
  131.     private ?int $productModelVariationId = null;
  132.     /**
  133.      * @var string|null
  134.      *
  135.      * @Column(name="vat_price_per_item", type="decimal", precision=12, scale=3, nullable=true)
  136.      */
  137.     private ?string $vatPricePerItem = null;
  138.     /**
  139.      * @var string|null
  140.      *
  141.      * @Column(name="total_vat_price", type="decimal", precision=12, scale=3, nullable=true)
  142.      */
  143.     private ?string $totalVatPrice = null;
  144.     /**
  145.      * @var string|null
  146.      *
  147.      * @Column(name="total_price", type="decimal", precision=12, scale=3, nullable=true)
  148.      */
  149.     private ?string $totalPrice = null;
  150.     /**
  151.      * @var string|null
  152.      *
  153.      * @Column(name="price_per_item", type="decimal", precision=12, scale=3, nullable=true)
  154.      */
  155.     private ?string $pricePerItemWithoutVat = null;
  156.     /**
  157.      * @var string|null
  158.      *
  159.      * @Column(name="price_per_item_with_vat", type="decimal", precision=12, scale=3, nullable=true)
  160.      */
  161.     private ?string $pricePerItemWithVat = null;
  162.     /**
  163.      * @var PersonalizationAttributeOptionCombination
  164.      *
  165.      * @ManyToOne(targetEntity="PersonalizationAttributeOptionCombination", inversedBy="stockMovementItems")
  166.      * @JoinColumn(name="personalization_attribute_option_combination_id", referencedColumnName="id", nullable=true)
  167.      */
  168.     private ?PersonalizationAttributeOptionCombination $personalizationAttributeOptionCombination;
  169.     public function __construct()
  170.     {
  171.         parent::__construct();
  172.         $this->items = new ArrayCollection();
  173.     }
  174.     /**
  175.      * @return int
  176.      */
  177.     public function getSortIndex(): int
  178.     {
  179.         return $this->sortIndex;
  180.     }
  181.     /**
  182.      * @param int $sortIndex
  183.      */
  184.     public function setSortIndex($sortIndex): void
  185.     {
  186.         $this->sortIndex = $sortIndex;
  187.     }
  188.     /**
  189.      * @return StockMovement
  190.      */
  191.     public function getMovement(): StockMovement
  192.     {
  193.         return $this->movement;
  194.     }
  195.     /**
  196.      * @param StockMovement $movement
  197.      */
  198.     public function setMovement($movement): void
  199.     {
  200.         $this->movement = $movement;
  201.     }
  202.     /**
  203.      * @return ArrayCollection
  204.      */
  205.     public function getAikenShipments()
  206.     {
  207.         return $this->aikenShipments;
  208.     }
  209.     /**
  210.      * @param ArrayCollection $aikenShipments
  211.      */
  212.     public function setAikenShipments($aikenShipments): void
  213.     {
  214.         $this->aikenShipments = $aikenShipments;
  215.     }
  216.     /**
  217.      * @return Product
  218.      */
  219.     public function getProduct(): Product
  220.     {
  221.         return $this->product;
  222.     }
  223.     /**
  224.      * @param Product $product
  225.      */
  226.     public function setProduct($product): void
  227.     {
  228.         $this->product = $product;
  229.     }
  230.     /**
  231.      * @return int
  232.      */
  233.     public function getQuantity(): int
  234.     {
  235.         return $this->quantity;
  236.     }
  237.     /**
  238.      * @param int $quantity
  239.      */
  240.     public function setQuantity(int $quantity): void
  241.     {
  242.         $this->quantity = $quantity;
  243.     }
  244.     /**
  245.      * @return int
  246.      */
  247.     public function getVat(): int
  248.     {
  249.         return $this->getMovement()->getVat();
  250.     }
  251.     /**
  252.      * @return float
  253.      */
  254.     public function getPrice(): float
  255.     {
  256.         return $this->price;
  257.     }
  258.     /**
  259.      * @param bool $homeCurrency
  260.      *
  261.      * @return string|int|float
  262.      */
  263.     public function getPricePerItem(bool $homeCurrency = false): string|int|float
  264.     {
  265.         if ( $this->getPrice() > 0 && $this->getQuantity() > 0 ) {
  266.             if ( $homeCurrency === true && $this->getMovement()->getExchangeRate() > 0 ) {
  267.                 return number_format(( $this->getPrice() / $this->getMovement()->getExchangeRate() ) / $this->getQuantity(), 2, '.', '');
  268.             }
  269.             return number_format($this->getPrice() / $this->getQuantity(), 2, '.', '');
  270.         }
  271.         return 0;
  272.     }
  273.     /**
  274.      * @return float
  275.      */
  276.     public function getTotalPricePerItem(): float
  277.     {
  278.         $movement = $this->movement;
  279.         return self::calculateTotalPricePerItem(
  280.             (float)$this->getPrice(),
  281.             (int)$this->getQuantity(),
  282.             $movement != null ? (float)$movement->getExtraPrice() : 0.0,
  283.             $movement != null ? (int)$movement->getQuantity() : 0
  284.         );
  285.     }
  286.     /**
  287.      * Same math as getTotalPricePerItem(), callable from scalar query rows so callers
  288.      * do not have to hydrate whole movement histories to read a price.
  289.      */
  290.     public static function calculateTotalPricePerItem(
  291.         float $price,
  292.         int $quantity,
  293.         float $movementExtraPrice,
  294.         int $movementQuantity
  295.     ): float {
  296.         $total = $price > 0 && $quantity > 0 ? (float)number_format($price / $quantity, 2, '.', '') : 0.0;
  297.         if ($movementQuantity > 0) {
  298.             $total += $movementExtraPrice / $movementQuantity;
  299.         }
  300.         return $total;
  301.     }
  302.     /**
  303.      * @param float $price
  304.      */
  305.     public function setPrice($price): void
  306.     {
  307.         $this->price = $price;
  308.     }
  309.     /**
  310.      * @return float
  311.      */
  312.     public function getVatPrice(): float
  313.     {
  314.         return $this->getCompany()->createVatPrice($this->price, $this->getVat());
  315.     }
  316.     /**
  317.      * @return string|int
  318.      */
  319.     public function getVatPricePerItem(): string|int
  320.     {
  321.         if ($this->vatPricePerItem) {
  322.             return $this->vatPricePerItem;
  323.         }
  324.         if ($this->getVatPrice() != 0 && $this->getQuantity() > 0) {
  325.             return number_format($this->getVatPrice() / $this->getQuantity(), 2, '.', '');
  326.         }
  327.         return 0;
  328.     }
  329.     /**
  330.      * @return ArrayCollection
  331.      */
  332.     public function getItems()
  333.     {
  334.         return $this->items;
  335.     }
  336.     /**
  337.      * @param ArrayCollection $items
  338.      */
  339.     public function setItems($items): void
  340.     {
  341.         $this->items = $items;
  342.     }
  343.     /**
  344.      * Add StockItem
  345.      *
  346.      * @param StockItem $item
  347.      */
  348.     public function addItem($item): void
  349.     {
  350.         if (!$this->items->contains($item)) {
  351.             $this->items->add($item);
  352.         }
  353.     }
  354.     /**
  355.      * Remove StockItem
  356.      *
  357.      * @param StockItem $item
  358.      */
  359.     public function removeItem($item): void
  360.     {
  361.         $this->items->removeElement($item);
  362.     }
  363.     /**
  364.      * @return ?OrderItem
  365.      */
  366.     public function getOrderItem(): ?OrderItem
  367.     {
  368.         return $this->orderItem;
  369.     }
  370.     /**
  371.      * @param ?OrderItem $orderItem
  372.      */
  373.     public function setOrderItem(?OrderItem $orderItem): void
  374.     {
  375.         $this->orderItem = $orderItem;
  376.     }
  377.     /**
  378.      * @return Company
  379.      */
  380.     public function getCompany(): Company
  381.     {
  382.         return $this->getMovement()->getStock()->getCompany();
  383.     }
  384.     /**
  385.      * @return mixed
  386.      */
  387.     public function getCurrency(): mixed
  388.     {
  389.         return $this->getCompany()->getCurrency();
  390.     }
  391.     /**
  392.      * @return ?OrderItemAttributeOption
  393.      */
  394.     public function getOrderItemAttribute(): ?OrderItemAttributeOption
  395.     {
  396.         return $this->orderItemAttribute;
  397.     }
  398.     /**
  399.      * @param ?OrderItemAttributeOption $orderItemAttribute
  400.      */
  401.     public function setOrderItemAttribute(?OrderItemAttributeOption $orderItemAttribute): void
  402.     {
  403.         $this->orderItemAttribute = $orderItemAttribute;
  404.     }
  405.     /**
  406.      * @return DocumentItem
  407.      */
  408.     public function getDocumentItem(): ?DocumentItem
  409.     {
  410.         return $this->documentItem;
  411.     }
  412.     /**
  413.      * @param ?DocumentItem $documentItem
  414.      */
  415.     public function setDocumentItem(?DocumentItem $documentItem): void
  416.     {
  417.         $this->documentItem = $documentItem;
  418.     }
  419.     /**
  420.      * @return PersonalizationAttributeOptionCombination
  421.      */
  422.     public function getPersonalizationAttributeOptionCombination(): ?PersonalizationAttributeOptionCombination
  423.     {
  424.         return $this->personalizationAttributeOptionCombination;
  425.     }
  426.     /**
  427.      * @param ?PersonalizationAttributeOptionCombination $personalizationAttributeOptionCombination
  428.      */
  429.     public function setPersonalizationAttributeOptionCombination(?PersonalizationAttributeOptionCombination $personalizationAttributeOptionCombination): void
  430.     {
  431.         $this->personalizationAttributeOptionCombination = $personalizationAttributeOptionCombination;
  432.     }
  433.     /**
  434.      * @return int|string
  435.      */
  436.     public function getAverageBuyingPricePerItem(): int|string
  437.     {
  438.         return $this->averageBuyingPricePerItem;
  439.     }
  440.     /**
  441.      * @param int|string $averageBuyingPricePerItem
  442.      */
  443.     public function setAverageBuyingPricePerItem($averageBuyingPricePerItem): void
  444.     {
  445.         $this->averageBuyingPricePerItem = $averageBuyingPricePerItem;
  446.     }
  447.     /**
  448.      * @param $childMovementItem
  449.      *
  450.      * @return void
  451.      */
  452.     public function removeConfigChangeChildMovementItem($childMovementItem): void
  453.     {
  454.         $this->configChangeChildMovementItems->removeElement($childMovementItem);
  455.     }
  456.     /**
  457.      * @return ArrayCollection
  458.      */
  459.     public function getConfigChangeChildMovementItems()
  460.     {
  461.         return $this->configChangeChildMovementItems;
  462.     }
  463.     /**
  464.      * @return StockMovementItem|null
  465.      */
  466.     public function getConfigChangeParentMovementItem(): ?StockMovementItem
  467.     {
  468.         return $this->configChangeParentMovementItem;
  469.     }
  470.     /**
  471.      * @param StockMovementItem|null $configChangeParentMovementItem
  472.      *
  473.      * @return void
  474.      */
  475.     public function setConfigChangeParentMovementItem(?StockMovementItem $configChangeParentMovementItem): void
  476.     {
  477.         $this->configChangeParentMovementItem = $configChangeParentMovementItem;
  478.     }
  479.     /**
  480.      * @return int|null
  481.      */
  482.     public function getProductModelVariationId(): ?int
  483.     {
  484.         return $this->productModelVariationId;
  485.     }
  486.     /**
  487.      * @param int|null $productModelVariationId
  488.      *
  489.      * @return void
  490.      */
  491.     public function setProductModelVariationId(?int $productModelVariationId): void
  492.     {
  493.         $this->productModelVariationId = $productModelVariationId;
  494.     }
  495.     public function setVatPricePerItem(?string $vatPricePerItem): void
  496.     {
  497.         $this->vatPricePerItem = $vatPricePerItem;
  498.     }
  499.     public function getTotalVatPrice(): ?string
  500.     {
  501.         return $this->totalVatPrice;
  502.     }
  503.     public function setTotalVatPrice(?string $totalVatPrice): void
  504.     {
  505.         $this->totalVatPrice = $totalVatPrice;
  506.     }
  507.     public function getTotalPrice(): ?string
  508.     {
  509.         return $this->totalPrice;
  510.     }
  511.     public function setTotalPrice(?string $totalPrice): void
  512.     {
  513.         $this->totalPrice = $totalPrice;
  514.     }
  515.     public function getPricePerItemWithoutVat(): ?string
  516.     {
  517.         return $this->pricePerItemWithoutVat;
  518.     }
  519.     public function setPricePerItemWithoutVat(?string $pricePerItemWithoutVat): void
  520.     {
  521.         $this->pricePerItemWithoutVat = $pricePerItemWithoutVat;
  522.     }
  523.     public function getPricePerItemWithVat(): ?string
  524.     {
  525.         return $this->pricePerItemWithVat;
  526.     }
  527.     public function setPricePerItemWithVat(?string $pricePerItemWithVat): void
  528.     {
  529.         $this->pricePerItemWithVat = $pricePerItemWithVat;
  530.     }
  531.     public function recalculateVatFields(float $vatRate): void
  532.     {
  533.         $quantity      = max(1, (int) $this->quantity);
  534.         $netTotal      = (float) $this->price;
  535.         $netPerItem    = $netTotal / $quantity;
  536.         $grossTotal    = $netTotal * (1 + $vatRate / 100);
  537.         $this->pricePerItemWithoutVat = (string) round($netPerItem, 3);
  538.         $this->pricePerItemWithVat    = (string) round($grossTotal / $quantity, 3);
  539.         $this->vatPricePerItem        = (string) round($netPerItem * $vatRate / 100, 3);
  540.         $this->totalVatPrice          = (string) round($netTotal * $vatRate / 100, 3);
  541.         $this->totalPrice             = (string) round($grossTotal, 3);
  542.     }
  543.     /**
  544.      * @PrePersist
  545.      * @PreUpdate
  546.      */
  547.     public function autoRecalculateVatFields(): void
  548.     {
  549.         if ($this->movement !== null && $this->price !== null && $this->quantity) {
  550.             $this->recalculateVatFields((float) $this->getVat());
  551.         }
  552.     }
  553. }