You are here

class OrderPaymentIntentSubscriber in Commerce Stripe 8

Subscribes to order events to syncronize orders with their payment intents.

Payment intents contain the amount which should be charged during a transaction. When a payment intent is confirmed server or client side, that amount is what is charged. To ensure a proper charge amount, we must update the payment intent amount whenever an order is updated.

Hierarchy

Expanded class hierarchy of OrderPaymentIntentSubscriber

1 file declares its use of OrderPaymentIntentSubscriber
DecoratedOrderPaymentIntentSubscriber.php in tests/modules/commerce_stripe_test/src/EventSubscriber/DecoratedOrderPaymentIntentSubscriber.php
1 string reference to 'OrderPaymentIntentSubscriber'
commerce_stripe.services.yml in ./commerce_stripe.services.yml
commerce_stripe.services.yml
1 service uses OrderPaymentIntentSubscriber
commerce_stripe.order_events_subscriber in ./commerce_stripe.services.yml
Drupal\commerce_stripe\EventSubscriber\OrderPaymentIntentSubscriber

File

src/EventSubscriber/OrderPaymentIntentSubscriber.php, line 25

Namespace

Drupal\commerce_stripe\EventSubscriber
View source
class OrderPaymentIntentSubscriber implements EventSubscriberInterface, DestructableInterface {

  /**
   * The entity type manager.
   *
   * @var \Drupal\Core\Entity\EntityTypeManagerInterface
   */
  protected $entityTypeManager;

  /**
   * The intent IDs that need updating.
   *
   * @var int[]
   */
  protected $updateList = [];

  /**
   * Constructs a new OrderEventsSubscriber object.
   *
   * @param \Drupal\Core\Entity\EntityTypeManagerInterface $entity_type_manager
   *   The entity type manager.
   */
  public function __construct(EntityTypeManagerInterface $entity_type_manager) {
    $this->entityTypeManager = $entity_type_manager;
  }

  /**
   * {@inheritdoc}
   */
  public static function getSubscribedEvents() {
    return [
      OrderEvents::ORDER_UPDATE => 'onOrderUpdate',
    ];
  }

  /**
   * {@inheritdoc}
   */
  public function destruct() {
    foreach ($this->updateList as $intent_id => $amount) {
      try {
        $intent = PaymentIntent::retrieve($intent_id);

        // You may only update the amount of a PaymentIntent with one of the
        // following statuses: requires_payment_method, requires_confirmation.
        if (in_array($intent->status, [
          PaymentIntent::STATUS_REQUIRES_PAYMENT_METHOD,
          PaymentIntent::STATUS_REQUIRES_CONFIRMATION,
        ], TRUE)) {
          PaymentIntent::update($intent_id, [
            'amount' => $amount,
          ]);
        }
      } catch (StripeError $e) {

        // Allow sync errors to silently fail.
      }
    }
  }

  /**
   * Ensures the Stripe payment intent is up to date.
   *
   * @param \Drupal\commerce_order\Event\OrderEvent $event
   *   The event.
   */
  public function onOrderUpdate(OrderEvent $event) {
    $order = $event
      ->getOrder();
    $gateway = $order
      ->get('payment_gateway');
    if ($gateway
      ->isEmpty() || !$gateway->entity instanceof PaymentGatewayInterface) {
      return;
    }
    $plugin = $gateway->entity
      ->getPlugin();
    if (!$plugin instanceof StripeInterface) {
      return;
    }
    $intent_id = $order
      ->getData('stripe_intent');
    if ($intent_id === NULL) {
      return;
    }
    $total_price = $order
      ->getTotalPrice();
    if ($total_price !== NULL) {
      $amount = $this
        ->toMinorUnits($order
        ->getTotalPrice());
      $this->updateList[$intent_id] = $amount;
    }
  }

  /**
   * Converts the given amount to its minor units.
   *
   * For example, 9.99 USD becomes 999.
   *
   * @todo Remove after https://www.drupal.org/node/2944281 is fixed.
   *
   * @param \Drupal\commerce_price\Price $amount
   *   The amount.
   *
   * @return int
   *   The amount in minor units, as an integer.
   */
  protected function toMinorUnits(Price $amount) {
    $currency_storage = $this->entityTypeManager
      ->getStorage('commerce_currency');

    /** @var \Drupal\commerce_price\Entity\CurrencyInterface $currency */
    $currency = $currency_storage
      ->load($amount
      ->getCurrencyCode());
    $fraction_digits = $currency
      ->getFractionDigits();
    $number = $amount
      ->getNumber();
    if ($fraction_digits > 0) {
      $number = Calculator::multiply($number, pow(10, $fraction_digits));
    }
    return round($number, 0);
  }

}

Members

Namesort descending Modifiers Type Description Overrides
OrderPaymentIntentSubscriber::$entityTypeManager protected property The entity type manager.
OrderPaymentIntentSubscriber::$updateList protected property The intent IDs that need updating.
OrderPaymentIntentSubscriber::destruct public function Performs destruct operations. Overrides DestructableInterface::destruct 1
OrderPaymentIntentSubscriber::getSubscribedEvents public static function Returns an array of event names this subscriber wants to listen to.
OrderPaymentIntentSubscriber::onOrderUpdate public function Ensures the Stripe payment intent is up to date.
OrderPaymentIntentSubscriber::toMinorUnits protected function Converts the given amount to its minor units.
OrderPaymentIntentSubscriber::__construct public function Constructs a new OrderEventsSubscriber object.