ProductDoctrineEventSubscriber   A
last analyzed

Complexity

Total Complexity 25

Size/Duplication

Total Lines 166
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 8

Importance

Changes 0
Metric Value
wmc 25
lcom 1
cbo 8
dl 0
loc 166
rs 10
c 0
b 0
f 0

12 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 4 1
A getSubscribedEvents() 0 7 1
A preUpdate() 0 4 1
A prePersist() 0 4 1
A onProductDataBeforeSave() 0 14 3
A refreshProductSellPrices() 0 15 1
A refreshProductVariantSellPrice() 0 22 1
A calculateAttributePrice() 0 19 4
A refreshProductBuyPrices() 0 11 1
B syncProductStock() 0 22 6
A syncVariantStock() 0 12 3
A getProductStock() 0 13 2
1
<?php
2
/*
3
 * WellCommerce Open-Source E-Commerce Platform
4
 * 
5
 * This file is part of the WellCommerce package.
6
 *
7
 * (c) Adam Piotrowski <[email protected]>
8
 * 
9
 * For the full copyright and license information,
10
 * please view the LICENSE file that was distributed with this source code.
11
 */
12
13
namespace WellCommerce\Bundle\CatalogBundle\EventListener;
14
15
use Doctrine\Common\EventSubscriber;
16
use Doctrine\Common\Persistence\Event\LifecycleEventArgs;
17
use WellCommerce\Bundle\AppBundle\Service\Tax\Helper\TaxHelperInterface;
18
use WellCommerce\Bundle\CatalogBundle\Entity\Product;
19
use WellCommerce\Bundle\CatalogBundle\Entity\Variant;
20
21
/**
22
 * Class ProductDoctrineEventSubscriber
23
 *
24
 * @author  Adam Piotrowski <[email protected]>
25
 */
26
class ProductDoctrineEventSubscriber implements EventSubscriber
27
{
28
    /**
29
     * @var TaxHelperInterface
30
     */
31
    private $taxHelper;
32
    
33
    public function __construct(TaxHelperInterface $taxHelper)
34
    {
35
        $this->taxHelper = $taxHelper;
36
    }
37
    
38
    public function getSubscribedEvents()
39
    {
40
        return [
41
            'prePersist',
42
            'preUpdate',
43
        ];
44
    }
45
    
46
    public function preUpdate(LifecycleEventArgs $args)
47
    {
48
        $this->onProductDataBeforeSave($args);
49
    }
50
    
51
    public function prePersist(LifecycleEventArgs $args)
52
    {
53
        $this->onProductDataBeforeSave($args);
54
    }
55
    
56
    public function onProductDataBeforeSave(LifecycleEventArgs $args)
57
    {
58
        $entity = $args->getObject();
59
        if ($entity instanceof Product) {
60
            $this->refreshProductSellPrices($entity);
61
            $this->refreshProductBuyPrices($entity);
62
            $this->syncProductStock($entity);
63
        }
64
        
65
        if ($entity instanceof Variant) {
66
            $this->refreshProductVariantSellPrice($entity);
67
            $this->syncVariantStock($entity);
68
        }
69
    }
70
    
71
    protected function refreshProductSellPrices(Product $product)
72
    {
73
        $sellPrice             = $product->getSellPrice();
74
        $grossAmount           = $sellPrice->getGrossAmount();
75
        $discountedGrossAmount = $sellPrice->getDiscountedGrossAmount();
76
        $taxRate               = $product->getSellPriceTax()->getValue();
77
        $netAmount             = $this->taxHelper->calculateNetPrice($grossAmount, $taxRate);
78
        $discountedNetAmount   = $this->taxHelper->calculateNetPrice($discountedGrossAmount, $taxRate);
79
        
80
        $sellPrice->setTaxRate($taxRate);
81
        $sellPrice->setTaxAmount($grossAmount - $netAmount);
82
        $sellPrice->setNetAmount($netAmount);
83
        $sellPrice->setDiscountedTaxAmount($discountedGrossAmount - $discountedNetAmount);
84
        $sellPrice->setDiscountedNetAmount($discountedNetAmount);
85
    }
86
    
87
    protected function refreshProductVariantSellPrice(Variant $variant)
88
    {
89
        $product               = $variant->getProduct();
90
        $sellPrice             = $product->getSellPrice();
91
        $grossAmount           = $this->calculateAttributePrice($variant, $sellPrice->getGrossAmount());
92
        $discountedGrossAmount = $this->calculateAttributePrice($variant, $sellPrice->getDiscountedGrossAmount());
93
        $taxRate               = $product->getSellPriceTax()->getValue();
94
        $netAmount             = $this->taxHelper->calculateNetPrice($grossAmount, $taxRate);
95
        $discountedNetAmount   = $this->taxHelper->calculateNetPrice($discountedGrossAmount, $taxRate);
96
        
97
        $productAttributeSellPrice = $variant->getSellPrice();
98
        $productAttributeSellPrice->setTaxRate($taxRate);
99
        $productAttributeSellPrice->setTaxAmount($grossAmount - $netAmount);
100
        $productAttributeSellPrice->setGrossAmount($grossAmount);
101
        $productAttributeSellPrice->setNetAmount($netAmount);
102
        $productAttributeSellPrice->setDiscountedGrossAmount($discountedGrossAmount);
103
        $productAttributeSellPrice->setDiscountedTaxAmount($discountedGrossAmount - $discountedNetAmount);
104
        $productAttributeSellPrice->setDiscountedNetAmount($discountedNetAmount);
105
        $productAttributeSellPrice->setValidFrom($sellPrice->getValidFrom());
106
        $productAttributeSellPrice->setValidTo($sellPrice->getValidTo());
107
        $productAttributeSellPrice->setCurrency($sellPrice->getCurrency());
108
    }
109
    
110
    protected function calculateAttributePrice(Variant $variant, $amount)
111
    {
112
        $modifierType  = $variant->getModifierType();
113
        $modifierValue = $variant->getModifierValue();
114
        
115
        switch ($modifierType) {
116
            case '+':
117
                $amount = $amount + $modifierValue;
118
                break;
119
            case '-':
120
                $amount = $amount - $modifierValue;
121
                break;
122
            case '%':
123
                $amount = $amount * ($modifierValue / 100);
124
                break;
125
        }
126
        
127
        return round($amount, 2);
128
    }
129
    
130
    protected function refreshProductBuyPrices(Product $product)
131
    {
132
        $buyPrice    = $product->getBuyPrice();
133
        $grossAmount = $buyPrice->getGrossAmount();
134
        $taxRate     = $product->getBuyPriceTax()->getValue();
135
        $netAmount   = $this->taxHelper->calculateNetPrice($grossAmount, $taxRate);
136
        
137
        $buyPrice->setTaxRate($taxRate);
138
        $buyPrice->setTaxAmount($grossAmount - $netAmount);
139
        $buyPrice->setNetAmount($netAmount);
140
    }
141
    
142
    protected function syncProductStock(Product $product)
143
    {
144
        $trackStock       = $product->getTrackStock();
145
        $stock            = $this->getProductStock($product);
146
        $grossPrice       = $product->getSellPrice()->getFinalGrossAmount();
147
        $isStockAvailable = (true === $trackStock) ? $stock > 0 : 1;
148
        $isPriceNonZero   = $grossPrice > 0;
149
        
150
        if (false === $product->isEnabled() && true === $trackStock) {
151
            $product->setEnabled($isStockAvailable);
152
        }
153
        
154
        $product->setStock($stock);
155
        
156
        if (false === $isPriceNonZero) {
157
            $product->setEnabled(false);
158
        }
159
        
160
        if (0 === $product->getCategories()->count()) {
161
            $product->setEnabled(false);
162
        }
163
    }
164
    
165
    protected function syncVariantStock(Variant $variant)
166
    {
167
        $product          = $variant->getProduct();
168
        $trackStock       = $product->getTrackStock();
169
        $stock            = $variant->getStock();
170
        $isStockAvailable = (true === $trackStock) ? $stock > 0 : 1;
171
        $variant->setEnabled($isStockAvailable);
172
        
173
        if (false === $product->isEnabled()) {
174
            $variant->setEnabled(false);
175
        }
176
    }
177
    
178
    protected function getProductStock(Product $product): int
179
    {
180
        if (0 === $product->getVariants()->count()) {
181
            return $product->getStock();
182
        }
183
        
184
        $stock = 0;
185
        $product->getVariants()->map(function (Variant $variant) use (&$stock) {
186
            $stock = $stock + $variant->getStock();
187
        });
188
        
189
        return $stock;
190
    }
191
}
192