uc_webform.module 39 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137
  1. <?php
  2. /**
  3. * @file
  4. * Provides components to the Webform module utilizing the Ubercart package.
  5. */
  6. /**
  7. * Implements hook_menu().
  8. */
  9. function uc_webform_menu() {
  10. $items = array();
  11. $items['cart/delete-form/%'] = array(
  12. 'title' => 'Delete',
  13. 'page callback' => 'drupal_get_form',
  14. 'page arguments' => array('uc_webform_submission_delete_products_form', 2),
  15. 'access arguments' => array('access content'),
  16. 'type' => MENU_CALLBACK,
  17. );
  18. $items['uc_webform/autocomplete'] = array(
  19. 'title' => 'Product autocomplete',
  20. 'page callback' => '_uc_webform_autocomplete_products',
  21. 'access arguments' => array('access content'),
  22. 'type' => MENU_CALLBACK,
  23. );
  24. $items['node/%webform_menu/webform-results/orders'] = array(
  25. 'title' => 'Orders',
  26. 'page callback' => 'uc_webform_product_analysis',
  27. 'page arguments' => array(1),
  28. 'access callback' => 'webform_results_access',
  29. 'access arguments' => array(1),
  30. 'weight' => 5,
  31. 'type' => MENU_LOCAL_TASK,
  32. );
  33. return $items;
  34. }
  35. /**
  36. * Implements hook_theme().
  37. */
  38. function uc_webform_theme() {
  39. return array(
  40. 'uc_webform_product_analysis' => array('variables' => array('node' => NULL)),
  41. );
  42. }
  43. /**
  44. * Provides an auto-complete list of products that do not contain attributes.
  45. */
  46. function _uc_webform_autocomplete_products($string = '') {
  47. $matches = array();
  48. // Limit selection to only those products that do *not* contain attributes.
  49. $attrib_query = db_select('uc_product_attributes', 'pa')
  50. ->fields('pa', array('nid'));
  51. $query = db_select('node', 'n')
  52. ->fields('n', array('nid', 'title'))
  53. ->condition('n.title', '%' . db_like($string) . '%', 'LIKE')
  54. ->condition('n.nid', $attrib_query, 'NOT IN');
  55. $query->join('uc_products', 'p', 'p.nid = n.nid');
  56. $query->addField('p', 'model');
  57. foreach ($query->execute() as $product) {
  58. $matches[$product->nid . '_' . $product->model] = check_plain($product->title);
  59. }
  60. drupal_json_output($matches);
  61. }
  62. /**
  63. * Provides a simple analysis of submissions that contain products.
  64. *
  65. * Called when viewing the "Orders" tab from within the results section of a
  66. * particular webform.
  67. */
  68. function uc_webform_product_analysis($node, $sids = array(), $analysis_component = NULL) {
  69. if (!is_array($sids)) {
  70. $sids = array();
  71. }
  72. // If showing a component's details, we don't want to loose the menu tabs.
  73. if ($analysis_component) {
  74. $item = menu_get_item('node/' . $node->nid . '/webform-results/analysis');
  75. menu_set_item(NULL, $item);
  76. }
  77. $components = isset($analysis_component) ? array($analysis_component['cid'] => $analysis_component) : $node->webform['components'];
  78. $data = array();
  79. $cids = array();
  80. $order_status_cid = 0;
  81. // First, find the Order Status cid.
  82. foreach ($components as $cid => $component) {
  83. if ($component['form_key'] == 'order_status') {
  84. $order_status_cid = $component['cid'];
  85. }
  86. }
  87. foreach ($components as $cid => $component) {
  88. // Limit the results to product and product_list components.
  89. if ($component['type'] == 'product') {
  90. if ($row_data = _uc_webform_product_orders($component, $order_status_cid)) {
  91. $data[$cid] = $row_data;
  92. }
  93. $cids[] = $component['cid'];
  94. }
  95. elseif ($component['type'] == 'product_list') {
  96. if ($row_data = _uc_webform_product_list_orders($component, $order_status_cid)) {
  97. $data[$cid] = $row_data;
  98. }
  99. $cids[] = $component['cid'];
  100. }
  101. elseif ($component['type'] == 'product_grid') {
  102. if ($row_data = _uc_webform_product_grid_orders($component, $order_status_cid)) {
  103. $data[$cid] = $row_data;
  104. }
  105. $cids[] = $component['cid'];
  106. }
  107. }
  108. if (empty($cids)) {
  109. return t('There are no products associated with this webform.');
  110. }
  111. else {
  112. return theme('uc_webform_product_analysis', array(
  113. 'node' => $node,
  114. 'data' => $data,
  115. 'sids' => $sids,
  116. 'analysis_component' => $analysis_component,
  117. 'order_status_cid' => $order_status_cid));
  118. }
  119. }
  120. /**
  121. * Generate statistics for product components, limited to checked out webforms.
  122. *
  123. * This information is displayed under the "orders" tab of the webform results.
  124. */
  125. function _uc_webform_product_orders($component, $order_status_cid) {
  126. // First, get the list of all submission IDs for webform submissions where
  127. // checkout has been completed.
  128. $query = db_select('webform_submitted_data', 'wsd')
  129. ->fields('wsd', array('sid'))
  130. ->condition('nid', $component['nid'], '=')
  131. ->condition('cid', $order_status_cid, '=')
  132. ->condition('data', 'Did not complete checkout', '<>');
  133. $sids = array();
  134. foreach ($query->execute() as $submission) {
  135. $sids[] = $submission->sid;
  136. }
  137. // Use the array of checked out submission ID's to grab only the checked out
  138. // product data.
  139. $product_results = array();
  140. $total = 0;
  141. if (!empty($sids)) {
  142. $co_query = db_select('webform_submitted_data', 'wsd')
  143. ->fields('wsd', array('no', 'data'))
  144. ->condition('cid', $component['cid'], '=')
  145. ->condition('nid', $component['nid'], '=')
  146. ->condition('sid', $sids, 'IN');
  147. foreach ($co_query->execute() as $co_result) {
  148. if ($co_result->no == 2) {
  149. $total += $co_result->data;
  150. }
  151. }
  152. }
  153. $product_info = explode('_', $component['extra']['product'], 2);
  154. $rows[0] = array(t($product_info[1]), $total);
  155. if ($total > 0) {
  156. return $rows;
  157. }
  158. else {
  159. return NULL;
  160. }
  161. }
  162. /**
  163. * Statistics for product_list components, limited to checked out webforms.
  164. *
  165. * This information is displayed under the "Orders" tab of the webform results.
  166. */
  167. function _uc_webform_product_list_orders($component, $order_status_cid) {
  168. // First, get the list of all submission IDs for webform submissions where
  169. // checkout has been completed.
  170. $query = db_select('webform_submitted_data', 'wsd')
  171. ->fields('wsd', array('sid'))
  172. ->condition('nid', $component['nid'], '=')
  173. ->condition('cid', $order_status_cid, '=')
  174. ->condition('data', 'Did not complete checkout', '<>');
  175. $sids = array();
  176. foreach ($query->execute() as $submission) {
  177. $sids[] = $submission->sid;
  178. }
  179. // Use the array of checked out submission ID's to grab only the checked out
  180. // product data.
  181. $product_results = array();
  182. if (!empty($sids)) {
  183. $co_query = db_select('webform_submitted_data', 'wsd')
  184. ->fields('wsd', array('no', 'data'))
  185. ->condition('cid', $component['cid'], '=')
  186. ->condition('nid', $component['nid'], '=')
  187. ->condition('sid', $sids, 'IN');
  188. foreach ($co_query->execute() as $co_result) {
  189. if ($co_result->no == 0) {
  190. continue;
  191. }
  192. else {
  193. if (array_key_exists($co_result->data, $product_results)) {
  194. $product_results[$co_result->data] += 1;
  195. }
  196. else {
  197. $product_results[$co_result->data] = 1;
  198. }
  199. }
  200. }
  201. }
  202. $rows = array();
  203. $count = 0;
  204. foreach ($product_results as $product => $qty) {
  205. $product_info = explode('_', $product, 2);
  206. $product_node = node_load($product_info[0]);
  207. $rows[$count] = array(t($product_node->model), $qty);
  208. $count++;
  209. }
  210. return $rows;
  211. }
  212. /**
  213. * Generate statistics for product_grid components, limited to checked out
  214. * webforms. This information is displayed under the "orders" tab of the
  215. * webform results.
  216. */
  217. function _uc_webform_product_grid_orders($component, $order_status_cid) {
  218. // Build the rows of the table, including the first column.
  219. $rows = array(array());
  220. $header = array(array());
  221. $product_nids = array();
  222. foreach ($component['extra']['products'] as $product) {
  223. $nid_sku = explode('_', $product, 2);
  224. $product_nids[] = $nid_sku[0];
  225. $product_node = node_load($nid_sku[0]);
  226. // I use the nid_sku combination here as a key.
  227. $rows[$product] = array($product_node->title);
  228. }
  229. // Select the available option IDs and names for each product in the table.
  230. $query = db_select('uc_product_options', 'po')
  231. ->fields('po', array('oid'));
  232. $query->join('uc_attribute_options', 'ao', 'po.oid = ao.oid');
  233. $query->addField('ao', 'name');
  234. $query->condition('po.nid', $product_nids, 'IN');
  235. // Build the header row.
  236. $options = array();
  237. foreach ($query->execute() as $option) {
  238. // Use the oid as an array key to help when quering the
  239. // webform_submitted_data table (since it stores the oid instead of the
  240. // option name).
  241. $header[$option->oid] = $option->name;
  242. }
  243. // Get a list of all submission IDs for submissions with completed checkouts.
  244. $query = db_select('webform_submitted_data', 'wsd')
  245. ->fields('wsd', array('sid'))
  246. ->condition('nid', $component['nid'], '=')
  247. ->condition('cid', $order_status_cid, '=')
  248. ->condition('data', 'Did not complete checkout', '<>');
  249. $sids = array();
  250. foreach ($query->execute() as $submission) {
  251. $sids[] = $submission->sid;
  252. }
  253. // Use the array of checked out submission ID's to grab only the checked out
  254. // product data.
  255. $selections = array();
  256. if (!empty($sids)) {
  257. $co_query = db_select('webform_submitted_data', 'wsd')
  258. ->fields('wsd', array('no', 'data'));
  259. $co_query->addExpression('COUNT(data)', 'datacount');
  260. $co_query->condition('cid', $component['cid'], '=');
  261. $co_query->condition('nid', $component['nid'], '=');
  262. $co_query->condition('sid', $sids, 'IN');
  263. $co_query->groupBy('no');
  264. $co_query->groupBy('data');
  265. foreach ($co_query->execute() as $data) {
  266. $aid_oid = explode('_', $data->data, 2);
  267. // The information is stored in the DB as attribute-ID_option-ID. This
  268. // line removes the attribute ID and leaves the $selections key as the
  269. // option ID.
  270. if (isset($aid_oid[1])) {
  271. $selections[$data->no][$aid_oid[1]] = $data->datacount;
  272. }
  273. }
  274. }
  275. // Check to see if any completed orders include this component. Return NULL
  276. // if there aren't any.
  277. if (!empty($selections)) {
  278. // Build up the 2D array that will be used to create the table.
  279. foreach ($rows as $rkey => $rval) {
  280. if ($rkey != 0) {
  281. foreach ($header as $hkey => $hval) {
  282. if ($hkey != 0) {
  283. // $rkey = nid_sku.
  284. // $hkey = option ID.
  285. $rows[$rkey][] = isset($selections[$rkey][$hkey]) ? $selections[$rkey][$hkey] : 0;
  286. }
  287. }
  288. }
  289. }
  290. $output = theme('table', array(
  291. 'header' => $header,
  292. 'rows' => $rows,
  293. 'attributes' => array(
  294. 'class' => array(
  295. 'webform-product-grid',
  296. ),
  297. ),
  298. ));
  299. return array(array(array('data' => $output, 'colspan' => 2)));
  300. }
  301. else {
  302. return NULL;
  303. }
  304. }
  305. /**
  306. * Output the content of the Analysis page.
  307. *
  308. * @see webform_results_analysis()
  309. */
  310. function theme_uc_webform_product_analysis($variables) {
  311. $node = $variables['node'];
  312. $rows = array();
  313. $question_number = 0;
  314. $single = isset($analysis_component);
  315. $header = array(
  316. $single ? $analysis_component['name'] : t('Q'),
  317. array(
  318. 'data' => $single ? '&nbsp' : t('Product Selection (completed checkouts)'),
  319. 'colspan' => '10',
  320. ),
  321. );
  322. foreach ($variables['data'] as $cid => $row_data) {
  323. $question_number++;
  324. if (is_array($row_data)) {
  325. $row = array();
  326. if (!$single) {
  327. $row[] = array(
  328. 'data' => '<strong>' . $question_number . '</strong>',
  329. 'rowspan' => count($row_data) + 1,
  330. 'valign' => 'top',
  331. );
  332. $row[] = array(
  333. 'data' => '<strong>' . check_plain($node->webform['components'][$cid]['name']) . '</strong>',
  334. 'colspan' => '10',
  335. );
  336. }
  337. $rows = array_merge($rows, array_merge(array($row), $row_data));
  338. }
  339. }
  340. $num_no_checkout = db_select('webform_submitted_data', 'wsd')
  341. ->condition('nid', $node->nid, '=')
  342. ->condition('data', 'Did not complete checkout', '=')
  343. ->countQuery()
  344. ->execute()
  345. ->fetchField();
  346. $total_submissions = db_select('webform_submitted_data', 'wsd')
  347. ->fields('wsd', array('DISTINCT sid'))
  348. ->condition('nid', $node->nid, '=')
  349. ->countQuery()
  350. ->execute()
  351. ->fetchField();
  352. $rows[] = array(array(
  353. 'data' => '<strong>$</strong>',
  354. 'rowspan' => 4,
  355. 'valign' => 'top',
  356. ), array(
  357. 'data' => '<strong>Checkout statistics</strong>',
  358. 'colspan' => 10,
  359. ));
  360. $rows[] = array(t('Total completed checkouts'), $total_submissions - $num_no_checkout);
  361. $rows[] = array('<strong>' . t('Total webform submissions') . '</strong>', $total_submissions);
  362. return theme('table', array('header' => $header, 'rows' => $rows));
  363. }
  364. /****************************************
  365. * Form API
  366. */
  367. /**
  368. * Adjustment for $form['#submit'][].
  369. */
  370. function uc_webform_form_node_submit(&$form, &$form_state) {
  371. }
  372. /**
  373. * Form alter for add to cart.
  374. */
  375. function uc_webform_form_uc_product_add_to_cart_form_alter(&$form, &$form_state) {
  376. if (isset($form['node']['#value']->webform_nid)) {
  377. // Replace standard add to cart with the webform corresponding to this
  378. // product.
  379. }
  380. }
  381. /**
  382. * Form alter.
  383. */
  384. function uc_webform_form_alter(&$form, &$form_state, $form_id) {
  385. // THIS FAILS because $form['submitted']['order_status']['#default_value']
  386. // is not set.
  387. // Ensure that the order_status field cannot be modified with firebug, etc.
  388. if ($form_id == 'webform_component_form' || $form_id == 'webform_component_edit_form') {
  389. // Allow select components to change attributes/options selected for a
  390. // product, i.e. via sku.
  391. if ($form['type']['#value'] == 'select') {
  392. $form['extra']['uc_webform_options'] = array(
  393. '#title' => 'Product SKU ',
  394. '#description' => 'You can choose to set what options will be selected by safe_key|option ',
  395. '#type' => 'textarea',
  396. '#default_value' => variable_get('uc_webform_sku_' . $form['nid']['#value'] . '_' . $form['cid']['#value'], ''),
  397. );
  398. $form['#submit'][] = 'uc_webform_sku_submit';
  399. }
  400. }
  401. }
  402. /**
  403. * Adjustment for $form['#submit'][].
  404. */
  405. function uc_webform_sku_submit(&$form, &$form_state) {
  406. if (isset($form_state['values']['extra']['uc_webform_options'])) {
  407. variable_set('uc_webform_sku_' . $form_state['values']['nid'] . '_' . $form_state['values']['cid'], $form_state['values']['extra']['uc_webform_options']);
  408. }
  409. }
  410. /**
  411. * Confirmation form before deleting products from a cart.
  412. *
  413. * When removing a single product from a cart alert the user that doing so will
  414. * also remove all other products associated with the same form.
  415. */
  416. function uc_webform_submission_delete_products_form($form, &$form_state,$wf_nid) {
  417. $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?');
  418. $destination = 'cart/'.$wf_nid;
  419. return confirm_form(array(), NULL, $destination, $question, t('Delete'), t('Cancel'));
  420. }
  421. /**
  422. * Adjustment for $form['#submit'][].
  423. */
  424. function uc_webform_submission_delete_products_form_submit($form, &$form_state) {
  425. // Remove all items from the current webform submission from the cart.
  426. $cart_items = uc_cart_get_contents();
  427. $wf_nid = arg(2);
  428. foreach ($cart_items as $cart_item) {
  429. if (isset($cart_item->data['webform_sid']) && $cart_item->data['webform_nid'] == $wf_nid) {
  430. uc_cart_remove_item($cart_item->nid, $cart_item->cart_id, $cart_item->data);
  431. }
  432. }
  433. $form_state['redirect'] = 'cart';
  434. }
  435. /**
  436. * Implements hook_form_FORM_ID_alter().
  437. */
  438. function uc_webform_form_uc_cart_view_form_alter(&$form, &$form_state) {
  439. $count = 0;
  440. while (isset($form['items'][$count])) {
  441. if (isset($form['items'][$count]['data']['#value'])) {
  442. $data = unserialize($form['items'][$count]['data']['#value']);
  443. if (isset($data['webform_ctype'])) {
  444. if (($data['webform_ctype'] == 'product_list') || ($data['webform_ctype'] == 'product') || ($data['webform_ctype'] == 'product_grid')) {
  445. // Check to see if the product was a mandatory field in the webform
  446. // submission.
  447. $component_query = db_select('webform_component', 'wc')
  448. ->fields('wc', array('mandatory', 'extra'))
  449. ->condition('nid', $data['webform_nid'], '=')
  450. ->condition('cid', $data['webform_cid'], '=');
  451. $component_info = $component_query->execute()->fetchAssoc();
  452. $component_info['extra'] = unserialize($component_info['extra']);
  453. // Users may not edit the quantity of a product from the cart.
  454. $form['items'][$count]['qty']['#disabled'] = TRUE;
  455. $data_query = db_select('webform_submitted_data', 'wsd')
  456. ->fields('wsd', array('data'))
  457. ->condition('nid', $data['webform_nid'], '=')
  458. ->condition('sid', $data['webform_sid'], '=')
  459. ->condition('cid', $data['webform_cid'], '=')
  460. ->condition('no', 0, '=');
  461. $data_result = $data_query->execute();
  462. $form['items'][$count]['qty']['#value'] = $data_result->fetchField();
  463. // Force the user to remove *all* webform-related products from the
  464. // cart if they want to remove *one* mandatory webform-related
  465. // product from the cart.
  466. //if ($component_info['mandatory'] == 1) {
  467. $form['items'][$count]['remove']['#type'] = 'item';
  468. $form['items'][$count]['remove']['#markup'] = l(t('Delete'), "cart/delete-form/".$data['webform_nid'], array(
  469. 'query' => drupal_get_destination(),
  470. ));
  471. //}
  472. //Remove link for registration products
  473. $form['items'][$count]['desc']['#markup'] = strip_tags($form['items'][$count]['desc']['#markup']);
  474. if (($data['webform_ctype'] == 'product_list') || ($data['webform_ctype'] == 'product_grid')) {
  475. // Users may not edit the quantity of a product_list or
  476. // product_grid webform product.
  477. $form['items'][$count]['qty']['#disabled'] = TRUE;
  478. // If #value is not specified here, all products will be removed
  479. // if any product is removed.
  480. $form['items'][$count]['qty']['#value'] = 1;
  481. }
  482. }
  483. }
  484. }
  485. $count++;
  486. }
  487. }
  488. /**
  489. * Implements hook_theme_registry_alter().
  490. *
  491. * There is a good article about this here:
  492. * http://www.lullabot.com/articles/overriding-theme-functions-in-modules
  493. */
  494. function uc_webform_theme_registry_alter(&$theme_registry) {
  495. if (!empty($theme_registry['webform_components_form'])) {
  496. $theme_registry['webform_components_form']['function'] = 'uc_webform_webform_components_form';
  497. }
  498. }
  499. /**
  500. * Override 'theme_webform_components_form($form)',
  501. * found in webform.components.inc.
  502. * This function will need to be updated everytime quicksketch makes a
  503. * corresponding change.
  504. *
  505. * Remove the 'Clone', 'Edit' and 'Delete' links from the hidden Order Status
  506. * component if
  507. * there are products included in the webform.
  508. */
  509. function uc_webform_webform_components_form($variables) {
  510. $form = $variables['form'];
  511. $form['components']['#attached']['library'][] = array('webform', 'admin');
  512. drupal_add_tabledrag('webform-components', 'order', 'sibling', 'webform-weight');
  513. drupal_add_tabledrag('webform-components', 'match', 'parent', 'webform-pid', 'webform-pid', 'webform-cid');
  514. $node = $form['#node'];
  515. $header = array(t('Label'), t('Type'), t('Value'), t('Mandatory'), t('Weight'), array(
  516. 'data' => t('Operations'),
  517. 'colspan' => 3,
  518. ),
  519. );
  520. $rows = array();
  521. // Add a row containing form elements for a new item.
  522. unset($form['add']['name']['#title'], $form['add_type']['#description']);
  523. $form['add']['name']['#attributes']['rel'] = t('New component name');
  524. $form['add']['name']['#attributes']['class'] = array('webform-default-value');
  525. $form['add']['cid']['#attributes']['class'] = array('webform-cid');
  526. $form['add']['pid']['#attributes']['class'] = array('webform-pid');
  527. $form['add']['weight']['#attributes']['class'] = array('webform-weight');
  528. $row_data = array(
  529. drupal_render($form['add']['name']),
  530. drupal_render($form['add']['type']),
  531. '',
  532. drupal_render($form['add']['mandatory']),
  533. drupal_render($form['add']['cid']) . drupal_render($form['add']['pid']) . drupal_render($form['add']['weight']),
  534. array(
  535. 'colspan' => 3,
  536. 'data' => drupal_render($form['add']['add']),
  537. ),
  538. );
  539. $add_form = array(
  540. 'data' => $row_data,
  541. 'class' => array('draggable', 'webform-add-form'),
  542. );
  543. $form_rendered = FALSE;
  544. if (!empty($node->webform['components'])) {
  545. $component_tree = array();
  546. $page_count = 1;
  547. _webform_components_tree_build($node->webform['components'], $component_tree, 0, $page_count);
  548. $component_tree = _webform_components_tree_sort($component_tree);
  549. /**
  550. * Build the table rows.
  551. */
  552. function _webform_components_form_rows($node, $cid, $component, $level, &$form, &$rows, &$add_form) {
  553. // Create presentable values.
  554. if (drupal_strlen($component['value']) > 30) {
  555. $component['value'] = drupal_substr($component['value'], 0, 30);
  556. $component['value'] .= '...';
  557. }
  558. $component['value'] = check_plain($component['value']);
  559. // Remove individual titles from the mandatory and weight fields.
  560. unset($form['components'][$cid]['mandatory']['#title']);
  561. unset($form['components'][$cid]['pid']['#title']);
  562. unset($form['components'][$cid]['weight']['#title']);
  563. // Add special classes for weight and parent fields.
  564. $form['components'][$cid]['cid']['#attributes']['class'] = array('webform-cid');
  565. $form['components'][$cid]['pid']['#attributes']['class'] = array('webform-pid');
  566. $form['components'][$cid]['weight']['#attributes']['class'] = array('webform-weight');
  567. // Build indentation for this row.
  568. $indents = '';
  569. for ($n = 1; $n <= $level; $n++) {
  570. $indents .= '<div class="indentation">&nbsp;</div>';
  571. }
  572. // Add each component to a table row.
  573. // Alteration: I've added this check to remove the 'Edit', 'Clone',
  574. // 'Delete' links when necessary.
  575. $product_form = 0;
  576. foreach ($form['#node']->webform['components'] as $comp) {
  577. $product_form = (($comp['type'] == 'product') || ($comp['type'] == 'product_list') || ($comp['type'] == 'product_grid')) ? 1 : 0;
  578. if ($product_form == 1) {
  579. break;
  580. }
  581. }
  582. if (($product_form == 1) && ($component['form_key'] == 'order_status')) {
  583. // Remove the Edit, Clone and Delete links.
  584. $row_data = array(
  585. $indents . filter_xss($component['name']),
  586. t($component['type']),
  587. ($component['value'] == '') ? '-' : $component['value'],
  588. drupal_render($form['components'][$cid]['mandatory']),
  589. drupal_render($form['components'][$cid]['cid']) . drupal_render($form['components'][$cid]['pid']) . drupal_render($form['components'][$cid]['weight']),
  590. '-',
  591. '-',
  592. '-',
  593. );
  594. }
  595. else {
  596. // Here is the original code.
  597. $row_data = array(
  598. $indents . filter_xss($component['name']),
  599. t($component['type']),
  600. ($component['value'] == '') ? '-' : $component['value'],
  601. drupal_render($form['components'][$cid]['mandatory']),
  602. drupal_render($form['components'][$cid]['cid']) . drupal_render($form['components'][$cid]['pid']) . drupal_render($form['components'][$cid]['weight']),
  603. l(t('Edit'), 'node/' . $node->nid . '/webform/components/' . $cid, array('query' => drupal_get_destination())),
  604. l(t('Clone'), 'node/' . $node->nid . '/webform/components/' . $cid . '/clone', array('query' => drupal_get_destination())),
  605. l(t('Delete'), 'node/' . $node->nid . '/webform/components/' . $cid . '/delete', array('query' => drupal_get_destination())),
  606. );
  607. }
  608. $row_class = array('draggable');
  609. if (!webform_component_feature($component['type'], 'group')) {
  610. $row_class[] = 'tabledrag-leaf';
  611. }
  612. if ($component['type'] == 'pagebreak') {
  613. $row_class[] = 'tabledrag-root';
  614. $row_class[] = 'webform-pagebreak';
  615. $row_data[0] = array(
  616. 'class' => array('webform-pagebreak'),
  617. 'data' => $row_data[0],
  618. );
  619. }
  620. $rows[] = array(
  621. 'data' => $row_data,
  622. 'class' => $row_class,
  623. );
  624. if (isset($component['children']) && is_array($component['children'])) {
  625. foreach ($component['children'] as $cid => $component) {
  626. _webform_components_form_rows($node, $cid, $component, $level + 1, $form, $rows, $add_form);
  627. }
  628. }
  629. // Add the add form if this was the last edited component.
  630. if (isset($_GET['cid']) && $component['cid'] == $_GET['cid'] && $add_form) {
  631. $add_form['data'][0] = $indents . $add_form['data'][0];
  632. $rows[] = $add_form;
  633. $add_form = FALSE;
  634. }
  635. }
  636. foreach ($component_tree['children'] as $cid => $component) {
  637. _webform_components_form_rows($node, $cid, $component, 0, $form, $rows, $add_form);
  638. }
  639. }
  640. else {
  641. $rows[] = array(array(
  642. 'data' => t('No Components, add a component below.'),
  643. 'colspan' => 9,
  644. ),
  645. );
  646. }
  647. // Append the add form if not already printed.
  648. if ($add_form) {
  649. $rows[] = $add_form;
  650. }
  651. $output = '';
  652. $output .= theme('table', array(
  653. 'header' => $header,
  654. 'rows' => $rows,
  655. 'attributes' => array('id' => 'webform-components'),
  656. ));
  657. $output .= drupal_render_children($form);
  658. return $output;
  659. }
  660. /**
  661. * Implements hook_uc_order().
  662. */
  663. function uc_webform_uc_order($op, &$arg1, $arg2) {
  664. switch ($op) {
  665. case 'submit':
  666. foreach ($arg1->products as $product) {
  667. if (isset($product->data['webform_sid'])) {
  668. $message = l(t('View form submission'), 'node/' . $product->data['webform_nid'] . '/submission/' . $product->data['webform_sid']);
  669. // Add an admin comment that links to the webform submission.
  670. uc_order_comment_save($arg1->order_id, $arg1->uid, $message, 'admin');
  671. // break;
  672. }
  673. }
  674. break;
  675. case 'update':
  676. foreach ($arg1->products as $product) {
  677. if (isset($product->data['webform_sid'])) {
  678. // Update the hidden Order Status field of the webform submission.
  679. $status = t('Order #') . $arg1->order_id . ': ' . drupal_strtoupper($arg2);
  680. $webform_node = node_load($product->data['webform_nid']);
  681. $webform_submission = webform_menu_submission_load($product->data['webform_sid'], $product->data['webform_nid']);
  682. if (count($webform_node->webform['components'])) {
  683. foreach ($webform_node->webform['components'] as $component) {
  684. if ($component['form_key'] == 'order_status') {
  685. $webform_submission->data[$component['cid']]['value'][0] = $status;
  686. webform_submission_update($webform_node, $webform_submission);
  687. }
  688. }
  689. }
  690. }
  691. }
  692. break;
  693. }
  694. }
  695. /**
  696. * Implements hook_uc_cart_item().
  697. * NOTE THIS IS REMOVED in Ubercart beta 4.
  698. * See http://drupal.org/node/1424852#comment-5611230
  699. */
  700. function uc_webform_uc_cart_item($op, &$item) {
  701. switch ($op) {
  702. case 'remove':
  703. $data = unserialize($item->data);
  704. if ($data['webform_ctype'] == 'product_list') {
  705. db_delete('webform_submitted_data')
  706. ->condition('nid', $data['webform_nid'], '=')
  707. ->condition('sid', $data['webform_sid'], '=')
  708. ->condition('data', $item->nid, '=')
  709. ->execute();
  710. }
  711. elseif ($data['webform_ctype'] == 'product') {
  712. db_delete('webform_submitted_data')
  713. ->condition('nid', $data['webform_nid'], '=')
  714. ->condition('sid', $data['webform_sid'], '=')
  715. ->condition('cid', $data['webform_cid'], '=')
  716. ->execute();
  717. }
  718. elseif ($data['webform_ctype'] == 'product_grid') {
  719. db_delete('webform_submitted_data')
  720. ->condition('nid', $data['webform_nid'], '=')
  721. ->condition('sid', $data['webform_sid'], '=')
  722. ->condition('cid', $data['webform_cid'], '=')
  723. ->execute();
  724. }
  725. break;
  726. }
  727. }
  728. /****************************************
  729. * Webform Hooks
  730. */
  731. /**
  732. * Implementation of hook_webform_component_info().
  733. *
  734. * Define components available to Webform.
  735. *
  736. * @see http://drupal.org/node/886014
  737. */
  738. function uc_webform_webform_component_info() {
  739. return array(
  740. 'product_list' => array(
  741. 'label' => t('Product list'),
  742. 'description' => t('Add a list of products to your webform.'),
  743. 'features' => array(
  744. 'csv' => TRUE,
  745. 'email' => TRUE,
  746. 'required' => TRUE,
  747. ),
  748. 'file' => 'components/product_list.inc',
  749. ),
  750. 'product' => array(
  751. 'label' => t('Product'),
  752. 'description' => t('Add a single product to your webform.'),
  753. 'features' => array(
  754. 'csv' => TRUE,
  755. 'email' => TRUE,
  756. 'required' => TRUE,
  757. ),
  758. 'file' => 'components/product.inc',
  759. ),
  760. 'product_grid' => array(
  761. 'label' => t('Product grid'),
  762. 'description' => t('Add a grid of products that contain attributes. Users select options.'),
  763. 'features' => array(
  764. 'csv' => TRUE,
  765. 'email' => TRUE,
  766. 'required' => TRUE,
  767. ),
  768. 'file' => 'components/product_grid.inc',
  769. ),
  770. 'hidden_product' => array(
  771. 'label' => t('Hidden product'),
  772. 'description' => t('A product which is not visible to the user, but which will be added to the cart with the webform submission.'),
  773. 'file' => 'components/hidden_product.inc',
  774. 'features' => array(
  775. 'required' => FALSE,
  776. 'email_address' => TRUE,
  777. 'email_name' => TRUE,
  778. 'title_display' => FALSE,
  779. ),
  780. ),
  781. );
  782. }
  783. /**
  784. * Respond to a Webform submission being inserted -
  785. * hook_webform_submission_insert().
  786. */
  787. function uc_webform_webform_submission_insert($node, $submission) {
  788. // If the latest webform submission has products in it, remove the
  789. // previous webform submission products and add the new ones. Otherwise,
  790. // allow the form to be submitted without incident.
  791. $remove = FALSE;
  792. foreach ($node->webform['components'] as $component) {
  793. if (($component['type'] == 'product_list') || ($component['type'] == 'product') || ($component['type'] == 'product_grid') || ($component['type'] == 'hidden_product')) {
  794. $remove = TRUE;
  795. break;
  796. }
  797. }
  798. // Believe that the stuff below can be removed thanks to
  799. // hook_webform_submission_delete() below.
  800. $remove_sid = FALSE;
  801. if ($remove) {
  802. // Kontrola : this feature is disabled on client request in order to allow for
  803. // multiple registrations on single order 04/29/2013
  804. // Remove items from previous webform submissions from the cart.
  805. // $cart_items = uc_cart_get_contents();
  806. //
  807. // foreach ($cart_items as $cart_item) {
  808. // if (isset($cart_item->data['webform_sid']) && ($cart_item->data['webform_sid'] != $submission->sid)) {
  809. // // Capture the submission ID of the previous submission so that we can
  810. // // clean up the webform tables next.
  811. // $remove_sid = (integer) $cart_item->data['webform_sid'];
  812. //
  813. // // Remove the item from the cart.
  814. // uc_cart_remove_item($cart_item->nid, $cart_item->cart_id, $cart_item->data);
  815. // }
  816. // }
  817. //
  818. // if ($remove_sid) {
  819. // // Remove the previous submissions from the webform tables.
  820. // db_delete('webform_submitted_data')
  821. // ->condition('sid', $remove_sid, '=')
  822. // ->execute();
  823. //
  824. // db_delete('webform_submissions')
  825. // ->condition('sid', $remove_sid, '=')
  826. // ->execute();
  827. // }
  828. // Add new items to the cart.
  829. foreach ($node->webform['components'] as $component) {
  830. if ($component['type'] == 'product_list') {
  831. if (array_key_exists($component['cid'], $submission->data)) {
  832. $key = $component['cid'];
  833. foreach ($submission->data[$key]['value'] as $val) {
  834. // This is all very dependent on the way that the product data is
  835. // stored in the webform_submitted_data table. Take a look there,
  836. // and also check out the uc_webform README.txt file.
  837. $product_info = explode('_', $val, 2);
  838. if (is_numeric($product_info[0])) {
  839. uc_cart_add_item($product_info[0], 1, array(
  840. 'webform_sid' => $submission->sid,
  841. 'webform_nid' => $node->nid,
  842. 'webform_ctype' => 'product_list',
  843. 'webform_cid' => $component['cid'],
  844. ));
  845. }
  846. }
  847. }
  848. }
  849. elseif ($component['type'] == 'product') {
  850. if (array_key_exists($component['cid'], $submission->data)) {
  851. $key = $component['cid'];
  852. // The quantity specified by the user.
  853. $qty = (integer) $submission->data[$key]['value'][0];
  854. $component_query = db_select('webform_component', 'wc')
  855. ->fields('wc', array('extra'))
  856. ->condition('cid', $component['cid'], '=')
  857. ->condition('nid', $node->nid, '=')
  858. ->execute();
  859. $component_data = unserialize($component_query->fetchField());
  860. // $product_info will contain an array with the product node ID and
  861. // the selected model (sku).
  862. $product_info = explode('_', $component_data['product'], 2);
  863. if ($qty > 0) {
  864. uc_cart_add_item($product_info[0], $qty, array(
  865. 'webform_sid' => $submission->sid,
  866. 'webform_nid' => $node->nid,
  867. 'webform_ctype' => 'product',
  868. 'webform_cid' => $component['cid'],
  869. ));
  870. }
  871. }
  872. }
  873. elseif ($component['type'] == 'hidden_product') {
  874. if (array_key_exists($component['cid'], $submission->data)) {
  875. $key = $component['cid'];
  876. // The quantity specified by the creator of the webform.
  877. $qty = (integer) $submission->data[$key]['value'][0];
  878. $component_query = db_select('webform_component', 'wc')
  879. ->fields('wc', array('extra'))
  880. ->condition('cid', $component['cid'], '=')
  881. ->condition('nid', $node->nid, '=')
  882. ->execute();
  883. $component_data = unserialize($component_query->fetchField());
  884. // $product_info will contain an array with the product node ID and
  885. // the selected model (sku).
  886. $product_info = explode('_', $component_data['hidden_product'], 2);
  887. if ($qty > 0) {
  888. uc_cart_add_item($product_info[0], $qty, array(
  889. 'webform_sid' => $submission->sid,
  890. 'webform_nid' => $node->nid,
  891. 'webform_ctype' => 'hidden_product',
  892. 'webform_cid' => $component['cid'],
  893. ));
  894. }
  895. }
  896. }
  897. elseif ($component['type'] == 'product_grid') {
  898. if (array_key_exists($component['cid'], $submission->data)) {
  899. $cid = $component['cid'];
  900. foreach ($submission->data[$cid]['value'] as $key => $prod_option) {
  901. // This is all very dependent on the way that the product data is
  902. // stored in the webform_submitted_data table. Take a look there,
  903. // and also check out the uc_webform README.txt file.
  904. if ($prod_option) {
  905. $product_info = explode('_', $key, 2);
  906. // The $prod_option variable actually contains both the attribute
  907. // ID and the option ID in the form of a string: aid_oid.
  908. $option_info = explode('_', $prod_option, 2);
  909. uc_cart_add_item($product_info[0], 1, array(
  910. 'attributes' => array(
  911. $option_info[0] => $option_info[1],
  912. ),
  913. 'webform_sid' => $submission->sid,
  914. 'webform_nid' => $node->nid,
  915. 'webform_ctype' => 'product_grid',
  916. 'webform_cid' => $component['cid'],
  917. )
  918. );
  919. }
  920. }
  921. }
  922. }
  923. }
  924. }
  925. }
  926. /**
  927. * Implements hook_webform_submission_delete().
  928. */
  929. function uc_webform_webform_submission_delete($node, $submission) {
  930. db_delete('uc_webform_submission')
  931. ->condition('sid', $submission->sid, '=')
  932. ->execute();
  933. }
  934. /**
  935. * Implements hook_webform_submission_load(&$submissions).
  936. */
  937. function uc_webform_webform_submission_load(&$submissions) {
  938. foreach ($submissions as $delta => $submission) {
  939. $query = db_select('uc_webform_submission', 'ucs')
  940. ->fields('ucs')
  941. ->condition('sid', $submission->sid, '=')
  942. ->execute()
  943. ->fetchAssoc();
  944. if ($query) {
  945. $submissions[$delta] = (object) array_merge((array) $submission, $query);
  946. }
  947. }
  948. }
  949. /**
  950. * Implements hook_webform_submission_render_alter().
  951. */
  952. function uc_webform_webform_submission_render_alter(&$renderable) {
  953. if (!isset($renderable['#submission']->order_id)) {
  954. return;
  955. }
  956. }
  957. /**
  958. * Implements hook_webform_component_insert().
  959. * http://api.lullabot.com/hook_webform_component_insert/7
  960. */
  961. function uc_webform_webform_component_insert($component) {
  962. if (($component['type'] == 'product') || ($component['type'] == 'product_list') || ($component['type'] == 'product_grid') || ($component['type'] == 'hidden_product')) {
  963. // Check to see whether the hidden field already exists.
  964. $result = db_select('webform_component', 'wc')
  965. ->fields('wc', array('cid'))
  966. ->condition('nid', $component['nid'], '=')
  967. ->condition('form_key', 'order_status', '=')
  968. ->execute()
  969. ->fetchField();
  970. $extra = array('conditional_operator' => '=');
  971. if (!$result) {
  972. // Insert a hidden field into the webform.
  973. $order_status_component = array(
  974. 'nid' => $component['nid'],
  975. 'pid' => $component['pid'],
  976. 'form_key' => 'order_status',
  977. 'name' => 'Order Status',
  978. 'type' => 'hidden',
  979. 'value' => 'Did not complete checkout',
  980. 'extra' => $extra,
  981. 'mandatory' => 0,
  982. 'weight' => -100,
  983. );
  984. webform_component_insert($order_status_component);
  985. }
  986. }
  987. }
  988. /**
  989. * Respond to a Webform component being updated in the database.
  990. */
  991. function uc_webform_webform_component_update($component) {
  992. if (($component['type'] == 'product') || ($component['type'] == 'product_list') || ($component['type'] == 'product_grid') || ($component['type'] == 'hidden_product')) {
  993. // We need to check to see whether the hidden field already exists.
  994. // We also need to find the max component id in the webform.
  995. $query = db_select('webform_component', 'wc')
  996. ->fields('wc', array('cid', 'form_key'))
  997. ->condition('wc.nid', $component['nid'], '=');
  998. $components_info['cids'] = array();
  999. $components_info['form_keys'] = array();
  1000. foreach ($query->execute() as $result) {
  1001. array_push($components_info['cids'], $result->cid);
  1002. array_push($components_info['form_keys'], $result->form_key);
  1003. }
  1004. $extra = array('conditional_operator' => '=');
  1005. if (!in_array('order_status', $components_info['form_keys'])) {
  1006. // Insert a hidden field into the webform.
  1007. $order_status_component = array(
  1008. nid => $component['nid'],
  1009. form_key => 'order_status',
  1010. name => 'Order Status',
  1011. type => 'hidden',
  1012. value => 'Did not complete checkout',
  1013. extra => $extra,
  1014. mandatory => 0,
  1015. weight => -100,
  1016. );
  1017. webform_component_insert($order_status_component);
  1018. }
  1019. }
  1020. }