No such customer

Created on 13 December 2022, about 2 years ago
Updated 25 January 2023, almost 2 years ago

Problem/Motivation

The problem is that when Stripe is trying to create a payment method Drupal checks in DB (in user__commerce_remote_id table) if the user has a customer_id from Stripe and when it is found in DB it tries to attach that customer to a payment method, but at that point, the customer_id does not exist in Stripe (it was deleted for some reason) and the remaining execution of script was stopped.

/modules/contrib/commerce_stripe/src/Plugin/Commerce/PaymentGateway/Stripe.php

protected function doCreatePaymentMethod(PaymentMethodInterface $payment_method, array $payment_details) {
  $stripe_payment_method_id = $payment_details['stripe_payment_method_id'];
  $owner = $payment_method->getOwner();
  $customer_id = NULL;
  if ($owner && $owner->isAuthenticated()) {
    $customer_id = $this->getRemoteCustomerId($owner); // Here it checks for commerce_remote_id, see the 'getRemoteCustomerId' function below.
  }
  try {
    $stripe_payment_method = PaymentMethod::retrieve($stripe_payment_method_id);
    if ($customer_id) {
      $stripe_payment_method->attach(['customer' => $customer_id]);
      $email = $owner->getEmail();
    }
    // If the user is authenticated, created a Stripe customer to attach the
    // payment method to.
    elseif ($owner && $owner->isAuthenticated()) {
      $email = $owner->getEmail();
      $customer = Customer::create([
        'email' => $email,
        'description' => $this->t('Customer for :mail', [':mail' => $email]),
        'payment_method' => $stripe_payment_method_id,
      ]);
      $customer_id = $customer->id;
      $this->setRemoteCustomerId($owner, $customer_id);
      $owner->save();
    }
    else {
      $email = NULL;
    }

    if ($customer_id && $email) {
      $payment_method_data = [
        'email' => $email,
      ];
      if ($billing_profile = $payment_method->getBillingProfile()) {
        $billing_address = $billing_profile->get('address')->first()->toArray();
        $payment_method_data['address'] = [
          'city' => $billing_address['locality'],
          'country' => $billing_address['country_code'],
          'line1' => $billing_address['address_line1'],
          'line2' => $billing_address['address_line2'],
          'postal_code' => $billing_address['postal_code'],
          'state' => $billing_address['administrative_area'],
        ];
        $payment_method_data['name'] = $billing_address['given_name'] . ' ' . $billing_address['family_name'];
      }
      PaymentMethod::update($stripe_payment_method_id, ['billing_details' => $payment_method_data]);
    }
  }
  catch (ApiErrorException $e) {
    ErrorHelper::handleException($e);
  }
  return $stripe_payment_method->card;
}
/modules/contrib/commerce/modules/payment/src/Plugin/Commerce/PaymentGateway/PaymentGatewayBase.php

public function getRemoteCustomerId(UserInterface $account) {
  $remote_id = NULL;
  if ($account->isAuthenticated()) {
    $provider = $this->parentEntity->id() . '|' . $this->getMode();
    /** @var \Drupal\commerce\Plugin\Field\FieldType\RemoteIdFieldItemListInterface $remote_ids */
    $remote_ids = $account->get('commerce_remote_id');
    $remote_id = $remote_ids->getByProvider($provider);
    // Gateways used to key customer IDs by module name, migrate that data.
    if (!$remote_id) {
      $remote_id = $remote_ids->getByProvider($this->pluginDefinition['provider']);
      if ($remote_id) {
        $remote_ids->setByProvider($this->pluginDefinition['provider'], NULL);
        $remote_ids->setByProvider($provider, $remote_id);
        $account->save();
      }
    }
  }

  return $remote_id;
}

Steps to reproduce

  1. To have wrong Stripe customer id in db table user__commerce_remote_id on column commerce_remote_id_remote_id
  2. Try to make payment
  3. Observe result

Proposed solution

The solution will be to check if the customer exists in Stripe, if not create a new customer and then continue further.

🐛 Bug report
Status

Active

Component

Code

Created by

🇦🇲Armenia alen simonyan

Live updates comments and jobs are added and updated live.
Sign in to follow issues

Comments & Activities

Not all content is available!

It's likely this issue predates Contrib.social: some issue and comment data are missing.

  • 🇬🇧United Kingdom jonathanshaw Stroud, UK

    I dislike the way the solution here always loads the remote customer; that's a call against Stripe's remote API and therefore slow.

    I'd prefer it if we could try/catch the error that happens if the customer does not exist, and fix & retry.

Production build 0.71.5 2024