You are here

commerce_stripe_connect.module in Commerce Stripe 7.3

Adds support for Stripe Connect using a single site-wide client ID.

File

modules/commerce_stripe_connect/commerce_stripe_connect.module
View source
<?php

/**
 * @file
 * Adds support for Stripe Connect using a single site-wide client ID.
 */

/**
 * Implements hook_menu().
 */
function commerce_stripe_connect_menu() {
  $items = array();

  // Stripe platform administration.
  $items['admin/commerce/config/stripe-platform'] = array(
    'title' => 'Stripe platform configuration',
    'description' => 'Register platform data, set application fee, and view connected accounts.',
    'page callback' => 'drupal_get_form',
    'page arguments' => array(
      'commerce_stripe_platform_configuration_form',
    ),
    'access arguments' => array(
      'administer commerce stripe platform',
    ),
    'file' => 'includes/commerce_stripe_connect.admin.inc',
  );

  // Connect or revoke Stripe platform access for the site account.
  $items['admin/commerce/config/stripe-connect'] = array(
    'title' => 'Stripe account access',
    'description' => 'Manage your Standard Stripe account connection.',
    'page callback' => 'commerce_stripe_connect_admin_page',
    'access arguments' => array(
      'commerce stripe connect site',
    ),
    'file' => 'includes/commerce_stripe_connect.admin.inc',
  );
  $items['stripe-connect/oauth'] = array(
    'title' => 'Stripe Connect Redirect Authorization',
    'type' => MENU_CALLBACK,
    'page callback' => 'commerce_stripe_connect_authorize',
    'access callback' => 'commerce_stripe_connect_authorize_access',
  );
  return $items;
}

/**
 * Implements hook_permission().
 */
function commerce_stripe_connect_permission() {
  return array(
    'administer commerce stripe platform' => array(
      'title' => t('Administer Stripe platform settings'),
      'description' => t('Allows users to register platform data and view connected accounts.'),
      'restrict access' => TRUE,
    ),
    'commerce stripe connect site' => array(
      'title' => t('Connect site to Standard Stripe account'),
      'description' => t('Allows users to connect the site to a Standard Stripe account or revoke access to it.'),
      'restrict access' => TRUE,
    ),
  );
}

/**
 * Access callback: validates access to the Stripe Connect OAuth return URL.
 */
function commerce_stripe_connect_authorize_access() {
  if (empty($_GET['state'])) {
    return FALSE;
  }

  // Prevent CSRF attacks with token verification.
  if (drupal_valid_token(check_plain($_GET['state']))) {
    return TRUE;
  }
  return FALSE;
}

/**
 * Page callback: processes a Stripe Connect OAuth return.
 */
function commerce_stripe_connect_authorize() {

  // Error response.
  if (!empty($_GET['error'])) {

    // Malformed URL.
    if (empty($_GET['error_description'])) {
      drupal_not_found();
    }
    drupal_set_message(check_plain($_GET['error_description']), 'error');
    drupal_goto('admin/commerce/config/stripe-connect');
  }

  // Verify that the URL includes scope and code values.
  if (empty($_GET['scope']) || empty($_GET['code'])) {
    drupal_not_found();
  }

  // Verify that the scope is read-write.
  if ($_GET['scope'] != 'read_write') {
    drupal_set_message(t('Stripe connect integration requires read/write access.'), 'error');
    drupal_goto('admin/commerce/config/stripe-connect');
  }

  // All is well. Get the authorization code and fetch user's credentials.
  $authorization_code = check_plain($_GET['code']);
  $client_secret = commerce_stripe_connect_get_setting('platform_secret_key', '');
  $ch = curl_init();
  curl_setopt_array($ch, array(
    CURLOPT_URL => 'https://connect.stripe.com/oauth/token',
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_HTTPHEADER => array(
      'Authorization: Bearer ' . $client_secret,
    ),
    CURLOPT_POST => TRUE,
    CURLOPT_POSTFIELDS => http_build_query(array(
      'client_secret' => $client_secret,
      'code' => $authorization_code,
      'grant_type' => 'authorization_code',
    )),
  ));
  $response = curl_exec($ch);
  $response_body = drupal_json_decode($response);
  if (!empty($response_body['error'])) {
    drupal_set_message(check_plain($response_body['error_description']), 'error');
    drupal_goto('admin/commerce/config/stripe-connect');
  }

  // Malformed data.
  if (empty($response_body['stripe_user_id']) || empty($response_body['access_token']) || empty($response_body['stripe_publishable_key'])) {
    drupal_not_found();
  }

  // Set the connected account ID and API credentials.
  commerce_stripe_connect_set_setting('connected_account_id', check_plain($response_body['stripe_user_id']));
  commerce_stripe_connect_set_setting('connected_secret_key', check_plain($response_body['access_token']));
  commerce_stripe_connect_set_setting('connected_public_key', check_plain($response_body['stripe_publishable_key']));

  // Redirect to the Stripe Connect page.
  drupal_set_message(t('Your site has been connected to your Standard Stripe account.'));
  drupal_goto('admin/commerce/config/stripe-connect');
}

/**
 * Implements hook_commerce_stripe_order_charge_alter().
 */
function commerce_stripe_connect_commerce_stripe_order_charge_alter(&$charge, $order) {

  // If developers use hook to specify a different application fee, do not overwrite.
  if (!empty($charge['application_fee'])) {
    return;
  }

  // Check that connected account is being used for API requests.
  if (empty($order->payment_method_settings['use_connected_account']) || $order->payment_method_settings['use_connected_account'] != 'site account') {
    return;
  }

  // Calculate and add application fee to the charge.
  $connect_settings = commerce_stripe_connect_get_settings();
  if ($connect_settings['application_fee_method'] == 'percentage') {
    if (empty($connect_settings['application_fee_percentage'])) {
      return;
    }
    $fee = $charge['amount'] * $connect_settings['application_fee_percentage'] / 100;
    $fee = (int) round($fee);
  }
  else {
    if (empty($connect_settings['application_fee_amount'])) {
      return;
    }
    $fee = commerce_currency_decimal_to_amount($connect_settings['application_fee_amount'], $charge['currency']);
  }
  if ($fee > 0) {

    // Maximum fee is order total charge minus 2.9% + $0.30 (the Stripe transaction fee).
    $stripe_fee = (int) round(0.029 * $charge['amount'] + 30);
    $max_fee = $charge['amount'] - $stripe_fee;
    $charge['application_fee'] = min($fee, $max_fee);
  }
}

/**
 * Implements hook_form_FORM_ID_alter().
 *
 * Provide option to proportionally refund application fees.
 */
function commerce_stripe_connect_form_commerce_stripe_refund_form_alter(&$form, &$form_state, $form_id) {

  // Ensure the original transaction actually has transaction fees.
  $transaction = $form_state['transaction'];
  if (!empty($transaction->payload)) {
    $timestamp = key($transaction->payload);
    $payload = json_decode($transaction->payload[$timestamp]);
    if (!empty($payload->application_fee)) {
      $form['refund_application_fee'] = array(
        '#type' => 'checkbox',
        '#title' => t('Proportionally refund any application fees.'),
        '#default_value' => TRUE,
        '#weight' => 2,
      );
      $form['actions']['#weight'] = 3;
    }
  }
}

/**
 * Implements hook_commerce_stripe_order_refund_alter().
 */
function commerce_stripe_connect_commerce_stripe_order_refund_alter(&$refund, $form_state) {

  // If developers use hook to specify a refund application fee setting, do not overwrite.
  if (!empty($refund['refund_application_fee'])) {
    return;
  }
  if (!empty($form_state['values']['refund_application_fee'])) {
    $refund['refund_application_fee'] = true;
  }
}

/**
 * Returns the default settings for the Stripe Connect module.
 */
function commerce_stripe_connect_default_settings() {
  return array(
    'platform_client_id' => '',
    'platform_secret_key' => '',
    'webhook_signing_secret' => '',
    'application_fee_method' => 'percentage',
    'application_fee_percentage' => '0',
    'application_fee_amount' => '0',
    'platform_currency' => '',
    'connected_account_id' => '',
    'connected_secret_key' => '',
    'connected_public_key' => '',
  );
}

/**
 * Returns the Stripe Connect settings as an associative array.
 */
function commerce_stripe_connect_get_settings() {
  return variable_get('commerce_stripe_connect_settings', commerce_stripe_connect_default_settings()) + commerce_stripe_connect_default_settings();
}

/**
 * Returns the Stripe Connect setting value for the given setting key.
 */
function commerce_stripe_connect_get_setting($key, $default_value = NULL) {
  $settings = commerce_stripe_connect_get_settings();
  return isset($settings[$key]) ? $settings[$key] : $default_value;
}

/**
 * Set the value for the given Stripe Connect setting key.
 */
function commerce_stripe_connect_set_setting($key, $value) {
  $settings = commerce_stripe_connect_get_settings();
  $settings[$key] = $value;
  variable_set('commerce_stripe_connect_settings', $settings);
}

Functions

Namesort descending Description
commerce_stripe_connect_authorize Page callback: processes a Stripe Connect OAuth return.
commerce_stripe_connect_authorize_access Access callback: validates access to the Stripe Connect OAuth return URL.
commerce_stripe_connect_commerce_stripe_order_charge_alter Implements hook_commerce_stripe_order_charge_alter().
commerce_stripe_connect_commerce_stripe_order_refund_alter Implements hook_commerce_stripe_order_refund_alter().
commerce_stripe_connect_default_settings Returns the default settings for the Stripe Connect module.
commerce_stripe_connect_form_commerce_stripe_refund_form_alter Implements hook_form_FORM_ID_alter().
commerce_stripe_connect_get_setting Returns the Stripe Connect setting value for the given setting key.
commerce_stripe_connect_get_settings Returns the Stripe Connect settings as an associative array.
commerce_stripe_connect_menu Implements hook_menu().
commerce_stripe_connect_permission Implements hook_permission().
commerce_stripe_connect_set_setting Set the value for the given Stripe Connect setting key.