· 8 years ago · Feb 09, 2018, 02:16 AM
1<?php
2/**
3 * Theme Base
4 * Master class for the websites primary functionality
5 * - Connection to lion IT API to pull in balance and submit coupon transactions (via SOAP ASP.NET wrapper)
6 * - Creation of w_coupon, w_coupon_type and w_transaction objects to store project details in
7 * - Integrates with ADFS system (plugin to create WP users based on active directory)
8 * - Email functionality for successful transactions (along with reporting)
9 */
10
11 class white_theme_base{
12
13 private static $instance = null;
14 private $low_coupon_stock_threshold = null;
15
16
17 private $api_endpoint_url = '';
18
19 public function __construct(){
20
21
22 $this->set_api_endpoint_base('https://beertickets.thewhiteagency.com.au');
23 $this->set_default_timezone('Australia/Sydney');
24 $this->set_low_coupon_stock_threshold(10);
25
26 //AJAX functionality
27 //main beer tickets redemption ajax call
28 add_action('wp_ajax_process_ticket_redemption', array($this, 'process_ticket_redemption'));
29 add_action('wp_ajax_nopriv_process_ticket_redemption', array($this, 'process_ticket_redemption'));
30 //process the CSV transaction log
31 add_action('wp_ajax_process_transaction_csv_report', array($this, 'process_transaction_csv_report'));
32 //resend out transaction email via admin setting (indiviudal transaction record)
33 add_action('wp_ajax_resend_transaction_email', array($this, 'resend_transaction_email'));
34
35 //TRANSACTIONS
36 add_action('init', array($this, 'register_transactions_post_type'));
37 add_action('add_meta_boxes_w_transaction', array($this, 'register_transaction_meta_boxes'), 10, 1);
38 add_action('manage_w_transaction_posts_columns', array($this, 'add_transaction_admin_columns'), 10, 1);
39 add_action('manage_w_transaction_posts_custom_column', array($this, 'customize_transaction_admin_columns'), 10, 2);
40 add_action('save_post_w_transaction', array($this, 'transaction_save_edit_admin_single'), 10, 1);
41
42 //Transaction admin columns, filters and sortables
43 add_action('manage_edit-w_transaction_sortable_columns', array($this, 'sortable_transaction_admin_columns'), 10, 1);
44 add_action('pre_get_posts', array($this, 'sortable_transaction_admin_columns_query'), 10, 1);
45 add_action('restrict_manage_posts', array($this, 'customize_transaction_admin_filters'));
46 add_action('pre_get_posts', array($this, 'restrict_transaction_admin_listing_filter'));
47 add_action('admin_notices', array($this, 'display_transaction_download_button_in_admin_header')); //display download button for transactions
48
49
50 //COUPONS
51 add_action('init', array($this, 'register_coupons_post_type'));
52 add_action('init', array($this, 'register_coupons_type_taxonomy'));
53 add_action('admin_menu', array($this, 'register_coupon_submenu_page'));
54 add_action('admin_init', array($this, 'process_csv_coupon_file_upload')); //process coupon uploads
55 add_action('admin_notices', array($this, 'display_coupon_upload_in_admin_header')); //display coupon upload button shortcut
56
57 //Coupon admin columns, filters, sortables and extras
58 add_action('manage_w_coupon_posts_columns', array($this, 'add_coupon_admin_columns'), 10, 1);
59 add_action('manage_w_coupon_posts_custom_column', array($this, 'customize_coupon_admin_columns'), 10, 2);
60 add_action('manage_edit-w_coupon_sortable_columns', array($this, 'sortable_coupon_admin_columns'), 10, 1);
61 add_action('pre_get_posts', array($this, 'sortable_coupon_admin_columns_query'), 10, 1);
62 add_action('restrict_manage_posts', array($this, 'customize_coupon_admin_filters'));
63 add_action('pre_get_posts', array($this, 'restrict_coupon_admin_listing_filter'));
64
65 //Coupon type taxonomy
66 add_action('w_coupon_type_add_form_fields', array($this,'register_coupon_taxonomy_form_fields'));
67 add_action('w_coupon_type_edit_form_fields', array($this, 'edit_coupon_taxonomy_form_fields'));
68 add_action('edited_w_coupon_type', array($this, 'save_coupon_taxonomy_form_fields'));
69 add_action('create_w_coupon_type', array($this, 'save_coupon_taxonomy_form_fields'));
70 add_action('manage_edit-w_coupon_type_columns', array($this, 'add_coupon_type_admin_columns'), 10, 1);
71 add_action('manage_w_coupon_type_custom_column', array($this, 'customize_coupon_type_admin_columns'), 10, 3);
72
73 //coupon metaboxes
74 add_action('add_meta_boxes_w_coupon', array($this, 'register_coupon_meta_boxes'), 10, 1);
75 //coupon single save
76 add_action('save_post_w_coupon', array($this, 'coupon_save_edit_admin_single'), 10, 1);
77
78 //mocu email address form (assigning mocus email to user account)
79 add_action('template_redirect', array($this, 'process_mocu_email_register'));
80
81 //Universal elements
82 add_action('admin_head', array($this, 'display_inline_admin_css')); //inline styling for pages
83 add_action('after_setup_theme', array($this, 'disable_admin_bar_for_subscribers')); //no admin bar for theme
84 add_action('init', array($this, 'redirect_users_from_admin_for_subscribers')); //subscribers cant access the backend
85 add_action('template_redirect', array($this, 'redirect_logged_out_users_to_homepage'), 50, 1); //redirect logged out users to homepage
86
87 }
88
89 /**
90 * Sets the low coupon threshold to be used for the system.
91 * This settings is used on successful transaction and used to check the system to ensure that there is appropriate levels of stock,
92 * in the case of a low level of stock an admin email is generated.
93 */
94 public function set_low_coupon_stock_threshold($low_coupon_stock_threshold){
95 $this->low_coupon_stock_threshold = $low_coupon_stock_threshold;
96 }
97
98
99
100 /**
101 * Checks to see if the current user is logged out and not on homepage, if so then redirect back home
102 */
103 public function redirect_logged_out_users_to_homepage(){
104
105 if((is_user_logged_in() == false) && (is_front_page() == false)){
106 $home_url = get_home_url();
107 header('Location: '. $home_url);
108 }
109 }
110
111 /**
112 * Sets the relative timezone for use in dates
113 */
114 public function set_default_timezone($timezone){
115 return date_default_timezone_set($timezone);
116 }
117
118 /**
119 * Outputs additional CSS in the head of admin pages
120 * - Hide slug and parent for w_coupon_type taxonomy (hide from user)
121 */
122 public function display_inline_admin_css(){
123 $screen = get_current_screen();
124
125 if($screen){
126
127 $base = $screen->base;
128 $post_type = $screen->post_type;
129 $taxonomy = $screen->taxonomy;
130
131 //if on the create new w_coupon_type screen, hide the slug and parent, it's not needed
132 if(($base == 'edit-tags') && ($taxonomy == 'w_coupon_type')){
133 ?>
134 <style type="text/css">
135 .form-field.term-slug-wrap,
136 .form-field.term-parent-wrap{
137 display: none;
138 }
139 </style>
140 <?php
141 }
142 }
143
144 }
145
146
147 /**
148 * Triggered when we complete the 'mocu_email_form' form inside the 'page-mocu-details.php' template
149 * Used to assign an email address to a user account (used to send the admin emails / receipt to)
150 */
151 public function process_mocu_email_register(){
152
153 //trigger only on the mocu email form
154 if(isset($_POST['mocu_email_form_submit'])){
155
156 $mocu_email = isset($_POST['mocu_email']) ? $_POST['mocu_email'] : '';
157 if($mocu_email){
158
159 $user = wp_get_current_user();
160 if($user->ID > 0){
161 $meta = update_user_meta($user->ID, 'user_mocu_email', $mocu_email);
162 }
163 }
164
165 }
166
167 }
168
169 /**
170 * Gets the current users mocu email address (supplied during the signup process)
171 */
172 public function get_user_mocu_email($user = ''){
173
174 if(empty($user)){
175 $user = wp_get_current_user();
176 }
177
178 $user_mocu_email = get_user_meta($user->ID, 'user_mocu_email', true);
179
180 return $user_mocu_email;
181 }
182
183 /**
184 * Gets the email form field for use on the 'page-mocu-details' template. Used to prepopulate the
185 * field if the user has previous supplied their email address
186 */
187 public function get_mocu_email_details_form_field(){
188
189 $html = '';
190
191 $user = wp_get_current_user();
192 $user_mocu_email = $this->get_user_mocu_email();
193
194 $html .='<div class="form-group input--material">';
195
196 $html .='<label for="inputValidation" class="control-label">EMAIL ADDRESS</label>';
197 $html .='<input name="mocu_email" id="inputValidation" type="txt" class="form-control" placeholder="Your MoCU email address*" value="' . $user_mocu_email . '">';
198 $html .='<span for="inputValidation" class="error-label"></span>';
199 $html .='</div>';
200
201 return $html;
202 }
203
204 public static function display_mocu_email_form_field(){
205 $instance = self::getInstance();
206
207 $html ='';
208 $html .= $instance->get_mocu_email_details_form_field();
209
210 echo $html;
211 }
212
213
214 /**
215 * Sets the API endpoint for our user functionality
216 */
217 public function set_api_endpoint_base($api_endpoint_url){
218 $this->api_endpoint_base = $api_endpoint_url;
219 }
220
221 /**
222 * gets the API endpoint
223 */
224 public function get_api_endpoint_base(){
225 return $this->api_endpoint_base;
226 }
227
228
229 /**
230 * Outputs a section on the 'w_coupon' administrator page to give quick access to the coupon upload menu
231 */
232 public function display_coupon_upload_in_admin_header(){
233
234 $html = '';
235
236 if(is_admin()){
237 $current_screen = get_current_screen();
238
239 //On the edit coupon page, show link to upload
240 if($current_screen->post_type == 'w_coupon' && $current_screen->base == 'edit'){
241 $html .= '<div class="coupon-admin-button-wrap">';
242 $html .= '<p>Click to upload additional coupons to the system</p>';
243 $html .= $this->get_coupon_upload_link_button();
244 $html .= '</div>';
245 }
246
247 }
248
249 echo $html;
250 }
251
252 /**
253 * Add a button to download the transactions in the DB
254 */
255 public function display_transaction_download_button_in_admin_header(){
256
257 $html = '';
258 if(is_admin()){
259 $current_screen = get_current_screen();
260
261 //On the edit transaction page, show download link
262 if($current_screen->post_type == 'w_transaction' && $current_screen->base == 'edit'){
263 $html .= '<div class="transaction-admin-wrap">';
264 $html .= '<p>Click here to download a CSV record of all transactions in the system</p>';
265 $html .= '<span class="button" id="download_transaction_csv">Download CSV Report</span>';
266 $html .= '</div>';
267
268 }
269
270 }
271 echo $html;
272 }
273
274
275 /**
276 * Generates a CSV file export for all transactions in the system
277 */
278 public function process_transaction_csv_report(){
279
280 $response = array();
281 $response['status'] = 'error';
282
283 $transaction_args = array(
284 'posts_per_page' => -1,
285 'post_type' => 'w_transaction',
286 'post_status' => 'publish'
287 );
288 $transactions = get_posts($transaction_args);
289
290
291 $date = New DateTime();
292 $date_format = $date->format("d_m_Y_H_i_s");
293
294 $path = get_stylesheet_directory() . '/transaction_reports/';
295
296 //if folder doesn't exist, create
297 if(!file_exists($path)){
298 mkdir($path, 755, true);
299 }
300
301 //open file for writing
302 $file_name = 'transaction-export-' . $date_format . '.csv';
303 $output_file = fopen($path . $file_name, 'w');
304
305 if($transactions){
306 if($output_file){
307
308 $headers = array(
309 'id',
310 'title',
311 'transaction_user_id',
312 'transaction_user_login',
313 'transaction_coupon_id',
314 'transaction_coupon_code',
315 'transaction_coupon_value',
316 'transaction_redemption_date',
317 'transaction_entity_id',
318 'transaction_cost_centre',
319 'transaction_sub_account',
320 'transaction_email_date',
321 'transaction_mocu_email',
322 'transaction_response_id'
323 );
324 $file_header_row = fputcsv($output_file, $headers);
325
326 //header row successfully added
327 if($file_header_row){
328 //loop through all transactions and output them
329 foreach($transactions as $transaction){
330 $transaction_id = $transaction->ID;
331 $transaction_title = $transaction->post_title;
332 $transaction_user_id = get_post_meta($transaction_id, 'transaction_user_id', true);
333 $transaction_coupon_id = get_post_meta($transaction_id, 'transaction_coupon_id', true);
334 $transaction_redemption_date = get_post_meta($transaction_id, 'transaction_redemption_date', true);
335 $transaction_entity_id = get_post_meta($transaction_id, 'transaction_entity_id', true);
336 $transaction_cost_centre = get_post_meta($transaction_id, 'transaction_cost_centre', true);
337 $transaction_sub_account = get_post_meta($transaction_id, 'transaction_sub_account', true);
338 $transaction_email_date = get_post_meta($transaction_id, 'transaction_email_date', true);
339 $transaction_mocu_email = get_post_meta($transaction_id, 'transaction_mocu_email', true);
340 $transaction_response_id = get_post_meta($transaction_id,'transaction_response_id', true);
341
342 //get additional user info
343 $user = get_user_by('ID', $transaction_user_id);
344 $user_info = get_userdata($user->ID);
345 $user_username = $user_info->user_login;
346
347 //get additional coupon information
348 $coupon = get_post($transaction_coupon_id);
349 $coupon_code = get_post_meta($coupon->ID, 'coupon_code', true);
350 $coupon_types = wp_get_object_terms($coupon->ID, 'w_coupon_type');
351 if($coupon_types){
352 $coupon_type = $coupon_types[0];
353 $coupon_type_value = get_term_meta($coupon_type->term_id, 'coupon_type_value', true);
354 $coupon_type_sku = get_term_meta($coupon_type->term_id, 'coupon_type_sku', true);
355 }
356
357 $values = array(
358 $transaction_id,
359 $transaction_title,
360 $transaction_user_id,
361 $user_username,
362 $transaction_coupon_id,
363 $coupon_code,
364 $coupon_type_value,
365 $transaction_redemption_date,
366 $transaction_entity_id,
367 $transaction_cost_centre,
368 $transaction_sub_account,
369 $transaction_email_date,
370 $transaction_mocu_email,
371 $transaction_response_id
372 );
373 $row = fputcsv( $output_file, $values);
374 }
375
376 //return success
377 $file_absolute_url = get_stylesheet_directory_uri() . '/transaction_reports/' . $file_name;
378 $response['status'] = 'success';
379 $response['messages'][] = 'Successfully created export file';
380 $response['data']['file_url'] = $file_absolute_url;
381 $response['data']['file_name'] = $file_name;
382
383 }else{
384 $response['messages'][] = 'Could not add the header row to the transaction file, export filed';
385
386 }
387 }else{
388 $response['messages'][] = 'Transaction file could not be written, export failed';
389 }
390 }else{
391 $response['messages'][] = 'No transactions to export';
392 }
393
394
395 fclose($output_file);
396
397 echo json_encode($response);
398 die();
399 }
400
401
402 /**
403 * Logs an arbitrary message to our event log, used for logging purposes (beertickets-log.txt)
404 */
405 public function log_report_message($message_element){
406
407 $date = New DateTime();
408 $date_format = $date->format("d/m/Y H:i:s");
409
410 $path = get_stylesheet_directory() . '/';
411 $file_name = 'beertickets-logs.txt';
412 $log_file = fopen($path . $file_name, 'a+');
413
414 if($log_file){
415 //array of messages
416 if(is_array($message_element)){
417 foreach($message_element as $message){
418
419
420 //lock the file, write our message and then unlock for others
421 flock($log_file, LOCK_EX);
422 fwrite($log_file, $date_format. ': ' . $message . "\n");
423 flock($log_file, LOCK_UN);
424 }
425 }
426 //singular message
427 else{
428 flock($log_file, LOCK_EX);
429 fwrite($log_file, $date_format. ': ' . $message_element . "\n");
430 flock($log_file, LOCK_UN);
431 }
432 }
433
434 fclose($log_file);
435 }
436
437 /**
438 * Registers a submenu page for our coupon content type
439 * Holds additional settings and options for coupons
440 */
441 public function register_coupon_submenu_page(){
442
443 add_submenu_page(
444 'edit.php?post_type=w_coupon',
445 __('Coupon Settings', 'beertickets'),
446 __('Coupon Settings', 'beertickets'),
447 'manage_options',
448 'coupon-settings',
449 array($this, 'display_coupon_submenu_page')
450 );
451 }
452
453 /**
454 * Displays the submenu for the coupon settings
455 * @see register_coupon_submenu_page
456 */
457 public function display_coupon_submenu_page(){
458
459 $html = '';
460
461 $html .= '<div class="wrap coupon-settings-admin">';
462 $html .= '<h1>Coupon Settings</h1>';
463 $html .= '<p>Upload your CSV file below. The importer expects the first row to be headers with the following field names <b>coupon_code</b>, <b>coupon_type_sku</b> and <b>coupon_expiry_date</b></p>';
464 $html .= '<p>Each coupon will be imported and mapped against all <b>coupon types</b>. Only coupons with a corresponding code will be imported</p>';
465 //check if we have an error message to flag
466 if(isset($_SESSION['messages'])){
467 $html .= '<div class="admin-messages">';
468 foreach($_SESSION['messages'] as $message){
469 $html .= '<p><strong>' . $message . '</strong></p>';
470 }
471 $html .= '</div>';
472 session_destroy();
473 }
474
475
476 //import section
477 $html .= '<div class="coupon-import">';
478 $html .= '<h2>Import CSV FIle</h2>';
479 $html .= '<p>Select the CSV file that contains your coupon details. This importer will create \'Coupons\' based on your provided information </p>';
480
481 //Form
482 $coupon_menu_url = menu_page_url('coupon-settings', false);
483 $html .= '<form id="coupon-csv-form" method="POST" action="' . $coupon_menu_url .'" enctype="multipart/form-data">';
484 $html .= '<p>';
485 $html .= '<label for="coupon-file-upload">';
486 $html .= '<input type="file" name="coupon-file-upload" id="coupon-file-upload"/>';
487 $html .= '</p>';
488 $html .= '<p>';
489 $html .= '<input type="submit" class="button button-primary" name="coupon-submit" id="coupon-submit" title="process import" value="Submit Coupon CSV Import"/>';
490 $html .= '</p>';
491
492 $html .= '</form>';
493 $html .- '</div>';
494
495
496 $log_file_url = get_stylesheet_directory() . '/beertickets-logs.txt';
497
498 //Additional settings
499 $html .= '<div>';
500 $html .= '<h2>Additional Settings</h2>';
501 $html .= '<p>Here are some additional settings / options for this system</p>';
502 $html .= '<div class="debug-admin-wrap">';
503 $html .= '<p>Click below to download the current bertickets log file</p>';
504
505 if(file_exists($log_file_url)){
506 $log_file_absolute_url = get_stylesheet_directory_uri() . '/beertickets-logs.txt';
507 $html .= '<a href="' . $log_file_absolute_url . '" target="_blank" download>';
508 $html .= '<span class="button" id="download_log_file">Get Log File</span>';
509 $html .= '</a>';
510 }else{
511 $html .= '<p>Currently there is no log file (or it cant be found)</p>';
512 }
513
514 $html .= '</div>';
515
516 $html .= '</div>';
517
518 $html .= '</div>';
519
520 echo $html;
521 }
522
523
524 /**
525 * Processes the CSV file import for the coupons post type
526 * Loads the CSV file and reads it's values into memory. Creating coupons as required from data
527 */
528 public function process_csv_coupon_file_upload(){
529
530 //trigger only on submit of coupon import
531 if(isset($_POST['coupon-submit'])){
532
533 //sesions, so we can store values
534 session_start();
535
536 //collect file data
537 $coupon_file_upload = isset($_FILES['coupon-file-upload']) ? $_FILES['coupon-file-upload'] : '';
538
539 //Check for errors
540 switch($coupon_file_upload['error']){
541
542 case UPLOAD_ERR_OK:
543 echo 'File upload good';
544 break;
545 case UPLOAD_ERR_NO_FILE:
546 echo 'No file uploaded';
547 break;
548 default:
549 echo 'Other error code';
550 break;
551 }
552
553 //check if we've uploaded a CSV
554 $mimes = array('application/vnd.ms-excel','text/plain','text/csv','text/tsv');
555 if(in_array($coupon_file_upload['type'], $mimes)){
556
557 //check for file size
558 if($coupon_file_upload['size'] > 0){
559
560 //Load CSV file i
561 $coupon_rows = array();
562 $header = null;
563
564 $csv_file = fopen($coupon_file_upload['tmp_name'], "r");
565 if($csv_file){
566 while($row = fgetcsv($csv_file)){
567 if($header == null){
568 $header = $row;
569
570 $needed_headers = array(
571 'coupon_code',
572 'coupon_type_sku',
573 'coupon_expiry_date'
574 );
575
576 //check to ensure the headers are exactly as we need them else fail
577 if(count(array_intersect($header, $needed_headers)) != count($needed_headers)){
578 $_SESSION['messages'][] = 'The header (the first column) of the CSV file isnt correct, the following names are needed: ' . implode(', ', $needed_headers);
579 break;
580 }
581
582 continue;
583 }
584 //create array of key values
585 $coupon_rows[] = array_combine($header, $row);
586 }
587
588 }else{
589 $_SESSION['messages'][] = 'fopen function did not work on uploaded CSV file, process aborted';
590 }
591
592 //if we have rows of data, create the coupons
593 if($coupon_rows){
594 foreach($coupon_rows as $coupon_data){
595
596
597 $coupon = $this->create_coupon_from_import($coupon_data);
598
599
600 //After all have been processed, display admin message with status
601 add_action('admin_notices', function() use ($coupon){
602
603 $html = '';
604
605 $class = ($coupon['status'] == true) ? 'notice-success' : 'notice-error';
606 $html .= '<div class="notice is-dismissible ' . $class .'">';
607 foreach($coupon['messages'] as $message){
608 $html .= '<p>' . $message . '</p>';
609 }
610 $html .= '</div>';
611
612 echo $html;
613 });
614
615
616 }
617
618 }
619
620
621
622
623 }else{
624 $_SESSION['messages'][] = 'Size of uploaded file is 0, processing terminated';
625 }
626
627 }else{
628 $_SESSION['messages'][] = 'Uploaded file doesnt appear to be a CSV file, processing terminated';
629 }
630
631 }
632
633
634 }
635
636
637
638
639
640
641 /**
642 * Registers a metabox for the w_coupon post type
643 */
644 public function register_coupon_meta_boxes($post){
645
646 add_meta_box(
647 'coupon-information',
648 __( 'Coupon Information' ),
649 array($this, 'display_coupon_meta_boxes'),
650 get_post_type($post),
651 'normal',
652 'default'
653 );
654
655 }
656
657 /**
658 * Registers a metabox for the w_transaction post type
659 */
660 public function register_transaction_meta_boxes($post){
661
662 add_meta_box(
663 'transaction-information',
664 __( 'Transaction Information' ),
665 array($this, 'display_transaction_meta_boxes'),
666 get_post_type($post),
667 'normal',
668 'default'
669 );
670
671 }
672
673
674 /**
675 * Rendering function to display the coupon metabox
676 * Displays all meta info for each of the coupons
677 */
678 public function display_coupon_meta_boxes($post){
679
680 // Add an nonce field so we can check for it later.
681 wp_nonce_field( 'coupon_information', 'coupon_information_nonce' );
682
683
684 $coupon_code = get_post_meta($post->ID, 'coupon_code', true);
685 $coupon_status = get_post_meta($post->ID, 'coupon_status', true);
686 $coupon_expiry_date = get_post_meta($post->ID, 'coupon_expiry_date', true);
687
688 $html = '';
689
690 $html .= '<p>Additional information about this coupon is displayed below</p>';
691
692 //coupon code
693 $html .= '<div class="field-wrap">';
694 $html .= '<label for="coupon_code">Code</label>';
695 $html .= '<small>Unique ID for the coupon, verified against the gateway</small>';
696 $html .= '<input type="text" name="coupon_code" id="coupon_code" value="' . $coupon_code . '" required/>';
697 $html .= '</div>';
698
699 //coupon status
700 $html .= '<div class="field-wrap">';
701 $html .= '<label for="coupon_status">Status</label>';
702 $html .= '<small>State of the coupon state</small>';
703 $html .= '<select name="coupon_status" id="coupon_status" required>';
704 $html .= '<option value="unused" ' . (($coupon_status == "unused") ? "selected" : "") . '>Unused</option>';
705 $html .= '<option value="used" ' . (($coupon_status == "used") ? "selected" : "") . '>Used</option>';
706 $html .= '</select>';
707 $html .= '</div>';
708
709 //coupon expiry (UNIX)
710 $expiry_date = new DateTime();
711 $expiry_date->setTimestamp(trim($coupon_expiry_date));
712
713 $html .= '<div class="field-wrap">';
714 $html .= '<label for="coupon_expiry_date">Expiry Date</label>';
715 $html .= '<small>Expiry date for this coupon, in the format of dd/mm/yyyy</small>';
716 $html .= '<small>(' . $expiry_date->format('d/m/Y') . ')</small>';
717 $html .= '<input type="text" name="coupon_expiry_date" id="coupon_expiry_date" value="' . $coupon_expiry_date . '" title="Enter a valid pattern mm/dd/yyyy" pattern="[01-31]{2}/{1}[01-12]{2}/{1}[1900-2100]{4}" required/>';
718 $html .= '</div>';
719
720
721 echo $html;
722
723 }
724
725 /**
726 * Render function to display the metabox for the transactioin post type
727 */
728 public function display_transaction_meta_boxes($post){
729
730 // Add an nonce field so we can check for it later.
731 wp_nonce_field( 'transacation_information', 'transacation_information_nonce' );
732
733 $html = '';
734
735 $html .= '<p>Additional information about this transaction is displayed below</p>';
736
737 $transaction_coupon_id = get_post_meta($post->ID, 'transaction_coupon_id', true);
738 $transaction_user_id = get_post_meta($post->ID, 'transaction_user_id', true);
739 $transaction_redemption_date = get_post_meta($post->ID, 'transaction_redemption_date', true);
740 $transaction_entity_id = get_post_meta($post->ID, 'transaction_entity_id', true);
741 $transaction_cost_centre = get_post_meta($post->ID, 'transaction_cost_centre', true);
742 $transaction_sub_account = get_post_meta($post->ID, 'transaction_sub_account', true);
743 $transaction_email_date = get_post_meta($post->ID, 'transaction_email_date', true);
744 $transaction_mocu_email = get_post_meta($post->ID, 'transaction_mocu_email', true);
745 $transaction_response_id = get_post_meta($post->ID,'transaction_response_id', true);
746
747
748 $html .= '<input type="hidden" name="transaction_id" id="transaction_id" value="' . $post->ID . '">';
749
750
751 //coupon code
752 $html .= '<div class="field-wrap">';
753 $html .= '<label for="transaction_coupon_id">Coupon</label>';
754 $html .= '<small>Select the coupon that this transaction is linked to</small>';
755
756 $coupon_args = array(
757 'post_type' => 'w_coupon',
758 'posts_per_page'=> -1,
759 'ordderby' => 'post_title',
760 'prder' => 'ASC',
761 'post_status' => 'publish'
762 );
763 $coupons = get_posts($coupon_args);
764 if($coupons){
765 $html .= '<select name="transaction_coupon_id" id="transaction_coupon_id">';
766 foreach($coupons as $coupon){
767
768 //determine if this coupon has already been 'used' (so the user can't select it)
769 $used = get_post_meta($coupon->ID, 'coupon_status', true);
770 if($used == 'used'){
771 $html .= '<option disabled value="' . $coupon->ID . '" ' . (($transaction_coupon_id == $coupon->ID) ? 'selected' : '' ) . '>' . $coupon->post_title . ' (Already been used)</option>';
772 }else{
773 $html .= '<option value="' . $coupon->ID . '" ' . (($transaction_coupon_id == $coupon->ID) ? 'selected' : '' ) . '>' . $coupon->post_title . '</option>';
774 }
775
776 }
777 $html .= '</select>';
778 }else{
779 $html .= '<small>No Coupons in system</small>';
780 }
781
782 $html .= '</div>';
783
784
785 //Author ID
786 $html .= '<div class="field-wrap">';
787 $html .= '<label for="transaction_user_id">Author</label>';
788 $html .= '<small>Select the user that this transaction is connected to</small>';
789
790 $users = get_users();
791
792 if($users){
793 $html .= '<select name="transaction_user_id" id="transaction_user_id">';
794 foreach($users as $user){
795 $html .= '<option value="' . $user->ID . '" ' . (($transaction_user_id == $user->ID) ? 'selected' : '' ) . '>' . $user->user_login . '</option>';
796 }
797 $html .= '</select>';
798 }else{
799 $html .= '<small>No users are currently in the system</small>';
800 }
801
802 $html .= '</div>';
803
804 //Transaction redemption date
805 $html .= '<div class="field-wrap">';
806 $html .= '<label for="transaction_redemption_date">Redemption Date</label>';
807 $html .= '<small>Redemeption date of the transaction</small>';
808 $html .= '<input type="text" name="transaction_redemption_date" id="transaction_redemption_date" value="' . $transaction_redemption_date . '"/>';
809 $html .= '</div>';
810
811 //transaction successful email date
812 $html .= '<div class="field-wrap">';
813 $html .= '<label for="transaction_email_date">Email Transaction Date</label>';
814 $html .= '<small>Date that the email was sent out for this transaction. This should match or be very similar to the transaction redemption date</small>';
815 $html .= '<input type="text" name="transaction_email_date" id="transaction_email_date" value="' . $transaction_email_date . '" placeholder="No date entered"/>';
816 $html .= '</div>';
817
818 //transaction email mocu address
819 $html .= '<div class="field-wrap">';
820 $html .= '<label for="transaction_mocu_email">Email Trasaction Address</label>';
821 $html .= '<small>The address that the transaction email was sent to. Users can update their address at any time so this field records where this email went</small>';
822 $html .= '<input type="email" name="transaction_mocu_email" id="transaction_mocu_email" value="' . $transaction_mocu_email . '" placeholder="No email address entered"/>';
823
824 $html .= '<div class="email-resend-wrapper">';
825 $html .= '<span class="button" id="resend_transaction_email">Resend transaction email</span>';
826 $html .= '<small>Sends out the thank you email to the email address entered above. <b>You must save this record first before doing this action</b></small>';
827 $html .= '</div>';
828 $html .= '</div>';
829
830 //entity id
831 $html .= '<div class="field-wrap">';
832 $html .= '<label for="transaction_entity_id">Entity ID</label>';
833 $html .= '<small>Entity code as returned by the successful transaction</small>';
834 $html .= '<input type="text" name="transaction_entity_id" id="transaction_entity_id" value="' . $transaction_entity_id . '"/>';
835 $html .= '</div>';
836
837 //cost centre
838 $html .= '<div class="field-wrap">';
839 $html .= '<label for="transaction_cost_centre">Cost Centre</label>';
840 $html .= '<small>Cost Centre as returned by the successful transaction</small>';
841 $html .= '<input type="text" name="transaction_cost_centre" id="transaction_cost_centre" value="' . $transaction_cost_centre . '"/>';
842 $html .= '</div>';
843
844 //sub account
845 $html .= '<div class="field-wrap">';
846 $html .= '<label for="transaction_sub_account">Sub Account</label>';
847 $html .= '<small>Sub Account as returned by the successful transaction</small>';
848 $html .= '<input type="text" name="transaction_sub_account" id="transaction_sub_account" value="' . $transaction_sub_account . '"/>';
849 $html .= '</div>';
850
851 //Transaction ID (from API)
852 $html .= '<div class="field-wrap">';
853 $html .= '<label for="transaction_response_id">Transaction ID API</label>';
854 $html .= '<small>The ID returned to us from the GetRedemption call to the API, this is their internal ID for our reference</small>';
855 $html .= '<input type="text" name="transaction_response_id" id="transaction_response_id" value="' . $transaction_response_id . '"/>';
856 $html .= '</div>';
857
858
859
860
861 echo $html;
862
863 }
864
865
866 /**
867 * Triggered on a single w_transaction creation or update
868 * Updates and assigns metadata about the transaction.
869 */
870 public function transaction_save_edit_admin_single($post_id){
871
872 //check nonce set
873 if(!isset($_POST['transacation_information_nonce'])){
874 return $post_id;
875 }
876
877
878 //verify nonce
879 if(!wp_verify_nonce($_POST['transacation_information_nonce'], 'transacation_information')){
880 return $post_id;
881 }
882
883 //not during autsave etc
884 if ( defined( 'DOING_AUTOSAVE' ) && DOING_AUTOSAVE ) {
885 return $post_id;
886 }
887
888 //collect meatdata
889 $transaction_coupon_id = isset($_POST['transaction_coupon_id']) ? sanitize_text_field($_POST['transaction_coupon_id']) : '';
890 $transaction_user_id = isset($_POST['transaction_user_id']) ? sanitize_text_field($_POST['transaction_user_id']) : '';
891 $transaction_redemption_date = isset($_POST['transaction_redemption_date']) ? sanitize_text_field($_POST['transaction_redemption_date']) : '';
892 $transaction_entity_id = isset($_POST['transaction_entity_id']) ? sanitize_text_field($_POST['transaction_entity_id']) : '';
893 $transaction_cost_centre = isset($_POST['transaction_cost_centre']) ? sanitize_text_field($_POST['transaction_cost_centre']) : '';
894 $transaction_sub_account = isset($_POST['transaction_sub_account']) ? sanitize_text_field($_POST['transaction_sub_account']) : '';
895 $transaction_email_date = isset($_POST['transaction_email_date']) ? sanitize_text_field($_POST['transaction_email_date']) : '';
896 $transaction_mocu_email = isset($_POST['transaction_mocu_email']) ? sanitize_text_field($_POST['transaction_mocu_email']) : '';
897 $transaction_response_id = isset($_POST['transaction_response_id']) ? sanitize_text_field($_POST['transaction_response_id']) : '';
898
899 update_post_meta($post_id, 'transaction_coupon_id', $transaction_coupon_id);
900 update_post_meta($post_id, 'transaction_user_id', $transaction_user_id);
901 update_post_meta($post_id, 'transaction_redemption_date', $transaction_redemption_date);
902 update_post_meta($post_id, 'transaction_entity_id', $transaction_entity_id);
903 update_post_meta($post_id, 'transaction_cost_centre', $transaction_cost_centre);
904 update_post_meta($post_id, 'transaction_sub_account', $transaction_sub_account);
905 update_post_meta($post_id, 'transaction_email_date', $transaction_email_date);
906 update_post_meta($post_id, 'transaction_mocu_email', $transaction_mocu_email);
907 update_post_meta($post_id, 'transaction_response_id', $transaction_response_id);
908 }
909
910
911 /**
912 * Triggered on single w_coupon creation or update
913 * Creates or updates the coupon and assigns applicable metadata for the object
914 */
915 public function coupon_save_edit_admin_single($post_id){
916
917 //check nonce set
918 if(!isset($_POST['coupon_information_nonce'])){
919 return $post_id;
920 }
921
922
923 //verify nonce
924 if(!wp_verify_nonce($_POST['coupon_information_nonce'], 'coupon_information')){
925 return $post_id;
926 }
927
928 //not during autsave etc
929 if ( defined( 'DOING_AUTOSAVE' ) && DOING_AUTOSAVE ) {
930 return $post_id;
931 }
932
933 ///Collect meta
934 $coupon_status = isset($_POST['coupon_status']) ? sanitize_text_field($_POST['coupon_status']) : '';
935 $coupon_code = isset($_POST['coupon_code']) ? sanitize_text_field($_POST['coupon_code']) : '';
936 $coupon_expiry_date = isset($_POST['coupon_expiry_date']) ? sanitize_text_field($_POST['coupon_expiry_date']) : '';
937
938
939 //update post meta
940 update_post_meta($post_id, 'coupon_status', $coupon_status);
941 update_post_meta($post_id, 'coupon_code', $coupon_code);
942 update_post_meta($post_id, 'coupon_expiry_date', $coupon_expiry_date);
943
944
945 }
946
947 /**
948 * Creates a new 'w_coupon' post type by passing in a unique coupon code, this code is compared against
949 * the list of 'w_coupon_type' terms to see if any of them match (to link them together)
950 * @param $coupon_data - associative array of imported data from the coupon (pulled from CSV import)
951 * @return Array of information about the process, 'status' and 'messages'
952 */
953 public function create_coupon_from_import($coupon_data = array()){
954
955
956 $response = array();
957 $response['status'] = false;
958
959 $coupon_data_sku_code = $coupon_data['coupon_type_sku'];
960 $coupon_code = $coupon_data['coupon_code'];
961 $coupon_expiry_date = $coupon_data['coupon_expiry_date'];
962
963 //get all the types of coupons we handle
964 $coupon_type_args = array(
965 'hide_empty' => false,
966 );
967 $coupon_types = get_terms('w_coupon_type', $coupon_type_args);
968
969 //only proceed if we have coupon types
970 if(!empty($coupon_types)){
971
972 //coupon code passed
973 if($coupon_code){
974
975 //check if code already exists as a coupon in system
976 $post_args = array(
977 'post_type' => 'w_coupon',
978 'post_status' => 'publish',
979 'posts_per_page'=> -1,
980 'meta_query' => array(
981 array(
982 'key' => 'coupon_code',
983 'value' => $coupon_code,
984 'compare' => '='
985 )
986 )
987 );
988
989 $posts = get_posts($post_args);
990
991 //Post already exists
992 if($posts){
993 foreach($posts as $post){
994 $response['messages'][] = 'A coupon already exists with the code: ' . $coupon_code . ' ,<a href="' . get_edit_post_link($post->ID) . '">Click here to view the coupon</a>';
995 }
996 }
997 //Doesn't exist, create
998 else{
999
1000 //See if any w_coupon_type exists with the supplied sku code
1001 $coupon_type_args = array(
1002 'taxonomy' => 'w_coupon_type',
1003 'hide_empty' => false,
1004 'number' => 1,
1005 'meta_key' => 'coupon_type_sku',
1006 'meta_value' => $coupon_data_sku_code
1007 );
1008 $coupon_types = get_terms($coupon_type_args);
1009
1010 //Found matching coupon type
1011 if($coupon_types){
1012 $coupon_type = $coupon_types[0];
1013 $coupon_type_id = $coupon_type->term_id;
1014
1015 //create coupon
1016 $post_args = array(
1017 'post_title' => 'Coupon: ' . $coupon_code,
1018 'post_type' => 'w_coupon',
1019 'post_status' => 'publish'
1020 );
1021
1022 //Create coupon or fail
1023 $coupon_id = wp_insert_post($post_args);
1024 if(is_int($coupon_id)){
1025 //successfully created post
1026 $coupon_created = true;
1027 $coupon = get_post($coupon_id);
1028
1029 //Assign this coupon to the correct coupon type taxonomy
1030 wp_set_object_terms($coupon_id, $coupon_type_id, 'w_coupon_type', false);
1031
1032
1033 //Add metadata now to associate coupon to code
1034 update_post_meta($coupon_id, 'coupon_code', $coupon_code);
1035 update_post_meta($coupon_id, 'coupon_status', 'unused');
1036
1037 //process d/m/Y format
1038 $coupon_expiry_date_formatted = DateTime::createFromFormat('d/m/Y', $coupon_expiry_date);
1039 $coupon_expiry_datetime = $coupon_expiry_date_formatted->getTimestamp();
1040 update_post_meta($coupon_id, 'coupon_expiry_date', $coupon_expiry_datetime);
1041
1042 $response['status'] = true;
1043 $response['messages'][] = 'Successfully created <a href="' . get_edit_post_link($coupon_id) . '"> Coupon ' . $coupon_code . '</a>';
1044
1045 }else{
1046 $response['messages'][] = 'Could not create post, error message returned: ' . $coupon->get_error_message();
1047 }
1048
1049 }else{
1050 //no matching coupon type found in system
1051 $response['messages'][] = 'Coupon SKU code "' . $coupon_code . '" didnt match the SKU code of any Coupon Type in the systm. Create the Coupon Type to continue';
1052 }
1053 }
1054 }else{
1055 $response['messages'][] = 'Coupon code empty, a code must be passed to create the record';
1056 }
1057 }else{
1058 $response['messages'][] = 'No Coupon types were defined, there needs to be at least 1 type defined to map coupons, please create these codes first';
1059 }
1060
1061 return $response;
1062
1063 }
1064
1065
1066 /**
1067 * Add new custom columns to the wordpress admin screen when viewing coupons
1068 * @see customize_coupon_admin_columns for how it's populated
1069 */
1070 public function add_coupon_admin_columns($columns){
1071
1072
1073 unset($columns['title']);
1074 unset($columns['taxonomy-w_coupon_type']);
1075 unset($columns['date']);
1076
1077 $columns['coupon_id'] = 'ID';
1078 $columns['title'] = 'Title';
1079 $columns['taxonomy-w_coupon_type'] = 'Coupon Type';
1080 $columns['coupon_status'] = 'Status';
1081 $columns['coupon_code'] = 'Code';
1082 $columns['coupon_expiry_date'] = 'Expiry Date';
1083
1084 return $columns;
1085 }
1086
1087 /**
1088 * Defines the output of custom columns displayed when viewing the listing of coupons
1089 */
1090 public function customize_coupon_admin_columns($column_name, $post_id){
1091
1092 if($column_name =='coupon_id'){
1093 $coupon_id = $post_id;
1094 echo $post_id;
1095 }else if($column_name == 'coupon_status'){
1096 $coupon_status = get_post_meta($post_id, 'coupon_status', true);
1097 echo $coupon_status;
1098 }else if($column_name == 'coupon_code'){
1099 $coupon_code = get_post_meta($post_id, 'coupon_code', true);
1100 echo $coupon_code;
1101 }else if($column_name == 'coupon_expiry_date'){
1102 $coupon_expiry_date = get_post_meta($post_id, 'coupon_expiry_date', true);
1103 if(!empty($coupon_expiry_date)){
1104 $expiry_date = new DateTime();
1105 $expiry_date->setTimestamp(trim($coupon_expiry_date));
1106 echo $coupon_expiry_date . '<br/>(' . $expiry_date->format('d/m/Y') . ')';
1107 }
1108 }
1109
1110
1111 }
1112
1113 /**
1114 * Makes our custom w_coupon custom columns sortable in the admin
1115 * @see sortable_coupon_admin_columns_query
1116 */
1117 public function sortable_coupon_admin_columns($column){
1118
1119
1120 $column['coupon_id'] = 'coupon_id_sort';
1121 $column['coupon_status'] = 'coupon_status_sort';
1122 $column['coupon_code'] = 'coupon_code_sort';
1123 $column['coupon_expiry_date'] = 'coupon_expiry_date_sort';
1124
1125 return $column;
1126 }
1127
1128 /**
1129 * Hooks into the 'pre_get_posts' filter to look for our custom sort filters used on the coupon admin, our intention is to
1130 * tell wordpress how we intent to sort these columns (since they are based on meta values)
1131 * @see sortable_coupon_admin_columns
1132 */
1133 public function sortable_coupon_admin_columns_query($query){
1134
1135 if(!is_admin()){
1136 return;
1137 }
1138
1139 $orderby = $query->get('orderby');
1140
1141 if($orderby == 'coupon_id_sort'){
1142 $query->set('orderby', 'post_id');
1143 }
1144 else if($orderby == 'coupon_status_sort'){
1145 $query->set('meta_key','coupon_status');
1146 $query->set('orderby', 'meta_value');
1147 }
1148 else if($orderby == 'coupon_code_sort'){
1149 $query->set('meta_key','coupon_code');
1150 $query->set('orderby', 'meta_value');
1151 }
1152 else if($orderby == 'coupon_expiry_date_sort'){
1153 $query->set('meta_key', 'coupon_expiry_date');
1154 $query->set('orderby', 'meta_value_num');
1155 }
1156
1157 }
1158
1159 /**
1160 * Add new filters to let users filter the coupons admin page
1161 * - Filter by coupon status
1162 * - Filter by coupon value
1163 * @see restrict_coupon_admin_listing_filter for filtering
1164 */
1165 public function customize_coupon_admin_filters(){
1166
1167 $current_screeen = get_current_screen();
1168
1169 //trigger only on applicable pages
1170 if($current_screeen->post_type == 'w_coupon'){
1171 if($current_screeen->base = 'edit'){
1172
1173 $html = '';
1174
1175 //Coupon status filter
1176 $coupon_status_filter = isset($_GET['coupon_status_filter']) ? $_GET['coupon_status_filter'] : '';
1177 $html .= '<select name="coupon_status_filter">';
1178 $html .= '<option value="default" ' . (($coupon_status_filter == "default") ? "selected" : "") . '>All Statuses</option>';
1179 $html .= '<option value="unused" ' . (($coupon_status_filter == "unused") ? "selected" : "") . '>Unused</option>';
1180 $html .= '<option value="used" ' . (($coupon_status_filter == "used") ? "selected" : "") . '>Used</option>';
1181 $html .= '</select>';
1182
1183
1184 //get all the types of coupons we handle
1185 $coupon_type_filter = isset($_GET['coupon_type_filter']) ? $_GET['coupon_type_filter'] : '';
1186 $coupon_type_args = array(
1187 'hide_empty' => false,
1188 );
1189 $coupon_types = get_terms('w_coupon_type', $coupon_type_args);
1190
1191 //coupon type (taxonomy) filter
1192 $html .= '<select name="coupon_type_filter">';
1193 $html .= '<option value="default" ' . (($coupon_type_filter == "default") ? "selected" : "") . '>All Coupon Types</option>';
1194 if(!empty($coupon_types)){
1195 foreach($coupon_types as $coupon_type){
1196 $coupon_type_id = $coupon_type->term_id;
1197 $coupon_name = $coupon_type->name;
1198 $html .= '<option value="' . $coupon_type_id . '" ' . (($coupon_type_filter == $coupon_type_id) ? "selected" : "") . '>' . $coupon_name . '</option>';
1199 }
1200 }
1201 $html .= '</select>';
1202
1203 echo $html;
1204 }
1205 }
1206 }
1207
1208 /**
1209 * Restricts the currently viewable coupons to only coupons that match our filters,
1210 * hooks into pre_get_posts to filter our posts we dont want
1211 * @see customize_coupon_admin_filters
1212 */
1213 public function restrict_coupon_admin_listing_filter($query){
1214
1215 if(is_admin()){
1216
1217 $current_screeen = get_current_screen();
1218
1219 if($current_screeen){
1220
1221 //trigger only on applicable pages
1222 if($current_screeen->post_type == 'w_coupon'){
1223 if($current_screeen->base = 'edit'){
1224
1225 //Filter by status
1226 if(isset($_GET['coupon_status_filter'])){
1227 $query_value = $_GET['coupon_status_filter'];
1228 if($query_value != 'default'){
1229 $query->set('meta_key','coupon_status');
1230 $query->set('meta_value', $query_value);
1231 }
1232 }
1233
1234 //Filter by w_coupon_type term
1235 if(isset($_GET['coupon_type_filter'])){
1236 $query_value = $_GET['coupon_type_filter'];
1237 if($query_value != 'default'){
1238 $tax_query = array(
1239 array(
1240 'taxonomy' => 'w_coupon_type',
1241 'field' => 'term_id',
1242 'terms' => (int) $query_value
1243 )
1244 );
1245 $query->set('tax_query', $tax_query);
1246 }
1247 }
1248
1249 }
1250 }
1251
1252 }
1253
1254 }
1255
1256 }
1257
1258
1259 /**
1260 * Add new custom columns to the wordpress admin screen when viewing transactions
1261 * @see customize_transaction_admin_columns for how it's populated
1262 */
1263 public function add_transaction_admin_columns($columns){
1264
1265 unset($columns['title']);
1266 unset($columns['date']);
1267
1268 $columns['transaction_id'] = 'ID';
1269 $columns['title'] = 'Title';
1270 $columns['transaction_user_id'] = 'User';
1271 $columns['transaction_coupon_id'] = 'Coupon Info';
1272 $columns['transaction_redemption_date'] = 'Redemeption Date';
1273 $columns['transaction_email_date'] = 'Email Date';
1274 $columns['transaction_mocu_email'] = 'Email Address <br/><small>(Mocu Address)</small>';
1275 $columns['transaction_response_id'] = 'Response ID <br/><small>(From the API)</small>';
1276
1277 return $columns;
1278 }
1279
1280 /**
1281 * Populates custom columns added to the w_transaction post type
1282 * @see add_transaction_admin_columns
1283 */
1284 public function customize_transaction_admin_columns($column_name, $post_id){
1285
1286 if($column_name == 'transaction_id'){
1287 echo $post_id;
1288 }
1289 //user information
1290 else if($column_name == 'transaction_user_id'){
1291
1292 $transaction_user_id = get_post_meta($post_id, 'transaction_user_id', true);
1293 $user = get_user_by('ID', $transaction_user_id);
1294
1295 //display user information
1296 if($user instanceof WP_User){
1297 $user_information = get_userdata($transaction_user_id);
1298 $user_profile_link = get_edit_user_link($transaction_user_id);
1299 echo '<a href="' . $user_profile_link . '">';
1300 echo 'User ID: ' . $transaction_user_id . ' </br>';
1301 echo '(' . $user_information->user_login . ')';
1302 echo '</a>';
1303 }else{
1304 echo 'User ID: ' . $transaction_user_id . ' Not Found (most likely has been deleted)';
1305 }
1306 }
1307 //Coupon information
1308 else if($column_name == 'transaction_coupon_id'){
1309
1310 $transaction_coupon_id = get_post_meta($post_id, 'transaction_coupon_id', true);
1311
1312 $coupon = get_post($transaction_coupon_id);
1313 if($coupon instanceof WP_Post){
1314
1315 //get information about the type of coupon used
1316 $coupon_value = '';
1317 $coupon_types = wp_get_object_terms($transaction_coupon_id, 'w_coupon_type');
1318 if($coupon_types){
1319 $coupon_type = $coupon_types[0];
1320 $coupon_type_value = get_term_meta($coupon_type->term_id, 'coupon_type_value', true );
1321 $coupon_type_sku = get_term_meta($coupon_type->term_id, 'coupon_type_sku', true );
1322 }
1323
1324 $coupon_link = get_edit_post_link($transaction_coupon_id);
1325
1326 echo '<a href="' . $coupon_link . '">';
1327 echo 'Coupon ID: ' . $transaction_coupon_id . '</br>';
1328 if(isset($coupon_type_value)){
1329 echo '($' . $coupon_type_value . ' Coupon)';
1330 }
1331 echo '</a>';
1332 }else{
1333 echo 'Coupon ID: ' . $transaction_coupon_id . ' Not Found (most likely has been deleted)';
1334 }
1335
1336
1337 }else if($column_name == 'transaction_redemption_date'){
1338
1339 $transaction_redemption_date = get_post_meta($post_id, 'transaction_redemption_date', true);
1340 echo $transaction_redemption_date;
1341 }else if($column_name == 'transaction_response_id'){
1342 $transaction_response_id = get_post_meta($post_id, 'transaction_response_id', true);
1343 echo $transaction_response_id;
1344 }else if($column_name == 'transaction_email_date'){
1345 $transaction_email_date = get_post_meta($post_id, 'transaction_email_date', true);
1346 if($transaction_email_date){
1347 echo $transaction_email_date;
1348 }else{
1349 echo '-';
1350 }
1351 }else if ($column_name == 'transaction_mocu_email'){
1352 $transaction_mocu_email = get_post_meta($post_id, 'transaction_mocu_email', true);
1353 if($transaction_mocu_email){
1354 echo $transaction_mocu_email;
1355 }else{
1356 echo '-';
1357 }
1358 }
1359 }
1360
1361
1362 /**
1363 * Makes our custom w_transaction custom columns sortable in the admin
1364 * @see sortable_transaction_admin_columns_query
1365 */
1366 public function sortable_transaction_admin_columns($column){
1367
1368
1369 $column['transaction_id'] = 'transaction_id_sort';
1370 $column['transaction_user_id'] = 'transaction_user_id_sort';
1371 $column['transaction_coupon_id'] = 'transaction_coupon_sort';
1372 $column['transaction_redemption_date'] = 'transaction_redemption_date_sort';
1373 $column['transaction_email_date'] = 'transaction_email_date_sort';
1374 $column['transaction_mocu_email'] = 'transaction_mocu_email_sort';
1375 $column['transaction_response_id'] = 'transaction_response_id_sort';
1376
1377 return $column;
1378 }
1379
1380 /**
1381 * Hooks into the 'pre_get_posts' filter to look for our custom sort filters used on the transaction admin, our intention is to
1382 * tell wordpress how we intent to sort these columns (since they are based on meta values)
1383 * @see sortable_coupon_admin_columns
1384 */
1385 public function sortable_transaction_admin_columns_query($query){
1386
1387 if(!is_admin()){
1388 return;
1389 }
1390
1391 $orderby = $query->get('orderby');
1392
1393 //sort by transaction id
1394 if($orderby == 'transaction_id'){
1395 $query->set('orderby', 'post_id');
1396 }
1397 //sort by user
1398 else if($orderby == 'transaction_user_id_sort'){
1399 $query->set('meta_key','transaction_user_id');
1400 $query->set('orderby', 'meta_value_num');
1401 }
1402 //sort by coupon id
1403 else if($orderby == 'transaction_coupon_sort'){
1404 $query->set('meta_key','transaction_coupon_id');
1405 $query->set('orderby', 'meta_value_num');
1406 }
1407 //redemption date
1408 else if($orderby == 'transaction_redemption_date_sort'){
1409 $query->set('meta_key','transaction_redemption_date');
1410 $query->set('orderby', 'meta_value_num');
1411 }
1412 //email date sent
1413 else if($orderby == 'transaction_email_date_sort'){
1414 $query->set('meta_key','transaction_email_date');
1415 $query->set('orderby', 'meta_value_num');
1416 }
1417 //mocu email address
1418 else if($orderby == 'transaction_mocu_email_sort'){
1419 $query->set('meta_key','transaction_mocu_email');
1420 $query->set('orderby', 'meta_value');
1421 }
1422 else if($orderby == 'transaction_response_id_sort'){
1423 $query->set('meta_key','transaction_response_id');
1424 $query->set('orderby', 'meta_value_num');
1425 }
1426
1427
1428 }
1429
1430 /**
1431 * Add new filters to let users filter the transactions admin page
1432 * - Filter by user
1433 * @see restrict_transaction_admin_listing_filter for filtering login
1434 */
1435 public function customize_transaction_admin_filters(){
1436
1437 $current_screeen = get_current_screen();
1438
1439 //trigger only on applicable pages
1440 if($current_screeen->post_type == 'w_transaction'){
1441 if($current_screeen->base = 'edit'){
1442
1443 $html = '';
1444
1445 //All transactions
1446 $transaction_args = array(
1447 'post_type' => 'w_transaction',
1448 'post_status' => 'publish',
1449 'posts_per_page'=> -1,
1450 );
1451 $trasactions = get_posts($transaction_args);
1452
1453 //Build a list of users who have purchased
1454 $users_info = array();
1455 foreach($trasactions as $transaction){
1456 $transaction_user_id = get_post_meta($transaction->ID, 'transaction_user_id', true);
1457 $user = get_user_by('ID', $transaction_user_id);
1458 $username = ($user instanceof WP_User) ? get_userdata($transaction_user_id)->user_login : 'User not found';
1459 //push onto array
1460 $users_info[] = array(
1461 'user_id' => $transaction_user_id,
1462 'username' => $username
1463 );
1464 }
1465
1466
1467 //transaction user id filter
1468 $transaction_user_id_filter = isset($_GET['transaction_user_id_filter']) ? $_GET['transaction_user_id_filter'] : '';
1469
1470 $html .= '<select name="transaction_user_id_filter">';
1471
1472 if($transaction_user_id_filter == "default" || $transaction_user_id_filter == ''){
1473 $html .= '<option value="default" selected>All Transaction Users</option>';
1474 }else{
1475 $html .= '<option value="default">All Transaction Users</option>';
1476 }
1477 if(!empty($users_info)){
1478 foreach($users_info as $user_info){
1479 if($transaction_user_id_filter == $user_info['user_id']){
1480 $html .= '<option value="' . $user_info['user_id'] . '" selected>#' . $user_info['user_id'] . ' - ' . $user_info['username'] . '</option>';
1481 }else{
1482 $html .= '<option value="' . $user_info['user_id'] . '">#' . $user_info['user_id'] . ' - ' . $user_info['username'] . '</option>';
1483 }
1484 }
1485 }
1486 $html .= '</select>';
1487
1488
1489 //Coupon ID
1490 $transaction_coupon_id_filter = isset($_GET['transaction_coupon_id_filter']) ? $_GET['transaction_coupon_id_filter'] : '';
1491 $html .= '<select name="transaction_coupon_id_filter">';
1492
1493 if($transaction_coupon_id_filter == "default" || $transaction_coupon_id_filter == ''){
1494 $html .= '<option value="default" selected>All Coupon IDs</option>';
1495 }else{
1496 $html .= '<option value="default">All Coupon IDs</option>';
1497 }
1498
1499 foreach($trasactions as $transaction){
1500 $transaction_coupon_id = get_post_meta($transaction->ID, 'transaction_coupon_id', true);
1501 if($transaction_coupon_id_filter == $transaction_coupon_id){
1502 $html .= '<option value="' . $transaction_coupon_id . '" selected>#' . $transaction_coupon_id . '</option>';
1503 }else{
1504 $html .= '<option value="' . $transaction_coupon_id . '">#' . $transaction_coupon_id . '</option>';
1505 }
1506
1507 }
1508 $html .= '</select>';
1509
1510
1511
1512
1513 echo $html;
1514 }
1515 }
1516 }
1517
1518 /**
1519 * Restricts the currently viewable transactions to only transactions that match our filters,
1520 * hooks into pre_get_posts to filter our posts we dont want
1521 * @see customize_transaction_admin_filters
1522 */
1523 public function restrict_transaction_admin_listing_filter($query){
1524
1525 if(is_admin()){
1526
1527 $current_screeen = get_current_screen();
1528
1529 if($current_screeen){
1530
1531 //trigger only on applicable pages
1532 if($current_screeen->post_type == 'w_transaction'){
1533 if($current_screeen->base = 'edit'){
1534
1535 //Filter by user
1536 if(isset($_GET['transaction_user_id_filter'])){
1537 $query_value = $_GET['transaction_user_id_filter'];
1538 if($query_value != 'default'){
1539 $query->set('meta_key','transaction_user_id');
1540 $query->set('meta_value', $query_value);
1541 }
1542 }
1543
1544
1545
1546 //Filter by w_coupon_type term
1547 if(isset($_GET['transaction_coupon_id_filter'])){
1548 $query_value = $_GET['transaction_coupon_id_filter'];
1549
1550 if($query_value != 'default'){
1551
1552 $query->set('meta_key','transaction_coupon_id');
1553 $query->set('meta_value', $query_value);
1554 }
1555 }
1556
1557
1558
1559 }
1560 }
1561
1562 }
1563
1564 }
1565
1566 }
1567
1568
1569
1570
1571 /**
1572 * Provides a link directly to the coupon upload admin menu page
1573 */
1574 public function get_coupon_upload_link_button(){
1575 $url = menu_page_url('coupon-settings', false);
1576 return '<a class="button" href="' . $url . '" title="Upload New Coupons">Upload Coupons</a>';
1577 }
1578
1579 //singleton instance
1580 public static function getInstance(){
1581 if(is_null(self::$instance)){
1582 self::$instance = new self();
1583 }
1584 return self::$instance;
1585 }
1586
1587
1588 /**
1589 * Connects to our API to pull in information about the current user from Active Directory
1590 * (exposed to us via an endpoint), this information is used for the transaction process.
1591 * @return $balance - current balance of user (or false on error)'
1592 */
1593 public function get_user_balance_info_from_api(){
1594
1595 $balance = 0;
1596
1597 //collect username from user to be passed to API
1598 $current_user = wp_get_current_user();
1599 if($current_user->ID > 0){
1600
1601 //arguments about the user
1602 $arguments = array(
1603 'user' => $current_user->user_login
1604 );
1605
1606 //method to use
1607 $method = '/User/GetUserBalance';
1608
1609 //get the respons for the user balance
1610 $response = json_decode($this->do_curl_request($method, $arguments, 'get'));
1611
1612 //if we had a successful curl call get points
1613 if($response->curl_status == 'success'){
1614
1615 //check if we successfully pulled balance info from user
1616 if($response->curl_data->Success == true){
1617 $balance = $response->curl_data->Data->Points;
1618 }
1619
1620 }
1621
1622 }
1623
1624 return $balance;
1625
1626 }
1627
1628 /**
1629 * Gets the total number of points that have been redeemed in the financial year for the user
1630 * Only X number of points can be spent on the system and this provides a tally
1631 */
1632 public function get_user_yearly_transaction_total(){
1633
1634 $balance = 0;
1635
1636 //get a list of all transactions from the user
1637 $user_transactions = $this->get_transaction_records_for_user();
1638 if($user_transactions){
1639
1640 $yearly_transactions = array();
1641
1642 //$fy_time_period_end = '';
1643
1644 $current_date = new DateTime();
1645 $current_date_month = (int) $current_date->format('m');
1646 $current_date_year = (int) $current_date->format('Y');
1647
1648 //Calculate financial calendar (1/4/20xx - 31/3/20xx) - As requested
1649
1650 //before april
1651 if($current_date_month < 4){
1652 $fy_date_period_start = dateTime::createFromFormat('d/m/Y', '31/03/' . ($current_date_year - 1));
1653 $fy_date_period_end = dateTime::createFromFormat('d/m/Y', '01/04/' . ($current_date_year));
1654 }
1655 //after march, calculate years
1656 else{
1657 $fy_date_period_start = dateTime::createFromFormat('d/m/Y', '01/04/' . ($current_date_year));
1658 $fy_date_period_end = dateTime::createFromFormat('d/m/Y', '31/03/' . ($current_date_year + 1));
1659 }
1660
1661 foreach($user_transactions as $transaction){
1662
1663 //get transactions date
1664 $transaction_redemption_date = get_post_meta($transaction->ID, 'transaction_redemption_date', true);
1665 if(!empty($transaction_redemption_date)){
1666 //check to see if this transaction belongs to this financial year
1667 $transaction_date = DateTime::createFromFormat('d/m/Y H:i:s A', $transaction_redemption_date);
1668
1669 //var_dump($transaction_date);
1670
1671 if(($transaction_date->getTimestamp() > $fy_date_period_start->getTimestamp()) && ($transaction_date->getTimestamp() < $fy_date_period_end->getTimestamp())){
1672 $yearly_transactions[] = $transaction;
1673 }
1674 }
1675 }
1676
1677 //if we have applicable transactions, count them
1678 if(!empty($yearly_transactions)){
1679 foreach($yearly_transactions as $transaction){
1680 $transaction_coupon_id = get_post_meta($transaction->ID, 'transaction_coupon_id', true);
1681 //get the coupon and find it's value
1682 $coupon = get_post($transaction_coupon_id);
1683 $coupon_types = wp_get_object_terms($coupon->ID, 'w_coupon_type');
1684 if($coupon_types){
1685 $coupon_type = $coupon_types[0];
1686 $coupon_type_value = get_term_meta($coupon_type->term_id, 'coupon_type_value', true );
1687 $coupon_type_sku = get_term_meta($coupon_type->term_id, 'coupon_type_sku', true );
1688
1689 //add this to our balance total
1690 $balance += (int) $coupon_type_value;
1691 }
1692
1693 }
1694 }
1695
1696 }
1697
1698 return $balance;
1699
1700 }
1701
1702 /**
1703 * Displays the user
1704 */
1705 public function display_user_yearly_transaction_total(){
1706
1707 $user = wp_get_current_user();
1708 $balance = $this->get_user_yearly_transaction_total();
1709
1710 $html = '';
1711
1712 $html .= '<div class="u-text--center">';
1713 $html .= '<div class="point-block">';
1714 $html .= '<span class="point-block__score">' . $balance . '</span> have been spent this FBT year (1st April - 31st March)';
1715 $html .= '</div>';
1716 $html .= '<p>*Please note, you can only redeem 1300 points on MoCU per FBT year</p>';
1717 $html .= '</div>';
1718
1719 //has transation
1720 $html .= '<div class="u-text--center">';
1721 $html .= $this->get_transaction_history_for_user($user);
1722 $html .= '</div>';
1723
1724
1725 echo $html;
1726
1727 }
1728
1729
1730
1731 /**
1732 * Connects to the API in order to do our curl call (to purchase the ticket from the API)
1733 * @param - $coupon_id - Coupon ID
1734 * @return - $response - response object with 'status' and 'messages' about process
1735 */
1736 public function post_coupon_purchase_to_api($coupon_id){
1737
1738
1739 $response = array();
1740 $response['status'] = 'error';
1741
1742 $coupon = get_post($coupon_id);
1743
1744 $todays_date = new DateTime();
1745 $todays_date = $todays_date->format('Y/m/d H:i:s A');
1746
1747
1748 //Before we send our response, create our transaction object, we sent the ID of this to the API
1749 $transaction_post_args = array(
1750 'post_title' => 'Transaction: ' . $todays_date,
1751 'post_type' => 'w_transaction',
1752 'post_status' => 'publish'
1753 );
1754 $transaction_id = wp_insert_post($transaction_post_args);
1755
1756 //collect user information
1757 $current_user = wp_get_current_user();
1758 if($current_user->ID > 0){
1759 $username = $current_user->user_login;
1760 }else{
1761 $response['messages'][] = 'You are currently not logged in';
1762 return $response;
1763 }
1764
1765 //get values about coupon (from coupon type and metadata)
1766 $coupon_type_value = '';
1767 $coupon_type_sku = '';
1768
1769
1770 //get all types assigned to the coupon, we only want one
1771 $coupon_types = wp_get_post_terms($coupon->ID, 'w_coupon_type');
1772 if($coupon_types){
1773 $coupon_type = $coupon_types[0];
1774 $coupon_type_value = get_term_meta($coupon_type->term_id, 'coupon_type_value', true);
1775 $coupon_type_sku = get_term_meta($coupon_type->term_id, 'coupon_type_sku', true);
1776 }
1777
1778 //arguments passed to the API
1779 $arguments = array(
1780 'RedemptionDate' => $todays_date,
1781 'TransactionID' => $transaction_id,
1782 'Username' => $username,
1783 'Redemptions' => array(
1784 array(
1785 'Quantity' => 1,
1786 'SkuNumber' => $coupon_type_sku,
1787 'Points' => $coupon_type_value
1788 )
1789 )
1790 );
1791
1792 //log the request we are sending to the API
1793 $argument_message = 'User #' . $current_user->ID . ' Raw request we are sending to the submission API: ' . var_export($arguments, true);
1794 $this->log_report_message($argument_message);
1795
1796 //method to use
1797 $method = '/User/SubmitRedemption';
1798
1799 //get the respons for the user balance
1800 $submit_redemption = json_decode($this->do_curl_request($method, $arguments, 'post'));
1801
1802 //if we had a successful curl call
1803 if($submit_redemption->curl_status == 'success'){
1804
1805 //get the data and check what the API has sent back
1806 $curl_data = $submit_redemption->curl_data;
1807
1808 //log the curl data response as a message
1809 $response_message = 'User #' . $current_user->ID . ' Raw Response from the submission API: ' . var_export($curl_data, true);
1810 $this->log_report_message($response_message);
1811
1812 //succesfully completed transaction
1813 if($curl_data->Success == true){
1814
1815 //get set of data
1816 $data = $curl_data->Data;
1817
1818 $response['status'] = 'success';
1819 $response['messages'][] = 'Successfully posted data to SubmitRedemption API';
1820
1821 //pass back our applicable data
1822 $response['data'] = array(
1823 'transaction_id' => $transaction_id,
1824 'coupon_id' => $coupon->ID,
1825 'user_id' => $current_user->ID,
1826 'api_info' => array(
1827 'entity' => $data->Entity,
1828 'cost_centre' => $data->CostCentre,
1829 'sub_account' => $data->SubAccount,
1830 'transaction_reciepts' => $data->TransactionReceipts[0] //for now only passing a single value from array
1831 )
1832 );
1833
1834 //success
1835 $response['status'] = 'success';
1836 $response['messages'][] = 'User ' . $current_user->ID . ' has successfully pulled posted the transactions to the API and retuned data';
1837 }
1838 //Failed transaction
1839 else{
1840 //Delete the transaction we made previously, there's an error and it's not needed
1841 wp_delete_post($transaction_id);
1842 $response['messages'][] = 'Failed to get a successful response from the SubmitRedemption API';
1843 }
1844
1845 }else{
1846 //CURL did not return a successful call
1847 $response['messages'][] = 'CURL did not return a successful response from PHP';
1848 }
1849
1850 //log messages
1851 $this->log_report_message($response['messages']);
1852
1853
1854 return $response;
1855
1856 }
1857
1858
1859
1860
1861
1862
1863 /**
1864 * Called to update the empty transaction post object with metadata, used after a successfull call to the API and return of data
1865 * @param $transaction_id - transaction ID
1866 * @param $coupon_id - Coupon id the user has purchased
1867 * @param $user - user id of purchaser
1868 * @param $api_info - Data passed back to us from the SubmitRedemption API
1869 */
1870 public function update_transaction_for_purchase($transaction_id, $coupon_id, $user_id, $api_info){
1871
1872 $response = array();
1873
1874 $transaction = get_post($transaction_id);
1875 if($transaction instanceof WP_Post){
1876
1877 $transaction_date = new DateTime();
1878 $transaction_date = $transaction_date->format('d/m/Y H:i:s A');
1879
1880 //get the user
1881 $user = get_user_by('ID', $user_id);
1882
1883 //get the coupon
1884 $coupon = get_post($coupon_id);
1885
1886 //add metadata to post
1887 update_post_meta($transaction_id, 'transaction_redemption_date', $transaction_date);
1888 update_post_meta($transaction_id, 'transaction_user_id', $user->ID);
1889 update_post_meta($transaction_id, 'transaction_coupon_id', $coupon->ID);
1890 update_post_meta($transaction_id, 'transaction_entity_id', $api_info['entity']); //entity ID
1891 update_post_meta($transaction_id, 'transaction_cost_centre', $api_info['cost_centre']); //cost centre
1892 update_post_meta($transaction_id, 'transaction_sub_account', $api_info['sub_account']); //sub account
1893 update_post_meta($transaction_id, 'transaction_response_id', $api_info['transaction_reciepts']); //unique ID returned back to us (single id)
1894
1895 $response['status'] = 'success';
1896 $response['messages'][] = 'User ' . $user->ID . ' has successfull updated transaction ID ' . $transaction_id . ' with metadata';
1897
1898 }else{
1899 $response['status'] = 'error';
1900 $response['messages'][] = 'Transaction record couldnt be loaded, it doesnt exist';
1901 }
1902
1903 return $response;
1904 }
1905
1906 /**
1907 * Gets the HTML output for a transaction table to show the user their transactions
1908 * @param - $user - user object
1909 */
1910 public function get_transaction_history_for_user($user){
1911
1912 $html = '';
1913
1914 $user_id = $user->ID;
1915
1916 $transaction_args = array(
1917 'post_type' => 'w_transaction',
1918 'posts_per_page'=> -1,
1919 'post_status' => 'publish',
1920 'orderby' => 'post_id',
1921 'order' => 'DESC',
1922 'meta_query' => array(
1923 array(
1924 'key' => 'transaction_user_id',
1925 'value' => $user_id
1926 )
1927 )
1928 );
1929 //Display transactions
1930 $transactions = get_posts($transaction_args);
1931 if($transactions){
1932 $html .= '<table class="transaction-table" border="1">';
1933 //Headers
1934 $html .= '<tr>';
1935 $html .= '<th>ID</th>';
1936 $html .= '<th>Redemption Date</th>';
1937 $html .= '<th>Coupon Code</th>';
1938 $html .= '<th>Value</th>';
1939 $html .= '</tr>';
1940 foreach($transactions as $transaction){
1941 $transaction_id = $transaction->ID;
1942 $transaction_redemption_date = get_post_meta($transaction->ID, 'transaction_redemption_date', true);
1943 $transaction_coupon_id = get_post_meta($transaction->ID, 'transaction_coupon_id', true);
1944 $transaction_coupon = get_post($transaction_coupon_id);
1945 $transaction_coupon_code = get_post_meta($transaction_coupon_id, 'coupon_code', true);
1946 $coupon_types = wp_get_object_terms($transaction_coupon->ID, 'w_coupon_type');
1947 if($coupon_types){
1948 $coupon_type = $coupon_types[0];
1949 $coupon_type_value = get_term_meta($coupon_type->term_id, 'coupon_type_value', true );
1950 $coupon_type_sku = get_term_meta($coupon_type->term_id, 'coupon_type_sku', true );
1951 }
1952
1953 //Output
1954 $html .= '<tr>';
1955 $html .= '<td>' . $transaction_id . '</td>';
1956 $html .= '<td>' . $transaction_redemption_date . '</td>';
1957 $html .= '<td>' . $transaction_coupon_code . '</td>';
1958 $html .= '<td>' . '$' . $coupon_type_value . '</td>';
1959 $html .= '</tr>';
1960 }
1961 $html .= '</table>';
1962
1963 }else{
1964 $html .= '<p>There are no current transactions to display</p>';
1965 }
1966
1967 return $html;
1968
1969 }
1970
1971 /**
1972 * Displays a table of transactions for the user. The user will only see their transactions
1973 */
1974 public static function display_transaction_history_for_user(){
1975
1976 $instance = self::getInstance();
1977
1978 $user = wp_get_current_user();
1979
1980 $html = '';
1981 $html .= $instance->get_transaction_history_for_user($user);
1982
1983 echo $html;
1984 }
1985
1986
1987 /**
1988 * Gets a listong of transaction records for the currently logged in user
1989 * @return $transactions
1990 */
1991 public function get_transaction_records_for_user(){
1992
1993 $transactions = array();
1994 $user = wp_get_current_user();
1995
1996 if($user->ID > 0){
1997
1998 $post_args = array(
1999 'post_type' => 'w_transaction',
2000 'post_status' => 'publish',
2001 'orderby' => 'post_id',
2002 'order' => 'DESC',
2003 'posts_per_page'=> -1,
2004 'meta_query' => array(
2005 array(
2006 'key' => 'transaction_user_id',
2007 'value' => $user->ID
2008 )
2009 )
2010 );
2011 $posts = get_posts($post_args);
2012 if(!empty($posts)){
2013 $transactions = $posts;
2014 }
2015 }
2016
2017 return $transactions;
2018
2019 }
2020
2021 /**
2022 * Ajax function used from admin back-end to resend out a user their transaction receipt
2023 * Values passed via Ajax POST request
2024 */
2025 public function resend_transaction_email(){
2026 $response = array();
2027 $response['status'] = 'error';
2028 $response['messages'] = array();
2029
2030 $transaction_id = isset($_POST['transaction_id']) ? (int) $_POST['transaction_id'] : '';
2031 if($transaction_id){
2032
2033 $transaction = get_post($transaction_id);
2034 if($transaction){
2035
2036 $transaction_mocu_email = get_post_meta($transaction_id, 'transaction_mocu_email', true);
2037 //send out email again to user
2038 $user_transaction_email_response = $this->send_email_to_user($transaction_id);
2039
2040 if($user_transaction_email_response['status'] == 'success'){
2041 $response['status'] = 'success';
2042 $response['messages'][] = 'Successfully resent out transaction #' . $transaction_id . ' to ' . $transaction_mocu_email;
2043 }else{
2044 //add collective messages to pass back to js
2045 $response['messages'] = $user_transaction_email_response['messages'] + $response['messages'];
2046 }
2047 }else{
2048 $response['messages'][] = 'Couldnt get transaction #' . $transaction_id . ' from the DB, it doesnt exist';
2049 }
2050 }else{
2051 $response['messages'][] = 'No transaction ID set, cant resend email';
2052 }
2053
2054 //log messages
2055 $this->log_report_message($response['messages']);
2056
2057 echo json_encode($response);
2058 die();
2059
2060 }
2061
2062
2063 /**
2064 * sends out the email to the user at the end of the proces
2065 * @param $transaction_id - transaction object, containing information about the transaction
2066 * @return $response - array of 'status' and 'messages' about the function
2067 */
2068 public function send_email_to_user($transaction_id){
2069
2070 $response = array();
2071 $response['status'] = 'error';
2072
2073 //get the composer autoload file (containing phpmailer)
2074 $composer_autoload = get_stylesheet_directory() . '/vendor/autoload.php';
2075
2076 if(file_exists($composer_autoload)){
2077 require_once $composer_autoload;
2078
2079 $transaction = get_post($transaction_id);
2080 if($transaction instanceof WP_Post){
2081
2082 //Pull information from transaction
2083 $transaction_user_id = get_post_meta($transaction->ID, 'transaction_user_id', true);
2084 $transaction_coupon_id = get_post_meta($transaction->ID, 'transaction_coupon_id', true);
2085 $transaction_redemption_date = get_post_meta($transaction->ID, 'transaction_redemption_date', true);
2086
2087 //get user information
2088 $user = get_user_by('ID', $transaction_user_id);
2089 $user_mocu_email = $this->get_user_mocu_email($user);
2090
2091 //double check to ensure phpmailer exists
2092 if(class_exists('PHPMailer')){
2093 $mail = new PHPMailer;
2094
2095 //TODO: Set the 'from' email address correctly
2096 $mail->From = 'hello@beertickets.mocu.com.au';
2097 $mail->FromName = 'MoCU Beer Tickets System';
2098 $mail->CharSet = 'UTF-8';
2099
2100 $mail->addAddress($user_mocu_email);
2101 $mail->isHTML(true);
2102
2103 $mail->Subject = 'MoCU Beer Tickets Receipt';
2104
2105 //Get the content for the body
2106 ob_start();
2107
2108 $url = get_stylesheet_directory() . '/lib/mocu_email_template.php';
2109 include $url;
2110 $template_email = ob_get_clean();
2111 $mail->Body = $template_email;
2112 $mail->msgHTML($template_email); //try and send text version also
2113
2114 //send email
2115 $mail_sent = $mail->send();
2116
2117 if($mail_sent){
2118 //Now that we have successfully sent the emai. Log it as metadata on the transaction
2119 $date = new DateTime();
2120 $date_format = $date->format('d/m/Y H:i:s A');
2121 $user_mocu_email = $this->get_user_mocu_email();
2122
2123 update_post_meta($transaction_id, 'transaction_email_date', $date_format);
2124 update_post_meta($transaction_id, 'transaction_mocu_email', $user_mocu_email);
2125
2126 $response['status'] = 'success';
2127 $response['messages'][] = 'User ' . $user->ID . ' has successfully been sent their email to the email address (' . $user_mocu_email . ') for transaction ' . $transaction_id;
2128
2129 }else{
2130 $response['messages'][] = 'There was an error sending out the user email to user #' . $transaction_user_id . ', the error is: ' . $mail->ErrorInfo;
2131 $response['messages'][] = 'Your transaction was still successful however.<a href="' . get_home_url() . '/thank-you/?transaction_id=' . $transaction_id . '"> click here to view your receipt online</a>';
2132 }
2133 }else{
2134 $response['messages'][] = 'PHP Mailer is not installed, please configure PHP mailer via composer';
2135 }
2136 }else{
2137 $response['messages'][] = 'Transaction ID was not found, user email not sent out';
2138 }
2139 }else{
2140 $response['messages'][] = 'PHP Mailer was not found, emails can not be sent out';
2141 }
2142
2143 //log messages
2144 $this->log_report_message($response['messages']);
2145
2146 return $response;
2147 }
2148
2149
2150
2151 /**
2152 * Displays the user balance information on the 'balance' page template (so the user knows how mucn they
2153 * currently have to spent)
2154 */
2155 public function display_user_balance_information(){
2156
2157 $balance = $this->get_user_balance_info_from_api();
2158
2159 $html = '';
2160
2161 $html .= '<div class="u-text--center">';
2162 $html .= '<h2>YOUR POINTS BALANCE</h2>';
2163 $html .= '<div class="point-block point-block--xl">';
2164 $html .= '<span class="point-block__score point-block__score--xl">' . $balance . '</span> points';
2165 $html .= '</div>';
2166
2167 $html .= '</div>';
2168
2169 echo $html;
2170
2171 }
2172
2173 /**
2174 * Perform a curl request.
2175 * Executes a curl request based on arguments and method, passes the response object back to be processed
2176 * @return json encoed object
2177 */
2178 public function do_curl_request($method, $arguments, $type){
2179
2180 $response = array();
2181
2182 $response['curl_status'] = 'failure';
2183 $response['curl_error'] = array();
2184 $response['curl_data'] = '';
2185
2186 $curl = curl_init();
2187
2188 //based on type of curl request either build querystring or build post
2189 if($type == 'get'){
2190 //encode array of args as string
2191 $encoded_arguments_string = http_build_query($arguments);
2192 $api_endpoint_url = $this->get_api_endpoint_base() . $method . '?' . $encoded_arguments_string;
2193 }else{
2194 //send as part of a post request
2195 $encoded_post_data = json_encode($arguments);
2196
2197 curl_setopt($curl, CURLOPT_CUSTOMREQUEST, "POST");
2198 curl_setopt($curl, CURLOPT_POSTFIELDS, $encoded_post_data);
2199 curl_setopt($curl, CURLOPT_HTTPHEADER, array(
2200 'Content-Type: application/json',
2201 'Content-Length: ' . strlen($encoded_post_data))
2202 );
2203
2204 $api_endpoint_url = $this->get_api_endpoint_base() . $method;
2205 }
2206
2207 curl_setopt($curl, CURLOPT_URL, $api_endpoint_url);
2208 curl_setopt($curl, CURLOPT_TIMEOUT, 60);
2209 curl_setopt($curl, CURLOPT_RETURNTRANSFER, true);
2210 curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, false); //TODO: this doesnt work when set to true (causes SSL error on PHP)
2211
2212
2213 $curl_content = curl_exec($curl);
2214 $curl_error = curl_error($curl);
2215 $curl_errorno = curl_errno($curl);
2216
2217
2218 //check for errors
2219 if(!empty($curl_error) || $curl_errorno != 0 || empty($curl_content)){
2220
2221 if(!empty($curl_error)){
2222 $response['curl_error'][] = 'Curl error encountered: ' . $curl_error;
2223 }
2224 if($curl_errorno != 0){
2225 $response['curl_error'][] = 'Curl error number encountered: ' . $curl_errorno;
2226 }
2227 if(empty($curl_content)){
2228 $response['curl_error'][] = 'Curl did not return any content';
2229
2230 }
2231 }
2232
2233 //process content
2234 if(!empty($curl_content)){
2235 $response['curl_status'] = 'success';
2236 $response['curl_data'] = json_decode($curl_content);
2237 }
2238
2239 //return json encoded response
2240 return json_encode($response);
2241
2242 }
2243
2244
2245 /**
2246 * Registers the 'w_coupon' content type
2247 * Used to hold all coupons that are used for the system redemption process
2248 */
2249 public function register_coupons_post_type(){
2250
2251 $labels = array(
2252 'name' => __( 'Coupons', 'beertickets' ),
2253 'singular_name' => __( 'Coupon', 'beertickets' ),
2254 'menu_name' => __( 'Coupons', 'beertickets' ),
2255 'name_admin_bar' => __( 'Coupon','beertickets' ),
2256 'add_new' => __( 'Add New', 'beertickets' ),
2257 'add_new_item' => __( 'Add New Coupon', 'beertickets' ),
2258 'new_item' => __( 'New Coupon', 'beertickets' ),
2259 'edit_item' => __( 'Edit Coupon', 'beertickets' ),
2260 'view_item' => __( 'View Coupon', 'beertickets' ),
2261 'all_items' => __( 'All Coupons', 'beertickets' ),
2262 'search_items' => __( 'Search Coupons', 'beertickets' ),
2263 'parent_item_colon' => __( 'Parent Coupons:', 'beertickets' ),
2264 'not_found' => __( 'No Coupons found.', 'beertickets' ),
2265 'not_found_in_trash' => __( 'No Coupons found in Trash.', 'beertickets' )
2266 );
2267
2268 $args = array(
2269 'labels' => $labels,
2270 'description' => __( 'Content type used to hold informatioin about each unique Coupon', 'beertickets' ),
2271 'public' => true,
2272 'publicly_queryable' => false,
2273 'show_ui' => true,
2274 'show_in_menu' => true,
2275 'query_var' => true,
2276 'rewrite' => array( 'slug' => 'coupon' ),
2277 'capability_type' => 'post',
2278 'has_archive' => false,
2279 'hierarchical' => false,
2280 'menu_position' => null,
2281 'supports' => array( 'title'),
2282 'menu_icon' => 'dashicons-tickets-alt'
2283 );
2284
2285 //register post type
2286 try{
2287 $post_type = register_post_type('w_coupon', $args);
2288 if($post_type instanceof WP_Error){
2289 throw new Exception($post_type->get_error_message());
2290 }
2291 }catch(Exception $e){
2292 echo $e->getMessage();
2293 }
2294
2295 }
2296
2297 /**
2298 * registers the coupon_type taxonomy which will hold information about the differnt types of coupons
2299 */
2300 public function register_coupons_type_taxonomy(){
2301
2302 // Add new taxonomy, make it hierarchical (like categories)
2303 $labels = array(
2304 'name' => __( 'Coupon Types', 'beertickets' ),
2305 'singular_name' => __( 'Coupon Type', 'beertickets' ),
2306 'search_items' => __( 'Search Coupon Types', 'beertickets' ),
2307 'all_items' => __( 'All Coupon Types', 'beertickets' ),
2308 'parent_item' => __( 'Parent Coupon Type', 'beertickets' ),
2309 'parent_item_colon' => __( 'Parent Coupon Type:', 'beertickets' ),
2310 'edit_item' => __( 'Edit Coupon Type', 'beertickets' ),
2311 'update_item' => __( 'Update Coupon Type', 'beertickets' ),
2312 'add_new_item' => __( 'Add New Coupon Type', 'beertickets' ),
2313 'new_item_name' => __( 'New Coupon Type Name', 'beertickets' ),
2314 'menu_name' => __( 'Coupon Types', 'beertickets' )
2315 );
2316
2317 $args = array(
2318 'hierarchical' => true,
2319 'labels' => $labels,
2320 'show_ui' => true,
2321 'show_admin_column' => true,
2322 'query_var' => true,
2323 'rewrite' => array( 'slug' => 'coupon_type' ),
2324 );
2325
2326 register_taxonomy( 'w_coupon_type', array( 'w_coupon' ), $args );
2327 }
2328
2329 public function register_coupon_taxonomy_form_fields(){
2330 $html = '';
2331
2332 //SKU CODE
2333 $html .= '<div class="form-field">';
2334 $html .= '<label for="coupon_type_sku">SKU Code</label>';
2335 $html .= '<input type="text" name="coupon_type_sku" id="coupon_type_sku" value="">';
2336 $html .= '<p class="description">SKU Code for this coupon</p>';
2337 $html .= '</div>';
2338
2339 //VALUE
2340 $html .= '<div class="form-field">';
2341 $html .= '<label for="coupon_type_value">Value</label>';
2342 $html .= '<input type="text" name="coupon_type_value" id="coupon_type_value" value="">';
2343 $html .= '<p class="description">Value assigned to this coupon type. Any coupons with this type will be worth this value</p>';
2344 $html .= '</div>';
2345
2346
2347 echo $html;
2348 }
2349
2350 /**
2351 * Displays our additional meta fields when editing an existing term
2352 */
2353 public function edit_coupon_taxonomy_form_fields($term){
2354
2355 $term_id = $term->term_id;
2356
2357 $html = '';
2358
2359 $coupon_type_sku = get_term_meta($term_id, 'coupon_type_sku', true );
2360 $coupon_type_value = get_term_meta($term_id, 'coupon_type_value', true);
2361
2362 //SKU Code
2363 $html .= '<tr class="form-field">';
2364 $html .= '<th scope="row" valign="top"><label for="coupon_type_sku">SKU Code</label></th>';
2365 $html .= '<td>';
2366 $html .= '<input type="text" name="coupon_type_sku" id="coupon_type_sku" value="' . $coupon_type_sku .'"/>';
2367 $html .= '<p class="description">SKU Code for this coupon</p>';
2368 $html .= '</td>';
2369 $html .= '</tr>';
2370
2371 //VALUE
2372 $html .= '<tr class="form-field">';
2373 $html .= '<th scope="row" valign="top"><label for="coupon_type_value">Value</label></th>';
2374 $html .= '<td>';
2375 $html .= '<input type="text" name="coupon_type_value" id="coupon_type_value" value="' . $coupon_type_value .'"/>';
2376 $html .= '<p class="description">Value assigned to this coupon type. Any coupons with this type will be worth this value </p>';
2377 $html .= '</td>';
2378 $html .= '</tr>';
2379
2380 echo $html;
2381 }
2382
2383 /**
2384 * Save our meta information for the w_coupon_type taxonomy
2385 * Called on both term creation and update
2386 */
2387 public function save_coupon_taxonomy_form_fields($term_id){
2388
2389 $coupon_type_sku = isset($_POST['coupon_type_sku']) ? $_POST['coupon_type_sku'] : '';
2390 $coupon_type_value = isset($_POST['coupon_type_value']) ? $_POST['coupon_type_value'] : '';
2391
2392 update_term_meta($term_id, 'coupon_type_sku', $coupon_type_sku);
2393 update_term_meta($term_id, 'coupon_type_value', $coupon_type_value);
2394
2395 }
2396
2397 /**
2398 * Adds custom columns to the w_coupon_type taxonomy admin page,
2399 * used to provide a quick glance of custom meta info
2400 */
2401 public function add_coupon_type_admin_columns($columns){
2402
2403 unset($columns['name']);
2404 unset($columns['description']);
2405 unset($columns['slug']);
2406 unset($columns['posts']);
2407
2408 $columns['id'] = 'ID';
2409 $columns['name'] = 'Name';
2410 $columns['sku_code'] = 'SKU Code';
2411 $columns['value'] = 'Value';
2412 $columns['description'];
2413 $columns['posts'] = 'Coupons';
2414
2415 return $columns;
2416 }
2417
2418 /**
2419 * Customizes the new admin columns added for the w_coupon_type terms
2420 * @see add_coupon_type_admin_columns
2421 */
2422 public function customize_coupon_type_admin_columns($content, $column_name, $coupon_type_id){
2423
2424 if($column_name == 'id'){
2425 echo $coupon_type_id;
2426 }
2427 else if($column_name == 'sku_code') {
2428 $coupon_type_sku = get_term_meta($coupon_type_id, 'coupon_type_sku', true);
2429 echo $coupon_type_sku;
2430
2431 }else if($column_name == 'value'){
2432 $coupon_type_value = get_term_meta($coupon_type_id, 'coupon_type_value', true);
2433 echo $coupon_type_value;
2434 }
2435 }
2436
2437
2438 /**
2439 * Registers the 'w_transaction' content type
2440 * Used to hold informatioin about a single transaction (redemption) of a coupon for a user
2441 */
2442 public function register_transactions_post_type(){
2443
2444 $labels = array(
2445 'name' => __( 'Transactions', 'beertickets' ),
2446 'singular_name' => __( 'Transaction', 'beertickets' ),
2447 'menu_name' => __( 'Transactions', 'beertickets' ),
2448 'name_admin_bar' => __( 'Transaction','beertickets' ),
2449 'add_new' => __( 'Add New', 'beertickets' ),
2450 'add_new_item' => __( 'Add New Transaction', 'beertickets' ),
2451 'new_item' => __( 'New Transaction', 'beertickets' ),
2452 'edit_item' => __( 'Edit Transaction', 'beertickets' ),
2453 'view_item' => __( 'View Transaction', 'beertickets' ),
2454 'all_items' => __( 'All Transactions', 'beertickets' ),
2455 'search_items' => __( 'Search Transactions', 'beertickets' ),
2456 'parent_item_colon' => __( 'Parent Transactions:', 'beertickets' ),
2457 'not_found' => __( 'No Transaction found.', 'beertickets' ),
2458 'not_found_in_trash' => __( 'No Transactions found in Trash.', 'beertickets' )
2459 );
2460
2461 $args = array(
2462 'labels' => $labels,
2463 'description' => __( 'Content type used to hold informatioin about each transaction in the system (redemption)', 'beertickets' ),
2464 'public' => true,
2465 'publicly_queryable' => false,
2466 'show_ui' => true,
2467 'show_in_menu' => true,
2468 'query_var' => true,
2469 'rewrite' => array( 'slug' => 'transaction' ),
2470 'capability_type' => 'post',
2471 'has_archive' => false,
2472 'hierarchical' => false,
2473 'menu_position' => null,
2474 'supports' => array( 'title'),
2475 'menu_icon' => 'dashicons-format-aside'
2476 );
2477
2478 //register post type
2479 try{
2480 $post_type = register_post_type('w_transaction', $args);
2481 if($post_type instanceof WP_Error){
2482 throw new Exception($post_type->get_error_message());
2483 }
2484 }catch(Exception $e){
2485 echo $e->getMessage();
2486 }
2487 }
2488
2489
2490
2491 /**
2492 * Process the transaction for the current user.
2493 * This will connect the user and their selected coupon process and call an external service to validate the transaction
2494 * This is called via AJAX and will retunrn a response object back to JS to determine our success or several points of failure
2495 */
2496 public function process_ticket_redemption(){
2497
2498 $response = array();
2499 $response['status'] = 'error';
2500 $response['messages'] = array();
2501
2502 //get current user
2503 $user = wp_get_current_user();
2504
2505 //get desired coupon category we want to purchase.
2506 $coupon_type_sku_id = isset($_POST['coupon_type_sku_id']) ? $_POST['coupon_type_sku_id'] : '';
2507
2508 //Check if we selected the 'default' option
2509 $coupon_type_selected_default = $this->coupon_type_default_selected($coupon_type_sku_id);
2510 if($coupon_type_selected_default['status'] == 'error'){
2511 $response['messages'] = $coupon_type_selected_default['messages'] + $response['messages'];
2512 echo json_encode($response);
2513 die();
2514 }
2515
2516 //first check to ensure we have a coupon in stock
2517 $coupon_in_stock = $this->coupon_type_has_stock($coupon_type_sku_id);
2518 if($coupon_in_stock['status'] == 'error'){
2519 $response['messages'][] = 'There are currrenly no coupon in stock with the selected denomination';
2520 echo json_encode($response);
2521 die();
2522 }
2523
2524 //Get coupons that are not used and belong to this coupon type
2525 $coupon_args = array(
2526 'posts_per_page' => 1,
2527 'post_type' => 'w_coupon',
2528 'post_status' => 'publish',
2529 'orderby' => 'post_date',
2530 'order' => 'ASC',
2531 'tax_query' => array(
2532 array(
2533 'taxonomy' => 'w_coupon_type',
2534 'field' => 'term_id',
2535 'terms' => $coupon_type_sku_id
2536 )
2537 ),
2538 'meta_query' => array(
2539 array(
2540 'key' => 'coupon_status',
2541 'value' => 'unused',
2542 'compare' => '='
2543 )
2544 )
2545 );
2546
2547
2548 $coupons = get_posts($coupon_args);
2549 $coupon = ($coupons) ? $coupons[0] : '';
2550
2551 //check that the user has enough points to spend and that they have not spent more than their 1300 balance
2552 $user_can_purchase = $this->user_has_points_to_purchase_coupon($coupon->ID);
2553
2554 if($user_can_purchase['status'] == 'error'){
2555 $response['messages'] = $user_can_purchase['messages'] + $response['messages'];
2556 echo json_encode($response);
2557 die();
2558 }
2559
2560 //Post our information to the SubmitRedemption API
2561 $coupon_response = $this->post_coupon_purchase_to_api($coupon->ID);
2562 if($coupon_response['status'] == 'error'){
2563 $response['messages'] = $coupon_response['messages'] + $response['messages'];
2564 echo json_encode($response);
2565 die();
2566 }
2567
2568 //if we successfully returned back from the api, access its data
2569 $coupon_response_data = $coupon_response['data'];
2570
2571 //update transaction with information
2572 $updated_transaction_response = $this->update_transaction_for_purchase(
2573 $coupon_response_data['transaction_id'],
2574 $coupon_response_data['coupon_id'],
2575 $coupon_response_data['user_id'],
2576 $coupon_response_data['api_info']
2577 );
2578
2579
2580 //update coupon and change it's status
2581 $update_coupon_status_response = $this->update_coupon_status_used($coupon_response_data['coupon_id']);
2582 if($update_coupon_status_response['status'] == 'error'){
2583 $response['messages'] = $update_coupon_status_response['messages'] + $response['messages'];
2584 echo json_encode($response);
2585 die();
2586 }
2587
2588 //Send out user email
2589 $user_transaction_email_response = $this->send_email_to_user($coupon_response_data['transaction_id']);
2590 if($user_transaction_email_response['status'] == 'error'){
2591 $response['messages'] = $user_transaction_email_response['messages'] + $response['messages'];
2592 echo json_encode($response);
2593 die();
2594 }
2595
2596
2597 //Send out admin low stock coupon email (maybe)
2598 $low_coupon_stock = $this->check_coupon_type_stock_level($coupon_type_sku_id);
2599
2600 //selected stock is low
2601 if($low_coupon_stock['status'] == 'success'){
2602
2603 //send out local stock notification email
2604 $admin_low_coupon_stock_response = $this->send_admin_low_coupon_stock_email($coupon_type_sku_id);
2605
2606 if($admin_low_coupon_stock_response['status'] == 'error'){
2607 $response['messages'] = $admin_low_coupon_stock_response['messages'] + $response['messages'];
2608 echo json_encode($response);
2609 die();
2610 }
2611 }
2612
2613
2614
2615 //If we executed down to here then it's all good.
2616 $response['status'] = 'success';
2617 $response['messages'][] = 'Successfully processed the transaction';
2618 $response['data']['redirect_url'] = get_home_url() . '/thank-you/?transaction_id=' . $coupon_response_data['transaction_id']; //redirection handled via JS
2619
2620 //log one final message
2621 $this->log_report_message('User #' . $user->ID . ' has successfully completed the transaction process');
2622
2623 echo json_encode($response);
2624 die();
2625
2626 }
2627
2628
2629 /**
2630 * After a successful trasnaction, mark the used coupon as used so that the transaction system doesn
2631 * use it again. They're kept for record keeping purposes.
2632 * @param $coupon_id - Coupon id
2633 */
2634 public function update_coupon_status_used($coupon_id){
2635
2636 $response = array();
2637 $response['status'] = 'error';
2638
2639 $coupon = get_post($coupon_id);
2640 if($coupon instanceof WP_Post){
2641 $updated_status = update_post_meta($coupon->ID, 'coupon_status', 'used');
2642 if($updated_status == true){
2643 $response['status'] = 'success';
2644 $response['messages'][] = 'Successfully updated the coupon and changed its status to used';
2645 }else{
2646 $response['messages'][] = 'Couldnt set "coupon_status" to used';
2647 }
2648
2649 }else{
2650 $response['messages'][] = 'Coupon could not be found';
2651 }
2652
2653 //log an messages
2654 $this->log_report_message($response['messages']);
2655
2656 return $response;
2657
2658 }
2659
2660 /**
2661 * Determines if the value selected from the coupon dropdown is the 'default' option, this shouldnt happen but
2662 * we perform this check anyway just to be sure we have a valid value
2663 */
2664 public function coupon_type_default_selected($coupon_type_id){
2665
2666 $repsonse = array();
2667 $response['status'] = 'error';
2668
2669 if($coupon_type_id == 'default'){
2670 $response['messages'][] = 'The default option was chosen from the user. User must select a correct drop down coupon option';
2671 }else{
2672 $response['status'] = 'success';
2673 $response['messages'][] = 'Didnt select the default option, allocating coupon';
2674 }
2675
2676 //log messages
2677 $this->log_report_message($response['messages']);
2678
2679 return $repsonse;
2680
2681 }
2682
2683
2684
2685 /**
2686 * Displays the coupon redemption dropdown box, displayed on the front end for users to
2687 * select which coupon they wish to redeem, dynamic as it's values are dependent on what coupons we have on stock and users points
2688 */
2689 public function display_coupon_redemption_dropdown(){
2690
2691 //get current users balance.
2692 $current_user_balance = $this->get_user_balance_info_from_api();
2693
2694 $current_user_points = isset($current_user_balance['points']) ? $current_user_balance['points'] : '';
2695
2696 $html = '';
2697
2698 $html .= '<select class="chosen-select" class="" name="coupon_type_sku_id" id="coupon_type_sku_id">';
2699 //$html .= '<option value="default">Choose a value</option>';
2700
2701 //Get a listing of all w_coupon_types, corresponding to the categries of coupons on offer
2702 $coupon_types_args = array(
2703 'hide_empty' => false,
2704 'orderby' => 'meta_value_num',
2705 'meta_key' => 'coupon_type_value',
2706 'order' => 'ASC'
2707 );
2708
2709 $coupon_types = get_terms('w_coupon_type', $coupon_types_args);
2710
2711 if($coupon_types){
2712 foreach($coupon_types as $coupon_type){
2713 $coupon_type_id = $coupon_type->term_id;
2714 $coupon_type_sku = get_term_meta($coupon_type_id, 'coupon_type_sku', true);
2715 $coupon_type_value = get_term_meta($coupon_type_id, 'coupon_type_value', true);
2716
2717 //check if we have any coupons in stock belonging to this category
2718 $coupon_type_has_stock = $this->coupon_type_has_stock($coupon_type_id);
2719 if($coupon_type_has_stock['status'] == 'success'){
2720 $html .= '<option value="' . $coupon_type_id . '">$' . $coupon_type_value . '</option>';
2721 }else{
2722 $html .= '<option disabled value="' . $coupon_type_id . '">$' . $coupon_type_value . ' (No Stock)</option>';
2723 }
2724
2725 }
2726 }
2727
2728 $html .= '</select>';
2729
2730 echo $html;
2731 }
2732
2733
2734 /**
2735 * Determines if this coupon_type category has any assigned coupons to it and if any of these coupons are unused
2736 * Used before we call the redemption API so we can be sure we have at least a coupon to allocate
2737 * @param $coupon_type_id - ID of the unique w_coupon_type term containing additional info
2738 * @return $response - true or false
2739 */
2740 public function coupon_type_has_stock($coupon_type_id){
2741
2742 $response = array();
2743 $response['status'] = 'error';
2744
2745 //Get todays current date
2746 $todays_date = new DateTime();
2747 $todays_date_timestamp = $todays_date->getTimestamp();
2748
2749 //get all coupons that have not been used and are not expired
2750 $coupon_args = array(
2751 'posts_per_page' => 1,
2752 'post_type' => 'w_coupon',
2753 'post_status' => 'publish',
2754 'tax_query' => array(
2755 array(
2756 'taxonomy' => 'w_coupon_type',
2757 'field' => 'term_id',
2758 'terms' => $coupon_type_id
2759 )
2760 ),
2761 'meta_query' => array(
2762 'relation' => 'AND',
2763 array(
2764 'key' => 'coupon_status',
2765 'value' => 'unused',
2766 'compare' => '='
2767 ),
2768 array(
2769 'key' => 'coupon_expiry_date',
2770 'value' => $todays_date_timestamp,
2771 'compare' => '>'
2772 )
2773 )
2774 );
2775
2776 //If we have at least a coupon to use.
2777 $coupons = get_posts($coupon_args);
2778 if(count($coupons) > 0){
2779 $response['status'] = 'success';
2780 $response['messages'][] = 'There are coupons that belong to #' . $coupon_type_id . ' Coupon Type ID';
2781 }else{
2782 $response['messages'][] = 'No coupons belong to the coupon type id of #' . $coupon_type_id;
2783 }
2784
2785 //log any messages
2786 $this->log_report_message($response['messages']);
2787
2788 return $response;
2789
2790 }
2791
2792 /**
2793 * Gets all of the coupon type category objects.
2794 * @return array
2795 */
2796 public function get_coupon_type_categories(){
2797
2798 //get all the types of coupons we handle
2799 $coupon_type_args = array(
2800 'hide_empty' => false,
2801 );
2802 $coupon_types = get_terms('w_coupon_type', $coupon_type_args);
2803
2804 return $coupon_types;
2805 }
2806
2807 /**
2808 * Gets a single coupon type category object (or error on failure)
2809 * @return object
2810 */
2811 public function get_coupon_type_category($coupon_type_id){
2812
2813 $coupon_type = get_term($coupon_type_id);
2814 return $coupon_type;
2815 }
2816
2817 /**
2818 * Check to see if the user has enough points to purchase the selected coupon
2819 * @param $coupon_id - coupon to purchase
2820 * @return $response - array of 'status' and 'messages' about operation
2821 */
2822 public function user_has_points_to_purchase_coupon($coupon_id){
2823
2824 $response = array();
2825 $response['status'] = 'error';
2826
2827 $current_user = wp_get_current_user();
2828
2829 //get total points and historic yearly spent points
2830 $current_point_balance = $this->get_user_balance_info_from_api();
2831 $total_points_spent = $this->get_user_yearly_transaction_total();
2832
2833 $coupon = get_post($coupon_id);
2834 $coupon_types = wp_get_object_terms($coupon->ID, 'w_coupon_type');
2835 if($coupon_types){
2836 $coupon_type = $coupon_types[0];
2837 $coupon_type_value = get_term_meta($coupon_type->term_id, 'coupon_type_value', true );
2838 $coupon_type_sku = get_term_meta($coupon_type->term_id, 'coupon_type_sku', true );
2839 }
2840
2841 //check if we have enough to purchase selected ticket
2842 if(($current_point_balance >= $coupon_type_value) && (($total_points_spent + $coupon_type_value) <= 1300)){
2843 $response['status'] = 'success';
2844 $response['messages'][] = 'User ' . $current_user->ID . ' has enough points for purchase coupon (ID: ' . $coupon_id . ') for a value of ' . $coupon_type_value;
2845 $response['messages'][] = 'User ' . $current_user->ID . ' has a balance of ' . $current_point_balance . ' points and a total yearly points of ' . $total_points_spent;
2846 }else{
2847 $response['messages'][] = 'User ID #' . $current_user->ID . ' either does not have enough points to purchase this coupon or your yearly ticket balance has exceeded the 1300 point maximum';
2848 }
2849
2850 //log messages
2851 $this->log_report_message($response['messages']);
2852
2853 return $response;
2854 }
2855
2856 /**
2857 * Gets the login / logout button for a front-end user of the system
2858 * Displays the ADFS login / logout link for the user
2859 */
2860 public function get_user_login_logout_button(){
2861
2862 $html = '';
2863
2864 $user = wp_get_current_user();
2865
2866 //logged in
2867 if($user->ID != 0){
2868 $home_page = get_home_url();
2869 $logout_url = wp_logout_url($home_page);
2870 $html .= '<a href="' . $logout_url .'" data-toggle="" data-target="" class="btn btn--outline">SIGN OUT</a>';
2871 }
2872 //not logged in
2873 else{
2874 $home_page = get_home_url();
2875 $login_url = $home_page . '/?option=saml_user_login';
2876 $html .= '<a href="' . $login_url . '" data-toggle="" data-target="" class="btn btn--outline">SIGN IN</a>';
2877 }
2878
2879 return $html;
2880 }
2881
2882 /**
2883 * Displays the login / logout button based on user
2884 */
2885 public static function display_user_login_logout_button(){
2886 $insatnce = self::getInstance();
2887
2888 $html = $insatnce->get_user_login_logout_button();
2889
2890 echo $html;
2891 }
2892
2893 /**
2894 * Disables the admin bar for the subsriber users (which ADFS maps to by default)
2895 */
2896 public function disable_admin_bar_for_subscribers(){
2897
2898 if (!current_user_can('administrator') && !is_admin()){
2899 show_admin_bar(false);
2900 }
2901 }
2902
2903 /**
2904 * If current user tries to access the back-end, redirect them back home
2905 */
2906 public function redirect_users_from_admin_for_subscribers(){
2907
2908 //Check to ensure our ajax calls and syncs work still with redirect
2909 if (stripos($_SERVER['REQUEST_URI'],'/wp-admin/') !== false &&
2910 stripos($_SERVER['REQUEST_URI'],'async-upload.php') == false &&
2911 stripos($_SERVER['REQUEST_URI'],'admin-ajax.php') == false){
2912
2913 //subscriber accessing
2914 if (current_user_can('subscriber')) {
2915 // Send a temporary redirect
2916 $url = get_home_url();
2917 wp_redirect($url ,302);
2918 }
2919 }
2920 }
2921
2922 /**
2923 * Checks to see if we have low stock for a selected coupon type.
2924 * @return $response - array of 'status' and 'messages' about operation
2925 */
2926 public function check_coupon_type_stock_level($coupon_type_id){
2927
2928 $response = array();
2929 $response['status'] = 'error';
2930
2931 $coupon_type = $this->get_coupon_type_category($coupon_type_id);
2932 if(!empty($coupon_type) && ($coupon_type instanceof WP_Term)){
2933
2934 //get the number of coupons
2935 $count = $this->get_coupon_count_by_coupon_id($coupon_type_id);
2936
2937 //check stock threshold
2938 if($count < $this->low_coupon_stock_threshold){
2939 $response['status'] = 'success';
2940 $response['messages'][] = 'Coupon type #' . $coupon_type_id . ' has low stock, it only has ' . $count . ' left.';
2941 }
2942 }else{
2943 $response['messages'][] = "The passed in term: " . $coupon_type_id . " either returned no assigned coupons or generated an error, cant check stock";
2944 }
2945
2946
2947 //log messages
2948 $this->log_report_message($response['messages']);
2949
2950 return $response;
2951 }
2952
2953
2954 /**
2955 * Counts the number of unused / available coupons for a selected coupon type.
2956 * @param coupon_type_id
2957 * @return int
2958 */
2959 public function get_coupon_count_by_coupon_id($coupon_type_id){
2960
2961 //Get all unused coupons for this term
2962 $coupon_args = array(
2963 'posts_per_page' => -1,
2964 'post_type' => 'w_coupon',
2965 'post_status' => 'publish',
2966 'orderby' => 'post_date',
2967 'order' => 'ASC',
2968 'tax_query' => array(
2969 array(
2970 'taxonomy' => 'w_coupon_type',
2971 'field' => 'term_id',
2972 'terms' => $coupon_type_id
2973 )
2974 ),
2975 'meta_query' => array(
2976 array(
2977 'key' => 'coupon_status',
2978 'value' => 'unused',
2979 'compare' => '='
2980 )
2981 )
2982 );
2983
2984
2985
2986 $coupons = get_posts($coupon_args);
2987
2988 //get coupon count
2989 $count = ($coupons) ? count($coupons) : 0;
2990
2991 return $count;
2992 }
2993
2994 /**
2995 * Sends an email to the nominated email address when coupons are in low stock.
2996 */
2997 public function send_admin_low_coupon_stock_email($coupon_type_id){
2998
2999 $response = array();
3000 $response['status'] = 'error';
3001
3002 //get the composer autoload file (containing phpmailer)
3003 $composer_autoload = get_stylesheet_directory() . '/vendor/autoload.php';
3004
3005 if(file_exists($composer_autoload)){
3006
3007 require_once $composer_autoload;
3008
3009
3010 //get coupon info ready for the template
3011 $coupon_type = $this->get_coupon_type_category($coupon_type_id);
3012 $coupon_type_value = get_term_meta($coupon_type->term_id, 'coupon_type_value', true);
3013 $coupon_type_sku = get_term_meta($coupon_type->term_id, 'coupon_type_sku', true);
3014 $coupon_type_count = $this->get_coupon_count_by_coupon_id($coupon_type_id);
3015
3016
3017 //double check to ensure phpmailer exists
3018 if(class_exists('PHPMailer')){
3019 $mail = new PHPMailer;
3020
3021 $mail->From = 'hello@beertickets.mocu.com.au';
3022 $mail->FromName = '(ADMIN) MoCU Beer Tickets System';
3023 $mail->CharSet = 'UTF-8';
3024
3025 //$mail->addAddress('simon.codrington@thewhiteagency.com.au');
3026 $mail->addAddress('InternalSupport@mocu.com.au');
3027 $mail->addAddress('Philippa.Jacobs@lionco.com');
3028 $mail->isHTML(true);
3029
3030 $mail->Subject = 'MoCU Beer Tickets Low Coupon Stock Notice (SKU: ' . $coupon_type_sku . ')';
3031
3032 //Get the content for the body
3033 ob_start();
3034
3035 $url = get_stylesheet_directory() . '/lib/mocu_admin_low_stock_email_template.php';
3036 include $url;
3037 $template_email = ob_get_clean();
3038
3039 $mail->Body = $template_email;
3040 $mail->msgHTML($template_email); //try and send text version also
3041
3042 //send email
3043 $mail_sent = $mail->send();
3044 if($mail_sent){
3045
3046 $response['status'] = 'success';
3047 $response['messages'][] = 'Email about low stock notice successfull sent';
3048
3049 }else{
3050 $response['messages'][] = 'There was an error sending out the low stock notice admin email, the error is: ' . $mail->ErrorInfo;
3051 }
3052 }else{
3053 $response['messages'][] = 'PHP Mailer is not installed, please configure PHP mailer via composer';
3054 }
3055 }else{
3056 $response['messages'][] = 'PHP Mailer was not found, emails can not be sent out';
3057 }
3058
3059 //log messages
3060 $this->log_report_message($response['messages']);
3061
3062 return $response;
3063 }
3064
3065
3066 }
3067 $white_theme_base = white_theme_base::getInstance();