PluginProbe ʕ •ᴥ•ʔ
LatePoint – Calendar Booking Plugin for Appointments and Events / 5.2.0
LatePoint – Calendar Booking Plugin for Appointments and Events v5.2.0
5.6.5 5.6.4 5.6.3 5.6.2 5.6.1 5.6.0 5.5.2 5.5.1 5.5.0 5.4.2 trunk 5.1.0 5.1.1 5.1.2 5.1.3 5.1.4 5.1.5 5.1.6 5.1.7 5.1.8 5.1.9 5.1.91 5.1.92 5.1.93 5.1.94 5.2.0 5.2.1 5.2.10 5.2.11 5.2.2 5.2.3 5.2.4 5.2.5 5.2.6 5.2.7 5.2.8 5.2.9 5.3.0 5.3.1 5.3.2 5.4.0 5.4.1
latepoint / lib / controllers / orders_controller.php
latepoint / lib / controllers Last commit date
activities_controller.php 11 months ago auth_controller.php 9 months ago booking_form_settings_controller.php 1 year ago bookings_controller.php 1 year ago calendars_controller.php 9 months ago carts_controller.php 1 year ago controller.php 9 months ago customer_cabinet_controller.php 9 months ago customers_controller.php 9 months ago dashboard_controller.php 9 months ago default_agent_controller.php 1 year ago events_controller.php 1 year ago form_fields_controller.php 9 months ago integrations_controller.php 9 months ago invoices_controller.php 1 year ago manage_booking_by_key_controller.php 1 year ago manage_order_by_key_controller.php 1 year ago notifications_controller.php 1 year ago orders_controller.php 1 year ago pro_controller.php 1 year ago process_jobs_controller.php 9 months ago processes_controller.php 1 year ago search_controller.php 1 year ago services_controller.php 9 months ago settings_controller.php 1 year ago steps_controller.php 9 months ago stripe_connect_controller.php 9 months ago support_topics_controller.php 1 year ago todos_controller.php 1 year ago transactions_controller.php 1 year ago wizard_controller.php 1 year ago
orders_controller.php
810 lines
1 <?php
2 /*
3 * Copyright (c) 2024 LatePoint LLC. All rights reserved.
4 */
5
6 if ( ! defined( 'ABSPATH' ) ) {
7 exit; // Exit if accessed directly.
8 }
9
10
11 if ( ! class_exists( 'OsOrdersController' ) ) :
12
13
14 class OsOrdersController extends OsController {
15
16 function __construct() {
17 parent::__construct();
18
19 $this->views_folder = LATEPOINT_VIEWS_ABSPATH . 'orders/';
20 $this->vars['page_header'] = OsMenuHelper::get_menu_items_by_id( 'orders' );
21 $this->vars['breadcrumbs'][] = array(
22 'label' => __( 'Orders', 'latepoint' ),
23 'link' => OsRouterHelper::build_link( OsRouterHelper::build_route_name( 'orders', 'index' ) )
24 );
25
26 $this->action_access['public'] = array_merge( $this->action_access['public'], [ 'continue_order_intent', 'continue_transaction_intent' ] );
27 }
28
29
30 public function view_order_log() {
31 $activities = new OsActivityModel();
32 $activities = $activities->where( [ 'order_id' => absint($this->params['order_id']) ] )->order_by( 'id desc' )->get_results_as_models();
33
34 $order = new OsOrderModel( $this->params['order_id'] );
35
36 $this->vars['order'] = $order;
37 $this->vars['activities'] = $activities;
38
39 $this->format_render( __FUNCTION__ );
40 }
41
42
43 public function continue_order_intent() {
44 $order_intent_key = $this->params['order_intent_key'];
45 $order_intent = OsOrderIntentHelper::get_order_intent_by_intent_key($order_intent_key);
46
47 if($order_intent->is_new_record()){
48 http_response_code( 400 );
49 OsDebugHelper::log('Order intent not found, id:'. $order_intent_key);
50 exit();
51 }else{
52
53 $order_intent->convert_to_order();
54
55 if ( $order_intent ) {
56 nocache_headers();
57 wp_redirect( $order_intent->get_page_url_with_intent(), 302 );
58 }
59 }
60
61 }
62
63
64 public function continue_transaction_intent() {
65 $intent_key = $this->params['transaction_intent_key'];
66 $transaction_intent = OsTransactionIntentHelper::get_transaction_intent_by_intent_key($intent_key);
67
68 if($transaction_intent->is_new_record()){
69 http_response_code( 400 );
70 OsDebugHelper::log('Transaction intent not found, id:'. $intent_key);
71 exit();
72 }else{
73 $transaction_intent->convert_to_transaction();
74
75 if ( $transaction_intent ) {
76 nocache_headers();
77 wp_redirect( $transaction_intent->get_page_url_with_intent(), 302 );
78 }
79 }
80 }
81
82 /*
83 Update order (used in admin on quick side form save)
84 */
85
86 public function update() {
87 $this->create_or_update();
88 }
89
90
91 /*
92 Create order (used in admin on quick side form save)
93 */
94
95 public function create() {
96 $this->create_or_update();
97 }
98
99
100 // Create/Update order from quick form in admin
101 public function create_or_update() {
102 $validation_errors = [];
103
104 if ( ! empty( $this->params['order']['id'] ) ) {
105 $this->check_nonce( 'edit_order_' . $this->params['order']['id'] );
106 } else {
107 $this->check_nonce( 'new_order' );
108 }
109
110 $order_params = $this->params['order'];
111 $customer_params = $this->params['customer'];
112
113
114 $order_items_params = $this->params['order_items'] ?? [];
115
116
117 $order = new OsOrderModel( $order_params['id'] );
118
119 // if we are updating a order - save a copy by cloning old order
120 $old_order = ( $order->is_new_record() ) ? [] : clone $order;
121 $order->set_data( $order_params );
122
123
124 // first validate & create a customer the customer
125 if ( $order->customer_id ) {
126 $customer = new OsCustomerModel( $order->customer_id );
127 $old_customer_data = $customer->get_data_vars();
128 $is_new_customer = false;
129 } else {
130 $customer = new OsCustomerModel();
131 $is_new_customer = true;
132 }
133 $customer->set_data( $customer_params );
134 if ( $customer->save() ) {
135 if ( $is_new_customer ) {
136 do_action( 'latepoint_customer_created', $customer );
137 $this->fields_to_update['order[customer_id]'] = $customer->id;
138 } else {
139 do_action( 'latepoint_customer_updated', $customer, $old_customer_data );
140 }
141
142 $order->customer_id = $customer->id;
143 }else{
144 $this->send_json( [
145 'status' => LATEPOINT_STATUS_ERROR,
146 // translators: %s is the description of an error
147 'message' => sprintf(__( 'Error: %s', 'latepoint'), implode( ', ', $customer->get_error_messages() ) ),
148 ]
149 );
150 }
151
152 // validate order items
153 foreach ( $order_items_params as $order_item_id => $order_item ) {
154 foreach ( $order_item['bookings'] as $booking_id => $booking_params ) {
155 $booking = OsOrdersHelper::create_booking_object_from_booking_data_form( $booking_params );
156 $booking->customer_id = $order->customer_id;
157 if ( !$booking->validate(false, ['order_item_id']) ) {
158 $validation_errors = array_merge($validation_errors, $booking->get_error_messages());
159 }
160 }
161 }
162
163 // check if there are errors saving bookings
164 if($validation_errors){
165 // translators: %s is the description of an error
166 $this->send_json( array( 'status' => LATEPOINT_STATUS_ERROR, 'message' => sprintf(__( 'Error: %s', 'latepoint'), implode( ', ', $validation_errors ) ) ) );
167 }
168
169 if ( $old_order ) {
170 // make sure old order items are still there, if not - remove them
171 $order_items = $order->get_items();
172 foreach ( $order_items as $order_item ) {
173 if ( ! isset( $order_items_params[ $order_item->id ] ) ) {
174 $order_item_id_to_delete = $order_item->id;
175 /**
176 * Fires right before an order item is about to be deleted
177 *
178 * @param {integer} $order_item_id ID of the Order Item which will be deleted
179 *
180 * @since 5.0.0
181 * @hook latepoint_order_item_will_be_deleted
182 *
183 */
184 do_action( 'latepoint_order_item_will_be_deleted', $order_item_id_to_delete );
185
186 $order_item->delete();
187
188 /**
189 * Fires right after an order item has been deleted
190 *
191 * @param {integer} $order_item_id ID of the Order Item that was deleted
192 *
193 * @since 5.0.0
194 * @hook latepoint_order_item_deleted
195 *
196 */
197 do_action( 'latepoint_order_item_deleted', $order_item_id_to_delete );
198 OsActivitiesHelper::log_order_item_deleted($order_item);
199 } else {
200 // it's a bundle order item - search for bookings that are attached to this bundle and remove them if not found in passed params list
201 if ( $order_item->is_bundle() ) {
202 $old_bundle_bookings = OsOrdersHelper::get_bookings_for_order_item( $order_item->id );
203 if ( $old_bundle_bookings ) {
204 foreach ( $old_bundle_bookings as $old_bundle_booking ) {
205 if ( empty( $order_items_params[ $order_item->id ]['bookings'][ $old_bundle_booking->id ] ) ) {
206
207 if ( OsRolesHelper::can_user_make_action_on_model_record( $old_bundle_booking, 'delete' ) ) {
208 $booking_id_to_delete = $old_bundle_booking->id;
209
210 /**
211 * Fires right before a booking is about to be deleted
212 *
213 * @param {integer} $booking_id ID of the booking that will be deleted
214 *
215 * @since 5.0.0
216 * @hook latepoint_booking_will_be_deleted
217 *
218 */
219 do_action( 'latepoint_booking_will_be_deleted', $booking_id_to_delete );
220
221 $old_bundle_booking->delete();
222 /**
223 * Fires right after a booking has been deleted
224 *
225 * @param {integer} $booking_id ID of the booking that was deleted
226 *
227 * @since 5.0.0
228 * @hook latepoint_booking_deleted
229 *
230 */
231 do_action( 'latepoint_booking_deleted', $booking_id_to_delete );
232 OsActivitiesHelper::log_booking_deleted($old_bundle_booking);
233 } else {
234 OsDebugHelper::log( 'Not allowed: Deleting Booking', 'permissions_error' );
235 }
236 }
237 }
238 }
239 }
240 }
241 }
242 }
243
244 // Because price is not in allowed_params to bulk set, check if it's passed in params and set it, OTHERWISE CALCULATE IT
245 if ( isset( $order_params['total'] ) ) {
246 $order->total = OsParamsHelper::sanitize_param( $order_params['total'], 'money' );
247 }
248 if ( isset( $order_params['subtotal'] ) ) {
249 $order->subtotal = OsParamsHelper::sanitize_param( $order_params['subtotal'], 'money' );
250 }
251
252 // save price breakdown, we only need to save before and after subtotal, as total and subtotal values are stored on the Order record itself
253 if ( ! empty( $this->params['price_breakdown'] ) ) {
254 $order->price_breakdown = wp_json_encode( OsOrdersHelper::generate_price_breakdown_from_params($this->params['price_breakdown']) );
255 }
256
257 // Check if we have to create a payment request
258 $create_payment_request = (sanitize_text_field($this->params['create_payment_request'] ?? '') == LATEPOINT_VALUE_ON);
259 if($create_payment_request){
260 $payment_request_data = $this->params['payment_request'];
261 $payment_request_data['portion'] = sanitize_text_field($payment_request_data['portion']);
262 $payment_request_data['charge_amount'] = sanitize_text_field($payment_request_data['charge_amount_'.$payment_request_data['portion']]);
263 $payment_request_data['due_at'] = OsTimeHelper::custom_datetime_utc_in_db_format(sanitize_text_field($payment_request_data['due_at']).' 23:59:59');
264 $order->set_initial_payment_data_value('time', LATEPOINT_PAYMENT_TIME_NOW, false);
265 $order->set_initial_payment_data_value('portion', $payment_request_data['portion'], false);
266 $order->set_initial_payment_data_value('charge_amount', OsMoneyHelper::convert_amount_from_money_input_to_db_format($payment_request_data['charge_amount'], false));
267
268 $payment_request = new OsPaymentRequestModel();
269
270 $payment_request = $payment_request->set_data($payment_request_data);
271
272 }else{
273 $order->set_initial_payment_data_value('time', LATEPOINT_PAYMENT_TIME_LATER);
274 $payment_request = null;
275 }
276
277 if ( $order->save() ) {
278
279 // save transactions
280 if ( ! empty( $this->params['transactions'] ) ) {
281 foreach ( $this->params['transactions'] as $transaction_params ) {
282 if ( ! empty( $transaction_params['id'] ) && filter_var( $transaction_params['id'], FILTER_VALIDATE_INT ) ) {
283 // update existing transaction
284 $transaction = new OsTransactionModel( $transaction_params['id'] );
285 $is_new_transaction = false;
286 } else {
287 // new transaction
288 $transaction = new OsTransactionModel();
289 $is_new_transaction = true;
290 }
291 unset( $transaction_params['id'] );
292 $transaction_params['invoice_id'] = filter_var( $transaction_params['invoice_id'], FILTER_VALIDATE_INT ) ? $transaction_params['invoice_id'] : null;
293 $transaction->set_data( $transaction_params );
294 $transaction->order_id = $order->id;
295 $transaction->customer_id = $customer->id;
296 $transaction->status = LATEPOINT_TRANSACTION_STATUS_SUCCEEDED;
297 $transaction->save();
298 if ( $is_new_transaction ) {
299 /**
300 * Transaction for order was created
301 *
302 * @param {OsTransactionModel} $transaction instance of transaction model that was created
303 *
304 * @since 5.0.0
305 * @hook latepoint_transaction_created
306 *
307 */
308 do_action( 'latepoint_transaction_created', $transaction );
309 }
310 }
311 }
312 foreach ( $order_items_params as $order_item_id => $order_item ) {
313 $order_item_model = new OsOrderItemModel();
314 $order_item_model->variant = $order_item['variant'];
315 if ( strpos( $order_item_id, 'new_' ) === false ) {
316 $order_item_model->load_by_id( $order_item_id );
317 }
318 if ( $order_item_model->is_bundle() ) {
319 $order_item_model->item_data = base64_decode( $order_item['item_data'] );
320 $order_item_model->recalculate_prices();
321 }
322
323
324 $order_item_model->order_id = $order->id;
325 if ( $order_item_model->save() ) {
326 foreach ( $order_item['bookings'] as $booking_id => $booking_params ) {
327 $booking = new OsBookingModel();
328 $old_booking = false;
329 if ( strpos( $order_item_id, 'new_' ) === false ) {
330 $booking->load_by_id( $booking_id );
331 if ( ! $booking->is_new_record() ) {
332 $old_booking = clone $booking;
333 }
334 }
335
336 $booking = OsOrdersHelper::create_booking_object_from_booking_data_form( $booking_params );
337 $booking->customer_id = $order->customer_id;
338 $booking->order_item_id = $order_item_model->id;
339 $booking->form_id = $booking_id;
340 if ( $booking->save() ) {
341 if ( $order_item_model->is_booking() ) {
342 $order_item_model->item_data = $booking->generate_item_data();
343 $order_item_model->recalculate_prices();
344 $order_item_model->save();
345 }
346 if ( $old_booking ) {
347 do_action( 'latepoint_booking_updated', $booking, $old_booking );
348 if($old_booking->status != $booking->status){
349 do_action( 'latepoint_booking_change_status', $booking, $old_booking );
350 OsActivitiesHelper::log_booking_change_status($booking, $old_booking);
351 }
352 } else {
353 do_action( 'latepoint_booking_created', $booking );
354 }
355 } else {
356 OsDebugHelper::log( 'Error saving booking (admin)', 'booking_save_error', $booking->get_error_messages() );
357 }
358 }
359 } else {
360 OsDebugHelper::log( 'Error saving order item (admin)', 'order_item_save_error', $order_item_model->get_error_messages() );
361 }
362 }
363
364
365
366 if ( $old_order ) {
367 /**
368 * Order was updated
369 *
370 * @param {OsOrderModel} $order instance of order model after it was updated
371 * @param {OsOrderModel} $old_order instance of order model before it was updated
372 *
373 * @since 5.0.0
374 * @hook latepoint_order_updated
375 *
376 */
377 do_action( 'latepoint_order_updated', $order, $old_order );
378 } else {
379 OsInvoicesHelper::create_invoices_for_new_order($order, $payment_request);
380 /**
381 * Order was created
382 *
383 * @param {OsOrderModel} $order instance of order model that was created
384 *
385 * @since 5.0.0
386 * @hook latepoint_order_created
387 *
388 */
389 do_action( 'latepoint_order_created', $order );
390 }
391
392 $status = LATEPOINT_STATUS_SUCCESS;
393 // translators: %s is a link to the updated order
394 $response_html = sprintf( ( ( $old_order ) ? __( 'Order Updated ID: %s', 'latepoint' ) : __( 'Order Created ID: %s', 'latepoint' ) ), '<span class="os-notification-link" ' . OsOrdersHelper::quick_order_btn_html( $order->id ) . '>' . $order->id . '</span>' );
395 } else {
396 OsDebugHelper::log( 'Error saving order (admin)', 'order_save_error', $order->get_error_messages() );
397 $status = LATEPOINT_STATUS_ERROR;
398
399 // translators: %s is an error message
400 $response_html = sprintf(__( 'Error: %s', 'latepoint'), implode( ', ', $order->get_error_messages() ));
401 }
402
403 if ( $this->get_return_format() == 'json' ) {
404 $this->send_json( array( 'status' => $status, 'message' => $response_html ) );
405 }
406
407 }
408
409
410 // reloads a section of a quick edit form that has a price breakdown
411 public function reload_price_breakdown() {
412 $order = new OsOrderModel();
413 $order->set_data( $this->params['order'] );
414
415 $order_items_params = $this->params['order_items'] ?? [];
416 foreach ( $order_items_params as $order_items_param ) {
417 $order->items[] = OsOrdersHelper::create_order_item_object( $order_items_param );
418 }
419
420 $order->subtotal = $order->recalculate_subtotal();
421 $order->total = $order->recalculate_total();
422
423 /**
424 * Reloads price breakdown rows
425 *
426 * @since 5.0.0
427 * @hook latepoint_register_role
428 *
429 * @param {OsOrderModel} $order Order for which to reload price breakdown
430 * @returns {OsOrderModel} Filtered order with updated price breakdown rows
431 */
432 $order = apply_filters( 'latepoint_order_reload_price_breakdown', $order );
433
434 // we don't need to generate balance and payments info as it is printed in a separate block
435 $this->vars['price_breakdown_rows'] = $order->generate_price_breakdown_rows( [ 'balance', 'payments' ], true );
436
437 $this->vars['order'] = $order;
438 $this->format_render( __FUNCTION__ );
439 }
440
441 function reload_balance_and_payments() {
442 $order_params = $this->params['order'];
443 $order_items_params = $this->params['order_items'] ?? [];
444
445 $order = new OsOrderModel();
446 $order->set_data( $order_params );
447
448 foreach ( $order_items_params as $order_items_param ) {
449 $order->items[] = OsOrdersHelper::create_order_item_object( $order_items_param );
450 }
451
452
453
454 // Because price is not in allowed_params to bulk set, check if it's passed in params and set it, OTHERWISE CALCULATE IT
455 if ( isset( $order_params['total'] ) ) {
456 $order->total = OsParamsHelper::sanitize_param( $order_params['total'], 'money' );
457 }
458 if ( isset( $order_params['subtotal'] ) ) {
459 $order->subtotal = OsParamsHelper::sanitize_param( $order_params['subtotal'], 'money' );
460 }
461
462
463 $this->vars['order'] = $order;
464 $this->format_render( __FUNCTION__ );
465 }
466
467 function generate_bundle_order_item_block() {
468 $bundle = new OsBundleModel( $this->params['bundle_id'] );
469
470 $order_item_id = OsUtilHelper::generate_form_id();
471 $response_html = '<div class="order-item order-item-variant-bundle" data-order-item-id="' . $order_item_id . '">';
472 $response_html .= OsOrdersHelper::generate_order_item_pill_for_bundle( $bundle, $order_item_id );
473 $response_html .= '</div>';
474
475 if ( $this->get_return_format() == 'json' ) {
476 $this->send_json( array( 'status' => LATEPOINT_STATUS_SUCCESS, 'message' => $response_html ) );
477 }
478 }
479
480 function generate_booking_order_item_block() {
481
482 if ( ! empty( $this->params['order_item_variant'] ) && ( $this->params['order_item_variant'] == LATEPOINT_ITEM_VARIANT_BUNDLE ) ) {
483 // booking for bundle, we don't need to wrap in order-item block because order item is a bundle
484 $booking = OsBookingHelper::build_booking_model_from_item_data( json_decode( base64_decode( $this->params['booking_item_data'] ), true ) );
485 $response_html = OsOrdersHelper::booking_data_form_for_order_item_id( $this->params['order_item_id'], $booking, LATEPOINT_ITEM_VARIANT_BUNDLE, false );
486 } else {
487 // regular booking
488 $booking = OsBookingHelper::prepare_new_from_params( $this->params );
489 $order_item_id = OsUtilHelper::generate_form_id();
490 $response_html = '<div class="order-item order-item-variant-booking" data-order-item-id="' . $order_item_id . '">';
491 $response_html .= OsOrdersHelper::booking_data_form_for_order_item_id( $order_item_id, $booking, LATEPOINT_ITEM_VARIANT_BOOKING, false );
492 $response_html .= '</div>';
493 }
494
495
496 if ( $this->get_return_format() == 'json' ) {
497 $this->send_json( array( 'status' => LATEPOINT_STATUS_SUCCESS, 'message' => $response_html ) );
498 }
499 }
500
501 function fold_booking_data_form() {
502 // input fields are formatted in customer preferred format, we need to convert that to database format Y-m-d
503 $order_item_id = $this->params['order_item_id'];
504 $booking_id = $this->params['booking_id'];
505
506 $booking_params = $this->params['order_items'][ $order_item_id ]['bookings'][ $booking_id ];
507 $booking = OsOrdersHelper::create_booking_object_from_booking_data_form( $booking_params );
508
509 if ( $this->params['order_items'][ $order_item_id ]['variant'] == LATEPOINT_ITEM_VARIANT_BUNDLE ) {
510 $response_html = OsOrdersHelper::generate_order_item_pill_for_bundle_booking( $booking, $order_item_id );
511 } else {
512 $response_html = OsOrdersHelper::generate_order_item_pill_for_booking( $booking, $order_item_id );
513 }
514 $this->send_json( array( 'status' => LATEPOINT_STATUS_SUCCESS, 'message' => $response_html ) );
515 }
516
517 function generate_order_item_booking_data_form() {
518 $order_item = new OsOrderItemModel();
519 $order_item->variant = $this->params['order_item_variant'] ?? LATEPOINT_ITEM_VARIANT_BOOKING;
520 if ( ! empty( $this->params['order_item_id'] ) ) {
521 // existing order item
522 if ( strpos( $this->params['order_item_id'], 'new_' ) !== false ) {
523 $order_item->form_id = $this->params['order_item_id'];
524 } else {
525 $order_item->id = $this->params['order_item_id'];
526 }
527 $order_item->item_data = ! empty( $this->params['order_item_item_data'] ) ? base64_decode( $this->params['order_item_item_data'] ) : '';
528 if ( $order_item->is_bundle() ) {
529 $booking_item_data = ! empty( $this->params['booking_item_data'] ) ? base64_decode( $this->params['booking_item_data'] ) : '';
530 $booking = OsBookingHelper::build_booking_model_from_item_data( json_decode( $booking_item_data, true ) );
531 } else {
532 $booking = $order_item->build_original_object_from_item_data();
533 }
534 } else {
535 // new order item
536 $booking = OsBookingHelper::prepare_new_from_params( $this->params );
537 }
538
539 $response_html = OsOrdersHelper::booking_data_form_for_order_item_id( $order_item->get_form_id(), $booking, $order_item->variant );
540 $this->send_json( array( 'status' => LATEPOINT_STATUS_SUCCESS, 'message' => $response_html ) );
541 }
542
543 function quick_edit() {
544
545 $customers = new OsCustomerModel();
546 // only load customers that belong to logged in agent, if any
547 if ( ! OsRolesHelper::are_all_records_allowed( 'agent' ) ) {
548 $customers->select( LATEPOINT_TABLE_CUSTOMERS . '.*' )->join( LATEPOINT_TABLE_BOOKINGS, [ 'customer_id' => LATEPOINT_TABLE_CUSTOMERS . '.id' ] )->group_by( LATEPOINT_TABLE_CUSTOMERS . '.id' )->where( [ LATEPOINT_TABLE_BOOKINGS . '.agent_id' => OsRolesHelper::get_allowed_records( 'agent' ) ] );
549 }
550
551
552 $customers_arr = $customers->order_by( 'first_name asc, last_name asc' )->set_limit( 20 )->get_results_as_models();
553 $this->vars['customers'] = $customers_arr;
554
555 // CREATING NEW ORDER
556 $order = new OsOrderModel();
557 $order_id = $this->params['id'] ?? false;
558
559 if ( ! empty( $this->params['booking_id'] ) ) {
560 $preselected_booking = new OsBookingModel( $this->params['booking_id'] );
561 $preselected_order_item = new OsOrderItemModel( $preselected_booking->order_item_id );
562 $order_id = $preselected_order_item->order_id;
563 } else {
564 $preselected_booking = false;
565 $preselected_order_item = false;
566 }
567
568 if ( $order_id ) {
569 // EDITING EXISTING ORDER
570 $order = new OsOrderModel( $order_id );
571 // TODO add this check for order
572 // if(!OsRolesHelper::can_user_make_action_on_model_record($order, 'view')){
573 // $this->send_json(array('status' => LATEPOINT_STATUS_ERROR, 'message' => 'Not Allowed'));
574 // }
575
576 $transactions = $order->get_transactions();
577
578 } else {
579 // NEW ORDER
580
581 // LOAD FROM PASSED PARAMS
582 $order->status = OsOrdersHelper::get_default_order_status();
583 $order->fulfillment_status = $order->get_default_fulfillment_status();
584
585 if ( ! empty( $this->params['customer_id'] ) ) {
586 $order->customer_id = $this->params['customer_id'];
587 }
588
589 $new_booking = OsBookingHelper::prepare_new_from_params( $this->params );
590 $new_booking = apply_filters( 'latepoint_prepare_booking_for_quick_view', $new_booking );
591 $order_item_model = new OsOrderItemModel();
592 $order_item_model->variant = LATEPOINT_ITEM_VARIANT_BOOKING;
593 $order_item_model->item_data = $new_booking->generate_item_data();
594
595 $order->items[] = $order_item_model;
596
597 $order->total = $order->recalculate_total();
598 $order->subtotal = $order->recalculate_subtotal();
599
600 $transactions = [];
601 }
602
603 $bundles = new OsBundleModel();
604 $bundles = $bundles->should_be_active()->get_results_as_models();
605 $this->vars['bundles'] = $bundles;
606
607
608 $this->vars['price_breakdown_rows'] = $order->generate_price_breakdown_rows();
609
610 $order = apply_filters( 'latepoint_prepare_order_for_quick_view', $order );
611
612 $order_bookings = $order->get_bookings_from_order_items();
613 $order_bundles = $order->get_bundles_from_order_items();
614
615
616 $this->vars['selected_customer'] = new OsCustomerModel( $order->customer_id );
617 $this->vars['order'] = $order;
618 $this->vars['preselected_booking'] = $preselected_booking;
619 $this->vars['preselected_order_item'] = $preselected_order_item;
620 $this->vars['show_only_preselected_items'] = $preselected_booking && $preselected_order_item && ( ( count( $order_bookings ) > 1 ) || ( count( $order_bundles ) ) || ( $order_bundles && $order_bookings ) );
621
622 $this->vars['order_bookings'] = $order_bookings;
623 $this->vars['order_bundles'] = $order_bundles;
624 $this->vars['transactions'] = $transactions;
625 $this->vars['default_fields_for_customer'] = OsSettingsHelper::get_default_fields_for_customer();
626 $this->format_render( __FUNCTION__ );
627 }
628
629 public function edit_form() {
630 $order = ( empty( $this->params['id'] ) ) ? new OsOrderModel() : new OsOrderModel( $this->params['id'] );
631 // legacy fix for older orders that didn't have portion column, get it from connected order
632 if ( ! $order->is_new_record() && empty( $order->payment_portion ) && ! empty( $order->booking_id ) ) {
633 $booking = new OsBookingModel( $order->booking_id );
634 if ( ! empty( $booking->id ) ) {
635 $order->payment_portion = $booking->payment_portion;
636 }
637 }
638 $this->vars['real_or_rand_id'] = ( $order->is_new_record() ) ? 'new_order_' . OsUtilHelper::random_text( 'alnum', 5 ) : $order->id;
639 $this->vars['order'] = $order;
640
641 $this->format_render( __FUNCTION__ );
642 }
643
644 public function destroy() {
645 if ( filter_var( $this->params['id'], FILTER_VALIDATE_INT ) ) {
646 $this->check_nonce( 'destroy_order_' . $this->params['id'] );
647 $order = new OsOrderModel( $this->params['id'] );
648 if ( $order->delete() ) {
649 $status = LATEPOINT_STATUS_SUCCESS;
650 $response_html = __( 'Order Removed', 'latepoint' );
651 } else {
652 $status = LATEPOINT_STATUS_ERROR;
653 $response_html = __( 'Error Removing Order', 'latepoint' );
654 }
655 } else {
656 $status = LATEPOINT_STATUS_ERROR;
657 $response_html = __( 'Error Removing Order', 'latepoint' );
658 }
659 if ( $this->get_return_format() == 'json' ) {
660 $this->send_json( array( 'status' => $status, 'message' => $response_html ) );
661 }
662 }
663
664 /*
665 Index of orders
666 */
667
668 public function index() {
669
670 $per_page = OsSettingsHelper::get_number_of_records_per_page();
671 $page_number = isset($this->params['page_number']) ? $this->params['page_number'] : 1;
672
673 $this->vars['page_header'] = false;
674
675 $orders = new OsOrderModel();
676
677
678 // TABLE SEARCH FILTERS
679 $filter = $this->params['filter'] ?? false;
680 $query_args = [];
681 if ( $filter ) {
682 if ( ! empty( $filter['id'] ) ) {
683 $query_args['id'] = $filter['id'];
684 }
685 if ( ! empty( $filter['total'] ) ) {
686 $query_args['total'] = $filter['total'];
687 }
688 if ( ! empty( $filter['status'] ) ) {
689 $query_args['status'] = $filter['status'];
690 }
691 if ( ! empty( $filter['payment_status'] ) ) {
692 $query_args['payment_status'] = $filter['payment_status'];
693 }
694 if ( ! empty( $filter['fulfillment_status'] ) ) {
695 $query_args['fulfillment_status'] = $filter['fulfillment_status'];
696 }
697 if ( ! empty( $filter['confirmation_code'] ) ) {
698 $query_args['confirmation_code LIKE'] = '%' . $filter['confirmation_code'] . '%';
699 }
700
701 if ( ! empty( $filter['customer']['full_name'] ) ) {
702 $orders->select( LATEPOINT_TABLE_ORDERS . '.*, ' . LATEPOINT_TABLE_CUSTOMERS . '.first_name, ' . LATEPOINT_TABLE_CUSTOMERS . '.last_name' );
703 $orders->join( LATEPOINT_TABLE_CUSTOMERS, [ 'id' => LATEPOINT_TABLE_ORDERS . '.customer_id' ] );
704
705 $query_args[ 'concat_ws(" ", ' . LATEPOINT_TABLE_CUSTOMERS . '.first_name,' . LATEPOINT_TABLE_CUSTOMERS . '.last_name) LIKE' ] = '%' . $filter['customer']['full_name'] . '%';
706 $this->vars['customer_name_query'] = $filter['customer']['full_name'];
707
708 }
709
710 if ( ! empty( $filter['created_at_from'] ) && ! empty( $filter['created_at_to'] ) ) {
711 $query_args['created_at >='] = $filter['created_at_from'] . ' 00:00:00';
712 $query_args['created_at <='] = $filter['created_at_to'] . ' 23:59:59';
713 }
714 }
715
716
717 // OUTPUT CSV IF REQUESTED
718 if ( isset( $this->params['download'] ) && $this->params['download'] == 'csv' ) {
719 $csv_filename = 'payments_' . OsUtilHelper::random_text() . '.csv';
720
721 header( "Content-Type: text/csv" );
722 header( "Content-Disposition: attachment; filename={$csv_filename}" );
723
724 $labels_row = [
725 __( 'ID', 'latepoint' ),
726 __( 'Token', 'latepoint' ),
727 __( 'Booking ID', 'latepoint' ),
728 __( 'Customer', 'latepoint' ),
729 __( 'Processor', 'latepoint' ),
730 __( 'Method', 'latepoint' ),
731 __( 'Amount', 'latepoint' ),
732 __( 'Status', 'latepoint' ),
733 __( 'Type', 'latepoint' ),
734 __( 'Date', 'latepoint' )
735 ];
736
737
738 $orders_data = [];
739 $orders_data[] = $labels_row;
740
741
742 $orders_arr = $orders->where( $query_args )->filter_allowed_records()->get_results_as_models();
743
744 if ( $orders_arr ) {
745 foreach ( $orders_arr as $order ) {
746 $values_row = [
747 $order->id,
748 $order->token,
749 $order->booking_id,
750 ( $order->customer_id ? $order->customer->full_name : 'n/a' ),
751 $order->processor,
752 $order->payment_method,
753 OsMoneyHelper::format_price( $order->amount, true, false ),
754 $order->status,
755 $order->kind,
756 $order->created_at,
757 ];
758 $values_row = apply_filters( 'latepoint_order_row_for_csv_export', $values_row, $order, $this->params );
759 $orders_data[] = $values_row;
760 }
761
762 }
763
764 $orders_data = apply_filters( 'latepoint_orders_data_for_csv_export', $orders_data, $this->params );
765 OsCSVHelper::array_to_csv( $orders_data );
766
767 return;
768 }
769
770 if ( $query_args ) {
771 $orders->where( $query_args );
772 }
773 $orders->filter_allowed_records();
774
775
776 $count_orders = clone $orders;
777 $total_orders = $count_orders->count();
778
779 $orders = $orders->order_by( LATEPOINT_TABLE_ORDERS . '.created_at desc' )->set_limit( $per_page );
780 if ( $page_number > 1 ) {
781 $orders = $orders->set_offset( ( $page_number - 1 ) * $per_page );
782 }
783
784 $this->vars['orders'] = $orders->get_results_as_models();
785
786 $this->vars['total_orders'] = $total_orders;
787 $this->vars['current_page_number'] = $page_number;
788 $this->vars['per_page'] = $per_page;
789 $total_pages = ceil( $total_orders / $per_page );
790 $this->vars['total_pages'] = $total_pages;
791
792 $this->vars['showing_from'] = ( ( $page_number - 1 ) * $per_page ) ? ( ( $page_number - 1 ) * $per_page ) : 1;
793 $this->vars['showing_to'] = min( $page_number * $per_page, $total_orders );
794
795 $this->format_render( [
796 'json_view_name' => '_table_body',
797 'html_view_name' => __FUNCTION__
798 ], [], [
799 'total_pages' => $total_pages,
800 'showing_from' => $this->vars['showing_from'],
801 'showing_to' => $this->vars['showing_to'],
802 'total_records' => $total_orders
803 ] );
804 }
805
806
807 }
808
809
810 endif;