commerce_webform.module in Commerce Webform 7
Same filename and directory in other branches
Commerce Webform module file
File
commerce_webform.moduleView source
<?php
/**
* @file
* Commerce Webform module file
*/
/**
* Implements hook_permission().
*/
function commerce_webform_permission() {
return array(
'alter productfield on paid webform' => array(
'title' => t('Alter webfor product field when paid'),
'description' => t('Users with this permission can make changes to the product fields on webforms even after the product has been paid for.'),
),
);
}
/**
* Define a special line item type for line items
* created via the commerce_webform module. This type
* will have two fields for storing the webform nid and
* submission sid of the webform submission which created
* it.
*/
function commerce_webform_commerce_line_item_type_info() {
$line_item_types = array();
$line_item_types['commerce_webform'] = array(
'type' => 'commerce_webform',
'name' => t('Commerce webform'),
'description' => t('References a product and a webform submission which caused the product to be added to the order.'),
'product' => TRUE,
'add_form_submit_value' => t('Add product'),
'base' => 'commerce_webform_line_item',
);
return $line_item_types;
}
/**
* Ensures the commerce webform line item type contains a product
* reference field, webform nid reference field and webform submission
* sid field.
*
* @param commerce_line_item $line_item_type
* The info array of the line item type being configured.
*/
function commerce_webform_line_item_configuration($line_item_type) {
// Add the standard commerce product line item fields.
commerce_product_line_item_configuration($line_item_type);
// Add the webform line item fields.
$field_names['nid'] = 'commerce_webform_nid';
$field_names['sid'] = 'commerce_webform_sid';
foreach ($field_names as $type => $field_name) {
// Check the commerce webform fields are not there already.
$field = field_info_field($field_name);
$instance = field_info_instance('commerce_line_item', $field_name, 'commerce_webform');
if (empty($field)) {
$field = array(
'active' => '1',
'cardinality' => '1',
'deleted' => '0',
'entity_types' => array(
'commerce_line_item',
),
'field_name' => $field_name,
'foreign keys' => array(),
'indexes' => array(),
'module' => 'number',
'settings' => array(),
'translatable' => '0',
'type' => 'number_integer',
'locked' => TRUE,
);
$field = field_create_field($field);
}
if (empty($instance)) {
$instance = array(
'field_name' => $field_name,
'entity_type' => 'commerce_line_item',
'bundle' => 'commerce_webform',
'commerce_cart_settings' => array(
'field_access' => 0,
),
'default_value' => 0,
'deleted' => '0',
'label' => t('Webform ' . $type),
'required' => 0,
'settings' => array(
'max' => '',
'min' => '',
'prefix' => '',
'suffix' => '',
'user_register_form' => FALSE,
),
'description' => 'If this line item is connected to a commere_webform then this field will have a positive numeric value connecting it to the webform ' . $type,
'widget' => array(
'active' => 0,
'module' => 'number',
'settings' => array(),
'type' => 'number',
'weight' => '3',
),
'display' => array(),
);
$entity_info = entity_get_info('commerce_line_item');
// Spoof the default view mode and node teaser so its display type is set.
$entity_info['view modes'] += array(
'default' => array(),
'node_teaser' => array(),
);
foreach ($entity_info['view modes'] as $view_mode => $data) {
$instance['display'][$view_mode] = array(
'label' => 'hidden',
'module' => 'number',
'type' => 'number_integer',
'settings' => array(
'decimal_separator' => '.',
'prefix_suffix' => TRUE,
'scale' => 0,
'thousand_separator' => ' ',
),
'weight' => 5,
);
}
field_create_instance($instance);
}
}
}
/**
* Returns an appropriate title for this line item.
*/
function commerce_webform_line_item_title($line_item) {
return commerce_product_line_item_title($line_item);
}
/**
* Returns the elements necessary to add a product line item through a line item
* manager widget.
*/
function commerce_webform_line_item_add_form($element, &$form_state) {
return commerce_product_line_item_add_form($element, $form_state);
}
/**
* Adds the selected product information to a line item added via a line item
* manager widget.
*
* @param commerce_line_item $line_item
* The newly created line item object.
* @param array $element
* The array representing the widget form element.
* @param array $form_state
* The present state of the form upon the latest submission.
* @param array $form
* The actual form array.
*
* @return string|NULL
* NULL if all is well or an error message if something goes wrong.
*/
function commerce_webform_line_item_add_form_submit(&$line_item, $element, &$form_state, $form) {
return commerce_product_line_item_add_form_submit($line_item, $element, $form_state, $form);
}
/**
* Implements hook_menu().
*/
function commerce_webform_menu() {
$items = array();
$items['commerce_webform/autocomplete'] = array(
'title' => 'commerce_webform autocomplete',
'page callback' => 'commerce_webform_autocomplete',
'access callback' => TRUE,
'type' => MENU_CALLBACK,
);
return $items;
}
/**
* Implements hook_theme().
*/
function commerce_webform_theme() {
return array(
'webform_display_productfield' => array(
'render element' => 'element',
'file' => 'productfield.inc',
),
'commerce_webform_product_display' => array(
'variables' => array(
'product' => NULL,
'price' => array(),
'component' => array(),
),
'file' => 'productfield.inc',
),
);
}
/**
* Returns output for product autocompletes.
*
* The values returned will be keyed by SKU and appear as such in the textfield,
* even though the preview in the autocomplete list shows "SKU: Title".
*/
function commerce_webform_autocomplete($string = '') {
$matches = array();
// The user enters a comma-separated list of tags.
// We only autocomplete the last tag.
$tags_typed = drupal_explode_tags($string);
$tag_last = drupal_strtolower(array_pop($tags_typed));
if (!empty($tag_last)) {
$prefix = count($tags_typed) ? implode(', ', $tags_typed) . ', ' : '';
$products = commerce_product_match_products(array(
'field_name' => 'commerce_webform',
), NULL, $tag_last, 'contains', array(), 10);
// Loop through the products and convert them into autocomplete output.
foreach ($products as $product_id => $data) {
// Add a class wrapper for a few required CSS overrides.
$matches[$prefix . $data['sku']] = '<div class="reference-autocomplete">' . $data['rendered'] . '</div>';
}
}
drupal_json_output($matches);
}
/**
* Implements hook_webform_component_info().
* Define the commerce webform field
*/
function commerce_webform_webform_component_info() {
$components = array();
$components['productfield'] = array(
'label' => t('Commerce product skus'),
'description' => t('List commerce products linked to this webform.'),
'features' => array(
'default_value' => FALSE,
'email' => TRUE,
'email_address' => FALSE,
'email_name' => FALSE,
),
'file' => 'productfield.inc',
);
return $components;
}
/**
* Get a list of commerce products from a webform
* submission.
*
* @param array $submission
* A webform submission array.
*
* @return array
* Keyed by product_id. Each value is an object containing
* product commerce_product The commerce_product object
* product_id int the product id
* quantity int the quantity chosen
*/
function commerce_webform_get_products_from_webform_submission($submission) {
$product_ids = array();
$products = array();
$data = array();
$components = $submission['components'];
foreach ($components as $component) {
if ($component['component']['type'] == 'productfield') {
foreach ($component['value'] as &$value) {
$value = json_decode($value);
if (!empty($value->product_id) && $value->quantity > 0) {
$product_ids[] = $value->product_id;
if (empty($data[$value->product_id])) {
$data[$value->product_id] = $value;
$data[$value->product_id]->required = $component['component']['mandatory'];
$data[$value->product_id]->choose_quantity = $component['component']['extra']['choose_quantity'];
}
else {
// Now we need to change the quantity.
$data[$value->product_id]->quantity = $data[$value->product_id]->quantity + $value->quantity;
}
}
}
}
}
$products = commerce_product_load_multiple($product_ids);
foreach ($products as $product) {
$data[$product->product_id]->product = $product;
}
return $data;
}
/**
* Update the details stored on a webform submission product field.
*
* @param obj $webform_submission
* The webform submission
* @param int $order_id
* The order id which paid for the order.
* @param int $line_item_id
* The line item id the product was purchased on
* @param int $product_id
* The product id which has been paid for.
* @param int $quantity
* The number purchased.
* @param boolean $paid
* TRUE if the item has now been paid for, FALSE if not yet.
*/
function commerce_webform_update_webform_submission_productfield($webform_submission, $order_id, $line_item_id, $product_id, $quantity, $paid) {
$node = node_load($webform_submission->nid);
$components = $node->webform['components'];
// Loop through all possible webform fields looking for
// productfields.
foreach ($components as $key => $component) {
if ($component['type'] == 'productfield') {
// Loop through the product options on the product field
// looking for the purchased product.
foreach ($component['extra']['items'] as $product_id_option => $details) {
if ($product_id_option == $product_id) {
// Loop through the submission values looking for the product
// which was just purchased.
foreach ($webform_submission->data[$key]['value'] as $value_key => $value) {
$value = json_decode($value);
if (!empty($value->product_id) && $value->product_id == $product_id) {
$value->order_id = $order_id;
$value->line_item_id = $line_item_id;
$value->paid = $paid;
$webform_submission->data[$key]['value'][$value_key] = json_encode($value);
// The following is the same as running
// webform_submission_update() except that
// it does not invoke the update hooks.
// Update the main submission info.
drupal_write_record('webform_submissions', $webform_submission, 'sid');
// Delete all old submission component data.
db_delete('webform_submitted_data')
->condition('sid', $webform_submission->sid)
->execute();
// Read submission component data.
$webform_submission->is_new = FALSE;
webform_submission_insert($node, $webform_submission);
// Do NOT return - but loop through all
// We need to find all items with this $product_id
// and give it the $line_item_id so that when Rule
// "Mark commerce webform as paid" is executed
// it will also be marked as paid.
}
}
}
}
}
}
}
/**
* Given a commerce line item return the linked webform submission.
*
* @param commerce_line_item|int $line_item
* The line item or line item id
*
* @return webform_submission|FALSE
* Either the linked webform submission or FALSE if there isn't one.
*/
function commerce_webform_get_webform_submission_from_lineitem($line_item) {
if (is_numeric($line_item)) {
$line_item = commerce_line_item_load($line_item);
}
if (!isset($line_item->type) || $line_item->type != 'commerce_webform') {
// Not linked to a commerce webform.
return FALSE;
}
$line_item_wrapper = entity_metadata_wrapper('commerce_line_item', $line_item);
$sid = $line_item_wrapper->commerce_webform_sid
->value();
if ($sid > 0) {
module_load_include('inc', 'webform', 'includes/webform.submissions');
$nid = $line_item_wrapper->commerce_webform_nid
->value();
return webform_get_submission($nid, $sid);
}
return FALSE;
}
/**
* Rules condition callback.
*
* @param node $node
* The submitted webform node.
*
* @return boolean
* Returns TRUE if the webform has a commerce productfield
*/
function commerce_webform_is_commerce_webform($node) {
$components = $node->webform['components'];
foreach ($components as $component) {
if ($component['type'] == 'productfield') {
return TRUE;
}
}
return FALSE;
}
/**
* Rules condition callback.
*
* @return boolean
* TRUE if the order contains a line item linked
* to a webform submission.
*/
function commerce_webform_is_commerce_webform_order($order) {
$order_wrapper = entity_metadata_wrapper('commerce_order', $order);
foreach ($order_wrapper->commerce_line_items
->value() as $line_item) {
if ($line_item->type == 'commerce_webform' && isset($line_item->commerce_webform_sid)) {
$line_item_wrapper = entity_metadata_wrapper('commerce_line_item', $line_item);
return $line_item_wrapper->commerce_webform_sid
->value() > 0;
}
}
return FALSE;
}
/**
* Rules condition callback.
*
* @return boolean
* TRUE if the order contains a line item linked
* to a specific webform submission.
*/
function commerce_webform_is_specific_commerce_webform_order($order, $webform_node) {
$order_wrapper = entity_metadata_wrapper('commerce_order', $order);
foreach ($order_wrapper->commerce_line_items
->value() as $line_item) {
if ($line_item->type == 'commerce_webform' && isset($line_item->commerce_webform_nid)) {
$line_item_wrapper = entity_metadata_wrapper('commerce_line_item', $line_item);
if ($line_item_wrapper->commerce_webform_nid
->value() == $webform_node->nid) {
return TRUE;
}
}
}
return FALSE;
}
/**
* Implements hook_field_extra_fields().
*/
function commerce_webform_field_extra_fields() {
$extra['commerce_order']['commerce_order']['display'] = array(
'commerce_webform_order_view' => array(
'label' => t('Webform submission details'),
'description' => t('If this order is linked to any webform submissions this will display them.'),
'weight' => 5,
),
);
return $extra;
}
/**
* Implements hook_entity_view().
*/
function commerce_webform_entity_view($order, $type, $view_mode, $langcode) {
$submissions = array();
if ($type == 'commerce_order' && $order->type == 'commerce_order') {
global $user;
$order_wrapper = entity_metadata_wrapper('commerce_order', $order);
foreach ($order_wrapper->commerce_line_items
->value() as $line_item) {
if (isset($line_item->commerce_webform_sid)) {
$line_item_wrapper = entity_metadata_wrapper('commerce_line_item', $line_item);
$sid = $line_item_wrapper->commerce_webform_sid
->value();
$nid = $line_item_wrapper->commerce_webform_nid
->value();
if ($sid > 0 && $nid > 0 && !isset($submissions["{$nid}:{$sid}"])) {
module_load_include('inc', 'webform', 'includes/webform.submissions');
$sub = webform_get_submission($nid, $sid);
if (user_access('access all webform results') || user_access('access own webform submissions') && $sub->uid == $user->uid) {
// If the user has access to this submission, print the details.
$submissions["{$nid}:{$sid}"] = array(
'node' => node_load($nid),
'submission' => $sub,
);
}
}
}
}
if (!empty($submissions)) {
$order->content['commerce_webform_order_view'] = array();
foreach ($submissions as $id => $submission) {
$node = $submission['node'];
$sub = $submission['submission'];
$order->content['commerce_webform_order_view'][$id]['#markup'] = l(t('View webform submission on webform %title', array(
'%title' => $node->title,
)), "node/{$node->nid}/submission/{$sub->sid}", array(
'html' => TRUE,
)) . webform_submission_render($node, $sub, NULL, 'html');
}
}
}
}
/**
* Implements hook_form_FORM_ID_alter().
* Add commerce webform items to Form Settings page.
*/
function commerce_webform_form_webform_configure_form_alter(&$form, &$form_state, $form_id) {
$node = $form_state['build_info']['args'][0];
$form['commerce_webform'] = array(
'#type' => 'fieldset',
'#title' => t('Commerce webform settings'),
'#collapsible' => TRUE,
'#collapsed' => TRUE,
'#weight' => 1,
'#description' => t('These settings are for when the submission of this webform will create a commerce order. The webform must have at least one productfield element on it to be a commerce webform.'),
);
$form['commerce_webform']['commerce_webform_new_order'] = array(
'#type' => 'checkbox',
'#title' => t('Create a separate order'),
'#description' => t('When the webform is submitted the default action is to add all selected products into the users current basket. If you want instead to create a special order just for this submission, check this box.'),
'#default_value' => isset($node->webform['commerce_webform_new_order']) ? $node->webform['commerce_webform_new_order'] : 0,
);
array_unshift($form['#submit'], 'commerce_webform_configure_submit');
}
/**
* Submit handler for webform_configure_form().
* Add the extra commerce webform configuration options.
*/
function commerce_webform_configure_submit($form, &$form_state) {
// Edit the node by reference just to shorten it up.
$node =& $form['#node'];
// Save the commerce_webform configuration.
$node->webform['commerce_webform_new_order'] = $form_state['values']['commerce_webform_new_order'];
}
/**
* Implements hook_form_FORM_ID_alter().
* Modify the cart modification form.
*/
function commerce_webform_form_views_form_commerce_cart_form_default_alter(&$form, &$form_state, $form_id) {
// Store a list of all webform added products in this order.
$webforms = array();
// Go through all items in the basket and note if they are webform
// products. If they cannot have their quantities changed, remove
// the quantity edit textfield.
foreach (element_children($form['edit_quantity']) as $id) {
// If this is a commerce webform item, check if it is mandatory.
$line_item_id = $form['edit_quantity'][$id]['#line_item_id'];
$line_item = commerce_line_item_load($line_item_id);
if ($line_item->type == 'commerce_webform') {
if (!in_array('_commerce_webform_cart_validate', $form['#validate']) && $line_item->data['commerce_webform']['choose_quantity'] && $line_item->data['commerce_webform']['required']) {
// This is a commerce_webform line item with variable quantity
// and is required, add a validation function to stop it from
// being set to 0.
array_unshift($form['#validate'], '_commerce_webform_cart_validate');
}
$nid = entity_metadata_wrapper('commerce_line_item', $line_item)->commerce_webform_nid
->value();
if (!isset($webforms[$nid])) {
$webforms[$nid] = array(
'count' => 0,
'title' => node_load($nid)->title,
);
}
$webforms[$nid]['count']++;
if (!$line_item->data['commerce_webform']['choose_quantity']) {
// Remove the ability to change the quantity.
$form['edit_quantity'][$id]['#type'] = 'value';
$form['edit_quantity'][$id]['quantity'] = array(
'#markup' => '<p>' . $form['edit_quantity'][$id]['#default_value'] . '</p>',
);
}
}
}
// Go through each of the delete buttons on the form. If they
// remove a commerce webform added item, show a message to
// connect them to the webform. If they are required add
// a submission function which removes all other webform
// items from the basket.
foreach (element_children($form['edit_delete']) as $id) {
if (!empty($form['edit_delete'][$id]['#line_item_id'])) {
$line_item_id = $form['edit_delete'][$id]['#line_item_id'];
$line_item = commerce_line_item_load($line_item_id);
if ($line_item->type == 'commerce_webform') {
$nid = entity_metadata_wrapper('commerce_line_item', $line_item)->commerce_webform_nid
->value();
$form['edit_delete'][$id]['#suffix'] = '<br /><em>' . t('Part of %webform', array(
'%webform' => $webforms[$nid]['title'],
)) . '</em>';
if ($webforms[$nid]['count'] > 1 && $line_item->data['commerce_webform']['required']) {
$form['edit_delete'][$id]['#suffix'] .= '<br /><em>' . t('Removing this item will remove the other %webform items from your basket.', array(
'%webform' => $webforms[$nid]['title'],
)) . '</em>';
array_unshift($form['edit_delete'][$id]['#submit'], '_commerce_webform_remove_required_product_from_order');
}
}
}
}
}
/**
* Commerce cart validation function.
* If there are commerce_webform elements in the cart, check
* if any have a variable quantity but are required and remove
* all webform items if the quantity was set to 0.
*/
function _commerce_webform_cart_validate(&$form, &$form_state) {
foreach (element_children($form['edit_quantity']) as $id) {
if ($form_state['values']['edit_quantity'][$id] < 1) {
// If the quantity has been reduced to 0,
// check if this is a required commerce_webform line item.
$line_item_id = $form['edit_quantity'][$id]['#line_item_id'];
$line_item = commerce_line_item_load($line_item_id);
if ($line_item->type == 'commerce_webform' && $line_item->data['commerce_webform']['required']) {
$sid = entity_metadata_wrapper('commerce_line_item', $line_item)->commerce_webform_sid
->value();
if ($sid > 0) {
_commerce_webform_remove_line_items_from_cart_form_by_sid($form, $form_state, $sid);
}
}
}
}
}
/**
* Form submission function. Someone has tried to remove
* a required commerce webform item from an order.
* Remove all submission products at the same time.
*/
function _commerce_webform_remove_required_product_from_order($form, &$form_state) {
$removed_line_item_id = $form_state['triggering_element']['#line_item_id'];
$removed_line_item = commerce_line_item_load($removed_line_item_id);
$sid = entity_metadata_wrapper('commerce_line_item', $removed_line_item)->commerce_webform_sid
->value();
if ($sid > 0) {
_commerce_webform_remove_line_items_from_cart_form_by_sid($form, $form_state, $sid, $removed_line_item_id);
}
}
/**
* Helper function for use by the cart update form functions.
* Remove all line items from an order which link to a specific submission.
*/
function _commerce_webform_remove_line_items_from_cart_form_by_sid(&$form, &$form_state, $sid, $suppress_message_line_item_id = 0) {
foreach (element_children($form['edit_quantity']) as $id) {
$line_item_id = $form['edit_quantity'][$id]['#line_item_id'];
$line_item = commerce_line_item_load($line_item_id);
if ($line_item->type == 'commerce_webform') {
$wrapper = entity_metadata_wrapper('commerce_line_item', $line_item);
if ($sid == $wrapper->commerce_webform_sid
->value()) {
$form_state['values']['edit_quantity'][$id] = 0;
if ($line_item_id != $suppress_message_line_item_id) {
drupal_set_message(t('%product removed from your cart.', array(
'%product' => $wrapper->commerce_product
->value()->title,
)));
}
}
}
}
}
/**
* Calculate the total default price of a webform. This is the
* sum of all productfields if they have a default set.
*
* @param object $node
* The webform node
*
* @return int
* The price in minor units.
*/
function commerce_webform_calculate_total_default_price_of_webform($node) {
if (!is_object($node)) {
$node = node_load($node);
}
$total = 0;
$components = $node->webform['components'];
// Loop through all possible webform fields looking for
// productfields.
foreach ($components as $key => $component) {
if ($component['type'] == 'productfield') {
// Loop through the product options on the product field
// looking for the default product.
if ($component['value']) {
$skus = explode(',', $component['value']);
foreach ($skus as $sku) {
$product = commerce_product_load_by_sku(trim($sku));
if ($product) {
$price = commerce_product_calculate_sell_price($product);
$total += $price['amount'];
}
}
}
}
}
return $total;
}
/**
* Implements hook_commerce_cart_product_comparison_properties_alter().
*
* When multiple submissions are made before checkout with the same products
* in them, commerce will group the line items which stops the sid properly
* being updated.
*/
function commerce_webform_commerce_cart_product_comparison_properties_alter(&$comparison_properties) {
$comparison_properties[] = 'commerce_webform_sid';
}
Functions
Name | Description |
---|---|
commerce_webform_autocomplete | Returns output for product autocompletes. |
commerce_webform_calculate_total_default_price_of_webform | Calculate the total default price of a webform. This is the sum of all productfields if they have a default set. |
commerce_webform_commerce_cart_product_comparison_properties_alter | Implements hook_commerce_cart_product_comparison_properties_alter(). |
commerce_webform_commerce_line_item_type_info | Define a special line item type for line items created via the commerce_webform module. This type will have two fields for storing the webform nid and submission sid of the webform submission which created it. |
commerce_webform_configure_submit | Submit handler for webform_configure_form(). Add the extra commerce webform configuration options. |
commerce_webform_entity_view | Implements hook_entity_view(). |
commerce_webform_field_extra_fields | Implements hook_field_extra_fields(). |
commerce_webform_form_views_form_commerce_cart_form_default_alter | Implements hook_form_FORM_ID_alter(). Modify the cart modification form. |
commerce_webform_form_webform_configure_form_alter | Implements hook_form_FORM_ID_alter(). Add commerce webform items to Form Settings page. |
commerce_webform_get_products_from_webform_submission | Get a list of commerce products from a webform submission. |
commerce_webform_get_webform_submission_from_lineitem | Given a commerce line item return the linked webform submission. |
commerce_webform_is_commerce_webform | Rules condition callback. |
commerce_webform_is_commerce_webform_order | Rules condition callback. |
commerce_webform_is_specific_commerce_webform_order | Rules condition callback. |
commerce_webform_line_item_add_form | Returns the elements necessary to add a product line item through a line item manager widget. |
commerce_webform_line_item_add_form_submit | Adds the selected product information to a line item added via a line item manager widget. |
commerce_webform_line_item_configuration | Ensures the commerce webform line item type contains a product reference field, webform nid reference field and webform submission sid field. |
commerce_webform_line_item_title | Returns an appropriate title for this line item. |
commerce_webform_menu | Implements hook_menu(). |
commerce_webform_permission | Implements hook_permission(). |
commerce_webform_theme | Implements hook_theme(). |
commerce_webform_update_webform_submission_productfield | Update the details stored on a webform submission product field. |
commerce_webform_webform_component_info | Implements hook_webform_component_info(). Define the commerce webform field |
_commerce_webform_cart_validate | Commerce cart validation function. If there are commerce_webform elements in the cart, check if any have a variable quantity but are required and remove all webform items if the quantity was set to 0. |
_commerce_webform_remove_line_items_from_cart_form_by_sid | Helper function for use by the cart update form functions. Remove all line items from an order which link to a specific submission. |
_commerce_webform_remove_required_product_from_order | Form submission function. Someone has tried to remove a required commerce webform item from an order. Remove all submission products at the same time. |