custom/plugins/WbfkExtensions/src/Subscriber/WbfkProductValidator.php line 42

Open in your IDE?
  1. <?php
  2. declare(strict_types=1);
  3. namespace WbfkExtensions\Subscriber;
  4. use JetBrains\PhpStorm\NoReturn;
  5. use Shopware\Core\Content\Product\Aggregate\ProductPrice\ProductPriceEntity;
  6. use Shopware\Core\Content\Product\ProductDefinition;
  7. use Shopware\Core\Content\Product\ProductEntity;
  8. use Shopware\Core\Defaults;
  9. use Shopware\Core\Framework\Context;
  10. use Shopware\Core\Framework\DataAbstractionLayer\EntityRepository;
  11. use Shopware\Core\Framework\DataAbstractionLayer\Pricing\Price;
  12. use Shopware\Core\Framework\DataAbstractionLayer\Search\Criteria;
  13. use Shopware\Core\Framework\DataAbstractionLayer\Write\Command\InsertCommand;
  14. use Shopware\Core\Framework\DataAbstractionLayer\Write\Command\UpdateCommand;
  15. use Shopware\Core\Framework\DataAbstractionLayer\Write\Validation\PreWriteValidationEvent;
  16. use Shopware\Core\Framework\Validation\WriteConstraintViolationException;
  17. use Symfony\Component\EventDispatcher\EventSubscriberInterface;
  18. use Symfony\Component\Validator\ConstraintViolation;
  19. use Symfony\Component\Validator\ConstraintViolationList;
  20. class WbfkProductValidator implements EventSubscriberInterface
  21. {
  22. /** @var ProductEntity[] */
  23. private array $productEntityCache = [];
  24. public function __construct(
  25. private readonly EntityRepository $productRepository
  26. ) {
  27. }
  28. public static function getSubscribedEvents(): array
  29. {
  30. return [
  31. PreWriteValidationEvent::class => 'onPreValidate',
  32. ];
  33. }
  34. public function onPreValidate(PreWriteValidationEvent $event): void
  35. {
  36. $violationList = new ConstraintViolationList();
  37. foreach ($event->getCommands() as $command) {
  38. if (!($command instanceof InsertCommand || $command instanceof UpdateCommand)) {
  39. continue;
  40. }
  41. if ($command->getDefinition()->getClass() === ProductDefinition::class) {
  42. $this->validateProductPrice($violationList, $command, $event->getContext());
  43. }
  44. if ($command->getDefinition()->getClass() === ProductPriceEntity::class) {
  45. $this->validatePriceListPrice($violationList, $command, $event->getContext());
  46. }
  47. }
  48. if ($violationList->count() > 0) {
  49. $event->getExceptions()->add(new WriteConstraintViolationException($violationList));
  50. }
  51. }
  52. #[NoReturn]
  53. private function validateProductPrice(ConstraintViolationList &$violations, InsertCommand|UpdateCommand $command, Context $context): void
  54. {
  55. $payload = $command->getPayload();
  56. $pKeys = $command->getPrimaryKey();
  57. if (empty($payload['price']) && empty($payload['purchase_prices'])) {
  58. return;
  59. }
  60. $product = $this->getProduct($context, $pKeys);
  61. /** @var Price $purchasePrice */
  62. $purchasePrice = $product->getPurchasePrices()->first();
  63. $purchaseNet = $purchasePrice->getNet();
  64. $purchaseGross = $purchasePrice->getGross();
  65. if (!empty($payload['purchase_prices'])) {
  66. $newPurchasePrice = (json_decode($payload['purchase_prices'], true))['c'.Defaults::CURRENCY];
  67. $purchaseNet = $newPurchasePrice['net'];
  68. $purchaseGross = $newPurchasePrice['gross'];
  69. }
  70. /** @var Price $price */
  71. $price = $product->getPrice()->get(Defaults::CURRENCY);
  72. $net = $price->getNet();
  73. $gross = $price->getGross();
  74. if (!empty($payload['price'])) {
  75. $newPrice = (json_decode($payload['price'], true))['c'.Defaults::CURRENCY];
  76. $net = $newPrice['net'];
  77. $gross = $newPrice['gross'];
  78. }
  79. // dd([
  80. // 'net' => $net,
  81. // 'gross' => $gross,
  82. // 'purchaseNet' => $purchaseNet,
  83. // 'purchaseGross' => $purchaseGross,
  84. // ]);
  85. if ($net < $purchaseNet) {
  86. $violations->add(
  87. new ConstraintViolation(
  88. "Der Nettopreis ($net) muss über den Netto-Einkaufspreis ($purchaseNet) liegen",
  89. 'Misskonfiguration Preis!',
  90. [],
  91. '',
  92. '/write/price',
  93. $net
  94. )
  95. );
  96. }
  97. if ($gross < $purchaseGross) {
  98. $violations->add(
  99. new ConstraintViolation(
  100. "Der Bruttopreis ($gross) muss über den Brutto-Einkaufspreis ($purchaseGross) liegen",
  101. 'Misskonfiguration Preis!',
  102. [],
  103. '',
  104. '/write/price',
  105. $net
  106. )
  107. );
  108. }
  109. }
  110. #[NoReturn]
  111. private function validatePriceListPrice(ConstraintViolationList &$violations, InsertCommand|UpdateCommand $command, Context $context): void
  112. {
  113. }
  114. private function getProduct(Context $context, array $pKeys): ?ProductEntity
  115. {
  116. $id = bin2hex($pKeys['id']);
  117. $productRepository = $this->productRepository;
  118. if (!isset($this->productEntityCache[$id])) {
  119. $this->productEntityCache[$id] = $context->enableInheritance(static function (Context $context) use ($id, $productRepository) {
  120. return $productRepository->search(new Criteria([$id]), $context)->first();
  121. });
  122. }
  123. return $this->productEntityCache[$id];
  124. }
  125. }