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