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 / Shipping_Method / Settings.php

Settings.php in PostNL for WooCommerce 5.9.12, at src/Shipping_Method/Settings.php

2,168 lines 76.3 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 /**
3 * Class Shipping_Method/Settings file.
4 *
5 * @package PostNLWooCommerce\Shipping_Method
6 */
7
8 namespace PostNLWooCommerce\Shipping_Method;
9
10 use PostNLWooCommerce\Rest_API\Barcode\Key_Validator;
11 use PostNLWooCommerce\Utils;
12
13 if ( ! defined( 'ABSPATH' ) ) {
14 exit;
15 }
16
17 /**
18 * Class Settings
19 *
20 * @package PostNLWooCommerce\Shipping_Method
21 */
22 class Settings extends \WC_Settings_API {
23 /**
24 * ID of the class extending the settings API. Used in option names.
25 *
26 * @var string
27 */
28 public $id = POSTNL_SETTINGS_ID;
29
30 /**
31 * The unique instance of the plugin.
32 *
33 * @var Settings
34 */
35 private static $instance;
36
37 /**
38 * Merchant codes option name
39 */
40 const MERCHANT_CODES_OPTION = 'postnl_merchant_codes';
41
42 /**
43 * Gets an instance of the settings.
44 *
45 * @return Settings
46 */
47 public static function get_instance() {
48 if ( null === self::$instance ) {
49 self::$instance = new self();
50 }
51
52 return self::$instance;
53 }
54
55 /**
56 * Get all setting fields.
57 *
58 * @return array
59 */
60 public function get_setting_fields() {
61 $fields = array(
62 // Manual.
63 'user_manual' => array(
64 'title' => esc_html__( 'Manual', 'postnl-for-woocommerce' ),
65 'type' => 'title',
66 // translators: %1$s & %2$s is replaced with <a> tag.
67 'description' => sprintf( __( 'Consult the %1$smanual%2$s for help installing the plug-in.', 'postnl-for-woocommerce' ), '<a href="https://postnl.github.io/woocommerce/new-manual/?lang=nl" target="_blank">', '</a>' ),
68 ),
69 // Account Settings.
70 'account_settings_title' => array(
71 'title' => esc_html__( 'Account Settings', 'postnl-for-woocommerce' ),
72 'type' => 'title',
73 // translators: %1$s & %2$s is replaced with <a> tag.
74 'description' => sprintf( __( 'Please configure your shipping parameters and your access towards the PostNL APIs by means of authentication. You can find the details of your PostNL account in Mijn %1$sPostNL%2$s under "My Account > API beheren".', 'postnl-for-woocommerce' ), '<a href="https://mijn.postnl.nl/c/BP2_Mod_Login.app" target="_blank">', '</a>' ),
75 ),
76 'environment_mode' => array(
77 'title' => esc_html__( 'Environment Mode', 'postnl-for-woocommerce' ),
78 'type' => 'select',
79 'description' => __( 'Choose the environment mode.', 'postnl-for-woocommerce' ),
80 'desc_tip' => true,
81 'options' => array(
82 'production' => esc_html__( 'Production', 'postnl-for-woocommerce' ),
83 'sandbox' => esc_html__( 'Sandbox', 'postnl-for-woocommerce' ),
84 ),
85 'class' => 'wc-enhanced-select',
86 'default' => 'production',
87 'placeholder' => '',
88 ),
89 // Legacy production key. Renamed to "Old API Key" and only rendered when
90 // a value is already stored (see the gating in get_setting_fields()); a
91 // fresh install shows the "API Key" field alone. Kept read-only so
92 // merchants enter their key in the new field ahead of the API migration.
93 'api_keys' => array(
94 'title' => esc_html__( 'Old API Key', 'postnl-for-woocommerce' ),
95 'type' => 'text',
96 'description' => esc_html__( 'The key you were using before. It is locked because new keys go in the field below.', 'postnl-for-woocommerce' ),
97 'desc_tip' => false,
98 'default' => '',
99 'placeholder' => '',
100 'custom_attributes' => array( 'readonly' => 'readonly' ),
101 ),
102 'api_keys_new' => array(
103 'title' => esc_html__( 'API Key', 'postnl-for-woocommerce' ),
104 'type' => 'text',
105 'description' => esc_html__( 'Enter your PostNL API key here. You can get it from the Self Service module on the PostNL Business Portal.', 'postnl-for-woocommerce' ),
106 'desc_tip' => false,
107 'default' => '',
108 'placeholder' => '',
109 ),
110 'api_keys_new_status' => array(
111 'type' => 'postnl_new_key_status',
112 'environment' => 'production',
113 ),
114 'api_keys_sandbox' => array(
115 'title' => esc_html__( 'Old Sandbox API Key', 'postnl-for-woocommerce' ),
116 'type' => 'text',
117 'description' => esc_html__( 'The sandbox key you were using before. It is locked because new keys go in the field below.', 'postnl-for-woocommerce' ),
118 'desc_tip' => false,
119 'default' => '',
120 'placeholder' => '',
121 'custom_attributes' => array( 'readonly' => 'readonly' ),
122 ),
123 'api_keys_sandbox_new' => array(
124 'title' => esc_html__( 'Sandbox API Key', 'postnl-for-woocommerce' ),
125 'type' => 'text',
126 'description' => esc_html__( 'Enter your PostNL sandbox API key here. You can get it from the Self Service module on the PostNL Business Portal.', 'postnl-for-woocommerce' ),
127 'desc_tip' => false,
128 'default' => '',
129 'placeholder' => '',
130 ),
131 'api_keys_sandbox_new_status' => array(
132 'type' => 'postnl_new_key_status',
133 'environment' => 'sandbox',
134 ),
135 'enable_logging' => array(
136 'title' => esc_html__( 'Logging', 'postnl-for-woocommerce' ),
137 'type' => 'checkbox',
138 'description' => sprintf(
139 // translators: %1$s is anchor opener tag and %2$s is anchor closer tag.
140 esc_html__( 'A log file containing the communication to the PostNL server will be maintained if this option is checked. This can be used in case of technical issues and can be found %1$shere%2$s.', 'postnl-for-woocommerce' ),
141 '<a href="' . esc_url( Utils::get_log_url() ) . '" target="_blank">',
142 '</a>'
143 ),
144 'label' => esc_html__( 'Enable', 'postnl-for-woocommerce' ),
145 'desc_tip' => false,
146 'default' => '',
147 'placeholder' => '',
148 ),
149 'customer_num' => array(
150 'title' => esc_html__( 'Customer Number', 'postnl-for-woocommerce' ),
151 'type' => 'text',
152 'description' => esc_html__( 'e.g. "11223344"', 'postnl-for-woocommerce' ),
153 'desc_tip' => true,
154 'default' => '',
155 'placeholder' => '11223344',
156 ),
157 'customer_code' => array(
158 'title' => esc_html__( 'Customer Code', 'postnl-for-woocommerce' ),
159 'type' => 'text',
160 'description' => esc_html__( 'e.g. "DEVC"', 'postnl-for-woocommerce' ),
161 'desc_tip' => true,
162 'default' => '',
163 'placeholder' => 'DEVC',
164 'custom_attributes' => array( 'maxlength' => '10' ),
165 ),
166 'return_company' => array(
167 'title' => esc_html__( 'Company Name', 'postnl-for-woocommerce' ),
168 'type' => 'text',
169 'description' => esc_html__( 'Enter company name - this name will be noted as the sender on the label', 'postnl-for-woocommerce' ),
170 'desc_tip' => true,
171 'default' => '',
172 ),
173 /*
174 Temporarily hardcoded.
175 'location_code' => array(
176 'title' => esc_html__( 'Location Code', 'postnl-for-woocommerce' ),
177 'type' => 'text',
178 'description' => esc_html__( 'e.g. "123456"', 'postnl-for-woocommerce' ),
179 'desc_tip' => true,
180 'default' => '',
181 'placeholder' => '123456',
182 'custom_attributes' => array( 'maxlength' => '10' ),
183 ),
184 */
185
186 // Return Settings.
187 'return_settings_title' => array(
188 'title' => esc_html__( 'Return Settings', 'postnl-for-woocommerce' ),
189 'type' => 'title',
190 // 'description' => esc_html__( 'If you have a reply number, only fill in the Zip code, City and Return code. If you want to return your shipments to a home address, also provide the address line (Street, Housenumber and HouseNrExt) of your return address.', 'postnl-for-woocommerce' ),
191 ),
192 'return_shipment_and_labels' => array(
193 'title' => esc_html__( 'Standard return option', 'postnl-for-woocommerce' ),
194 'type' => 'select',
195 'description' => esc_html__( '- None: return labels are not automatically created', 'postnl-for-woocommerce' ) . '<br>' .
196 esc_html__( '- Label in the box: a separate return label is created at the same time as the label for the outward shipment and can be included in the box.', 'postnl-for-woocommerce' ),
197
198 'options' => array(
199 'none' => esc_html__( 'None', 'postnl-for-woocommerce' ),
200 'in_box' => esc_html__( 'Label in the box', 'postnl-for-woocommerce' ),
201 ),
202 'for_country' => array( 'NL' ),
203 ),
204 // 'return_address_default' => array(
205 // 'title' => esc_html__( 'Always print returnlabel together with shipping label', 'postnl-for-woocommerce' ),
206 // 'type' => 'checkbox',
207 // 'description' => esc_html__( 'With this setting enabled, the return-label of a shipment will automatically be downloaded and printed when the shipping label created.', 'postnl-for-woocommerce' ),
208 // 'desc_tip' => true,
209 // 'default' => '',
210 // 'label' => esc_html__( 'Enable', 'postnl-for-woocommerce' ),
211 // 'placeholder' => '',
212 // ),
213 'return_shipment_and_labels_all' => array(
214 'title' => esc_html__( 'Directly activate return function for all labels', 'postnl-for-woocommerce' ),
215 'type' => 'select',
216 'label' => esc_html__( 'Enable', 'postnl-for-woocommerce' ),
217 // 'description' => esc_html__( 'Tick this box if you want all labels to be activated for returning immediately. If you do not tick this box the return function can be activated on an order-by-order basis.', 'postnl-for-woocommerce' ),
218 'options' => array(
219 'yes' => esc_html__( 'Yes, activate return function directly for all orders', 'postnl-for-woocommerce' ),
220 'no' => esc_html__( 'No, activate return function per individual order', 'postnl-for-woocommerce' ),
221 ),
222 'for_country' => array( 'NL' ),
223 ),
224 'activate_smart_return' => array(
225 'title' => esc_html__( 'Activate Smart Return', 'postnl-for-woocommerce' ),
226 'type' => 'checkbox',
227 'default' => '',
228 'label' => esc_html__( 'Activate', 'postnl-for-woocommerce' ),
229 'placeholder' => '',
230 ),
231 'return_address_or_reply_no' => array(
232 'title' => esc_html__( 'Return to home address', 'postnl-for-woocommerce' ),
233 'type' => 'checkbox',
234 'label' => esc_html__( 'Activate', 'postnl-for-woocommerce' ),
235 'description' => esc_html__( 'Activate this setting to use a home address for return shipments', 'postnl-for-woocommerce' ),
236 'desc_tip' => true,
237 ),
238 'return_replynumber' => array(
239 'title' => esc_html__( 'Replynumber', 'postnl-for-woocommerce' ),
240 'type' => 'text',
241 'description' => esc_html__( 'Enter replynumber.', 'postnl-for-woocommerce' ),
242 'desc_tip' => true,
243 'default' => '',
244 'for_country' => array( 'NL' ),
245 'class' => 'country-nl',
246 ),
247 'freepost_zip' => array(
248 'title' => esc_html__( 'Freepost Zipcode', 'postnl-for-woocommerce' ),
249 'type' => 'text',
250 'description' => esc_html__( 'Enter Freepost Zipcode.', 'postnl-for-woocommerce' ),
251 'desc_tip' => true,
252 'default' => '',
253 ),
254 'freepost_city' => array(
255 'title' => esc_html__( 'Freepost City', 'postnl-for-woocommerce' ),
256 'type' => 'text',
257 'description' => esc_html__( 'Enter Freepost City.', 'postnl-for-woocommerce' ),
258 'desc_tip' => true,
259 'default' => '',
260 ),
261 'return_address_street' => array(
262 'title' => esc_html__( 'Street Address', 'postnl-for-woocommerce' ),
263 'type' => 'text',
264 'description' => esc_html__( 'Enter Return Street Address.', 'postnl-for-woocommerce' ),
265 'desc_tip' => true,
266 'default' => '',
267 ),
268 'return_address_house_no' => array(
269 'title' => esc_html__( 'House Number', 'postnl-for-woocommerce' ),
270 'type' => 'text',
271 'description' => esc_html__( 'Enter return house number.', 'postnl-for-woocommerce' ),
272 'desc_tip' => true,
273 'default' => '',
274 ),
275 'return_address_house_noext' => array(
276 'title' => esc_html__( 'House Number Extension', 'postnl-for-woocommerce' ),
277 'type' => 'text',
278 'description' => esc_html__( 'Enter return house number extension.', 'postnl-for-woocommerce' ),
279 'desc_tip' => true,
280 'default' => '',
281 ),
282 'return_address_zip' => array(
283 'title' => esc_html__( 'Zipcode', 'postnl-for-woocommerce' ),
284 'type' => 'text',
285 'description' => esc_html__( 'Enter Return Zipcode.', 'postnl-for-woocommerce' ),
286 'desc_tip' => true,
287 'default' => '',
288 ),
289 'return_address_city' => array(
290 'title' => esc_html__( 'City', 'postnl-for-woocommerce' ),
291 'type' => 'text',
292 'description' => esc_html__( 'Enter Return City.', 'postnl-for-woocommerce' ),
293 'desc_tip' => true,
294 'default' => '',
295 ),
296 'return_customer_code' => array(
297 'title' => esc_html__( 'Return Customer Code', 'postnl-for-woocommerce' ),
298 'type' => 'text',
299 'description' => esc_html__( 'Be aware that the Return Customer Code differs from the regular Customer Code. You can find your Return customer code in Mijn PostNL.', 'postnl-for-woocommerce' ),
300 'desc_tip' => true,
301 'default' => '',
302 ),
303 // Delivery Options Settings.
304 'delivery_options_title' => array(
305 'title' => esc_html__( 'Checkout Settings', 'postnl-for-woocommerce' ),
306 'type' => 'title',
307 'description' => esc_html__( 'Please configure your checkout preferences.', 'postnl-for-woocommerce' ),
308 ),
309 'supported_shipping_methods' => array(
310 'title' => esc_html__( 'Shipping Methods', 'postnl-for-woocommerce' ),
311 'type' => 'multiselect',
312 'description' => esc_html__( 'Select Shipping Methods can be associated with PostNL.', 'postnl-for-woocommerce' ),
313 'desc_tip' => true,
314 'options' => $this->get_shipping_methods(),
315 'class' => 'wc-enhanced-select',
316 ),
317 'letterbox_24_fee' => array(
318 'title' => esc_html__( 'Extra fee for the letterboxparcel (24 hours)', 'postnl-for-woocommerce' ),
319 'type' => 'price',
320 'description' => esc_html__( 'Extra fee added when Letterboxparcel Standard (24 hours) has been selected.', 'postnl-for-woocommerce' ),
321 'desc_tip' => true,
322 'for_country' => array( 'NL' ),
323 'class' => 'wc_input_price country-nl',
324 ),
325 'letterbox_fee' => array(
326 'title' => __( 'Letterbox fee', 'postnl-for-woocommerce' ),
327 'type' => 'price',
328 'description' => __( 'Overrides the shipping cost when all items are eligible for letterbox delivery. Leave empty to use the standard shipping cost. The fee is set to €0 when free shipping applies.', 'postnl-for-woocommerce' ),
329 'desc_tip' => true,
330 'for_country' => array( 'NL' ),
331 'class' => 'wc_input_price country-nl',
332 ),
333 'enable_pickup_points' => array(
334 'title' => __( 'PostNL Pick-up Points', 'postnl-for-woocommerce' ),
335 'type' => 'checkbox',
336 'label' => __( 'Enable', 'postnl-for-woocommerce' ),
337 'description' => __( 'Show PostNL pick-up points in the checkout so that your customers can choose to get their orders delivered at a PostNL pick-up point.', 'postnl-for-woocommerce' ),
338 'desc_tip' => true,
339 'default' => 'yes',
340 'for_country' => array( 'NL', 'BE' ),
341 'class' => 'country-nl country-be',
342 ),
343 'pickup_delivery_fee' => array(
344 'title' => __( 'Extra fee pick-up delivery', 'postnl-for-woocommerce' ),
345 'type' => 'price',
346 'description' => __( 'Extra fee added when the customer selects a PostNL pick-up point.', 'postnl-for-woocommerce' ),
347 'desc_tip' => true,
348 'for_country' => array( 'NL', 'BE' ),
349 'class' => 'wc_input_price country-nl country-be',
350 ),
351 /*
352 Temporarily commented out.
353 'number_pickup_points' => array(
354 'title' => __( 'Number of Pickup Points', 'postnl-for-woocommerce' ),
355 'type' => 'number',
356 'description' => __( 'Number of pickup points displayed in the frontend. Maximum will be 20.', 'postnl-for-woocommerce' ),
357 'desc_tip' => true,
358 'class' => '',
359 'default' => '10',
360 'custom_attributes' => array(
361 'min' => '1',
362 'max' => '20',
363 ),
364 'for_country' => array( 'NL', 'BE' ),
365 'class' => 'country-nl country-be',
366 ),
367 */
368
369 'enable_delivery_days' => array(
370 'title' => __( 'Delivery', 'postnl-for-woocommerce' ),
371 'type' => 'checkbox',
372 'label' => __( 'Enable', 'postnl-for-woocommerce' ),
373 'description' => __( 'Show delivery days in the checkout so that your customers can choose which day to receive their order.', 'postnl-for-woocommerce' ),
374 'desc_tip' => true,
375 'default' => '',
376 'for_country' => array( 'NL' ),
377 'class' => 'country-nl',
378 ),
379 'delivery_days_fee' => array(
380 'title' => __( 'Extra fee home delivery', 'postnl-for-woocommerce' ),
381 'type' => 'price',
382 'description' => __( 'Extra fee added when the customer selects home delivery.', 'postnl-for-woocommerce' ),
383 'desc_tip' => true,
384 'for_country' => array( 'NL', 'BE' ),
385 'class' => 'wc_input_price country-nl country-be',
386 ),
387 'number_delivery_days' => array(
388 'title' => __( 'Number of Delivery Days', 'postnl-for-woocommerce' ),
389 'type' => 'number',
390 'description' => __( 'Number of delivery days displayed in the frontend. Maximum will be 12.', 'postnl-for-woocommerce' ),
391 'desc_tip' => true,
392 'default' => '10',
393 'for_country' => array( 'NL' ),
394 'custom_attributes' => array(
395 'min' => '1',
396 'max' => '12',
397 ),
398 'class' => 'country-nl',
399 ),
400 'enable_morning_delivery' => array(
401 'title' => __( 'Morning Delivery', 'postnl-for-woocommerce' ),
402 'type' => 'checkbox',
403 'label' => __( 'Enable', 'postnl-for-woocommerce' ),
404 'description' => __( 'Enable morning delivery in the checkout so your customers can choose to receive their orders in the morning.', 'postnl-for-woocommerce' ),
405 'desc_tip' => true,
406 'default' => '',
407 'for_country' => array( 'NL' ),
408 'class' => 'country-nl',
409 ),
410 'morning_delivery_fee' => array(
411 'title' => __( 'Morning Delivery Fee', 'postnl-for-woocommerce' ),
412 'type' => 'price',
413 'description' => __( 'Fee for receiving orders in the morning.', 'postnl-for-woocommerce' ),
414 'desc_tip' => true,
415 'for_country' => array( 'NL' ),
416 'class' => 'wc_input_price country-nl',
417 ),
418 'enable_evening_delivery' => array(
419 'title' => __( 'Evening Delivery', 'postnl-for-woocommerce' ),
420 'type' => 'checkbox',
421 'label' => __( 'Enable', 'postnl-for-woocommerce' ),
422 'description' => __( 'Enable evening delivery in the checkout so your customers can choose to receive their orders in the evening.', 'postnl-for-woocommerce' ),
423 'desc_tip' => true,
424 'default' => '',
425 'for_country' => array( 'NL' ),
426 'class' => 'country-nl',
427 ),
428 'evening_delivery_fee' => array(
429 'title' => __( 'Evening Delivery Fee', 'postnl-for-woocommerce' ),
430 'type' => 'price',
431 'description' => __( 'Fee for receiving orders in the evening.', 'postnl-for-woocommerce' ),
432 'desc_tip' => true,
433 'for_country' => array( 'NL' ),
434 'class' => 'wc_input_price country-nl',
435 ),
436 'default_checkout_tab' => array(
437 'title' => __( 'Default Delivery Options Tab', 'postnl-for-woocommerce' ),
438 'type' => 'select',
439 'description' => __( 'Choose which tab is shown first in the delivery options menu at checkout.', 'postnl-for-woocommerce' ),
440 'desc_tip' => true,
441 'default' => 'delivery_day',
442 'options' => array(
443 'delivery_day' => __( 'Home Delivery', 'postnl-for-woocommerce' ),
444 'dropoff_points' => __( 'Pickup Points', 'postnl-for-woocommerce' ),
445 ),
446 'for_country' => array( 'NL', 'BE' ),
447 'class' => 'country-nl country-be',
448 ),
449 'transit_time' => array(
450 'title' => esc_html__( 'Transit Time', 'postnl-for-woocommerce' ),
451 'type' => 'number',
452 'description' => esc_html__( 'The number of days it takes for the order to be delivered after the order has been placed.', 'postnl-for-woocommerce' ),
453 'desc_tip' => true,
454 'default' => '1',
455 'placeholder' => '',
456 ),
457 'cut_off_time' => array(
458 'title' => esc_html__( 'Cut Off Time', 'postnl-for-woocommerce' ),
459 'type' => 'time',
460 'description' => esc_html__( 'If an order is ordered after this time, one day will be added to the transit time.', 'postnl-for-woocommerce' ),
461 'desc_tip' => true,
462 'default' => '18:00',
463 'placeholder' => '',
464 ),
465 'dropoff_day_mon' => array(
466 'title' => __( 'Drop off Days', 'postnl-for-woocommerce' ),
467 'type' => 'checkbox',
468 'label' => __( 'Monday', 'postnl-for-woocommerce' ),
469 'description' => __( 'Select which days orders will be shipped.', 'postnl-for-woocommerce' ),
470 'default' => 'yes',
471 'desc_tip' => true,
472 ),
473 'dropoff_day_tue' => array(
474 'type' => 'checkbox',
475 'label' => __( 'Tuesday', 'postnl-for-woocommerce' ),
476 'default' => 'yes',
477 ),
478 'dropoff_day_wed' => array(
479 'type' => 'checkbox',
480 'label' => __( 'Wednesday', 'postnl-for-woocommerce' ),
481 'default' => 'yes',
482 ),
483 'dropoff_day_thu' => array(
484 'type' => 'checkbox',
485 'label' => __( 'Thursday', 'postnl-for-woocommerce' ),
486 'default' => 'yes',
487 ),
488 'dropoff_day_fri' => array(
489 'type' => 'checkbox',
490 'label' => __( 'Friday', 'postnl-for-woocommerce' ),
491 'default' => 'yes',
492 ),
493 'dropoff_day_sat' => array(
494 'type' => 'checkbox',
495 'label' => __( 'Saturday', 'postnl-for-woocommerce' ),
496 'default' => 'yes',
497 ),
498 'dropoff_day_sun' => array(
499 'type' => 'checkbox',
500 'label' => __( 'Sunday', 'postnl-for-woocommerce' ),
501 ),
502 'validate_nl_address' => array(
503 'title' => __( 'Validate Dutch addresses', 'postnl-for-woocommerce' ),
504 'type' => 'checkbox',
505 'label' => __( 'Enable', 'postnl-for-woocommerce' ),
506 'description' => __( 'Based on zipcode and housenumber combination the address is checked.', 'postnl-for-woocommerce' ),
507 'desc_tip' => true,
508 'default' => 'yes',
509 ),
510 'reorder_nl_address' => array(
511 'title' => __( 'Use PostNL address-field', 'postnl-for-woocommerce' ),
512 'type' => 'checkbox',
513 'label' => __( 'Enable', 'postnl-for-woocommerce' ),
514 'description' => __( 'For zipcode, housenumber, housenumber extension and street separate address fields are displayed when this settings is enabled. This only applies for Dutch addresses.', 'postnl-for-woocommerce' ),
515 'desc_tip' => true,
516 'default' => 'yes',
517 ),
518
519 // Shipping Outside Europe Settings.
520 'shipping_outside_eu_title' => array(
521 'title' => esc_html__( 'Shipping Outside Europe Settings', 'postnl-for-woocommerce' ),
522 'type' => 'title',
523 'description' => esc_html__( 'Please insert your Parcels non-EU credentials.', 'postnl-for-woocommerce' ),
524 ),
525 'globalpack_barcode_type' => array(
526 'title' => esc_html__( 'Parcels non-EU Barcode Type', 'postnl-for-woocommerce' ),
527 'type' => 'text',
528 'description' => '',
529 'desc_tip' => true,
530 'default' => '',
531 'placeholder' => esc_html__( 'CD', 'postnl-for-woocommerce' ),
532 'custom_attributes' => array( 'maxlength' => '10' ),
533 ),
534 'globalpack_customer_code' => array(
535 'title' => esc_html__( 'Parcels non-EU Customer Code', 'postnl-for-woocommerce' ),
536 'type' => 'text',
537 'description' => '',
538 'desc_tip' => true,
539 'default' => '',
540 'placeholder' => esc_html__( '1234', 'postnl-for-woocommerce' ),
541 'custom_attributes' => array( 'maxlength' => '10' ),
542 ),
543 'hs_tariff_code' => array(
544 'title' => esc_html__( 'Default HS Tariff Code', 'postnl-for-woocommerce' ),
545 'type' => 'text',
546 'description' => esc_html__( 'The HS tariff code is used by customs to classify goods. The HS tariff code can be found on the website of the Dutch Chamber of Commerce.', 'postnl-for-woocommerce' ),
547 'desc_tip' => true,
548 'default' => '',
549 'placeholder' => '',
550 ),
551 'country_origin' => array(
552 'title' => esc_html__( 'Default Country of Origin', 'postnl-for-woocommerce' ),
553 'type' => 'select',
554 'description' => esc_html__( 'Default country of origin is used by customs.', 'postnl-for-woocommerce' ),
555 'desc_tip' => true,
556 'default' => Utils::get_base_country(),
557 'options' => WC()->countries->get_countries(),
558 'placeholder' => '',
559 ),
560 'merchant_codes_repeater' => array(
561 'title' => esc_html__( 'Merchant Customs Code', 'postnl-for-woocommerce' ),
562 'type' => 'repeater',
563 'description' => esc_html__( 'Add merchant codes for specific non-EU countries.', 'postnl-for-woocommerce' ),
564 'desc_tip' => true,
565 'for_country' => array( 'NL', 'BE' ),
566
567 ),
568
569 'printer_email_title' => array(
570 'title' => esc_html__( 'Printer &amp; Email Settings', 'postnl-for-woocommerce' ),
571 'type' => 'title',
572 'description' => esc_html__( 'Please configure your printer and email preferences.', 'postnl-for-woocommerce' ),
573 ),
574 'printer_type' => array(
575 'title' => esc_html__( 'Printer Type', 'postnl-for-woocommerce' ),
576 'type' => 'select',
577 'description' => esc_html__( 'It is not recommended to send .pdf files/labels directly to a Zebra printer If you want to send it directly to your Zebra printer, please use .gif files or the native (generic) zpl printer type', 'postnl-for-woocommerce' ),
578 'desc_tip' => true,
579 'default' => 'PDF',
580 'options' => array(
581 'PDF' => 'PDF',
582 'GIF' => 'GIF',
583 'JPG' => 'JPG',
584 'ZPL' => 'ZPL',
585 ),
586 ),
587 'printer_type_resolution' => array(
588 'title' => esc_html__( 'DPI', 'postnl-for-woocommerce' ),
589 'type' => 'select',
590 'default' => '600',
591 'options' => array(
592 '600' => '600',
593 '300' => '300',
594 '200' => '200',
595 ),
596 ),
597 'label_format' => array(
598 'title' => esc_html__( 'Label Format', 'postnl-for-woocommerce' ),
599 'type' => 'select',
600 'description' => esc_html__( 'Use A6 format in case you use a labelprinter. Use A4 format for other regular printers.', 'postnl-for-woocommerce' ),
601 'desc_tip' => true,
602 'default' => 'A6',
603 'options' => array(
604 'A6' => 'A6',
605 'A4' => 'A4',
606 ),
607 'class' => 'wc-enhanced-select',
608 ),
609 'shipping_confirmation_email' => array(
610 'title' => esc_html__( 'Shipping confirmation e-mail address', 'postnl-for-woocommerce' ),
611 'type' => 'email',
612 'description' => esc_html__( 'This e-mail address will be used by PostNL for shipping confirmations. If left empty, no sender e-mail will be included.', 'postnl-for-woocommerce' ),
613 'desc_tip' => true,
614 ),
615 'woocommerce_email' => array(
616 'title' => esc_html__( 'WooCommerce Email', 'postnl-for-woocommerce' ),
617 'type' => 'checkbox',
618 'label' => esc_html__( 'When PostNL label is created send email to customer.', 'postnl-for-woocommerce' ),
619 'description' => esc_html__( 'When PostNL label is created send email to customer.', 'postnl-for-woocommerce' ),
620 'desc_tip' => true,
621 'default' => '',
622 'placeholder' => '',
623 ),
624 'woocommerce_email_text' => array(
625 'title' => esc_html__( 'WooCommerce Email Text', 'postnl-for-woocommerce' ),
626 'type' => 'text',
627 'description' => esc_html__( 'Text added for tracking note email.', 'postnl-for-woocommerce' ),
628 'desc_tip' => true,
629 'default' => esc_html__( 'This is your track and track link {tracking-link}', 'postnl-for-woocommerce' ),
630 'placeholder' => esc_html__( 'This is your track and track link {tracking-link}', 'postnl-for-woocommerce' ),
631 ),
632 // Default shipping Options Settings.
633 'default_shipping_options_title' => array(
634 'title' => esc_html__( 'Default shipping Options Settings', 'postnl-for-woocommerce' ),
635 'type' => 'title',
636 'description' => esc_html__( 'Please select Default shipping Options.', 'postnl-for-woocommerce' ),
637 'for_country' => array( 'NL' ),
638 ),
639 'default_shipping_options_nl' => array(
640 'title' => __( 'Shipping options domestic', 'postnl-for-woocommerce' ),
641 'type' => 'select',
642 'description' => __( 'Select a default shipping option for domestic orders that are shipped with PostNL.', 'postnl-for-woocommerce' ),
643 'default' => 'standard_shipment',
644 'for_country' => array( 'NL' ),
645 'options' => array(
646 'standard_shipment' => __( 'Standard shipment', 'postnl-for-woocommerce' ),
647 'id_check' => __( 'ID Check (18+)', 'postnl-for-woocommerce' ),
648 'id_check|insured_shipping' => __( 'ID Check (18+) + Insured Shipping', 'postnl-for-woocommerce' ),
649 // 'insured_shipping' => __( 'Insured Shipping', 'postnl-for-woocommerce' ),
650 'return_no_answer' => __( 'Return if no answer', 'postnl-for-woocommerce' ),
651 'signature_on_delivery' => __( 'Signature on Delivery', 'postnl-for-woocommerce' ),
652 'only_home_address' => __( 'Only Home Address', 'postnl-for-woocommerce' ),
653 'letterbox' => __( 'Letterboxparcel Standard (24 hours)', 'postnl-for-woocommerce' ),
654 'letterbox_48' => __( 'Letterboxparcel 48 hours', 'postnl-for-woocommerce' ),
655 'signature_on_delivery|insured_shipping' => __( 'Signature on Delivery + Insured Shipping', 'postnl-for-woocommerce' ),
656 'signature_on_delivery|return_no_answer' => __( 'Signature on Delivery + Return if no answer', 'postnl-for-woocommerce' ),
657 'insured_shipping|return_no_answer|signature_on_delivery' => __( 'Insured Shipping + Return if no answer + Signature on Delivery', 'postnl-for-woocommerce' ),
658 'only_home_address|return_no_answer' => __( 'Only Home Address + Return if no answer', 'postnl-for-woocommerce' ),
659 'only_home_address|return_no_answer|signature_on_delivery' => __( 'Only Home Address + Return if no answer + Signature on Delivery', 'postnl-for-woocommerce' ),
660 'only_home_address|signature_on_delivery' => __( 'Only Home Address + Signature on Delivery', 'postnl-for-woocommerce' ),
661 'delivery_code_at_door|insured_shipping' => esc_html__( 'Delivery Code at Door + Insured Shipping', 'postnl-for-woocommerce' ),
662 ),
663 ),
664 'default_shipping_options_be' => array(
665 'title' => __( 'Shipping options Belgium', 'postnl-for-woocommerce' ),
666 'type' => 'select',
667 'description' => __( 'Select a default shipping option for the orders shipped to Belgium with PostNL.', 'postnl-for-woocommerce' ),
668 'default' => 'standard_belgium',
669 'for_country' => array( 'NL' ),
670 'options' => array(
671 'standard_belgium' => __( 'Standard Shipment Belgium', 'postnl-for-woocommerce' ),
672 'standard_belgium|only_home_address' => __( 'Standard Shipment Belgium + Only Home Address', 'postnl-for-woocommerce' ),
673 'standard_belgium|signature_on_delivery' => __( 'Standard Shipment Belgium + Signature on Delivery', 'postnl-for-woocommerce' ),
674 'standard_belgium|insured_shipping' => __( 'Standard Shipment Belgium + Insured Shipping', 'postnl-for-woocommerce' ),
675 'mailboxpacket' => __( 'Boxable Packet', 'postnl-for-woocommerce' ),
676 'mailboxpacket|track_and_trace' => __( 'Boxable Packet + Track & Trace', 'postnl-for-woocommerce' ),
677 'packets' => __( 'Packets', 'postnl-for-woocommerce' ),
678 'packets|track_and_trace' => __( 'Packets + Track & Trace', 'postnl-for-woocommerce' ),
679 'packets|track_and_trace|insured_shipping' => __( 'Packets + Track & Trace + Insured', 'postnl-for-woocommerce' ),
680 ),
681 ),
682 'default_shipping_options_eu' => array(
683 'title' => __( 'Shipping options EU', 'postnl-for-woocommerce' ),
684 'type' => 'select',
685 'description' => __( 'Select a default shipping option for the orders shipped within European Union zone.', 'postnl-for-woocommerce' ),
686 'default' => 'eu_parcel|track_and_trace',
687 'for_country' => array( 'NL' ),
688 'options' => array(
689 'eu_parcel|track_and_trace' => __( 'EU Parcel + Track & Trace', 'postnl-for-woocommerce' ),
690 'eu_parcel|track_and_trace|insured_shipping' => __( 'EU Parcel + Track & Trace + Insured', 'postnl-for-woocommerce' ),
691 'eu_parcel|track_and_trace|insured_plus' => __( 'EU Parcel + Track & Trace + Insured Plus', 'postnl-for-woocommerce' ),
692 'mailboxpacket' => __( 'Boxable Packet', 'postnl-for-woocommerce' ),
693 'mailboxpacket|track_and_trace' => __( 'Boxable Packet + Track & Trace', 'postnl-for-woocommerce' ),
694 'packets' => __( 'Packets', 'postnl-for-woocommerce' ),
695 'packets|track_and_trace' => __( 'Packets + Track & Trace', 'postnl-for-woocommerce' ),
696 'packets|track_and_trace|insured_shipping' => __( 'Packets + Track & Trace + Insured', 'postnl-for-woocommerce' ),
697 ),
698 ),
699 'default_shipping_options_row' => array(
700 'title' => __( 'Default Shipping International', 'postnl-for-woocommerce' ),
701 'type' => 'select',
702 'description' => __( 'Shipping options non-EU (outside the EU borders).', 'postnl-for-woocommerce' ),
703 'default' => 'parcel_non_eu|track_and_trace',
704 'for_country' => array( 'NL' ),
705 'options' => array(
706 'parcel_non_eu|track_and_trace' => __( 'Parcel non-EU + Track & Trace', 'postnl-for-woocommerce' ),
707 'parcel_non_eu|track_and_trace|insured_shipping' => __( 'Parcel non-EU + Track & Trace + Insured', 'postnl-for-woocommerce' ),
708 'parcel_non_eu|track_and_trace|insured_plus' => __( 'Parcel non-EU + Track & Trace + Insured Plus', 'postnl-for-woocommerce' ),
709 'mailboxpacket' => __( 'Boxable Packet', 'postnl-for-woocommerce' ),
710 'mailboxpacket|track_and_trace' => __( 'Boxable Packet + Track & Trace', 'postnl-for-woocommerce' ),
711 'packets' => __( 'Packets', 'postnl-for-woocommerce' ),
712 'packets|track_and_trace' => __( 'Packets + Track & Trace', 'postnl-for-woocommerce' ),
713 'packets|track_and_trace|insured_shipping' => __( 'Packets + Track & Trace + Insured', 'postnl-for-woocommerce' ),
714 ),
715 ),
716 'default_shipping_options_pickup' => array(
717 'title' => __( 'Default Shipping Pickup', 'postnl-for-woocommerce' ),
718 'type' => 'select',
719 'description' => __( 'Shipping options Pickup.', 'postnl-for-woocommerce' ),
720 'default' => 'id_check',
721 'for_country' => array( 'NL' ),
722 'options' => array(
723 '' => esc_html__( 'Standard Shipping', 'postnl-for-woocommerce' ),
724 'id_check' => esc_html__( 'ID Check (18+)', 'postnl-for-woocommerce' ),
725 'insured_shipping' => esc_html__( 'Insured Shipping', 'postnl-for-woocommerce' ),
726 'id_check|insured_shipping' => esc_html__( 'ID Check (18+) + Insured Shipping', 'postnl-for-woocommerce' ),
727 ),
728 ),
729 'default_automatic_letterboxparcel_product' => array(
730 'title' => esc_html__( 'Default automatic letterboxparcel product', 'postnl-for-woocommerce' ),
731 'type' => 'select',
732 'description' => '',
733 'default' => 'letterbox',
734 'for_country' => array( 'NL' ),
735 'options' => array(
736 'letterbox' => esc_html__( 'Letterboxparcel Standard (24 hours)', 'postnl-for-woocommerce' ),
737 'letterbox_48' => esc_html__( 'Letterboxparcel 48 hours', 'postnl-for-woocommerce' ),
738 'customer_decide' => esc_html__( 'Let customer decide', 'postnl-for-woocommerce' ),
739 ),
740 ),
741 'auto_complete_order' => array(
742 'title' => esc_html__( 'Automatically change order status to Completed', 'postnl-for-woocommerce' ),
743 'type' => 'checkbox',
744 'label' => esc_html__( 'Automatically change order status to Completed once an order has been pre-alerted and printed', 'postnl-for-woocommerce' ),
745 'description' => esc_html__( 'Automatically change order status to Completed once an order has been pre-alerted and printed', 'postnl-for-woocommerce' ),
746 'desc_tip' => true,
747 'default' => '',
748 'placeholder' => '',
749 ),
750
751 );
752
753 // The legacy key fields are shown only when a key is already stored: a
754 // fresh install enters its key in the new "API Key" field alone. The
755 // decision is made on the saved value (not the posted one) so a failed
756 // save does not make the field flicker in and out. Reading the raw option
757 // directly avoids recursing through get_country_option()/filter_setting_fields().
758 if ( '' === trim( (string) $this->get_option( 'api_keys' ) ) ) {
759 unset( $fields['api_keys'] );
760 }
761
762 if ( '' === trim( (string) $this->get_option( 'api_keys_sandbox' ) ) ) {
763 unset( $fields['api_keys_sandbox'] );
764 }
765
766 return $fields;
767 }
768
769 /**
770 * Filter the setting fields based on store country.
771 *
772 * @param String $country Two characters country code.
773 * @param bool $only_field_country Flag to check if it only return for the field with 'for_country' array exists.
774 *
775 * @return array
776 */
777 public function filter_setting_fields( $country, $only_field_country = false, $settings = false ) {
778 $setting_fields = $this->get_setting_fields();
779 if ( $country == 'BE' && ! $settings ) {
780 $setting_fields['default_shipping_options_title'] =
781 array(
782 'title' => esc_html__( 'Default shipping Options Settings', 'postnl-for-woocommerce' ),
783 'type' => 'title',
784 'description' => esc_html__( 'Please select Default shipping Options.', 'postnl-for-woocommerce' ),
785 'for_country' => array( 'BE' ),
786 );
787
788 $setting_fields['default_shipping_options_row'] =
789 array(
790 'title' => __( 'Default Shipping International', 'postnl-for-woocommerce' ),
791 'type' => 'select',
792 'description' => __( 'Select a default shipping option for the orders shipped internationally (outside the EU borders).', 'postnl-for-woocommerce' ),
793 'default' => 'parcel_non_eu|track_and_trace|insured_plus',
794 'for_country' => array( 'BE' ),
795 'options' => array(
796 'parcel_non_eu|track_and_trace|insured_plus' => __( 'Parcel non-EU + Track & Trace + Insured Plus', 'postnl-for-woocommerce' ),
797 ),
798 );
799 }
800 $country_fields = array_filter(
801 $setting_fields,
802 function ( $field ) use ( $country, $only_field_country ) {
803 if ( empty( $field['for_country'] ) && false === $only_field_country ) {
804 return true;
805 }
806
807 if ( ! empty( $field['for_country'] ) && is_array( $field['for_country'] ) && in_array( $country, $field['for_country'], true ) ) {
808 return true;
809 }
810
811 if ( ! empty( $field['for_country'] ) && $field['for_country'] === $country ) {
812 return true;
813 }
814
815 return false;
816 }
817 );
818
819 return $country_fields;
820 }
821
822 /**
823 * Return NL setting fields only.
824 *
825 * @param bool $only_field_country Flag to check if it only return for the field with 'for_country' array exists.
826 *
827 * @return array
828 */
829 public function nl_setting_fields( $only_field_country = false ) {
830 return $this->filter_setting_fields( 'NL', $only_field_country );
831 }
832
833 /**
834 * Return BE setting fields only.
835 *
836 * @param bool $only_field_country Flag to check if it only return for the field with 'for_country' array exists.
837 *
838 * @return array
839 */
840 public function be_setting_fields( $only_field_country = false ) {
841 return $this->filter_setting_fields( 'BE', $only_field_country, true );
842 }
843
844 /**
845 * Get setting option value based on country.
846 *
847 * @param String $field Field name.
848 * @param String $default_value Default value if the field value is empty.
849 *
850 * @return String
851 */
852 public function get_country_option( $field, $default_value = '' ) {
853 $base_country = Utils::get_base_country();
854 $fields_country = array_keys( $this->filter_setting_fields( $base_country, false ) );
855
856 return in_array( $field, $fields_country, true ) ? $this->get_option( $field, $default_value ) : '';
857 }
858
859 /**
860 * Get API Key from the settings.
861 *
862 * @return String
863 */
864 public function get_api_key() {
865 return $this->get_country_option( 'api_keys', '' );
866 }
867
868 /**
869 * Get sandbox API Key from the settings.
870 *
871 * @return String
872 */
873 public function get_api_key_sandbox() {
874 return $this->get_country_option( 'api_keys_sandbox', '' );
875 }
876
877 /**
878 * Option storing the SHA-256 hash of the new API key value that last
879 * passed validation. Storing a hash (rather than a global yes/no flag)
880 * binds the validated state to the exact key value, so any out-of-band
881 * edit or partial save naturally invalidates the flag.
882 */
883 const NEW_API_KEY_VALIDATED_HASH_OPTION = 'postnl_api_keys_new_validated_hash';
884
885 /**
886 * Get the raw value of the new sandbox API key as entered by the merchant.
887 *
888 * @return string
889 */
890 public function get_api_key_sandbox_new() {
891 return trim( (string) $this->get_country_option( 'api_keys_sandbox_new', '' ) );
892 }
893
894 /**
895 * Get the raw value of the new API key for the current environment.
896 *
897 * PostNL issues environment-scoped keys, so sandbox and production each have
898 * their own new-key field. Returning the field that matches the active
899 * environment keeps every V4 consumer (Service_Factory, the adoption header,
900 * the effective-key fallback) pointed at the right key without each caller
901 * having to branch on the environment itself.
902 *
903 * @return string
904 */
905 public function get_api_key_new() {
906 if ( $this->is_sandbox() ) {
907 return $this->get_api_key_sandbox_new();
908 }
909
910 return trim( (string) $this->get_country_option( 'api_keys_new', '' ) );
911 }
912
913 /**
914 * The original (pre-migration) API key for the current environment.
915 *
916 * @return string
917 */
918 public function get_original_api_key() {
919 return $this->is_sandbox()
920 ? trim( (string) $this->get_api_key_sandbox() )
921 : trim( (string) $this->get_api_key() );
922 }
923
924 /**
925 * Name of the option storing the validated-key hash for a given environment.
926 *
927 * The validated flag is environment-scoped: a key validated in production must
928 * not be treated as validated in sandbox (and vice versa), otherwise the V4
929 * gate would route a production key against the sandbox host, or the reverse.
930 * A single option cannot hold both, since validating one environment would
931 * overwrite the other, so each environment gets its own option.
932 *
933 * @param bool|null $is_sandbox Environment to scope to, or null for the current one.
934 *
935 * @return string
936 */
937 protected function validated_hash_option_name( $is_sandbox = null ) {
938 $is_sandbox = ( null === $is_sandbox ) ? $this->is_sandbox() : (bool) $is_sandbox;
939
940 return self::NEW_API_KEY_VALIDATED_HASH_OPTION . ( $is_sandbox ? '_sandbox' : '' );
941 }
942
943 /**
944 * Whether the currently-entered new API key matches the key that last
945 * passed validation against the PostNL API for the current environment.
946 *
947 * @return bool
948 */
949 public function is_api_key_new_validated() {
950 return $this->is_api_key_new_validated_value( $this->get_api_key_new() );
951 }
952
953 /**
954 * Whether a specific key value matches the key that last passed
955 * validation. Takes the value explicitly so callers (e.g. the save-time
956 * handler) can check the freshly-entered key without relying on the
957 * settings object's in-memory cache being up to date.
958 *
959 * @param string $key Candidate key value.
960 * @param bool|null $is_sandbox Environment to check, or null for the current one.
961 *
962 * @return bool
963 */
964 public function is_api_key_new_validated_value( $key, $is_sandbox = null ) {
965 $key = trim( (string) $key );
966 if ( '' === $key ) {
967 return false;
968 }
969
970 $stored = (string) get_option( $this->validated_hash_option_name( $is_sandbox ), '' );
971 if ( '' === $stored ) {
972 return false;
973 }
974
975 return hash_equals( $stored, hash( 'sha256', $key ) );
976 }
977
978 /**
979 * Record that the currently-entered new API key has passed validation,
980 * or clear the flag entirely. The hash binds the flag to the exact key
981 * value the merchant just successfully tested, scoped to its environment.
982 *
983 * @param bool $validated Validation outcome.
984 * @param string|null $key The exact key value that was validated. When
985 * omitted, falls back to the stored setting —
986 * but callers running mid-save should pass the
987 * freshly-entered value to avoid hashing a
988 * stale cached value.
989 * @param bool|null $is_sandbox Environment to scope to, or null for the current one.
990 */
991 public function set_api_key_new_validated( $validated, $key = null, $is_sandbox = null ) {
992 $option = $this->validated_hash_option_name( $is_sandbox );
993
994 if ( ! $validated ) {
995 delete_option( $option );
996 return;
997 }
998
999 $key = trim( (string) ( null === $key ? $this->get_api_key_new() : $key ) );
1000 if ( '' === $key ) {
1001 delete_option( $option );
1002 return;
1003 }
1004
1005 update_option( $option, hash( 'sha256', $key ) );
1006 }
1007
1008 /**
1009 * Return the API key the plugin should actually send to PostNL for the
1010 * current environment. Falls back to the original key whenever the new
1011 * key is empty, identical, or has not been validated.
1012 *
1013 * @return string
1014 */
1015 public function get_effective_api_key() {
1016 $original = $this->get_original_api_key();
1017 $new_key = $this->get_api_key_new();
1018
1019 if ( '' === $new_key ) {
1020 return $original;
1021 }
1022
1023 if ( $new_key === $original ) {
1024 return $original;
1025 }
1026
1027 if ( ! $this->is_api_key_new_validated() ) {
1028 return $original;
1029 }
1030
1031 return $new_key;
1032 }
1033
1034 /**
1035 * Option storing the reason the new key last failed validation, so the
1036 * settings status row can tell "key rejected" apart from "could not reach
1037 * PostNL" or "customer details missing" — all of which report the same
1038 * "Entered" header value. Only consulted when the header value is "Entered".
1039 */
1040 const NEW_API_KEY_STATUS_OPTION = 'postnl_api_keys_new_status';
1041
1042 /**
1043 * Map the new-key state to its NewKey header value. Kept as one pure method
1044 * so the outgoing header and the settings status row can never disagree.
1045 *
1046 * - "No" : the new-key field is empty.
1047 * - "Same" : the new-key field matches the original key.
1048 * - "Entered" : a distinct key was entered but has not passed validation.
1049 * - "Yes" : a distinct new key has been entered and validated.
1050 *
1051 * "Yes" is gated on validation because PostNL defines it as a key that
1052 * "works"; a key that failed our validation reports "Entered" so PostNL does
1053 * not count the merchant as ready to migrate.
1054 *
1055 * @param string $new_key The entered new key.
1056 * @param string $original The original (pre-migration) key.
1057 * @param bool $validated Whether the new key passed validation.
1058 *
1059 * @return string
1060 */
1061 protected function derive_new_key_header_value( $new_key, $original, $validated ) {
1062 if ( '' === $new_key ) {
1063 return 'No';
1064 }
1065
1066 if ( $new_key === $original ) {
1067 return 'Same';
1068 }
1069
1070 if ( ! $validated ) {
1071 return 'Entered';
1072 }
1073
1074 return 'Yes';
1075 }
1076
1077 /**
1078 * Value for the NewKey header sent on every outgoing API call, computed for
1079 * the current environment.
1080 *
1081 * @return string
1082 */
1083 public function get_new_key_header_value() {
1084 return $this->derive_new_key_header_value(
1085 $this->get_api_key_new(),
1086 $this->get_original_api_key(),
1087 $this->is_api_key_new_validated()
1088 );
1089 }
1090
1091 /**
1092 * Persist (or clear) the reason the new key last failed validation, scoped
1093 * to the given environment.
1094 *
1095 * @param string $reason One of 'invalid', 'rejected', 'unreachable', 'missing', or '' to clear.
1096 * @param bool|null $is_sandbox Environment to scope to, or null for the current one.
1097 */
1098 public function set_new_key_status_reason( $reason, $is_sandbox = null ) {
1099 $option = self::NEW_API_KEY_STATUS_OPTION . ( $this->resolve_is_sandbox( $is_sandbox ) ? '_sandbox' : '' );
1100
1101 if ( '' === $reason ) {
1102 delete_option( $option );
1103 return;
1104 }
1105
1106 update_option( $option, $reason );
1107 }
1108
1109 /**
1110 * PostNL developer portal page for the API migration. It explains how to
1111 * upgrade PHP, how to request a new API key via the Self Service (SSAM)
1112 * module, and when to update the plug-in for API v4. Confirmed by PostNL as
1113 * the destination for the migration banners (in place of the Self Service
1114 * portal directly), so customers get the full step-by-step instructions first.
1115 */
1116 const SELF_SERVICE_URL = 'https://developer.postnl.nl/integration-with-postnl/api-overview/future-proof-api-s/plug-ins/';
1117
1118 /**
1119 * Link to the PostNL Business Portal Self Service module, reused across the
1120 * status row and the migration banner.
1121 *
1122 * @return string
1123 */
1124 public function self_service_link() {
1125 return sprintf(
1126 '<a href="%1$s" target="_blank" rel="noopener noreferrer">%2$s</a>',
1127 esc_url( self::SELF_SERVICE_URL ),
1128 esc_html__( 'Self Service module on the PostNL Business Portal', 'postnl-for-woocommerce' )
1129 );
1130 }
1131
1132 /**
1133 * Resolve the status of the new key for a given environment: the header value
1134 * plus a colour, label, a one-line summary and a "what to do next" paragraph
1135 * for the settings status row. The label and colour derive from the same
1136 * header value the API calls send, so the screen and PostNL's adoption count
1137 * can never contradict each other.
1138 *
1139 * @param bool|null $is_sandbox Environment to describe, or null for the current one.
1140 *
1141 * @return array{header:string,label:string,color:string,summary:string,description:string}
1142 */
1143 public function get_new_key_status( $is_sandbox = null ) {
1144 $is_sandbox = $this->resolve_is_sandbox( $is_sandbox );
1145
1146 $new_key = $is_sandbox ? $this->get_api_key_sandbox_new() : trim( (string) $this->get_country_option( 'api_keys_new', '' ) );
1147 $original = $is_sandbox ? trim( (string) $this->get_api_key_sandbox() ) : trim( (string) $this->get_api_key() );
1148 $validated = $this->is_api_key_new_validated_value( $new_key, $is_sandbox );
1149
1150 // The rendered row describes what is actually stored, so the validated
1151 // state it shows is a saved one.
1152 return $this->build_new_key_status( $new_key, $original, $validated, $is_sandbox, true, $this->resolve_new_key_status_reason( $is_sandbox ) );
1153 }
1154
1155 /**
1156 * Map a new-key state to the status row's colour, label, one-line summary and
1157 * "what to do next" paragraph. Pure: every input is passed in, so the settings
1158 * render path and the on-blur endpoint produce identical copy for the same
1159 * state and cannot drift. The label and colour follow the same header value
1160 * the API calls send, so the screen and PostNL's adoption count agree.
1161 *
1162 * @param string $new_key The entered new key.
1163 * @param string $original The original (pre-migration) key; '' on a fresh install.
1164 * @param bool $validated Whether the new key has passed validation.
1165 * @param bool $is_sandbox Environment being described.
1166 * @param bool $saved Whether $validated reflects a saved state. A key that
1167 * validates on blur but has not been saved yet gets the
1168 * amber "works, not saved" state instead of green.
1169 * @param string $reason Persisted/derived failure reason for an entered key.
1170 *
1171 * @return array{header:string,label:string,color:string,summary:string,description:string}
1172 */
1173 public function build_new_key_status( $new_key, $original, $validated, $is_sandbox, $saved, $reason = '' ) {
1174 unset( $is_sandbox );
1175
1176 $header = $this->derive_new_key_header_value( $new_key, $original, $validated );
1177 $link = $this->self_service_link();
1178 $has_old = '' !== trim( (string) $original );
1179
1180 switch ( $header ) {
1181 case 'Yes':
1182 if ( ! $saved ) {
1183 return array(
1184 'header' => $header,
1185 'label' => __( 'Works, not saved yet', 'postnl-for-woocommerce' ),
1186 'color' => '#dba617',
1187 'summary' => __( 'This key works. Save changes to start using it.', 'postnl-for-woocommerce' ),
1188 'description' => '',
1189 );
1190 }
1191
1192 return array(
1193 'header' => $header,
1194 'label' => __( 'Valid', 'postnl-for-woocommerce' ),
1195 'color' => '#008a20',
1196 'summary' => __( 'Your API key is working and will be used for the new PostNL APIs.', 'postnl-for-woocommerce' ),
1197 'description' => '',
1198 );
1199
1200 case 'Same':
1201 return array(
1202 'header' => $header,
1203 'label' => __( 'Same as old key', 'postnl-for-woocommerce' ),
1204 'color' => '#dba617',
1205 'summary' => __( 'This is the key you already had, not a new one.', 'postnl-for-woocommerce' ),
1206 // translators: %s is a link to the PostNL Business Portal Self Service module.
1207 'description' => sprintf( __( 'You need a separate key. Request one from the %s, then paste it into the field above.', 'postnl-for-woocommerce' ), $link ),
1208 );
1209
1210 case 'Entered':
1211 return array_merge(
1212 array( 'header' => $header ),
1213 $this->get_new_key_invalid_copy( $reason, $has_old, $link )
1214 );
1215
1216 default:
1217 return array(
1218 'header' => $header,
1219 'label' => __( 'Not set', 'postnl-for-woocommerce' ),
1220 'color' => '#757575',
1221 'summary' => __( 'You have not entered your API key yet.', 'postnl-for-woocommerce' ),
1222 'description' => $has_old
1223 // translators: %s is a link to the PostNL Business Portal Self Service module.
1224 ? sprintf( __( 'Request your new key from the %s and enter it above to switch over from your old key.', 'postnl-for-woocommerce' ), $link )
1225 // translators: %s is a link to the PostNL Business Portal Self Service module.
1226 : sprintf( __( 'Request your key from the %s and enter it above — the plug-in needs it to connect to PostNL.', 'postnl-for-woocommerce' ), $link ),
1227 );
1228 }
1229 }
1230
1231 /**
1232 * The failure reason to describe in the status row. Missing customer details
1233 * is decided live — if they are blank now, that is the reason whatever the
1234 * last save recorded — otherwise the reason persisted at save time is used.
1235 *
1236 * @param bool $is_sandbox Environment to resolve for.
1237 *
1238 * @return string One of the Key_Validator REASON_* slugs, or ''.
1239 */
1240 protected function resolve_new_key_status_reason( $is_sandbox ) {
1241 if ( '' === trim( (string) $this->get_customer_code() ) || '' === trim( (string) $this->get_customer_num() ) ) {
1242 return Key_Validator::REASON_MISSING;
1243 }
1244
1245 return (string) get_option( self::NEW_API_KEY_STATUS_OPTION . ( $is_sandbox ? '_sandbox' : '' ), '' );
1246 }
1247
1248 /**
1249 * Label, colour, summary and description for an entered key that is not in
1250 * use, per reason. Only a genuine rejection is red "Not valid"; an outage, a
1251 * mismatch or missing details read as amber "could not check", so an outage
1252 * never tells the merchant their key is invalid. Whether an old key is still
1253 * carrying the plugin is passed in rather than re-read, so the copy is correct
1254 * on a fresh install (where nothing is in use).
1255 *
1256 * @param string $reason One of the Key_Validator REASON_* slugs.
1257 * @param bool $has_old Whether a usable old key is still stored.
1258 * @param string $link Self Service link markup.
1259 *
1260 * @return array{label:string,color:string,summary:string,description:string}
1261 */
1262 protected function get_new_key_invalid_copy( $reason, $has_old, $link ) {
1263 $tail = $has_old
1264 ? __( ' The plug-in is still using your old key.', 'postnl-for-woocommerce' )
1265 : __( ' The plug-in has no working key to connect with yet.', 'postnl-for-woocommerce' );
1266
1267 switch ( $reason ) {
1268 case Key_Validator::REASON_REJECTED:
1269 return array(
1270 'label' => __( 'Could not check', 'postnl-for-woocommerce' ),
1271 'color' => '#dba617',
1272 'summary' => __( 'PostNL could not process the check.', 'postnl-for-woocommerce' ) . $tail,
1273 'description' => __( 'This usually means the Customer Code or Customer Number does not match this key. Check them and save again.', 'postnl-for-woocommerce' ),
1274 );
1275
1276 case Key_Validator::REASON_MISSING:
1277 return array(
1278 'label' => __( 'Not checked', 'postnl-for-woocommerce' ),
1279 'color' => '#dba617',
1280 'summary' => __( 'We have not checked this key yet.', 'postnl-for-woocommerce' ) . $tail,
1281 'description' => __( 'Fill in your Customer Code and Customer Number, then save again.', 'postnl-for-woocommerce' ),
1282 );
1283
1284 case Key_Validator::REASON_UNREACHABLE:
1285 return array(
1286 'label' => __( 'Could not check', 'postnl-for-woocommerce' ),
1287 'color' => '#dba617',
1288 'summary' => __( 'We could not reach PostNL to check this key.', 'postnl-for-woocommerce' ) . $tail,
1289 'description' => __( 'This is usually temporary. Save again in a few minutes.', 'postnl-for-woocommerce' ),
1290 );
1291
1292 case Key_Validator::REASON_INVALID:
1293 default:
1294 return array(
1295 'label' => __( 'Not valid', 'postnl-for-woocommerce' ),
1296 'color' => '#d63638',
1297 'summary' => __( 'PostNL rejected this key.', 'postnl-for-woocommerce' ) . $tail,
1298 // translators: %s is a link to the PostNL Business Portal Self Service module.
1299 'description' => sprintf( __( 'Check that you copied the whole key with no extra spaces, then save again. If it keeps failing, request a new key from the %s.', 'postnl-for-woocommerce' ), $link ),
1300 );
1301 }
1302 }
1303
1304 /**
1305 * Normalise a nullable environment flag to the current environment.
1306 *
1307 * @param bool|null $is_sandbox Environment flag, or null for the current one.
1308 *
1309 * @return bool
1310 */
1311 protected function resolve_is_sandbox( $is_sandbox ) {
1312 return ( null === $is_sandbox ) ? $this->is_sandbox() : (bool) $is_sandbox;
1313 }
1314
1315 /**
1316 * Get customer number from the settings.
1317 *
1318 * @return String
1319 */
1320 public function get_customer_num() {
1321 return $this->get_country_option( 'customer_num', '' );
1322 }
1323
1324 /**
1325 * Get customer code from the settings.
1326 *
1327 * @return String
1328 */
1329 public function get_customer_code() {
1330 return $this->get_country_option( 'customer_code', '' );
1331 }
1332
1333 /**
1334 * Get location code from the settings.
1335 *
1336 * @return String
1337 */
1338 public function get_location_code() {
1339 /*
1340 Temporarily hardcoded.
1341 return $this->get_country_option( 'location_code', '' );
1342 */
1343
1344 return '123456';
1345 }
1346
1347 /**
1348 * Return true if sandbox mode is ticked.
1349 *
1350 * @return String
1351 */
1352 public function get_environment_mode() {
1353 return $this->get_country_option( 'environment_mode', '' );
1354 }
1355
1356 /**
1357 * Return true if sandbox mode is ticked.
1358 *
1359 * @return Bool
1360 */
1361 public function is_sandbox() {
1362 return ( 'sandbox' === $this->get_environment_mode() );
1363 }
1364
1365 /**
1366 * Get return address default from the settings.
1367 *
1368 * @return String
1369 */
1370 public function get_return_address_default() {
1371 return $this->get_country_option( 'return_address_default', '' );
1372 }
1373
1374 /**
1375 * Get return company name from the settings.
1376 *
1377 * @return String
1378 */
1379 public function get_return_company_name() {
1380 return $this->get_country_option( 'return_company', '' );
1381 }
1382
1383 /**
1384 * Get value of the return address or reply number.
1385 *
1386 * @return bool
1387 */
1388 public function is_return_to_home_enabled() {
1389 if ( 'yes' === $this->get_country_option( 'return_address_or_reply_no', '' ) ) {
1390 return true;
1391 }
1392
1393 return false;
1394 }
1395
1396 /**
1397 * Get value of the return address or reply number.
1398 *
1399 * @return bool
1400 */
1401 public function is_smart_return_enabled() {
1402 if ( 'yes' === $this->get_country_option( 'activate_smart_return', '' ) ) {
1403 return true;
1404 }
1405
1406 return false;
1407 }
1408
1409 /**
1410 * Get return reply number from the settings.
1411 *
1412 * @return String
1413 */
1414 public function get_return_reply_number() {
1415 return $this->get_country_option( 'return_replynumber', '' );
1416 }
1417
1418 /**
1419 * Get freepost city from the settings.
1420 *
1421 * @return String
1422 */
1423 public function get_freepost_city() {
1424 return $this->get_country_option( 'freepost_city', '' );
1425 }
1426
1427 /**
1428 * Get freepost zipcode from the settings.
1429 *
1430 * @return String
1431 */
1432 public function get_freepost_zipcode() {
1433 return $this->get_country_option( 'freepost_zip', '' );
1434 }
1435
1436 /**
1437 * Get return street address from the settings.
1438 *
1439 * @return String
1440 */
1441 public function get_return_address_street() {
1442 return $this->get_country_option( 'return_address_street', '' );
1443 }
1444
1445 /**
1446 * Get return house number address from the settings.
1447 *
1448 * @return String
1449 */
1450 public function get_return_address_house_no() {
1451 return $this->get_country_option( 'return_address_house_no', '' );
1452 }
1453
1454 /**
1455 * Get return house number extension address from the settings.
1456 *
1457 * @return String
1458 */
1459 public function get_return_address_house_noext() {
1460 return $this->get_country_option( 'return_address_house_noext', '' );
1461 }
1462
1463 /**
1464 * Get return city address from the settings.
1465 *
1466 * @return String
1467 */
1468 public function get_return_city() {
1469 return $this->get_country_option( 'return_address_city', '' );
1470 }
1471
1472 /**
1473 * Get return state address from the settings.
1474 *
1475 * @return String
1476 */
1477 public function get_return_state() {
1478 return $this->get_country_option( 'return_address_state', '' );
1479 }
1480
1481 /**
1482 * Get return state address from the settings.
1483 *
1484 * @return String
1485 */
1486 public function get_return_zipcode() {
1487 return $this->get_country_option( 'return_address_zip', '' );
1488 }
1489
1490 /**
1491 * Get return phone number from the settings.
1492 *
1493 * @return String
1494 */
1495 public function get_return_phone() {
1496 return $this->get_country_option( 'return_phone', '' );
1497 }
1498
1499 /**
1500 * Get return email from the settings.
1501 *
1502 * @return String
1503 */
1504 public function get_return_email() {
1505 return $this->get_country_option( 'return_email', '' );
1506 }
1507
1508 /**
1509 * Get return customer code from the settings.
1510 *
1511 * @return String
1512 */
1513 public function get_return_customer_code() {
1514 return $this->get_country_option( 'return_customer_code', '' );
1515 }
1516
1517 /**
1518 * Get return shipment and labels select value.
1519 *
1520 * PostNL discontinues the "Shipment & Return" label product on 1 July 2026.
1521 * Any value still stored as 'shipping_return' is coerced to 'none' at read
1522 * time so outbound label generation never requests the discontinued product,
1523 * even on stores the one-time revert migration has not reached.
1524 *
1525 * @return String
1526 */
1527 public function get_return_shipment_and_labels() {
1528 $value = $this->get_country_option( 'return_shipment_and_labels', '' );
1529
1530 return 'shipping_return' === $value ? 'none' : $value;
1531 }
1532
1533 /**
1534 * Get value of the return shipment and labels all checkbox.
1535 *
1536 * @return String
1537 */
1538 public function get_return_shipment_and_labels_all() {
1539 return $this->get_country_option( 'return_shipment_and_labels_all', '' );
1540 }
1541
1542 /**
1543 * Get return customer code from the settings.
1544 *
1545 * @return String
1546 */
1547 public function get_return_direct_print_label() {
1548 return $this->get_country_option( 'return_direct_print_label', '' );
1549 }
1550
1551 /**
1552 * Return true if 'print returnlabel directly with shipping label' field is ticked.
1553 *
1554 * @return Bool
1555 */
1556 public function is_return_direct_print_enabled() {
1557 return ( 'yes' === $this->get_return_direct_print_label() );
1558 }
1559
1560 /**
1561 * Get the letterboxparcel (24 hours) extra fee from the settings.
1562 *
1563 * @since 5.9.6
1564 *
1565 * @return float
1566 */
1567 public function get_letterbox_24_fee() {
1568 return (float) $this->get_country_option( 'letterbox_24_fee' );
1569 }
1570
1571 /**
1572 * Get enable delivery from the settings.
1573 *
1574 * @return String
1575 */
1576 public function get_enable_delivery() {
1577 return $this->get_country_option( 'enable_delivery', '' );
1578 }
1579
1580 /**
1581 * Return true if delivery field is ticked.
1582 *
1583 * @return Bool
1584 */
1585 public function is_delivery_enabled() {
1586 return ( 'yes' === $this->get_enable_delivery() );
1587 }
1588
1589 /**
1590 * Get enable pickup points from the settings.
1591 *
1592 * @return String
1593 */
1594 public function get_enable_pickup_points() {
1595 return $this->get_country_option( 'enable_pickup_points' );
1596 }
1597
1598 /**
1599 * Get pick-up delivery fee from the settings.
1600 *
1601 * @return float
1602 */
1603 public function get_pickup_delivery_fee() {
1604 return (float) $this->get_country_option( 'pickup_delivery_fee' );
1605 }
1606
1607 /**
1608 * Return true if delivery days field is ticked.
1609 *
1610 * @return Bool
1611 */
1612 public function is_pickup_points_enabled() {
1613 return ( 'yes' === $this->get_enable_pickup_points() );
1614 }
1615
1616 /**
1617 * Get number pickup points from the settings.
1618 *
1619 * @return Int
1620 */
1621 public function get_number_pickup_points() {
1622 /*
1623 Temporarily hardcoded.
1624 return $this->get_country_option( 'number_pickup_points' );
1625 */
1626
1627 return 3;
1628 }
1629
1630 /**
1631 * Get enable delivery days from the settings.
1632 *
1633 * @return String
1634 */
1635 public function get_enable_delivery_days() {
1636 return $this->get_country_option( 'enable_delivery_days' );
1637 }
1638
1639 /**
1640 * Return true if delivery days field is ticked.
1641 *
1642 * @return Bool
1643 */
1644 public function is_delivery_days_enabled() {
1645 return ( 'yes' === $this->get_enable_delivery_days() );
1646 }
1647
1648 /**
1649 * Get delivery days fees the settings.
1650 *
1651 * @return float
1652 */
1653 public function get_delivery_days_fee() {
1654 return (float) $this->get_country_option( 'delivery_days_fee' );
1655 }
1656
1657 /**
1658 * Get letterbox fee from the settings.
1659 * Returns null when the field is empty (meaning: do not override).
1660 *
1661 * @return float|null
1662 */
1663 public function get_letterbox_fee() {
1664 $value = $this->get_country_option( 'letterbox_fee' );
1665 return ( '' !== $value ) ? (float) $value : null;
1666 }
1667
1668 /**
1669 * Get number delivery days from the settings.
1670 *
1671 * @return Int
1672 */
1673 public function get_number_delivery_days() {
1674 return $this->get_country_option( 'number_delivery_days' );
1675 }
1676
1677 /**
1678 * Get default checkout tab from the settings.
1679 *
1680 * @return string 'delivery_day' or 'dropoff_points'
1681 */
1682 public function get_default_checkout_tab() {
1683 $value = $this->get_country_option( 'default_checkout_tab' );
1684 if ( in_array( $value, array( 'delivery_day', 'dropoff_points' ), true ) ) {
1685 return $value;
1686 }
1687 if ( 'BE' === Utils::get_base_country() ) {
1688 // TODO: gate on is_pickup_points_enabled(). When pickup is disabled
1689 // we still return 'dropoff_points' here, an id no tab list contains.
1690 // Container.php and the React resolver both fall back, so it's
1691 // harmless today, but the contract should be: never return an id
1692 // that can't render. See PR #306 review.
1693 return 'dropoff_points';
1694 }
1695 return 'delivery_day';
1696 }
1697
1698 /**
1699 * Get enable evening delivery from the settings.
1700 *
1701 * @return String
1702 */
1703 public function get_enable_evening_delivery() {
1704 return $this->get_country_option( 'enable_evening_delivery' );
1705 }
1706
1707 /**
1708 * Return true if evening delivery field is ticked.
1709 *
1710 * @return Bool
1711 */
1712 public function is_evening_delivery_enabled() {
1713 return ( 'yes' === $this->get_enable_evening_delivery() );
1714 }
1715
1716 /**
1717 * Get evening delivery fee from the settings.
1718 *
1719 * @return String
1720 */
1721 public function get_evening_delivery_fee() {
1722 return $this->get_country_option( 'evening_delivery_fee' );
1723 }
1724
1725 /**
1726 * Get enable morning delivery from the settings.
1727 *
1728 * @return String
1729 */
1730 public function get_enable_morning_delivery() {
1731 return $this->get_country_option( 'enable_morning_delivery' );
1732 }
1733
1734 /**
1735 * Return true if evening delivery field is ticked.
1736 *
1737 * @return Bool
1738 */
1739 public function is_morning_delivery_enabled() {
1740 return ( 'yes' === $this->get_enable_morning_delivery() );
1741 }
1742
1743 /**
1744 * Get evening delivery fee from the settings.
1745 *
1746 * @return String
1747 */
1748 public function get_morning_delivery_fee() {
1749 return $this->get_country_option( 'morning_delivery_fee' );
1750 }
1751
1752 /**
1753 * Get transit time value from the settings.
1754 *
1755 * @return String
1756 */
1757 public function get_transit_time() {
1758 return $this->get_country_option( 'transit_time', '' );
1759 }
1760
1761 /**
1762 * Get cut off time value from the settings.
1763 *
1764 * @return String
1765 */
1766 public function get_cut_off_time() {
1767 return $this->get_country_option( 'cut_off_time', '' );
1768 }
1769
1770 /**
1771 * Get dropoff monday value from the settings.
1772 *
1773 * @return String
1774 */
1775 public function get_dropoff_monday() {
1776 return $this->get_country_option( 'dropoff_day_mon', '' );
1777 }
1778
1779 /**
1780 * Return true if dropoff monday field is ticked.
1781 *
1782 * @return Bool
1783 */
1784 public function is_dropoff_monday_enabled() {
1785 return ( 'yes' === $this->get_dropoff_monday() );
1786 }
1787
1788 /**
1789 * Get dropoff tuesday value from the settings.
1790 *
1791 * @return String
1792 */
1793 public function get_dropoff_tuesday() {
1794 return $this->get_country_option( 'dropoff_day_tue', '' );
1795 }
1796
1797 /**
1798 * Return true if dropoff tuesday field is ticked.
1799 *
1800 * @return Bool
1801 */
1802 public function is_dropoff_tuesday_enabled() {
1803 return ( 'yes' === $this->get_dropoff_tuesday() );
1804 }
1805
1806 /**
1807 * Get dropoff wednesday value from the settings.
1808 *
1809 * @return String
1810 */
1811 public function get_dropoff_wednesday() {
1812 return $this->get_country_option( 'dropoff_day_wed', '' );
1813 }
1814
1815 /**
1816 * Return true if dropoff wednesday field is ticked.
1817 *
1818 * @return Bool
1819 */
1820 public function is_dropoff_wednesday_enabled() {
1821 return ( 'yes' === $this->get_dropoff_wednesday() );
1822 }
1823
1824 /**
1825 * Get dropoff thursday value from the settings.
1826 *
1827 * @return String
1828 */
1829 public function get_dropoff_thursday() {
1830 return $this->get_country_option( 'dropoff_day_thu', '' );
1831 }
1832
1833 /**
1834 * Return true if dropoff thursday field is ticked.
1835 *
1836 * @return Bool
1837 */
1838 public function is_dropoff_thursday_enabled() {
1839 return ( 'yes' === $this->get_dropoff_thursday() );
1840 }
1841
1842 /**
1843 * Get dropoff friday value from the settings.
1844 *
1845 * @return String
1846 */
1847 public function get_dropoff_friday() {
1848 return $this->get_country_option( 'dropoff_day_fri', '' );
1849 }
1850
1851 /**
1852 * Return true if dropoff friday field is ticked.
1853 *
1854 * @return Bool
1855 */
1856 public function is_dropoff_friday_enabled() {
1857 return ( 'yes' === $this->get_dropoff_friday() );
1858 }
1859
1860 /**
1861 * Get dropoff saturday value from the settings.
1862 *
1863 * @return String
1864 */
1865 public function get_dropoff_saturday() {
1866 return $this->get_country_option( 'dropoff_day_sat', '' );
1867 }
1868
1869 /**
1870 * Return true if dropoff saturday field is ticked.
1871 *
1872 * @return Bool
1873 */
1874 public function is_dropoff_saturday_enabled() {
1875 return ( 'yes' === $this->get_dropoff_saturday() );
1876 }
1877
1878 /**
1879 * Get dropoff sunday value from the settings.
1880 *
1881 * @return String
1882 */
1883 public function get_dropoff_sunday() {
1884 return $this->get_country_option( 'dropoff_day_sun', '' );
1885 }
1886
1887 /**
1888 * Return true if dropoff sunday field is ticked.
1889 *
1890 * @return Bool
1891 */
1892 public function is_dropoff_sunday_enabled() {
1893 return ( 'yes' === $this->get_dropoff_sunday() );
1894 }
1895
1896 /**
1897 * Get dropoff days from the settings.
1898 *
1899 * @return array
1900 */
1901 public function get_dropoff_days() {
1902 $dropoff_days = array();
1903
1904 if ( $this->is_dropoff_monday_enabled() ) {
1905 $dropoff_days[] = 'mon';
1906 }
1907
1908 if ( $this->is_dropoff_tuesday_enabled() ) {
1909 $dropoff_days[] = 'tue';
1910 }
1911
1912 if ( $this->is_dropoff_wednesday_enabled() ) {
1913 $dropoff_days[] = 'wed';
1914 }
1915
1916 if ( $this->is_dropoff_thursday_enabled() ) {
1917 $dropoff_days[] = 'thu';
1918 }
1919
1920 if ( $this->is_dropoff_friday_enabled() ) {
1921 $dropoff_days[] = 'fri';
1922 }
1923
1924 if ( $this->is_dropoff_saturday_enabled() ) {
1925 $dropoff_days[] = 'sat';
1926 }
1927
1928 if ( $this->is_dropoff_sunday_enabled() ) {
1929 $dropoff_days[] = 'sun';
1930 }
1931
1932 return $dropoff_days;
1933 }
1934
1935 /**
1936 * Get excluded dropoff days from the settings.
1937 *
1938 * @return array
1939 */
1940 public function get_excluded_dropoff_days() {
1941 $completed_days = array_keys( Utils::days_of_week() );
1942 $dropoff_days = $this->get_dropoff_days();
1943
1944 return array_diff( $completed_days, $dropoff_days );
1945 }
1946
1947 /**
1948 * Get globalpack type barcode from the settings.
1949 *
1950 * @return String
1951 */
1952 public function get_globalpack_barcode_type() {
1953 return $this->get_country_option( 'globalpack_barcode_type', '' );
1954 }
1955
1956 /**
1957 * Get globalpack customer code from the settings.
1958 *
1959 * @return String
1960 */
1961 public function get_globalpack_customer_code() {
1962 return $this->get_country_option( 'globalpack_customer_code', '' );
1963 }
1964
1965 /**
1966 * Get HS Tariff code from the settings.
1967 *
1968 * @return String
1969 */
1970 public function get_hs_tariff_code() {
1971 return $this->get_country_option( 'hs_tariff_code', '' );
1972 }
1973
1974 /**
1975 * Get HS Tariff code from the settings.
1976 *
1977 * @return String
1978 */
1979 public function get_country_origin() {
1980 return $this->get_country_option( 'country_origin', '' );
1981 }
1982
1983 /**
1984 * Get label format from the settings.
1985 *
1986 * @return String
1987 */
1988 public function get_label_format() {
1989 return $this->get_country_option( 'label_format', '' );
1990 }
1991
1992 /**
1993 * Get printer type from the settings.
1994 * PDF by default.
1995 *
1996 * @return String
1997 */
1998 public function get_printer_type() {
1999 $printer_type = $this->get_country_option( 'printer_type', '' );
2000 $resolution = (int) $this->get_country_option( 'printer_type_resolution', 600 );
2001
2002 switch ( $printer_type ) {
2003 case 'JPG':
2004 return sprintf( 'GraphicFile|JPG %d dpi', $resolution );
2005 case 'GIF':
2006 return sprintf( 'GraphicFile|GIF %d dpi', $resolution );
2007 case 'ZPL':
2008 return sprintf( 'Zebra|Generic ZPL II %d dpi', $resolution );
2009 default:
2010 return 'GraphicFile|PDF';
2011 }
2012 }
2013
2014 /**
2015 * Get shipping confirmation email text value from the settings.
2016 *
2017 * @return String
2018 */
2019 public function get_shipping_confirmation_email() {
2020 return $this->get_country_option( 'shipping_confirmation_email', '' );
2021 }
2022
2023 /**
2024 * Get woocommerce email checkbox value from the settings.
2025 *
2026 * @return String
2027 */
2028 public function get_woocommerce_email() {
2029 return $this->get_country_option( 'woocommerce_email', '' );
2030 }
2031
2032 /**
2033 * Return true if woocommerce email field is ticked.
2034 *
2035 * @return Bool
2036 */
2037 public function is_woocommerce_email_enabled() {
2038 return ( 'yes' === $this->get_woocommerce_email() );
2039 }
2040
2041 /**
2042 * Get woocommerce email text value from the settings.
2043 *
2044 * @return String
2045 */
2046 public function get_woocommerce_email_text() {
2047 return $this->get_country_option( 'woocommerce_email_text', '' );
2048 }
2049
2050 /**
2051 * Get check Netherlands address value from the settings.
2052 *
2053 * @return String
2054 */
2055 public function get_validate_nl_address() {
2056 return $this->get_country_option( 'validate_nl_address', '' );
2057 }
2058
2059 /**
2060 * Return true if check Netherlands address field is ticked.
2061 *
2062 * @return Bool
2063 */
2064 public function is_validate_nl_address_enabled() {
2065 return ( 'yes' === $this->get_validate_nl_address() );
2066 }
2067
2068 /**
2069 * Get reorder Netherlands address value from the settings.
2070 *
2071 * @return String
2072 */
2073 public function get_reorder_nl_address() {
2074 return $this->get_country_option( 'reorder_nl_address', '' );
2075 }
2076
2077 /**
2078 * Return true if reorder Netherlands address field is ticked.
2079 *
2080 * @return Bool
2081 */
2082 public function is_reorder_nl_address_enabled() {
2083 return ( 'yes' === $this->get_reorder_nl_address() );
2084 }
2085
2086 /**
2087 * Get enable logging value from the settings.
2088 *
2089 * @return String
2090 */
2091 public function get_enable_logging() {
2092 return $this->get_country_option( 'enable_logging', '' );
2093 }
2094
2095 /**
2096 * Return true if enable logging field is ticked.
2097 *
2098 * @return Bool
2099 */
2100 public function is_logging_enabled() {
2101 return ( 'yes' === $this->get_enable_logging() );
2102 }
2103
2104 /**
2105 * Get all shipping options.
2106 *
2107 * @param string $zone Shipping zone, available options: 'ne' - to Netherlands, 'be' - to Belgium, 'eu' - to European Union, 'row' - international shipping.
2108 *
2109 * @return array
2110 */
2111 public function get_default_shipping_options( $zone ) {
2112 $shipping_options = $this->get_country_option( 'default_shipping_options_' . strtolower( $zone ), '' );
2113
2114 return Utils::prepare_shipping_options( $shipping_options );
2115 }
2116
2117 /**
2118 * Get default automatic letterboxparcel product from the settings.
2119 *
2120 * @since 5.9.6
2121 *
2122 * @return String
2123 */
2124 public function get_default_automatic_letterboxparcel_product() {
2125 return $this->get_country_option( 'default_automatic_letterboxparcel_product', 'letterbox' );
2126 }
2127
2128 /**
2129 * Return array of shipping methods.
2130 *
2131 * @return array.
2132 */
2133 public function get_shipping_methods() {
2134 return wp_list_pluck( WC()->shipping()->shipping_methods, 'method_title', 'id' );
2135 }
2136
2137 /**
2138 * Get supported shipping methods from the settings.
2139 *
2140 * @return array.
2141 */
2142 public function get_supported_shipping_methods() {
2143 $suppoted_shipping_methods = (array) $this->get_option( 'supported_shipping_methods' );
2144 // Add PostNL method by default
2145 $suppoted_shipping_methods[] = POSTNL_SETTINGS_ID;
2146
2147 return $suppoted_shipping_methods;
2148 }
2149
2150 /**
2151 * Get Automatically change order status to Completed value from the settings.
2152 *
2153 * @return String
2154 */
2155 public function get_auto_complete_order() {
2156 return $this->get_country_option( 'auto_complete_order', '' );
2157 }
2158
2159 /**
2160 * Return true if Automatically change order status to Completed is ticked.
2161 *
2162 * @return Bool
2163 */
2164 public function is_auto_complete_order_enabled() {
2165 return ( 'yes' === $this->get_auto_complete_order() );
2166 }
2167 }
2168