'Delete', 'page callback' => 'drupal_get_form', 'page arguments' => array('uc_webform_submission_delete_products_form', 2), 'access arguments' => array('access content'), 'type' => MENU_CALLBACK, ); $items['uc_webform/autocomplete'] = array( 'title' => 'Product autocomplete', 'page callback' => '_uc_webform_autocomplete_products', 'access arguments' => array('access content'), 'type' => MENU_CALLBACK, ); $items['node/%webform_menu/webform-results/orders'] = array( 'title' => 'Orders', 'page callback' => 'uc_webform_product_analysis', 'page arguments' => array(1), 'access callback' => 'webform_results_access', 'access arguments' => array(1), 'weight' => 5, 'type' => MENU_LOCAL_TASK, ); return $items; } /** * Implements hook_theme(). */ function uc_webform_theme() { return array( 'uc_webform_product_analysis' => array('variables' => array('node' => NULL)), ); } /** * Provides an auto-complete list of products that do not contain attributes. */ function _uc_webform_autocomplete_products($string = '') { $matches = array(); // Limit selection to only those products that do *not* contain attributes. $attrib_query = db_select('uc_product_attributes', 'pa') ->fields('pa', array('nid')); $query = db_select('node', 'n') ->fields('n', array('nid', 'title')) ->condition('n.title', '%' . db_like($string) . '%', 'LIKE') ->condition('n.nid', $attrib_query, 'NOT IN'); $query->join('uc_products', 'p', 'p.nid = n.nid'); $query->addField('p', 'model'); foreach ($query->execute() as $product) { $matches[$product->nid . '_' . $product->model] = check_plain($product->title); } drupal_json_output($matches); } /** * Provides a simple analysis of submissions that contain products. * * Called when viewing the "Orders" tab from within the results section of a * particular webform. */ function uc_webform_product_analysis($node, $sids = array(), $analysis_component = NULL) { if (!is_array($sids)) { $sids = array(); } // If showing a component's details, we don't want to loose the menu tabs. if ($analysis_component) { $item = menu_get_item('node/' . $node->nid . '/webform-results/analysis'); menu_set_item(NULL, $item); } $components = isset($analysis_component) ? array($analysis_component['cid'] => $analysis_component) : $node->webform['components']; $data = array(); $cids = array(); $order_status_cid = 0; // First, find the Order Status cid. foreach ($components as $cid => $component) { if ($component['form_key'] == 'order_status') { $order_status_cid = $component['cid']; } } foreach ($components as $cid => $component) { // Limit the results to product and product_list components. if ($component['type'] == 'product') { if ($row_data = _uc_webform_product_orders($component, $order_status_cid)) { $data[$cid] = $row_data; } $cids[] = $component['cid']; } elseif ($component['type'] == 'product_list') { if ($row_data = _uc_webform_product_list_orders($component, $order_status_cid)) { $data[$cid] = $row_data; } $cids[] = $component['cid']; } elseif ($component['type'] == 'product_grid') { if ($row_data = _uc_webform_product_grid_orders($component, $order_status_cid)) { $data[$cid] = $row_data; } $cids[] = $component['cid']; } } if (empty($cids)) { return t('There are no products associated with this webform.'); } else { return theme('uc_webform_product_analysis', array( 'node' => $node, 'data' => $data, 'sids' => $sids, 'analysis_component' => $analysis_component, 'order_status_cid' => $order_status_cid)); } } /** * Generate statistics for product components, limited to checked out webforms. * * This information is displayed under the "orders" tab of the webform results. */ function _uc_webform_product_orders($component, $order_status_cid) { // First, get the list of all submission IDs for webform submissions where // checkout has been completed. $query = db_select('webform_submitted_data', 'wsd') ->fields('wsd', array('sid')) ->condition('nid', $component['nid'], '=') ->condition('cid', $order_status_cid, '=') ->condition('data', 'Did not complete checkout', '<>'); $sids = array(); foreach ($query->execute() as $submission) { $sids[] = $submission->sid; } // Use the array of checked out submission ID's to grab only the checked out // product data. $product_results = array(); $total = 0; if (!empty($sids)) { $co_query = db_select('webform_submitted_data', 'wsd') ->fields('wsd', array('no', 'data')) ->condition('cid', $component['cid'], '=') ->condition('nid', $component['nid'], '=') ->condition('sid', $sids, 'IN'); foreach ($co_query->execute() as $co_result) { if ($co_result->no == 2) { $total += $co_result->data; } } } $product_info = explode('_', $component['extra']['product'], 2); $rows[0] = array(t($product_info[1]), $total); if ($total > 0) { return $rows; } else { return NULL; } } /** * Statistics for product_list components, limited to checked out webforms. * * This information is displayed under the "Orders" tab of the webform results. */ function _uc_webform_product_list_orders($component, $order_status_cid) { // First, get the list of all submission IDs for webform submissions where // checkout has been completed. $query = db_select('webform_submitted_data', 'wsd') ->fields('wsd', array('sid')) ->condition('nid', $component['nid'], '=') ->condition('cid', $order_status_cid, '=') ->condition('data', 'Did not complete checkout', '<>'); $sids = array(); foreach ($query->execute() as $submission) { $sids[] = $submission->sid; } // Use the array of checked out submission ID's to grab only the checked out // product data. $product_results = array(); if (!empty($sids)) { $co_query = db_select('webform_submitted_data', 'wsd') ->fields('wsd', array('no', 'data')) ->condition('cid', $component['cid'], '=') ->condition('nid', $component['nid'], '=') ->condition('sid', $sids, 'IN'); foreach ($co_query->execute() as $co_result) { if ($co_result->no == 0) { continue; } else { if (array_key_exists($co_result->data, $product_results)) { $product_results[$co_result->data] += 1; } else { $product_results[$co_result->data] = 1; } } } } $rows = array(); $count = 0; foreach ($product_results as $product => $qty) { $product_info = explode('_', $product, 2); $product_node = node_load($product_info[0]); $rows[$count] = array(t($product_node->model), $qty); $count++; } return $rows; } /** * Generate statistics for product_grid components, limited to checked out * webforms. This information is displayed under the "orders" tab of the * webform results. */ function _uc_webform_product_grid_orders($component, $order_status_cid) { // Build the rows of the table, including the first column. $rows = array(array()); $header = array(array()); $product_nids = array(); foreach ($component['extra']['products'] as $product) { $nid_sku = explode('_', $product, 2); $product_nids[] = $nid_sku[0]; $product_node = node_load($nid_sku[0]); // I use the nid_sku combination here as a key. $rows[$product] = array($product_node->title); } // Select the available option IDs and names for each product in the table. $query = db_select('uc_product_options', 'po') ->fields('po', array('oid')); $query->join('uc_attribute_options', 'ao', 'po.oid = ao.oid'); $query->addField('ao', 'name'); $query->condition('po.nid', $product_nids, 'IN'); // Build the header row. $options = array(); foreach ($query->execute() as $option) { // Use the oid as an array key to help when quering the // webform_submitted_data table (since it stores the oid instead of the // option name). $header[$option->oid] = $option->name; } // Get a list of all submission IDs for submissions with completed checkouts. $query = db_select('webform_submitted_data', 'wsd') ->fields('wsd', array('sid')) ->condition('nid', $component['nid'], '=') ->condition('cid', $order_status_cid, '=') ->condition('data', 'Did not complete checkout', '<>'); $sids = array(); foreach ($query->execute() as $submission) { $sids[] = $submission->sid; } // Use the array of checked out submission ID's to grab only the checked out // product data. $selections = array(); if (!empty($sids)) { $co_query = db_select('webform_submitted_data', 'wsd') ->fields('wsd', array('no', 'data')); $co_query->addExpression('COUNT(data)', 'datacount'); $co_query->condition('cid', $component['cid'], '='); $co_query->condition('nid', $component['nid'], '='); $co_query->condition('sid', $sids, 'IN'); $co_query->groupBy('no'); $co_query->groupBy('data'); foreach ($co_query->execute() as $data) { $aid_oid = explode('_', $data->data, 2); // The information is stored in the DB as attribute-ID_option-ID. This // line removes the attribute ID and leaves the $selections key as the // option ID. if (isset($aid_oid[1])) { $selections[$data->no][$aid_oid[1]] = $data->datacount; } } } // Check to see if any completed orders include this component. Return NULL // if there aren't any. if (!empty($selections)) { // Build up the 2D array that will be used to create the table. foreach ($rows as $rkey => $rval) { if ($rkey != 0) { foreach ($header as $hkey => $hval) { if ($hkey != 0) { // $rkey = nid_sku. // $hkey = option ID. $rows[$rkey][] = isset($selections[$rkey][$hkey]) ? $selections[$rkey][$hkey] : 0; } } } } $output = theme('table', array( 'header' => $header, 'rows' => $rows, 'attributes' => array( 'class' => array( 'webform-product-grid', ), ), )); return array(array(array('data' => $output, 'colspan' => 2))); } else { return NULL; } } /** * Output the content of the Analysis page. * * @see webform_results_analysis() */ function theme_uc_webform_product_analysis($variables) { $node = $variables['node']; $rows = array(); $question_number = 0; $single = isset($analysis_component); $header = array( $single ? $analysis_component['name'] : t('Q'), array( 'data' => $single ? ' ' : t('Product Selection (completed checkouts)'), 'colspan' => '10', ), ); foreach ($variables['data'] as $cid => $row_data) { $question_number++; if (is_array($row_data)) { $row = array(); if (!$single) { $row[] = array( 'data' => '' . $question_number . '', 'rowspan' => count($row_data) + 1, 'valign' => 'top', ); $row[] = array( 'data' => '' . check_plain($node->webform['components'][$cid]['name']) . '', 'colspan' => '10', ); } $rows = array_merge($rows, array_merge(array($row), $row_data)); } } $num_no_checkout = db_select('webform_submitted_data', 'wsd') ->condition('nid', $node->nid, '=') ->condition('data', 'Did not complete checkout', '=') ->countQuery() ->execute() ->fetchField(); $total_submissions = db_select('webform_submitted_data', 'wsd') ->fields('wsd', array('DISTINCT sid')) ->condition('nid', $node->nid, '=') ->countQuery() ->execute() ->fetchField(); $rows[] = array(array( 'data' => '$', 'rowspan' => 4, 'valign' => 'top', ), array( 'data' => 'Checkout statistics', 'colspan' => 10, )); $rows[] = array(t('Total completed checkouts'), $total_submissions - $num_no_checkout); $rows[] = array('' . t('Total webform submissions') . '', $total_submissions); return theme('table', array('header' => $header, 'rows' => $rows)); } /**************************************** * Form API */ /** * Adjustment for $form['#submit'][]. */ function uc_webform_form_node_submit(&$form, &$form_state) { } /** * Form alter for add to cart. */ function uc_webform_form_uc_product_add_to_cart_form_alter(&$form, &$form_state) { if (isset($form['node']['#value']->webform_nid)) { // Replace standard add to cart with the webform corresponding to this // product. } } /** * Form alter. */ function uc_webform_form_alter(&$form, &$form_state, $form_id) { // THIS FAILS because $form['submitted']['order_status']['#default_value'] // is not set. // Ensure that the order_status field cannot be modified with firebug, etc. if ($form_id == 'webform_component_form' || $form_id == 'webform_component_edit_form') { // Allow select components to change attributes/options selected for a // product, i.e. via sku. if ($form['type']['#value'] == 'select') { $form['extra']['uc_webform_options'] = array( '#title' => 'Product SKU ', '#description' => 'You can choose to set what options will be selected by safe_key|option ', '#type' => 'textarea', '#default_value' => variable_get('uc_webform_sku_' . $form['nid']['#value'] . '_' . $form['cid']['#value'], ''), ); $form['#submit'][] = 'uc_webform_sku_submit'; } } } /** * Adjustment for $form['#submit'][]. */ function uc_webform_sku_submit(&$form, &$form_state) { if (isset($form_state['values']['extra']['uc_webform_options'])) { variable_set('uc_webform_sku_' . $form_state['values']['nid'] . '_' . $form_state['values']['cid'], $form_state['values']['extra']['uc_webform_options']); } } /** * Confirmation form before deleting products from a cart. * * When removing a single product from a cart alert the user that doing so will * also remove all other products associated with the same form. */ function uc_webform_submission_delete_products_form($form, &$form_state,$wf_nid) { $question = t('If you remove this product from your cart, all products associated with your form submission will also be removed. Are you sure you want to delete this product?'); $destination = 'cart/'.$wf_nid; return confirm_form(array(), NULL, $destination, $question, t('Delete'), t('Cancel')); } /** * Adjustment for $form['#submit'][]. */ function uc_webform_submission_delete_products_form_submit($form, &$form_state) { // Remove all items from the current webform submission from the cart. $cart_items = uc_cart_get_contents(); $wf_nid = arg(2); foreach ($cart_items as $cart_item) { if (isset($cart_item->data['webform_sid']) && $cart_item->data['webform_nid'] == $wf_nid) { uc_cart_remove_item($cart_item->nid, $cart_item->cart_id, $cart_item->data); } } $form_state['redirect'] = 'cart'; } /** * Implements hook_form_FORM_ID_alter(). */ function uc_webform_form_uc_cart_view_form_alter(&$form, &$form_state) { $count = 0; while (isset($form['items'][$count])) { if (isset($form['items'][$count]['data']['#value'])) { $data = unserialize($form['items'][$count]['data']['#value']); if (isset($data['webform_ctype'])) { if (($data['webform_ctype'] == 'product_list') || ($data['webform_ctype'] == 'product') || ($data['webform_ctype'] == 'product_grid')) { // Check to see if the product was a mandatory field in the webform // submission. $component_query = db_select('webform_component', 'wc') ->fields('wc', array('mandatory', 'extra')) ->condition('nid', $data['webform_nid'], '=') ->condition('cid', $data['webform_cid'], '='); $component_info = $component_query->execute()->fetchAssoc(); $component_info['extra'] = unserialize($component_info['extra']); // Users may not edit the quantity of a product from the cart. $form['items'][$count]['qty']['#disabled'] = TRUE; $data_query = db_select('webform_submitted_data', 'wsd') ->fields('wsd', array('data')) ->condition('nid', $data['webform_nid'], '=') ->condition('sid', $data['webform_sid'], '=') ->condition('cid', $data['webform_cid'], '=') ->condition('no', 0, '='); $data_result = $data_query->execute(); $form['items'][$count]['qty']['#value'] = $data_result->fetchField(); // Force the user to remove *all* webform-related products from the // cart if they want to remove *one* mandatory webform-related // product from the cart. //if ($component_info['mandatory'] == 1) { $form['items'][$count]['remove']['#type'] = 'item'; $form['items'][$count]['remove']['#markup'] = l(t('Delete'), "cart/delete-form/".$data['webform_nid'], array( 'query' => drupal_get_destination(), )); //} //Remove link for registration products $form['items'][$count]['desc']['#markup'] = strip_tags($form['items'][$count]['desc']['#markup']); if (($data['webform_ctype'] == 'product_list') || ($data['webform_ctype'] == 'product_grid')) { // Users may not edit the quantity of a product_list or // product_grid webform product. $form['items'][$count]['qty']['#disabled'] = TRUE; // If #value is not specified here, all products will be removed // if any product is removed. $form['items'][$count]['qty']['#value'] = 1; } } } } $count++; } } /** * Implements hook_theme_registry_alter(). * * There is a good article about this here: * http://www.lullabot.com/articles/overriding-theme-functions-in-modules */ function uc_webform_theme_registry_alter(&$theme_registry) { if (!empty($theme_registry['webform_components_form'])) { $theme_registry['webform_components_form']['function'] = 'uc_webform_webform_components_form'; } } /** * Override 'theme_webform_components_form($form)', * found in webform.components.inc. * This function will need to be updated everytime quicksketch makes a * corresponding change. * * Remove the 'Clone', 'Edit' and 'Delete' links from the hidden Order Status * component if * there are products included in the webform. */ function uc_webform_webform_components_form($variables) { $form = $variables['form']; $form['components']['#attached']['library'][] = array('webform', 'admin'); drupal_add_tabledrag('webform-components', 'order', 'sibling', 'webform-weight'); drupal_add_tabledrag('webform-components', 'match', 'parent', 'webform-pid', 'webform-pid', 'webform-cid'); $node = $form['#node']; $header = array(t('Label'), t('Type'), t('Value'), t('Mandatory'), t('Weight'), array( 'data' => t('Operations'), 'colspan' => 3, ), ); $rows = array(); // Add a row containing form elements for a new item. unset($form['add']['name']['#title'], $form['add_type']['#description']); $form['add']['name']['#attributes']['rel'] = t('New component name'); $form['add']['name']['#attributes']['class'] = array('webform-default-value'); $form['add']['cid']['#attributes']['class'] = array('webform-cid'); $form['add']['pid']['#attributes']['class'] = array('webform-pid'); $form['add']['weight']['#attributes']['class'] = array('webform-weight'); $row_data = array( drupal_render($form['add']['name']), drupal_render($form['add']['type']), '', drupal_render($form['add']['mandatory']), drupal_render($form['add']['cid']) . drupal_render($form['add']['pid']) . drupal_render($form['add']['weight']), array( 'colspan' => 3, 'data' => drupal_render($form['add']['add']), ), ); $add_form = array( 'data' => $row_data, 'class' => array('draggable', 'webform-add-form'), ); $form_rendered = FALSE; if (!empty($node->webform['components'])) { $component_tree = array(); $page_count = 1; _webform_components_tree_build($node->webform['components'], $component_tree, 0, $page_count); $component_tree = _webform_components_tree_sort($component_tree); /** * Build the table rows. */ function _webform_components_form_rows($node, $cid, $component, $level, &$form, &$rows, &$add_form) { // Create presentable values. if (drupal_strlen($component['value']) > 30) { $component['value'] = drupal_substr($component['value'], 0, 30); $component['value'] .= '...'; } $component['value'] = check_plain($component['value']); // Remove individual titles from the mandatory and weight fields. unset($form['components'][$cid]['mandatory']['#title']); unset($form['components'][$cid]['pid']['#title']); unset($form['components'][$cid]['weight']['#title']); // Add special classes for weight and parent fields. $form['components'][$cid]['cid']['#attributes']['class'] = array('webform-cid'); $form['components'][$cid]['pid']['#attributes']['class'] = array('webform-pid'); $form['components'][$cid]['weight']['#attributes']['class'] = array('webform-weight'); // Build indentation for this row. $indents = ''; for ($n = 1; $n <= $level; $n++) { $indents .= '