PluginProbe
PostNL for WooCommerce / 5.9.12
PostNL for WooCommerce v5.9.12
5.9.12 5.9.11 5.9.10 5.9.9 5.9.8 5.9.7 5.9.6 trunk 2.5.0 2.5.1 2.5.2 2.5.3 2.5.4 2.5.5 3.1.4 3.1.5 3.1.6 3.1.7 4.0.0 4.0.1 4.0.2 4.3.2 4.3.3 4.4.0 4.4.1 All 72 releases
woo-postnl / src / Checkout_Blocks / Extend_Block_Core.php

Extend_Block_Core.php in PostNL for WooCommerce 5.9.12, at src/Checkout_Blocks/Extend_Block_Core.php

648 lines 23.7 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2
3 namespace PostNLWooCommerce\Checkout_Blocks;
4
5 use function PostNLWooCommerce\postnl;
6 use PostNLWooCommerce\Frontend\Delivery_Day;
7 use PostNLWooCommerce\Frontend\Dropoff_Points;
8 use PostNLWooCommerce\Frontend\Container;
9 use PostNLWooCommerce\Frontend\Checkout_Fields;
10 use PostNLWooCommerce\Utils;
11 use PostNLWooCommerce\Address_Utils;
12
13 if ( ! defined( 'ABSPATH' ) ) {
14 exit;
15 }
16
17 class Extend_Block_Core {
18
19 /**
20 * Plugin Identifier, unique to each plugin.
21 *
22 * @var string
23 */
24 private $name = 'postnl';
25
26 /**
27 * Settings class instance.
28 *
29 * @var Settings
30 */
31 protected $settings;
32
33 /**
34 * Bootstraps the class and hooks required data.
35 */
36 public function __construct() {
37
38 $this->settings = postnl()->get_shipping_settings();
39
40 // Initialize hooks
41 add_action(
42 'woocommerce_store_api_checkout_update_order_from_request',
43 array(
44 $this,
45 'save_postnl_checkout_fields',
46 ),
47 10,
48 2
49 );
50
51 // Register the update callback when WooCommerce Blocks is loaded
52 add_action( 'init', array( $this, 'register_store_api_callback' ) );
53 add_action( 'woocommerce_cart_calculate_fees', array( $this, 'postnl_add_custom_fee' ) );
54 add_filter( 'woocommerce_package_rates', array( $this, 'add_postnl_fees_to_rates' ), 20, 2 );
55
56 if ( $this->settings->is_reorder_nl_address_enabled() ) {
57 $this->register_additional_checkout_fields();
58 }
59
60 // Validate adress in cart
61 add_action( 'woocommerce_store_api_cart_errors', array( $this, 'postnl_validate_address_in_cart' ), 10, 2 );
62
63 /**
64 * Registers AJAX actions.
65 */
66 add_action( 'wp_ajax_postnl_set_checkout_post_data', array( $this, 'handle_set_checkout_post_data' ) );
67 add_action( 'wp_ajax_nopriv_postnl_set_checkout_post_data', array( $this, 'handle_set_checkout_post_data' ) );
68 }
69
70
71 /**
72 * Validate address in cart.
73 * Only shows validation error for NL addresses.
74 */
75 public function postnl_validate_address_in_cart( $errors, $cart ) {
76 // Only validate NL addresses
77 $shipping_country = WC()->customer ? WC()->customer->get_shipping_country() : '';
78 if ( 'NL' !== $shipping_country ) {
79 // Clear any stale invalid marker for non-NL countries
80 WC()->session->__unset( POSTNL_SETTINGS_ID . '_invalid_address_marker' );
81 return;
82 }
83
84 $invalid_marker = WC()->session->get( POSTNL_SETTINGS_ID . '_invalid_address_marker', false );
85
86 if ( $invalid_marker ) {
87 $errors->add(
88 'invalid_address',
89 esc_html__( 'This is not a valid address!', 'postnl-for-woocommerce' )
90 );
91 }
92 }
93
94 /**
95 * Register additional checkout fields .
96 */
97 public function register_additional_checkout_fields() {
98 add_action(
99 'init',
100 function () {
101 woocommerce_register_additional_checkout_field(
102 array(
103 'id' => 'postnl/house_number',
104 'label' => __( 'House number', 'postnl-for-woocommerce' ),
105 'location' => 'address',
106 'required' => false,
107 'attributes' => array(
108 'autocomplete' => 'house_number',
109 ),
110 ),
111 );
112 }
113 );
114 }
115
116 /**
117 * Register the update callback with WooCommerce Store API
118 */
119 public function register_store_api_callback() {
120 if ( function_exists( 'woocommerce_store_api_register_update_callback' ) ) {
121 woocommerce_store_api_register_update_callback(
122 array(
123 'namespace' => $this->name,
124 'callback' => array( $this, 'postnl_store_api_callback' ),
125 )
126 );
127 }
128 }
129
130 /**
131 * Callback function for the Store API update
132 *
133 * @param array $data Data sent from the client.
134 */
135 public function postnl_store_api_callback( $data ) {
136 if ( isset( $data['action'] ) && 'update_delivery_fee' === $data['action'] ) {
137 $price = isset( $data['price'] ) ? floatval( $data['price'] ) : 0;
138 $type = isset( $data['type'] ) ? sanitize_text_field( $data['type'] ) : '';
139
140 // Store the fee amount and type in session
141 WC()->session->set( 'postnl_delivery_fee', $price );
142 WC()->session->set( 'postnl_delivery_type', $type );
143 } else {
144 WC()->session->__unset( 'postnl_delivery_fee' );
145 WC()->session->__unset( 'postnl_delivery_type' );
146 }
147 }
148
149 /**
150 * Adds the delivery fee to the WooCommerce cart.
151 *
152 * Morning/evening delivery fees are folded directly into the shipping rate
153 * cost via add_postnl_fees_to_rates(), so no separate fee line item is added.
154 *
155 * @param \WC_Cart $cart The WooCommerce cart object.
156 */
157 public function postnl_add_custom_fee( $cart ) {
158 return;
159 }
160
161 /**
162 * Add Postnl fees to the supported shipping rates
163 *
164 * @param array $rates
165 * @param array $package
166 * @return array
167 */
168 public function add_postnl_fees_to_rates( $rates, $package ) {
169 if ( Utils::is_free_shipping_applied() ) {
170 return $rates;
171 }
172
173 // Letterbox-eligible carts are owned by the variant emitters
174 // (inject_letterbox_rates_for_all_methods + PostNL::calculate_shipping).
175 // No tab-based extras apply on top — per spec, when ALA triggers the
176 // home delivery / pickup / delivery day surcharges are ignored.
177 if ( Utils::is_cart_eligible_auto_letterbox( WC()->cart ) ) {
178 return $rates;
179 }
180
181 $session_type = WC()->session->get( 'postnl_delivery_type', '' );
182 if ( '' === $session_type ) {
183 return $rates;
184 }
185
186 $pickup_fee = $this->settings->get_pickup_delivery_fee();
187 $base_day_fee = $this->settings->get_delivery_days_fee();
188 $supported = $this->settings->get_supported_shipping_methods();
189
190 foreach ( $rates as $rate_id => $rate ) {
191
192 if ( ! in_array( $rate->get_method_id(), $supported, true ) ) {
193 continue;
194 }
195
196 // PostNL threshold-based free shipping: the rate was registered with
197 // cost = 0 by PostNL::calculate_shipping(). Do not inject any fees.
198 if ( 0.0 === (float) $rate->cost ) {
199 continue;
200 }
201
202 $extra = 0;
203
204 if ( 'Pickup' === $session_type && $pickup_fee > 0 ) {
205 $extra = $pickup_fee;
206 } elseif ( 'Pickup' !== $session_type ) {
207 // Fold both the tab base fee and any morning/evening extra fee into the rate.
208 $extra = $base_day_fee + (float) WC()->session->get( 'postnl_delivery_fee', 0 );
209 }
210
211 if ( $extra <= 0 ) {
212 continue;
213 }
214
215 $rate->cost += $extra;
216
217 if ( wc_tax_enabled() && 'taxable' === $rate->get_tax_status() ) {
218 $tax_rates = \WC_Tax::get_shipping_tax_rates();
219 $rate->taxes = \WC_Tax::calc_shipping_tax( $rate->cost, $tax_rates );
220 }
221 }
222
223 return $rates;
224 }
225
226 /**
227 * Get the carrier base cost by reading the currently-selected PostNL rate
228 * and subtracting the PostNL fees that were injected into it.
229 *
230 * The injected amount is: tab base fee + session extra fee (morning/evening).
231 * Returns the raw carrier cost before PostNL touched the rate.
232 *
233 * @return float Carrier base cost (≥ 0), pre-tax.
234 */
235 private function get_carrier_base_cost_for_blocks(): float {
236 $session_type = WC()->session->get( 'postnl_delivery_type', '' );
237 $session_fee = (float) WC()->session->get( 'postnl_delivery_fee', 0 );
238 $pickup_fee = (float) $this->settings->get_pickup_delivery_fee();
239 $base_day_fee = (float) $this->settings->get_delivery_days_fee();
240 $supported = $this->settings->get_supported_shipping_methods();
241
242 $injected = 0.0;
243 if ( 'Pickup' === $session_type ) {
244 $injected = $pickup_fee;
245 } elseif ( '' !== $session_type ) {
246 $injected = $base_day_fee + $session_fee;
247 }
248
249 $chosen = WC()->session ? WC()->session->get( 'chosen_shipping_methods', array() ) : array();
250 WC()->cart->calculate_shipping();
251 $packages = WC()->shipping()->get_packages();
252
253 foreach ( $packages as $i => $package ) {
254 $method_key = $chosen[ $i ] ?? '';
255
256 if ( ! isset( $package['rates'][ $method_key ] ) ) {
257 continue;
258 }
259
260 $rate = $package['rates'][ $method_key ];
261
262 if ( in_array( $rate->get_method_id(), $supported, true ) ) {
263 return max( 0.0, (float) $rate->cost - $injected );
264 }
265 }
266
267 return 0.0;
268 }
269
270 /**
271 * Check whether a supported PostNL shipping method is the chosen method.
272 *
273 * Used to detect PostNL threshold-based free shipping: if a PostNL method is
274 * selected but its carrier base cost is 0, the minimum_for_free_shipping
275 * threshold has been reached and all PostNL fees should be suppressed.
276 *
277 * @return bool
278 */
279 private function is_postnl_method_chosen(): bool {
280 $chosen = WC()->session ? WC()->session->get( 'chosen_shipping_methods', array() ) : array();
281 $packages = WC()->shipping()->get_packages();
282 $supported = $this->settings->get_supported_shipping_methods();
283
284 foreach ( $packages as $i => $package ) {
285 $method_key = $chosen[ $i ] ?? '';
286 if ( isset( $package['rates'][ $method_key ] ) && in_array( $package['rates'][ $method_key ]->get_method_id(), $supported, true ) ) {
287 return true;
288 }
289 }
290
291 return false;
292 }
293
294 /**
295 * Saves the PostNL delivery day or dropoff points fields to the order's metadata.
296 *
297 * @param \WC_Order $order Order object.
298 * @param \WP_REST_Request $request REST request object.
299 */
300 public function save_postnl_checkout_fields( \WC_Order $order, \WP_REST_Request $request ) {
301
302 $postnl_request_data = $request['extensions'][ $this->name ];
303
304 // Extract billing and shipping house numbers with sanitization
305 $shipping_house_number = '';
306
307 if ( ! empty( $postnl_request_data['houseNumber'] ) && $this->settings->is_reorder_nl_address_enabled() ) {
308 $shipping_house_number = sanitize_text_field( $postnl_request_data['houseNumber'] );
309 }
310 // Update billing and shipping house numbers
311 $order->update_meta_data( '_shipping_house_number', $shipping_house_number );
312
313 /**
314 * Prepare Pickup Data
315 */
316 $drop_data = array(
317 'frontend' => array(
318 'dropoff_points' => isset( $postnl_request_data['dropoffPoints'] ) ? sanitize_text_field( $postnl_request_data['dropoffPoints'] ) : '',
319 'dropoff_points_address_company' => isset( $postnl_request_data['dropoffPointsAddressCompany'] ) ? sanitize_text_field( $postnl_request_data['dropoffPointsAddressCompany'] ) : '',
320 'dropoff_points_distance' => isset( $postnl_request_data['dropoffPointsDistance'] ) ? sanitize_text_field( $postnl_request_data['dropoffPointsDistance'] ) : '',
321 'dropoff_points_address_address_1' => isset( $postnl_request_data['dropoffPointsAddress1'] ) ? sanitize_text_field( $postnl_request_data['dropoffPointsAddress1'] ) : '',
322 'dropoff_points_address_address_2' => isset( $postnl_request_data['dropoffPointsAddress2'] ) ? sanitize_text_field( $postnl_request_data['dropoffPointsAddress2'] ) : '',
323 'dropoff_points_address_city' => isset( $postnl_request_data['dropoffPointsCity'] ) ? sanitize_text_field( $postnl_request_data['dropoffPointsCity'] ) : '',
324 'dropoff_points_address_postcode' => isset( $postnl_request_data['dropoffPointsPostcode'] ) ? sanitize_text_field( $postnl_request_data['dropoffPointsPostcode'] ) : '',
325 'dropoff_points_address_country' => isset( $postnl_request_data['dropoffPointsCountry'] ) ? sanitize_text_field( $postnl_request_data['dropoffPointsCountry'] ) : '',
326 'dropoff_points_partner_id' => isset( $postnl_request_data['dropoffPointsPartnerID'] ) ? sanitize_text_field( $postnl_request_data['dropoffPointsPartnerID'] ) : '',
327 'dropoff_points_date' => isset( $postnl_request_data['dropoffPointsDate'] ) ? sanitize_text_field( $postnl_request_data['dropoffPointsDate'] ) : '',
328 'dropoff_points_time' => isset( $postnl_request_data['dropoffPointsTime'] ) ? sanitize_text_field( $postnl_request_data['dropoffPointsTime'] ) : '',
329 'dropoff_points_type' => isset( $postnl_request_data['dropoffPointsType'] ) ? sanitize_text_field( $postnl_request_data['dropoffPointsType'] ) : '',
330 ),
331 );
332
333 /**
334 * Prepare Delivery Day Data
335 */
336 $delivery_day_data = array(
337 'frontend' => array(
338 'delivery_day' => isset( $postnl_request_data['deliveryDay'] ) ? sanitize_text_field( $postnl_request_data['deliveryDay'] ) : '',
339 'delivery_day_date' => isset( $postnl_request_data['deliveryDayDate'] ) ? sanitize_text_field( $postnl_request_data['deliveryDayDate'] ) : '',
340 'delivery_day_from' => isset( $postnl_request_data['deliveryDayFrom'] ) ? sanitize_text_field( $postnl_request_data['deliveryDayFrom'] ) : '',
341 'delivery_day_to' => isset( $postnl_request_data['deliveryDayTo'] ) ? sanitize_text_field( $postnl_request_data['deliveryDayTo'] ) : '',
342 'delivery_day_price' => isset( $postnl_request_data['deliveryDayPrice'] ) ? sanitize_text_field( $postnl_request_data['deliveryDayPrice'] ) : '',
343 'delivery_day_type' => isset( $postnl_request_data['deliveryDayType'] ) ? sanitize_text_field( $postnl_request_data['deliveryDayType'] ) : '',
344 ),
345 );
346
347 if ( ! empty( $drop_data['frontend']['dropoff_points'] ) ) {
348 $order->update_meta_data( '_postnl_order_metadata', $drop_data );
349 } elseif ( ! empty( $delivery_day_data['frontend']['delivery_day'] ) ) {
350 // Save Delivery Day Data
351 $order->update_meta_data( '_postnl_order_metadata', $delivery_day_data );
352 }
353
354 // Save letterbox type from shipping method selection.
355 $this->save_letterbox_type_from_shipping( $order );
356
357 /**
358 * Save the order to persist changes
359 */
360 $order->save_meta_data();
361 }
362
363 /**
364 * Save the letterbox type from the selected shipping method in blocks checkout.
365 *
366 * @param \WC_Order $order Order object.
367 */
368 private function save_letterbox_type_from_shipping( $order ) {
369 $shipping_methods = $order->get_shipping_methods();
370 if ( empty( $shipping_methods ) ) {
371 return;
372 }
373
374 $supported = $this->settings->get_supported_shipping_methods();
375 $valid = array( 'letterbox', 'letterbox_48' );
376
377 foreach ( $shipping_methods as $shipping_item ) {
378 // Restrict to PostNL-supported methods so a third-party plugin's
379 // own 'letterbox_type' shipping-item meta cannot leak into ours.
380 if ( ! in_array( $shipping_item->get_method_id(), $supported, true ) ) {
381 continue;
382 }
383
384 $letterbox_type = $shipping_item->get_meta( 'letterbox_type' );
385 if ( in_array( $letterbox_type, $valid, true ) ) {
386 $order->update_meta_data( '_postnl_letterbox_type', $letterbox_type );
387 return;
388 }
389 }
390 }
391
392 /**
393 * Handle AJAX request to set checkout post data and return updated delivery options.
394 */
395 public function handle_set_checkout_post_data() {
396
397 // Verify nonce
398 if ( ! isset( $_POST['nonce'] ) || ! wp_verify_nonce( sanitize_text_field( wp_unslash( $_POST['nonce'] ) ), 'postnl_delivery_day_nonce' ) ) {
399 wp_send_json_error( array( 'message' => 'Invalid nonce' ), 400 );
400 wp_die();
401 }
402
403 // Check if data is provided
404 if ( ! isset( $_POST['data'] ) || ! is_array( $_POST['data'] ) ) {
405 wp_send_json_error( array( 'message' => 'No data provided.' ), 400 );
406 wp_die();
407 }
408
409 // Sanitize data
410 $sanitized_data = array_map( 'sanitize_text_field', wp_unslash( $_POST['data'] ) );
411
412 $original_shipping_address_1 = $sanitized_data['shipping_address_1'] ?? '';
413
414 $sanitized_data = Address_Utils::set_post_data_address( $sanitized_data );
415
416 $shipping_country = isset( $sanitized_data['shipping_country'] ) ? $sanitized_data['shipping_country'] : '';
417
418 // Save the house number and postcode on WC customer if provided
419 if ( isset( $sanitized_data['shipping_house_number'] ) && isset( $sanitized_data['shipping_postcode'] ) ) {
420 WC()->customer->set_shipping_postcode( $sanitized_data['shipping_postcode'] );
421 WC()->customer->update_meta_data( '_wc_shipping/postnl/house_number', $sanitized_data['shipping_house_number'] );
422 WC()->customer->set_shipping_country( $sanitized_data['shipping_country'] );
423 WC()->customer->set_shipping_address_2( $sanitized_data['shipping_address_2'] ?? '' );
424 WC()->customer->save();
425 }
426
427 // If not NL, clear session and return
428 if ( ! in_array( $shipping_country, array( 'NL', 'BE' ), true ) ) {
429 Utils::clear_postnl_checkout_session();
430 wp_send_json_success(
431 array(
432 'message' => 'No delivery options available outside NL.',
433 'show_container' => false,
434 'delivery_options' => array(),
435 'dropoff_options' => array(),
436 ),
437 200
438 );
439 wp_die();
440 }
441
442 // Check if required fields are present
443 if (
444 empty( $sanitized_data['shipping_postcode'] )
445 ||
446 (
447 $this->settings->is_reorder_nl_address_enabled()
448 && empty( $sanitized_data['shipping_house_number'] )
449 && 'NL' == $shipping_country
450 ) ) {
451 Utils::clear_postnl_checkout_session();
452 wp_send_json_success(
453 array(
454 'message' => esc_html__( 'Postcode or house number is missing.', 'postnl-for-woocommerce' ),
455 'show_container' => false,
456 'delivery_options' => array(),
457 'dropoff_options' => array(),
458 ),
459 200
460 );
461 wp_die();
462 }
463
464 // Retrieve previously sanitized data from session
465 $previous_sanitized_data = WC()->session->get( 'postnl_checkout_post_data' );
466 $address_changed = $previous_sanitized_data !== $sanitized_data;
467
468 if ( $address_changed ) {
469 // Clear previous validated address
470 WC()->session->__unset( POSTNL_SETTINGS_ID . '_validated_address' );
471 }
472
473 // Retrieve validated address from session
474 $validated_address = WC()->session->get( POSTNL_SETTINGS_ID . '_validated_address' );
475
476 // Construct without registering hooks: this instance is only used for its
477 // helper methods below. The bootstrap Container (Main::get_frontend(), fired
478 // on the init hook — which also runs during admin-ajax) already owns the
479 // global woocommerce_package_rates filters. Re-registering them here would
480 // run inject_letterbox_rates_for_all_methods twice during this request's
481 // shipping calculation and duplicate the letterbox 24h/48h rates.
482 $container = new Container( false );
483
484 // If validation is enabled and address changed or not validated yet
485 if ( $container->is_address_validation_required() && 'NL' === $shipping_country && ( $address_changed || empty( $validated_address ) ) ) {
486 try {
487 $container->validated_address( $sanitized_data );
488 // Attempt to fetch validated address again
489 $validated_address = WC()->session->get( POSTNL_SETTINGS_ID . '_validated_address' );
490 } catch ( \Exception $e ) {
491
492 }
493 }
494
495 // Store data in WooCommerce session
496 WC()->session->set( 'postnl_checkout_post_data', $sanitized_data );
497
498 // Save address_1 and city if available
499 if (
500 ! empty( $validated_address )
501 && isset( $validated_address['street'], $validated_address['city'] )
502 && $validated_address['street'] !== ''
503 && $validated_address['city'] !== ''
504 ) {
505 // Use validated data
506 if ( $this->settings->is_reorder_nl_address_enabled() ) {
507 // Separate house number field is enabled, use street only
508 WC()->customer->set_shipping_address_1( $validated_address['street'] );
509 } else {
510 // House number is part of address_1, combine street and house number.
511 $house_number = $validated_address['house_number'] ?? '';
512 $address_1 = $validated_address['street'] . ' ' . $house_number;
513 WC()->customer->set_shipping_address_1( $address_1 );
514 }
515
516 WC()->customer->set_shipping_city( $validated_address['city'] );
517 } else {
518 if ( $this->settings->is_reorder_nl_address_enabled() ) {
519 WC()->customer->set_shipping_address_1( $sanitized_data['shipping_address_1'] ?? '' );
520 } else {
521 WC()->customer->set_shipping_address_1( $original_shipping_address_1 );
522 }
523 WC()->customer->set_shipping_city( $sanitized_data['shipping_city'] ?? '' );
524 WC()->customer->set_shipping_state( $sanitized_data['shipping_state'] ?? '' );
525 }
526
527 // Save the customer data
528 WC()->customer->save();
529
530 // Check letterbox (ALA) eligibility *after* the customer's shipping
531 // country has been persisted above. is_cart_eligible_auto_letterbox()
532 // reads that saved country, so evaluating it earlier made the first
533 // AJAX call on a fresh session read a stale country and wrongly report
534 // not-eligible — which left the blocks delivery-day / pickup tabs
535 // unblocked until a full page reload.
536 $letterbox = Utils::is_cart_eligible_auto_letterbox( WC()->cart );
537
538 // Proceed to fetch delivery and dropoff options
539 $order_data = $sanitized_data;
540
541 $delivery_day = new Delivery_Day();
542 $dropoff = new Dropoff_Points();
543 $checkout_data = $container->get_checkout_data( $order_data );
544 $delivery_options = $delivery_day->get_content_data( $checkout_data['response'], $checkout_data['post_data'] );
545 $dropoff_options = $dropoff->get_content_data( $checkout_data['response'], $checkout_data['post_data'] );
546
547 $is_free_shipping = Utils::is_free_shipping_applied();
548
549 // Compute tax-display-adjusted values for block checkout tab labels.
550 $raw_carrier_base_cost = $this->get_carrier_base_cost_for_blocks();
551 $carrier_base_cost = Utils::get_fee_total_price( $raw_carrier_base_cost );
552 $delivery_day_fee_display = Utils::get_fee_total_price( (float) $this->settings->get_delivery_days_fee() );
553 $pickup_fee_display = Utils::get_fee_total_price( (float) $this->settings->get_pickup_delivery_fee() );
554
555 // The WC Store API returns shipping rate `price` as the ex-tax cost.
556 // The JS back-calculation must compensate by multiplying the ex-tax rate
557 // cost by this ratio before subtracting the incl-tax PostNL fee amounts.
558 $tax_ratio = Utils::get_fee_total_price( 1.0 );
559
560 // PostNL threshold-based free shipping: a PostNL method is selected but its
561 // rate was registered with cost = 0 (minimum_for_free_shipping reached).
562 if ( ! $is_free_shipping && 0.0 === $raw_carrier_base_cost && $this->is_postnl_method_chosen() ) {
563 $is_free_shipping = true;
564 $carrier_base_cost = 0.0;
565 }
566
567 // **Letterbox is Eligible**
568 if ( $letterbox ) {
569 wp_send_json_success(
570 array(
571 'message' => 'Eligible for letterbox.',
572 'show_container' => true,
573 'validated_address' => $validated_address,
574 'delivery_options' => $delivery_options['delivery_options'],
575 'dropoff_options' => array(),
576 'is_letterbox' => true,
577 'is_free_shipping' => $is_free_shipping,
578 'carrier_base_cost' => $carrier_base_cost,
579 'delivery_day_fee_display' => $delivery_day_fee_display,
580 'pickup_fee_display' => $pickup_fee_display,
581 'tax_ratio' => $tax_ratio,
582 ),
583 200
584 );
585 wp_die();
586 }
587
588 // Attempt to retrieve checkout data, delivery, and dropoff options
589 try {
590 $delivery_options_array = isset( $delivery_options['delivery_options'] ) ? $delivery_options['delivery_options'] : array();
591 $dropoff_options_array = isset( $dropoff_options['dropoff_options'] ) ? $dropoff_options['dropoff_options'] : array();
592
593 // Determine whether to show the container
594 if ( empty( $delivery_options_array ) && empty( $dropoff_options_array ) ) {
595 Utils::clear_postnl_checkout_session();
596 wp_send_json_success(
597 array(
598 'message' => 'No delivery or dropoff options available.',
599 'show_container' => false,
600 'validated_address' => $validated_address,
601 'delivery_options' => array(),
602 'dropoff_options' => array(),
603 'is_free_shipping' => $is_free_shipping,
604 'is_letterbox' => false,
605 ),
606 200
607 );
608 wp_die();
609 }
610
611 // If there are delivery or dropoff options, show the container
612 wp_send_json_success(
613 array(
614 'message' => 'Data saved successfully.',
615 'show_container' => true,
616 'validated_address' => $validated_address,
617 'delivery_options' => $delivery_options_array,
618 'dropoff_options' => $dropoff_options_array,
619 'is_delivery_days_enabled' => $delivery_options['is_delivery_days_enabled'],
620 'is_free_shipping' => $is_free_shipping,
621 'is_letterbox' => false,
622 'carrier_base_cost' => $carrier_base_cost,
623 'delivery_day_fee_display' => $delivery_day_fee_display,
624 'pickup_fee_display' => $pickup_fee_display,
625 'tax_ratio' => $tax_ratio,
626 ),
627 200
628 );
629 wp_die();
630
631 } catch ( \Exception $e ) {
632 // If fetching delivery options fails.
633 Utils::clear_postnl_checkout_session();
634 wp_send_json_success(
635 array(
636 'message' => 'Failed to fetch delivery options.',
637 'show_container' => false,
638 'validated_address' => $validated_address,
639 'delivery_options' => array(),
640 'dropoff_options' => array(),
641 ),
642 200
643 );
644 wp_die();
645 }
646 }
647 }
648