Basic search API integration.
[sandbox/serialjaywalker/1195272.git] / modules / order / commerce_pos_order.module
1 <?php
2
3 /**
4 * @file
5 * Contains functions for the commerce_pos_order module
6 */
7
8 /**
9 * Implements hook_entity_info_alter().
10 */
11 function commerce_pos_order_entity_info_alter(&$entity_info) {
12 //Adds display modes for the receipt and POS screen.
13 $entity_info['commerce_order']['view modes']['pos screen'] = array(
14 'label' => t('POS Screen'),
15 'custom settings' => TRUE,
16 );
17 $entity_info['commerce_order']['view modes']['pos receipt'] = array(
18 'label' => t('POS Receipt'),
19 'custom settings' => TRUE,
20 );
21 }
22
23 /**
24 * Implements hook_element_info().
25 */
26 function commerce_pos_order_element_info() {
27 $items = array();
28
29 $items['commerce_pos_order'] = array(
30 '#input' => TRUE,
31 '#process' => array('commerce_pos_order_element_process'),
32 '#element_validate' => array('commerce_pos_order_element_element_validate'),
33 '#theme_wrappers' => array('commerce_pos_order_element_wrapper'),
34 '#theme' => array('commerce_pos_order_element'),
35 );
36
37 return $items;
38 }
39
40 /**
41 * Process callback for commerce_pos_order form element.
42 */
43 function commerce_pos_order_element_process($element, &$form_state, $complete_form) {
44 drupal_add_library('system', 'ui.button');
45 drupal_add_js(drupal_get_path('module', 'commerce_pos_order') . '/commerce_pos_order.js', array('weight' => 20));
46
47 $element['#tree'] = TRUE;
48 $order = $element['#order'];
49 $element['order_id'] = array(
50 '#type' => 'value',
51 '#value' => isset($order->order_id) ? $order->order_id : NULL,
52 );
53
54 $element['order_status'] = array(
55 '#type' => 'radios',
56 '#title' => t('Status'),
57 '#options' => commerce_pos_order_status_options(),
58 '#default_value' => $order->status,
59 '#attributes' => array('class' => array('commerce-pos-order-status')),
60 '#weight' => 20,
61 );
62
63 return $element;
64 }
65
66 /**
67 * Template preprocessor for POS order element.
68 */
69 function template_preprocess_commerce_pos_order_element(&$variables) {
70 $element = $variables['commerce_pos_order'];
71 $order = $element['#order'];
72
73 if (is_object($order)) {
74 $element['content'] = entity_get_controller('commerce_order')->view(array($order->order_id => $order), 'pos screen');
75 $variables['commerce_pos_order'] = $element;
76 }
77 }
78
79 /**
80 * Theme function for POS order element.
81 */
82 function theme_commerce_pos_order_element($variables) {
83 return drupal_render($variables['commerce_pos_order']['content']) . drupal_render_children($variables['commerce_pos_order']);
84 }
85
86 /**
87 * Validate callback for commerce_pos_order form element
88 */
89 function commerce_pos_order_element_element_validate($element, &$form_state) {
90 $order_id = $element['#order']->order_id;
91 if (!commerce_order_load($order_id)) {
92 form_error($element, t('Attempted to modify an invalid order'));
93 }
94 }
95
96 /**
97 * Implements hook_commerce_pos_action_info().
98 */
99 function commerce_pos_order_commerce_pos_action_info() {
100 return array(
101 'commerce_pos_order_load' => array(
102 'callbacks' => array(
103 'parse' => 'commerce_pos_order_load_parse',
104 'access' => 'commerce_pos_order_access',
105 'validate' => 'commerce_pos_order_load_validate',
106 'execute' => 'commerce_pos_order_load_execute',
107 'extract' => 'commerce_pos_order_load_extract',
108 ),
109 'action text' => 'OR',
110 /*'button' => array(
111 'title' => t('Load order'),
112 'section' => 'order',
113 ),*/
114 'weight' => 99,
115 ),
116 'commerce_pos_order_set_status' => array(
117 'callbacks' => array(
118 'access' => 'commerce_pos_order_access',
119 'validate' => 'commerce_pos_order_set_status_validate',
120 'execute' => 'commerce_pos_order_set_status_execute',
121 'extract' => 'commerce_pos_order_set_status_extract',
122 ),
123 'weight' => 99,
124 ),
125 'commerce_pos_order_print_receipt' => array(
126 'callbacks' => array(
127 'access' => 'commerce_pos_order_access',
128 'parse' => 'commerce_pos_order_print_receipt_parse',
129 'validate' => 'commerce_pos_order_action_print_receipt_validate',
130 'execute' => 'commerce_pos_order_print_receipt_execute',
131 ),
132 'action text' => 'PR',
133 'button' => array(
134 'title' => t('Receipt'),
135 'section' => 'order',
136 'weight' => 75,
137 ),
138 'weight' => 80,
139 ),
140 );
141 }
142
143 /**
144 * Parse callback for receipt printing.
145 */
146 function commerce_pos_order_print_receipt_parse($input, $action_text) {
147 return $input == $action_text;
148 }
149
150
151 /**
152 * Validate callback for printing a receipt.
153 */
154 function commerce_pos_order_action_print_receipt_validate($variables) {
155 if (empty($variables['order'])) {
156 return array(t('You must have an order loaded to print a receipt'));
157 }
158 else {
159 $status = commerce_order_status_load($variables['order']->status);
160 if ($status['state'] != 'completed') {
161 return array(t('You can only print a receipt for a completed order.'));
162 }
163 }
164 }
165
166 /**
167 * Execute callback for receipt printing.
168 */
169 function commerce_pos_order_print_receipt_execute(&$variables) {
170 $variables['order']->data['print_receipt'] = TRUE;
171 }
172
173 /**
174 * Extract callback for setting the order status.
175 */
176 function commerce_pos_order_set_status_extract(&$variables, $values) {
177 $variables['order_status'] = $values['order']['order_status'];
178 }
179
180 /**
181 * Validate callback for setting order status.
182 */
183 function commerce_pos_order_set_status_validate(&$variables) {
184 //Allow administrators to configure this by rules.
185 $order = $variables['order'];
186 $order->status = $variables['order_status'];
187 rules_invoke_event('commerce_pos_order_set_status', $order);
188
189 if (!empty($order->error)) {
190 return array($order->error);
191 }
192 $variables['order'] = $order;
193 }
194
195 /**
196 * Validation callback to be used by actions that need to modify an order.
197 */
198 function commerce_pos_order_require_modifiable_order(&$variables) {
199 //TODO: if rules won't do this reliably, it may be necessary to replace this with hard-coded validation
200 if (!empty($variables['order'])) {
201 $order = $variables['order'];
202 rules_invoke_event('commerce_pos_modify_order_validate', $order);
203 }
204 if (!empty($order->error)) {
205 $error = $order->error;
206 unset($order->error);
207 return array($error);
208 }
209 }
210
211 /**
212 * Execute callback for set order status command.
213 */
214 function commerce_pos_order_set_status_execute(&$variables) {
215 commerce_order_save($variables['order']);
216 }
217
218 /**
219 * Access callback for commerce_pos_order load.
220 */
221 function commerce_pos_order_access($variables) {
222 $order = $variables['order'];
223 if (empty($order->order_id)) {
224 return commerce_order_access('create');
225 }
226 else {
227 return commerce_order_access('view', $order);
228 }
229 }
230
231 /**
232 * Parse callback for order load action.
233 */
234 function commerce_pos_order_load_parse($input, $action_text = 'OR') {
235 return commerce_pos_string_ends_with($action_text, $input);
236 }
237
238 /**
239 * Extract callback for order load action.
240 */
241 function commerce_pos_order_load_extract(&$variables, $values) {
242 $input = $variables['input'];
243 if (!empty($values['action_name']) || !empty($values['new_action_name'])) {
244 $order_number = $input;
245 }
246 else {
247 $action_text = $variables['action']['action text'];
248 $order_number = drupal_substr($input, 0, drupal_strlen($input) - drupal_strlen($action_text));
249 }
250 $variables['order_number'] = $order_number;
251 }
252
253 /**
254 * Validate callback for order load action.
255 */
256 function commerce_pos_order_load_validate(&$variables) {
257 if(!empty($variables['order'])) {
258 return array(t('Please clear the current order before loading another.'));
259 }
260 else {
261 $order_number = $variables['order_number'];
262 $order = commerce_order_load_by_number($order_number);
263
264 if ($order && $order->type == 'commerce_order') {
265 $variables['order_id'] = $order->order_id;
266 $variables['order'] = $order;
267 }
268 else {
269 return array(t('The order could not be loaded.'));
270 }
271 }
272 }
273
274
275 /**
276 * Implements hook_commerce_pos_build().
277 */
278 function commerce_pos_order_commerce_pos_build($variables = array()) {
279 $return_val = array();
280 if (!empty($variables['order'])) {
281 $order = $variables['order'];
282 // if (commerce_pos_order_is_pos_order($order)) {
283 // commerce_pos_order_refresh($order);
284 // }
285 $return_val['order'] = array(
286 '#type' => 'commerce_pos_order',
287 '#title' => t('Order'),
288 '#order' => $order,
289 );
290
291 if (!empty($order->data['print_receipt']) && $order->data['print_receipt'] == REQUEST_TIME) {
292 $header = commerce_pos_order_receipt_wrapper('header');
293 $footer = commerce_pos_order_receipt_wrapper('footer');
294 $return_val['receipt'] = array(
295 '#type' => 'commerce_pos_receipt',
296 '#time' => format_date($order->changed),
297 '#header' => check_markup($header['value'], $header['format']),
298 '#footer' => check_markup($footer['value'], $footer['format']),
299 'content' => entity_get_controller('commerce_order')->view(array($order->order_id => $order), 'pos receipt'),
300 );
301 }
302 elseif (!empty($order->data['print_empty_receipt']) && $order->data['print_empty_receipt'] == REQUEST_TIME) {
303 $return_val['empty_receipt'] = array(
304 '#type' => 'commerce_pos_receipt',
305 '#unstyled' => TRUE,
306 'content' => array('#markup' => t('No content')),
307 );
308 }
309 //Give modules a hook to update customer displays.
310 module_invoke_all('commerce_pos_order_display', $variables['order']);
311 }
312 return $return_val;
313 }
314
315 /**
316 * Make sure that the pos screen and pos receipt view modes will show the order total.
317 *
318 * @param $type
319 * The order bundle to configure.
320 */
321 function commerce_pos_order_configure_order_type($type = 'commerce_order') {
322 //Update the order total field.
323 $instance = field_info_instance('commerce_order', 'commerce_order_total', $type);
324 if (!empty($instance)) {
325 $display = array(
326 'type' => 'commerce_price_formatted_components',
327 'settings' => array(
328 'calculation' => FALSE,
329 ),
330 );
331 $instance['display']['pos screen'] = $display;
332 $instance['display']['pos receipt'] = $display;
333 field_update_instance($instance);
334 }
335 }
336
337 /**
338 * Implements hook_enable().
339 */
340 function commerce_pos_order_enable() {
341 commerce_pos_order_configure_order_type();
342 }
343
344 /**
345 * Implements hook_theme().
346 */
347 function commerce_pos_order_theme($existing, $type, $theme, $path) {
348 return array(
349 'commerce_pos_order_element_wrapper' => array(
350 'render element' => 'commerce_pos_order',
351 ),
352 'commerce_pos_order_element' => array(
353 'render element' => 'commerce_pos_order',
354 ),
355 );
356 }
357
358 /**
359 * Theme wrapper for commerce_pos_order element
360 */
361 function theme_commerce_pos_order_element_wrapper($variables) {
362 drupal_add_css(drupal_get_path('module', 'commerce_pos_order') . '/theme/commerce_pos_order.css');
363 $element = $variables['commerce_pos_order'];
364 $prefix = '<div class = \'commerce-pos-order\' tabindex=\'2\' >';
365 $suffix = '</div>';
366 return $prefix . $element['#children'] . $suffix;
367 }
368
369 /**
370 * Implements hook_commerce_pos_extract().
371 */
372 function commerce_pos_order_commerce_pos_extract(&$variables, $values) {
373 if(!empty($values['order']['order_id']) && $variables['action']['name'] != 'commerce_pos_clear') {
374 $variables['order'] = commerce_order_load($values['order']['order_id']);
375 //commerce_pos_order_refresh($variables['order']);
376 }
377 }
378
379 /**
380 * Implements hook_commerce_order_status_info().
381 */
382 function commerce_pos_order_commerce_order_status_info() {
383 $order_statuses = array();
384
385 $order_statuses['pos_canceled'] = array(
386 'name' => 'pos_canceled',
387 'title' => t('Canceled (POS)'),
388 'state' => 'canceled',
389 'weight' => 10,
390 'pos' => TRUE,
391 'pos title' => t('Canceled'),
392 );
393
394 $order_statuses['pos_in_progress'] = array(
395 'name' => 'pos_in_progress',
396 'title' => t('In Progress (POS)'),
397 'state' => 'pos',
398 'pos' => TRUE,
399 'pos title' => t('In Progress'),
400 );
401
402 $order_statuses['pos_completed'] = array(
403 'name' => 'pos_completed',
404 'title' => t('Completed (POS)'),
405 'state' => 'completed',
406 'pos' => TRUE,
407 'pos title' => t('Completed'),
408 );
409
410 return $order_statuses;
411 }
412
413 /**
414 * Implements hook_commerce_order_state_info().
415 */
416 function commerce_pos_order_commerce_order_state_info() {
417 $order_states = array();
418
419 $order_states['pos'] = array(
420 'name' => 'pos',
421 'title' => t('At POS'),
422 'description' => t('Orders in this state have started checkout at the POS but have not been completed.'),
423 'weight' => -5,
424 'default_status' => 'pos_in_progress',
425 );
426
427 return $order_states;
428 }
429
430 /**
431 * Return an array of POS order statuses.
432 */
433 function commerce_pos_order_statuses() {
434 $statuses = &drupal_static(__FUNCTION__);
435 if (empty($statuses)) {
436 $statuses = commerce_order_statuses(array('pos' => TRUE));
437 }
438 return $statuses;
439 }
440
441 /**
442 * Implements hook_commerce_order_status_info_alter().
443 */
444 function commerce_pos_order_commerce_order_status_info_alter(&$order_status_info) {
445 foreach ($order_status_info as $name => $status) {
446 if(empty($status['pos'])) {
447 $order_status_info[$name]['pos'] = FALSE;
448 }
449 }
450 }
451
452 /**
453 * Return a list of options for order status selection in the POS.
454 */
455 function commerce_pos_order_status_options() {
456 $statuses = commerce_pos_order_statuses();
457 $options = array();
458 foreach ($statuses as $key => $status) {
459 $options[$status['name']] = $status['pos title'];
460 }
461 return $options;
462 }
463
464 /**
465 * Returns a new empty order
466 */
467 function commerce_pos_order_new($uid = 0) {
468 return commerce_order_new($uid, 'pos_in_progress', 'commerce_order');
469 }
470
471 /**
472 * Implements hook_views_api() {
473 */
474 function commerce_pos_order_views_api() {
475 return array(
476 'api' => 3,
477 'path' => drupal_get_path('module', 'commerce_pos_order') . '/includes/views',
478 );
479 }
480
481 /**
482 * Determines whether or not the given order is at the POS.
483 */
484 function commerce_pos_order_is_pos_order($order) {
485 // If the order is in a pos order status, assume it is at the POS.
486 $status = commerce_order_status_load($order->status);
487 $is_pos_order = ($status['state'] == 'pos');
488
489 // Allow other modules to make the judgment based on some other criteria.
490 if (in_array(FALSE, module_invoke_all('commerce_pos_order_is_pos_order', $order, $is_pos_order))) {
491 $is_pos_order = FALSE;
492 }
493
494 return $is_pos_order;
495 }
496
497
498
499 /**
500 * Implements hook_form_FORM_ID_alter().
501 */
502 function commerce_pos_order_form_commerce_pos_settings_form_alter(&$form, &$form_state) {
503 $form['order'] = array(
504 '#type' => 'fieldset',
505 '#title' => t('Order settings'),
506 );
507 $header = commerce_pos_order_receipt_wrapper('header');
508 $form['order']['commerce_pos_order_receipt_header'] = array(
509 '#type' => 'text_format',
510 '#title' => t('Receipt header'),
511 '#default_value' => $header['value'],
512 '#format' => $header['format'],
513 );
514 $footer = commerce_pos_order_receipt_wrapper('footer');
515 $form['order']['commerce_pos_order_receipt_footer'] = array(
516 '#type' => 'text_format',
517 '#title' => t('Receipt footer'),
518 '#default_value' => $footer['value'],
519 '#format' => $footer['format'],
520 );
521 }
522
523 /**
524 * Function to get the receipt header or footer.
525 * @param $part
526 * 'header' or 'footer'
527 */
528 function commerce_pos_order_receipt_wrapper($part) {
529 return variable_get('commerce_pos_order_receipt_' . $part, array());
530 }
531
532 /**
533 * Implements hook_commerce_pos_button_section_info().
534 */
535 function commerce_pos_order_commerce_pos_button_section_info() {
536 return array('order' => array('#weight' => -70));
537 }
538
539 /**
540 * Implements hook_commerce_pos_preload().
541 */
542 function commerce_pos_order_commerce_pos_preload() {
543 drupal_add_css(drupal_get_path('module', 'commerce_pos_order') . '/theme/commerce_pos_order.css');
544 drupal_add_js(drupal_get_path('module', 'commerce_pos_order') . '/commerce_pos_order.js', array('weight' => 20));
545 }