stockMovementFromOrderLine()   A
last analyzed

Complexity

Conditions 1
Paths 1

Size

Total Lines 7
Code Lines 4

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 2

Importance

Changes 0
Metric Value
dl 0
loc 7
ccs 0
cts 3
cp 0
rs 9.4285
c 0
b 0
f 0
cc 1
eloc 4
nc 1
nop 1
crap 2
1
<?php
2
3
declare(strict_types=1);
4
5
namespace Loevgaard\DandomainStockBundle\EventListener;
6
7
use Doctrine\Common\EventSubscriber;
8
use Doctrine\ORM\EntityManager;
9
use Doctrine\ORM\Event\OnFlushEventArgs;
10
use Doctrine\ORM\Events;
11
use Doctrine\ORM\Mapping\ClassMetadata;
12
use Doctrine\ORM\ORMException;
13
use Doctrine\ORM\UnitOfWork;
14
use Loevgaard\DandomainFoundation\Entity\Generated\OrderLineInterface;
15
use Loevgaard\DandomainStock\Entity\Generated\StockMovementInterface;
16
use Loevgaard\DandomainStock\Entity\StockMovement;
17
use Loevgaard\DandomainStock\Exception\CurrencyMismatchException;
18
use Loevgaard\DandomainStock\Exception\StockMovementProductMismatchException;
19
use Loevgaard\DandomainStock\Exception\UndefinedPriceForCurrencyException;
20
use Loevgaard\DandomainStock\Exception\UnsetCurrencyException;
21
use Loevgaard\DandomainStock\Exception\UnsetProductException;
22
23
class StockMovementSubscriber implements EventSubscriber
24
{
25
    /**
26
     * @var array
27
     */
28
    private $orderStateIds;
29
30
    /**
31
     * @param array $orderStateIds An array of external ids for order states (use the id in the Dandomain interface)
32
     */
33 1
    public function __construct(array $orderStateIds)
34
    {
35 1
        $this->orderStateIds = $orderStateIds;
36 1
    }
37
38 1
    public function getSubscribedEvents()
39
    {
40
        return [
41 1
            Events::onFlush,
42
        ];
43
    }
44
45
    /**
46
     * @param OnFlushEventArgs $args
47
     * @throws CurrencyMismatchException
48
     * @throws ORMException
49
     * @throws StockMovementProductMismatchException
50
     * @throws UndefinedPriceForCurrencyException
51
     * @throws UnsetCurrencyException
52
     * @throws UnsetProductException
53
     */
54
    public function onFlush(OnFlushEventArgs $args)
55
    {
56
        $em = $args->getEntityManager();
57
        $uow = $em->getUnitOfWork();
58
59
        foreach ($uow->getScheduledEntityInsertions() as $entity) {
60
            /** @var OrderLineInterface $entity */
61
            if(!$this->isOrderLine($entity) || !$this->isValidState($entity)) {
62
                continue;
63
            }
64
65
            $stockMovement = $this->stockMovementFromOrderLine($entity);
66
67
            $this->persistStockMovement($stockMovement, $em, $uow);
68
        }
69
70
        foreach ($uow->getScheduledEntityUpdates() as $entity) {
71
            /** @var OrderLineInterface $entity */
72
            if(!$this->isOrderLine($entity) || !$this->isValidState($entity)) {
73
                continue;
74
            }
75
76
            $stockMovement = $this->stockMovementFromOrderLine($entity);
77
            $effectiveStockMovement = $entity->computeEffectiveStockMovement();
78
            if ($effectiveStockMovement) {
79
                $stockMovement = $effectiveStockMovement->diff($stockMovement);
80
                $stockMovement->setType(StockMovement::TYPE_REGULATION);
81
            }
82
83
            $this->persistStockMovement($stockMovement, $em, $uow);
84
        }
85
86
        foreach ($uow->getScheduledEntityDeletions() as $entity) {
87
            /** @var OrderLineInterface $entity */
88
            if(!$this->isOrderLine($entity)) {
89
                continue;
90
            }
91
92
            $effectiveStockMovement = $entity->computeEffectiveStockMovement();
93
94
            if ($effectiveStockMovement) {
95
                $stockMovement = $effectiveStockMovement->inverse();
96
                $stockMovement
97
                    ->setType(StockMovement::TYPE_REGULATION) // we set the type as regulation since it is not a sale now
98
                    ->setOrderLineRemoved(true)
99
                    ->setOrderLine(null);
100
101
                $this->persistStockMovement($stockMovement, $em, $uow);
102
            }
103
104
            foreach ($entity->getStockMovements() as $stockMovement) {
105
                $stockMovement
106
                    ->setOrderLineRemoved(true)
107
                    ->setOrderLine(null);
108
109
                $md = $this->metaData($em, $stockMovement);
110
                $uow->recomputeSingleEntityChangeSet($md, $stockMovement);
111
            }
112
        }
113
    }
114
115
    private function isOrderLine($entity) : bool
116
    {
117
        // if the order line does not have a valid product, we dont consider it an order line in the context of a stock movement
118
        // examples of products like this are discounts
119
        return $entity instanceof OrderLineInterface && $entity->getProduct();
0 ignored issues
show
Bug introduced by
The class Loevgaard\DandomainFound...ated\OrderLineInterface does not exist. Did you forget a USE statement, or did you not list all dependencies?

This error could be the result of:

1. Missing dependencies

PHP Analyzer uses your composer.json file (if available) to determine the dependencies of your project and to determine all the available classes and functions. It expects the composer.json to be in the root folder of your repository.

Are you sure this class is defined by one of your dependencies, or did you maybe not list a dependency in either the require or require-dev section?

2. Missing use statement

PHP does not complain about undefined classes in ìnstanceof checks. For example, the following PHP code will work perfectly fine:

if ($x instanceof DoesNotExist) {
    // Do something.
}

If you have not tested against this specific condition, such errors might go unnoticed.

Loading history...
120
    }
121
122
    private function isValidState(OrderLineInterface $orderLine) : bool
123
    {
124
        return $orderLine->getOrder()
125
            && $orderLine->getOrder()->getState()
126
            && in_array($orderLine->getOrder()->getState()->getExternalId(), $this->orderStateIds);
127
    }
128
129
    /**
130
     * @param OrderLineInterface $orderLine
131
     * @return StockMovement
132
     * @throws CurrencyMismatchException
133
     * @throws UndefinedPriceForCurrencyException
134
     * @throws UnsetProductException
135
     */
136
    private function stockMovementFromOrderLine(OrderLineInterface $orderLine) : StockMovement
137
    {
138
        $stockMovement = new StockMovement();
139
        $stockMovement->populateFromOrderLine($orderLine);
140
141
        return $stockMovement;
142
    }
143
144
    private function metaData(EntityManager $entityManager, $entity) : ClassMetadata
145
    {
146
        return $entityManager->getClassMetadata(get_class($entity));
147
    }
148
149
    /**
150
     * @param StockMovementInterface $stockMovement
151
     * @param EntityManager $entityManager
152
     * @param UnitOfWork $unitOfWork
153
     * @return boolean
154
     * @throws ORMException
155
     */
156
    private function persistStockMovement(StockMovementInterface $stockMovement, EntityManager $entityManager, UnitOfWork $unitOfWork) : bool
157
    {
158
        // if the quantity is 0 we don't want to add a stock movement since this will just pollute the stock movement table
159
        if($stockMovement->getQuantity() === 0) {
160
            return false;
161
        }
162
163
        $stockMovement->validate();
164
        $entityManager->persist($stockMovement);
165
        $md = $this->metaData($entityManager, $stockMovement);
166
        $unitOfWork->computeChangeSet($md, $stockMovement);
167
168
        return true;
169
    }
170
}
171