1
|
<?php
|
2
|
|
3
|
/**
|
4
|
* @file
|
5
|
* Administrative callbacks for the Checkout module.
|
6
|
*/
|
7
|
|
8
|
|
9
|
/**
|
10
|
* Build the checkout form builder, adding in data for the checkout pages and
|
11
|
* the appropriate fields to enable tabledrag on the checkout panes.
|
12
|
*/
|
13
|
function commerce_checkout_builder_form($form, &$form_state) {
|
14
|
// Load an array of all available checkout pages.
|
15
|
$checkout_pages = commerce_checkout_pages();
|
16
|
|
17
|
// Add a "disabled" pseudo-page.
|
18
|
$checkout_pages['disabled'] = array('page_id' => 'disabled', 'title' => t('Disabled'));
|
19
|
|
20
|
$form['checkout_pages'] = array(
|
21
|
'#type' => 'value',
|
22
|
'#value' => $checkout_pages,
|
23
|
);
|
24
|
|
25
|
$checkout_pages_options = array();
|
26
|
|
27
|
// Create arrays for checkout panes in each of the pages.
|
28
|
foreach (array_keys($checkout_pages) as $page_id) {
|
29
|
$form['page'][$page_id]['panes'] = array('#tree' => TRUE);
|
30
|
|
31
|
// Build the options list for selecting the pane's checkout page.
|
32
|
$checkout_pages_options[$page_id] = $checkout_pages[$page_id]['title'];
|
33
|
}
|
34
|
|
35
|
// Loop through all the checkout panes on the site.
|
36
|
$panes = commerce_checkout_panes();
|
37
|
|
38
|
foreach ($panes as $pane_id => $checkout_pane) {
|
39
|
// Determine a checkout pane's current checkout page.
|
40
|
$page_id = $checkout_pane['enabled'] ? $checkout_pane['page'] : 'disabled';
|
41
|
|
42
|
// If the page no longer exists, place the pane on the first page.
|
43
|
if (empty($checkout_pages[$page_id])) {
|
44
|
reset($checkout_pages);
|
45
|
$page_id = key($checkout_pages);
|
46
|
}
|
47
|
|
48
|
// Add the pane's name to the form array.
|
49
|
$form['page'][$page_id]['panes'][$pane_id]['name'] = array(
|
50
|
'#markup' => check_plain($checkout_pane['name']),
|
51
|
);
|
52
|
|
53
|
// Add the select field for the pane's checkout page.
|
54
|
$form['page'][$page_id]['panes'][$pane_id]['page'] = array(
|
55
|
'#type' => 'select',
|
56
|
'#options' => $checkout_pages_options,
|
57
|
'#default_value' => $checkout_pane['page'],
|
58
|
'#attributes' => array('class' => array('checkout-pane-page checkout-pane-page-'. $checkout_pane['page'])),
|
59
|
);
|
60
|
|
61
|
// Add the select field for the pane's weight.
|
62
|
$form['page'][$page_id]['panes'][$pane_id]['weight'] = array(
|
63
|
'#type' => 'weight',
|
64
|
'#delta' => 20,
|
65
|
'#default_value' => $checkout_pane['weight'],
|
66
|
'#attributes' => array('class' => array('checkout-pane-weight checkout-pane-weight-'. $checkout_pane['page'])),
|
67
|
);
|
68
|
|
69
|
// Add a configuration link for the pane.
|
70
|
$form['page'][$page_id]['panes'][$pane_id]['ops'] = array(
|
71
|
'#markup' => l(t('configure'), 'admin/commerce/config/checkout/form/pane/'. $pane_id),
|
72
|
);
|
73
|
}
|
74
|
|
75
|
$form['actions'] = array(
|
76
|
'#type' => 'actions',
|
77
|
'#tree' => FALSE,
|
78
|
);
|
79
|
$form['actions']['submit'] = array(
|
80
|
'#type' => 'submit',
|
81
|
'#value' => t('Save configuration'),
|
82
|
'#submit' => array('commerce_checkout_builder_form_save_submit'),
|
83
|
);
|
84
|
$form['actions']['reset'] = array(
|
85
|
'#type' => 'submit',
|
86
|
'#value' => t('Reset to defaults'),
|
87
|
'#submit' => array('commerce_checkout_builder_form_reset_submit'),
|
88
|
);
|
89
|
|
90
|
return $form;
|
91
|
}
|
92
|
|
93
|
/**
|
94
|
* Validation handler for the checkout builder form.
|
95
|
*/
|
96
|
function commerce_checkout_builder_form_validate(&$form, &$form_state) {
|
97
|
$pages = commerce_checkout_pages();
|
98
|
|
99
|
// Get unmodified checkout panes.
|
100
|
$panes = commerce_checkout_panes(array(), TRUE);
|
101
|
|
102
|
// Get saved checkout panes. If an error is detected, we'll need it to
|
103
|
// reference the original form structure so we can accurately locate the
|
104
|
// elements in the form and set their values.
|
105
|
$saved_panes = commerce_checkout_panes();
|
106
|
|
107
|
// Loop through each configured panes.
|
108
|
foreach ($form_state['values']['panes'] as $pane_id => $checkout_pane) {
|
109
|
// Check if pane should be locked but is configured on the wrong checkout page.
|
110
|
if (!empty($panes[$pane_id]['locked']) && $checkout_pane['page'] != $panes[$pane_id]['page']) {
|
111
|
$element = &$form['page'][$saved_panes[$pane_id]['page']]['panes'][$pane_id]['page'];
|
112
|
|
113
|
if ($panes[$pane_id]['page'] == 'disabled') {
|
114
|
drupal_set_message(t('%pane must be configured before it can be enabled. It has been moved back to a disabled position.', array('%pane' => $panes[$pane_id]['title'])), 'warning');
|
115
|
}
|
116
|
else {
|
117
|
drupal_set_message(t('%pane is locked in the code to the %page page and was repositioned accordingly.', array('%pane' => $panes[$pane_id]['title'], '%page' => $pages[$panes[$pane_id]['page']]['title'])), 'warning');
|
118
|
}
|
119
|
|
120
|
form_set_value($element, $panes[$pane_id]['page'], $form_state);
|
121
|
}
|
122
|
}
|
123
|
}
|
124
|
|
125
|
/**
|
126
|
* Submit handler for the checkout builder form's save button.
|
127
|
*/
|
128
|
function commerce_checkout_builder_form_save_submit($form, &$form_state) {
|
129
|
// Loop through each of the checkout panes.
|
130
|
if (!empty($form_state['values']['panes'])) {
|
131
|
foreach ($form_state['values']['panes'] as $pane_id => $data) {
|
132
|
// Load and update the checkout pane array.
|
133
|
$checkout_pane = commerce_checkout_pane_load($pane_id);
|
134
|
$checkout_pane['weight'] = $data['weight'];
|
135
|
|
136
|
// Accommodate the "Disabled" pseudo-page in the form.
|
137
|
if ($data['page'] == 'disabled') {
|
138
|
$checkout_pane['enabled'] = FALSE;
|
139
|
$checkout_pane['page'] = 'disabled';
|
140
|
}
|
141
|
else {
|
142
|
$checkout_pane['enabled'] = TRUE;
|
143
|
$checkout_pane['page'] = $data['page'];
|
144
|
}
|
145
|
|
146
|
commerce_checkout_pane_save($checkout_pane);
|
147
|
}
|
148
|
}
|
149
|
|
150
|
drupal_set_message(t('Checkout pane positions saved.'));
|
151
|
}
|
152
|
|
153
|
/**
|
154
|
* Submit handler for the checkout builder form's reset button.
|
155
|
*/
|
156
|
function commerce_checkout_builder_form_reset_submit($form, &$form_state) {
|
157
|
// Empty the checkout pane table of configuration data.
|
158
|
db_truncate('commerce_checkout_pane')->execute();
|
159
|
drupal_set_message(t('Checkout pane positions reset.'));
|
160
|
}
|
161
|
|
162
|
/**
|
163
|
* Theme the checkout pages form to enable tabledrag.
|
164
|
*/
|
165
|
function theme_commerce_checkout_builder_form($variables) {
|
166
|
$form = $variables['form'];
|
167
|
|
168
|
drupal_add_css(drupal_get_path('module', 'commerce_checkout') .'/theme/commerce_checkout.admin.css');
|
169
|
drupal_add_js(drupal_get_path('module', 'commerce_checkout') .'/commerce_checkout_admin.js');
|
170
|
|
171
|
// Build the full table header; Page and Weight will be hidden by tabledrag.
|
172
|
$header = array(t('Checkout pane'), t('Page'), t('Weight'), t('Operations'));
|
173
|
|
174
|
$rows = array();
|
175
|
|
176
|
// Loop through each page array in the form.
|
177
|
foreach ($form['checkout_pages']['#value'] as $page_id => $checkout_page) {
|
178
|
// Initialize the tabledrag for this page.
|
179
|
drupal_add_tabledrag('panes', 'match', 'sibling', 'checkout-pane-page', 'checkout-pane-page-'. $page_id);
|
180
|
drupal_add_tabledrag('panes', 'order', 'sibling', 'checkout-pane-weight', 'checkout-pane-weight-'. $page_id);
|
181
|
|
182
|
// Add a non-draggable header row for each checkout page.
|
183
|
$row = array(
|
184
|
array('data' => $checkout_page['title'], 'colspan' => 4),
|
185
|
);
|
186
|
|
187
|
$rows[] = array('data' => $row, 'class' => array('page-header'));
|
188
|
|
189
|
// Determine whether the page currently has any panes in it.
|
190
|
$class = count(element_children($form['page'][$page_id]['panes'])) == 0 ? 'page-empty' : 'page-populated';
|
191
|
|
192
|
// Add a row to the table that will be automatically shown or hidden as a
|
193
|
// placeholder for pages that do not have any panes.
|
194
|
$rows[] = array(
|
195
|
'data' => array(
|
196
|
array('data' => $page_id != 'disabled' ? t('No panes on this page.') : t('No disabled panes.'), 'colspan' => 4),
|
197
|
),
|
198
|
'class' => array('page-message page-'. $page_id .'-message', $class),
|
199
|
);
|
200
|
|
201
|
// Loop through each checkout pane currently assigned to this page.
|
202
|
foreach (element_children($form['page'][$page_id]['panes']) as $pane_id) {
|
203
|
$row = array(
|
204
|
drupal_render($form['page'][$page_id]['panes'][$pane_id]['name']),
|
205
|
drupal_render($form['page'][$page_id]['panes'][$pane_id]['page']),
|
206
|
drupal_render($form['page'][$page_id]['panes'][$pane_id]['weight']),
|
207
|
drupal_render($form['page'][$page_id]['panes'][$pane_id]['ops']),
|
208
|
);
|
209
|
|
210
|
$rows[] = array('data' => $row, 'class' => array('draggable'));
|
211
|
}
|
212
|
}
|
213
|
|
214
|
$variables = array(
|
215
|
'header' => $header,
|
216
|
'rows' => $rows,
|
217
|
'attributes' => array('id' => 'panes'),
|
218
|
);
|
219
|
|
220
|
return theme('table', $variables) . drupal_render_children($form);
|
221
|
}
|
222
|
|
223
|
/**
|
224
|
* Build the configuration form for a checkout pane.
|
225
|
*/
|
226
|
function commerce_checkout_pane_settings_form($form, &$form_state, $checkout_pane) {
|
227
|
// Build the form array with the bare minimum fields.
|
228
|
$form['checkout_pane'] = array(
|
229
|
'#type' => 'value',
|
230
|
'#value' => $checkout_pane,
|
231
|
);
|
232
|
|
233
|
$form['display'] = array(
|
234
|
'#type' => 'fieldset',
|
235
|
'#title' => t('Display settings'),
|
236
|
'#description' => t('These settings are common to all checkout panes and affect their appearance on the checkout form.'),
|
237
|
);
|
238
|
$form['display']['collapsibility'] = array(
|
239
|
'#type' => 'radios',
|
240
|
'#title' => t('Checkout form fieldset display'),
|
241
|
'#description' => t('Checkout panes are rendered on the checkout form in individual fieldsets.') .'<br />'. t('Specify here how the fieldset for this pane will appear.'),
|
242
|
'#options' => array(
|
243
|
'default' => t('Display this pane in a non-collapsible fieldset.'),
|
244
|
'collapsible' => t('Display this pane in a collapsible fieldset.'),
|
245
|
'collapsed' => t('Display this pane in a collapsed fieldset.'),
|
246
|
'none' => t('Do not display this pane in a fieldset.'),
|
247
|
),
|
248
|
'#default_value' => $checkout_pane['fieldset'] ? ($checkout_pane['collapsible'] ? ($checkout_pane['collapsed'] ? 'collapsed' : 'collapsible') : 'default') : 'none',
|
249
|
);
|
250
|
|
251
|
// If the checkout pane has a review callback, allow the user to include the
|
252
|
// pane on the review checkout pane.
|
253
|
$form['display']['review'] = array(
|
254
|
'#type' => 'checkbox',
|
255
|
'#title' => t('Include this pane on the Review checkout pane.'),
|
256
|
'#default_value' => $checkout_pane['review'],
|
257
|
'#access' => (boolean) commerce_checkout_pane_callback($checkout_pane, 'review'),
|
258
|
);
|
259
|
|
260
|
// If a settings form exists for the specified checkout pane...
|
261
|
if ($callback = commerce_checkout_pane_callback($checkout_pane, 'settings_form')) {
|
262
|
// Create a fieldset to hold the checkout pane settings.
|
263
|
$form['settings'] = array(
|
264
|
'#type' => 'fieldset',
|
265
|
'#title' => t('Checkout pane configuration'),
|
266
|
'#description' => t('These settings are specific to this checkout pane.'),
|
267
|
);
|
268
|
|
269
|
// Add the settings from the callback to the form.
|
270
|
$form['settings'] += $callback($checkout_pane);
|
271
|
}
|
272
|
|
273
|
$form['submit'] = array(
|
274
|
'#type' => 'submit',
|
275
|
'#value' => t('Save configuration'),
|
276
|
'#submit' => array('commerce_checkout_pane_settings_form_save_submit'),
|
277
|
);
|
278
|
$form['reset'] = array(
|
279
|
'#type' => 'submit',
|
280
|
'#value' => t('Reset to defaults'),
|
281
|
'#suffix' => l(t('Cancel'), 'admin/commerce/config/checkout/form'),
|
282
|
'#submit' => array('commerce_checkout_pane_settings_form_reset_submit'),
|
283
|
);
|
284
|
|
285
|
return $form;
|
286
|
}
|
287
|
|
288
|
/**
|
289
|
* Submit handler for the checkout pane settings form's save button.
|
290
|
*/
|
291
|
function commerce_checkout_pane_settings_form_save_submit($form, &$form_state) {
|
292
|
// Load and update the pane with values from the form.
|
293
|
$checkout_pane = commerce_checkout_pane_load($form_state['values']['checkout_pane']['pane_id']);
|
294
|
|
295
|
// Update the fieldset collapsibility variables.
|
296
|
switch ($form_state['values']['collapsibility']) {
|
297
|
case 'collapsible':
|
298
|
$checkout_pane['fieldset'] = TRUE;
|
299
|
$checkout_pane['collapsible'] = TRUE;
|
300
|
$checkout_pane['collapsed'] = FALSE;
|
301
|
break;
|
302
|
case 'collapsed':
|
303
|
$checkout_pane['fieldset'] = TRUE;
|
304
|
$checkout_pane['collapsible'] = TRUE;
|
305
|
$checkout_pane['collapsed'] = TRUE;
|
306
|
break;
|
307
|
case 'none':
|
308
|
$checkout_pane['fieldset'] = FALSE;
|
309
|
$checkout_pane['collapsible'] = FALSE;
|
310
|
$checkout_pane['collapsed'] = FALSE;
|
311
|
break;
|
312
|
case 'default':
|
313
|
default:
|
314
|
$checkout_pane['fieldset'] = TRUE;
|
315
|
$checkout_pane['collapsible'] = FALSE;
|
316
|
$checkout_pane['collapsed'] = FALSE;
|
317
|
break;
|
318
|
}
|
319
|
|
320
|
// Update the pane's review page visibility.
|
321
|
$checkout_pane['review'] = $form_state['values']['review'];
|
322
|
|
323
|
// Save the changes.
|
324
|
commerce_checkout_pane_save($checkout_pane);
|
325
|
|
326
|
// Save this checkout pane's settings as if this was a system settings form.
|
327
|
if (!empty($form['settings'])) {
|
328
|
foreach (element_children($form['settings']) as $field) {
|
329
|
if (!empty($form['settings'][$field]['#type'])) {
|
330
|
// Provide support for containers one level deep.
|
331
|
if (in_array($form['settings'][$field]['#type'], array('container', 'fieldset'))) {
|
332
|
foreach (element_children($form['settings'][$field]) as $nested_field) {
|
333
|
if (isset($form_state['values'][$nested_field])) {
|
334
|
variable_set($nested_field, $form_state['values'][$nested_field]);
|
335
|
}
|
336
|
}
|
337
|
}
|
338
|
elseif (isset($form_state['values'][$field])) {
|
339
|
variable_set($field, $form_state['values'][$field]);
|
340
|
}
|
341
|
}
|
342
|
}
|
343
|
}
|
344
|
|
345
|
drupal_set_message(t('Checkout pane saved.'));
|
346
|
|
347
|
// Redirect to the main checkout form builder page on save.
|
348
|
$form_state['redirect'] = 'admin/commerce/config/checkout/form';
|
349
|
}
|
350
|
|
351
|
/**
|
352
|
* Submit handler for the checkout pane settings form's reset button.
|
353
|
*/
|
354
|
function commerce_checkout_pane_settings_form_reset_submit($form, &$form_state) {
|
355
|
// Reset the display settings for the checkout pane.
|
356
|
commerce_checkout_pane_reset($form_state['values']['checkout_pane']['pane_id']);
|
357
|
|
358
|
// Reset this checkout pane's settings as if this was a system settings form.
|
359
|
if (!empty($form['settings'])) {
|
360
|
foreach (element_children($form['settings']) as $field) {
|
361
|
// Provide support for containers one level deep.
|
362
|
if (in_array($form['settings'][$field]['#type'], array('container', 'fieldset'))) {
|
363
|
foreach (element_children($form['settings'][$field]) as $nested_field) {
|
364
|
variable_del($nested_field);
|
365
|
}
|
366
|
}
|
367
|
else {
|
368
|
variable_del($field);
|
369
|
}
|
370
|
}
|
371
|
}
|
372
|
|
373
|
drupal_set_message(t('Checkout pane reset.'));
|
374
|
}
|
375
|
|
376
|
/**
|
377
|
* Builds the checkout completion Rules Overview page.
|
378
|
*/
|
379
|
function commerce_checkout_complete_rules() {
|
380
|
RulesPluginUI::$basePath = 'admin/commerce/config/checkout/rules';
|
381
|
$options = array('show plugin' => FALSE);
|
382
|
|
383
|
$content['enabled']['title']['#markup'] = '<h3>' . t('Enabled checkout completion rules') . '</h3>';
|
384
|
|
385
|
$conditions = array('event' => 'commerce_checkout_complete', 'plugin' => 'reaction rule', 'active' => TRUE);
|
386
|
$content['enabled']['rules'] = RulesPluginUI::overviewTable($conditions, $options);
|
387
|
$content['enabled']['rules']['#empty'] = t('There are no active checkout completion rules.');
|
388
|
|
389
|
$content['disabled']['title']['#markup'] = '<h3>' . t('Disabled checkout completion rules') . '</h3>';
|
390
|
|
391
|
$conditions['active'] = FALSE;
|
392
|
$content['disabled']['rules'] = RulesPluginUI::overviewTable($conditions, $options);
|
393
|
$content['disabled']['rules']['#empty'] = t('There are no disabled checkout rules.');
|
394
|
|
395
|
// Store the function name in the content array to make it easy to alter the
|
396
|
// contents of this page.
|
397
|
$content['#page_callback'] = 'commerce_checkout_complete_rules';
|
398
|
|
399
|
return $content;
|
400
|
}
|
401
|
|
402
|
/**
|
403
|
* Form callback: confirmation form for manually invoking the checkout
|
404
|
* completion event for an order.
|
405
|
*
|
406
|
* @param $order
|
407
|
* The order object to process checkout completion on.
|
408
|
*
|
409
|
* @return
|
410
|
* The form array to confirm the process.
|
411
|
*
|
412
|
* @see confirm_form()
|
413
|
*/
|
414
|
function commerce_checkout_complete_form($form, &$form_state, $order) {
|
415
|
$form['order_id'] = array(
|
416
|
'#type' => 'value',
|
417
|
'#value' => $order->order_id,
|
418
|
);
|
419
|
|
420
|
// Build a description of what the user may expect to occur on submission.
|
421
|
$items = array(
|
422
|
t('The normal checkout completion process will be invoked on this order.'),
|
423
|
t('This may involve order status updates and e-mail notifications.'),
|
424
|
);
|
425
|
|
426
|
$form = confirm_form($form,
|
427
|
t('Are you sure you want to simulate checkout completion for order @number?', array('@number' => $order->order_number)),
|
428
|
'admin/commerce/orders/' . $order->order_id . '/edit',
|
429
|
'<p>' . theme('item_list', array('items' => $items)) . '</p>',
|
430
|
t('Simulate checkout completion'),
|
431
|
t('Cancel')
|
432
|
);
|
433
|
|
434
|
return $form;
|
435
|
}
|
436
|
|
437
|
/**
|
438
|
* Form submit callback for commerce_checkout_complete_form().
|
439
|
*/
|
440
|
function commerce_checkout_complete_form_submit($form, &$form_state) {
|
441
|
if ($order = commerce_order_load($form_state['values']['order_id'])) {
|
442
|
commerce_checkout_complete($order);
|
443
|
drupal_set_message(t('Checkout completion rules have been executed for the order.'));
|
444
|
$form_state['redirect'] = 'admin/commerce/orders/' . $order->order_id . '/edit';
|
445
|
}
|
446
|
else {
|
447
|
drupal_set_message(t('Order not found.'), 'error');
|
448
|
$form_state['redirect'] = 'admin/commerce/orders';
|
449
|
}
|
450
|
}
|