PluginProbe
DPD SK for WooCommerce / trunk
DPD SK for WooCommerce vtrunk
9.2.1 9.1.0 9.2.0 9.0.0 trunk 1.0.0 1.0.1 2.0.0 2.0.1 3.0.0 3.0.1 3.0.2 4.0.0 4.0.1 4.0.2 4.0.3 4.0.4 5.0.0 5.0.1 5.0.2 5.0.3 6.0.0 6.0.1 7.0.0 7.0.1 All 37 releases
wc-dpd / includes / Order.php

Order.php in DPD SK for WooCommerce trunk, at includes/Order.php

718 lines 26.8 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2
3 namespace WcDPD;
4
5 defined('ABSPATH') || exit;
6
7 /**
8 * Order class
9 */
10 class Order
11 {
12 public const BANK_ID_META_KEY = 'dpd_bank_id';
13 public const ADDRESS_ID_META_KEY = 'dpd_address_id';
14 public const SHIPPING_META_KEY = 'dpd_shipping';
15 public const NOTIFICATION_META_KEY = 'dpd_notification';
16 public const REFERENCE_1_META_KEY = 'dpd_refrence_1';
17 public const REFERENCE_2_META_KEY = 'dpd_refrence_2';
18 public const TRACKING_NUMBER_META_KEY = 'dpd_tracking_number';
19 public const PACKAGE_WEIGHT_META_KEY = 'dpd_package_weight';
20 public const EXPORT_STATUS_META_KEY = 'dpd_export_status';
21 public const EXPORT_SUCCESS_STATUS = 'success';
22 public const EXPORT_FAILED_STATUS = 'failed';
23 public const EXPORT_LABEL_URL_META_KEY = 'dpd_export_label_url';
24 public const EXPORT_PACKAGE_NUMBER_META_KEY = 'dpd_export_package_number';
25 public const EXPORT_MPSID_META_KEY = 'dpd_export_mpsid';
26
27 public static function init()
28 {
29 add_action('woocommerce_checkout_update_order_meta', [__CLASS__, 'saveParcelShopShippingMethodFieldsToOrder'], 10, 2);
30 add_action('woocommerce_store_api_checkout_order_processed', [__CLASS__, 'saveParcelShopShippingMethodFieldsToOrder'], 10, 1);
31 add_action('woocommerce_order_details_after_order_table', [__CLASS__, 'displayParcelShopShippingOrderTableInfo'], 10, 1);
32 add_action('woocommerce_admin_order_data_after_billing_address', [__CLASS__, 'displayParcelShopShippingAdminOrderInfo'], 10, 1);
33 }
34
35 /**
36 * Export order to DPD
37 *
38 * @param integer $order_id
39 *
40 * @return bool
41 */
42 public static function export($order_id = 0)
43 {
44 if (!$order_id) {
45 return false;
46 }
47
48 $order = wc_get_order($order_id);
49
50 if (!$order instanceof \WC_Order) {
51 return false;
52 }
53
54 if (!self::canExportOrder($order)) {
55 Notice::error(sprintf(__('Order %d is already exported to DPD.', 'wc-dpd'), $order_id));
56
57 return false;
58 }
59
60 // Only orders that were actually shipped can be handed over to DPD.
61 // Runs after canExportOrder() so reset/re-download of an already
62 // exported order keeps working untouched.
63 if (!self::isExportableShipment($order)) {
64 Notice::error(sprintf(
65 /* translators: %d: order number */
66 __('Order %d has no shipping method, nothing to export.', 'wc-dpd'),
67 $order_id
68 ));
69
70 return false;
71 }
72
73 try {
74 $data = self::getOrderExportData($order);
75
76 if ($data[DpdExport::ORDER_HAS_PARCELSHOP_SHIPPING_KEY] && empty($data[DpdExport::ORDER_PARCELSHOP_PUS_ID])) {
77 throw new \Exception(sprintf(
78 /* translators: %d: order number */
79 __('Order %d has Parcel Shop shipping but no pickup point was selected. Ask the customer for the pickup point, or edit the shipping method.', 'wc-dpd'),
80 $order_id
81 ));
82 }
83
84 do_action('wc_dpd_before_order_export', $order, $data);
85
86 $response = DpdExport::doExport($data, $order);
87
88 $order->update_meta_data(Order::EXPORT_LABEL_URL_META_KEY, $response[Order::EXPORT_LABEL_URL_META_KEY]);
89 $order->update_meta_data(Order::EXPORT_PACKAGE_NUMBER_META_KEY, $response[Order::EXPORT_PACKAGE_NUMBER_META_KEY]);
90 $order->update_meta_data(Order::EXPORT_MPSID_META_KEY, $response[Order::EXPORT_MPSID_META_KEY]);
91 $order->update_meta_data(Order::EXPORT_STATUS_META_KEY, $response[Order::EXPORT_STATUS_META_KEY]);
92 $order->save_meta_data();
93
94 $message = sprintf(__('Order %d was successfully exported', 'wc-dpd'), $order_id);
95
96 Notice::success($message);
97 $order->add_order_note(Notice::PREFIX . $message);
98
99 do_action('wc_dpd_after_order_export', $order, $response);
100
101 return true;
102 } catch (\Exception $e) {
103 $message = esc_html($e->getMessage());
104
105 Notice::error($message);
106 $order->add_order_note(Notice::PREFIX . $message);
107
108 do_action('wc_dpd_order_export_error', $order, $e);
109
110 return false;
111 }
112 }
113
114 /**
115 * Reset export data
116 *
117 * @param integer $order_id
118 *
119 * @return void
120 */
121 public static function reset($order_id)
122 {
123 $order = wc_get_order($order_id);
124
125 if (!$order instanceof \WC_Order) {
126 return false;
127 }
128
129 $order->delete_meta_data(Order::EXPORT_LABEL_URL_META_KEY);
130 $order->delete_meta_data(Order::EXPORT_PACKAGE_NUMBER_META_KEY);
131 $order->delete_meta_data(Order::EXPORT_MPSID_META_KEY);
132 $order->delete_meta_data(Order::EXPORT_STATUS_META_KEY);
133 $order->save_meta_data();
134
135 $message = sprintf(__('Order %d export data was successfully reset', 'wc-dpd'), $order_id);
136
137 Notice::success($message);
138
139 $order->add_order_note(Notice::PREFIX . $message);
140 }
141
142 /**
143 * Get order data for export
144 *
145 * @param \WC_Order $order
146 *
147 * @return array
148 */
149 public static function getOrderExportData(\WC_Order $order)
150 {
151 $order_id = $order->get_id();
152 $order = wc_get_order($order_id);
153 $order_number = $order->get_order_number();
154 $shipment_type = 'b2c';
155
156 $billing_full_name = $order->get_formatted_billing_full_name();
157 $shipping_full_name = $order->get_formatted_shipping_full_name();
158 $full_name = trim($shipping_full_name) ? $shipping_full_name : $billing_full_name;
159
160 /**
161 * Filter the customer full name before the export length validation runs.
162 *
163 * DPD limits the name to 35 characters; returning a shortened value here
164 * lets shops with long names export without editing the order address.
165 *
166 * @param string $full_name Resolved full name (shipping over billing).
167 * @param \WC_Order $order
168 */
169 $full_name = apply_filters('wc_dpd_export_customer_full_name', $full_name, $order);
170
171 // Throw error if full name is longer than 35 characters
172 $full_name_allowed_length = 35;
173 if (mb_strlen($full_name) > $full_name_allowed_length) {
174 throw new \Exception(sprintf(__('Full name %s is longer than %d characters. Please shorten it.', 'wc-dpd'), $full_name, $full_name_allowed_length));
175 }
176
177 $billing_company = $order->get_billing_company();
178 $shipping_company = $order->get_shipping_company();
179 $company = trim($shipping_company) ? $shipping_company : $billing_company;
180
181 /**
182 * Filter the company name before the export length validation runs.
183 *
184 * DPD limits the company name to 35 characters; returning a shortened
185 * value here lets shops with long company names export without editing
186 * the order address.
187 *
188 * @param string $company Resolved company (shipping over billing), may be empty.
189 * @param \WC_Order $order
190 */
191 $company = apply_filters('wc_dpd_export_customer_company', $company, $order);
192 $company_allowed_length = 35;
193
194 if ($company) {
195 // Throw error if company name is longer than 35 characters
196 if (mb_strlen($company) > $company_allowed_length) {
197 throw new \Exception(sprintf(__('Company name %s is longer than %d characters. Please shorten it.', 'wc-dpd'), $company, $company_allowed_length));
198 }
199
200 $shipment_type = 'b2b';
201 }
202
203 $billing_address_1 = $order->get_billing_address_1();
204 $billing_address_2 = $order->get_billing_address_2();
205 $shipping_address_1 = $order->get_shipping_address_1();
206 $shipping_address_2 = $order->get_shipping_address_2();
207
208 $street = $shipping_address_1 ? $shipping_address_1 : $billing_address_1;
209 $street_2 = $shipping_address_2 ? $shipping_address_2 : $billing_address_2;
210
211 $house_number = '';
212 if ($street_2) {
213 $house_number = $street_2;
214 } elseif (preg_match('/^([^\d]*[^\d\s]) *(\d.*)$/', $street, $parsed_address_1)) {
215 $street = !empty($parsed_address_1[1]) ? $parsed_address_1[1] : '';
216 $house_number = !empty($parsed_address_1[2]) ? $parsed_address_1[2] : '';
217 }
218
219 $billing_postcode = $order->get_billing_postcode();
220 $shipping_postcode = $order->get_shipping_postcode();
221 $postcode = $shipping_postcode ? $shipping_postcode : $billing_postcode;
222
223 $billing_city = $order->get_billing_city();
224 $shipping_city = $order->get_shipping_city();
225 $city = $shipping_city ? $shipping_city : $billing_city;
226
227 $billing_country_code = $order->get_billing_country();
228 $shipping_country_code = $order->get_shipping_country();
229 $country_code = $shipping_country_code ? $shipping_country_code : $billing_country_code;
230
231 $phone = $order->get_billing_phone();
232 $email = $order->get_billing_email();
233 $customer_note = $order->get_customer_note();
234 $order_price = $order->get_total();
235 $order_currency = $order->get_currency();
236 $shipping_method = $order->get_shipping_method();
237 $payment_method = $order->get_payment_method();
238 $order_pickup_date = self::getPickupDate();
239 $shipping = $order->get_meta(self::SHIPPING_META_KEY, true);
240 $parcelshop_id = 0;
241 $parcelshop_pus_id = 0;
242
243 // If order has parcel shipping selected, change settings
244 $has_parcelshop_shipping = Order::hasParcelShpping($order);
245 if ($has_parcelshop_shipping) {
246 $shipping = '17';
247 $shipment_type = 'psd';
248 $parcelshop_id = $order->get_meta(DpdParcelShopShippingMethod::PARCELSHOP_ID_META_KEY, true);
249 $parcelshop_pus_id = $order->get_meta(DpdParcelShopShippingMethod::PARCELSHOP_PUS_ID_META_KEY, true);
250 }
251
252 $bank_id = sanitize_text_field($order->get_meta(self::BANK_ID_META_KEY, true));
253 $address_id = sanitize_text_field($order->get_meta(self::ADDRESS_ID_META_KEY, true));
254 $reference_1 = sanitize_text_field($order->get_meta(self::REFERENCE_1_META_KEY, true));
255 $reference_2 = sanitize_text_field($order->get_meta(self::REFERENCE_2_META_KEY, true));
256 $package_weight = sanitize_text_field($order->get_meta(self::PACKAGE_WEIGHT_META_KEY, true));
257
258 $notification = $order->get_meta(self::NOTIFICATION_META_KEY, true);
259 $notification = $notification == 'yes' ? 'yes' : 'no';
260
261 return [
262 DpdExport::SHIPMENT_TYPE_KEY => $shipment_type,
263 DpdExport::CUSTOMER_FULL_NAME_KEY => $full_name,
264 DpdExport::CUSTOMER_COMPANY_KEY => $company,
265 DpdExport::CUSTOMER_STREET_KEY => $street,
266 DpdExport::CUSTOMER_HOUSE_NUMBER_KEY => $house_number,
267 DpdExport::CUSTOMER_ZIP_KEY => $postcode,
268 DpdExport::CUSTOMER_CITY_KEY => $city,
269 DpdExport::CUSTOMER_COUNTRY_KEY => $country_code,
270 DpdExport::CUSTOMER_PHONE_KEY => $phone,
271 DpdExport::CUSTOMER_EMAIL_KEY => $email,
272 DpdExport::ORDER_NOTE_KEY => $order_number,
273 DpdExport::ORDER_REFERENCE_1_KEY => $reference_1,
274 DpdExport::ORDER_REFERENCE_2_KEY => $reference_2,
275 DpdExport::ORDER_PACKAGE_WEIGHT_KEY => $package_weight,
276 DpdExport::ORDER_ID_KEY => $order_id,
277 DpdExport::ORDER_PRICE_KEY => $order_price,
278 DpdExport::ORDER_CURRENCY_KEY => $order_currency,
279 DpdExport::ORDER_PAYMENT_METHOD_KEY => $payment_method,
280 DpdExport::ORDER_HAS_PARCELSHOP_SHIPPING_KEY => $has_parcelshop_shipping,
281 DpdExport::ORDER_SHIPPING_METHOD_KEY => $shipping_method,
282 DpdExport::ORDER_PARCELSHOP_ID => $parcelshop_id,
283 DpdExport::ORDER_PARCELSHOP_PUS_ID => $parcelshop_pus_id,
284 DpdExport::ORDER_PICKUP_DATE_KEY => $order_pickup_date,
285 DpdExportSettings::SHIPPING_OPTION_KEY => $shipping,
286 DpdExportSettings::ADDRESS_ID_OPTION_KEY => $address_id,
287 DpdExportSettings::BANK_ID_OPTION_KEY => $bank_id,
288 DpdExportSettings::NOTIFICATION_OPTION_KEY => $notification,
289 ];
290 }
291
292 /**
293 * Check if order can be exported to DPD
294 *
295 * @param int $order_id
296 *
297 * @return bool
298 */
299 public static function canExportOrder($order)
300 {
301 $export_status = $order->get_meta(self::EXPORT_STATUS_META_KEY, true);
302
303 if ($export_status == self::EXPORT_SUCCESS_STATUS) {
304 return false;
305 }
306
307 return true;
308 }
309
310 /**
311 * Save parcelshop fields to the order
312 *
313 * @param int $order_id
314 *
315 * @return void
316 */
317 public static function saveParcelShopShippingMethodFieldsToOrder($order_id)
318 {
319 // Get posted data either from $_POST, WP_REST_Request, or order object
320 $posted_data = [];
321
322 if ($order_id instanceof \WP_REST_Request) {
323 $request_data = $order_id->get_json_params();
324 $order_id = $request_data['order_id'] ?? 0;
325 $posted_data['shipping_method'] = [$request_data['shipping_method'] ?? ''];
326
327 // Map REST API fields to POST fields
328 $dpd_fields = [
329 DpdParcelShopShippingMethod::PARCELSHOP_ID_META_KEY,
330 DpdParcelShopShippingMethod::PARCELSHOP_PUS_ID_META_KEY,
331 DpdParcelShopShippingMethod::PARCELSHOP_NAME_META_KEY,
332 DpdParcelShopShippingMethod::PARCELSHOP_STREET_META_KEY,
333 DpdParcelShopShippingMethod::PARCELSHOP_ZIP_META_KEY,
334 DpdParcelShopShippingMethod::PARCELSHOP_CITY_META_KEY,
335 DpdParcelShopShippingMethod::PARCELSHOP_COUNTRY_CODE_META_KEY
336 ];
337
338 foreach ($dpd_fields as $field) {
339 if (isset($request_data[$field])) {
340 $posted_data[$field] = $request_data[$field];
341 }
342 }
343 } else {
344 // Get order object
345 $order = wc_get_order($order_id);
346 if (!$order instanceof \WC_Order) {
347 return;
348 }
349
350 // Get shipping method from order
351 $shipping_methods = $order->get_shipping_methods();
352 $shipping_method = reset($shipping_methods);
353
354 if (!$shipping_method) {
355 return;
356 }
357
358 $posted_data['shipping_method'] = [$shipping_method->get_method_id()];
359
360 // Try to get data from POST first
361 if (!empty($_POST)) {
362 $posted_data = $_POST;
363 } else {
364 // Try to get data from WooCommerce session
365 if (WC()->session) {
366 $chosen_parcelshop = WC()->session->get(Shipping::SESSION_CHOSEN_PARCELSHOP_KEY, []);
367
368 if (!empty($chosen_parcelshop)) {
369 // Update the mapping to match the actual session data keys
370 $posted_data[DpdParcelShopShippingMethod::PARCELSHOP_ID_META_KEY] = $chosen_parcelshop['wc_dpd_parcelshop_id'] ?? '';
371 $posted_data[DpdParcelShopShippingMethod::PARCELSHOP_PUS_ID_META_KEY] = $chosen_parcelshop['wc_dpd_parcelshop_pus_id'] ?? '';
372 $posted_data[DpdParcelShopShippingMethod::PARCELSHOP_NAME_META_KEY] = $chosen_parcelshop['wc_dpd_parcelshop_name'] ?? '';
373 $posted_data[DpdParcelShopShippingMethod::PARCELSHOP_STREET_META_KEY] = $chosen_parcelshop['wc_dpd_parcelshop_street'] ?? '';
374 $posted_data[DpdParcelShopShippingMethod::PARCELSHOP_ZIP_META_KEY] = $chosen_parcelshop['wc_dpd_parcelshop_zip'] ?? '';
375 $posted_data[DpdParcelShopShippingMethod::PARCELSHOP_CITY_META_KEY] = $chosen_parcelshop['wc_dpd_parcelshop_city'] ?? '';
376 $posted_data[DpdParcelShopShippingMethod::PARCELSHOP_COUNTRY_CODE_META_KEY] = $chosen_parcelshop['wc_dpd_parcelshop_country_code'] ?? '';
377 }
378 }
379 }
380 }
381
382 if (is_admin()) {
383 return;
384 }
385
386 if (empty($posted_data['shipping_method'][0])) {
387 return;
388 }
389
390 if ($posted_data['shipping_method'][0] != DpdParcelShopShippingMethod::SETTINGS_ID_KEY) {
391 return;
392 }
393
394 // Get order if not already retrieved
395 if (!isset($order)) {
396 $order = wc_get_order($order_id);
397 if (!$order instanceof \WC_Order) {
398 return;
399 }
400 }
401
402 // Sanitize and save parcelshop data
403 $fields_to_save = [
404 DpdParcelShopShippingMethod::PARCELSHOP_ID_META_KEY => 'intval',
405 DpdParcelShopShippingMethod::PARCELSHOP_PUS_ID_META_KEY => 'sanitize_text_field',
406 DpdParcelShopShippingMethod::PARCELSHOP_NAME_META_KEY => 'sanitize_text_field',
407 DpdParcelShopShippingMethod::PARCELSHOP_STREET_META_KEY => 'sanitize_text_field',
408 DpdParcelShopShippingMethod::PARCELSHOP_ZIP_META_KEY => 'sanitize_text_field',
409 DpdParcelShopShippingMethod::PARCELSHOP_CITY_META_KEY => 'sanitize_text_field',
410 DpdParcelShopShippingMethod::PARCELSHOP_COUNTRY_CODE_META_KEY => 'sanitize_text_field'
411 ];
412
413 foreach ($fields_to_save as $meta_key => $sanitize_callback) {
414 $value = isset($posted_data[$meta_key]) ? $posted_data[$meta_key] : '';
415 $sanitized_value = $sanitize_callback($value);
416 $order->update_meta_data($meta_key, $sanitized_value);
417 }
418
419 $order->save_meta_data();
420
421 // Clear chosen parcelshop session data
422 if (WC()->session) {
423 WC()->session->set(Shipping::SESSION_CHOSEN_PARCELSHOP_KEY, []);
424 }
425 }
426
427 /**
428 * Display parcelshop shipping info after order detail
429 *
430 * @param object $order
431 *
432 * @return void
433 */
434 public static function displayParcelShopShippingOrderTableInfo(object $order)
435 {
436 echo self::getParcelShopOrderHtmlDetails($order);
437 }
438
439 /**
440 * Display parcelshop shipping info in the admin order detail
441 *
442 * @param object $order
443 *
444 * @return void
445 */
446 public static function displayParcelShopShippingAdminOrderInfo(object $order)
447 {
448 echo self::getParcelShopOrderHtmlDetails($order, 'admin');
449 }
450
451 /**
452 * Get parcelshop order html details
453 *
454 * @param \WC_Order $order
455 * @param string $type
456 *
457 * @return string
458 */
459 public static function getParcelShopOrderHtmlDetails($order, $type = '')
460 {
461 if (!$order instanceof \WC_Order) {
462 return;
463 }
464
465 $order_id = (int) $order->get_ID();
466 $has_parcelshop_shipping_method = self::hasParcelShpping($order);
467
468 if (!$has_parcelshop_shipping_method) {
469 return;
470 }
471
472 $parcelshop_id = (int) $order->get_meta(DpdParcelShopShippingMethod::PARCELSHOP_ID_META_KEY, true);
473 $parcelshop_pus_id = (string) $order->get_meta(DpdParcelShopShippingMethod::PARCELSHOP_PUS_ID_META_KEY, true);
474 $parcelshop_name = (string) $order->get_meta(DpdParcelShopShippingMethod::PARCELSHOP_NAME_META_KEY, true);
475 $parcelshop_street = (string) $order->get_meta(DpdParcelShopShippingMethod::PARCELSHOP_STREET_META_KEY, true);
476 $parcelshop_zip = (string) $order->get_meta(DpdParcelShopShippingMethod::PARCELSHOP_ZIP_META_KEY, true);
477 $parcelshop_city = (string) $order->get_meta(DpdParcelShopShippingMethod::PARCELSHOP_CITY_META_KEY, true);
478 $parcelshop_country_code = (string) $order->get_meta(DpdParcelShopShippingMethod::PARCELSHOP_COUNTRY_CODE_META_KEY, true);
479
480 $countries = (array) WC()->countries->get_allowed_countries();
481 $parcelshop_country_name = isset($countries[strtoupper($parcelshop_country_code)]) ? (string) $countries[strtoupper($parcelshop_country_code)] : '';
482
483 return include_template('chosen-parcelshop-order-data.php', [
484 'type' => $type,
485 'parcelshop_id' => $parcelshop_id,
486 'parcelshop_pus_id' => $parcelshop_pus_id,
487 'parcelshop_name' => $parcelshop_name,
488 'parcelshop_street' => $parcelshop_street,
489 'parcelshop_zip' => $parcelshop_zip,
490 'parcelshop_city' => $parcelshop_city,
491 'parcelshop_country_name' => $parcelshop_country_name,
492 'parcelshop_country_code' => $parcelshop_country_code,
493 ]);
494 }
495
496 /**
497 * Check if the order is a physical shipment worth exporting
498 *
499 * Virtual / download-only orders never carry a shipping method, so there is
500 * no parcel for DPD to pick up.
501 *
502 * @param \WC_Order $order
503 *
504 * @return bool
505 */
506 public static function isExportableShipment(\WC_Order $order)
507 {
508 return !empty($order->get_shipping_methods());
509 }
510
511 /**
512 * Check if order has parcel shipping method selected
513 *
514 * @param \WC_Order $order
515 *
516 * @return boolean
517 */
518 public static function hasParcelShpping(\WC_Order $order)
519 {
520 $order_shipping_methods = (array) $order->get_shipping_methods();
521
522 foreach ($order_shipping_methods as $_key => $shipping_method) {
523 if ($shipping_method->get_method_id() !== DpdParcelShopShippingMethod::SETTINGS_ID_KEY) {
524 continue;
525 }
526
527 return true;
528 }
529
530 return false;
531 }
532
533 /**
534 * Bulk download labels
535 *
536 * @param array $order_ids
537 *
538 * @return bool
539 */
540 public static function bulkDownloadLabels($order_ids = [])
541 {
542 if (empty($order_ids)) {
543 Notice::error('You have to select at least one order.');
544
545 return false;
546 }
547
548 // Hard cap on batch size to prevent accidental DoS against the DPD API.
549 $max_batch = (int) apply_filters('wc_dpd_bulk_labels_max_batch', 100);
550 if (count($order_ids) > $max_batch) {
551 Notice::error(sprintf(esc_html__('Bulk download is limited to %d orders per request.', 'wc-dpd'), (int) $max_batch));
552 return false;
553 }
554
555 $package_numbers = [];
556 $processing_order_ids = [];
557 foreach ($order_ids as $order_id) {
558 $order = wc_get_order($order_id);
559
560 if (!$order instanceof \WC_Order) {
561 continue;
562 }
563
564 $package_number = wp_kses_post($order->get_meta(self::EXPORT_PACKAGE_NUMBER_META_KEY, true));
565
566 if (!$package_number) {
567 Notice::error(sprintf(__('Order %d does not have the package number and its label couldn\'t be printed.', 'wc-dpd'), $order_id));
568
569 continue;
570 }
571
572 $package_numbers[] = $package_number;
573 $processing_order_ids[] = $order_id;
574 }
575
576 if (empty($package_numbers)) {
577 Notice::error(sprintf(__('None of your selected orders have a package number.', 'wc-dpd'), $order_id));
578
579 return false;
580 }
581
582 $client = new Client();
583 $pdf_content = $client->bulkDownloadLabels($package_numbers);
584
585 if (!$pdf_content) {
586 Notice::error(sprintf(__('Something went wrong and the pdf content is not valid. Please check orders %s if the package numbers are correct.', 'wc-dpd'), implode(', ', $processing_order_ids)));
587
588 return false;
589 }
590
591 // Generate pdf
592 header('Content-type: application/pdf');
593 header('Content-Disposition: attachment; filename="labels.pdf"');
594 echo $pdf_content;
595
596 exit;
597 }
598
599 /**
600 * Get pickup date
601 *
602 * @return string
603 */
604 public static function getPickupDate()
605 {
606 $pickup_date = wp_date('Ymd');
607
608 while (self::isDayOff($pickup_date)) {
609 $pickup_date = wp_date('Ymd', strtotime($pickup_date . ' +1 day'));
610 }
611
612 return $pickup_date;
613 }
614
615 /**
616 * Check if the given date is a day off (Saturday, Sunday, or a holiday in Slovakia)
617 *
618 * @param string $date
619 *
620 * @return bool
621 */
622 public static function isDayOff($date)
623 {
624 $day_of_week = wp_date('w', strtotime($date));
625
626 // If it's Saturday or Sunday
627 if ($day_of_week == 6 || $day_of_week == 0) {
628 return true;
629 }
630
631 // If it's a holiday
632 if (self::isHoliday($date)) {
633 return true;
634 }
635
636 return false;
637 }
638
639 /**
640 * Check if the given date is a holiday in Slovakia
641 *
642 * @param string $date
643 *
644 * @return bool
645 */
646 public static function isHoliday($date)
647 {
648 // Holidays in Slovakia (month-day format)
649 $holidays = array(
650 '01-01', // New Year's Day
651 '01-06', // Epiphany
652 '05-01', // International Workers' Day
653 '05-08', // Victory in Europe Day
654 '07-05', // St. Cyril and St. Methodius Day
655 '08-29', // Slovak National Uprising Anniversary
656 '09-15', // Day of Our Lady of Sorrows
657 '10-28', // Day of the Establishment of the Slovak Republic
658 '11-01', // All Saints' Day
659 '11-17', // Struggle for Freedom and Democracy Day
660 '12-24', // Christmas Eve
661 '12-25', // Christmas Day
662 '12-26', // St. Stephen's Day
663 );
664
665 // Extract the year from the given date
666 $year = date('Y', strtotime($date));
667
668 // Calculate Easter for the given year
669 $easter_date = self::calculateEasterForYear($year);
670 $easter_date_timestamp = strtotime($easter_date);
671
672 // Add Easter-related holidays to the array
673 $holidays[] = date('m-d', strtotime('-2 days', $easter_date_timestamp)); // Good Friday
674 $holidays[] = date('m-d', $easter_date_timestamp); // Easter Sunday
675 $holidays[] = date('m-d', strtotime('+1 day', $easter_date_timestamp)); // Easter Monday
676
677 // Get the month and day from the given date
678 $given_date = date('m-d', strtotime($date));
679
680 // Check if the given date is in the holidays array
681 if (in_array($given_date, $holidays)) {
682 return true;
683 }
684
685 return false;
686 }
687
688 /**
689 * Calculate the date of Easter for a given year
690 *
691 * @param int $year
692 *
693 * @return string
694 */
695 public static function calculateEasterForYear($year)
696 {
697 // Anonymous Gregorian algorithm (Butcher/Meeus) -- pure PHP, no ext-calendar
698 // dependency (easter_days() is unavailable when the calendar extension is
699 // not loaded, which broke bulk export on hosts without it).
700 $a = $year % 19;
701 $b = intdiv($year, 100);
702 $c = $year % 100;
703 $d = intdiv($b, 4);
704 $e = $b % 4;
705 $f = intdiv($b + 8, 25);
706 $g = intdiv($b - $f + 1, 3);
707 $h = (19 * $a + $b - $d - $g + 15) % 30;
708 $i = intdiv($c, 4);
709 $k = $c % 4;
710 $l = (32 + 2 * $e + 2 * $i - $h - $k) % 7;
711 $m = intdiv($a + 11 * $h + 22 * $l, 451);
712 $month = intdiv($h + $l - 7 * $m + 114, 31);
713 $day = (($h + $l - 7 * $m + 114) % 31) + 1;
714
715 return sprintf('%04d-%02d-%02d', $year, $month, $day);
716 }
717 }
718