custom/plugins/WbfkMultipleTransactions/src/Subscriber/CartConvertedEventSubscriber.php line 38

Open in your IDE?
  1. <?php
  2. declare(strict_types=1);
  3. namespace Wbfk\MultipleTransactions\Subscriber;
  4. use Shopware\Core\Checkout\Cart\Order\CartConvertedEvent;
  5. use Shopware\Core\Checkout\Cart\Price\CashRounding;
  6. use Shopware\Core\Checkout\Cart\Price\Struct\CalculatedPrice;
  7. use Shopware\Core\Checkout\Order\Aggregate\OrderTransaction\OrderTransactionCollection;
  8. use Shopware\Core\Checkout\Order\Aggregate\OrderTransaction\OrderTransactionStates;
  9. use Shopware\Core\Framework\Context;
  10. use Shopware\Core\Framework\DataAbstractionLayer\EntityRepository;
  11. use Shopware\Core\Framework\DataAbstractionLayer\Pricing\CashRoundingConfig;
  12. use Shopware\Core\Framework\DataAbstractionLayer\Search\Criteria;
  13. use Shopware\Core\Framework\DataAbstractionLayer\Search\Filter\EqualsFilter;
  14. use Shopware\Core\System\StateMachine\Aggregation\StateMachineState\StateMachineStateEntity;
  15. use Symfony\Component\EventDispatcher\EventSubscriberInterface;
  16. use Wbfk\MultipleTransactions\Core\Checkout\Order\TransactionsSummary;
  17. class CartConvertedEventSubscriber implements EventSubscriberInterface
  18. {
  19.     public function __construct(
  20.         private readonly CashRounding $cashRounding,
  21.         private readonly EntityRepository $stateMachineStateRepository,
  22.         private readonly EntityRepository $orderTransactionRepository
  23.     ) {
  24.     }
  25.     public static function getSubscribedEvents(): array
  26.     {
  27.         return [
  28.             CartConvertedEvent::class => 'adjustTransactionAmountToIncludeAlreadyPaidAmount',
  29.         ];
  30.     }
  31.     public function adjustTransactionAmountToIncludeAlreadyPaidAmount(CartConvertedEvent $event): void
  32.     {
  33.         /** @var TransactionsSummary $transactionsSummary */
  34.         $transactionsSummary $event->getCart()->getExtension('transactionsSummary');
  35.         if (!$transactionsSummary) {
  36.             return;
  37.         }
  38.         if ($transactionsSummary->alreadyPaid === 0.0) {
  39.             return;
  40.         }
  41.         $convertedCart $event->getConvertedCart();
  42.         /** @var ?CalculatedPrice $calculatedPrice */
  43.         $calculatedPrice $convertedCart['transactions'][0]['amount'] ?? null;
  44.         if (!$calculatedPrice) {
  45.             return;
  46.         }
  47.         $total $calculatedPrice->getTotalPrice();
  48.         $total -= $transactionsSummary->alreadyPaid;
  49.         $convertedCart['transactions'][0]['stateId'] = $this->getPartiallyPaidStateId($event->getContext());
  50.         // If there is excess payment, this should be handled by the shop admin.
  51.         // If the total is same as already paid, then there is no need to create a new transaction.
  52.         if ($total <= 0) {
  53.             unset($convertedCart['transactions']);
  54.             // Need to delete last transaction if it is partially paid transaction as it is not needed anymore.
  55.             // This happens when order is already edited added new items or quantity changed to higher requiring extra payment.
  56.             // Then this order might be further edited and removed some items or quantity changed to lower requiring refund/ or not requiring extra payment.
  57.             $lastTransaction $transactionsSummary->transactions->last();
  58.             if ($lastTransaction && $lastTransaction->stateMachineState->technicalName === OrderTransactionStates::STATE_PARTIALLY_PAID) {
  59.                 $this->orderTransactionRepository->delete([
  60.                     ['id' => $lastTransaction->getId()],
  61.                 ], $event->getContext());
  62.             }
  63.         } else {
  64.             $cashRoundingConfig = new CashRoundingConfig(20.01true);
  65.             $total $this->cashRounding->cashRound($total$cashRoundingConfig);
  66.             $convertedCart['transactions'][0]['amount'] =
  67.                 new CalculatedPrice($total$total$calculatedPrice->getCalculatedTaxes(), $calculatedPrice->getTaxRules(), 1);
  68.             // Saving previous transactions summary in custom fields to for any debugging purposes.
  69.             $customFields $convertedCart['transactions'][0]['customFields'] ?? [];
  70.             $customFields['previousTransactionsSummary'] = $transactionsSummary;
  71.             $convertedCart['transactions'][0]['customFields'] = $customFields;
  72.         }
  73.         $event->setConvertedCart($convertedCart);
  74.     }
  75.     private function getPartiallyPaidStateId(Context $context): string
  76.     {
  77.         $criteria = new Criteria();
  78.         $criteria->addFilter(new EqualsFilter('technicalName'OrderTransactionStates::STATE_PARTIALLY_PAID));
  79.         $criteria->setLimit(1);
  80.         /** @var StateMachineStateEntity $state */
  81.         $state $this->stateMachineStateRepository->search($criteria$context)->first();
  82.         if ($state === null) {
  83.             throw new \RuntimeException('Could not find state for partially paid transactions');
  84.         }
  85.         return $state->getId();
  86.     }
  87. }