You are here

mailchimp_ecommerce_ubercart.module in Mailchimp E-Commerce 7

Integrates Ubercart with Mailchimp eCommerce.

File

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

/**
 * @file
 * Integrates Ubercart with Mailchimp eCommerce.
 */

/**
 * Implements hook_form_FORM_ID_alter().
 */
function mailchimp_ecommerce_ubercart_form_mailchimp_ecommerce_admin_settings_alter(&$form, &$form_state) {

  // Set default currently from Ubercart.
  $form['mailchimp_ecommerce_currency']['#default_value'] = variable_get('uc_currency_code', 'USD');

  // Identify Ubercart to Mailchimp.
  $form['platform']['#default_value'] = 'Drupal Ubercart';
  $form['sync']['orders'] = [
    '#markup' => '<br>' . l(t('Sync historical orders to Mailchimp'), 'admin/config/services/mailchimp/ecommerce/sync-orders'),
  ];
}

/**
 * Implements hook_node_insert().
 */
function mailchimp_ecommerce_ubercart_node_insert($node) {
  if (uc_product_is_product($node)) {

    // Create a corresponding Mailchimp product.
    $product = mailchimp_ecommerce_ubercart_get_product_values_from_node($node);

    // get variants
    $variants = mailchimp_ecommerce_ubercart_get_product_variant_values($product);

    // add base product
    mailchimp_ecommerce_add_product($product['id'], $product['variant_id'], $product['title'], $product['description'], $product['type'], $product['sku'], $product['url'], $product['price']);
  }

  // add variants
  if (!empty($variants)) {
    foreach ($variants as $variant) {

      // mailchimp_ecommerce_add_product() will add variants if product already exists
      mailchimp_ecommerce_add_product($product['id'], $variant['variant_id'], $variant['title'], $product['description'], $product['type'], $variant['sku'], $product['url'], $variant['price']);
    }
  }
}

/**
 * Returns an array of variant specific data from a product.
 *
 * @param $product
 *  array of product info from
 *   mailchimp_ecommerce_ubercart_get_product_values_from_node()
 *
 * @return array
 */
function mailchimp_ecommerce_ubercart_get_product_variant_values($product) {
  $variants = [];
  if (module_exists('uc_attribute')) {
    $attributes = uc_product_get_attributes($product['id']);

    // Get variant adjusted price, and modified title (from UC option name)
    $combinations = db_select('uc_product_adjustments', 'pa')
      ->fields('pa', [
      'combination',
      'model',
    ])
      ->condition('pa.nid', $product['id'])
      ->execute()
      ->fetchAllKeyed();
    foreach ($combinations as $serialized_combo => $sku) {
      $combo = unserialize($serialized_combo);
      $option_id = reset($combo);
      $attribute_id = key($combo);
      $variant_data = $attributes[$attribute_id]->options[$option_id];

      // store variant data for adding to MC API
      $variants[$sku]['variant_id'] = $sku;
      $variants[$sku]['sku'] = $sku;
      $variants[$sku]['title'] = $product['title'] . ' (' . $attributes[$attribute_id]->label . ': ' . $variant_data->name . ')';
      $variants[$sku]['price'] = $product['price'] + $variant_data->price;
    }
  }

  // Calling all modules implementing hook_mailchimp_ecommerce_ubercart_product_variant_alter():
  drupal_alter('mailchimp_ecommerce_ubercart_product_variant', $variants, $product);
  return $variants;
}

/**
 * Implements hook_node_update().
 */
function mailchimp_ecommerce_ubercart_node_update($node) {
  if (uc_product_is_product($node)) {

    // Update the corresponding Mailchimp product.
    $product = mailchimp_ecommerce_ubercart_get_product_values_from_node($node);

    // get variants
    $variants = mailchimp_ecommerce_ubercart_get_product_variant_values($product);

    // update base variant
    mailchimp_ecommerce_update_product($product['id'], $product['variant_id'], $product['title'], $product['description'], $product['sku'], $product['url'], $product['price']);

    // add variants
    if (!empty($variants)) {
      foreach ($variants as $variant) {
        mailchimp_ecommerce_update_product($product['id'], $variant['variant_id'], $variant['title'], $product['description'], $variant['sku'], $product['url'], $variant['price']);
      }
    }
  }
}

// TODO update product when Ubercart Attributes, Options, or Adjustments are saved

/**
 * Implements hook_node_delete().
 */
function mailchimp_ecommerce_ubercart_node_delete($node) {
  if (uc_product_is_product($node)) {

    // Delete the corresponding Mailchimp product.
    $product = mailchimp_ecommerce_ubercart_get_product_values_from_node($node);
    mailchimp_ecommerce_delete_product_variant($product['id'], $product['variant_id']);
  }
}

/**
 * Implements hook_mailchimp_ecommerce_add_store().
 */
function mailchimp_ecommerce_ubercart_mailchimp_ecommerce_add_store($store) {

  // Add existing Ubercart products to Mailchimp.
  $batch = [
    'title' => t('Adding products to Mailchimp'),
    'operations' => [],
  ];

  // select all nodes that are types of products
  $query = db_select('node', 'n')
    ->fields('n', [
    'nid',
  ]);
  $query
    ->join('node_type', 'nt', 'n.type = nt.type');
  $nids = $query
    ->condition('nt.base', [
    'uc_product',
    'uc_product_kit',
  ], 'IN')
    ->execute()
    ->fetchCol();
  $products = node_load_multiple($nids);
  if (!empty($products)) {
    $product_ids = array_keys($products);
    foreach ($product_ids as $product_id) {
      $batch['operations'][] = [
        'mailchimp_ecommerce_ubercart_batch_add_product',
        [
          $product_id,
        ],
      ];
    }
  }
  batch_set($batch);
}

/**
 * Implements hook_form_FORM_ID_alter().
 */
function mailchimp_ecommerce_ubercart_form_mailchimp_ecommerce_admin_sync_alter(&$form, &$form_state) {
  $form['#submit'][] = 'mailchimp_ecommerce_ubercart_admin_sync_submit';
}

/**
 * Submit handler for the Mailchimp eCommerce sync form.
 */
function mailchimp_ecommerce_ubercart_admin_sync_submit($form, &$form_state) {
  if (!empty($form_state['values']['sync_products'])) {
    $batch = [
      'title' => t('Adding products to Mailchimp'),
      'operations' => [],
    ];
    $result = db_select('uc_products', 'ucp')
      ->fields('ucp', [
      'nid',
    ])
      ->addTag('mailchimp_ecommerce_ubercart_product_sync')
      ->execute()
      ->fetchCol();
    if (count($result)) {
      $product_ids = array_unique($result);
      $batch['operations'][] = [
        'mailchimp_ecommerce_ubercart_batch_add_products',
        [
          $product_ids,
        ],
      ];
    }
    batch_set($batch);
  }
}

/**
 * Batch callback used to add products to Mailchimp.
 */
function mailchimp_ecommerce_ubercart_batch_add_products($product_ids, &$context) {
  if (!isset($context['sandbox']['progress'])) {
    $context['sandbox']['progress'] = 0;
    $context['sandbox']['total'] = count($product_ids);
    $context['results']['product_ids'] = $product_ids;
  }
  $batch_limit = variable_get('mailchimp_batch_limit', 100);
  $batch = array_slice($context['results']['product_ids'], $context['sandbox']['progress'], $batch_limit);
  foreach ($batch as $product_id) {
    $node = node_load($product_id);
    mailchimp_ecommerce_ubercart_node_insert($node);
    $context['sandbox']['progress']++;
    $context['message'] = t('Sent @count of @total products to Mailchimp', [
      '@count' => $context['sandbox']['progress'],
      '@total' => $context['sandbox']['total'],
    ]);
    $context['finished'] = $context['sandbox']['progress'] / $context['sandbox']['total'];
  }
}

/**
 * Gets Mailchimp product values from an Ubercart product node.
 *
 * @param object $node
 *   The Ubercart 'product' type node.
 *
 * @return array
 *   Array of product values for use with Mailchimp.
 */
function mailchimp_ecommerce_ubercart_get_product_values_from_node($node) {
  $node_wrapper = entity_metadata_wrapper('node', $node);
  $product = [
    'id' => $node_wrapper->nid
      ->value(),
    'variant_id' => $node_wrapper->model
      ->value(),
    'sku' => $node_wrapper->model
      ->value(),
    'title' => $node_wrapper->title
      ->value(),
    'url' => $alias = drupal_get_path_alias($node->nid),
    'description' => isset($node_wrapper->body
      ->value()['value']) ? $node_wrapper->body
      ->value()['value'] : '',
    'price' => $node_wrapper->sell_price
      ->value(),
    // TODO 'url' index is in here twice. Figure out which one is correct.
    'url' => _mailchimp_ecommerce_ubercart_build_product_url($node_wrapper->nid
      ->value()),
    'type' => mailchimp_ecommerce_get_node_type_name($node_wrapper
      ->getBundle()),
  ];
  return $product;
}

/**
 * Implements hook_uc_order().
 */
function mailchimp_ecommerce_ubercart_uc_order($op, $order) {
  if ($op == 'new') {
    $mc_order = mailchimp_ecommerce_ubercart_build_order($order);

    // Do nothing with no email.
    if (!$mc_order['customer']['email_address']) {
      return;
    }
    if ($order->order_status == 'in_checkout') {

      // Ubercart doesn't create an entity for a customer, so we create
      // a customer in Mailchimp at the same time as the cart.
      if (mailchimp_ecommerce_get_customer($order->uid)) {
        mailchimp_ecommerce_update_customer($mc_order['customer']);
      }
      else {
        mailchimp_ecommerce_add_customer($mc_order['customer']);
      }

      // Create new cart in Mailchimp.
      mailchimp_ecommerce_add_cart($order->order_id, $mc_order['customer'], $mc_order['order_data']);
    }
    else {

      // Create new order in Mailchimp.
      mailchimp_ecommerce_add_order($order->order_id, $mc_order['customer'], $mc_order['order_data']);
    }
  }
  elseif ($op == 'save') {
    $mc_order = mailchimp_ecommerce_ubercart_build_order($order);
    if ($order->order_status == 'in_checkout') {

      // Update cart in Mailchimp.
      mailchimp_ecommerce_update_cart($order->order_id, $mc_order['customer'], $mc_order['order_data']);
    }
    else {
      if (!empty(mailchimp_ecommerce_get_order($order->order_id))) {

        // Update existing order in Mailchimp.
        mailchimp_ecommerce_update_order($order->order_id, $mc_order['order_data']);
      }
    }
  }
  elseif ($op == 'update') {
    if ($order->order_status == 'in_checkout') {
      $mc_order = mailchimp_ecommerce_ubercart_build_order($order);

      // Convert cart to order in Mailchimp.
      mailchimp_ecommerce_delete_cart($order->order_id);
      mailchimp_ecommerce_add_order($order->order_id, $mc_order['customer'], $mc_order['order_data']);
    }
  }
}

/**
 * Builds a Mailchimp order from an Ubercart order.
 *
 * @param UcOrder $order
 *   The Ubercart order.
 *
 * @return object
 *   Order object in a Mailchimp-friendly format.
 */
function mailchimp_ecommerce_ubercart_build_order($order) {
  $currency_code = $order->currency;
  $order_total = '';
  $discount_total = 0;
  $processed_at_foreign = $order->created;
  $lines = [];
  $billing_address = mailchimp_ecommerce_ubercart_parse_billing_address($order);
  $billing_address->name = $order->billing_first_name . ' ' . $order->billing_last_name;
  $billing_address->company = $order->billing_company;
  $order_total = uc_order_get_total($order);
  if (empty($order->products)) {

    // carts needs separate product lookup
    $products = uc_cart_get_contents();
  }
  else {

    // completed orders are loaded with products
    $products = $order->products;
  }
  if (!empty($products)) {
    foreach ($products as $product) {
      if (isset($product->module) && $product->module === "uc_coupon") {

        // calculate discount_total for order
        $discount_total += $product->price;
      }
      else {
        $line = [
          'id' => isset($product->cart_item_id) ? $product->cart_item_id : $product->order_product_id,
          'product_id' => $product->nid,
          'product_variant_id' => $product->model,
          'quantity' => (int) $product->qty,
          'price' => $product->price,
        ];
        $lines[] = $line;
      }
    }
  }
  $customer_id = _mailchimp_ecommerce_get_local_customer($order->primary_email);
  $customer = [
    'id' => $customer_id,
    'email_address' => $order->primary_email,
    'first_name' => $order->billing_first_name,
    'last_name' => $order->billing_last_name,
    'address' => mailchimp_ecommerce_ubercart_parse_billing_address($order),
  ];
  $order_data = [
    'currency_code' => $currency_code,
    'order_total' => $order_total,
    'discount_total' => abs($discount_total),
    'billing_address' => $billing_address,
    'processed_at_foreign' => date('c', $processed_at_foreign),
    'lines' => $lines,
  ];
  return [
    'customer' => $customer,
    'order_data' => $order_data,
  ];
}

/**
 * Parses a billing address from an Ubercart order.
 *
 * @param object $order
 *   The Ubercart order.
 *
 * @return object
 *   An address object formatted for use with Mailchimp.
 */
function mailchimp_ecommerce_ubercart_parse_billing_address($order) {
  $country = uc_get_country_data([
    'country_id' => $order->billing_country,
  ]);
  $country_code = isset($country[0]) ? $country[0]['country_iso_code_3'] : '';
  $province_code = uc_get_zone_code($order->billing_zone);
  $address = (object) [
    'address1' => $order->billing_street1,
    'address2' => $order->billing_street2,
    'city' => $order->billing_city,
    'province_code' => $province_code !== FALSE ? $province_code : '',
    'postal_code' => $order->billing_postal_code,
    'country_code' => $country_code,
  ];
  return $address;
}

// TODO: Implement mailchimp_ecommerce_update_customer()
// TODO: Implement mailchimp_ecommerce_delete_customer()
// TODO: Implement mailchimp_ecommerce_get_customer()

/**
 * Creates a URL from a product, as long as the product is referenced by a node.
 *
 * @param object $product
 *   The Commerce object.
 *
 * @return string
 *   The URL of the node referencing the product.
 */
function _mailchimp_ecommerce_ubercart_build_product_url($nid) {
  $url = url('node/' . $nid, [
    'absolute' => TRUE,
  ]);
  return $url;
}

/**
 * Implements hook_form_FORM_ID_alter().
 */
function mailchimp_ecommerce_ubercart_form_mailchimp_ecommerce_admin_sync_orders_alter(&$form, &$form_state) {
  $form['#submit'][] = 'mailchimp_ecommerce_ubercart_admin_sync_orders_submit';
}

/**
 * Submit handler for the Mailchimp eCommerce sync form.
 */
function mailchimp_ecommerce_ubercart_admin_sync_orders_submit($form, &$form_state) {
  if (!empty($form_state['values']['sync_orders'])) {
    $batch = [
      'title' => t('Adding orders to Mailchimp'),
      'operations' => [],
    ];

    // get completed orders within specified time period (months)
    $months = abs(intval($form_state['values']['timespan'])) * -1;
    $min_timestamp = strtotime($months . ' months');
    $result = db_select('uc_orders', 'o')
      ->fields('o', [
      'order_id',
    ])
      ->condition('o.created', $min_timestamp, '>')
      ->execute()
      ->fetchCol();
    if (count($result)) {
      $order_ids = array_unique($result);
      $batch['operations'][] = [
        'mailchimp_ecommerce_ubercart_batch_add_orders',
        [
          $order_ids,
        ],
      ];
    }
    batch_set($batch);
  }
}

/**
 * Batch callback used to add orders to Mailchimp.
 */
function mailchimp_ecommerce_ubercart_batch_add_orders($order_ids, &$context) {
  if (!isset($context['sandbox']['progress'])) {
    $context['sandbox']['progress'] = 0;
    $context['sandbox']['total'] = count($order_ids);
    $context['results']['order_ids'] = $order_ids;
    $context['sandbox']['current_order'] = 0;
  }
  $batch_limit = variable_get('mailchimp_batch_limit', 100);
  $batch = array_slice($context['results']['order_ids'], $context['sandbox']['progress'], $batch_limit);
  $orders = uc_order_load_multiple($batch);
  foreach ($orders as $order) {
    $context['sandbox']['current_order'] = $order->order_id;
    $mc_order = mailchimp_ecommerce_ubercart_build_order($order);

    // create customer if they do not already exist
    $customer = mailchimp_ecommerce_get_customer($mc_order['customer']['id']);
    if ($customer) {
      mailchimp_ecommerce_update_customer($mc_order['customer']);
    }
    else {
      mailchimp_ecommerce_add_customer($mc_order['customer']);
    }

    // check if the order exists so we can call the correct endpoint.
    if ($order->order_status == 'pending' || $order->order_status == 'completed') {
      $order_exists = mailchimp_ecommerce_get_order($order->order_id);
      if ($order_exists) {
        mailchimp_ecommerce_update_order($order->order_id, $mc_order['order_data']);
      }
      else {
        mailchimp_ecommerce_add_order($order->order_id, $mc_order['customer'], $mc_order['order_data']);
      }
    }
    else {
      $cart = mailchimp_ecommerce_get_cart($order->order_id);
      if ($cart) {
        mailchimp_ecommerce_update_cart($order->order_id, $mc_order['customer'], $mc_order['order_data']);
      }
      else {
        mailchimp_ecommerce_add_cart($order->order_id, $mc_order['customer'], $mc_order['order_data']);
      }
    }
    $context['sandbox']['progress']++;
    $context['message'] = t('Sent @count of @total orders to Mailchimp', [
      '@count' => $context['sandbox']['progress'],
      '@total' => $context['sandbox']['total'],
    ]);
    $context['finished'] = $context['sandbox']['progress'] / $context['sandbox']['total'];
  }
}

Functions

Namesort descending Description
mailchimp_ecommerce_ubercart_admin_sync_orders_submit Submit handler for the Mailchimp eCommerce sync form.
mailchimp_ecommerce_ubercart_admin_sync_submit Submit handler for the Mailchimp eCommerce sync form.
mailchimp_ecommerce_ubercart_batch_add_orders Batch callback used to add orders to Mailchimp.
mailchimp_ecommerce_ubercart_batch_add_products Batch callback used to add products to Mailchimp.
mailchimp_ecommerce_ubercart_build_order Builds a Mailchimp order from an Ubercart order.
mailchimp_ecommerce_ubercart_form_mailchimp_ecommerce_admin_settings_alter Implements hook_form_FORM_ID_alter().
mailchimp_ecommerce_ubercart_form_mailchimp_ecommerce_admin_sync_alter Implements hook_form_FORM_ID_alter().
mailchimp_ecommerce_ubercart_form_mailchimp_ecommerce_admin_sync_orders_alter Implements hook_form_FORM_ID_alter().
mailchimp_ecommerce_ubercart_get_product_values_from_node Gets Mailchimp product values from an Ubercart product node.
mailchimp_ecommerce_ubercart_get_product_variant_values Returns an array of variant specific data from a product.
mailchimp_ecommerce_ubercart_mailchimp_ecommerce_add_store Implements hook_mailchimp_ecommerce_add_store().
mailchimp_ecommerce_ubercart_node_delete Implements hook_node_delete().
mailchimp_ecommerce_ubercart_node_insert Implements hook_node_insert().
mailchimp_ecommerce_ubercart_node_update Implements hook_node_update().
mailchimp_ecommerce_ubercart_parse_billing_address Parses a billing address from an Ubercart order.
mailchimp_ecommerce_ubercart_uc_order Implements hook_uc_order().
_mailchimp_ecommerce_ubercart_build_product_url Creates a URL from a product, as long as the product is referenced by a node.