uc_cart.pages.inc 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620
  1. <?php
  2. /**
  3. * @file
  4. * Cart menu items.
  5. */
  6. /**
  7. * Displays the cart view page.
  8. *
  9. * Show the products in the cart with a form to adjust cart contents or go to
  10. * checkout.
  11. */
  12. function uc_cart_view() {
  13. // Failsafe so that this function only works when called with no arguments.
  14. // This prevents the accidental wiping of the cart_order session variable.
  15. if (func_num_args() > 0) {
  16. return MENU_NOT_FOUND;
  17. }
  18. // Load the array of shopping cart items.
  19. $items = uc_cart_get_contents();
  20. // Display the empty cart page if there are no items in the cart.
  21. if (empty($items)) {
  22. return array(
  23. '#theme' => 'uc_empty_cart',
  24. );
  25. }
  26. $build = array();
  27. // Load through the cart panes...
  28. foreach (uc_cart_cart_pane_list($items) as $id => $pane) {
  29. // If the pane is enabled...
  30. if ($pane['enabled']) {
  31. // Add its output to the cart view.
  32. $build[$id] = $pane['body'];
  33. }
  34. }
  35. // Add a custom cart breadcrumb if specified.
  36. if (($text = variable_get('uc_cart_breadcrumb_text', '')) !== '') {
  37. $link = l($text, variable_get('uc_cart_breadcrumb_url', '<front>'));
  38. drupal_set_breadcrumb(array($link));
  39. }
  40. return $build;
  41. }
  42. /**
  43. * Confirm that the customer wants to empty their cart.
  44. */
  45. function uc_cart_empty_confirm($form, &$form_state) {
  46. return confirm_form($form, t('Are you sure you want to empty your shopping cart?'), 'cart');
  47. }
  48. /**
  49. * Submission handler to empty the cart after confirmations.
  50. */
  51. function uc_cart_empty_confirm_submit($form, &$form_state) {
  52. uc_cart_empty();
  53. $form_state['redirect'] = 'cart';
  54. }
  55. /**
  56. * Displays the cart checkout page built of checkout panes from enabled modules.
  57. */
  58. function uc_cart_checkout() {
  59. global $user;
  60. $items = uc_cart_get_contents();
  61. if (count($items) == 0 || !variable_get('uc_checkout_enabled', TRUE)) {
  62. drupal_goto('cart');
  63. }
  64. if (($min = variable_get('uc_minimum_subtotal', 0)) > 0) {
  65. $subtotal = 0;
  66. if (is_array($items) && count($items) > 0) {
  67. foreach ($items as $item) {
  68. $data = module_invoke($item->module, 'uc_cart_display', $item);
  69. if (!empty($data)) {
  70. $subtotal += $data['#total'];
  71. }
  72. }
  73. }
  74. if ($subtotal < $min) {
  75. drupal_set_message(t('The minimum order subtotal for checkout is @min.', array('@min' => uc_currency_format($min))), 'error');
  76. drupal_goto('cart');
  77. }
  78. }
  79. // Send anonymous users to login page when anonymous checkout is disabled.
  80. if (!$user->uid && !variable_get('uc_checkout_anonymous', TRUE)) {
  81. drupal_set_message(t('You must login before you can proceed to checkout.'));
  82. if (variable_get('user_register', 1) != 0) {
  83. drupal_set_message(t('If you do not have an account yet, you should <a href="!url">register now</a>.', array('!url' => url('user/register', array('query' => drupal_get_destination())))));
  84. }
  85. drupal_goto('user', array('query' => drupal_get_destination()));
  86. }
  87. // Load an order from the session, if available.
  88. if (isset($_SESSION['cart_order'])) {
  89. $order = uc_order_load($_SESSION['cart_order']);
  90. if ($order) {
  91. // Don't use an existing order if it has changed status or owner, or if
  92. // there has been no activity for 10 minutes (to prevent identity theft).
  93. if (uc_order_status_data($order->order_status, 'state') != 'in_checkout' ||
  94. ($user->uid > 0 && $user->uid != $order->uid) ||
  95. $order->modified < REQUEST_TIME - UC_CART_CHECKOUT_TIMEOUT) {
  96. if (uc_order_status_data($order->order_status, 'state') == 'in_checkout' && $order->modified < REQUEST_TIME - UC_CART_CHECKOUT_TIMEOUT) {
  97. // Mark expired orders as abandoned.
  98. uc_order_update_status($order->order_id, 'abandoned');
  99. }
  100. unset($order);
  101. }
  102. }
  103. else {
  104. // Ghost session.
  105. unset($_SESSION['cart_order']);
  106. drupal_set_message(t('Your session has expired or is no longer valid. Please review your order and try again.'));
  107. drupal_goto('cart');
  108. }
  109. }
  110. // Determine whether the form is being submitted or built for the first time.
  111. if (isset($_POST['form_id']) && $_POST['form_id'] == 'uc_cart_checkout_form') {
  112. // If this is a form submission, make sure the cart order is still valid.
  113. if (!isset($order)) {
  114. drupal_set_message(t('Your session has expired or is no longer valid. Please review your order and try again.'));
  115. drupal_goto('cart');
  116. }
  117. elseif (!empty($_SESSION['uc_cart_order_rebuild'])) {
  118. drupal_set_message(t('Your shopping cart contents have changed. Please review your order and try again.'));
  119. drupal_goto('cart');
  120. }
  121. }
  122. else {
  123. // Prepare the cart order.
  124. $rebuild = FALSE;
  125. if (!isset($order)) {
  126. // Create a new order if necessary.
  127. $order = uc_order_new($user->uid);
  128. $_SESSION['cart_order'] = $order->order_id;
  129. $rebuild = TRUE;
  130. }
  131. elseif (!empty($_SESSION['uc_cart_order_rebuild'])) {
  132. // Or, if the cart has changed, then remove old products and line items.
  133. $efq = new EntityFieldQuery();
  134. $result = $efq->entityCondition('entity_type', 'uc_order_product')
  135. ->propertyCondition('order_id', $order->order_id)
  136. ->execute();
  137. if (!empty($result['uc_order_product'])) {
  138. $product_ids = array_keys($result['uc_order_product']);
  139. uc_order_product_delete_multiple($product_ids);
  140. }
  141. uc_order_delete_line_item($order->order_id, TRUE);
  142. $rebuild = TRUE;
  143. }
  144. if ($rebuild) {
  145. // Copy the cart contents to the cart order.
  146. $order->products = uc_cart_get_contents();
  147. unset($_SESSION['uc_cart_order_rebuild']);
  148. }
  149. elseif (!uc_order_product_revive($order->products)) {
  150. drupal_set_message(t('Some of the products in this order are no longer available.'), 'error');
  151. drupal_goto('cart');
  152. }
  153. }
  154. // Trigger the "Customer starts checkout" hook and event.
  155. module_invoke_all('uc_cart_checkout_start', $order);
  156. rules_invoke_event('uc_cart_checkout_start', $order);
  157. return drupal_get_form('uc_cart_checkout_form', $order);
  158. }
  159. /**
  160. * The checkout form built up from the enabled checkout panes.
  161. *
  162. * @param $order
  163. * The order that is being checked out.
  164. *
  165. * @see uc_cart_checkout_form_process()
  166. * @see uc_cart_checkout_form_validate()
  167. * @see uc_cart_checkout_form_submit()
  168. * @see uc_cart_checkout_review()
  169. * @see theme_uc_cart_checkout_form()
  170. * @ingroup forms
  171. */
  172. function uc_cart_checkout_form($form, &$form_state, $order) {
  173. if ($processed = isset($form_state['storage']['order'])) {
  174. $order = $form_state['storage']['order'];
  175. }
  176. else {
  177. $form_state['storage']['order'] = $order;
  178. $form_state['storage']['base_path'] = implode('/', array_slice(arg(), 0, -1));
  179. }
  180. $form['#attributes']['class'][] = 'uc-cart-checkout-form';
  181. $form['#attached']['js'][] = drupal_get_path('module', 'uc_cart') . '/uc_cart.js';
  182. $form['#attached']['css'][] = drupal_get_path('module', 'uc_cart') . '/uc_cart.css';
  183. if ($instructions = variable_get('uc_checkout_instructions', '')) {
  184. $form['instructions'] = array(
  185. '#prefix' => '<div id="checkout-instructions">',
  186. '#markup' => filter_xss_admin($instructions),
  187. '#suffix' => '</div>',
  188. );
  189. }
  190. $form['panes'] = array('#tree' => TRUE);
  191. $panes = _uc_checkout_pane_list();
  192. // If the order isn't shippable, remove panes with shippable == TRUE.
  193. if (!uc_order_is_shippable($order) && variable_get('uc_cart_delivery_not_shippable', TRUE)) {
  194. $panes = uc_cart_filter_checkout_panes($panes, array('shippable' => TRUE));
  195. }
  196. // Invoke the 'prepare' op of enabled panes, but only if their 'process' ops
  197. // have not been invoked on this request (i.e. when rebuilding after AJAX).
  198. foreach ($panes as $id => $pane) {
  199. if ($pane['enabled'] && empty($form_state['storage']['panes'][$id]['prepared']) && isset($pane['callback']) && function_exists($pane['callback'])) {
  200. $pane['callback']('prepare', $order, $form, $form_state);
  201. $form_state['storage']['panes'][$id]['prepared'] = TRUE;
  202. $processed = FALSE; // Make sure we save the updated order.
  203. }
  204. }
  205. // Load the line items and save the order. We do this after the 'prepare'
  206. // callbacks of enabled panes have been invoked, because these may have
  207. // altered the order.
  208. if (!$processed) {
  209. $order->line_items = uc_order_load_line_items($order);
  210. uc_order_save($order);
  211. }
  212. foreach ($panes as $id => $pane) {
  213. if ($pane['enabled']) {
  214. $pane['prev'] = _uc_cart_checkout_prev_pane($panes, $id);
  215. $pane['next'] = _uc_cart_checkout_next_pane($panes, $id);
  216. if (!isset($pane['collapsed'])) {
  217. $collapsed = ($pane['prev'] === FALSE || empty($displayed[$pane['prev']])) ? FALSE : TRUE;
  218. }
  219. if (isset($form_state['expanded_panes']) && in_array($id, $form_state['expanded_panes'])) {
  220. $collapsed = FALSE;
  221. }
  222. $return = $pane['callback']('view', $order, $form, $form_state);
  223. // Add the pane if any display data is returned from the callback.
  224. if (is_array($return) && (!empty($return['description']) || !empty($return['contents']))) {
  225. // Create the fieldset for the pane.
  226. $form['panes'][$id] = array(
  227. '#type' => 'fieldset',
  228. '#title' => check_plain($pane['title']),
  229. '#description' => !empty($return['description']) ? $return['description'] : '',
  230. '#collapsible' => $pane['collapsible'] && variable_get('uc_use_next_buttons', FALSE),
  231. '#collapsed' => variable_get('uc_use_next_buttons', FALSE) ? $collapsed : FALSE,
  232. '#id' => $id . '-pane',
  233. '#theme' => isset($return['theme']) ? $return['theme'] : NULL,
  234. );
  235. // Add the contents of the fieldset if any were returned.
  236. if (!empty($return['contents'])) {
  237. $form['panes'][$id] = array_merge($form['panes'][$id], $return['contents']);
  238. }
  239. // Add the 'Next' button if necessary.
  240. if ((!isset($return['next-button']) || $return['next-button'] !== FALSE) && $pane['next'] !== FALSE &&
  241. variable_get('uc_use_next_buttons', FALSE) != FALSE) {
  242. $opt = variable_get('uc_collapse_current_pane', FALSE) ? $id : 'false';
  243. $form['panes'][$id]['next'] = array(
  244. '#type' => 'button',
  245. '#value' => t('Next'),
  246. '#weight' => 20,
  247. '#attributes' => array('onclick' => "return uc_cart_next_button_click(this, '" . $pane['next'] . "', '" . $opt . "');"),
  248. '#prefix' => '<div class="next-button">',
  249. '#suffix' => '</div>',
  250. );
  251. }
  252. // Log that this pane was actually displayed.
  253. $displayed[$id] = TRUE;
  254. }
  255. }
  256. }
  257. unset($form_state['expanded_panes']);
  258. $form['actions'] = array('#type' => 'actions');
  259. $form['actions']['cancel'] = array(
  260. '#type' => 'submit',
  261. '#value' => t('Cancel'),
  262. '#validate' => array(), // Disable validation to prevent a new order
  263. // from being created.
  264. '#limit_validation_errors' => array(),
  265. '#submit' => array('uc_cart_checkout_form_cancel'),
  266. );
  267. $form['actions']['continue'] = array(
  268. '#type' => 'submit',
  269. '#value' => t('Review order'),
  270. );
  271. form_load_include($form_state, 'inc', 'uc_store', 'includes/uc_ajax_attach');
  272. $form['#process'][] = 'uc_ajax_process_form';
  273. unset($_SESSION['uc_checkout'][$order->order_id]);
  274. return $form;
  275. }
  276. /**
  277. * Default theme function for the checkout form.
  278. *
  279. * @param $variables
  280. * An associative array containing:
  281. * - form: A render element representing the form.
  282. *
  283. * @see uc_cart_checkout_form()
  284. * @ingroup themeable
  285. */
  286. function theme_uc_cart_checkout_form($variables) {
  287. return drupal_render_children($variables['form']);
  288. }
  289. /**
  290. * Form validation for uc_cart_checkout_form().
  291. *
  292. * @see uc_cart_checkout_form()
  293. * @see uc_cart_checkout_form_submit()
  294. */
  295. function uc_cart_checkout_form_validate($form, &$form_state) {
  296. $order = $form_state['storage']['order'];
  297. // Update the order "modified" time to prevent timeout on ajax requests.
  298. $order->modified = REQUEST_TIME;
  299. // Validate/process the cart panes. A FALSE value results in failed checkout.
  300. $form_state['checkout_valid'] = TRUE;
  301. foreach (element_children($form_state['values']['panes']) as $pane_id) {
  302. $func = _uc_checkout_pane_data($pane_id, 'callback');
  303. if (is_string($func) && function_exists($func)) {
  304. $isvalid = $func('process', $order, $form, $form_state);
  305. if ($isvalid === FALSE) {
  306. $form_state['expanded_panes'][] = $pane_id;
  307. $form_state['checkout_valid'] = FALSE;
  308. }
  309. }
  310. }
  311. // Reload line items and save order.
  312. $order->line_items = uc_order_load_line_items($order);
  313. uc_order_save($order);
  314. }
  315. /**
  316. * Form submission handler for uc_cart_checkout_form().
  317. *
  318. * @see uc_cart_checkout_form()
  319. * @see uc_cart_checkout_form_validate()
  320. */
  321. function uc_cart_checkout_form_submit($form, &$form_state) {
  322. if ($form_state['checkout_valid'] === FALSE) {
  323. $url = $form_state['storage']['base_path'] . '/checkout';
  324. }
  325. else {
  326. $url = $form_state['storage']['base_path'] . '/checkout/review';
  327. $_SESSION['uc_checkout'][$form_state['storage']['order']->order_id]['do_review'] = TRUE;
  328. }
  329. unset($form_state['checkout_valid']);
  330. $form_state['redirect'] = $url;
  331. }
  332. /**
  333. * Submit handler for "Cancel" button on uc_cart_checkout_form().
  334. *
  335. * @see uc_cart_checkout_form()
  336. */
  337. function uc_cart_checkout_form_cancel($form, &$form_state) {
  338. $order = $form_state['storage']['order'];
  339. if (isset($_SESSION['cart_order']) && $_SESSION['cart_order'] == $order->order_id) {
  340. uc_order_comment_save($_SESSION['cart_order'], 0, t('Customer canceled this order from the checkout form.'));
  341. unset($_SESSION['cart_order']);
  342. }
  343. unset($_SESSION['uc_checkout'][$order->order_id]);
  344. $form_state['redirect'] = $form_state['storage']['base_path'];
  345. }
  346. /**
  347. * Allows a customer to review their order before finally submitting it.
  348. *
  349. * @see uc_cart_checkout_form()
  350. */
  351. function uc_cart_checkout_review() {
  352. drupal_add_js(drupal_get_path('module', 'uc_cart') . '/uc_cart.js');
  353. if (empty($_SESSION['cart_order']) || empty($_SESSION['uc_checkout'][$_SESSION['cart_order']]['do_review'])) {
  354. drupal_goto('cart/checkout');
  355. }
  356. $order = uc_order_load($_SESSION['cart_order']);
  357. if ($order === FALSE || uc_order_status_data($order->order_status, 'state') != 'in_checkout') {
  358. unset($_SESSION['uc_checkout'][$order->order_id]['do_review']);
  359. drupal_goto('cart/checkout');
  360. }
  361. elseif (!uc_order_product_revive($order->products)) {
  362. drupal_set_message(t('Some of the products in this order are no longer available.'), 'error');
  363. drupal_goto('cart');
  364. }
  365. $panes = _uc_checkout_pane_list();
  366. // If the cart isn't shippable, bypass panes with shippable == TRUE.
  367. if (!uc_order_is_shippable($order) && variable_get('uc_cart_delivery_not_shippable', TRUE)) {
  368. $panes = uc_cart_filter_checkout_panes($panes, array('shippable' => TRUE));
  369. }
  370. foreach ($panes as $pane) {
  371. if ($pane['enabled']) {
  372. $func = $pane['callback'];
  373. if (function_exists($func)) {
  374. $return = $func('review', $order, NULL);
  375. if (!is_null($return)) {
  376. $data[$pane['title']] = $return;
  377. }
  378. }
  379. }
  380. }
  381. $build = array(
  382. '#theme' => 'uc_cart_checkout_review',
  383. '#panes' => $data,
  384. '#form' => drupal_get_form('uc_cart_checkout_review_form', $order),
  385. );
  386. return $build;
  387. }
  388. /**
  389. * Themes the checkout review order page.
  390. *
  391. * @param $variables
  392. * An associative array containing:
  393. * - form: A render element representing the form, that by default includes
  394. * the 'Back' and 'Submit order' buttons at the bottom of the review page.
  395. * - panes: An associative array for each checkout pane that has information
  396. * to add to the review page, keyed by the pane title:
  397. * - <pane title>: The data returned for that pane or an array of returned
  398. * data.
  399. *
  400. * @return
  401. * A string of HTML for the page contents.
  402. *
  403. * @ingroup themeable
  404. */
  405. function theme_uc_cart_checkout_review($variables) {
  406. $panes = $variables['panes'];
  407. $form = $variables['form'];
  408. drupal_add_css(drupal_get_path('module', 'uc_cart') . '/uc_cart.css');
  409. $output = '<div id="review-instructions">' . filter_xss_admin(variable_get('uc_checkout_review_instructions', uc_get_message('review_instructions'))) . '</div>';
  410. $output .= '<table class="order-review-table">';
  411. foreach ($panes as $title => $data) {
  412. $output .= '<tr class="pane-title-row">';
  413. $output .= '<td colspan="2">' . $title . '</td>';
  414. $output .= '</tr>';
  415. if (is_array($data)) {
  416. foreach ($data as $row) {
  417. if (is_array($row)) {
  418. if (isset($row['border'])) {
  419. $border = ' class="row-border-' . $row['border'] . '"';
  420. }
  421. else {
  422. $border = '';
  423. }
  424. $output .= '<tr' . $border . '>';
  425. $output .= '<td class="title-col">' . $row['title'] . ':</td>';
  426. $output .= '<td class="data-col">' . $row['data'] . '</td>';
  427. $output .= '</tr>';
  428. }
  429. else {
  430. $output .= '<tr><td colspan="2">' . $row . '</td></tr>';
  431. }
  432. }
  433. }
  434. else {
  435. $output .= '<tr><td colspan="2">' . $data . '</td></tr>';
  436. }
  437. }
  438. $output .= '<tr class="review-button-row">';
  439. $output .= '<td colspan="2">' . drupal_render($form) . '</td>';
  440. $output .= '</tr>';
  441. $output .= '</table>';
  442. return $output;
  443. }
  444. /**
  445. * Gives customers the option to finish checkout or go revise their information.
  446. *
  447. * @see uc_cart_checkout_review_form_back()
  448. * @see uc_cart_checkout_review_form_submit()
  449. * @ingroup forms
  450. */
  451. function uc_cart_checkout_review_form($form, &$form_state, $order) {
  452. if (!isset($form_state['uc_order'])) {
  453. $form_state['uc_order'] = $order;
  454. $form_state['storage']['base_path'] = implode('/', array_slice(arg(), 0, -2));
  455. }
  456. $form['actions'] = array('#type' => 'actions');
  457. $form['actions']['back'] = array(
  458. '#type' => 'submit',
  459. '#value' => t('Back'),
  460. '#submit' => array('uc_cart_checkout_review_form_back'),
  461. );
  462. $form['actions']['submit'] = array(
  463. '#type' => 'submit',
  464. '#value' => t('Submit order'),
  465. );
  466. return $form;
  467. }
  468. /**
  469. * Returns the customer to the checkout page to edit their information.
  470. *
  471. * @see uc_cart_checkout_review_form()
  472. */
  473. function uc_cart_checkout_review_form_back($form, &$form_state) {
  474. $form_state['redirect'] = $form_state['storage']['base_path'] . '/checkout';
  475. }
  476. /**
  477. * Final checks to make sure the order can be completed.
  478. *
  479. * @see uc_cart_checkout_review_form()
  480. */
  481. function uc_cart_checkout_review_form_submit($form, &$form_state) {
  482. // Invoke hook_uc_order($op = 'submit') to test to make sure the order can
  483. // be completed... used for auto payment in uc_credit.module.
  484. $order = $form_state['uc_order'];
  485. $error = FALSE;
  486. // Invoke it on a per-module basis instead of all at once.
  487. foreach (module_implements('uc_order') as $module) {
  488. $function = $module . '_uc_order';
  489. if (function_exists($function)) {
  490. // $order must be passed by reference.
  491. $result = $function('submit', $order, NULL);
  492. $msg_type = 'status';
  493. if ($result[0]['pass'] === FALSE) {
  494. $error = TRUE;
  495. $msg_type = 'error';
  496. }
  497. if (!empty($result[0]['message'])) {
  498. drupal_set_message($result[0]['message'], $msg_type);
  499. }
  500. // Stop invoking the hooks if there was an error.
  501. if ($error) {
  502. break;
  503. }
  504. }
  505. }
  506. if ($error) {
  507. $form_state['redirect'] = $form_state['storage']['base_path'] . '/checkout/review';
  508. }
  509. else {
  510. unset($_SESSION['uc_checkout'][$order->order_id]['do_review']);
  511. $_SESSION['uc_checkout'][$order->order_id]['do_complete'] = TRUE;
  512. $form_state['redirect'] = $form_state['storage']['base_path'] . '/checkout/complete';
  513. }
  514. }
  515. /**
  516. * Completes the sale and finishes checkout.
  517. */
  518. function uc_cart_checkout_complete() {
  519. if (empty($_SESSION['cart_order']) || empty($_SESSION['uc_checkout'][$_SESSION['cart_order']]['do_complete'])) {
  520. drupal_goto('cart');
  521. }
  522. $order = uc_order_load(intval($_SESSION['cart_order']));
  523. if (empty($order)) {
  524. // Display messages to customers and the administrator if the order was lost.
  525. drupal_set_message(t("We're sorry. An error occurred while processing your order that prevents us from completing it at this time. Please contact us and we will resolve the issue as soon as possible."), 'error');
  526. watchdog('uc_cart', 'An empty order made it to checkout! Cart order ID: @cart_order', array('@cart_order' => $_SESSION['cart_order']), WATCHDOG_ERROR);
  527. drupal_goto('cart');
  528. }
  529. $build = uc_cart_complete_sale($order, variable_get('uc_new_customer_login', FALSE));
  530. unset($_SESSION['uc_checkout'][$order->order_id], $_SESSION['cart_order']);
  531. // Add a comment to let sales team know this came in through the site.
  532. uc_order_comment_save($order->order_id, 0, t('Order created through website.'), 'admin');
  533. $page = variable_get('uc_cart_checkout_complete_page', '');
  534. if (!empty($page)) {
  535. drupal_goto($page);
  536. }
  537. return $build;
  538. }