custom/plugins/VRPaymentVRPay/src/Subscriber/TransactionSubscriber.php line 95

Open in your IDE?
  1. <?php declare(strict_types=1);
  2. namespace VRPayment\VRPay\Subscriber;
  3. use http\Exception\UnexpectedValueException;
  4. use Psr\Container\ContainerInterface;
  5. use Shopware\Core\System\SalesChannel\Context\SalesChannelContextFactory;
  6. use Shopware\Core\System\SalesChannel\SalesChannelContext;
  7. use Symfony\Component\EventDispatcher\EventSubscriberInterface;
  8. use Shopware\Core\Checkout\Payment\Exception\AsyncPaymentFinalizeException;
  9. use Shopware\Core\Framework\DataAbstractionLayer\EntityRepository;
  10. use Shopware\Core\Framework\DataAbstractionLayer\Search\Criteria;
  11. use Shopware\Core\Framework\DataAbstractionLayer\Search\Filter\EqualsFilter;
  12. use Shopware\Core\Framework\DataAbstractionLayer\Event\EntityWrittenContainerEvent;
  13. use Shopware\Core\Framework\DataAbstractionLayer\Event\EntityWrittenEvent;
  14. use VRPayment\VRPay\Core\Checkout\Order\TransactionDefinition;
  15. use VRPayment\VRPay\Core\Checkout\Order\TransactionEntity;
  16. use VRPayment\VRPay\Service\Payment\Interfaces\VRPaymentInterface;
  17. use VRPayment\VRPay\Service\VRPay\Client;
  18. /**
  19.  * Class TransactionSubscriber
  20.  * Reacts on changes in our transaction entities to react to state changes and apply those changes through the payment
  21.  * gateway
  22.  *
  23.  * @package VRPayment\VRPay\Subscriber
  24.  */
  25. class TransactionSubscriber implements EventSubscriberInterface
  26. {
  27.     /**
  28.      * @var EntityRepository
  29.      */
  30.     private $transactionRepository;
  31.     /**
  32.      * @var Client
  33.      */
  34.     private $client;
  35.     /**
  36.      * @var SalesChannelContextFactory
  37.      */
  38.     private $salesChannelContextFactory;
  39.     /**
  40.      * @var ContainerInterface
  41.      */
  42.     private $container;
  43.     public static function getSubscribedEvents()
  44.     {
  45.         return [
  46.             EntityWrittenContainerEvent::class => 'onEntityWritten',
  47.         ];
  48.     }
  49.     /**
  50.      * TransactionSubscriber constructor.
  51.      * @param EntityRepository $transactionRepository
  52.      * @param Client $client
  53.      * @param SalesChannelContextFactory $salesChannelContextFactory
  54.      */
  55.     public function __construct(EntityRepository $transactionRepositoryClient $client$salesChannelContextFactory)
  56.     {
  57.         $this->transactionRepository $transactionRepository;
  58.         $this->client $client;
  59.         $this->salesChannelContextFactory $salesChannelContextFactory;
  60.     }
  61.     /**
  62.      * @internal
  63.      * @required
  64.      */
  65.     public function setContainer(ContainerInterface $container): ?ContainerInterface
  66.     {
  67.         $previous $this->container;
  68.         $this->container $container;
  69.         return $previous;
  70.     }
  71.     /**
  72.      * Called when any entity within Shopware was written to the db. Only reacts to writes of our transactions.
  73.      * If refundedAt was set, perform a refund with the payment gateway.
  74.      *
  75.      * @param EntityWrittenContainerEvent $event
  76.      *
  77.      * @throws \Exception
  78.      */
  79.     public function onEntityWritten(EntityWrittenContainerEvent $event)
  80.     {
  81.         foreach($event->getEvents() as $writtenEvent)
  82.         {
  83.             /** @var EntityWrittenEvent $writtenEvent */
  84.             if($writtenEvent->getEntityName() !== TransactionDefinition::ENTITY_NAME)
  85.             {
  86.                 continue;
  87.             }
  88.             foreach($writtenEvent->getPayloads() as $payload)
  89.             {
  90.                 if(!isset($payload['refundedAt']) || empty($payload['refundedAt']))
  91.                 {
  92.                     continue;
  93.                 }
  94.                 $this->refundPayment($payload['id']);
  95.             }
  96.         }
  97.     }
  98.     /**
  99.      * refunds a payment at the payment provider. If something goes wrong, our transaction is updated to have
  100.      * refundedAt back at null to reflect the correct state of the transaction.
  101.      *
  102.      * @param string $transactionId
  103.      *
  104.      * @throws \Exception
  105.      */
  106.     private function refundPayment(string $transactionId)
  107.     {
  108.         $defaultContext = \Shopware\Core\Framework\Context::createDefaultContext();
  109.         // search the vr pay transaction by the given vr pay transaction id and fetch the relations we need for refunding
  110.         $vrpayTransactions $this->transactionRepository->search(
  111.             (new Criteria([$transactionId]))
  112.                 ->addAssociation('orderTransaction.paymentMethod')
  113.                 ->addAssociation('orderTransaction.order.salesChannel.currency'),
  114.             $defaultContext
  115.         );
  116.         if($vrpayTransactions->getTotal() !== 1)
  117.         {
  118.             throw new \OutOfBoundsException('unkown vr pay transaction given for refund');
  119.         }
  120.         /** @var TransactionEntity $vrpayTransaction */
  121.         $vrpayTransaction $vrpayTransactions->getEntities()->first();
  122.         try
  123.         {
  124.             // gsther required information and call the api to refund
  125.             $shopwareTransaction $vrpayTransaction->getOrderTransaction();
  126.             $paymentHandlerClass $shopwareTransaction->getPaymentMethod()->getHandlerIdentifier();
  127.             /** @var VRPaymentInterface $paymentHandler */
  128.             $paymentHandler $this->container->get($paymentHandlerClass);
  129.             $this->client->refundTransaction(
  130.                 $paymentHandler,
  131.                 $this->salesChannelContextFactory->create(uniqid(), $shopwareTransaction->getOrder()->getSalesChannelId()),
  132.                 $vrpayTransaction->getTransactionId(),
  133.                 $shopwareTransaction->getAmount()->getTotalPrice(),
  134.                 $shopwareTransaction->getOrder()->getSalesChannel()->getCurrency()->getIsoCode()
  135.             );
  136.         }
  137.         catch(\Exception $e)
  138.         {
  139.             // if anything goes wrong, update the transaction to NULL the refundedAt field
  140.             $this->transactionRepository->update([['id' => $vrpayTransaction->getId(), 'refundedAt' => null]], $defaultContext);
  141.             throw $e;
  142.         }
  143.     }
  144. }