PluginProbe ʕ •ᴥ•ʔ
LatePoint – Calendar Booking Plugin for Appointments and Events / 5.1.1
LatePoint – Calendar Booking Plugin for Appointments and Events v5.1.1
5.6.7 5.6.6 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 / helpers / orders_helper.php
latepoint / lib / helpers Last commit date
activities_helper.php 1 year ago agent_helper.php 1 year ago auth_helper.php 1 year ago blocks_helper.php 1 year ago booking_helper.php 1 year ago bricks_helper.php 1 year ago bundles_helper.php 1 year ago calendar_helper.php 1 year ago carts_helper.php 1 year ago connector_helper.php 1 year ago csv_helper.php 1 year ago customer_helper.php 1 year ago database_helper.php 1 year ago debug_helper.php 1 year ago defaults_helper.php 1 year ago elementor_helper.php 1 year ago email_helper.php 1 year ago encrypt_helper.php 1 year ago events_helper.php 1 year ago form_helper.php 1 year ago icalendar_helper.php 1 year ago image_helper.php 1 year ago invoices_helper.php 1 year ago license_helper.php 1 year ago location_helper.php 1 year ago marketing_systems_helper.php 1 year ago meeting_systems_helper.php 1 year ago menu_helper.php 1 year ago meta_helper.php 1 year ago migrations_helper.php 1 year ago money_helper.php 1 year ago notifications_helper.php 1 year ago order_intent_helper.php 1 year ago orders_helper.php 1 year ago pages_helper.php 1 year ago params_helper.php 1 year ago payments_helper.php 1 year ago price_breakdown_helper.php 1 year ago process_jobs_helper.php 1 year ago processes_helper.php 1 year ago replacer_helper.php 1 year ago resource_helper.php 1 year ago roles_helper.php 1 year ago router_helper.php 1 year ago service_helper.php 1 year ago sessions_helper.php 1 year ago settings_helper.php 1 year ago shortcodes_helper.php 1 year ago sms_helper.php 1 year ago steps_helper.php 1 year ago stripe_connect_helper.php 1 year ago styles_helper.php 1 year ago support_topics_helper.php 1 year ago time_helper.php 1 year ago timeline_helper.php 1 year ago transaction_intent_helper.php 1 year ago util_helper.php 1 year ago version_specific_updates_helper.php 1 year ago work_periods_helper.php 1 year ago wp_datetime.php 1 year ago wp_user_helper.php 1 year ago
orders_helper.php
626 lines
1 <?php
2 /*
3 * Copyright (c) 2023 LatePoint LLC. All rights reserved.
4 */
5
6 class OsOrdersHelper {
7
8 /**
9 * @param $order_item_id
10 * @param $service_id
11 *
12 * @return OsBookingModel[]
13 */
14 public static function get_bookings_for_order_item( $order_item_id, $service_id = false, array $only_statuses = [] ): array {
15 $bookings = new OsBookingModel();
16 if ( $service_id ) {
17 $bookings = $bookings->where( [ 'service_id' => $service_id ] );
18 }
19 if ( ! empty( $only_statuses ) ) {
20 $bookings = $bookings->where( [ 'status' => $only_statuses ] );
21 }
22 $bookings = $bookings->where( [ 'order_item_id' => $order_item_id ] )->order_by( 'start_datetime_utc asc' )->get_results_as_models();
23
24 return $bookings;
25 }
26
27 public static function quick_order_btn_html( $order_id = false, $params = array() ) {
28 $html = '';
29 if ( $order_id ) {
30 $params['id'] = $order_id;
31 }
32 $route = OsRouterHelper::build_route_name( 'orders', 'quick_edit' );
33
34 $params_str = http_build_query( $params );
35 $html = 'data-os-params="' . esc_attr( $params_str ) . '"
36 data-os-action="' . esc_attr( $route ) . '"
37 data-os-output-target="side-panel"
38 data-os-after-call="latepoint_init_quick_order_form"';
39
40 return $html;
41 }
42
43 public static function get_order_statuses_list() {
44 $statuses = [
45 LATEPOINT_ORDER_STATUS_OPEN => __( 'Open', 'latepoint' ),
46 LATEPOINT_ORDER_STATUS_CANCELLED => __( 'Cancelled', 'latepoint' ),
47 LATEPOINT_ORDER_STATUS_COMPLETED => __( 'Completed', 'latepoint' )
48 ];
49
50 /**
51 * Get list of statuses for orders
52 *
53 * @param {array} $statuses array of order status codes
54 * @returns {array} The filtered array of status codes
55 *
56 * @since 5.0.0
57 * @hook latepoint_order_statuses
58 *
59 */
60 return apply_filters( 'latepoint_order_statuses', $statuses );
61 }
62
63 public static function bundle_services_and_booked_count_for_order_item_id( int $order_item_id ): array {
64 $order_item = new OsOrderItemModel( $order_item_id );
65 $bundle_services = [];
66 if ( $order_item->is_bundle() ) {
67 $bundle = $order_item->build_original_object_from_item_data();
68 $bundle_services = $bundle->get_services( $order_item_id );
69 }
70
71 return $bundle_services;
72 }
73
74
75 public static function get_items_for_order_id( $order_id ) {
76 $order_items = new OsOrderItemModel();
77
78 return $order_items->where( [ 'order_id' => $order_id ] )->get_results_as_models();
79 }
80
81 public static function create_order_item_from_cart_item( OsCartItemModel $cart_item ): OsOrderItemModel {
82 $order_item = new OsOrderItemModel();
83 $order_item->variant = $cart_item->variant;
84 $order_item->item_data = $cart_item->item_data;
85 $order_item->total = $cart_item->get_total();
86 $order_item->subtotal = $cart_item->get_subtotal();
87 $order_item->coupon_code = $cart_item->get_coupon_code();
88 $order_item->coupon_discount = $cart_item->get_coupon_discount();
89 $order_item->tax_total = $cart_item->get_tax_total();
90
91 return $order_item;
92 }
93
94
95 public static function get_fulfillment_statuses_list(): array {
96 $statuses = [
97 LATEPOINT_ORDER_FULFILLMENT_STATUS_NOT_FULFILLED => __( 'Not Fulfilled', 'latepoint' ),
98 LATEPOINT_ORDER_FULFILLMENT_STATUS_FULFILLED => __( 'Fulfilled', 'latepoint' ),
99 LATEPOINT_ORDER_FULFILLMENT_STATUS_PARTIALLY_FULFILLED => __( 'Partially Fulfilled', 'latepoint' )
100 ];
101
102 /**
103 * Get list of fulfillment statuses for orders
104 *
105 * @param {array} $statuses array of order fulfillment status codes
106 * @returns {array} The filtered array of fulfillment status codes
107 *
108 * @since 5.0.0
109 * @hook latepoint_order_fulfillment_statuses
110 *
111 */
112 return apply_filters( 'latepoint_order_fulfillment_statuses', $statuses );
113 }
114
115 public static function get_order_payment_statuses_list(): array {
116 $statuses = [
117 LATEPOINT_ORDER_PAYMENT_STATUS_NOT_PAID => __( 'Not Paid', 'latepoint' ),
118 LATEPOINT_ORDER_PAYMENT_STATUS_PARTIALLY_PAID => __( 'Partially Paid', 'latepoint' ),
119 LATEPOINT_ORDER_PAYMENT_STATUS_FULLY_PAID => __( 'Fully Paid', 'latepoint' ),
120 LATEPOINT_ORDER_PAYMENT_STATUS_PROCESSING => __( 'Processing', 'latepoint' ),
121 ];
122
123 /**
124 * Get list of fulfillment statuses for orders
125 *
126 * @param {array} $statuses array of order payment status codes
127 * @returns {array} The filtered array of payment status codes
128 *
129 * @since 5.0.0
130 * @hook latepoint_order_payment_statuses
131 *
132 */
133 return apply_filters( 'latepoint_order_payment_statuses', $statuses );
134 }
135
136 public static function get_default_order_status(): string {
137 $status = LATEPOINT_ORDER_STATUS_OPEN;
138
139 /**
140 * Get default order status
141 *
142 * @param {string} $status a default order status
143 * @returns {string} filtered status
144 *
145 * @since 5.0.0
146 * @hook latepoint_get_default_order_status
147 *
148 */
149 return apply_filters( 'latepoint_get_default_order_status', $status );
150 }
151
152
153 public static function get_nice_order_payment_status_name( $status ) {
154 $statuses_list = OsOrdersHelper::get_order_payment_statuses_list();
155 if ( $status && isset( $statuses_list[ $status ] ) ) {
156 return $statuses_list[ $status ];
157 } else {
158 return __( 'Undefined Status', 'latepoint' );
159 }
160 }
161
162 public static function get_nice_order_status_name( $status ) {
163 $statuses_list = OsOrdersHelper::get_order_statuses_list();
164 if ( $status && isset( $statuses_list[ $status ] ) ) {
165 return $statuses_list[ $status ];
166 } else {
167 return __( 'Undefined Status', 'latepoint' );
168 }
169 }
170
171 public static function get_nice_order_fulfillment_status_name( $status ) {
172 $statuses_list = OsOrdersHelper::get_fulfillment_statuses_list();
173 if ( $status && isset( $statuses_list[ $status ] ) ) {
174 return $statuses_list[ $status ];
175 } else {
176 return __( 'Undefined Status', 'latepoint' );
177 }
178 }
179
180
181 public static function unfold_price_breakdown_row( $rows ) {
182 $readable_price_breakdown = [];
183 foreach ( $rows as $row ) {
184 if ( empty( $row ) ) {
185 continue;
186 }
187 if ( ! empty( $row['heading'] ) && ! empty( $row['items'] ) ) {
188 $readable_price_breakdown = array_merge( $readable_price_breakdown, self::unfold_price_breakdown_row( $row['items'] ) );
189 } elseif ( ! empty( $row['label'] ) ) {
190 $label = $row['label'];
191 if ( ! empty( $row['note'] ) ) {
192 $label .= ' ' . $row['note'];
193 }
194 if ( ! empty( $row['badge'] ) ) {
195 $label .= ' (' . $row['badge'] . ')';
196 }
197 $readable_price_breakdown[ $label ] = $row['raw_value'] * 1;
198 } else {
199 $readable_price_breakdown = array_merge( $readable_price_breakdown, self::unfold_price_breakdown_row( $row ) );
200 }
201 }
202
203 return $readable_price_breakdown;
204 }
205
206
207 public static function generate_confirmation_message( OsOrderModel $order ): string {
208 $html = '<div class="summary-status-wrapper summary-status-style-' . esc_attr( OsStepsHelper::get_step_setting_value( 'confirmation', 'order_confirmation_message_style', 'green' ) ) . '">
209 <div class="summary-status-inner">
210 <div class="ss-icon"></div>
211 <div class="ss-title">' . OsStepsHelper::get_step_setting_value( 'confirmation', 'order_confirmation_message_title', esc_html__( 'Appointment Confirmed', 'latepoint' ) ) . '</div>
212 <div class="ss-description">' . OsStepsHelper::get_step_setting_value( 'confirmation', 'order_confirmation_message_content', esc_html__( 'We look forward to seeing you.', 'latepoint' ) ) . '</div>
213 <div class="ss-confirmation-number"><span>' . esc_html__( 'Order #', 'latepoint' ) . '</span><strong>' . esc_html( $order->confirmation_code ) . '</strong></div>
214 </div>
215 </div>';
216
217 return $html;
218 }
219
220
221 public static function generate_direct_manage_order_url( OsOrderModel $order, string $for, string $action = 'show' ): string {
222 if ( ! in_array( $for, [ 'agent', 'customer' ] ) ) {
223 return '';
224 }
225 $actions = [ 'show', 'list_payments' ];
226 if ( ! in_array( $action, $actions ) ) {
227 $action = $actions[0];
228 }
229 $key = $order->get_key_to_manage_for( $for );
230 $url = OsRouterHelper::build_admin_post_link( [ 'manage_order_by_key', $action ], [ 'key' => $key ] );
231
232 return $url;
233 }
234
235 public static function get_order_id_and_manage_ability_by_key( string $key ) {
236 $order_id = OsMetaHelper::get_order_id_by_meta_value( "key_to_manage_for_agent", $key );
237 if ( $order_id ) {
238 return [ 'order_id' => $order_id, 'for' => 'agent' ];
239 }
240
241 $order_id = OsMetaHelper::get_order_id_by_meta_value( "key_to_manage_for_customer", $key );
242 if ( $order_id ) {
243 return [ 'order_id' => $order_id, 'for' => 'customer' ];
244 }
245
246 return false;
247 }
248
249 public static function create_booking_object_from_booking_data_form( array $params ): OsBookingModel {
250 $booking = new OsBookingModel();
251
252 if ( ! empty( $params['item_data'] ) ) {
253 $item_data = json_decode( base64_decode( $params['item_data'] ), true );
254 $booking->set_data( $item_data );
255 } else {
256 $filtered_params = $params;
257 // input fields are formatted in customer preferred format, we need to convert that to database format Y-m-d
258 $filtered_params['start_date'] = OsTimeHelper::reformat_date_string( $params['start_date_formatted'], OsSettingsHelper::get_date_format(), 'Y-m-d' );
259
260
261 if ( isset( $params['start_time']['formatted_value'] ) ) {
262 $start_ampm = isset( $params['start_time']['ampm'] ) ? $params['start_time']['ampm'] : false;
263 $filtered_params['start_time'] = OsTimeHelper::convert_time_to_minutes( $params['start_time']['formatted_value'], $start_ampm );
264 }
265
266 // set custom end time/date if it was passed in params
267 if ( isset( $params['end_time']['formatted_value'] ) ) {
268 $end_ampm = isset( $params['end_time']['ampm'] ) ? $params['end_time']['ampm'] : false;
269 $filtered_params['end_time'] = OsTimeHelper::convert_time_to_minutes( $params['end_time']['formatted_value'], $end_ampm );
270 if ( $filtered_params['end_time'] <= $filtered_params['start_time'] ) {
271 // it's next day
272 $date_obj = new OsWpDateTime( $filtered_params['start_date'] );
273 $filtered_params['end_date'] = $date_obj->modify( '+1 day' )->format( 'Y-m-d' );
274 } else {
275 $filtered_params['end_date'] = $filtered_params['start_date'];
276 }
277 }
278 $booking->set_data( $filtered_params );
279 $booking->set_utc_datetimes();
280 }
281
282 return $booking;
283 }
284
285 public static function loading_tile_for_order_item( string $order_item_id ) {
286 return '<div class="order-item-temp-holder" data-order-item-id="' . $order_item_id . '"><div class="oit-avatar"></div><div class="oit-main-info"><div class="oit-title"></div><div class="oit-sub-title"></div></div></div>';
287 }
288
289 public static function booking_data_form_for_order_item_id( string $order_item_id, OsBookingModel $booking, string $order_item_variant = LATEPOINT_ITEM_VARIANT_BOOKING, bool $is_folded = true ): string {
290 $services = OsServiceHelper::get_allowed_active_services();
291 $agents = OsAgentHelper::get_allowed_active_agents();
292
293 $order_item_id = empty( $order_item_id ) ? OsUtilHelper::generate_form_id() : $order_item_id;
294
295 $extra_css_class = $is_folded ? 'is-folded' : 'is-unfolded';
296 $html = '';
297 $html = '<div class="order-item-booking-data-form-wrapper order-item-booking-data-variant-' . $order_item_variant . ' ' . $extra_css_class . '"
298 data-order-item-variant="' . $order_item_variant . '"
299 data-order-item-id="' . $order_item_id . '"
300 data-booking-id="' . $booking->get_form_id() . '">';
301 $html .= self::loading_tile_for_order_item( $order_item_id );
302 switch ( $order_item_variant ) {
303 case LATEPOINT_ITEM_VARIANT_BOOKING:
304 $html .= OsOrdersHelper::generate_order_item_pill_for_booking( $booking, $order_item_id );
305 break;
306 case LATEPOINT_ITEM_VARIANT_BUNDLE:
307 $html .= OsOrdersHelper::generate_order_item_pill_for_bundle_booking( $booking, $order_item_id );
308 break;
309 }
310 $html .= '<div class="order-booking-data-heading">
311 <div class="fold-order-item-wrapper fold-order-item-booking-data-form-btn">
312 <div class="fold-order-item-icon">
313 <i class="latepoint-icon latepoint-icon-chevron-up"></i>
314 </div>
315 <div class="ob-label">' . ( $booking->is_new_record() ? __( 'New Booking', 'latepoint' ) : __( 'Edit Booking', 'latepoint' ) ) . '</div>
316 </div>
317
318 <div class="remove-order-item-new-booking-btn remove-order-item-btn" data-os-prompt="' . __( 'Are you sure you want to remove this booking from the order?', 'latepoint' ) . '">
319 <i class="latepoint-icon latepoint-icon-trash1"></i>
320 </div>
321 </div>';
322 $html .= '<div class="order-item-booking-data-form-inner">';
323 $html .= OsFormHelper::hidden_field( 'order_items[' . $order_item_id . '][variant]', $order_item_variant );
324 ob_start();
325 include( LATEPOINT_VIEWS_ABSPATH . 'bookings/_booking_data.php' );
326 $html .= ob_get_clean();
327 $html .= '</div>';
328 $html .= '</div>';
329
330 return $html;
331 }
332
333
334 public static function get_orders_for_select() : array {
335 $order = new OsOrderModel();
336 $order = $order->order_by( 'id desc' )->set_limit( 100 )->get_results_as_models();
337 $order_options = [];
338 foreach ( $order as $order ) {
339 $name = $order->customer->full_name . ' [' . $order->confirmation_code . ' : ' . $order->id . ']';
340 $order_options[] = [ 'value' => $order->id, 'label' => esc_html( $name ) ];
341 }
342
343 return $order_options;
344 }
345
346 public static function generate_order_item_pill_for_bundle( OsBundleModel $bundle, $order_item_id = false, $preselected_booking_id = false ): string {
347 $html = '';
348 $order_item_form_id = $order_item_id ? $order_item_id : OsUtilHelper::generate_form_id();
349 $html .= '<div class="order-item-pill order-item-pill-variant-bundle" data-order-item-id="' . $order_item_form_id . '">';
350 $html .= '<input name="order_items[' . $order_item_form_id . '][id]" class="order_item_id" value="' . $order_item_form_id . '" type="hidden"/>';
351 $html .= '<input name="order_items[' . $order_item_form_id . '][variant]" value="' . LATEPOINT_ITEM_VARIANT_BUNDLE . '" type="hidden"/>';
352 $html .= '<input name="order_items[' . $order_item_form_id . '][item_data]" class="order_item_item_data" value="' . base64_encode( wp_json_encode( $bundle->generate_params_for_booking_form() ) ) . '" type="hidden"/>';
353 $html .= '<div class="order-item-pill-inner">';
354 $html .= '<div class="order-item-remove-btn remove-order-item-btn"
355 data-os-prompt="' . __( 'Are you sure you want to remove this item from the order? All associated appointments will be removed as well.', 'latepoint' ) . '"></div>';
356 $html .= OsBundlesHelper::generate_order_summary_for_bundle( $bundle, $order_item_form_id, $preselected_booking_id );
357 $html .= '<div class="bundle-icon"><i class="latepoint-icon latepoint-icon-chevron-down"></i></div>';
358 $html .= '</div>';
359 $html .= '<div class="order-item-shadow"></div><div class="order-item-shadow"></div>';
360 $html .= '</div>';
361
362 return $html;
363 }
364
365 public static function generate_order_item_pill_for_booking( OsBookingModel $booking, $order_item_id = false ): string {
366 $html = '';
367 $order_item_form_id = $order_item_id ? $order_item_id : OsUtilHelper::generate_form_id();
368 $is_past = ( ! $booking->is_upcoming() ) ? 'is-past' : '';
369 $html .= '<div class="order-item-pill order-item-pill-variant-' . LATEPOINT_ITEM_VARIANT_BOOKING . ' ' . $is_past . ' status-' . $booking->status . '" data-order-item-id="' . $order_item_form_id . '">';
370 $html .= '<input name="order_items[' . $order_item_form_id . '][id]" class="order_item_id" value="' . $order_item_form_id . '" type="hidden"/>';
371 $html .= '<input name="order_items[' . $order_item_form_id . '][variant]" value="' . LATEPOINT_ITEM_VARIANT_BOOKING . '" type="hidden"/>';
372 $html .= '<div class="order-item-pill-inner">';
373 $html .= '<div class="order-item-remove-btn remove-order-item-btn"
374 data-os-prompt="' . __( 'Are you sure you want to remove this item from the order?', 'latepoint' ) . '"></div>';
375 $html .= '<div class="booking-item-status-pill"></div>';
376 $html .= OsBookingHelper::generate_summary_for_booking( $booking, false, 'agent' );
377 $html .= '<div class="os-avatar-w" style="background-image: url(' . ( ( $booking->agent->avatar_image_id ) ? $booking->agent->get_avatar_url() : '' ) . ')">';
378 if ( ! $booking->agent->avatar_image_id ) {
379 $html .= '<div class="os-avatar"><span>' . $booking->agent->get_initials() . '</span></div>';
380 }
381 $html .= '</div>';
382 $html .= '</div>';
383 $html .= '</div>';
384
385 return $html;
386 }
387
388 public static function generate_order_item_pill_for_bundle_booking( OsBookingModel $booking, $order_item_id ): string {
389 $is_past = ( ! $booking->is_upcoming() ) ? 'is-past' : '';
390 $html = '<div class="bundle-booking-item-pill ' . $is_past . ' status-' . $booking->status . '">';
391 $html .= '<div class="bundle-booking-item-pill-inner">';
392 $html .= '<div class="booking-item-status-pill"></div>';
393 $html .= '<div class="bib-datetime">' . $booking->get_nice_start_datetime() . '</div>';
394 $html .= '</div>';
395 $html .= '</div>';
396
397 return $html;
398 }
399
400 public static function generate_booking_block_for_bundle_order_item( OsBookingModel $booking, $order_item_id, bool $is_booked = true, $is_preselected = false ): string {
401 $html = '';
402 $is_booked_css = $is_booked ? 'is-booked' : '';
403 $is_preselected_css = ( $is_preselected ? 'is-preselected' : '' );
404
405 $html .= '<div class="order-item-variant-bundle-booking ' . $is_booked_css . ' ' . $is_preselected_css . '"
406 data-order-item-variant="' . LATEPOINT_ITEM_VARIANT_BUNDLE . '"
407 data-order-item-id="' . $order_item_id . '"
408 data-booking-id="' . $booking->get_form_id() . '">';
409 $html .= '<div class="scheduled-bundle-booking">';
410 $html .= self::loading_tile_for_order_item( $order_item_id );
411 if ( $is_booked ) {
412 $html .= OsOrdersHelper::booking_data_form_for_order_item_id( $order_item_id, $booking, LATEPOINT_ITEM_VARIANT_BUNDLE, ! $is_preselected );
413 }
414 $html .= '</div>';
415 $html .= '<div class="unscheduled-bundle-booking">
416 <div class="booking-item-status-pill"></div>
417 <div class="bib-label">' . __( 'Schedule now', 'latepoint' ) . '</div>
418 <input name="order_items[' . $order_item_id . '][unscheduled_bookings][' . $booking->get_form_id() . '][item_data]" class="unscheduled_booking_item_data" value="' . base64_encode( wp_json_encode( $booking->generate_params_for_booking_form() ) ) . '" type="hidden"/>
419 </div>';
420 $html .= '</div>';
421
422 return $html;
423 }
424
425 public static function generate_price_breakdown_from_params( array $price_breakdown_params ): array {
426 $price_breakdown_rows = [];
427 $allowed_keys = [ 'before_subtotal', 'after_subtotal' ];
428 foreach ( $allowed_keys as $key ) {
429 if ( ! empty( $price_breakdown_params[ $key ] ) ) {
430 foreach ( $price_breakdown_params[ $key ] as $row ) {
431 if ( ! empty( $row['items'] ) ) {
432 $group = [ 'heading' => '', 'items' => [], 'sub_items' => [] ];
433 if ( ! empty( $row['heading'] ) ) {
434 $group['heading'] = $row['heading'];
435 }
436 foreach ( $row['items'] as $item ) {
437 if ( isset( $item['value'] ) ) {
438 $item['raw_value'] = OsMoneyHelper::convert_amount_from_money_input_to_db_format( $item['value'] );
439 }
440 $group['items'][] = $item;
441 }
442 if ( ! empty( $row['sub_items'] ) ) {
443 foreach ( $row['sub_items'] as $sub_item ) {
444 if ( isset( $sub_item['value'] ) ) {
445 $sub_item['raw_value'] = OsMoneyHelper::convert_amount_from_money_input_to_db_format( $sub_item['value'] );
446 }
447 $group['sub_items'][] = $sub_item;
448 }
449 }
450 $price_breakdown_rows[ $key ][] = $group;
451 } else {
452 if ( isset( $row['value'] ) ) {
453 $row['raw_value'] = OsMoneyHelper::convert_amount_from_money_input_to_db_format( $row['value'] );
454 }
455 $price_breakdown_rows[ $key ][] = $row;
456 }
457 }
458 }
459 }
460
461 return $price_breakdown_rows;
462 }
463
464 public static function create_order_item_object( array $order_items_param ): OsOrderItemModel {
465 $order_item_model = new OsOrderItemModel();
466 $order_item_model->variant = $order_items_param['variant'];
467 if ( $order_item_model->is_bundle() ) {
468 $order_item_model->item_data = base64_decode( $order_items_param['item_data'] );
469 } else {
470 // it's a booking variant - so there is only one booking in the array, but still loop for ease of use
471 foreach ( $order_items_param['bookings'] as $booking_params ) {
472 $booking = OsOrdersHelper::create_booking_object_from_booking_data_form( $booking_params );
473 $order_item_model->item_data = $booking->generate_item_data();
474 }
475 }
476
477 return $order_item_model;
478 }
479
480 public static function generate_transactions_breakdown_html( OsOrderModel $order ): string {
481 $html = '';
482 $transactions = $order->get_transactions();
483 if ( $transactions ) {
484 $html .= '<div style="margin: 20px 0;">';
485 foreach ( $transactions as $transaction ) {
486 $html .= '<div style="margin-bottom: 10px;">';
487 $html .= '<div>' . esc_html__( 'Payment Portion: ', 'latepoint' ) . '<strong>' . $transaction->get_payment_portion_nice_name() . '</strong></div>';
488 $html .= '<div>' . esc_html__( 'Payment Amount: ', 'latepoint' ) . '<strong>' . OsMoneyHelper::format_price( $transaction->amount, true, false ) . '</strong></div>';
489 $html .= '</div>';
490 }
491 $html .= '</div>';
492 } else {
493 $html .= esc_html__( 'No transactions found.', 'latepoint' );
494 }
495
496 return $html;
497 }
498
499 public static function generate_summary_breakdown_html( OsOrderModel $order ): string {
500 ob_start();
501 OsPriceBreakdownHelper::output_price_breakdown( $order->generate_price_breakdown_rows(), true );
502 $html = ob_get_clean();
503
504 return $html;
505 }
506
507 public static function generate_order_items_html( OsOrderModel $order ) {
508 $html = '';
509 $order_items = $order->get_items();
510 $html .= '<table style="width: 100%;">';
511 $total_items = count( $order_items );
512 $i = 0;
513 foreach ( $order_items as $order_item ) {
514 $i ++;
515 $html .= '<tr>';
516 $data_style = ( $i < $total_items ) ? 'border-bottom: 1px solid #eee;' : '';
517 $html .= '<td style="' . $data_style . ' padding: 10px 0;">';
518 if ( $order_item->is_bundle() ) {
519 $bundle = $order_item->build_original_object_from_item_data();
520 $html .= '<div>' . $bundle->name . '</div>';
521 $bundle_services = $bundle->get_services();
522 foreach ( $bundle_services as $service ) {
523 $qty = $service->join_attributes['quantity'];
524 $qty_html = $qty > 1 ? ' [' . $qty . ']' : '';
525 $html .= '<div style="color: #999; font-size: 14px;">' . esc_html( $service->name . $qty_html ) . '</div>';
526 }
527 } else {
528 $booking = $order_item->build_original_object_from_item_data();
529 $html .= '<div style="font-weight: bold;">' . $booking->service->name . '</div>';
530 $html .= '<div>' . $booking->get_nice_start_datetime() . '</div>';
531 $html .= '<div>' . $booking->agent->get_full_name() . '</div>';
532 }
533 $html .= '</td>';
534 $html .= '</tr>';
535 }
536 $html .= '</table>';
537
538 return $html;
539 }
540
541 public static function extract_agent_emails( OsOrderModel $order ): string {
542 $to_emails = [];
543 $order_items = $order->get_items();
544 foreach ( $order_items as $order_item ) {
545 if ( $order_item->is_bundle() ) {
546 $bundle_bookings = OsOrdersHelper::get_bookings_for_order_item( $order_item->id );
547 foreach ( $bundle_bookings as $booking ) {
548 $to_emails[] = $booking->agent->get_full_name() . ' <' . $booking->agent->email . '>';
549 }
550 } else {
551 // booking
552 $booking = $order_item->build_original_object_from_item_data();
553 $to_emails[] = $booking->agent->get_full_name() . ' <' . $booking->agent->email . '>';
554 }
555 }
556 $to_emails = array_unique( $to_emails );
557
558 return implode( ', ', $to_emails );
559 }
560
561 public static function extract_agent_full_names( OsOrderModel $order ): string {
562 $full_names = [];
563 $order_items = $order->get_items();
564 foreach ( $order_items as $order_item ) {
565 if ( $order_item->is_bundle() ) {
566 $bundle_bookings = OsOrdersHelper::get_bookings_for_order_item( $order_item->id );
567 foreach ( $bundle_bookings as $booking ) {
568 $full_names[] = $booking->agent->get_full_name();
569 }
570 } else {
571 // booking
572 $booking = $order_item->build_original_object_from_item_data();
573 $full_names[] = $booking->agent->get_full_name();
574 }
575 }
576 $full_names = array_unique( $full_names );
577
578 return implode( ', ', $full_names );
579 }
580
581
582
583 /**
584 * Extract property by name from order. For example, location_id, agent_id...
585 * @param OsOrderModel $order
586 * @param string $property
587 *
588 * @return string
589 */
590 public static function extract_property_by_name( OsOrderModel $order, string $property ): string {
591 $property_values = [];
592 $order_items = $order->get_items();
593
594 $property_map = [
595 'service_ids' => 'service_id',
596 'location_ids' => 'location_id',
597 'agent_ids' => 'agent_id',
598 'bundle_ids' => 'bundle_id'
599 ];
600
601 if(empty($property_map[$property])){
602 return '';
603 }
604 $mapped_property = $property_map[$property];
605
606 foreach ( $order_items as $order_item ) {
607 if ( $order_item->is_bundle() ) {
608 if ($mapped_property == 'bundle_id') {
609 $property_values[] = $order_item->get_item_data_value_by_key( 'bundle_id' );
610 } else {
611 $bundle_bookings = OsOrdersHelper::get_bookings_for_order_item( $order_item->id );
612 $property_values = array_merge( $property_values, array_column( $bundle_bookings, $mapped_property ) );
613 }
614 } else {
615 $booking = $order_item->build_original_object_from_item_data();
616 if ( ! empty( $booking->$mapped_property ) ) {
617 $property_values[] = $booking->$mapped_property;
618 }
619 }
620 }
621
622 return implode( ',', array_unique( $property_values ) );
623 }
624
625 }
626