-
Notifications
You must be signed in to change notification settings - Fork 38
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
OP-289: Add new inventory management logic
- Loading branch information
Showing
12 changed files
with
561 additions
and
0 deletions.
There are no files selected for viewing
25 changes: 25 additions & 0 deletions
25
src/Inventory/Checker/BundledProductsInventoryManagementFeatureFlagChecker.php
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,25 @@ | ||
<?php | ||
|
||
/* | ||
* This file has been created by developers from BitBag. | ||
* Feel free to contact us once you face any issues or want to start | ||
* You can find more information about us on https://bitbag.io and write us | ||
* an email on hello@bitbag.io. | ||
*/ | ||
|
||
declare(strict_types=1); | ||
|
||
namespace BitBag\SyliusProductBundlePlugin\Inventory\Checker; | ||
|
||
final class BundledProductsInventoryManagementFeatureFlagChecker implements FeatureFlagCheckerInterface | ||
{ | ||
public function __construct( | ||
private readonly bool $enabled, | ||
) { | ||
} | ||
|
||
public function isEnabled(): bool | ||
{ | ||
return $this->enabled; | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,17 @@ | ||
<?php | ||
|
||
/* | ||
* This file has been created by developers from BitBag. | ||
* Feel free to contact us once you face any issues or want to start | ||
* You can find more information about us on https://bitbag.io and write us | ||
* an email on hello@bitbag.io. | ||
*/ | ||
|
||
declare(strict_types=1); | ||
|
||
namespace BitBag\SyliusProductBundlePlugin\Inventory\Checker; | ||
|
||
interface FeatureFlagCheckerInterface | ||
{ | ||
public function isEnabled(): bool; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,41 @@ | ||
<?php | ||
|
||
/* | ||
* This file has been created by developers from BitBag. | ||
* Feel free to contact us once you face any issues or want to start | ||
* You can find more information about us on https://bitbag.io and write us | ||
* an email on hello@bitbag.io. | ||
*/ | ||
|
||
declare(strict_types=1); | ||
|
||
namespace BitBag\SyliusProductBundlePlugin\Inventory\Checker; | ||
|
||
use BitBag\SyliusProductBundlePlugin\Entity\ProductInterface; | ||
use Sylius\Component\Core\Inventory\Checker\OrderItemAvailabilityCheckerInterface; | ||
use Sylius\Component\Core\Model\OrderItemInterface as BaseOrderItemInterface; | ||
|
||
final class OrderItemAvailabilityChecker implements OrderItemAvailabilityCheckerInterface | ||
{ | ||
public function __construct( | ||
private readonly OrderItemAvailabilityCheckerInterface $decorated, | ||
private readonly FeatureFlagCheckerInterface $featureFlagChecker, | ||
private readonly ProductBundleOrderItemAvailabilityCheckerInterface $bundleOrderItemAvailabilityChecker, | ||
) { | ||
} | ||
|
||
public function isReservedStockSufficient(BaseOrderItemInterface $orderItem): bool | ||
{ | ||
if (!$this->featureFlagChecker->isEnabled()) { | ||
return $this->decorated->isReservedStockSufficient($orderItem); | ||
} | ||
|
||
/** @var ProductInterface $product */ | ||
$product = $orderItem->getProduct(); | ||
if (!$product->isBundle()) { | ||
return $this->decorated->isReservedStockSufficient($orderItem); | ||
} | ||
|
||
return $this->bundleOrderItemAvailabilityChecker->areOrderedBundledProductVariantsAvailable($orderItem); | ||
} | ||
} |
41 changes: 41 additions & 0 deletions
41
src/Inventory/Checker/ProductBundleOrderItemAvailabilityChecker.php
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,41 @@ | ||
<?php | ||
|
||
/* | ||
* This file has been created by developers from BitBag. | ||
* Feel free to contact us once you face any issues or want to start | ||
* You can find more information about us on https://bitbag.io and write us | ||
* an email on hello@bitbag.io. | ||
*/ | ||
|
||
declare(strict_types=1); | ||
|
||
namespace BitBag\SyliusProductBundlePlugin\Inventory\Checker; | ||
|
||
use BitBag\SyliusProductBundlePlugin\Entity\OrderItemInterface; | ||
use Sylius\Component\Core\Model\OrderItemInterface as BaseOrderItemInterface; | ||
use Sylius\Component\Core\Model\ProductVariantInterface; | ||
|
||
final class ProductBundleOrderItemAvailabilityChecker implements ProductBundleOrderItemAvailabilityCheckerInterface | ||
{ | ||
public function areOrderedBundledProductVariantsAvailable(BaseOrderItemInterface|OrderItemInterface $orderItem): bool | ||
{ | ||
if (!$orderItem instanceof OrderItemInterface) { | ||
return true; | ||
} | ||
|
||
foreach ($orderItem->getProductBundleOrderItems() as $bundleOrderItem) { | ||
$quantity = $orderItem->getQuantity() * (int) $bundleOrderItem->getQuantity(); | ||
/** @var ProductVariantInterface $variant */ | ||
$variant = $bundleOrderItem->getProductVariant(); | ||
if (!$variant->isTracked()) { | ||
continue; | ||
} | ||
|
||
if (0 > (int) $variant->getOnHold() - $quantity || 0 > (int) $variant->getOnHand() - $quantity) { | ||
return false; | ||
} | ||
} | ||
|
||
return true; | ||
} | ||
} |
20 changes: 20 additions & 0 deletions
20
src/Inventory/Checker/ProductBundleOrderItemAvailabilityCheckerInterface.php
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,20 @@ | ||
<?php | ||
|
||
/* | ||
* This file has been created by developers from BitBag. | ||
* Feel free to contact us once you face any issues or want to start | ||
* You can find more information about us on https://bitbag.io and write us | ||
* an email on hello@bitbag.io. | ||
*/ | ||
|
||
declare(strict_types=1); | ||
|
||
namespace BitBag\SyliusProductBundlePlugin\Inventory\Checker; | ||
|
||
use BitBag\SyliusProductBundlePlugin\Entity\OrderItemInterface; | ||
use Sylius\Component\Core\Model\OrderItemInterface as BaseOrderItemInterface; | ||
|
||
interface ProductBundleOrderItemAvailabilityCheckerInterface | ||
{ | ||
public function areOrderedBundledProductVariantsAvailable(BaseOrderItemInterface|OrderItemInterface $orderItem): bool; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,124 @@ | ||
<?php | ||
|
||
/* | ||
* This file has been created by developers from BitBag. | ||
* Feel free to contact us once you face any issues or want to start | ||
* You can find more information about us on https://bitbag.io and write us | ||
* an email on hello@bitbag.io. | ||
*/ | ||
|
||
declare(strict_types=1); | ||
|
||
namespace BitBag\SyliusProductBundlePlugin\Inventory\Operator; | ||
|
||
use BitBag\SyliusProductBundlePlugin\Entity\OrderItemInterface; | ||
use BitBag\SyliusProductBundlePlugin\Entity\ProductInterface; | ||
use BitBag\SyliusProductBundlePlugin\Inventory\Checker\FeatureFlagCheckerInterface; | ||
use Doctrine\DBAL\LockMode; | ||
use Doctrine\ORM\EntityManagerInterface; | ||
use Sylius\Component\Core\Inventory\Operator\OrderInventoryOperatorInterface; | ||
use Sylius\Component\Core\Model\OrderInterface; | ||
use Sylius\Component\Core\Model\ProductVariantInterface; | ||
use Sylius\Component\Core\OrderPaymentStates; | ||
|
||
final class OrderInventoryOperator implements OrderInventoryOperatorInterface | ||
{ | ||
public function __construct( | ||
private readonly OrderInventoryOperatorInterface $decorated, | ||
private readonly EntityManagerInterface $productVariantManager, | ||
private readonly FeatureFlagCheckerInterface $featureFlagChecker, | ||
private readonly ProductBundleOrderInventoryOperatorInterface $productBundleOrderInventoryOperator, | ||
) { | ||
} | ||
|
||
public function cancel(OrderInterface $order): void | ||
{ | ||
$this->lockOrderProductVariants($order); | ||
|
||
if (!$this->featureFlagChecker->isEnabled()) { | ||
$this->decorated->cancel($order); | ||
} | ||
|
||
if (in_array( | ||
$order->getPaymentState(), | ||
[OrderPaymentStates::STATE_PAID, OrderPaymentStates::STATE_REFUNDED], | ||
true, | ||
)) { | ||
$this->productBundleOrderInventoryOperator->giveBack($order); | ||
|
||
return; | ||
} | ||
|
||
$this->productBundleOrderInventoryOperator->release($order); | ||
} | ||
|
||
public function hold(OrderInterface $order): void | ||
{ | ||
$this->lockOrderProductVariants($order); | ||
|
||
if (!$this->featureFlagChecker->isEnabled()) { | ||
$this->decorated->hold($order); | ||
|
||
return; | ||
} | ||
|
||
$this->productBundleOrderInventoryOperator->hold($order); | ||
} | ||
|
||
public function sell(OrderInterface $order): void | ||
{ | ||
$this->lockOrderProductVariants($order); | ||
|
||
if (!$this->featureFlagChecker->isEnabled()) { | ||
$this->decorated->sell($order); | ||
|
||
return; | ||
} | ||
|
||
$this->productBundleOrderInventoryOperator->sell($order); | ||
} | ||
|
||
private function lockOrderProductVariants(OrderInterface $order): void | ||
{ | ||
/** @var OrderItemInterface $orderItem */ | ||
foreach ($order->getItems() as $orderItem) { | ||
$this->lockOrderItemProductVariants($orderItem); | ||
} | ||
} | ||
|
||
private function lockOrderItemProductVariants(OrderItemInterface $orderItem): void | ||
{ | ||
/** @var ProductInterface $product */ | ||
$product = $orderItem->getProduct(); | ||
if ($this->featureFlagChecker->isEnabled() && $product->isBundle()) { | ||
$this->lockBundledOrderItemProductVariants($orderItem); | ||
} else { | ||
$this->lockOrderItemProductVariant($orderItem); | ||
} | ||
} | ||
|
||
private function lockOrderItemProductVariant(OrderItemInterface $orderItem): void | ||
{ | ||
$this->lockProductVariant($orderItem->getVariant()); | ||
} | ||
|
||
private function lockBundledOrderItemProductVariants(OrderItemInterface $orderItem): void | ||
{ | ||
foreach ($orderItem->getProductBundleOrderItems() as $bundleOrderItem) { | ||
$this->lockProductVariant($bundleOrderItem->getProductVariant()); | ||
} | ||
} | ||
|
||
private function lockProductVariant(?ProductVariantInterface $variant): void | ||
{ | ||
if (null === $variant) { | ||
throw new \InvalidArgumentException('Variant cannot be null'); | ||
} | ||
|
||
if (!$variant->isTracked()) { | ||
return; | ||
} | ||
|
||
$this->productVariantManager->lock($variant, LockMode::OPTIMISTIC, $variant->getVersion()); | ||
} | ||
} |
Oops, something went wrong.