PluginProbe
PostNL for WooCommerce / 4.0.1
PostNL for WooCommerce v4.0.1
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 / includes / frontend / class-wcpn-checkout.php

class-wcpn-checkout.php in PostNL for WooCommerce 4.0.1, at includes/frontend/class-wcpn-checkout.php

482 lines 18.5 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2
3 use MyParcelNL\Sdk\src\Factory\DeliveryOptionsAdapterFactory;
4 use MyParcelNL\Sdk\src\Model\Consignment\AbstractConsignment;
5 use MyParcelNL\Sdk\src\Model\Consignment\PostNLConsignment;
6 use MyParcelNL\Sdk\src\Support\Arr;
7 use WPO\WC\PostNL\Compatibility\Order as WCX_Order;
8 use WPO\WC\PostNL\Compatibility\WC_Core as WCX;
9
10 if (! defined('ABSPATH')) {
11 exit;
12 } // Exit if accessed directly
13
14 if (class_exists('WCPN_Checkout')) {
15 return new WCPN_Checkout();
16 }
17
18 /**
19 * Frontend views
20 */
21 class WCPN_Checkout
22 {
23 private const DELIVERY_OPTIONS_KEY_MAP = [
24 'deliveryType' => 'delivery_type',
25 'isPickup' => 'is_pickup',
26 'labelDescription' => 'label_description',
27 'pickupLocation' => 'pickup_location',
28 'packageType' => 'package_type',
29 'shipmentOptions' => 'shipment_options',
30 'shipmentOptions.ageCheck' => 'shipment_options.age_check',
31 'shipmentOptions.insuredAmount' => 'shipment_options.insured_amount',
32 'shipmentOptions.onlyRecipient' => 'shipment_options.only_recipient',
33 'shipmentOptions.returnShipment' => 'shipment_options.return_shipment',
34 ];
35
36 /**
37 * WCPN_Checkout constructor.
38 */
39 public function __construct()
40 {
41 add_action("wp_enqueue_scripts", [$this, "enqueue_frontend_scripts"], 100);
42
43 // Save delivery options data
44 add_action("woocommerce_checkout_update_order_meta", [$this, "save_delivery_options"], 10, 2);
45 }
46
47 /**
48 * Load styles & scripts on the checkout page.
49 *
50 * @throws \Exception
51 */
52 public function enqueue_frontend_scripts(): void
53 {
54 // The order received page has the same page id as the checkout so `is_checkout()` returns true on both...
55 if (! is_checkout() || is_order_received_page()) {
56 return;
57 }
58
59 // if using split address fields
60 $useSplitAddressFields = WCPOST()->setting_collection->isEnabled(WCPOST_Settings::SETTING_USE_SPLIT_ADDRESS_FIELDS);
61 if ($useSplitAddressFields) {
62 wp_enqueue_script(
63 "wcpn-checkout-fields",
64 WCPOST()->plugin_url() . "/assets/js/wcpn-checkout-fields.js",
65 ["wc-checkout"],
66 WC_POSTNL_VERSION,
67 true
68 );
69 }
70
71 // Don"t load the delivery options scripts if it"s disabled
72 if (! WCPOST()->setting_collection->isEnabled(WCPOST_Settings::SETTING_DELIVERY_OPTIONS_ENABLED)) {
73 return;
74 }
75
76 /**
77 * JS dependencies array
78 */
79 $deps = ["wc-checkout"];
80
81 /**
82 * If split address fields are enabled add the checkout fields script as an additional dependency.
83 */
84 if ($useSplitAddressFields) {
85 $deps[] = "wcpn-checkout-fields";
86 }
87
88 wp_enqueue_script(
89 "wc-postnl",
90 WCPOST()->plugin_url() . "/assets/js/postnl.js",
91 $deps,
92 WC_POSTNL_VERSION,
93 true
94 );
95
96 wp_enqueue_script(
97 "wc-postnl-frontend",
98 WCPOST()->plugin_url() . "/assets/js/wcpn-frontend.js",
99 array_merge($deps, ["wc-postnl", "jquery"]),
100 WC_POSTNL_VERSION,
101 true
102 );
103
104 $this->inject_delivery_options_variables();
105 }
106
107 /**
108 * Localize variables into the delivery options scripts.
109 *
110 * @throws Exception
111 */
112 public function inject_delivery_options_variables(): void
113 {
114 wp_localize_script(
115 'wc-postnl-frontend',
116 'wcpn',
117 [
118 "ajax_url" => admin_url("admin-ajax.php"),
119 ]
120 );
121
122 wp_localize_script(
123 "wc-postnl-frontend",
124 "PostNLDisplaySettings",
125 [
126 // Convert true/false to int for JavaScript
127 "isUsingSplitAddressFields" => (int) WCPOST()->setting_collection->isEnabled(
128 WCPOST_Settings::SETTING_USE_SPLIT_ADDRESS_FIELDS
129 ),
130 "splitAddressFieldsCountries" => WCPN_NL_Postcode_Fields::COUNTRIES_WITH_SPLIT_ADDRESS_FIELDS,
131 ]
132 );
133
134 wp_localize_script(
135 "wc-postnl",
136 "MyParcelDeliveryOptions",
137 [
138 "allowedShippingMethods" => json_encode($this->getShippingMethodsAllowingDeliveryOptions()),
139 "disallowedShippingMethods" => json_encode(WCPN_Export::DISALLOWED_SHIPPING_METHODS),
140 "alwaysShow" => $this->alwaysDisplayDeliveryOptions(),
141 "hiddenInputName" => WCPOST_Admin::META_DELIVERY_OPTIONS,
142 ]
143 );
144
145 wp_localize_script(
146 'wc-postnl',
147 'MyParcelConfig',
148 $this->get_delivery_options_config()
149 );
150
151 // Load the checkout template.
152 add_action(
153 apply_filters(
154 'wc_wcpn_delivery_options_location',
155 WCPOST()->setting_collection->getByName(WCPOST_Settings::SETTING_DELIVERY_OPTIONS_POSITION)
156 ),
157 [$this, 'output_delivery_options'],
158 10
159 );
160 }
161
162 /**
163 * @return string
164 */
165 public function get_delivery_options_shipping_methods()
166 {
167 $packageTypes = WCPOST()->setting_collection->getByName(WCPOST_Settings::SETTING_SHIPPING_METHODS_PACKAGE_TYPES);
168
169 if (! is_array($packageTypes)) {
170 $packageTypes = [];
171 }
172
173 $shipping_methods = [];
174
175 if (array_key_exists(AbstractConsignment::PACKAGE_TYPE_PACKAGE, $packageTypes ?? [])) {
176 // Shipping methods associated with parcels = enable delivery options
177 $shipping_methods = $packageTypes[AbstractConsignment::PACKAGE_TYPE_PACKAGE];
178 }
179
180 return json_encode($shipping_methods);
181 }
182
183 /**
184 * Get the delivery options config in JSON for passing to JavaScript.
185 *
186 * @return false|mixed|string|void
187 */
188 public function get_delivery_options_config()
189 {
190 $settings = WCPOST()->setting_collection;
191 $carriers = $this->get_carriers();
192
193 $postNLConfig = [
194 "config" => [
195 "currency" => get_woocommerce_currency(),
196 "locale" => "nl-NL",
197 "platform" => "myparcel",
198 ],
199 "strings" => [
200 "addressNotFound" => __("Address details are not entered", "woocommerce-postnl"),
201 "city" => __("City", "woocommerce-postnl"),
202 "closed" => __("Closed", "woocommerce-postnl"),
203 "deliveryEveningTitle" => $this->getDeliveryOptionsTitle(WCPOST_Settings::SETTING_EVENING_DELIVERY_TITLE),
204 "deliveryMorningTitle" => $this->getDeliveryOptionsTitle(WCPOST_Settings::SETTING_MORNING_DELIVERY_TITLE),
205 "deliveryStandardTitle" => $this->getDeliveryOptionsTitle(WCPOST_Settings::SETTING_STANDARD_TITLE),
206 "deliveryTitle" => $this->getDeliveryOptionsTitle(WCPOST_Settings::SETTING_DELIVERY_TITLE),
207 "headerDeliveryOptions" => $this->getDeliveryOptionsTitle(WCPOST_Settings::SETTING_HEADER_DELIVERY_OPTIONS_TITLE),
208 "houseNumber" => __("House number", "woocommerce-postnl"),
209 "onlyRecipientTitle" => $this->getDeliveryOptionsTitle(WCPOST_Settings::SETTING_ONLY_RECIPIENT_TITLE),
210 "openingHours" => __("Opening hours", "woocommerce-postnl"),
211 "pickUpFrom" => __("Pick up from", "woocommerce-postnl"),
212 "pickupTitle" => $this->getDeliveryOptionsTitle(WCPOST_Settings::SETTING_PICKUP_TITLE),
213 "postcode" => __("Postcode", "woocommerce-postnl"),
214 "retry" => __("Retry", "woocommerce-postnl"),
215 "signatureTitle" => $this->getDeliveryOptionsTitle(WCPOST_Settings::SETTING_SIGNATURE_TITLE),
216 "wrongHouseNumberCity" => __("Postcode/city combination unknown", "woocommerce-postnl"),
217 ],
218 ];
219
220 $chosenShippingMethodPrice = (float) WC()->session->get('cart_totals')['shipping_total'];
221
222 foreach ($carriers as $carrier) {
223 foreach (self::getDeliveryOptionsConfigMap($carrier) as $key => $setting) {
224 [$settingName, $function, $basePrice] = $setting;
225 $value = $settings->{$function}($carrier . '_' . $settingName);
226
227 if ($basePrice) {
228 $value = $value + $chosenShippingMethodPrice;
229 }
230
231 Arr::set($postNLConfig, 'config.' . $key, $value);
232 }
233 }
234 $postNLConfig['config']['priceStandardDelivery'] = $chosenShippingMethodPrice;
235
236 return json_encode($postNLConfig, JSON_UNESCAPED_SLASHES);
237 }
238
239 /**
240 * @param string $title
241 *
242 * @return string
243 */
244 public function getDeliveryOptionsTitle(string $title): string
245 {
246 $settings = WCPOST()->setting_collection;
247
248 return __(strip_tags($settings->getStringByName($title)), "woocommerce-postnl");
249 }
250
251 /**
252 * Output the delivery options template.
253 */
254 public function output_delivery_options()
255 {
256 do_action('woocommerce_postnl_before_delivery_options');
257 require_once(WCPOST()->includes . '/views/html-delivery-options-template.php');
258 do_action('woocommerce_postnl_after_delivery_options');
259 }
260
261 /**
262 * Get the array of enabled carriers by checking if they have either delivery or pickup enabled.
263 *
264 * @return array
265 */
266 private function get_carriers(): array
267 {
268 $settings = WCPOST()->setting_collection;
269 $carriers = [];
270
271 foreach ([PostNLConsignment::CARRIER_NAME] as $carrier) {
272 if ($settings->getByName("{$carrier}_" . WCPOST_Settings::SETTING_CARRIER_PICKUP_ENABLED)
273 || $settings->getByName(
274 "{$carrier}_" . WCPOST_Settings::SETTING_CARRIER_DELIVERY_ENABLED
275 )) {
276 $carriers[] = $carrier;
277 }
278 }
279
280 return $carriers;
281 }
282
283 /**
284 * Save delivery options to order when used
285 *
286 * @param int $order_id
287 * @param array $posted
288 *
289 * @return void
290 * @throws Exception
291 */
292 public static function save_delivery_options($order_id)
293 {
294 $order = WCX::get_order($order_id);
295
296 $shippingMethod = Arr::get($_POST, "shipping_method");
297 $highestShippingClass = Arr::get($_POST, "postnl_highest_shipping_class") ?? $shippingMethod[0];
298
299 /**
300 * Save the current version of our plugin to the order.
301 */
302 WCX_Order::update_meta_data(
303 $order,
304 WCPOST_Admin::META_ORDER_VERSION,
305 WCPOST()->version
306 );
307
308 /**
309 * Save the order weight here because it's easier than digging through order data after creating it.
310 *
311 * @see https://businessbloomer.com/woocommerce-save-display-order-total-weight/
312 */
313 WCX_Order::update_meta_data(
314 $order,
315 WCPOST_Admin::META_ORDER_WEIGHT,
316 WC()->cart->get_cart_contents_weight()
317 );
318
319 WCX_Order::update_meta_data(
320 $order,
321 WCPOST_Admin::META_SHIPMENT_OPTIONS_EXTRA,
322 [
323 'collo_amount' => 1,
324 'weight' => WC()->cart->get_cart_contents_weight(),
325 ]
326 );
327
328 if ($highestShippingClass) {
329 WCX_Order::update_meta_data(
330 $order,
331 WCPOST_Admin::META_HIGHEST_SHIPPING_CLASS,
332 $highestShippingClass
333 );
334 }
335
336 $deliveryOptionsFromPost = stripslashes(Arr::get($_POST, WCPOST_Admin::META_DELIVERY_OPTIONS));
337 $deliveryOptionsFromShippingClass = $highestShippingClass
338 ? [
339 'packageType' => WCPN_Export::getPackageTypeFromShippingMethod(
340 $shippingMethod[0],
341 $highestShippingClass
342 ),
343 ]
344 : null;
345
346 $deliveryOptions = $deliveryOptionsFromPost ?? $deliveryOptionsFromShippingClass;
347
348 if ($deliveryOptions) {
349 $deliveryOptions = json_decode($deliveryOptions, true);
350 $deliveryOptions = self::convertDeliveryOptionsForAdapter($deliveryOptions);
351
352 /*
353 * Create a new DeliveryOptions class from the data.
354 */
355 $deliveryOptions = new WCPN_DeliveryOptionsFromOrderAdapter(null, $deliveryOptions);
356
357 /*
358 * Store it in the meta data. It will be serialized so class references will be kept.
359 */
360 WCX_Order::update_meta_data(
361 $order,
362 WCPOST_Admin::META_DELIVERY_OPTIONS,
363 $deliveryOptions
364 );
365 }
366 }
367
368 /**
369 * Return the names of shipping methods that will show delivery options. If DISPLAY_FOR_ALL_METHODS is enabled it'll
370 * return an empty array and the frontend will allow any shipping except any that are specifically disallowed.
371 *
372 * @return string[]
373 * @throws Exception
374 * @see WCPN_Export::DISALLOWED_SHIPPING_METHODS
375 */
376 private function getShippingMethodsAllowingDeliveryOptions(): array
377 {
378 $allowedMethods = [];
379 $displayFor = WCPOST()->setting_collection->getByName(WCPOST_Settings::SETTING_DELIVERY_OPTIONS_DISPLAY);
380
381 if ($displayFor === WCPN_Settings_Data::DISPLAY_FOR_ALL_METHODS) {
382 return $allowedMethods;
383 }
384
385 $shippingMethodsByPackageType = WCPOST()->setting_collection->getByName(WCPOST_Settings::SETTING_SHIPPING_METHODS_PACKAGE_TYPES);
386 $shippingMethodsForPackage = $shippingMethodsByPackageType[AbstractConsignment::PACKAGE_TYPE_PACKAGE_NAME];
387
388 foreach ($shippingMethodsForPackage as $shippingMethod) {
389 [$methodId] = self::splitShippingMethodString($shippingMethod);
390
391 if (!in_array($methodId, WCPN_Export::DISALLOWED_SHIPPING_METHODS)) {
392 $allowedMethods[] = $shippingMethod;
393 }
394 }
395
396 return $allowedMethods;
397 }
398
399 /**
400 * @return bool
401 */
402 private function alwaysDisplayDeliveryOptions(): bool
403 {
404 $display = WCPOST()->setting_collection->getByName(WCPOST_Settings::SETTING_DELIVERY_OPTIONS_DISPLAY);
405
406 return $display === WCPN_Settings_Data::DISPLAY_FOR_ALL_METHODS;
407 }
408
409 /**
410 * Split a <rateId>:<instanceId> string into an array. If there is no instanceId, the second array element will be
411 * null.
412 *
413 * @param $shippingMethod
414 *
415 * @return array
416 */
417 public static function splitShippingMethodString(string $shippingMethod): array
418 {
419 $split = explode(':', $shippingMethod, 2);
420
421 if (count($split) === 1) {
422 $split[] = null;
423 }
424
425 return $split;
426 }
427
428 /**
429 * Map keys from the delivery options to the keys used in the adapters.
430 *
431 * @param array $deliveryOptions
432 *
433 * @return array
434 */
435 private static function convertDeliveryOptionsForAdapter(array $deliveryOptions): array
436 {
437 foreach (self::DELIVERY_OPTIONS_KEY_MAP as $camel => $snake) {
438 $value = Arr::get($deliveryOptions, $camel);
439 if (isset($value)) {
440 Arr::set($deliveryOptions, $snake, $value);
441 Arr::forget($deliveryOptions, $camel);
442 }
443 }
444
445 return $deliveryOptions;
446 }
447
448 /**
449 * @param string $carrier
450 *
451 * @return array[]
452 */
453 private static function getDeliveryOptionsConfigMap(string $carrier): array
454 {
455 return [
456 "carrierSettings.$carrier.allowDeliveryOptions" => [WCPOST_Settings::SETTING_CARRIER_DELIVERY_ENABLED, 'isEnabled', false],
457 "carrierSettings.$carrier.allowEveningDelivery" => [WCPOST_Settings::SETTING_CARRIER_DELIVERY_EVENING_ENABLED, 'isEnabled', false],
458 "carrierSettings.$carrier.allowMondayDelivery" => [WCPOST_Settings::SETTING_CARRIER_MONDAY_DELIVERY_ENABLED, 'isEnabled', false],
459 "carrierSettings.$carrier.allowMorningDelivery" => [WCPOST_Settings::SETTING_CARRIER_DELIVERY_MORNING_ENABLED, 'isEnabled', false],
460 "carrierSettings.$carrier.allowOnlyRecipient" => [WCPOST_Settings::SETTING_CARRIER_ONLY_RECIPIENT_ENABLED, 'isEnabled', false],
461 "carrierSettings.$carrier.allowPickupLocations" => [WCPOST_Settings::SETTING_CARRIER_PICKUP_ENABLED, 'isEnabled', false],
462 "carrierSettings.$carrier.allowSaturdayDelivery" => [WCPOST_Settings::SETTING_CARRIER_SATURDAY_DELIVERY_ENABLED, 'isEnabled', false],
463 "carrierSettings.$carrier.allowSignature" => [WCPOST_Settings::SETTING_CARRIER_SIGNATURE_ENABLED, 'isEnabled', false],
464 "carrierSettings.$carrier.priceEveningDelivery" => [WCPOST_Settings::SETTING_CARRIER_DELIVERY_EVENING_FEE, 'getFloatByName', true],
465 "carrierSettings.$carrier.priceMondayDelivery" => [WCPOST_Settings::SETTING_CARRIER_MONDAY_DELIVERY_FEE, 'getFloatByName', true],
466 "carrierSettings.$carrier.priceMorningDelivery" => [WCPOST_Settings::SETTING_CARRIER_DELIVERY_MORNING_FEE, 'getFloatByName', true],
467 "carrierSettings.$carrier.priceOnlyRecipient" => [WCPOST_Settings::SETTING_CARRIER_ONLY_RECIPIENT_FEE, 'getFloatByName', false],
468 "carrierSettings.$carrier.pricePickup" => [WCPOST_Settings::SETTING_CARRIER_PICKUP_FEE, 'getFloatByName', true],
469 "carrierSettings.$carrier.priceSaturdayDelivery" => [WCPOST_Settings::SETTING_CARRIER_SATURDAY_DELIVERY_FEE, 'getFloatByName', true],
470 "carrierSettings.$carrier.priceSignature" => [WCPOST_Settings::SETTING_CARRIER_SIGNATURE_FEE, 'getFloatByName', false],
471 "cutoffTime" => [WCPOST_Settings::SETTING_CARRIER_CUTOFF_TIME, 'getStringByName', false],
472 "deliveryDaysWindow" => [WCPOST_Settings::SETTING_CARRIER_DELIVERY_DAYS_WINDOW, 'getIntegerByName', false],
473 "dropOffDays" => [WCPOST_Settings::SETTING_CARRIER_DROP_OFF_DAYS, 'getByName', false],
474 "dropOffDelay" => [WCPOST_Settings::SETTING_CARRIER_DROP_OFF_DELAY, 'getIntegerByName', false],
475 "fridayCutoffTime" => [WCPOST_Settings::SETTING_CARRIER_FRIDAY_CUTOFF_TIME, 'getStringByName', false],
476 "saturdayCutoffTime" => [WCPOST_Settings::SETTING_CARRIER_CUTOFF_TIME, 'getStringByName', false],
477 ];
478 }
479 }
480
481 return new WCPN_Checkout();
482