mailchimp_ecommerce_commerce.module in Mailchimp E-Commerce 7
Same filename and directory in other branches
Integrates Drupal Commerce with Mailchimp eCommerce.
File
modules/mailchimp_ecommerce_commerce/mailchimp_ecommerce_commerce.moduleView source
<?php
/**
* @file
* Integrates Drupal Commerce with Mailchimp eCommerce.
*/
/**
* Implements hook_form_FORM_ID_alter().
*/
function mailchimp_ecommerce_commerce_form_mailchimp_ecommerce_admin_settings_alter(&$form, &$form_state) {
// Set default currently from Commerce.
$form['mailchimp_ecommerce_currency']['#default_value'] = commerce_default_currency();
$form['product'] = [
'#type' => 'fieldset',
'#title' => t('Products'),
'#description' => t("This information is used to determine the URLs of products on this website. if a product is referenced by a node, that node's URL will be sent to Mailchimp as part of the product information."),
'#collapsible' => FALSE,
];
$node_type_options = $node_field_options = [
'' => '-- Select --',
];
$image_field_options = $image_styles = [
'' => '-- Select --',
];
$description_field_options = [
'' => '-- Select --',
];
$node_types = node_type_get_names();
foreach ($node_types as $node_type => $node_name) {
$node_type_options[$node_type] = $node_name;
}
$product_node_type = variable_get('mailchimp_ecommerce_product_node_type', '');
$form['product']['mailchimp_ecommerce_product_node_type'] = [
'#type' => 'select',
'#options' => $node_type_options,
'#title' => t('Product content type'),
'#description' => t('Select the content type used to display products on your site.'),
'#default_value' => $product_node_type,
'#ajax' => [
'callback' => 'mailchimp_ecommerce_commerce_admin_settings_form_ajax_callback',
'wrapper' => 'node-field-wrapper',
],
];
if (empty($product_node_type)) {
$product_node_type = !empty($form_state['values']['mailchimp_ecommerce_product_node_type']) ? $form_state['values']['mailchimp_ecommerce_product_node_type'] : NULL;
}
$product_image_types = [];
// List product reference fields.
if (!empty($product_node_type)) {
$field_info = field_info_instances('node', $product_node_type);
if (!empty($field_info)) {
foreach ($field_info as $field_name => $properties) {
// Only list product reference fields.
if (isset($properties['settings']['referenceable_types'])) {
$node_field_options[$field_name] = $properties['label'];
// Track referenceable product variation types for this field.
$product_image_types += array_filter($properties['settings']['referenceable_types']);
}
if (isset($properties['settings']['text_processing'])) {
$description_field_options[$field_name] = $properties['label'];
}
// Include image fields from product display types.
$field = field_info_field($field_name);
if ($field['type'] == 'image' || $field['type'] == 'file') {
$image_field_options[$field['field_name']] = t('@label (product display)', array(
'@label' => $properties['label'],
));
}
}
}
}
$form['product']['mailchimp_ecommerce_product_node_field'] = [
'#type' => 'select',
'#options' => $node_field_options,
'#title' => t('Product reference field'),
'#description' => t('Select the product reference field used on the above content type.'),
'#default_value' => variable_get('mailchimp_ecommerce_product_node_field', ''),
'#prefix' => '<div id="node-field-wrapper">',
'#suffix' => '</div>',
];
// Since each product variant can have its own image, inform Mailchimp
// about any image fields that exist on our enabled product types.
foreach ($product_image_types as $product_image_type) {
foreach (field_info_instances('commerce_product', $product_image_type) as $field_name => $properties) {
$field = field_info_field($field_name);
if ($field['type'] == 'image' || $field['type'] == 'file') {
$image_field_options[$field['field_name']] = $properties['label'];
}
}
}
$form['product']['mailchimp_ecommerce_commerce_image_field'] = [
'#type' => 'select',
'#options' => $image_field_options,
'#title' => t('Product image field'),
'#description' => t('Select the image field used on the above content type.'),
'#default_value' => variable_get('mailchimp_ecommerce_commerce_image_field', ''),
'#prefix' => '<div id="node-field-wrapper">',
'#suffix' => '</div>',
];
$image_styles = image_style_options(FALSE);
$form['product']['mailchimp_ecommerce_commerce_image_style'] = [
'#type' => 'select',
'#empty_option' => t('None (original image)'),
'#multiple' => FALSE,
'#options' => $image_styles,
'#title' => t('Image style'),
'#description' => t('The image style to use when sending product images to Mailchimp.'),
'#default_value' => variable_get('mailchimp_ecommerce_commerce_image_style', ''),
];
$form['product']['mailchimp_ecommerce_description_field'] = [
'#type' => 'select',
'#options' => $description_field_options,
'#title' => t('Description textfield'),
'#description' => t('Select the description text field used on the above content type.'),
'#default_value' => variable_get('mailchimp_ecommerce_description_field', ''),
'#prefix' => '<div id="node-field-wrapper">',
'#suffix' => '</div>',
];
// If Stock modules are detected, show the admin some options for
// handling inventory quantities.
// @todo: Allow for any other known Stock modules.
if (module_exists('commerce_stock')) {
$form['stock'] = [
'#type' => 'fieldset',
'#title' => t('Inventory'),
'#description' => t("Stock module detected. The Fixed Inventory Amount will be used for any products that do not have stock fields configured."),
'#collapsible' => FALSE,
];
$form['stock']['mailchimp_ecommerce_use_fixed_inventory'] = [
'#type' => 'checkbox',
'#title' => t('Use fixed inventory'),
'#description' => t('Enable to set the Fixed Inventory Amount for all products regardless of stock availability.'),
'#default_value' => variable_get('mailchimp_ecommerce_use_fixed_inventory', FALSE),
];
$form['stock']['mailchimp_ecommerce_fixed_inventory_amount'] = [
'#type' => 'textfield',
'#title' => t('Fixed inventory amount'),
'#default_value' => variable_get('mailchimp_ecommerce_fixed_inventory_amount', 1),
];
}
// Identify Drupal Commerce to Mailchimp.
$form['platform']['#default_value'] = 'Drupal Commerce';
// Sync historical orders
$form['sync']['orders'] = [
'#markup' => '<br>' . l(t('Sync historical orders to MailChimp'), 'admin/config/services/mailchimp/ecommerce/sync-orders'),
];
// Validate our settings.
$form['#validate'][] = 'mailchimp_ecommerce_commerce_admin_validate';
}
/**
* Validation handler for our admin settings form.
*/
function mailchimp_ecommerce_commerce_admin_validate(&$form, &$form_state) {
// Make sure the inventory amount is an integer.
$amount = isset($form_state['values']['mailchimp_ecommerce_fixed_inventory_amount']) ? $form_state['values']['mailchimp_ecommerce_fixed_inventory_amount'] : '';
if (!empty($amount) && !is_numeric($amount) && !is_int($amount)) {
form_set_error('mailchimp_ecommerce_fixed_inventory_amount', 'Inventory amount must be an integer.');
return FALSE;
}
// If a blank string was passed in, reset the variable to our default.
if ($amount == '') {
$form_state['values']['mailchimp_ecommerce_fixed_inventory_amount'] = 1;
}
}
/**
* Callback for AJAX request triggered by checkbox to toggle advanced UI on/off.
*/
function mailchimp_ecommerce_commerce_admin_settings_form_ajax_callback($form, &$form_state) {
return $form['product']['mailchimp_ecommerce_product_node_field'];
}
/**
* Implements hook_form_FORM_ID_alter().
*/
function mailchimp_ecommerce_commerce_form_mailchimp_ecommerce_admin_sync_alter(&$form, &$form_state) {
$form['#submit'][] = 'mailchimp_ecommerce_commerce_admin_sync_submit';
}
/**
* Submit handler for the Mailchimp eCommerce sync form.
*/
function mailchimp_ecommerce_commerce_admin_sync_submit($form, &$form_state) {
if (!empty($form_state['values']['sync_products'])) {
$batch = [
'title' => t('Adding products to Mailchimp'),
'operations' => [],
];
$query = new EntityFieldQuery();
$result = $query
->entityCondition('entity_type', 'commerce_product')
->addTag('mailchimp_ecommerce_commerce_product_sync')
->execute();
if (isset($result['commerce_product'])) {
$product_ids = array_keys($result['commerce_product']);
$batch['operations'][] = [
'mailchimp_ecommerce_commerce_batch_add_products',
[
$product_ids,
],
];
}
batch_set($batch);
}
}
/**
* Batch callback used to add products to Mailchimp.
*/
function mailchimp_ecommerce_commerce_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) {
$product = commerce_product_load($product_id);
mailchimp_ecommerce_commerce_commerce_product_insert($product);
$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'];
}
}
/**
* Implements hook_commerce_order_update().
*
* When an in-progress cart order changes status, notify
* Mailchimp if we're configured to do so.
*/
function mailchimp_ecommerce_commerce_commerce_order_update($order) {
$send_carts = variable_get('mailchimp_ecommerce_send_carts', FALSE);
$cart_states = array_keys(commerce_order_statuses([
'state' => 'cart',
]));
$checkout_states = array_keys(commerce_order_statuses([
'state' => 'checkout',
]));
// Only send a cart if we are in cart or checkout status, and the status has changed.
if (in_array($order->status, $cart_states) || in_array($order->status, $checkout_states)) {
if ($send_carts == TRUE && $order->original->status != $order->status) {
// @todo: Handle admin-created orders.
_mailchimp_ecommerce_commerce_send_cart($order);
}
}
else {
// Not a cart; update the order.
$order_wrapper = entity_metadata_wrapper('commerce_order', $order);
$mc_order = _mailchimp_ecommerce_commerce_build_order($order_wrapper);
mailchimp_ecommerce_update_order($order->order_id, $mc_order['order_data']);
}
}
/**
* Implements hook_commerce_order_delete().
*/
function mailchimp_ecommerce_commerce_commerce_order_delete($order) {
// If this order was completed, it is an MC Order.
$post_checkout = array_keys(commerce_order_statuses([
'state' => 'completed',
]));
if (in_array($order->status, $post_checkout)) {
mailchimp_ecommerce_delete_order($order->order_id);
}
else {
mailchimp_ecommerce_delete_cart($order->order_id);
}
}
/**
* Implements hook_commerce_cart_product_add().
*/
function mailchimp_ecommerce_commerce_commerce_cart_product_add($order, $product, $quantity, $line_item) {
$send_carts = variable_get('mailchimp_ecommerce_send_carts', FALSE);
// Do not send Carts to Mailchimp if we're not configured to.
if ($send_carts == FALSE) {
return;
}
// If this order is new, that means this is the first line item;
// send the entire cart to Mailchimp first.
if ($order->created == $order->changed) {
_mailchimp_ecommerce_commerce_send_cart($order);
}
else {
$line_item_wrapper = entity_metadata_wrapper('commerce_line_item', $line_item);
$cart_product = [
'product_id' => $product->product_id,
'product_variant_id' => $product->sku,
'quantity' => (int) $quantity,
'price' => commerce_currency_amount_to_decimal($line_item_wrapper->commerce_unit_price->amount
->value(), $line_item_wrapper->commerce_unit_price->currency_code
->value()),
];
mailchimp_ecommerce_add_cart_line($order->order_id, $line_item->line_item_id, $cart_product);
}
}
/**
* Implements hook_commerce_cart_product_remove().
*
* Removing a product from a shopping cart requires
* deleting the cartLine from Mailchimp.
*/
function mailchimp_ecommerce_commerce_commerce_cart_product_remove($order, $product, $quantity, $line_item) {
$send_carts = variable_get('mailchimp_ecommerce_send_carts', FALSE);
// Do not send Carts to Mailchimp if we're not configured to.
if ($send_carts == FALSE) {
return;
}
mailchimp_ecommerce_delete_cart_line($order->order_id, $line_item->line_item_id);
}
/**
* Implements hook_commerce_line_item_update().
*/
function mailchimp_ecommerce_commerce_commerce_line_item_update($line_item) {
$send_carts = variable_get('mailchimp_ecommerce_send_carts', FALSE);
// Do not send Carts to Mailchimp if we're not configured to.
if ($send_carts == FALSE) {
return;
}
$line_item_wrapper = entity_metadata_wrapper('commerce_line_item', $line_item);
if (in_array($line_item_wrapper->type
->value(), commerce_product_line_item_types())) {
$product = $line_item_wrapper->commerce_product
->value();
$mc_product = [
'product_id' => $product->product_id,
'product_variant_id' => $product->sku,
'quantity' => (int) $line_item->quantity,
'price' => commerce_currency_amount_to_decimal($line_item_wrapper->commerce_unit_price->amount
->value(), $line_item_wrapper->commerce_unit_price->currency_code
->value()),
];
mailchimp_ecommerce_update_cart_line($line_item->order_id, $line_item->line_item_id, $mc_product);
}
}
/**
* Implements hook_commerce_customer_profile_insert().
*/
function mailchimp_ecommerce_commerce_commerce_customer_profile_insert($customer_profile) {
$first_name = '';
$last_name = '';
if (!($customer_email = _mailchimp_ecommmerce_commerce_get_customer_email($customer_profile))) {
return;
}
$customer_id = _mailchimp_ecommerce_get_local_customer($customer_email);
$customer_profile_wrapper = entity_metadata_wrapper('commerce_customer_profile', $customer_profile);
if (isset($customer_profile_wrapper->commerce_customer_address) && !empty($customer_profile_wrapper->commerce_customer_address
->value()) && isset($customer_profile_wrapper->commerce_customer_address->first_name, $customer_profile_wrapper->commerce_customer_address->last_name)) {
$first_name = $customer_profile_wrapper->commerce_customer_address->first_name
->value();
$last_name = $customer_profile_wrapper->commerce_customer_address->last_name
->value();
}
$customer = [
'id' => $customer_id,
'email_address' => $customer_email,
'first_name' => $first_name,
'last_name' => $last_name,
'address' => mailchimp_ecommerce_commerce_parse_customer_profile_address($customer_profile_wrapper),
];
if (mailchimp_ecommerce_get_customer($customer_id)) {
mailchimp_ecommerce_update_customer($customer);
}
else {
mailchimp_ecommerce_add_customer($customer);
}
// Update the cart with the customer information, if customer profile exists.
if (isset($customer_profile->entity_context['entity_id']) && !empty($customer_profile->entity_context['entity_id'])) {
$order_id = $customer_profile->entity_context['entity_id'];
$order = commerce_order_load($order_id);
$order_wrapper = entity_metadata_wrapper('commerce_order', $order);
$mc_order = _mailchimp_ecommerce_commerce_build_order($order_wrapper);
mailchimp_ecommerce_update_cart($order->order_id, $mc_order['customer'], $mc_order['order_data']);
}
}
/**
* Implements hook_commerce_customer_profile_update().
*/
function mailchimp_ecommerce_commerce_commerce_customer_profile_update($customer_profile) {
$first_name = '';
$last_name = '';
if (isset($customer_profile->entity_context['entity_id'])) {
$order_id = $customer_profile->entity_context['entity_id'];
}
else {
return;
}
if (!($customer_email = _mailchimp_ecommmerce_commerce_get_customer_email($customer_profile))) {
return;
}
$customer_id = _mailchimp_ecommerce_get_local_customer($customer_email);
$customer_profile_wrapper = entity_metadata_wrapper('commerce_customer_profile', $customer_profile);
if (isset($customer_profile_wrapper->commerce_customer_address) && !empty($customer_profile_wrapper->commerce_customer_address
->value()) && isset($customer_profile_wrapper->commerce_customer_address->first_name, $customer_profile_wrapper->commerce_customer_address->last_name)) {
$first_name = $customer_profile_wrapper->commerce_customer_address->first_name
->value();
$last_name = $customer_profile_wrapper->commerce_customer_address->last_name
->value();
}
$customer = [
'id' => $customer_id,
'email_address' => $customer_email,
'first_name' => $first_name,
'last_name' => $last_name,
'address' => mailchimp_ecommerce_commerce_parse_customer_profile_address($customer_profile_wrapper),
];
if (mailchimp_ecommerce_get_customer($customer_id)) {
mailchimp_ecommerce_update_customer($customer);
}
else {
mailchimp_ecommerce_add_customer($customer);
}
// Update the order with the customer information.
$order = commerce_order_load($order_id);
$order_wrapper = entity_metadata_wrapper('commerce_order', $order);
$mc_order = _mailchimp_ecommerce_commerce_build_order($order_wrapper);
// TODO: Restore when this function supports orders that are not carts.
//mailchimp_ecommerce_update_cart($order->order_id, $mc_order['customer'], $mc_order['order_data']);
}
/**
* Implements hook_commerce_customer_profile_delete().
*/
function mailchimp_ecommerce_commerce_commerce_customer_profile_delete($customer_profile) {
}
/**
* Implements hook_commerce_cart_order_refresh().
*/
function mailchimp_ecommerce_commerce_commerce_cart_order_refresh($order_wrapper) {
}
/**
* Helper to pull the customer email address from a profile.
*/
function _mailchimp_ecommmerce_commerce_get_customer_email($customer_profile) {
$customer_email = '';
if ($customer_profile->uid != 0) {
$account = user_load($customer_profile->uid);
$customer_email = $account->mail;
}
else {
if (!empty($customer_profile->entity_context['entity_id'])) {
$order_id = $customer_profile->entity_context['entity_id'];
$order = commerce_order_load($order_id);
if ($order) {
$customer_email = $order->mail;
}
}
elseif (!empty($_POST['account']['login']['mail'])) {
$customer_email = check_plain($_POST['account']['login']['mail']);
}
}
return $customer_email;
}
/**
* Implements hook_commerce_checkout_complete().
*/
function mailchimp_ecommerce_commerce_commerce_checkout_complete($order) {
$order_wrapper = entity_metadata_wrapper('commerce_order', $order);
$mc_order = _mailchimp_ecommerce_commerce_build_order($order_wrapper);
// 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']);
}
/**
* Implements hook_node_insert().
*
* When a node gets created, send it to Mailchimp.
*/
function mailchimp_ecommerce_commerce_node_insert($node) {
$product_node_type = variable_get('mailchimp_ecommerce_product_node_type', '');
if (!empty($product_node_type) && $node->type == $product_node_type) {
// See if the configured product field exists.
$field = variable_get('mailchimp_ecommerce_product_node_field', '');
if (!empty($field) && isset($node->{$field}) && !empty($node->{$field})) {
$wrapper = entity_metadata_wrapper('node', $node);
// Only add a product if one is already referenced in the field.
if ($products = $wrapper->{$field}
->value()) {
foreach ($products as $product) {
mailchimp_ecommerce_commerce_commerce_product_insert($product);
}
}
}
}
}
/**
* Implements hook_node_update().
*
* Update a node at Mailchimp when it is updated.
*/
function mailchimp_ecommerce_commerce_node_update($node) {
$product_node_type = variable_get('mailchimp_ecommerce_product_node_type', '');
if (!empty($product_node_type) && $node->type == $product_node_type) {
// See if the configured product field exists.
$field = variable_get('mailchimp_ecommerce_product_node_field', '');
// If the product reference field exists and has data, loop through
// the associated product IDs, looking for all product display nodes.
if (!empty($field) && isset($node->{$field}) && !empty($node->{$field})) {
$wrapper = entity_metadata_wrapper('node', $node);
$ids = $wrapper->{$field}
->raw();
if (!empty($ids)) {
foreach (array_values($ids) as $product_id) {
$query = new EntityFieldQuery();
$query
->entityCondition('entity_type', 'node')
->entityCondition('bundle', $product_node_type)
->fieldCondition($field, 'product_id', $product_id)
->propertyCondition('status', TRUE);
$result = $query
->execute();
// Update our available products.
if (!empty($result['node'])) {
$product = commerce_product_load($product_id);
mailchimp_ecommerce_commerce_commerce_product_update($product);
}
}
}
}
}
}
/**
* Implements hook_node_delete().
*
* Delete a product at Mailchimp, but only if no other nodes are referencing it.
*/
function mailchimp_ecommerce_commerce_node_delete($node) {
$product_node_type = variable_get('mailchimp_ecommerce_product_node_type', '');
if (!empty($product_node_type) && $node->type == $product_node_type) {
// See if the configured product field exists.
$field = variable_get('mailchimp_ecommerce_product_node_field', '');
if (!empty($field) && isset($node->{$field}) && !empty($node->{$field})) {
$wrapper = entity_metadata_wrapper('node', $node);
$ids = $wrapper->{$field}
->raw();
// Find all product IDs referenced in our configured field.
if (!empty($ids)) {
foreach (array_values($ids) as $product_id) {
$query = new EntityFieldQuery();
$query
->entityCondition('entity_type', 'node')
->entityCondition('bundle', $product_node_type)
->propertyCondition('nid', $node->nid, '<>')
->fieldCondition($field, 'product_id', $product_id)
->propertyCondition('status', TRUE);
$result = $query
->execute();
// If no other nodes reference this product, we can delete it.
if (empty($result['node'])) {
$product = commerce_product_load($product_id);
mailchimp_ecommerce_commerce_commerce_product_delete($product);
}
}
}
}
}
}
/**
* Implements hook_commerce_product_insert().
*/
function mailchimp_ecommerce_commerce_commerce_product_insert($product) {
$product_wrapper = entity_metadata_wrapper('commerce_product', $product);
$price = commerce_currency_amount_to_decimal($product_wrapper->commerce_price->amount
->value(), $product_wrapper->commerce_price->currency_code
->value());
$url = _mailchimp_ecommerce_commerce_build_product_url($product);
$image_url = _mailchimp_ecommerce_commerce_build_image_url($product);
$stock = _mailchimp_ecommerce_commerce_get_inventory($product);
$description = _mailchimp_ecommerce_commerce_get_description($product);
// TODO: Get product description from product display, if available.
mailchimp_ecommerce_add_product($product->product_id, $product->sku, $product->title, $description, $product->type, $product->sku, $url, $price, $image_url, $stock);
}
/**
* Implements hook_commerce_product_update().
*/
function mailchimp_ecommerce_commerce_commerce_product_update($product) {
$product_wrapper = entity_metadata_wrapper('commerce_product', $product);
$price = commerce_currency_amount_to_decimal($product_wrapper->commerce_price->amount
->value(), $product_wrapper->commerce_price->currency_code
->value());
$url = _mailchimp_ecommerce_commerce_build_product_url($product);
$image_url = _mailchimp_ecommerce_commerce_build_image_url($product);
$stock = _mailchimp_ecommerce_commerce_get_inventory($product);
$description = _mailchimp_ecommerce_commerce_get_description($product);
mailchimp_ecommerce_update_product($product->product_id, $product->sku, $product->title, $description, $product->sku, $url, $price, $image_url, $stock);
}
/**
* Implements hook_commerce_product_delete().
*/
function mailchimp_ecommerce_commerce_commerce_product_delete($product) {
mailchimp_ecommerce_delete_product_variant($product->product_id, $product->sku);
}
/**
* Implements hook_default_rules_configuration().
*/
function mailchimp_ecommerce_commerce_default_rules_configuration() {
$rules = [];
// Add a reaction rule to display the default Add to Cart message.
$rule = rules_reaction_rule();
$rule->label = t('Send cart to Mailchimp');
$rule->tags = [
'Commerce Cart',
];
$rule->active = TRUE;
$rule
->event('commerce_cart_product_add')
->event('commerce_cart_product_remove')
->action('mailchimp_ecommerce_commerce_send_cart', [
'commerce_order:select' => 'commerce-order',
]);
$rules['mailchimp_ecommerce_commerce_send_cart'] = $rule;
return $rules;
}
/**
* Implements hook_rules_action_info().
*/
function mailchimp_ecommerce_commerce_rules_action_info() {
$actions = [];
$actions['mailchimp_ecommerce_commerce_send_cart'] = [
'label' => t('Send a cart to Mailchimp'),
'parameter' => [
'commerce_order' => [
'type' => 'commerce_order',
'label' => t('Order to send'),
],
],
'group' => t('Commerce Order'),
'callbacks' => [
'execute' => '_mailchimp_ecommerce_commerce_send_cart',
],
];
return $actions;
}
/**
* Private function to send cart data to Mailchimp.
*/
function _mailchimp_ecommerce_commerce_send_cart($order) {
// Do nothing with no email
if (!$order->mail) {
return;
}
if (empty($order->commerce_line_items)) {
// Last line item has been deleted, remove the cart because you can't save
// an empty cart in Mailchimp.
mailchimp_ecommerce_delete_cart($order->order_id);
return;
}
$order_wrapper = entity_metadata_wrapper('commerce_order', $order);
$mc_order = _mailchimp_ecommerce_commerce_build_order($order_wrapper);
if ($order->created == $order->changed) {
mailchimp_ecommerce_add_cart($order->order_id, $mc_order['customer'], $mc_order['order_data']);
}
else {
mailchimp_ecommerce_update_cart($order->order_id, $mc_order['customer'], $mc_order['order_data']);
}
}
/**
* Parses an address from a Commerce customer profile.
*
* @param object $customer_profile_wrapper
* Commerce customer profile object.
*
* @return object
* Address object in a Mailchimp-friendly format.
*/
function mailchimp_ecommerce_commerce_parse_customer_profile_address($customer_profile_wrapper) {
$address = [];
if (isset($customer_profile_wrapper->commerce_customer_address) && !empty($customer_profile_wrapper->commerce_customer_address
->value()) && isset($customer_profile_wrapper->commerce_customer_address->thoroughfare, $customer_profile_wrapper->commerce_customer_address->premise, $customer_profile_wrapper->commerce_customer_address->locality, $customer_profile_wrapper->commerce_customer_address->administrative_area, $customer_profile_wrapper->commerce_customer_address->postal_code, $customer_profile_wrapper->commerce_customer_address->country)) {
$address = [
'address1' => $customer_profile_wrapper->commerce_customer_address->thoroughfare
->value(),
'address2' => $customer_profile_wrapper->commerce_customer_address->premise
->value(),
'city' => $customer_profile_wrapper->commerce_customer_address->locality
->value(),
'province_code' => $customer_profile_wrapper->commerce_customer_address->administrative_area
->value(),
'postal_code' => $customer_profile_wrapper->commerce_customer_address->postal_code
->value(),
'country_code' => $customer_profile_wrapper->commerce_customer_address->country
->value(),
];
}
return $address;
}
/**
* Builds a Mailchimp order from a Commerce order.
*
* @param object $order_wrapper
* Commerce order object wrapper.
*
* @return object
* Order object in a Mailchimp-friendly format.
*
* @throws Exception
* Throws an exception if Opt In Status is not set.
*/
function _mailchimp_ecommerce_commerce_build_order($order_wrapper) {
$store_domain = variable_get('mailchimp_ecommerce_store_domain', '');
$order = $order_wrapper
->value();
$cart_uri = commerce_checkout_order_uri($order);
$checkout_url = $store_domain ? $store_domain . '/' . $cart_uri : '';
$billing_address = [];
$processed_at_foreign = $order_wrapper->created
->value();
$lines = [];
if (isset($order_wrapper->mail)) {
$customer_email = $order_wrapper->mail
->value();
}
else {
$customer_email = check_plain($_POST['account']['login']['mail']);
}
$customer_id = _mailchimp_ecommerce_get_local_customer($customer_email);
if ($order_wrapper->commerce_order_total
->__isset('currency_code') && $order_wrapper->commerce_order_total->currency_code
->value()) {
$currency_code = $order_wrapper->commerce_order_total->currency_code
->value();
}
else {
$currency_code = commerce_default_currency();
}
$order_total = commerce_currency_amount_to_decimal($order_wrapper->commerce_order_total->amount
->value(), $currency_code);
$customer_wrapper = NULL;
if ($order_wrapper
->__isset('commerce_customer_billing') && $order_wrapper->commerce_customer_billing
->value()) {
$order_customer = commerce_customer_profile_load($order_wrapper->commerce_customer_billing
->getIdentifier());
$customer_wrapper = entity_metadata_wrapper('commerce_customer_profile', $order_customer);
// If a valid order customer was found, include the current address.
if ($customer_wrapper
->__isset('commerce_customer_address')) {
$billing_address = mailchimp_ecommerce_commerce_parse_customer_profile_address($customer_wrapper);
}
}
foreach ($order_wrapper->commerce_line_items as $delta => $line_item_wrapper) {
if (in_array($line_item_wrapper->type
->value(), commerce_product_line_item_types())) {
$products[] = $line_item_wrapper->commerce_product;
$line = [
'id' => (string) $line_item_wrapper
->getIdentifier(),
'product_id' => (string) $line_item_wrapper->commerce_product
->raw(),
'product_variant_id' => $line_item_wrapper->commerce_product->sku
->value(),
'quantity' => (int) $line_item_wrapper->quantity
->value(),
'price' => commerce_currency_amount_to_decimal($line_item_wrapper->commerce_unit_price->amount
->value(), $line_item_wrapper->commerce_unit_price->currency_code
->value()),
];
$lines[] = $line;
}
}
// Customer parameters used in the 'customer' portions of the API wrapper.
$customer = [
'id' => $customer_id,
'email_address' => $customer_email,
];
// Order parameters that are used as the 'cart' portions of the API wrapper.
$order_data = [
'checkout_url' => $checkout_url,
'currency_code' => $currency_code,
'order_total' => $order_total,
'billing_address' => $billing_address,
'processed_at_foreign' => date('c', $processed_at_foreign),
'lines' => $lines,
];
// Order parameters that are required for Order Notifications.
$order_status = $order_wrapper->status
->value();
$mc_order_statuses = mailchimp_ecommerce_get_mc_order_statuses($order_status);
if (!empty($mc_order_statuses['financial_status']) || !empty($mc_order_statuses['fulfillment_status'])) {
$order_data['landing_site'] = $_SERVER['HTTP_HOST'];
$order_data['financial_status'] = $mc_order_statuses['financial_status'];
$order_data['fulfillment_status'] = $mc_order_statuses['fulfillment_status'];
}
return [
'customer' => $customer,
'order_data' => $order_data,
];
}
/**
* 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_commerce_build_product_url($product) {
// Mailchimp will accept an empty string if no URL is available.
$url = '';
// Find the node associated with this product.
$product_node_type = variable_get('mailchimp_ecommerce_product_node_type', '');
$product_node_field = variable_get('mailchimp_ecommerce_product_node_field', '');
if (!empty($product_node_type) && !empty($product_node_field)) {
$query = new EntityFieldQuery();
$query
->entityCondition('entity_type', 'node')
->entityCondition('bundle', $product_node_type)
->fieldCondition($product_node_field, 'product_id', $product->product_id)
->propertyCondition('status', NODE_PUBLISHED);
$result = $query
->execute();
if (!empty($result) && !empty($result['node'])) {
$node = reset($result['node']);
$url = url('node/' . $node->nid, [
'absolute' => TRUE,
]);
}
}
return $url;
}
/**
* Creates an Image URL for a product variant.
*
* @param object $product
* The Commerce product entity.
*
* @return string
* The external URL of the stylized image.
*/
function _mailchimp_ecommerce_commerce_build_image_url($product) {
$image_field = variable_get('mailchimp_ecommerce_commerce_image_field', '');
$image_style = variable_get('mailchimp_ecommerce_commerce_image_style', '');
$image_url = '';
if (!empty($image_field)) {
$image = NULL;
$product_wrapper = entity_metadata_wrapper('commerce_product', $product);
if ($product_wrapper
->__isset($image_field) && $product_wrapper->{$image_field}
->value()) {
$image = $product_wrapper->{$image_field}
->value();
}
else {
$node_type = variable_get('mailchimp_ecommerce_product_node_type', '');
$product_reference_field = variable_get('mailchimp_ecommerce_product_node_field', '');
if (!empty($node_type) && !empty($product_reference_field)) {
$query = new EntityFieldQuery();
$query
->entityCondition('entity_type', 'node')
->entityCondition('bundle', $node_type)
->fieldCondition($product_reference_field, 'product_id', $product->product_id, '=')
->range(0, 1);
$result = $query
->execute();
if ($result && !empty($result['node'])) {
$node = array_pop($result['node']);
$node = node_load($node->nid);
if (isset($node->{$image_field}) && !empty($node->{$image_field})) {
$wrapper = entity_metadata_wrapper('node', $node);
if ($wrapper
->__isset($image_field) && $wrapper->{$image_field}
->value()) {
$image = $wrapper->{$image_field}
->value();
}
}
}
}
}
// @TODO: Check cardinality of image field, and send all available images.
if (is_array($image) && !isset($image['fid'])) {
$image = reset($image);
}
if (isset($image['fid'])) {
// Construct a public URL for this image.
// If the product is being added via a node form, we must load the new file.
$fid = $image['fid'];
$file = file_load($fid);
if (!empty($image_style)) {
$image_url = image_style_url($image_style, $file->uri);
}
else {
$image_url = file_create_url($file->uri);
}
}
}
return $image_url;
}
/**
* Get the description for a given product from its configured field.
*/
function _mailchimp_ecommerce_commerce_get_description($product) {
$description = '';
$field_name = variable_get('mailchimp_ecommerce_description_field', '');
$node_type = variable_get('mailchimp_ecommerce_product_node_type', '');
$product_node_field = variable_get('mailchimp_ecommerce_product_node_field', '');
if (!empty($field_name) && !empty($node_type) && !empty($product_node_field)) {
// Query the database to find the display node.
$query = new EntityFieldQuery();
$query
->entityCondition('entity_type', 'node')
->entityCondition('bundle', $node_type)
->fieldCondition($product_node_field, 'product_id', $product->product_id, '=')
->range(0, 1);
$result = $query
->execute();
if ($result && !empty($result['node'])) {
$node = array_pop($result['node']);
$node = node_load($node->nid);
if (isset($node->{$field_name}) && !empty($node->{$field_name})) {
$wrapper = entity_metadata_wrapper('node', $node);
$field_value = $wrapper->{$field_name}
->value();
if (is_array($field_value)) {
$description = strip_tags($field_value['value']);
}
else {
$description = strip_tags($field_value);
}
}
}
}
// Allow other modules to alter the description.
drupal_alter('mailchimp_ecommerce_product_description', $description, $product);
return $description;
}
/**
* Find the inventory of a given product.
*
* @param object $product
* The Commerce product.
*
* @return int
* The stock amount, or 1 if no options are configured.
*/
function _mailchimp_ecommerce_commerce_get_inventory($product) {
// A default inventory amount is required for product recommendations.
// Setting to 1 is a safe fallback in case no stock modules are enabled.
$inventory_amount = variable_get('mailchimp_ecommerce_fixed_inventory_amount', 1);
if (variable_get('mailchimp_ecommerce_use_fixed_inventory', FALSE) == FALSE) {
$product_wrapper = entity_metadata_wrapper('commerce_product', $product);
if ($product_wrapper
->__isset('commerce_stock') && $product_wrapper->commerce_stock
->value()) {
$inventory_amount = (int) $product_wrapper->commerce_stock
->value();
}
}
return $inventory_amount;
}
/**
* Implements hook_form_FORM_ID_alter().
*/
function mailchimp_ecommerce_commerce_form_mailchimp_ecommerce_admin_sync_orders_alter(&$form, &$form_state) {
$form['#submit'][] = 'mailchimp_ecommerce_commerce_admin_sync_orders_submit';
}
/**
* Submit handler for the MailChimp eCommerce sync form.
*/
function mailchimp_ecommerce_commerce_admin_sync_orders_submit($form, &$form_state) {
if (!empty($form_state['values']['sync_orders'])) {
$batch = [
'title' => t('Adding orders to MailChimp'),
'operations' => [],
];
// get orders within specified time period (months)
$months = abs(intval($form_state['values']['timespan'])) * -1;
$min_timestamp = strtotime($months . ' months');
$query = new EntityFieldQuery();
$results = $query
->entityCondition('entity_type', 'commerce_order')
->execute();
if (isset($results['commerce_order'])) {
$order_ids = array_keys($results['commerce_order']);
$batch['operations'][] = [
'mailchimp_ecommerce_commerce_batch_add_orders',
[
$order_ids,
],
];
batch_set($batch);
}
}
}
/**
* Batch callback used to add orders to MailChimp.
*/
function mailchimp_ecommerce_commerce_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 = commerce_order_load_multiple($batch);
foreach ($orders as $order) {
$context['sandbox']['current_order'] = $order->order_id;
$order_wrapper = entity_metadata_wrapper('commerce_order', $order);
$mc_order = _mailchimp_ecommerce_commerce_build_order($order_wrapper);
// 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']);
}
if ($order->order_status == 'pending' || $order->order_status == 'complete') {
$order = mailchimp_ecommerce_get_order($order->order_id);
if ($order) {
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 {
// TODO What if the cart already exists?
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'];
}