src/AtechNet/CoreBundle/Entity/Product.php line 52

Open in your IDE?
  1. <?php
  2. namespace App\AtechNet\CoreBundle\Entity;
  3. use App\AtechNet\CoreBundle\Helper\Collections;
  4. use App\AtechNet\CoreBundle\Translation\TranslationHelper;
  5. use App\AtechNet\CoreBundle\Translation\TranslatorInterface;
  6. use Doctrine\Common\Collections\ArrayCollection;
  7. use Doctrine\Common\Collections\Collection;
  8. use Doctrine\Common\Collections\Criteria;
  9. use Doctrine\ORM\Mapping\Column;
  10. use Doctrine\ORM\Mapping\Entity;
  11. use Doctrine\ORM\Mapping\HasLifecycleCallbacks;
  12. use Doctrine\ORM\Mapping\JoinColumn;
  13. use Doctrine\ORM\Mapping\JoinTable;
  14. use Doctrine\ORM\Mapping\ManyToMany;
  15. use Doctrine\ORM\Mapping\ManyToOne;
  16. use Doctrine\ORM\Mapping\OneToMany;
  17. use Doctrine\ORM\Mapping\OneToOne;
  18. use Doctrine\ORM\Mapping\OrderBy;
  19. use Doctrine\ORM\Mapping\Table as Table;
  20. use Doctrine\ORM\Mapping\UniqueConstraint;
  21. use Symfony\Bridge\Doctrine\Validator\Constraints\UniqueEntity;
  22. use Symfony\Component\Validator\Constraints as Assert;
  23. /**
  24.  * @Entity(repositoryClass="App\AtechNet\CoreBundle\Repository\ProductRepository")
  25.  * @Table(name="products", uniqueConstraints={
  26.  *     @UniqueConstraint(name="unique_product_code", columns={"type_id", "code"}),
  27.  * })
  28.  *
  29.  * @UniqueEntity(
  30.  *     fields={"type", "code"},
  31.  *     errorPath="code",
  32.  *     message="This Id is already in use with that type. Try to save it again."
  33.  * )
  34.  * @UniqueEntity(
  35.  *     fields={"ean"},
  36.  *     errorPath="ean",
  37.  *     message="This EAN is already in use.",
  38.  *     ignoreNull=true
  39.  * )
  40.  * @UniqueEntity(
  41.  *     fields={"partNumber"},
  42.  *     errorPath="partNumber",
  43.  *     message="This Part Number is already in use.",
  44.  *     ignoreNull=true
  45.  * )
  46.  *
  47.  * @HasLifecycleCallbacks
  48.  */
  49. class Product extends AbstractSignedEntity
  50. {
  51.     public const string Unit_Pcs = 'pcs';
  52.     public const int SHIPPING_ID = 82;
  53.     public const int CASH_ON_DELIVERY_PRODUCT_ID = 23848;
  54.     public const int COMPENSATION_ITEM_ID = 31175;
  55.     public const int CABLE_POWER_PRODUCT_ID = 2285;
  56.     public const int CABLE_POWER_UK_PRODUCT_ID = 12638;
  57.     public const int CABLE_POWER_UK_MALE_PRODUCT_ID = 12637;
  58.     public const int CABLE_POWER_UK_FEMALE_PRODUCT_ID = 26954;
  59.     public const int CABLE_POWER_CH_NOTEBOOK_PRODUCT_ID = 64928;
  60.     public const int CABLE_POWER_CH_COMPUTER_PRODUCT_ID = 68732;
  61.     public const int PRODUCT_IN_STOCK_AVAILABLE_STOCK_MOVEMENT_QTY_REFRESH_LIMIT = 2000;
  62.     public const int ADATTORLO_PRODUCT_ID = 30896;
  63.     public const int ESET_NOD32_90_DAY_TRIAL_PRODUCT_ID = 35249;
  64.     public const int GDATA_90_DAY_TRIAL_PRODUCT_ID = 37334;
  65.     public const int MPL_PACKAGE_FEE_PRODUCT_ID = 41630;
  66.     public const int KEYBOARD_STICKER_SK_CZ_ID = 191;
  67.     public const int KEYBOARD_STICKER_HU_ID = 2656;
  68.     public const int UNIDENTIFIED_PRODUCT_ID = 55679;
  69.     public const int SUMMER_2026_COUPON_GIFT_ITEM_ID = 67485;
  70.     public const int PEXESO_SCHOOL_GIFT_ITEM_ID = 70223;
  71.     public const int BATTERY_USED_70 = 70831;
  72.     public const int BATTERY_USED_71 = 70832;
  73.     /**
  74.      * @return array
  75.      */
  76.     public static function getUnitChoices(): array
  77.     {
  78.         return [
  79.             self::Unit_Pcs => self::Unit_Pcs,
  80.         ];
  81.     }
  82.     public const OutOfStockStatus_Empty = 0;
  83.     public const OutOfStockStatus_NotVisibleDefault = 1;
  84.     public const OutOfStockStatus_VisibleComingSoon = 2;
  85.     public const OutOfStockStatus_VisibleSoldOut = 3;
  86.     public const OutOfStockStatus_VisibleShadow = 4;
  87.     public const OutOfStockStatus_VisibleOrderable5Days = 5;
  88.     public const OutOfStockStatus_VisibleOrderable10Days = 6;
  89.     public const OutOfStockStatus_VisibleOrderable15Days = 7;
  90.     /**
  91.      * @return array
  92.      */
  93.     public static function getStockStatusChoices(): array
  94.     {
  95.         return [
  96.             self::OutOfStockStatus_Empty => 'Empty',
  97.             self::OutOfStockStatus_NotVisibleDefault => 'Not visible, default',
  98.             self::OutOfStockStatus_VisibleComingSoon => 'Visible, coming soon (cannot order)',
  99.             self::OutOfStockStatus_VisibleSoldOut => 'Visible, sold out listed (cannot order)',
  100.             self::OutOfStockStatus_VisibleShadow => 'Visible, shadow',
  101.             self::OutOfStockStatus_VisibleOrderable5Days => 'Visible, orderable, 5 days',
  102.             self::OutOfStockStatus_VisibleOrderable10Days => 'Visible, orderable, 10 days',
  103.             self::OutOfStockStatus_VisibleOrderable15Days => 'Visible, orderable, 15 days',
  104.         ];
  105.     }
  106.     /**
  107.      * @return array
  108.      */
  109.     public static function getVisibleOutOfStockStatusChoices(): array
  110.     {
  111.         $stockStatusChoices = self::getStockStatusChoices();
  112.         unset($stockStatusChoices[self::OutOfStockStatus_Empty]);
  113.         unset($stockStatusChoices[self::OutOfStockStatus_NotVisibleDefault]);
  114.         return $stockStatusChoices;
  115.     }
  116.     public const QualityStatus_Empty = 0;
  117.     public const QualityStatus_Platinum = 1;
  118.     public const QualityStatus_Unpacked = 2;
  119.     public const QualityStatus_Refurbished_A_Plus = 3;
  120.     public const QualityStatus_Gold = 4;
  121.     public const QualityStatus_Silver = 5;
  122.     public const QualityStatus_Bronze = 6;
  123.     public const QualityStatus_Iron = 7;
  124.     public const QualityStatus_New = 8;
  125.     public const QualityStatus_Bazaar = 9;
  126.     /**
  127.      * @return array
  128.      */
  129.     public static function getQualityStatusChoices(): array
  130.     {
  131.         return [
  132.             self::QualityStatus_Empty => 'Empty',
  133.             self::QualityStatus_New => 'New',
  134.             self::QualityStatus_Platinum => 'Platinum',
  135.             self::QualityStatus_Gold => 'Gold',
  136.             self::QualityStatus_Silver => 'Silver',
  137.             self::QualityStatus_Bronze => 'Bronze',
  138.             self::QualityStatus_Bazaar => 'Bazaar',
  139.         ];
  140.     }
  141.     /**
  142.      * @return array
  143.      */
  144.     public static function getQualityStatusKeys(): array
  145.     {
  146.         return [
  147.             self::QualityStatus_Empty,
  148.             self::QualityStatus_New,
  149.             self::QualityStatus_Platinum,
  150.             self::QualityStatus_Gold,
  151.             self::QualityStatus_Silver,
  152.             self::QualityStatus_Bronze,
  153.             self::QualityStatus_Bazaar,
  154.         ];
  155.     }
  156.     /**
  157.      * @return array
  158.      */
  159.     public static function getQualityStatusAsAttributeOptionId(): array
  160.     {
  161.         return [
  162.             self::QualityStatus_Bazaar => AttributeOption::ATTRIBUTE_OPTION_QUALITY_BAZAAR,
  163.             self::QualityStatus_Bronze => AttributeOption::ATTRIBUTE_OPTION_QUALITY_BRONZ,
  164.             self::QualityStatus_Silver => AttributeOption::ATTRIBUTE_OPTION_QUALITY_SILVER,
  165.             self::QualityStatus_Gold => AttributeOption::ATTRIBUTE_OPTION_QUALITY_GOLD,
  166.             self::QualityStatus_New => AttributeOption::ATTRIBUTE_OPTION_QUALITY_NEW,
  167.             self::QualityStatus_Platinum => AttributeOption::ATTRIBUTE_OPTION_QUALITY_PLATINUM,
  168.         ];
  169.     }
  170.     /**
  171.      * @return array
  172.      */
  173.     public static function getEUQualityStatusPairs(): array
  174.     {
  175.         return [
  176.             self::QualityStatus_Empty => 'Empty',
  177.             self::QualityStatus_New => 'New',
  178.             self::QualityStatus_Platinum => 'A',
  179.             self::QualityStatus_Gold => 'A',
  180.             self::QualityStatus_Silver => 'A',
  181.             self::QualityStatus_Bronze => 'B+',
  182.             self::QualityStatus_Bazaar => 'C',
  183.         ];
  184.     }
  185.     /**
  186.      * @param $key
  187.      * @return mixed|null
  188.      */
  189.     public static function getQualityStatusTitleForKey($key)
  190.     {
  191.         return self::getQualityStatusChoices()[$key] ?? null;
  192.     }
  193.     public const string PRODUCT_BADGE_GAMER = 'gamer';
  194.     public const string PRODUCT_BADGE_WORKSTATION = 'workstation';
  195.     public const string PRODUCT_BADGE_2_IN_1 = '2in1 notebook';
  196.     public const string PRODUCT_BADGE_CHROMEBOOK = 'Chromebook';
  197.     public const string PRODUCT_BADGE_TINY_PC = 'Tiny PC';
  198.     public const string PRODUCT_BADGE_BESTSELLER = 'bestseller';
  199.     /**
  200.      * @return array
  201.      */
  202.     public static function getBadgesChoices(): array
  203.     {
  204.         return [
  205.             'gamer'           => 'gamer',
  206.             'work'            => 'work',
  207.             'travel'          => 'travel',
  208.             'senior'          => 'senior',
  209.             'internet'        => 'internet',
  210.             'win10'           => 'win10',
  211.             'workstation'     => 'workstation',
  212.             'Tiny PC'         => 'Tiny PC',
  213.             '2in1 notebook'   => '2in1 notebook',
  214.             'Chromebook'      => 'Chromebook',
  215.             'Notebook bundle' => 'Notebook bundle',
  216.             'Skin'            => 'Skin',
  217.             'Skinable'        => 'Skinable',
  218.             'Ultrabook'       => 'Ultrabook',
  219.             'Windows 11'      => 'Windows 11',
  220.             'Touchscreen'     => 'Touchscreen',
  221.             'bestseller'      => 'bestseller'
  222.         ];
  223.     }
  224.     public const giftCartIds = [
  225.         48709,
  226.         48708,
  227.         48707,
  228.         48706,
  229.     ];
  230.     public const int MARGIN_LEVEL_NO = 0;
  231.     public const int MARGIN_LEVEL_A = 1;
  232.     public const int MARGIN_LEVEL_B = 2;
  233.     public const int MARGIN_LEVEL_C = 3;
  234.     public const int MARGIN_LEVEL_D = 4;
  235.     public const int MARGIN_LEVEL_E = 5;
  236.     public const int MARGIN_LEVEL_F = 6;
  237.     /**
  238.      * @return string[]
  239.      */
  240.     public static function getMarginLevelChoices(): array
  241.     {
  242.         return [
  243.             self::MARGIN_LEVEL_NO => 'NO',
  244.             self::MARGIN_LEVEL_A  => 'A',
  245.             self::MARGIN_LEVEL_B  => 'B',
  246.             self::MARGIN_LEVEL_C  => 'C',
  247.             self::MARGIN_LEVEL_D  => 'D',
  248.             self::MARGIN_LEVEL_E  => 'E',
  249.             self::MARGIN_LEVEL_F  => 'F'
  250.         ];
  251.     }
  252.     /**
  253.      * @var string
  254.      *
  255.      * @Column(name="omega_plu", type="text", nullable=true)
  256.      */
  257.     private $omegaPlu = null;
  258.     /**
  259.      * Unified Unique ID
  260.      *
  261.      * @var string
  262.      *
  263.      * @Column(name="code", type="string", nullable=false)
  264.      */
  265.     private $code;
  266.     /**
  267.      * @var Vendor
  268.      *
  269.      * @ManyToOne(targetEntity="Vendor")
  270.      * @JoinColumn(name="vendor_id", referencedColumnName="id")
  271.      */
  272.     private $vendor;
  273.     /**
  274.      * @var ProductType
  275.      *
  276.      * @Assert\NotNull
  277.      *
  278.      * @ManyToOne(targetEntity="ProductType")
  279.      * @JoinColumn(name="type_id", referencedColumnName="id")
  280.      */
  281.     private $type;
  282.     /**
  283.      * @var Album
  284.      *
  285.      * @Assert\NotNull
  286.      *
  287.      * @OneToOne(targetEntity="Album", cascade={"persist", "remove"})
  288.      * @JoinColumn(name="photo_album_id", referencedColumnName="id")
  289.      */
  290.     private $album;
  291.     /**
  292.      * @var string
  293.      *
  294.      * @Assert\NotNull
  295.      *
  296.      * @Column(name="name", type="text")
  297.      */
  298.     private $name;
  299.     /**
  300.      * @var Collection<int, ProductModel>
  301.      * @ManyToMany(targetEntity="ProductModel", mappedBy="connectedProducts")
  302.      * @OrderBy({"created" = "DESC"})
  303.      */
  304.     private $connectedProductModels;
  305.     /**
  306.      * @var Collection<int, Product>
  307.      *
  308.      * @ManyToMany(targetEntity="Product", inversedBy="parentAlternativeProducts")
  309.      * @JoinTable(
  310.      *  name="products_alternative_products",
  311.      *  joinColumns={
  312.      *      @JoinColumn(name="product_id", referencedColumnName="id")
  313.      *  },
  314.      *  inverseJoinColumns={
  315.      *      @JoinColumn(name="alternative_product_id", referencedColumnName="id")
  316.      *  })
  317.      * @OrderBy({"id" = "DESC"})
  318.      */
  319.     private $alternativeProducts;
  320.     /**
  321.      * @var Collection<int, Product>
  322.      *
  323.      * @ManyToMany(targetEntity="Product", mappedBy="alternativeProducts")
  324.      * @OrderBy({"id" = "DESC"})
  325.      */
  326.     private $parentAlternativeProducts;
  327.     /**
  328.      * @var Product|null
  329.      *
  330.      * @ManyToOne(targetEntity="Product")
  331.      * @JoinColumn(name="current_alternative_product_id", referencedColumnName="id", nullable=true)
  332.      */
  333.     private ?Product $currentAlternativeProduct = null;
  334.     /**
  335.      * @var int
  336.      *
  337.      * @Assert\NotNull
  338.      *
  339.      * @Column(name="warranty", type="integer")
  340.      */
  341.     private $warranty;
  342.     /**
  343.      * @var string
  344.      *
  345.      * @Column(name="part_number", type="text", nullable=true)
  346.      */
  347.     private $partNumber = null;
  348.     /**
  349.      * @var string
  350.      *
  351.      * @Column(name="ean", type="text", nullable=true)
  352.      */
  353.     private $ean = null;
  354.     /**
  355.      * @var string
  356.      *
  357.      * @Column(name="gtin", type="text", nullable=true)
  358.      */
  359.     private $gtin = null;
  360.     /**
  361.      * @var string
  362.      *
  363.      * @Column(name="amazon_code", type="text", nullable=true)
  364.      */
  365.     private $amazonCode = null;
  366.     /**
  367.      * @var int
  368.      *
  369.      * @Column(name="length", type="integer")
  370.      */
  371.     private $length = 0;
  372.     /**
  373.      * @var string
  374.      *
  375.      * @Column(name="width", type="integer")
  376.      */
  377.     private $width = 0;
  378.     /**
  379.      * @var string
  380.      *
  381.      * @Column(name="height", type="integer")
  382.      */
  383.     private $height = 0;
  384.     /**
  385.      * @var string
  386.      *
  387.      * @Column(name="weight", type="integer")
  388.      */
  389.     private $weight = 0;
  390.     /**
  391.      * @var string
  392.      *
  393.      * @Assert\NotNull
  394.      *
  395.      * @Column(name="unit", type="string")
  396.      */
  397.     private $unit;
  398.     /**
  399.      * @var array
  400.      *
  401.      * @Assert\NotNull
  402.      *
  403.      * @Column(name="badges", type="array")
  404.      */
  405.     private $badges = [];
  406.     /**
  407.      * @var string
  408.      *
  409.      * @Column(name="detail", type="text", nullable=true)
  410.      */
  411.     private $detail = null;
  412.     /**
  413.      * @var string
  414.      *
  415.      * @Column(name="stock_position", type="text", length=96, nullable=true)
  416.      */
  417.     private $stockPosition;
  418.     /**
  419.      * @var int
  420.      *
  421.      * @Column(name="out_of_stock_status", type="integer")
  422.      */
  423.     private $outOfStockStatus = 1;
  424.     /**
  425.      * @var Collection
  426.      *
  427.      * @OneToMany(targetEntity="ProductMeta", mappedBy="product", cascade={"persist", "remove"})
  428.      **/
  429.     private $metas;
  430.     /**
  431.      * @var Collection
  432.      *
  433.      * @Assert\Valid
  434.      *
  435.      * @OneToMany(targetEntity="ProductAttribute", mappedBy="product", cascade={"persist", "remove"})
  436.      **/
  437.     private $productAttributes;
  438.     /**
  439.      * @var Collection
  440.      *
  441.      * @Assert\Valid
  442.      *
  443.      * @OneToMany(targetEntity="ProductContainer", mappedBy="product", cascade={"persist", "remove"})
  444.      **/
  445.     private $productContainers;
  446.     /**
  447.      * @var Collection
  448.      *
  449.      * @Assert\Valid
  450.      *
  451.      * @OneToMany(targetEntity="ProductContainer", mappedBy="child", cascade={"persist", "remove"})
  452.      **/
  453.     private $childContainers;
  454.     /**
  455.      * @var Collection
  456.      *
  457.      * @Assert\Valid
  458.      *
  459.      * @OneToMany(targetEntity="ProductCommission", mappedBy="product", cascade={"persist", "remove"})
  460.      **/
  461.     private $commissions;
  462.     /**
  463.      * @var Collection
  464.      *
  465.      * @Assert\Valid
  466.      *
  467.      * @OneToMany(targetEntity="OrderItem", mappedBy="product", cascade={"persist", "remove"})
  468.      **/
  469.     private $orderItems;
  470.     /**
  471.      * @var Collection
  472.      *
  473.      * @Assert\Valid
  474.      **/
  475.     private $reservations;
  476.     /**
  477.      * @var int
  478.      *
  479.      * @Assert\NotNull
  480.      *
  481.      * @Column(name="quality_status", type="integer")
  482.      */
  483.     private $qualityStatus;
  484.     /**
  485.      * @var \DateTime
  486.      *
  487.      * @Column(name="sold_out_date", type="datetime", nullable=true, options={"comment":"Generated value on update if cache_available became 0."})
  488.      */
  489.     private $soldOutDate;
  490.     /**
  491.      * @var string
  492.      *
  493.      * @Column(name="cache_description", type="text", nullable=true, options={"comment":"Generated value on insert and update."})
  494.      */
  495.     private $cacheDescription;
  496.     /**
  497.      * @var \DateTime
  498.      *
  499.      * @Column(name="cache_item_last_updated", type="datetime", nullable=false, options={"comment":"Generated value on insert and update."})
  500.      */
  501.     private $cacheItemLastUpdated;
  502.     /**
  503.      * @var int
  504.      *
  505.      * @Column(name="available", type="integer", nullable=false)
  506.      */
  507.     private $available = 0;
  508.     /**
  509.      * @var int
  510.      *
  511.      * @Column(name="in_stock", type="integer", nullable=false)
  512.      */
  513.     private $inStock = 0;
  514.     /**
  515.      * @var bool
  516.      *
  517.      * @Column(name="archived", type="boolean")
  518.      */
  519.     private $archived;
  520.     /**
  521.      * @var bool
  522.      *
  523.      * @Column(name="scannable", type="boolean")
  524.      */
  525.     private $scannable = true;
  526.     /**
  527.      * @var float
  528.      *
  529.      * @Column(name="last_price", type="float", nullable=false)
  530.      */
  531.     private $lastPrice = 0;
  532.     /**
  533.      * @var float
  534.      *
  535.      * @Column(name="avg_price", type="float", nullable=false)
  536.      */
  537.     private $avgPrice = 0;
  538.     /**
  539.      * @var Collection
  540.      *
  541.      * @OneToMany(targetEntity="StockMovementItem", mappedBy="product", orphanRemoval=true, fetch="EXTRA_LAZY")
  542.      * @OrderBy({"created" = "DESC"})
  543.      **/
  544.     private $stockMovementItems;
  545.     /**
  546.      * @var bool
  547.      *
  548.      * @Column(name="container", type="boolean")
  549.      */
  550.     private $container = false;
  551.     /**
  552.      * @var Collection
  553.      *
  554.      * @ManyToMany(targetEntity="CategoryPage", mappedBy="products")
  555.      * @OrderBy({"id" = "DESC"})
  556.      */
  557.     private $categoryPages;
  558.     /**
  559.      * @var Collection
  560.      *
  561.      * @ManyToMany(targetEntity="CategoryPage", mappedBy="popularProducts")
  562.      * @OrderBy({"id" = "DESC"})
  563.      */
  564.     private $popularProductsCategoryPages;
  565.     /**
  566.      * @var Collection
  567.      *
  568.      * @ManyToMany(targetEntity="ProductTag", mappedBy="products")
  569.      * @OrderBy({"id" = "DESC"})
  570.      */
  571.     private $tags;
  572.     
  573.     /**
  574.      * @var Collection
  575.      *
  576.      * @OneToMany(targetEntity="CustomerNotification", mappedBy="product")
  577.      */
  578.     private $notifications;
  579.     /**
  580.      * @var Collection
  581.      *
  582.      * @OneToMany(targetEntity="ProductPriceLog", mappedBy="product")
  583.      **/
  584.     private $priceLogEntries;
  585.     /**
  586.      * @var \DateTime
  587.      *
  588.      * @Column(name="last_sale", type="datetime", nullable=true)
  589.      */
  590.     private $lastSale = null;
  591.     /**
  592.      * @var Collection
  593.      *
  594.      * @OneToMany(targetEntity="ProductExternalFeedName", mappedBy="product", cascade={"persist", "remove"})
  595.      */
  596.     private $externalFeedNames;
  597.     /**
  598.      * @var int
  599.      *
  600.      * @Column(name="cpu_mark", type="integer")
  601.      */
  602.     private $cpuMark = 0;
  603.     /**
  604.      * @var ProductModel
  605.      *
  606.      * @ManyToOne(targetEntity="ProductModel", inversedBy="products")
  607.      * @JoinColumn(name="product_model_id", referencedColumnName="id", nullable=true)
  608.      */
  609.     private $productModel;
  610.     /**
  611.      * @var bool
  612.      *
  613.      * @Column(name="spare_part_card", type="boolean")
  614.      */
  615.     private $sparePartCard = false;
  616.     /**
  617.      * @var float
  618.      *
  619.      * @Column(name="spare_part_price", type="float", nullable=false)
  620.      */
  621.     private $sparePartPrice = 0;
  622.     /**
  623.      * @var int
  624.      *
  625.      * @Column(name="sold_during_time_frame", type="integer", nullable=false, options={"default": 0})     */
  626.     private $soldDuringTimeFrame = 0;
  627.     /**
  628.      * @var \DateTime
  629.      *
  630.      * @Column(name="spare_part_created", type="datetime", nullable=true)
  631.      */
  632.     private $sparePartCreated = null;
  633.     /**
  634.      * @var \DateTime
  635.      *
  636.      * @Column(name="spare_part_updated", type="datetime", nullable=true)
  637.      */
  638.     private $sparePartUpdated = null;
  639.     /**
  640.      * @var User
  641.      *
  642.      * @ManyToOne(targetEntity="User")
  643.      * @JoinColumn(name="spare_part_created_by", referencedColumnName="id", nullable=true)
  644.      */
  645.     private $sparePartCreatedBy = null;
  646.     /**
  647.      * @var User
  648.      *
  649.      * @ManyToOne(targetEntity="User")
  650.      * @JoinColumn(name="spare_part_updated_by", referencedColumnName="id", nullable=true)
  651.      */
  652.     private $sparePartUpdatedBy = null;
  653.     /**
  654.      * @var int
  655.      *
  656.      * @Column(name="margin_level", type="integer", nullable=false)
  657.      */
  658.     private $marginLevel = 0;
  659.     /**
  660.      * @var Collection
  661.      *
  662.      * @ManyToMany(targetEntity="Coupon", mappedBy="products")
  663.      */
  664.     private $coupons;
  665.     /**
  666.      * @var int|null
  667.      *
  668.      * @Column(name="quantity_limit", type="integer", nullable=true)
  669.      */
  670.     private $quantityLimit;
  671.     /**
  672.      * @var bool
  673.      *
  674.      * @Column(name="availability_paused_for_product_model", type="boolean")
  675.      */
  676.     private $availabilityPausedForProductModel = false;
  677.     /**
  678.      * @var Collection
  679.      *
  680.      * @OneToMany(targetEntity="ProductVariation", mappedBy="product", orphanRemoval=true)
  681.      * @OrderBy({"created" = "DESC"})
  682.      **/
  683.     private $productVariations;
  684.     /**
  685.      * @var FixedAttributeOptionCombination
  686.      *
  687.      * @ManyToOne(targetEntity="FixedAttributeOptionCombination", inversedBy="products")
  688.      * @JoinColumn(name="fixed_attribute_option_combination_id", referencedColumnName="id", nullable=true)
  689.      */
  690.     private $fixedAttributeOptionCombination;
  691.     /**
  692.      * @var int
  693.      *
  694.      * @Column(name="last_qty_calculated_for_marketplaces", type="integer", nullable=false)
  695.      */
  696.     private $lastQtyCalculatedForMarketplaces = 0;
  697.     /**
  698.      * @var int
  699.      *
  700.      * @Column(name="calculated_qty_grade_new", type="integer", nullable=false)
  701.      */
  702.     private $calculatedQtyGradeNew = 0;
  703.     /**
  704.      * @var int
  705.      *
  706.      * @Column(name="calculated_qty_grade_a", type="integer", nullable=false)
  707.      */
  708.     private $calculatedQtyGradeA = 0;
  709.     /**
  710.      * @var int
  711.      *
  712.      * @Column(name="calculated_qty_grade_b", type="integer", nullable=false)
  713.      */
  714.     private $calculatedQtyGradeB = 0;
  715.     /**
  716.      * @var int
  717.      *
  718.      * @Column(name="calculated_qty_grade_c", type="integer", nullable=false)
  719.      */
  720.     private $calculatedQtyGradeC = 0;
  721.     /**
  722.      * @var int
  723.      *
  724.      * @Column(name="calculated_qty_grade_d", type="integer", nullable=false)
  725.      */
  726.     private $calculatedQtyGradeD = 0;
  727.     /**
  728.      * @var \DateTime
  729.      *
  730.      * @Column(name="calculated_qty_date", type="datetime", nullable=true)
  731.      */
  732.     private $lastQtySyncDate;
  733.     /**
  734.      * @var Collection
  735.      *
  736.      * @OneToMany(targetEntity="CustomerClaimProduct", mappedBy="product")
  737.      */
  738.     private $customerClaimProducts;
  739.     public function __construct()
  740.     {
  741.         parent::__construct();
  742.         $this->customerClaimProducts = new ArrayCollection();
  743.         $this->cacheItemLastUpdated = new \DateTime();
  744.         $this->productAttributes = new ArrayCollection();
  745.         $this->metas = new ArrayCollection();
  746.         $this->stockMovementItems = new ArrayCollection();
  747.         $this->productContainers = new ArrayCollection();
  748.         $this->childContainers = new ArrayCollection();
  749.         $this->tags = new ArrayCollection();
  750.         $this->priceLogEntries = new ArrayCollection();
  751.         $this->externalFeedNames = new ArrayCollection();
  752.         $this->coupons = new ArrayCollection();
  753.         $this->productVariations = new ArrayCollection();
  754.         $this->connectedProductModels = new ArrayCollection();
  755.         $this->alternativeProducts = new ArrayCollection();
  756.         $this->parentAlternativeProducts = new ArrayCollection();
  757.     }
  758.     /**
  759.      * @return ProductType
  760.      */
  761.     public function getType()
  762.     {
  763.         return $this->type ?? $this->productModel?->getType() ?? null;
  764.     }
  765.     /**
  766.      * @param ProductType $productType
  767.      */
  768.     public function setType($productType)
  769.     {
  770.         $this->type = $productType;
  771.     }
  772.     /**
  773.      * @return string
  774.      */
  775.     public function getName()
  776.     {
  777.         return $this->name;
  778.     }
  779.     /**
  780.      * @param string $name
  781.      */
  782.     public function setName($name)
  783.     {
  784.         $this->name = $name;
  785.     }
  786.     /**
  787.      * @return Collection
  788.      */
  789.     public function getProductAttributes()
  790.     {
  791.         return $this->productAttributes;
  792.     }
  793.     /**
  794.      * Add ProductAttribute
  795.      *
  796.      * @param ProductAttribute $prodAttribute
  797.      * @return ProductAttribute
  798.      */
  799.     public function addProductAttribute($prodAttribute)
  800.     {
  801.         if (!$this->productAttributes->contains($prodAttribute)) {
  802.             $this->productAttributes->add($prodAttribute);
  803.             $prodAttribute->setProduct($this);
  804.         }
  805.         return $this;
  806.     }
  807.     /**
  808.      * Remove ProductAttribute
  809.      *
  810.      * @param ProductAttribute $prodAttribute
  811.      * @return ProductAttribute
  812.      */
  813.     public function removeProductAttribute($prodAttribute)
  814.     {
  815.         $this->productAttributes->removeElement($prodAttribute);
  816.         return $this;
  817.     }
  818.     /**
  819.      * @param string $code
  820.      */
  821.     public function setCode($code)
  822.     {
  823.         $this->code = $code;
  824.     }
  825.     /**
  826.      * @return string
  827.      */
  828.     public function getCode()
  829.     {
  830.         return $this->code;
  831.     }
  832.     /**
  833.      * Get current price for given domain
  834.      *
  835.      * @param Domain $domain
  836.      * @return float
  837.      */
  838.     public function getCurrentPriceForDomain($domain)
  839.     {
  840.         $metaForDomain = $this->getDomainMeta($domain);
  841.         if (!$metaForDomain) {
  842.             return 0;
  843.         }
  844.         if ($metaForDomain->isDiscounted()) {
  845.             return $metaForDomain->getDomainDiscount();
  846.         }
  847.         return $metaForDomain->getDomainPrice();
  848.     }
  849.     /**
  850.      * Get current vat price for given domain
  851.      *
  852.      * @param Domain $domain
  853.      * @return float
  854.      */
  855.     public function getCurrentVatPriceForDomain($domain, $useDiscount = true)
  856.     {
  857.         $metaForDomain = $this->getDomainMeta($domain);
  858.         if (!$metaForDomain) {
  859.             return 0;
  860.         }
  861.         if ($metaForDomain->isDiscounted() && $useDiscount) {
  862.             return $metaForDomain->getDomainVatDiscount();
  863.         }
  864.         return $metaForDomain->getDomainVatPrice();
  865.     }
  866.     /**
  867.      * @param Domain $domain
  868.      * @param Customer $customer
  869.      * @param bool $showCurrency
  870.      * @return float
  871.      */
  872.     public function getCurrentRealPrice($domain, $customer, $showCurrency = false)
  873.     {
  874.         $metaForDomain = $this->getDomainMeta($domain);
  875.         if ($metaForDomain->isDiscounted()) {
  876.             if ($customer->getVatId() == '' || $customer->getVatId() == null) {
  877.                 $price = $metaForDomain->getDomainVatDiscount();
  878.             } else {
  879.                 $price = $metaForDomain->getDomainDiscount();
  880.             }
  881.         } else {
  882.             if ($customer->getVatId() == '' || $customer->getVatId() == null) {
  883.                 $price = $metaForDomain->getDomainVatPrice();
  884.             } else {
  885.                 $price = $metaForDomain->getDomainPrice();
  886.             }
  887.         }
  888.         if ($showCurrency) {
  889.             $price = $price . ' ' . $domain->getCurrency();
  890.         }
  891.         return $price;
  892.     }
  893.     /**
  894.      * @return Album
  895.      */
  896.     public function getAlbum()
  897.     {
  898.         return $this->album;
  899.     }
  900.     /**
  901.      * @param Album $album
  902.      */
  903.     public function setAlbum($album)
  904.     {
  905.         $this->album = $album;
  906.     }
  907.     /**
  908.      * @return Collection
  909.      */
  910.     public function getMetas()
  911.     {
  912.         $orderedMetas = [];
  913.         $metas = $this->metas;
  914.         foreach ($metas as $meta) {
  915.             $orderedMetas[$meta->getDomain()->getSortIndex() - 1] = $meta;
  916.         }
  917.         ksort($orderedMetas);
  918.         return $orderedMetas;
  919.     }
  920.     /**
  921.      * @param Domain $domain
  922.      * @return ProductMeta|bool
  923.      */
  924.     public function getDomainMeta($domain)
  925.     {
  926.         /**
  927.          * @var ProductMeta $meta
  928.          */
  929.         foreach ($this->getMetas() as $meta) {
  930.             if ($meta->getDomain()->getId() === $domain->getId()) {
  931.                 return $meta;
  932.             }
  933.         }
  934.         return false;
  935.     }
  936.     /**
  937.      * @param int $domainId
  938.      * @return ProductMeta|bool
  939.      */
  940.     public function getDomainMetaByDomainId($domainId)
  941.     {
  942.         /**
  943.          * @var ProductMeta $meta
  944.          */
  945.         foreach ($this->getMetas() as $meta) {
  946.             if ($meta->getDomain()->getId() === $domainId) {
  947.                 return $meta;
  948.             }
  949.         }
  950.         return false;
  951.     }
  952.     /**
  953.      * Add ProductMeta
  954.      *
  955.      * @param ProductMeta $meta
  956.      * @return Product
  957.      */
  958.     public function addMeta($meta)
  959.     {
  960.         if (!$this->metas->contains($meta)) {
  961.             $this->metas->add($meta);
  962.             $meta->setProduct($this);
  963.         }
  964.         return $this;
  965.     }
  966.     /**
  967.      * Remove ProductMeta
  968.      *
  969.      * @param ProductMeta $meta
  970.      * @return Product
  971.      */
  972.     public function removeMeta($meta)
  973.     {
  974.         $this->metas->removeElement($meta);
  975.         return $this;
  976.     }
  977.     /**
  978.      * @return string
  979.      */
  980.     public function getEan()
  981.     {
  982.         return $this->ean;
  983.     }
  984.     /**
  985.      * @param string $prefix
  986.      * @return string
  987.      */
  988.     public function getFormattedEan($prefix = 'FRB')
  989.     {
  990.         $validEanLength = 13;
  991.         $lengthWithPrefixAndCode = strlen($prefix . $this->code);
  992.         $zeroesLength = $validEanLength - $lengthWithPrefixAndCode;
  993.         $formattedEan = $prefix;
  994.         for ($i = 0; $i < $zeroesLength; $i++) {
  995.             $formattedEan .= '0';
  996.         }
  997.         $formattedEan .= $this->code;
  998.         return $formattedEan;
  999.     }
  1000.     /**
  1001.      * @param string $ean
  1002.      */
  1003.     public function setEan($ean)
  1004.     {
  1005.         $this->ean = $ean;
  1006.     }
  1007.     /**
  1008.      * @return string
  1009.      */
  1010.     public function getPartNumber()
  1011.     {
  1012.         return $this->partNumber;
  1013.     }
  1014.     /**
  1015.      * @param string $partNumber
  1016.      */
  1017.     public function setPartNumber($partNumber)
  1018.     {
  1019.         $this->partNumber = $partNumber;
  1020.     }
  1021.     /**
  1022.      * @return integer
  1023.      */
  1024.     public function getLength()
  1025.     {
  1026.         return $this->length;
  1027.     }
  1028.     /**
  1029.      * @param integer $length
  1030.      */
  1031.     public function setLength($length)
  1032.     {
  1033.         $this->length = $length;
  1034.     }
  1035.     /**
  1036.      * @return integer
  1037.      */
  1038.     public function getWidth()
  1039.     {
  1040.         return $this->width;
  1041.     }
  1042.     /**
  1043.      * @param integer $width
  1044.      */
  1045.     public function setWidth($width)
  1046.     {
  1047.         $this->width = $width;
  1048.     }
  1049.     /**
  1050.      * @return integer
  1051.      */
  1052.     public function getHeight()
  1053.     {
  1054.         return $this->height;
  1055.     }
  1056.     /**
  1057.      * @param integer $height
  1058.      */
  1059.     public function setHeight($height)
  1060.     {
  1061.         $this->height = $height;
  1062.     }
  1063.     /**
  1064.      * @return integer
  1065.      */
  1066.     public function getWeight()
  1067.     {
  1068.         return $this->weight;
  1069.     }
  1070.     /**
  1071.      * @param integer $weight
  1072.      */
  1073.     public function setWeight($weight)
  1074.     {
  1075.         $this->weight = $weight;
  1076.     }
  1077.     /**
  1078.      * @return integer
  1079.      */
  1080.     public function getSoldDuringTimeFrame()
  1081.     {
  1082.         return $this->soldDuringTimeFrame;
  1083.     }
  1084.     /**
  1085.      * @param integer $SoldDuringTimeFrame
  1086.      */
  1087.     public function setSoldDuringTimeFrame($soldDuringTimeFrame)
  1088.     {
  1089.         $this->soldDuringTimeFrame = $soldDuringTimeFrame;
  1090.     }
  1091.     /**
  1092.      * @return string
  1093.      */
  1094.     public function getUnit()
  1095.     {
  1096.         return $this->unit;
  1097.     }
  1098.     /**
  1099.      * @param string $unit
  1100.      */
  1101.     public function setUnit($unit)
  1102.     {
  1103.         if ($unit !== self::Unit_Pcs) {
  1104.             throw new \LogicException('Invalid Product Unit.');
  1105.         }
  1106.         $this->unit = $unit;
  1107.     }
  1108.     /**
  1109.      * @return boolean
  1110.      **/
  1111.     public function isAvailable()
  1112.     {
  1113.         if ($this->getAvailable() > 0 || $this->outOfStockStatus == self::OutOfStockStatus_VisibleShadow) {
  1114.             return true;
  1115.         }
  1116.         return false;
  1117.     }
  1118.     /**
  1119.      * @return bool
  1120.      */
  1121.     public function isReservable(): bool
  1122.     {
  1123.         if (in_array($this->outOfStockStatus, [self::OutOfStockStatus_VisibleOrderable5Days, self::OutOfStockStatus_VisibleOrderable10Days, self::OutOfStockStatus_VisibleOrderable15Days])) {
  1124.             return true;
  1125.         }
  1126.         return false;
  1127.     }
  1128.     /**
  1129.      * @return int
  1130.      **/
  1131.     public function getAvailable()
  1132.     {
  1133.         return $this->available;
  1134.     }
  1135.     /**
  1136.      * @param int $available
  1137.      */
  1138.     public function setAvailable($available)
  1139.     {
  1140.         $this->available = $available;
  1141.     }
  1142.     /**
  1143.      * @return int
  1144.      **/
  1145.     public function getLastQtyCalculatedForMarketplaces()
  1146.     {
  1147.         return $this->lastQtyCalculatedForMarketplaces;
  1148.     }
  1149.     /**
  1150.      * @param int $lastQtyCalculatedForMarketplaces
  1151.      */
  1152.     public function setLastQtyCalculatedForMarketplaces($lastQtyCalculatedForMarketplaces)
  1153.     {
  1154.         $this->lastQtyCalculatedForMarketplaces = $lastQtyCalculatedForMarketplaces;
  1155.     }
  1156.     /**
  1157.      * @return \DateTime
  1158.      */
  1159.     public function getItemLastUpdated()
  1160.     {
  1161.         return $this->cacheItemLastUpdated;
  1162.     }
  1163.     /**
  1164.      * @return Vendor
  1165.      */
  1166.     public function getVendor()
  1167.     {
  1168.         return $this->vendor ?? $this->productModel?->getVendor() ?? null;
  1169.     }
  1170.     /**
  1171.      * @param Vendor $vendor
  1172.      */
  1173.     public function setVendor($vendor)
  1174.     {
  1175.         $this->vendor = $vendor;
  1176.     }
  1177.     /**
  1178.      * @param TranslatorInterface|null $translator
  1179.      * @param bool $inverted
  1180.      * @return string
  1181.      */
  1182.     public function getFullTitle(TranslatorInterface $translator = null, $inverted = false)
  1183.     {
  1184.         $vendor = $this->vendor ? $this->vendor->getName() : $this->productModel->getVendor()->getName();
  1185.         $type = $this->type ? $this->type->getTitle($translator) : $this->productModel->getType()->getTitle($translator);
  1186.         if ($vendor !== 'VARIOUS' && $type !== 'OTHER' && $type !== 'Service') {
  1187.             return sprintf('%s %s %s', $type, $vendor, $this->getName());
  1188.         } else {
  1189.             if ($vendor == 'VARIOUS' && ($type == 'OTHER' || $type == 'Service')) {
  1190.                 return $this->getName();
  1191.             } elseif ($vendor !== 'VARIOUS' && ($type == 'OTHER' || $type == 'Service')) {
  1192.                 return sprintf('%s %s', $vendor, $this->getName());
  1193.             } elseif ($vendor == 'VARIOUS' && $type !== 'OTHER' && $type !== 'Service') {
  1194.                 return $inverted ? sprintf('%s %s', $this->getName(), $type) : sprintf('%s %s', $type, $this->getName());
  1195.             }
  1196.         }
  1197.     }
  1198.     /**
  1199.      * @param TranslatorInterface|null $translator
  1200.      * @param bool $inverted
  1201.      * @return string
  1202.      */
  1203.     public function getFullTitleLatestTable(TranslatorInterface $translator = null, $inverted = false)
  1204.     {
  1205.         $vendor = $this->vendor ? $this->vendor->getName() : $this->productModel->getVendor()->getName();
  1206.         $type = $this->type ? $this->type->getTitle($translator) : $this->productModel->getType()->getTitle($translator);
  1207.         if ($vendor !== 'VARIOUS' && $type !== 'OTHER' && $type !== 'Service') {
  1208.             return sprintf('%s %s %s', $type, $vendor, $this->getName());
  1209.         } else {
  1210.             if ($vendor == 'VARIOUS' && ($type == 'OTHER' || $type == 'Service')) {
  1211.                 return $this->getName();
  1212.             } elseif ($vendor !== 'VARIOUS' && ($type == 'OTHER' || $type == 'Service')) {
  1213.                 return sprintf('%s %s', $vendor, $this->getName());
  1214.             } elseif ($vendor == 'VARIOUS' && $type !== 'OTHER' && $type !== 'Service') {
  1215.                 return $inverted ? sprintf('%s', $this->getName()) : sprintf('%s', $this->getName());
  1216.             }
  1217.         }
  1218.     }
  1219.     public function getLongName($withStockStatus = true)
  1220.     {
  1221.         $values = [];
  1222.         $values[] = $this->getCode();
  1223.         $values[] = $this->getType()->getTitle();
  1224.         if ('VARIOUS' != $this->getVendor()->getName()) {
  1225.             $values[] = $this->getVendor()->getName();
  1226.         }
  1227.         $values[] = $this->getName();
  1228.         $desc = $this->getDescription();
  1229.         if ($desc != null) {
  1230.             $values[] = $desc;
  1231.         }
  1232.         if ($withStockStatus) {
  1233.             $values[] = '(' . $this->getAvailable() . '/' . $this->getInStock() . ')';
  1234.         }
  1235.         return implode(' - ', $values);
  1236.     }
  1237.     public function getLongName2() // Stock movements
  1238.     {
  1239.         $name = $this->getCode() . ' - ' . $this->getType()->getTitle();
  1240.         if ('VARIOUS' != $this->getVendor()->getName()) {
  1241.             $name .= ' ' . $this->getVendor()->getName();
  1242.         }
  1243.         $name .= ' ' . $this->getName();
  1244.         $desc = $this->getDescription();
  1245.         if ($desc != null) {
  1246.             $name .= ' - ' . $desc;
  1247.         }
  1248.         return $name;
  1249.     }
  1250.     private $pageFileName = [];
  1251.     /**
  1252.      * The result is cached after the first call. The extension is not cached, it's always appended.
  1253.      *
  1254.      * @param TranslatorInterface $translator
  1255.      * @param string $ext
  1256.      * @param $fromCache
  1257.      * @return string without php
  1258.      * @internal param array $translationArray
  1259.      */
  1260.     public function getPageFileName(TranslatorInterface $translator = null, $ext = '.php', $fromCache = true)
  1261.     {
  1262.         $transName = ($translator == null ? 'default' : $translator->getName());
  1263.         if (!isset($this->pageFileName[$transName]) || !$fromCache) {
  1264.             $type = preg_replace('/^\W+|\W+$/', '', TranslationHelper::ascii_convert($this->getType()->getTitle($translator)));
  1265.             $type = preg_replace('/\W+/', '-', $type);
  1266.             $name = preg_replace('/^\W+|\W+$/', '', TranslationHelper::ascii_convert($this->getName()));
  1267.             $name = preg_replace('/\W+/', '-', $name);
  1268.             $vendor = $this->getVendor()->getName();
  1269.             if ($vendor != 'UNKNOWN') {
  1270.                 $vendor = preg_replace('/^\W+|\W+$/', '', $this->getVendor()->getName());
  1271.                 $vendor = preg_replace('/\W+/', '-', $vendor);
  1272.                 $fileName = sprintf("%s-%s-%s-%d", $type, $vendor, $name, $this->getId());
  1273.             } else {
  1274.                 $fileName = sprintf("%s-%s-%d", $type, $name, $this->getId());
  1275.             }
  1276.             $fileName = strtolower($fileName);
  1277.             if ($fromCache) {
  1278.                 $this->pageFileName[$transName] = $fileName;
  1279.             } else {
  1280.                 return $fileName;
  1281.             }
  1282.         }
  1283.         return $this->pageFileName[$transName] . $ext;
  1284.     }
  1285.     /**
  1286.      * @param string $description
  1287.      */
  1288.     public function setDescription($description)
  1289.     {
  1290.         $this->cacheDescription = $description;
  1291.     }
  1292.     /**
  1293.      * @return string
  1294.      */
  1295.     public function getDescription()
  1296.     {
  1297.         return $this->cacheDescription;
  1298.     }
  1299.     public function getNonCoaDescription($domainId)
  1300.     {
  1301.         if ($domainId == 1 || $domainId == 3) {
  1302.             return str_replace([' | Win 7 Pro COA', ' | Win 7 Home COA'], ['', ''], $this->cacheDescription);
  1303.         }
  1304.         return $this->cacheDescription;
  1305.     }
  1306.     private $confProdAttr = null;
  1307.     /**
  1308.      * @param bool $fromCache
  1309.      * @return array
  1310.      */
  1311.     public function getConfigurationAttributes($fromCache = true)
  1312.     {
  1313.         if ($this->confProdAttr == null || !$fromCache) {
  1314.             $confProdAttr = [];
  1315.             /**
  1316.              * @var ProductAttribute $prodAttr
  1317.              */
  1318.             foreach ($this->productAttributes as $prodAttr) {
  1319.                 $attr = $prodAttr->getOption()->getAttribute();
  1320.                 if ($attr->isConfigurator()) {
  1321.                     $confProdAttr[] = $prodAttr;
  1322.                 }
  1323.             }
  1324.             uasort($confProdAttr, [$this, 'compareProductAttribute']);
  1325.             if ($fromCache) {
  1326.                 $this->confProdAttr = $confProdAttr;
  1327.             } else {
  1328.                 return $confProdAttr;
  1329.             }
  1330.         }
  1331.         return $this->confProdAttr;
  1332.     }
  1333.     /**
  1334.      * @param ProductAttribute $a
  1335.      * @param ProductAttribute $b
  1336.      * @return int
  1337.      */
  1338.     public function compareProductAttribute(ProductAttribute $a, ProductAttribute $b)
  1339.     {
  1340.         return $this->compareVariousAttributeOptions($a->getOption(), $b->getOption());
  1341.     }
  1342.     /**
  1343.      * @return bool
  1344.      */
  1345.     public function hasConfigurationAttributes()
  1346.     {
  1347.         return count($this->getConfigurationAttributes()) > 0;
  1348.     }
  1349.     private $confAttrOptions = null;
  1350.     /**
  1351.      * The result is cached after the first call.
  1352.      *
  1353.      * @param bool $fromCache
  1354.      * @return array
  1355.      */
  1356.     public function getConfigurationAttributeOptions($fromCache = true)
  1357.     {
  1358.         if ($this->confAttrOptions == null || !$fromCache) {
  1359.             $attrOptions = [];
  1360.             /**
  1361.              * @var ProductAttribute $prodAttr
  1362.              */
  1363.             foreach ($this->getConfigurationAttributes() as $prodAttr) {
  1364.                 if (!$prodAttr->isUsed()) {
  1365.                     $option = $prodAttr->getOption();
  1366.                     $attrOptions[$option->getId()] = $option;
  1367.                 }
  1368.             }
  1369.             //uasort($attrOptions, array($this, 'compareVariousAttributeOptions'));
  1370.             if ($fromCache) {
  1371.                 $this->confAttrOptions = $attrOptions;
  1372.             } else {
  1373.                 return $attrOptions;
  1374.             }
  1375.         }
  1376.         return $this->confAttrOptions;
  1377.     }
  1378.     /**
  1379.      * @return bool
  1380.      */
  1381.     public function hasConfigurationAttributeOptions()
  1382.     {
  1383.         return count($this->getConfigurationAttributeOptions()) > 0;
  1384.     }
  1385.     private $specAttrOptions = null;
  1386.     /**
  1387.      * The result is cached after the first call.
  1388.      *
  1389.      * @param bool $fromCache
  1390.      * @return array
  1391.      */
  1392.     public function getSpecificationAttributeOptions($fromCache = true)
  1393.     {
  1394.         if ($this->specAttrOptions == null || !$fromCache) {
  1395.             $attrOptions = [];
  1396.             /**
  1397.              * @var ProductAttribute $prodAttr
  1398.              */
  1399.             foreach ($this->productAttributes as $prodAttr) {
  1400.                 if ($prodAttr->getOption()->getAttribute()->getType() == 'conf') {
  1401.                     $option = $prodAttr->getOption();
  1402.                     $attrOptions[$option->getId()] = $option;
  1403.                 }
  1404.             }
  1405.             uasort($attrOptions, [$this, 'compareVariousAttributeOptions']);
  1406.             if ($fromCache) {
  1407.                 $this->specAttrOptions = $attrOptions;
  1408.             } else {
  1409.                 return $attrOptions;
  1410.             }
  1411.         }
  1412.         return $this->specAttrOptions;
  1413.     }
  1414.     private $specProductAttrOptions = null;
  1415.     /**
  1416.      * The result is cached after the first call.
  1417.      *
  1418.      * @param bool $fromCache
  1419.      * @return array
  1420.      */
  1421.     public function getSpecificationProductAttributeOptions($fromCache = true)
  1422.     {
  1423.         if ($this->specProductAttrOptions == null || !$fromCache) {
  1424.             $attrOptions = [];
  1425.             /**
  1426.              * @var ProductAttribute $prodAttr
  1427.              */
  1428.             foreach ($this->productAttributes as $prodAttr) {
  1429.                 if ($prodAttr->getOption()->getAttribute()->getType() == 'conf') {
  1430.                     $option = $prodAttr;
  1431.                     $attrOptions[$option->getId()] = $option;
  1432.                 }
  1433.             }
  1434.             uasort($attrOptions, [$this, 'compareVariousProductAttributeOptions']);
  1435.             if ($fromCache) {
  1436.                 $this->specProductAttrOptions = $attrOptions;
  1437.             } else {
  1438.                 return $attrOptions;
  1439.             }
  1440.         }
  1441.         return $this->specProductAttrOptions;
  1442.     }
  1443.     private $accAttrOptions = null;
  1444.     /**
  1445.      * The result is cached after the first call.
  1446.      *
  1447.      * @param bool $fromCache
  1448.      * @param bool $withAlwaysIncludedAttributes
  1449.      * @return array
  1450.      */
  1451.     public function getAccessoryAttributeOptions($fromCache = true, $withAlwaysIncludedAttributes = false)
  1452.     {
  1453.         if ($this->accAttrOptions == null || !$fromCache) {
  1454.             $attrOptions = [];
  1455.             /**
  1456.              * @var ProductAttribute $prodAttr
  1457.              */
  1458.             foreach ($this->productAttributes as $prodAttr) {
  1459.                 if (!$withAlwaysIncludedAttributes && $prodAttr->isAlways()) {
  1460.                     continue;
  1461.                 }
  1462.                 $option = $prodAttr->getOption();
  1463.                 if ($option->getAttribute()->isAccessory()) {
  1464.                     $attrOptions[$option->getId()] = $option;
  1465.                 }
  1466.             }
  1467.             uasort($attrOptions, [$this, 'compareVariousAttributeOptions']);
  1468.             if ($fromCache) {
  1469.                 $this->accAttrOptions = $attrOptions;
  1470.             } else {
  1471.                 return $attrOptions;
  1472.             }
  1473.         }
  1474.         return $this->accAttrOptions;
  1475.     }
  1476.     private $accProductAttrOptions = null;
  1477.     /**
  1478.      * The result is cached after the first call.
  1479.      *
  1480.      * @param bool $fromCache
  1481.      * @return array
  1482.      */
  1483.     public function getAccessoryProductAttributeOptions($fromCache = true)
  1484.     {
  1485.         if ($this->accProductAttrOptions == null || !$fromCache) {
  1486.             $attrOptions = [];
  1487.             /**
  1488.              * @var ProductAttribute $prodAttr
  1489.              */
  1490.             foreach ($this->productAttributes as $prodAttr) {
  1491.                 if ($prodAttr->getOption()->getAttribute()->isAccessory()) {
  1492.                     $attrOptions[$prodAttr->getId()] = $prodAttr;
  1493.                 }
  1494.             }
  1495.             uasort($attrOptions, [$this, 'compareVariousProductAttributeOptions']);
  1496.             if ($fromCache) {
  1497.                 $this->accProductAttrOptions = $attrOptions;
  1498.             } else {
  1499.                 return $attrOptions;
  1500.             }
  1501.         }
  1502.         return $this->accProductAttrOptions;
  1503.     }
  1504.     /**
  1505.      * @return bool
  1506.      */
  1507.     public function hasAccessoryAttributeOptions()
  1508.     {
  1509.         return count($this->getAccessoryAttributeOptions()) > 0;
  1510.     }
  1511.     /**
  1512.      * @param AttributeOption $a
  1513.      * @param AttributeOption $b
  1514.      * @return int
  1515.      */
  1516.     public static function compareVariousAttributeOptions(AttributeOption $a, AttributeOption $b)
  1517.     {
  1518.         $result = Collections::compare($a->getAttribute(), $b->getAttribute());
  1519.         if ($result == 0) {
  1520.             return Collections::compareGraph($a, $b);
  1521.         }
  1522.         return $result;
  1523.     }
  1524.     /**
  1525.      * @param ProductAttribute $a
  1526.      * @param ProductAttribute $b
  1527.      * @return int
  1528.      */
  1529.     public static function compareVariousProductAttributeOptions(ProductAttribute $a, ProductAttribute $b)
  1530.     {
  1531.         $result = Collections::compare($a->getOption()->getAttribute(), $b->getOption()->getAttribute());
  1532.         if ($result == 0) {
  1533.             return Collections::compareGraph($a->getOption(), $b->getOption());
  1534.         }
  1535.         return $result;
  1536.     }
  1537.     /**
  1538.      * @return int
  1539.      */
  1540.     public function getWarranty()
  1541.     {
  1542.         return $this->warranty;
  1543.     }
  1544.     /**
  1545.      * @param int $warranty
  1546.      */
  1547.     public function setWarranty($warranty)
  1548.     {
  1549.         $this->warranty = $warranty;
  1550.     }
  1551.     /**
  1552.      * @return array
  1553.      */
  1554.     public function getBadges()
  1555.     {
  1556.         if (!$this->isAvailable()) {
  1557.             return array_diff($this->badges, ['24h']);
  1558.         }
  1559.         return $this->badges;
  1560.     }
  1561.     /**
  1562.      * @param string $badges
  1563.      */
  1564.     public function setBadges($badges)
  1565.     {
  1566.         $this->badges = $badges;
  1567.     }
  1568.     /**
  1569.      * @param string $badge
  1570.      * @return void
  1571.      */
  1572.     public function addToBadgeList(string $badge): void
  1573.     {
  1574.         $badges = $this->badges;
  1575.         if (!$this->hasBadgeItem($badge)) {
  1576.             $badges[] = $badge;
  1577.             $this->setBadges($badges);
  1578.         }
  1579.     }
  1580.     /**
  1581.      * @param string $badge
  1582.      * @return boolean
  1583.      */
  1584.     public function hasBadgeItem(string $badge): bool
  1585.     {
  1586.         return in_array($badge, $this->getBadges());
  1587.     }
  1588.     public function removeBadgeItem(string $badge): void
  1589.     {
  1590.         $badges = $this->badges;
  1591.         $arrayKeyToRemove = null;
  1592.         foreach ($badges as $key => $value) {
  1593.             if ($value == $badge) {
  1594.                 $arrayKeyToRemove = $key;
  1595.                 break;
  1596.             }
  1597.         }
  1598.         if (!is_null($arrayKeyToRemove)) {
  1599.             unset($badges[$arrayKeyToRemove]);
  1600.             $this->setBadges($badges);
  1601.         }
  1602.     }
  1603.     /**
  1604.      * @return string
  1605.      */
  1606.     public function getDetail()
  1607.     {
  1608.         return $this->detail;
  1609.     }
  1610.     /**
  1611.      * @param string $detail
  1612.      */
  1613.     public function setDetail($detail)
  1614.     {
  1615.         $this->detail = $detail;
  1616.     }
  1617.     public function getFormatDetail()
  1618.     {
  1619.         return self::createFormatedDetail($this->detail);
  1620.     }
  1621.     /**
  1622.      * @return string|null
  1623.      */
  1624.     public function getStockPosition(): ?string
  1625.     {
  1626.         return $this->stockPosition;
  1627.     }
  1628.     /**
  1629.      * @param string|null $stockPosition
  1630.      */
  1631.     public function setStockPosition(?string $stockPosition)
  1632.     {
  1633.         if (is_null($stockPosition)) {
  1634.             $this->stockPosition = null;
  1635.         } else {
  1636.             $this->stockPosition = mb_substr($stockPosition, 0, 96);
  1637.         }
  1638.     }
  1639.     /**
  1640.      * @return string
  1641.      */
  1642.     public function getOmegaPlu()
  1643.     {
  1644.         return $this->omegaPlu;
  1645.     }
  1646.     /**
  1647.      * @param string $omegaPlu
  1648.      */
  1649.     public function setOmegaPlu($omegaPlu)
  1650.     {
  1651.         $this->omegaPlu = $omegaPlu;
  1652.     }
  1653.     /**
  1654.      * Initialize cache fields used at display. Cached values are stored in database.
  1655.      * You have to call this method whenever the product or product depending object change.
  1656.      */
  1657.     public function initCacheFields()
  1658.     {
  1659.         //sort description
  1660.         $separator = ' | ';
  1661.         $desc = '';
  1662.         /**
  1663.          * Clear cache
  1664.          * @var AttributeOption $option
  1665.          */
  1666.         foreach ($this->getSpecificationAttributeOptions(false) as $option) {
  1667.             if ($option->isInShortDesc()) {
  1668.                 if ($desc !== '') {
  1669.                     $desc .= $separator;
  1670.                 }
  1671.                 /**
  1672.                  * if HDD, SSD, SSHD show attribute title after option title
  1673.                  */
  1674.                 if (in_array($option->getAttribute()->getId(), [5, 6, 7, 8, 9, 166])) {
  1675.                     $desc .= $option->getTitle() . ' ' . $option->getAttribute()->getTitle();
  1676.                 } else {
  1677.                     $desc .= $option->getTitle();
  1678.                 }
  1679.             }
  1680.         }
  1681.         $this->cacheDescription = $desc;
  1682.     }
  1683.     /**
  1684.      * @return boolean
  1685.      */
  1686.     public function isShadow()
  1687.     {
  1688.         if ($this->outOfStockStatus === self::OutOfStockStatus_VisibleShadow) {
  1689.             return true;
  1690.         } else {
  1691.             return false;
  1692.         }
  1693.     }
  1694.     /**
  1695.      * @return int
  1696.      */
  1697.     public function getQualityStatus()
  1698.     {
  1699.         return $this->qualityStatus;
  1700.     }
  1701.     /**
  1702.      * @param int $qualityStatus
  1703.      */
  1704.     public function setQualityStatus($qualityStatus)
  1705.     {
  1706.         $this->qualityStatus = $qualityStatus;
  1707.     }
  1708.     /**
  1709.      * @param $id
  1710.      * @param TranslatorInterface $translator
  1711.      * @return int
  1712.      */
  1713.     public function getQualityStatusTitle(?int $id = null, TranslatorInterface $translator = null)
  1714.     {
  1715.         if (is_null($id)) {
  1716.             $id = $this->qualityStatus;
  1717.         }
  1718.         if (!is_null($translator)) {
  1719.             return $translator->trans(self::getQualityStatusChoices()[$id]);
  1720.         }
  1721.         return self::getQualityStatusChoices()[$id];
  1722.     }
  1723.     /**
  1724.      * @param string $detail
  1725.      * @return string
  1726.      */
  1727.     public static function createFormatedDetail($detail)
  1728.     {
  1729.         $result = '';
  1730.         $lines = preg_split('/\\n\\r*/', $detail);
  1731.         if (count($lines) > 0) {
  1732.             $result .= '<div class="detail">';
  1733.         }
  1734.         $is_list = false;
  1735.         foreach ($lines as $line) {
  1736.             $line = trim($line);
  1737.             $line = str_replace('[b]', '<strong>', $line);
  1738.             $line = str_replace('[/b]', '</strong>', $line);
  1739.             $line = str_replace('[bl]', '<span class="blue-text">', $line);
  1740.             $line = str_replace('[/bl]', '</span>', $line);
  1741.             $line = str_replace('[r]', '<span class="red-text">', $line);
  1742.             $line = str_replace('[/r]', '</span>', $line);
  1743.             if ($line == '') {
  1744.                 $result .= '<br>';
  1745.             } elseif ($line == '[l]' && !$is_list) {
  1746.                 $result .= '<dl>';
  1747.                 $is_list = true;
  1748.             } elseif ($line == '[/l]' && $is_list) {
  1749.                 $result .= '</dl>';
  1750.                 $is_list = false;
  1751.             } elseif ($is_list) {
  1752.                 $result .= '<dt>' . $line . '</dt>';
  1753.             } else {
  1754.                 $result .= '<p>' . $line . '</p>';
  1755.             }
  1756.         }
  1757.         if (count($lines) > 0) {
  1758.             $result .= '</div>';
  1759.         }
  1760.         return $result;
  1761.     }
  1762.     /**
  1763.      * @param AttributeOption $attributeOption
  1764.      *
  1765.      * @return bool
  1766.      */
  1767.     public function hasAttributeOption($attributeOption)
  1768.     {
  1769.         /**
  1770.          * @var AttributeOption $attr
  1771.          */
  1772.         foreach ($this->getSpecificationAttributeOptions() as $attr) {
  1773.             if ($attr->getId() == $attributeOption->getId()) {
  1774.                 return true;
  1775.             }
  1776.             if ($attr->hasParent() && $attr->getParent()->getId() == $attributeOption->getId()) {
  1777.                 return true;
  1778.             }
  1779.         }
  1780.         return false;
  1781.     }
  1782.     /**
  1783.      * @return int
  1784.      */
  1785.     public function getOutOfStockStatus()
  1786.     {
  1787.         return $this->outOfStockStatus;
  1788.     }
  1789.     /**
  1790.      * @param int $outOfStockStatus
  1791.      */
  1792.     public function setOutOfStockStatus($outOfStockStatus)
  1793.     {
  1794.         $this->outOfStockStatus = $outOfStockStatus;
  1795.     }
  1796.     /**
  1797.      * @param $id
  1798.      * @return int
  1799.      */
  1800.     public function getOutOfStockStatusTitle($id)
  1801.     {
  1802.         return self::getStockStatusChoices()[$id];
  1803.     }
  1804.     /**
  1805.      * @param null $dimension*
  1806.      * @param null $unit
  1807.      * Possible units for dimensions: g, dkg, kg, t,
  1808.      * Possible units for weight: mm, cm, dm, m
  1809.      * @param bool $includeUnitInName
  1810.      * @return null|string
  1811.      */
  1812.     public function dimensionInUnit($dimension = null, $unit = null, $includeUnitInName = false)
  1813.     {
  1814.         if ($dimension != null && $unit != null) {
  1815.             switch ($unit) {
  1816.                 case 'g':
  1817.                     $result = $dimension;
  1818.                     break;
  1819.                 case 'dkg':
  1820.                     $result = $dimension / 100;
  1821.                     break;
  1822.                 case 'kg':
  1823.                     $result = $dimension / 1000;
  1824.                     break;
  1825.                 case 't':
  1826.                     $result = $dimension / 10000;
  1827.                     break;
  1828.                 case 'mm':
  1829.                     $result = $dimension;
  1830.                     break;
  1831.                 case 'cm':
  1832.                     $result = $dimension / 10;
  1833.                     break;
  1834.                 case 'dm':
  1835.                     $result = $dimension / 100;
  1836.                     break;
  1837.                 case 'm':
  1838.                     $result = $dimension / 1000;
  1839.                     break;
  1840.                 default:
  1841.                     return null;
  1842.             }
  1843.             if ($includeUnitInName) {
  1844.                 return $result . ' ' . $unit;
  1845.             } else {
  1846.                 return $result;
  1847.             }
  1848.         } else {
  1849.             return null;
  1850.         }
  1851.     }
  1852.     /**
  1853.      * Returns length dimensions in given unit
  1854.      *
  1855.      * @param null $unit
  1856.      * @param bool $includeUnitInName
  1857.      * @return null|string
  1858.      */
  1859.     public function dimensions($unit = null, $includeUnitInName = false)
  1860.     {
  1861.         $dimensions = '';
  1862.         if ($unit != null) {
  1863.             if ($this->getLength() != 0) {
  1864.                 $dimensions .= $this->dimensionInUnit($this->getLength(), $unit, $includeUnitInName);
  1865.             }
  1866.             if ($this->getWidth() != 0) {
  1867.                 if ($dimensions != '') {
  1868.                     $dimensions .= ' x ';
  1869.                 }
  1870.                 $dimensions .= $this->dimensionInUnit($this->getWidth(), $unit, $includeUnitInName);
  1871.             }
  1872.             if ($this->getLength() != 0) {
  1873.                 if ($dimensions != '') {
  1874.                     $dimensions .= ' x ';
  1875.                 }
  1876.                 $dimensions .= $this->dimensionInUnit($this->getHeight(), $unit, $includeUnitInName);
  1877.             }
  1878.             if ($dimensions != '') {
  1879.                 return $dimensions;
  1880.             } else {
  1881.                 return null;
  1882.             }
  1883.         } else {
  1884.             return null;
  1885.         }
  1886.     }
  1887.     /**
  1888.      * IF substract sold commission parameter is true, substract commissions with status sold and defined invoice nubmer
  1889.      * else return full number of commissions
  1890.      *
  1891.      * @param bool $subtractReturnedCommissions
  1892.      * @return Collection
  1893.      * @internal param bool $subtractSoldCommissions
  1894.      * @internal param bool $subtractSoldCommissions
  1895.      */
  1896.     public function getCommissions($subtractReturnedCommissions = true)
  1897.     {
  1898.         if ($subtractReturnedCommissions) {
  1899.             $notSoldCommissions = new ArrayCollection();
  1900.             if (!is_null($this->commissions) && $this->commissions->count() > 0) {
  1901.                 foreach ($this->commissions as $commission) {
  1902.                     if (
  1903.                         $commission->getStatus() == ProductCommission::Status_AtPartner
  1904.                         || ($commission->getStatus() == ProductCommission::Status_Sold && ($commission->getInvoiceNumber() == '' || $commission->getInvoiceNumber() == null))
  1905.                     ) {
  1906.                         $notSoldCommissions->add($commission);
  1907.                     }
  1908.                 }
  1909.             }
  1910.             return $notSoldCommissions;
  1911.         } else {
  1912.             return $this->commissions;
  1913.         }
  1914.     }
  1915.     /**
  1916.      * @return int
  1917.      */
  1918.     public function getCommissionCount()
  1919.     {
  1920.         $commissions = 0;
  1921.         if ($this->getCommissions() !== null) {
  1922.             $commissions = $this->getCommissions()->count();
  1923.         }
  1924.         return $commissions;
  1925.     }
  1926.     /**
  1927.      * @param \DateTime|null $dateSince
  1928.      * @return Collection
  1929.      */
  1930.     public function getOrderItems(?\DateTime $dateSince = null)
  1931.     {
  1932.         if (!is_null($this->orderItems) && !is_null($dateSince)) {
  1933.             $criteria = Criteria::create();
  1934.             $criteria->where(Criteria::expr()->gt('created', $dateSince));
  1935.             return $this->orderItems->matching($criteria);
  1936.         } else {
  1937.             return $this->orderItems;
  1938.         }
  1939.     }
  1940.     /**
  1941.      * @return Collection
  1942.      */
  1943.     public function getReservations()
  1944.     {
  1945.         $this->reservations = new ArrayCollection();
  1946.         $reservationsSince = (new \DateTime())->setDate(2016, 12, 2)->setTime(0, 0);
  1947.         $orderItems = $this->getOrderItems($reservationsSince);
  1948.         if (!is_null($orderItems)) {
  1949.             foreach ($orderItems as $orderItem) {
  1950.                 $order = $orderItem->getOrder();
  1951.                 if (
  1952.                     (is_null($order->getInvoiceCode()) || $order->getInvoiceCode() == '')
  1953.                     && (!is_null($order->getLastStockMovement()) && $order->getLastStockMovement()->getType() != StockMovement::TYPE_OUT)
  1954.                 ) {
  1955.                     $this->reservations->add($orderItem);
  1956.                 }
  1957.             }
  1958.         }
  1959.         return $this->reservations;
  1960.     }
  1961.     /**
  1962.      * @return int
  1963.      */
  1964.     public function getReservationsCount()
  1965.     {
  1966.         $reservationCount = 0;
  1967.         foreach ($this->getReservations() as $reservation) {
  1968.             $reservationCount += $reservation->getQuantity();
  1969.         }
  1970.         return $reservationCount;
  1971.     }
  1972.     /**
  1973.      * @return Collection
  1974.      */
  1975.     public function getSold()
  1976.     {
  1977.         $sold = new ArrayCollection();
  1978.         $soldSince = (new \DateTime())->setDate(2016, 12, 2)->setTime(0, 0);
  1979.         $orderItems = $this->getOrderItems($soldSince);
  1980.         if (!is_null($orderItems)) {
  1981.             foreach ($orderItems as $orderItem) {
  1982.                 $order = $orderItem->getOrder();
  1983.                 if (!is_null($order->getLastStockMovement()) && $order->getLastStockMovement()->getType() == StockMovement::TYPE_OUT) {
  1984.                     $sold->add($orderItem);
  1985.                 }
  1986.             }
  1987.         }
  1988.         return $sold;
  1989.     }
  1990.     /**
  1991.      * @return int
  1992.      */
  1993.     public function getSoldCount()
  1994.     {
  1995.         $soldCount = 0;
  1996.         foreach ($this->getSold() as $sold) {
  1997.             $soldCount += $sold->getQuantity();
  1998.         }
  1999.         return $soldCount;
  2000.     }
  2001.     public function isShipping()
  2002.     {
  2003.         return self::SHIPPING_ID == $this->getId();
  2004.     }
  2005.     /**
  2006.      * @return int
  2007.      */
  2008.     public function getInStock()
  2009.     {
  2010.         return $this->inStock;
  2011.     }
  2012.     /**
  2013.      * @param int $inStock
  2014.      */
  2015.     public function setInStock($inStock)
  2016.     {
  2017.         $this->inStock = $inStock;
  2018.     }
  2019.     /**
  2020.      * @return boolean
  2021.      */
  2022.     public function isArchived()
  2023.     {
  2024.         return $this->archived;
  2025.     }
  2026.     /**
  2027.      * @param boolean $archived
  2028.      */
  2029.     public function setArchived($archived)
  2030.     {
  2031.         $this->archived = $archived;
  2032.     }
  2033.     /**
  2034.      * @return boolean
  2035.      */
  2036.     public function isScannable()
  2037.     {
  2038.         return $this->scannable;
  2039.     }
  2040.     public function isScannableWithType()
  2041.     {
  2042.         $isTypeScannable = $this->type ? $this->type->isScannable() : $this->productModel->getType()->isScannable();
  2043.         return $this->scannable && $isTypeScannable;
  2044.     }
  2045.     /**
  2046.      * @param boolean $scannable
  2047.      */
  2048.     public function setScannable($scannable)
  2049.     {
  2050.         $this->scannable = $scannable;
  2051.     }
  2052.     /**
  2053.      * @return Collection
  2054.      */
  2055.     public function getStockMovementItems()
  2056.     {
  2057.         return $this->stockMovementItems;
  2058.     }
  2059.     /**
  2060.      * @return StockMovementItem|null
  2061.      */
  2062.     public function getLastStockMovementItem()
  2063.     {
  2064.         $stockMovementItems = $this->getStockMovementItems();
  2065.         return $stockMovementItems->count() > 0 ? $stockMovementItems->first() : null;
  2066.     }
  2067.     /**
  2068.      * @return Collection
  2069.      */
  2070.     public function getProductVariations()
  2071.     {
  2072.         return $this->productVariations;
  2073.     }
  2074.     /**
  2075.      * @return boolean
  2076.      */
  2077.     public function isContainer()
  2078.     {
  2079.         return $this->container;
  2080.     }
  2081.     /**
  2082.      * @param boolean $container
  2083.      */
  2084.     public function setContainer($container)
  2085.     {
  2086.         $this->container = $container;
  2087.     }
  2088.     /**
  2089.      * @return Collection
  2090.      */
  2091.     public function getProductContainers()
  2092.     {
  2093.         return $this->productContainers;
  2094.     }
  2095.     /**
  2096.      * @return Collection
  2097.      */
  2098.     public function getChildContainers()
  2099.     {
  2100.         return $this->childContainers;
  2101.     }
  2102.     /**
  2103.      * @param Collection $productContainers
  2104.      */
  2105.     public function setProductContainers($productContainers)
  2106.     {
  2107.         $this->productContainers = $productContainers;
  2108.     }
  2109.     /**
  2110.      * @return float
  2111.      */
  2112.     public function getLastPrice()
  2113.     {
  2114.         return $this->lastPrice;
  2115.     }
  2116.     /**
  2117.      * @param float $lastPrice
  2118.      */
  2119.     public function setLastPrice($lastPrice)
  2120.     {
  2121.         $this->lastPrice = $lastPrice;
  2122.     }
  2123.     /**
  2124.      * @return float
  2125.      */
  2126.     public function getAvgPrice()
  2127.     {
  2128.         return $this->avgPrice;
  2129.     }
  2130.     /**
  2131.      * @param float $avgPrice
  2132.      */
  2133.     public function setAvgPrice($avgPrice)
  2134.     {
  2135.         $this->avgPrice = $avgPrice;
  2136.     }
  2137.     /**
  2138.      * @return Collection
  2139.      */
  2140.     public function getCategoryPages()
  2141.     {
  2142.         return $this->categoryPages;
  2143.     }
  2144.     /**
  2145.      * @param Collection $categoryPages
  2146.      */
  2147.     public function setCategoryPages($categoryPages)
  2148.     {
  2149.         $this->categoryPages = $categoryPages;
  2150.     }
  2151.     /**
  2152.      * @return string
  2153.      */
  2154.     public function getGtin()
  2155.     {
  2156.         return $this->gtin;
  2157.     }
  2158.     /**
  2159.      * @param string $gtin
  2160.      */
  2161.     public function setGtin($gtin)
  2162.     {
  2163.         $this->gtin = $gtin;
  2164.     }
  2165.     /**
  2166.      * @return string
  2167.      */
  2168.     public function getAmazonCode()
  2169.     {
  2170.         return $this->amazonCode;
  2171.     }
  2172.     /**
  2173.      * @param string $amazonCode
  2174.      */
  2175.     public function setAmazonCode($amazonCode)
  2176.     {
  2177.         $this->amazonCode = $amazonCode;
  2178.     }
  2179.     /**
  2180.      * @param ProductTag $tag
  2181.      *
  2182.      * @return Product
  2183.      */
  2184.     public function addTag(ProductTag $tag): Product
  2185.     {
  2186.         $this->tags[] = $tag;
  2187.         return $this;
  2188.     }
  2189.     /**
  2190.      * @param ProductTag $tag
  2191.      *
  2192.      * @return boolean
  2193.      */
  2194.     public function removeTag(ProductTag $tag): bool
  2195.     {
  2196.         return $this->tags->removeElement($tag);
  2197.     }
  2198.     /**
  2199.      * @return Collection
  2200.      */
  2201.     public function getTags()
  2202.     {
  2203.         return $this->tags;
  2204.     }
  2205.     /**
  2206.      * @return Collection
  2207.      */
  2208.     public function getNotifications()
  2209.     {
  2210.         return $this->notifications;
  2211.     }
  2212.     public function getPriceLogs()
  2213.     {
  2214.         return $this->priceLogEntries;
  2215.     }
  2216.     /**
  2217.      * @return \DateTime|null
  2218.      */
  2219.     public function getLastSale(): ?\DateTime
  2220.     {
  2221.         return $this->lastSale;
  2222.     }
  2223.     /**
  2224.      * @param \DateTime|null $lastSale
  2225.      */
  2226.     public function setLastSale(?\DateTime $lastSale)
  2227.     {
  2228.         $this->lastSale = $lastSale;
  2229.     }
  2230.     /**
  2231.      * @param ProductExternalFeedName $externalFeedName
  2232.      */
  2233.     public function addExternalFeedName(ProductExternalFeedName $externalFeedName): void
  2234.     {
  2235.         $this->externalFeedNames[] = $externalFeedName;
  2236.     }
  2237.     /**
  2238.      * @param ProductExternalFeedName $externalFeedName
  2239.      */
  2240.     public function removeExternalFeedName(ProductExternalFeedName $externalFeedName): bool
  2241.     {
  2242.         return $this->externalFeedNames->removeElement($externalFeedName);
  2243.     }
  2244.     /**
  2245.      * @return Collection
  2246.      */
  2247.     public function getExternalFeedNames(): Collection
  2248.     {
  2249.         return $this->externalFeedNames;
  2250.     }
  2251.     /**
  2252.      * @return ?ProductExternalFeedName
  2253.      */
  2254.     public function getExternalFeedNameByLanguage(Language $language)
  2255.     {
  2256.         return $this->externalFeedNames->filter(
  2257.             function (ProductExternalFeedName $feedName) use ($language) {
  2258.                 return $feedName->getLanguage() == $language;
  2259.             }
  2260.         )->first();
  2261.     }
  2262.     /**
  2263.      * @return bool
  2264.      */
  2265.     public function containerHasMainProduct(): bool
  2266.     {
  2267.         if ($this->isContainer()) {
  2268.             foreach ($this->getProductContainers() as $productContainer) {
  2269.                 if ($productContainer->getChild() && in_array($productContainer->getProduct()->getType()->getId(), [44, 52, 60])) { // Monitor, Notebook, PC
  2270.                     return true;
  2271.                 }
  2272.             }
  2273.         }
  2274.         return false;
  2275.     }
  2276.     /**
  2277.      * @return bool
  2278.      */
  2279.     public function isMainProduct(): bool
  2280.     {
  2281.         return in_array($this->getType()->getId(), ProductType::getMainProductTypeIds());
  2282.     }
  2283.     /**
  2284.      * @param StockMovementItem $stockMovementItem
  2285.      * @return float
  2286.      */
  2287.     public function getLastPurchasePrice(StockMovementItem $stockMovementItem): float
  2288.     {
  2289.         foreach ($this->stockMovementItems as $index => $movementItem) {
  2290.             if ($movementItem->getId() == $stockMovementItem->getId()) {
  2291.                 // Increase
  2292.                 $increaseWith = 1;
  2293.                 do {
  2294.                     // Previous Stock Movement Item
  2295.                     $previousStockMovementItem = $this->stockMovementItems->get(($index + $increaseWith));
  2296.                     if ($previousStockMovementItem) {
  2297.                         // Need a In Stock Movement
  2298.                         $stockMovement = $previousStockMovementItem->getMovement();
  2299.                         if ($stockMovement->getType() == StockMovement::TYPE_IN) {
  2300.                             // Exchange Currency
  2301.                             $exchangeCurrency = $stockMovement->getMerchant()->getDomain()->getCurrencyTextCode();
  2302.                             // Exchange Rate
  2303.                             $exchangeRate = 1;
  2304.                             if ($exchangeCurrency !== 'EUR') {
  2305.                                 $exchangeRate = (float)$stockMovement->getExchangeRate();
  2306.                             }
  2307.                             if ((float)$exchangeRate <= 0) {
  2308.                                 $exchangeRate = 1;
  2309.                             }
  2310.                             // Converted Price
  2311.                             return round(($previousStockMovementItem->getTotalPricePerItem() / $exchangeRate), 2);
  2312.                         }
  2313.                     }
  2314.                     // Increase
  2315.                     $increaseWith++;
  2316.                 } while ($previousStockMovementItem);
  2317.             }
  2318.         }
  2319.         return .0;
  2320.     }
  2321.     /**
  2322.      * @param StockMovementItem $stockMovementItem
  2323.      * @return array
  2324.      */
  2325.     public function getLastPurchasePriceWithCurrency(StockMovementItem $stockMovementItem): array
  2326.     {
  2327.         foreach ($this->stockMovementItems as $index => $movementItem) {
  2328.             if ($movementItem->getId() == $stockMovementItem->getId()) {
  2329.                 // Increase
  2330.                 $increaseWith = 1;
  2331.                 do {
  2332.                     // Previous Stock Movement Item
  2333.                     $previousStockMovementItem = $this->stockMovementItems->get(($index + $increaseWith));
  2334.                     if ($previousStockMovementItem) {
  2335.                         // Need a In Stock Movement
  2336.                         $stockMovement = $previousStockMovementItem->getMovement();
  2337.                         if ($stockMovement->getType() == StockMovement::TYPE_IN) {
  2338.                             return [
  2339.                                 'currency' => $stockMovement->getMerchant()->getDomain()->getCurrencyTextCode(),
  2340.                                 'value' => $previousStockMovementItem->getTotalPricePerItem(),
  2341.                             ];
  2342.                         }
  2343.                     }
  2344.                     // Increase
  2345.                     $increaseWith++;
  2346.                 } while ($previousStockMovementItem);
  2347.             }
  2348.         }
  2349.         return [];
  2350.     }
  2351.     /**
  2352.      * @return int[]
  2353.      */
  2354.     public static function getExcludededProductIdsFromUpdate(): array
  2355.     {
  2356.         return [
  2357.             Product::SHIPPING_ID,
  2358.             Product::CASH_ON_DELIVERY_PRODUCT_ID,
  2359.             Product::CABLE_POWER_PRODUCT_ID,
  2360.             Product::MPL_PACKAGE_FEE_PRODUCT_ID,
  2361.         ];
  2362.     }
  2363.     /**
  2364.      * @return int[]
  2365.      */
  2366.     public static function getExcludededProductTypeIdsFromUpdate(): array
  2367.     {
  2368.         return [
  2369.             ProductType::PRODUCT_TYPE_ID_SERVICE,
  2370.         ];
  2371.     }
  2372.     /**
  2373.      * @return Collection
  2374.      */
  2375.     public function getPopularProductsCategoryPages(): Collection
  2376.     {
  2377.         return $this->popularProductsCategoryPages;
  2378.     }
  2379.     /**
  2380.      * @param Collection $popularProductsCategoryPages
  2381.      */
  2382.     public function setPopularProductsCategoryPages(Collection $popularProductsCategoryPages): void
  2383.     {
  2384.         $this->popularProductsCategoryPages = $popularProductsCategoryPages;
  2385.     }
  2386.     /**
  2387.      * @return bool
  2388.      */
  2389.     public function isInQuarantine(): bool
  2390.     {
  2391.         return (mb_strpos($this->name, 'QUARANTINE @') !== false ? true : false);
  2392.     }
  2393.     /**
  2394.      * @return boolean
  2395.      */
  2396.     public function isUltrabook(): bool
  2397.     {
  2398.         if ($this->getWeight() > 1500 || $this->getWeight() == 0) {
  2399.             return false;
  2400.         }
  2401.         if ($this->getHeight() > 20 || $this->getHeight() == 0) {
  2402.             return false;
  2403.         }
  2404.         if (str_contains(strtolower($this->name), 'chromebook')) {
  2405.             return false;
  2406.         }
  2407.         $hasIntelCoreProcessor = $hasSSDAttribute = false;
  2408.         /**
  2409.          * @var ProductAttribute $productAttribute
  2410.          */
  2411.         foreach ($this->getConfigurationAttributes() as $productAttribute) {
  2412.             if (str_contains(strtolower($productAttribute->getOption()->getTitle()), 'intel core')) {
  2413.                 $hasIntelCoreProcessor = true;
  2414.             }
  2415.             if ($productAttribute->getOption()->getAttribute()->getId() == Attribute::ATTRIBUTE_ID_SSD) {
  2416.                 $hasSSDAttribute = true;
  2417.             }
  2418.             if ($hasIntelCoreProcessor && $hasSSDAttribute) {
  2419.                 return true;
  2420.             }
  2421.         }
  2422.         return $hasIntelCoreProcessor && $hasSSDAttribute;
  2423.     }
  2424.     /**
  2425.      * @return boolean
  2426.      */
  2427.     public function isWindows11Compatible(): bool
  2428.     {
  2429.         if (!in_array($this->type->getId(), ProductType::getWindows11CompatibleList())) {
  2430.             return false;
  2431.         }
  2432.         if (in_array('ChromeBook', $this->badges) || str_contains(strtolower($this->getFullTitle()), 'chromebook')) {
  2433.             return false;
  2434.         }
  2435.         if ($this->getVendor()->getName() == 'Apple') {
  2436.             return false;
  2437.         }
  2438.         /**
  2439.          * @var ProductAttribute $productAttribute
  2440.          */
  2441.         foreach ($this->getConfigurationAttributes() as $productAttribute) {
  2442.             if ($productAttribute->getOption()->getAttribute()->getId() == Attribute::ATTRIBUTE_ID_CPU_GENERATION) {
  2443.                 $selectedOption = $productAttribute->getOption();
  2444.                 $cpuGenerationNumber = (int) str_replace('. Generation', '', $selectedOption->getTitle());
  2445.                 return $cpuGenerationNumber >= 8;
  2446.             }
  2447.             // AMD Processors - https://docs.google.com/spreadsheets/d/1j2CfMFTS19YoPzrD06n3PWQpK_EfJXZKArypPwVQT-w/edit#gid=2081660312
  2448.             if (in_array($productAttribute->getOption()->getId(), [5276, 5301, 5092, 5094, 5228, 4829, 4830, 4906, 4215, 4228, 4397, 3988, 2682, 2734, 2321, 2323, 2513, 2211])) {
  2449.                 return true;
  2450.             }
  2451.         }
  2452.         return false;
  2453.     }
  2454.     /**
  2455.      * @return bool
  2456.      */
  2457.     public function isTinyPC(): bool
  2458.     {
  2459.         return $this->hasBadgeItem(self::PRODUCT_BADGE_TINY_PC);
  2460.     }
  2461.     /**
  2462.      * @return int
  2463.      */
  2464.     public function getCpuMark(): int
  2465.     {
  2466.         return $this->cpuMark;
  2467.     }
  2468.     /**
  2469.      * @param int $cpuMark
  2470.      * @return void
  2471.      */
  2472.     public function setCpuMark(int $cpuMark): void
  2473.     {
  2474.         $this->cpuMark = $cpuMark;
  2475.     }
  2476.     /**
  2477.      * @return ProductModel|null
  2478.      */
  2479.     public function getProductModel(): ?ProductModel
  2480.     {
  2481.         return $this->productModel;
  2482.     }
  2483.     /**
  2484.      * @param ProductModel|null $productModel
  2485.      * @return void
  2486.      */
  2487.     public function setProductModel(?ProductModel $productModel): void
  2488.     {
  2489.         $this->productModel = $productModel;
  2490.     }
  2491.     /**
  2492.      * @return bool
  2493.      */
  2494.     public function isSparePartCard(): bool
  2495.     {
  2496.         return $this->sparePartCard;
  2497.     }
  2498.     /**
  2499.      * @param bool $sparePartCard
  2500.      * @return void
  2501.      */
  2502.     public function setSparePartCard(bool $sparePartCard): void
  2503.     {
  2504.         $this->sparePartCard = $sparePartCard;
  2505.     }
  2506.     /**
  2507.      * @return float|int
  2508.      */
  2509.     public function getSparePartPrice(): float|int
  2510.     {
  2511.         return $this->sparePartPrice;
  2512.     }
  2513.     /**
  2514.      * @param float|int $sparePartPrice
  2515.      * @return void
  2516.      */
  2517.     public function setSparePartPrice(float|int $sparePartPrice): void
  2518.     {
  2519.         $this->sparePartPrice = $sparePartPrice;
  2520.     }
  2521.     public function getSparePartCreated(): ?\DateTime
  2522.     {
  2523.         return $this->sparePartCreated;
  2524.     }
  2525.     public function setSparePartCreated(?\DateTime $sparePartCreated): void
  2526.     {
  2527.         $this->sparePartCreated = $sparePartCreated;
  2528.     }
  2529.     public function getSparePartUpdated(): ?\DateTime
  2530.     {
  2531.         return $this->sparePartUpdated;
  2532.     }
  2533.     public function setSparePartUpdated(?\DateTime $sparePartUpdated): void
  2534.     {
  2535.         $this->sparePartUpdated = $sparePartUpdated;
  2536.     }
  2537.     public function getSparePartCreatedBy(): ?User
  2538.     {
  2539.         return $this->sparePartCreatedBy;
  2540.     }
  2541.     public function setSparePartCreatedBy(?User $sparePartCreatedBy): void
  2542.     {
  2543.         $this->sparePartCreatedBy = $sparePartCreatedBy;
  2544.     }
  2545.     public function getSparePartUpdatedBy(): ?User
  2546.     {
  2547.         return $this->sparePartUpdatedBy;
  2548.     }
  2549.     public function setSparePartUpdatedBy(?User $sparePartUpdatedBy): void
  2550.     {
  2551.         $this->sparePartUpdatedBy = $sparePartUpdatedBy;
  2552.     }
  2553.     /**
  2554.      * @return int
  2555.      */
  2556.     public function getMarginLevel(): int
  2557.     {
  2558.         return $this->marginLevel;
  2559.     }
  2560.     /**
  2561.      * @param int $marginLevel
  2562.      * @return void
  2563.      */
  2564.     public function setMarginLevel(int $marginLevel): void
  2565.     {
  2566.         $this->marginLevel = $marginLevel;
  2567.     }
  2568.     /**
  2569.      * @param float $currentPrice
  2570.      * 
  2571.      * @return string
  2572.      */
  2573.     public function getCalculatedMarginLevel(float $currentPrice): string
  2574.     {
  2575.         if ( $currentPrice <= 0 || $this->avgPrice <= 0 ) {
  2576.             return self::getMarginLevelChoices()[$this->marginLevel] ?? self::getMarginLevelChoices()[self::MARGIN_LEVEL_NO];
  2577.         }
  2578.         if (( $currentPrice - $this->avgPrice ) > 200 ) {
  2579.             return self::getMarginLevelChoices()[self::MARGIN_LEVEL_A];
  2580.         }
  2581.         elseif (( $currentPrice - $this->avgPrice ) > 150 ) {
  2582.             return self::getMarginLevelChoices()[self::MARGIN_LEVEL_B];
  2583.         }
  2584.         elseif (( $currentPrice - $this->avgPrice ) > 100 ) {
  2585.             return self::getMarginLevelChoices()[self::MARGIN_LEVEL_C];
  2586.         }
  2587.         elseif (( $currentPrice - $this->avgPrice ) > 50 ) {
  2588.             return self::getMarginLevelChoices()[self::MARGIN_LEVEL_D];
  2589.         } 
  2590.         else {
  2591.             return self::getMarginLevelChoices()[self::MARGIN_LEVEL_E];
  2592.         }
  2593.     }
  2594.     /**
  2595.      * @return Collection
  2596.      */
  2597.     public function getCoupons()
  2598.     {
  2599.         return $this->coupons;
  2600.     }
  2601.     /**
  2602.      * @param Collection $coupons
  2603.      * @return void
  2604.      */
  2605.     public function setCoupons(Collection $coupons): void
  2606.     {
  2607.         $this->coupons = $coupons;
  2608.     }
  2609.     public function getQuantityLimit(): ?int
  2610.     {
  2611.         return $this->quantityLimit;
  2612.     }
  2613.     public function setQuantityLimit(?int $quantityLimit): void
  2614.     {
  2615.         $this->quantityLimit = $quantityLimit;
  2616.     }
  2617.     /**
  2618.      * @return bool
  2619.      */
  2620.     public function isAvailabilityPausedForProductModel(): bool
  2621.     {
  2622.         return $this->availabilityPausedForProductModel;
  2623.     }
  2624.     /**
  2625.      * @param bool $availabilityPausedForProductModel
  2626.      * @return void
  2627.      */
  2628.     public function setAvailabilityPausedForProductModel(bool $availabilityPausedForProductModel): void
  2629.     {
  2630.         $this->availabilityPausedForProductModel = $availabilityPausedForProductModel;
  2631.     }
  2632.     /**
  2633.      * @return FixedAttributeOptionCombination
  2634.      */
  2635.     public function getFixedAttributeOptionCombination()
  2636.     {
  2637.         return $this->fixedAttributeOptionCombination;
  2638.     }
  2639.     /**
  2640.      * @param FixedAttributeOptionCombination $fixedAttributeOptionCombination
  2641.      */
  2642.     public function setFixedAttributeOptionCombination(FixedAttributeOptionCombination $fixedAttributeOptionCombination)
  2643.     {
  2644.         $this->fixedAttributeOptionCombination = $fixedAttributeOptionCombination;
  2645.     }
  2646.     /**
  2647.      * @return \DateTime
  2648.      */
  2649.     public function getLastQtySyncDate(): ?\DateTime
  2650.     {
  2651.         return $this->lastQtySyncDate;
  2652.     }
  2653.     /**
  2654.      * @param \DateTime $lastQtySyncDate
  2655.      */
  2656.     public function setLastQtySyncDate(\DateTime $lastQtySyncDate)
  2657.     {
  2658.         $this->lastQtySyncDate = $lastQtySyncDate;
  2659.     }
  2660.     public function getConnectedBatteries(): array
  2661.     {
  2662.         $result = [];
  2663.         $productModel = $this->getProductModel();
  2664.         /** @var Product $product */
  2665.         foreach ($productModel?->getConnectedProducts() ?? [] as $product) {
  2666.             if ($product->getType()->getId() == ProductType::PRODUCT_TYPE_ID_NOTEBOOK_BATTERY) {
  2667.                 $result[] = $product;
  2668.             }
  2669.         }
  2670.         return $result;
  2671.     }
  2672.     public function addConnectedProductModel(ProductModel $productModel): self
  2673.     {
  2674.         if (!$this->connectedProductModels->contains($productModel)) {
  2675.             $this->connectedProductModels->add($productModel);
  2676.         }
  2677.         return $this;
  2678.     }
  2679.     public function getConnectedProductModels()
  2680.     {
  2681.         return $this->connectedProductModels;
  2682.     }
  2683.     /**
  2684.      * @return Collection<int, Product>
  2685.      */
  2686.     public function getAlternativeProducts(): Collection
  2687.     {
  2688.         return $this->alternativeProducts;
  2689.     }
  2690.     public function addAlternativeProduct(Product $product): self
  2691.     {
  2692.         if (!$this->alternativeProducts->contains($product)) {
  2693.             $this->alternativeProducts->add($product);
  2694.         }
  2695.         return $this;
  2696.     }
  2697.     public function removeAlternativeProduct(Product $product): self
  2698.     {
  2699.         $this->alternativeProducts->removeElement($product);
  2700.         return $this;
  2701.     }
  2702.     /**
  2703.      * @return Collection<int, Product>
  2704.      */
  2705.     public function getParentAlternativeProducts(): Collection
  2706.     {
  2707.         return $this->parentAlternativeProducts;
  2708.     }
  2709.     public function getCurrentAlternativeProduct(): ?Product
  2710.     {
  2711.         return $this->currentAlternativeProduct;
  2712.     }
  2713.     public function setCurrentAlternativeProduct(?Product $currentAlternativeProduct): void
  2714.     {
  2715.         $this->currentAlternativeProduct = $currentAlternativeProduct;
  2716.     }
  2717.     /**
  2718.      * @return Collection
  2719.      */
  2720.     public function getCustomerClaimProducts(): Collection
  2721.     {
  2722.         return $this->customerClaimProducts;
  2723.     }
  2724.     public function addCustomerClaimProduct(CustomerClaimProduct $customerClaimProduct): self
  2725.     {
  2726.         if (!$this->customerClaimProducts->contains($customerClaimProduct)) {
  2727.             $this->customerClaimProducts[] = $customerClaimProduct;
  2728.             $customerClaimProduct->setProduct($this);
  2729.         }
  2730.         return $this;
  2731.     }
  2732.     public function removeCustomerClaimProduct(CustomerClaimProduct $customerClaimProduct): self
  2733.     {
  2734.         if ($this->customerClaimProducts->removeElement($customerClaimProduct)) {
  2735.             if ($customerClaimProduct->getProduct() === $this) {
  2736.                 $customerClaimProduct->setProduct(null);
  2737.             }
  2738.         }
  2739.         return $this;
  2740.     }
  2741.     /**
  2742.      * @return int
  2743.      */
  2744.     public function getCalculatedQtyGradeNew()
  2745.     {
  2746.         return $this->calculatedQtyGradeNew;
  2747.     }
  2748.     /**
  2749.      * @param int $calculatedQtyGradeNew
  2750.      */
  2751.     public function setCalculatedQtyGradeNew(int $calculatedQtyGradeNew)
  2752.     {
  2753.         $this->calculatedQtyGradeNew = $calculatedQtyGradeNew;
  2754.     }
  2755.     /**
  2756.      * @return int
  2757.      */
  2758.     public function getCalculatedQtyGradeA()
  2759.     {
  2760.         return $this->calculatedQtyGradeA;
  2761.     }
  2762.     /**
  2763.      * @param int $calculatedQtyGradeA
  2764.      */
  2765.     public function setCalculatedQtyGradeA(int $calculatedQtyGradeA)
  2766.     {
  2767.         $this->calculatedQtyGradeA = $calculatedQtyGradeA;
  2768.     }
  2769.     /**
  2770.      * @return int
  2771.      */
  2772.     public function getCalculatedQtyGradeB()
  2773.     {
  2774.         return $this->calculatedQtyGradeB;
  2775.     }
  2776.     /**
  2777.      * @param int $calculatedQtyGradeB
  2778.      */
  2779.     public function setCalculatedQtyGradeB(int $calculatedQtyGradeB)
  2780.     {
  2781.         $this->calculatedQtyGradeB = $calculatedQtyGradeB;
  2782.     }
  2783.     /**
  2784.      * @return int
  2785.      */
  2786.     public function getCalculatedQtyGradeC()
  2787.     {
  2788.         return $this->calculatedQtyGradeC;
  2789.     }
  2790.     /**
  2791.      * @param int $calculatedQtyGradeC
  2792.      */
  2793.     public function setCalculatedQtyGradeC(int $calculatedQtyGradeC)
  2794.     {
  2795.         $this->calculatedQtyGradeC = $calculatedQtyGradeC;
  2796.     }
  2797.     /**
  2798.      * @return int
  2799.      */
  2800.     public function getCalculatedQtyGradeD()
  2801.     {
  2802.         return $this->calculatedQtyGradeD;
  2803.     }
  2804.     /**
  2805.      * @param int $calculatedQtyGradeD
  2806.      */
  2807.     public function setCalculatedQtyGradeD(int $calculatedQtyGradeD)
  2808.     {
  2809.         $this->calculatedQtyGradeD = $calculatedQtyGradeD;
  2810.     }
  2811.     /**
  2812.      * @return bool
  2813.      */
  2814.     public function isMicrosoftOffice(): bool
  2815.     {
  2816.         /** @var ProductAttribute $productAttribute */
  2817.         foreach ($this->productAttributes as $productAttribute) {
  2818.             if ($productAttribute->getOption()->getId() == AttributeOption::ATTRIBUTE_OPTION_ID_OFFICE && $productAttribute->getOption()->getAttribute()->getId() == Attribute::ATTRIBUTE_ID_SOFTWARE) {
  2819.                 return true;
  2820.             }
  2821.         }
  2822.         return false;
  2823.     }
  2824.     /**
  2825.      * @return bool
  2826.      */
  2827.     public function isBazaar(): bool
  2828.     {
  2829.         return $this->qualityStatus === self::QualityStatus_Bazaar;
  2830.     }
  2831. }