PageRenderTime 32ms CodeModel.GetById 21ms RepoModel.GetById 0ms app.codeStats 0ms

/profiles/commerce_kickstart/modules/commerce/modules/payment/includes/commerce_payment.checkout_pane.inc

http://webstart.codeplex.com
Pascal | 315 lines | 105 code | 26 blank | 184 comment | 25 complexity | 049ae5bada95d63d33e5907df3cb1ca0 MD5 | raw file
Possible License(s): GPL-2.0, AGPL-1.0
  1. <?php
  2. /**
  3. * @file
  4. * Callback functions for the Payment module's checkout panes.
  5. */
  6. /**
  7. * Checkout pane callback: returns the payment pane's settings form.
  8. */
  9. function commerce_payment_pane_settings_form($checkout_pane) {
  10. $form = array();
  11. $form['commerce_payment_pane_require_method'] = array(
  12. '#type' => 'checkbox',
  13. '#title' => t('Require a payment method at all times, preventing checkout if none is available.'),
  14. '#default_value' => variable_get('commerce_payment_pane_require_method', FALSE),
  15. );
  16. return $form;
  17. }
  18. /**
  19. * Payment pane: form callback.
  20. */
  21. function commerce_payment_pane_checkout_form($form, &$form_state, $checkout_pane, $order) {
  22. $pane_form = array();
  23. // Invoke the payment methods event that will populate the order with
  24. // an array of method IDs for available payment methods.
  25. $order->payment_methods = array();
  26. rules_invoke_all('commerce_payment_methods', $order);
  27. // Sort the payment methods array by the enabling Rules' weight values.
  28. uasort($order->payment_methods, 'drupal_sort_weight');
  29. // Generate an array of payment method options for the checkout form.
  30. $options = array();
  31. foreach ($order->payment_methods as $instance_id => $method_info) {
  32. // Ensure we've received a valid payment method.
  33. if ($payment_method = commerce_payment_method_load($method_info['method_id'])) {
  34. $options[$instance_id] = $payment_method['display_title'];
  35. }
  36. }
  37. // If no payment methods were found, return the empty form.
  38. if (empty($options)) {
  39. if (!variable_get('commerce_payment_pane_require_method', FALSE)) {
  40. return $pane_form;
  41. }
  42. else {
  43. $pane_form['message'] = array(
  44. '#markup' => '<div>' . t('Unfortunately we could not find any suitable payment methods, and we require a payment method to complete checkout.') . '<br /><strong>' . t('Please contact us to resolve any issues with your order.') . '</strong></div>',
  45. );
  46. }
  47. }
  48. // Store the payment methods in the form for validation purposes.
  49. $pane_form['payment_methods'] = array(
  50. '#type' => 'value',
  51. '#value' => $order->payment_methods,
  52. );
  53. // If at least one payment option is available...
  54. if (!empty($options)) {
  55. // Add a radio select widget to specify the payment method.
  56. $pane_form['payment_method'] = array(
  57. '#type' => 'radios',
  58. '#options' => $options,
  59. '#ajax' => array(
  60. 'callback' => 'commerce_payment_pane_checkout_form_details_refresh',
  61. 'wrapper' => 'payment-details',
  62. ),
  63. );
  64. // Find the default payment method using either the preselected value stored
  65. // in the order / checkout pane or the first available method.
  66. $pane_values = !empty($form_state['values']) ? $form_state['values'][$checkout_pane['pane_id']] : array();
  67. if (isset($pane_values['payment_method']) && isset($options[$pane_values['payment_method']])) {
  68. $default_value = $pane_values['payment_method'];
  69. }
  70. elseif (isset($order->data['payment_method']) && isset($options[$order->data['payment_method']])) {
  71. $default_value = $order->data['payment_method'];
  72. }
  73. else {
  74. reset($options);
  75. $default_value = key($options);
  76. }
  77. // Set the default value for the payment method radios.
  78. $pane_form['payment_method']['#default_value'] = $default_value;
  79. // Add the payment method specific form elements.
  80. $method_info = $order->payment_methods[$pane_form['payment_method']['#default_value']];
  81. $payment_method = commerce_payment_method_load($method_info['method_id']);
  82. $payment_method['settings'] = $method_info['settings'];
  83. if ($callback = commerce_payment_method_callback($payment_method, 'submit_form')) {
  84. $pane_form['payment_details'] = $callback($payment_method, $pane_values, $checkout_pane, $order);
  85. }
  86. else {
  87. $pane_form['payment_details'] = array();
  88. }
  89. $pane_form['payment_details']['#prefix'] = '<div id="payment-details">';
  90. $pane_form['payment_details']['#suffix'] = '</div>';
  91. }
  92. return $pane_form;
  93. }
  94. /**
  95. * Returns the payment details element for display via AJAX.
  96. */
  97. function commerce_payment_pane_checkout_form_details_refresh($form, $form_state) {
  98. return $form['commerce_payment']['payment_details'];
  99. }
  100. /**
  101. * Payment pane: validation callback.
  102. */
  103. function commerce_payment_pane_checkout_form_validate($form, &$form_state, $checkout_pane, $order) {
  104. $pane_id = $checkout_pane['pane_id'];
  105. // Only attempt validation if we actually had payment methods on the form.
  106. if (!empty($form[$pane_id]) && !empty($form_state['values'][$pane_id])) {
  107. $pane_form = $form[$pane_id];
  108. $pane_values = $form_state['values'][$pane_id];
  109. // Only attempt validation if there were payment methods available.
  110. if (!empty($pane_values['payment_methods'])) {
  111. // If the selected payment method was changed...
  112. if ($pane_values['payment_method'] != $pane_form['payment_method']['#default_value']) {
  113. // And the newly selected method has a valid form callback...
  114. if ($payment_method = commerce_payment_method_instance_load($pane_values['payment_method'])) {
  115. if (commerce_payment_method_callback($payment_method, 'submit_form')) {
  116. // Fail validation so the form is rebuilt to include the payment method
  117. // specific form elements.
  118. return FALSE;
  119. }
  120. }
  121. }
  122. // Delegate validation to the payment method callback.
  123. $payment_method = commerce_payment_method_instance_load($pane_values['payment_method']);
  124. if ($callback = commerce_payment_method_callback($payment_method, 'submit_form_validate')) {
  125. $result = $callback($payment_method, $pane_form['payment_details'], $pane_values['payment_details'], $order, array($checkout_pane['pane_id'], 'payment_details'));
  126. // To prevent payment method validation routines from having to return TRUE
  127. // explicitly, only return FALSE if it was specifically returned. Otherwise
  128. // default to TRUE.
  129. return $result === FALSE ? FALSE : TRUE;
  130. }
  131. }
  132. elseif (variable_get('commerce_payment_pane_require_method', FALSE)) {
  133. drupal_set_message(t('You cannot complete checkout without submitting payment. Please contact us if an error continues to prevent you from seeing valid payment methods for your order.'), 'error');
  134. return FALSE;
  135. }
  136. }
  137. // Nothing to validate.
  138. return TRUE;
  139. }
  140. /**
  141. * Payment pane: submit callback.
  142. */
  143. function commerce_payment_pane_checkout_form_submit($form, &$form_state, $checkout_pane, $order) {
  144. $pane_id = $checkout_pane['pane_id'];
  145. // Only submit if we actually had payment methods on the form.
  146. if (!empty($form[$pane_id]) && !empty($form_state['values'][$pane_id])) {
  147. $pane_form = $form[$pane_id];
  148. $pane_values = $form_state['values'][$pane_id];
  149. // Only process if there were payment methods available.
  150. if ($pane_values['payment_methods']) {
  151. $order->data['payment_method'] = $pane_values['payment_method'];
  152. // If we can calculate a single order total for the order...
  153. if ($balance = commerce_payment_order_balance($order)) {
  154. // Delegate submit to the payment method callback.
  155. $payment_method = commerce_payment_method_instance_load($pane_values['payment_method']);
  156. if ($callback = commerce_payment_method_callback($payment_method, 'submit_form_submit')) {
  157. // If payment fails, rebuild the checkout form without progressing.
  158. if ($callback($payment_method, $pane_form['payment_details'], $pane_values['payment_details'], $order, $balance) === FALSE) {
  159. $form_state['rebuild'] = TRUE;
  160. }
  161. }
  162. }
  163. }
  164. }
  165. }
  166. /**
  167. * Payment redirect pane: form callback.
  168. */
  169. function commerce_payment_redirect_pane_checkout_form(&$form, &$form_state, $checkout_pane, $order) {
  170. // First load the order's specified payment method instance.
  171. if (!empty($order->data['payment_method'])) {
  172. $payment_method = commerce_payment_method_instance_load($order->data['payment_method']);
  173. }
  174. else {
  175. $payment_method = FALSE;
  176. }
  177. // If the payment method doesn't exist or does not require a redirect...
  178. if (!$payment_method || !$payment_method['offsite']) {
  179. // Advance the customer to the next step of the checkout process.
  180. commerce_payment_redirect_pane_next_page($order);
  181. drupal_goto(commerce_checkout_order_uri($order));
  182. }
  183. // If the user came to the cancel URL...
  184. if (arg(3) == 'back' && arg(4) == $order->data['payment_redirect_key']) {
  185. // Send the customer to the previous step of the checkout process.
  186. commerce_payment_redirect_pane_previous_page($order);
  187. drupal_goto(commerce_checkout_order_uri($order));
  188. }
  189. // If the user came to the return URL...
  190. if (arg(3) == 'return' && arg(4) == $order->data['payment_redirect_key']) {
  191. // Check for a validate handler on return.
  192. $validate_callback = commerce_payment_method_callback($payment_method, 'redirect_form_validate');
  193. // If there is no validate handler or if there is and it isn't FALSE...
  194. if (!$validate_callback || $validate_callback($order, $payment_method) !== FALSE) {
  195. // Perform any submit functions if necessary.
  196. if ($callback = commerce_payment_method_callback($payment_method, 'redirect_form_submit')) {
  197. $callback($order, $payment_method);
  198. }
  199. // Send the customer on to the next checkout page.
  200. commerce_payment_redirect_pane_next_page($order);
  201. drupal_goto(commerce_checkout_order_uri($order));
  202. }
  203. else {
  204. // Otherwise display the failure message and send the customer back.
  205. drupal_set_message(t('Payment failed at the payment server. Please review your information and try again.'), 'error');
  206. commerce_payment_redirect_pane_previous_page($order);
  207. drupal_goto(commerce_checkout_order_uri($order));
  208. }
  209. }
  210. // If the function to build the redirect form exists...
  211. if ($callback = commerce_payment_method_callback($payment_method, 'redirect_form')) {
  212. // Generate a key to use in the return URL from the redirected service.
  213. $order->data['payment_redirect_key'] = drupal_hash_base64(time());
  214. commerce_order_save($order);
  215. // If the payment method has the 'offsite_autoredirect' option enabled, add
  216. // the redirection behavior.
  217. if (!empty($payment_method['offsite_autoredirect'])) {
  218. $form['#attached']['js'][] = drupal_get_path('module', 'commerce_payment') . '/commerce_payment.js';
  219. $form['help']['#markup'] = '<div class="checkout-help">' . t('Please wait while you are redirected to the payment server. If nothing happens within 10 seconds, please click on the button below.') . '</div>';
  220. }
  221. // Merge the new form into the current form array, preserving the help text
  222. // if it exists. We also add a wrapper so the form can be easily submitted.
  223. $form += drupal_get_form($callback, $order, $payment_method);
  224. $form['#prefix'] = '<div class="payment-redirect-form">';
  225. $form['#suffix'] = '</div>';
  226. }
  227. else {
  228. // Alert the administrator that the module does not provide a required form.
  229. drupal_set_message(t('The %title payment method indicates it is offsite but does not define the necessary form to process the redirect.', array('%title' => $payment_method['title'])), 'error');
  230. }
  231. }
  232. /**
  233. * Utility function: return a payment redirect page for POST.
  234. *
  235. * @param $action
  236. * The destination URL the values should be posted to.
  237. * @param $values
  238. * An associative array of values that will be posted to the destination URL.
  239. * @return
  240. * A renderable array.
  241. */
  242. function commerce_payment_post_redirect_form($action, array $values = array()) {
  243. $form = array(
  244. '#type' => 'form',
  245. '#action' => $action,
  246. '#method' => 'POST',
  247. '#id' => '',
  248. '#attributes' => array(),
  249. );
  250. foreach ($values as $key => $value) {
  251. $form[$value] = array(
  252. '#type' => 'hidden',
  253. '#name' => $key,
  254. '#value' => $value,
  255. '#id' => '',
  256. '#attributes' => array(),
  257. );
  258. }
  259. $form['submit'] = array(
  260. '#type' => 'submit',
  261. '#id' => '',
  262. '#value' => t('Proceed to payment'),
  263. );
  264. return array(
  265. 'form' => array(
  266. '#type' => 'markup',
  267. '#markup' => drupal_render($form),
  268. ),
  269. );
  270. }