You are here

class StripeGateway in Ubercart Stripe 8.3

Same name and namespace in other branches
  1. 8.2 src/Plugin/Ubercart/PaymentMethod/StripeGateway.php \Drupal\uc_stripe\Plugin\Ubercart\PaymentMethod\StripeGateway

Stripe Ubercart gateway payment method.

Plugin annotation


@UbercartPaymentMethod(
  id = "stripe_gateway",
  name = @Translation("Stripe gateway"),
)

Hierarchy

Expanded class hierarchy of StripeGateway

File

src/Plugin/Ubercart/PaymentMethod/StripeGateway.php, line 19

Namespace

Drupal\uc_stripe\Plugin\Ubercart\PaymentMethod
View source
class StripeGateway extends CreditCardPaymentMethodBase {

  /**
   * {@inheritdoc}
   */
  public function defaultConfiguration() {
    return parent::defaultConfiguration() + [
      'txn_type' => UC_CREDIT_AUTH_CAPTURE,
      'test_secret_key' => '',
      'test_publishable_key' => '',
      'live_secret_key' => '',
      'live_publishable_key' => '',
      'testmode' => TRUE,
    ];
  }

  /**
   * {@inheritdoc}
   */
  public function buildConfigurationForm(array $form, FormStateInterface $form_state) {
    $form = parent::buildConfigurationForm($form, $form_state);
    $form['test_secret_key'] = array(
      '#type' => 'textfield',
      '#title' => t('Test Secret Key'),
      '#default_value' => $this->configuration['test_secret_key'],
      '#description' => t('Your Development Stripe API Key. Must be the "secret" key, not the "publishable" one.'),
    );
    $form['test_publishable_key'] = array(
      '#type' => 'textfield',
      '#title' => t('Test Publishable Key'),
      '#default_value' => $this->configuration['test_publishable_key'],
      '#description' => t('Your Development Stripe API Key. Must be the "publishable" key, not the "secret" one.'),
    );
    $form['live_secret_key'] = array(
      '#type' => 'textfield',
      '#title' => t('Live Secret Key'),
      '#default_value' => $this->configuration['live_secret_key'],
      '#description' => t('Your Live Stripe API Key. Must be the "secret" key, not the "publishable" one.'),
    );
    $form['live_publishable_key'] = array(
      '#type' => 'textfield',
      '#title' => t('Live Publishable Key'),
      '#default_value' => $this->configuration['live_publishable_key'],
      '#description' => t('Your Live Stripe API Key. Must be the "publishable" key, not the "secret" one.'),
    );
    $form['testmode'] = array(
      '#type' => 'checkbox',
      '#title' => t('Test mode'),
      '#description' => 'Testing Mode: Stripe will use the development API key to process the transaction so the card will not actually be charged.',
      '#default_value' => $this->configuration['testmode'],
    );
    return $form;
  }
  public function validateConfigurationForm(array &$form, FormStateInterface $form_state) {
    $elements = [
      'test_secret_key',
      'test_publishable_key',
      'live_secret_key',
      'live_publishable_key',
    ];
    foreach ($elements as $element_name) {
      $raw_key = $form_state
        ->getValue([
        'settings',
        $element_name,
      ]);
      $sanitized_key = $this
        ->trimKey($raw_key);
      $form_state
        ->setValue([
        'settings',
        $element_name,
      ], $sanitized_key);
      if (!$this
        ->validateKey($form_state
        ->getValue([
        'settings',
        $element_name,
      ]))) {
        $form_state
          ->setError($form[$element_name], t('@name does not appear to be a valid stripe key', array(
          '@name' => $element_name,
        )));
      }
    }
    parent::validateConfigurationForm($form, $form_state);
  }
  protected function trimKey($key) {
    $key = trim($key);
    $key = \Drupal\Component\Utility\Html::escape($key);
    return $key;
  }

  /**
   * Validate Stripe key
   *
   * @param $key
   * @return boolean
   */
  public static function validateKey($key) {
    $valid = preg_match('/^[a-zA-Z0-9_]+$/', $key);
    return $valid;
  }

  /**
   * {@inheritdoc}
   */
  public function submitConfigurationForm(array &$form, FormStateInterface $form_state) {
    foreach ([
      'test_secret_key',
      'test_publishable_key',
      'live_secret_key',
      'live_publishable_key',
      'testmode',
    ] as $item) {
      $this->configuration[$item] = $form_state
        ->getValue($item);
    }
    return parent::submitConfigurationForm($form, $form_state);
  }
  public function cartDetails(OrderInterface $order, array $form, FormStateInterface $form_state) {
    $form = parent::cartDetails($order, $form, $form_state);
    $apikey = $this->configuration['testmode'] ? $this->configuration['test_publishable_key'] : $this->configuration['live_publishable_key'];
    $stripe_is_enabled = TRUE;
    $form['#attached']['drupalSettings']['uc_stripe']['publishable_key'] = $apikey;

    // NOTE: This value seems routinely not to get to the JS
    $form['#attached']['drupalSettings']['uc_stripe']['stripe_is_enabled'] = $stripe_is_enabled;

    // Add custom JS and CSS
    $form['#attached']['library'][] = 'uc_stripe/uc_stripe';
    $form['stripe_nojs_warning'] = array(
      '#type' => 'item',
      '#markup' => '<span id="stripe-nojs-warning" class="stripe-warning">' . t('Sorry, for security reasons your card cannot be processed because Javascript is disabled in your browser.') . '</span>',
      '#weight' => -1000,
    );
    $form['stripe_token'] = array(
      '#type' => 'hidden',
      '#default_value' => 'default',
      '#attributes' => array(
        'id' => 'edit-panes-payment-details-stripe-token',
      ),
    );

    // Prevent form Credit card fill and submission if javascript has not removed
    // the "disabled" attributes..
    // If JS happens to be disabled, we don't want user to be able to enter CC data.
    // Note that we can't use '#disabled', as it causes Form API to discard all input,
    // so use the disabled attribute instead.
    $form['cc_number']['#attributes']['disabled'] = 'disabled';
    if (empty($form['actions']['continue']['#attributes'])) {
      $form['actions']['continue']['#attributes'] = array();
    }
    $form['actions']['continue']['#attributes']['disabled'] = 'disabled';

    // Add custom submit which will do saving away of token during submit.
    //    $form['#submit'][] = 'uc_stripe_checkout_form_customsubmit';
    // Add a section for stripe.js error messages (CC validation, etc.)
    $form['messages'] = array(
      '#markup' => "<div class='uc-stripe-messages messages error hidden'></div>",
    );
    if ($this->configuration['testmode']) {
      $form['testmode'] = [
        '#prefix' => "<div class='messages uc-stripe-testmode'>",
        '#markup' => $this
          ->t('Test mode is <strong>ON</strong> for the Ubercart Stripe Payment Gateway. Your  card will not be charged. To change this setting, edit the payment method at @link.', [
          '@link' => Link::createFromRoute(t('payment method settings'), 'entity.uc_payment_method.collection')
            ->toString(),
        ]),
        '#suffix' => "</div>",
      ];
    }
    return $form;
  }
  public function cartProcess(OrderInterface $order, array $form, FormStateInterface $form_state) {
    $stripe_token_val = $form_state
      ->getValue([
      'panes',
      'payment',
      'details',
      'stripe_token',
    ]);
    if (!empty($stripe_token_val)) {
      \Drupal::service('user.private_tempstore')
        ->get('uc_stripe')
        ->set('uc_stripe_token', $stripe_token_val);
    }
    return parent::cartProcess($order, $form, $form_state);

    // TODO: Change the autogenerated stub
  }

  /**
   * {@inheritdoc}
   */
  protected function chargeCard(OrderInterface $order, $amount, $txn_type, $reference = NULL) {
    $user = \Drupal::currentUser();
    if (!$this
      ->prepareApi()) {
      $result = array(
        'success' => FALSE,
        'comment' => t('Stripe API not found.'),
        'message' => t('Stripe API not found. Contact the site administrator.'),
        'uid' => $user
          ->id(),
        'order_id' => $order
          ->id(),
      );
      return $result;
    }

    // Format the amount in cents, which is what Stripe wants
    $amount = uc_currency_format($amount, FALSE, FALSE, FALSE);
    $stripe_customer_id = FALSE;

    // If the user running the order is not the order's owner
    // (like if an admin is processing an order on someone's behalf)
    // then load the customer ID from the user object.
    // Otherwise, make a brand new customer each time a user checks out.
    if ($user
      ->id() != $order
      ->getOwnerId()) {
      $stripe_customer_id = $this
        ->getStripeCustomerID($order
        ->id());
    }

    // Always Create a new customer in stripe for new orders
    if (!$stripe_customer_id) {
      try {

        // If the token is not in the user's session, we can't set up a new customer
        $stripe_token = \Drupal::service('user.private_tempstore')
          ->get('uc_stripe')
          ->get('uc_stripe_token');
        if (empty($stripe_token)) {
          throw new \Exception('Token not found');
        }

        //Create the customer in stripe
        $customer = \Stripe\Customer::create(array(
          "source" => $stripe_token,
          'description' => "OrderID: {$order->id()}",
          'email' => $order
            ->getEmail(),
        ));

        // Store the customer ID in temp storage,
        // We'll pick it up later to save it in the database since we might not have a $user object at this point anyway
        \Drupal::service('user.private_tempstore')
          ->get('uc_stripe')
          ->set('uc_stripe_customer_id', $customer->id);
      } catch (Exception $e) {
        $result = array(
          'success' => FALSE,
          'comment' => $e
            ->getCode(),
          'message' => t("Stripe Customer Creation Failed for order !order: !message", array(
            "!order" => $order
              ->id(),
            "!message" => $e
              ->getMessage(),
          )),
          'uid' => $user
            ->id(),
          'order_id' => $order
            ->id(),
        );
        uc_order_comment_save($order
          ->id(), $user
          ->id(), $result['message']);
        \Drupal::logger('uc_stripe')
          ->notice('Failed stripe customer creation: @message', array(
          '@message' => $result['message'],
        ));
        $message = $this
          ->t('Credit card charge failed.');
        uc_order_comment_save($order
          ->id(), $user
          ->id(), $message, 'admin');
        return $result;
      }

      // Charge the customer

      //--Handle transactions for $0

      // Stripe can't handle transactions < $0.50, but $0 is a common value
      // so we will just return a positive result when the amount is $0.
      if ($amount == 0) {
        $result = array(
          'success' => TRUE,
          'message' => t('Payment of 0 approved'),
          'uid' => $user->uid,
          'trans_id' => md5(uniqid(rand())),
        );
        uc_order_comment_save($order
          ->id(), $user
          ->id(), $result['message'], 'admin');
        return $result;
      }
      try {

        // charge the Customer the amount in the order
        $currency = \Drupal::config('uc_store.settings')
          ->get('currency')['code'];
        $charge = \Stripe\Charge::create(array(
          "amount" => $amount,
          "currency" => strtolower($currency),
          "customer" => $customer->id,
          "description" => t("Order #@order_id", array(
            "@order_id" => $order
              ->id(),
          )),
        ));
        $formatted_amount = $amount / 100;
        $formatted_amount = number_format($formatted_amount, 2);
        $message = $this
          ->t('Credit card charged: @amount', [
          '@amount' => $formatted_amount,
        ]);
        uc_order_comment_save($order
          ->id(), $user
          ->id(), $message, 'admin');
        $result = array(
          'success' => TRUE,
          'comment' => $this
            ->t('Card charged, resolution code: 0022548315'),
          'message' => $this
            ->t('Credit card payment processed successfully.'),
          'uid' => $user
            ->id(),
        );
        return $result;
      } catch (Exception $e) {
        $result = array(
          'success' => FALSE,
          'comment' => $e
            ->getCode(),
          'message' => t("Stripe Charge Failed for order !order: !message", array(
            "!order" => $order
              ->id(),
            "!message" => $e
              ->getMessage(),
          )),
          'uid' => $user->uid,
          'order_id' => $order
            ->id(),
        );
        uc_order_comment_save($order
          ->id(), $user->uid, $result['message'], 'admin');
        watchdog('uc_stripe', 'Stripe charge failed for order @order, message: @message', array(
          '@order' => $order
            ->id(),
          '@message' => $result['message'],
        ));
        return $result;
      }

      //  Default / Fallback procedure to fail if the above conditions aren't met
      $result = array(
        'success' => FALSE,
        'comment' => "Stripe Gateway Error",
        'message' => "Stripe Gateway Error",
        'uid' => $user->uid,
        'order_id' => $order
          ->id(),
      );
      uc_order_comment_save($order
        ->id(), $user->uid, $result['message'], 'admin');
      watchdog('uc_stripe', 'Stripe gateway error for order @order_id', array(
        'order_id' => $order
          ->id(),
      ));
      return $result;
    }
  }

  /**
   * Utility function: Load stripe API
   *
   * @return bool
   */
  public function prepareApi() {

    // Not clear that this is useful since payment config form forces at least some config
    if (!_uc_stripe_check_api_keys($this
      ->getConfiguration())) {
      \Drupal::logger('uc_stripe')
        ->error('Stripe API keys are not configured. Payments cannot be made without them.', array());
      return FALSE;
    }
    $secret_key = $this->configuration['testmode'] ? $this->configuration['test_secret_key'] : $this->configuration['live_secret_key'];
    try {
      \Stripe\Stripe::setApiKey($secret_key);
    } catch (Exception $e) {
      \Drupal::logger('uc_stripe')
        ->notice('Error setting the Stripe API Key. Payments will not be processed: %error', array(
        '%error' => $e
          ->getMessage(),
      ));
    }
    return TRUE;
  }

  /**
   * @param string $number
   * @return bool
   */
  protected function validateCardNumber($number) {

    // Do nothing - let Stripe validate the number
    return TRUE;
  }

  /**
   * @param string $cvv
   * @return bool
   */
  protected function validateCvv($cvv) {

    // Do nothing - let Stripe validate the CVV
    return TRUE;
  }

  /**
   * Retrieve the Stripe customer id for a user
   *
   * @param $uid
   * @return string|NULL
   */
  function getStripeCustomerID($uid) {

    /** @var \Drupal\user\UserDataInterface $userdata_container */
    $userdata_container = \Drupal::getContainer('user.data');
    $id = $userdata_container
      ->get('uc_stripe', $uid, 'uc_stripe_customer_id');
    return $id;
  }

}

Members

Namesort descending Modifiers Type Description Overrides
CreditCardPaymentMethodBase::cartReview public function Returns the payment method review details. Overrides PaymentMethodPluginBase::cartReview
CreditCardPaymentMethodBase::cartReviewTitle public function Returns the payment method title to be used on the checkout review page. Overrides PaymentMethodPluginBase::cartReviewTitle
CreditCardPaymentMethodBase::customerView public function Called when an order is being viewed by a customer. Overrides PaymentMethodPluginBase::customerView
CreditCardPaymentMethodBase::displayCardNumber protected function Returns a credit card number with appropriate masking.
CreditCardPaymentMethodBase::getDisplayLabel public function Returns the payment method label with logo. Overrides PaymentMethodPluginBase::getDisplayLabel
CreditCardPaymentMethodBase::getEnabledFields public function Returns the set of fields which are used by this payment method.
CreditCardPaymentMethodBase::getEnabledTypes public function Returns the set of card types which are used by this payment method.
CreditCardPaymentMethodBase::getTransactionTypes public function Returns the set of transaction types allowed by this payment method. 1
CreditCardPaymentMethodBase::orderEditDetails public function Called when an order is being edited with this payment method. Overrides PaymentMethodPluginBase::orderEditDetails
CreditCardPaymentMethodBase::orderLoad public function Called when an order is being loaded with this payment method. Overrides PaymentMethodPluginBase::orderLoad
CreditCardPaymentMethodBase::orderSave public function Called when an order is being saved with this payment method. Overrides PaymentMethodPluginBase::orderSave
CreditCardPaymentMethodBase::orderSubmit public function Called when an order is being submitted with this payment method. Overrides PaymentMethodPluginBase::orderSubmit
CreditCardPaymentMethodBase::orderView public function Called when an order is being viewed by an administrator. Overrides PaymentMethodPluginBase::orderView
CreditCardPaymentMethodBase::processPayment public function Process a payment through the credit card gateway.
CreditCardPaymentMethodBase::validateExpirationDate protected function Validates an expiration date on a card.
CreditCardPaymentMethodBase::validateIssueNumber protected function Validates an issue number on a card.
CreditCardPaymentMethodBase::validateStartDate protected function Validates a start date on a card.
DependencySerializationTrait::$_entityStorages protected property An array of entity type IDs keyed by the property name of their storages.
DependencySerializationTrait::$_serviceIds protected property An array of service IDs keyed by property name used for serialization.
DependencySerializationTrait::__sleep public function 1
DependencySerializationTrait::__wakeup public function 2
MessengerTrait::$messenger protected property The messenger. 29
MessengerTrait::messenger public function Gets the messenger. 29
MessengerTrait::setMessenger public function Sets the messenger.
PaymentMethodPluginBase::$database protected property The database service.
PaymentMethodPluginBase::create public static function Creates an instance of the plugin. Overrides ContainerFactoryPluginInterface::create
PaymentMethodPluginBase::getConfiguration public function Gets this plugin's configuration. Overrides ConfigurableInterface::getConfiguration
PaymentMethodPluginBase::orderDelete public function Called when an order is being deleted. Overrides PaymentMethodPluginInterface::orderDelete 1
PaymentMethodPluginBase::orderEditProcess public function Called when an order is being submitted after being edited. Overrides PaymentMethodPluginInterface::orderEditProcess 1
PaymentMethodPluginBase::setConfiguration public function Sets the configuration for this plugin instance. Overrides ConfigurableInterface::setConfiguration
PaymentMethodPluginBase::__construct public function Constructs the PaymentMethodPluginBase object. Overrides PluginBase::__construct
PluginBase::$configuration protected property Configuration information passed into the plugin. 1
PluginBase::$pluginDefinition protected property The plugin implementation definition. 1
PluginBase::$pluginId protected property The plugin_id.
PluginBase::DERIVATIVE_SEPARATOR constant A string which is used to separate base plugin IDs from the derivative ID.
PluginBase::getBaseId public function Gets the base_plugin_id of the plugin instance. Overrides DerivativeInspectionInterface::getBaseId
PluginBase::getDerivativeId public function Gets the derivative_id of the plugin instance. Overrides DerivativeInspectionInterface::getDerivativeId
PluginBase::getPluginDefinition public function Gets the definition of the plugin implementation. Overrides PluginInspectionInterface::getPluginDefinition 3
PluginBase::getPluginId public function Gets the plugin_id of the plugin instance. Overrides PluginInspectionInterface::getPluginId
PluginBase::isConfigurable public function Determines if the plugin is configurable.
StringTranslationTrait::$stringTranslation protected property The string translation service. 1
StringTranslationTrait::formatPlural protected function Formats a string containing a count of items.
StringTranslationTrait::getNumberOfPlurals protected function Returns the number of plurals supported by a given language.
StringTranslationTrait::getStringTranslation protected function Gets the string translation service.
StringTranslationTrait::setStringTranslation public function Sets the string translation service to use. 2
StringTranslationTrait::t protected function Translates a string to the current language or to a given language.
StripeGateway::buildConfigurationForm public function Form constructor. Overrides CreditCardPaymentMethodBase::buildConfigurationForm
StripeGateway::cartDetails public function Returns the form or render array to be displayed at checkout. Overrides CreditCardPaymentMethodBase::cartDetails
StripeGateway::cartProcess public function Called when checkout is submitted with this payment method selected. Overrides CreditCardPaymentMethodBase::cartProcess
StripeGateway::chargeCard protected function Called when a credit card should be processed. Overrides CreditCardPaymentMethodBase::chargeCard
StripeGateway::defaultConfiguration public function Gets default configuration for this plugin. Overrides CreditCardPaymentMethodBase::defaultConfiguration
StripeGateway::getStripeCustomerID function Retrieve the Stripe customer id for a user
StripeGateway::prepareApi public function Utility function: Load stripe API
StripeGateway::submitConfigurationForm public function Form submission handler. Overrides CreditCardPaymentMethodBase::submitConfigurationForm
StripeGateway::trimKey protected function
StripeGateway::validateCardNumber protected function Overrides CreditCardPaymentMethodBase::validateCardNumber
StripeGateway::validateConfigurationForm public function Form validation handler. Overrides PaymentMethodPluginBase::validateConfigurationForm
StripeGateway::validateCvv protected function Overrides CreditCardPaymentMethodBase::validateCvv
StripeGateway::validateKey public static function Validate Stripe key