mailchimp_ecommerce_ubercart.module in Mailchimp E-Commerce 7
Same filename and directory in other branches
Integrates Ubercart with Mailchimp eCommerce.
File
modules/mailchimp_ecommerce_ubercart/mailchimp_ecommerce_ubercart.moduleView 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'];
}
}