src/EventSubscriber/Inventory/ShipmentStockMovementSubscriber.php line 36
<?php
namespace App\EventSubscriber\Inventory;
use App\Doctrine\Type\Inventory\MovementType;
use App\Entity\Expediting\Package;
use App\Entity\Inventory\PackageStockEntry;
use App\Entity\Inventory\PackageStockExit;
use App\Entity\Inventory\Warehouse;
use App\Event\Inventory\ShipmentStockEntryEvent;
use App\Event\Inventory\ShipmentStockEventInterface;
use App\Event\Inventory\ShipmentStockExitEvent;
use Doctrine\ORM\EntityManagerInterface;
use DomainException;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
readonly class ShipmentStockMovementSubscriber implements EventSubscriberInterface
{
public function __construct(
private EntityManagerInterface $entityManager,
) {}
public static function getSubscribedEvents(): array
{
return [
ShipmentStockEntryEvent::IDENTIFIER => ['handleEntry', 0],
ShipmentStockExitEvent::IDENTIFIER => ['handleExit', 0],
];
}
public function handleEntry(ShipmentStockEventInterface $event): void
{
$this->processMovements($event, MovementType::ENTRY);
}
public function handleExit(ShipmentStockEventInterface $event): void
{
$this->processMovements($event, MovementType::EXIT);
}
private function processMovements(ShipmentStockEventInterface $event, MovementType $movementType): void
{
$shippingSegment = $event->getShippingSegment();
$warehouse = MovementType::ENTRY === $movementType
? $shippingSegment->getPlaceOfDischarge()
: $shippingSegment->getPlaceOfLoading();
foreach ($shippingSegment->getShippingPlan()->getPackages() as $package) {
$entity = MovementType::ENTRY === $movementType
? new PackageStockEntry()
: new PackageStockExit();
$entity
->setPackage($package)
->setWarehouse($warehouse)
->setShippingSegment($shippingSegment)
->setCompletedAt($event->getCompletedOn());
// Before persisting, we need to correctly associate all Exits with the corresponding Entries
if (MovementType::EXIT === $movementType) {
$stockEntry = $this->getPackageStockEntry($package, $warehouse);
$entity->setStockEntry($stockEntry);
}
$this->entityManager->persist($entity);
}
$this->entityManager->flush();
}
private function getPackageStockEntry(Package $package, Warehouse $warehouse): PackageStockEntry
{
foreach ($package->getMovements() as $movement) {
if (
$movement instanceof PackageStockEntry &&
$movement->getWarehouse() === $warehouse
) {
if ($movement->getStockExit() instanceof PackageStockExit) {
throw new DomainException('Last stock entry is already associated with a stock exit.');
}
return $movement;
}
}
throw new DomainException('No stock entry found for stock exit.');
}
}