PluginProbe
Packeta / 2.1
Packeta v2.1
2.3.2 2.3.1 trunk 1.2.2 1.2.3 1.2.4 1.2.5 1.2.6 1.3.0 1.3.1 1.3.2 1.4 1.4.1 1.4.2 1.4.3 1.5.0 1.5.1 1.5.2 1.5.3 1.5.4 1.6.0 1.6.1 1.6.2 1.6.3 1.6.4 All 56 releases
packeta / src / Packetery / Module / Options / OptionsProvider.php

OptionsProvider.php in Packeta 2.1, at src/Packetery/Module/Options/OptionsProvider.php

764 lines 18.1 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 /**
3 * Class OptionsProvider
4 *
5 * @package Packetery
6 */
7
8 declare( strict_types=1 );
9
10 namespace Packetery\Module\Options;
11
12 use Packetery\Core\Entity\PacketStatus;
13 use Packetery\Module\Framework\WpAdapter;
14 use Packetery\Module\ModuleHelper;
15
16 /**
17 * Class OptionsProvider
18 *
19 * @package Packetery
20 */
21 class OptionsProvider {
22
23 public const DEFAULT_VALUE_PACKETA_LABEL_FORMAT = 'A6 on A4';
24 public const DEFAULT_VALUE_CARRIER_LABEL_FORMAT = self::DEFAULT_VALUE_PACKETA_LABEL_FORMAT;
25 public const DEFAULT_VALUE_CARRIER_SETTINGS = false;
26 public const MAX_STATUS_SYNCING_PACKETS_DEFAULT = 100;
27 public const MAX_DAYS_OF_PACKET_STATUS_SYNCING_DEFAULT = 14;
28 public const FORCE_PACKET_CANCEL_DEFAULT = true;
29 public const PACKET_AUTO_SUBMISSION_ALLOWED_DEFAULT = false;
30 public const WIDGET_AUTO_OPEN_DEFAULT = false;
31 public const AUTO_ORDER_STATUS_DEFAULT = '';
32 public const EMAIL_HOOK_DEFAULT = 'woocommerce_email_footer';
33 public const AUTO_ORDER_STATUS = 'auto_order_status';
34 public const DISPLAY_FREE_SHIPPING_IN_CHECKOUT_DEFAULT = true;
35 public const PRICES_INCLUDE_TAX_DEFAULT = false;
36 public const HIDE_CHECKOUT_LOGO_DEFAULT = false;
37
38 public const AUTOMATIC_CHECKOUT_DETECTION = 'automatic_checkout_detection';
39 public const BLOCK_CHECKOUT_DETECTION = 'block_checkout_detection';
40 public const CLASSIC_CHECKOUT_DETECTION = 'classic_checkout_detection';
41
42 public const DEFAULT_DIMENSIONS_UNIT_MM = 'mm';
43 public const DIMENSIONS_UNIT_CM = 'cm';
44
45 /**
46 * Options data.
47 *
48 * @var array<string, mixed>
49 */
50 private $data;
51
52 /**
53 * Sync data.
54 *
55 * @var array<string, mixed>
56 * }
57 */
58 private $syncData;
59
60 /**
61 * Auto submission data.
62 *
63 * @var array<string, mixed>
64 */
65 private $autoSubmissionData;
66
67 /**
68 * @var array<string, mixed>
69 */
70 private $advancedData;
71
72 public function __construct( WpAdapter $wpAdapter ) {
73 $data = $wpAdapter->getOption( OptionNames::PACKETERY );
74 if ( $data === false || $data === null ) {
75 $data = array();
76 }
77
78 $syncData = $wpAdapter->getOption( OptionNames::PACKETERY_SYNC );
79 if ( $syncData === false || $syncData === null ) {
80 $syncData = [];
81 }
82
83 $autoSubmissionData = $wpAdapter->getOption( OptionNames::PACKETERY_AUTO_SUBMISSION );
84 if ( $autoSubmissionData === false || $autoSubmissionData === null ) {
85 $autoSubmissionData = [];
86 }
87
88 $advancedData = $wpAdapter->getOption( OptionNames::PACKETERY_ADVANCED );
89 if ( $advancedData === false || $advancedData === null ) {
90 $advancedData = [];
91 }
92
93 $this->data = $data;
94 $this->syncData = $syncData;
95 $this->autoSubmissionData = $autoSubmissionData;
96 $this->advancedData = $advancedData;
97 }
98
99 /**
100 * Gets data section.
101 *
102 * @param string $optionsName Option name of settings.
103 *
104 * @return array<string, mixed> Only section of options data by given $optionName.
105 * @throws \InvalidArgumentException When provided option name does not exist.
106 */
107 public function getOptionsByName( string $optionsName ): array {
108 $data = $this->getAllOptions();
109 if ( ! isset( $data[ $optionsName ] ) ) {
110 throw new \InvalidArgumentException( sprintf( 'Option name "%s" does not exist.', $optionsName ) );
111 }
112
113 return $data[ $optionsName ];
114 }
115
116 /**
117 * Gets data as array.
118 *
119 * @return array<string, array> All plugin options data by given $optionName.
120 */
121 public function getAllOptions(): array {
122 return [
123 OptionNames::PACKETERY => $this->data,
124 OptionNames::PACKETERY_SYNC => $this->syncData,
125 OptionNames::PACKETERY_AUTO_SUBMISSION => $this->autoSubmissionData,
126 OptionNames::PACKETERY_ADVANCED => $this->advancedData,
127 ];
128 }
129
130 /**
131 * Tells if provider has any data,
132 *
133 * @param string $optionName Option name of settings.
134 *
135 * @return bool Has any data.
136 */
137 public function has_any( string $optionName ): bool {
138 return count( $this->getOptionsByName( $optionName ) ) > 0;
139 }
140
141 /**
142 * Gets content from options array.
143 *
144 * @param string $key Options array key.
145 *
146 * @return mixed|null Content.
147 */
148 private function get( string $key ) {
149 return ( $this->data[ $key ] ?? null );
150 }
151
152 /**
153 * API key dynamically crafted from API password.
154 *
155 * @return string|null Content.
156 */
157 public function get_api_key(): ?string {
158 $apiKey = $this->get( 'api_key' );
159 if ( $apiKey !== null && $apiKey !== '' && $apiKey !== false ) {
160 return $apiKey;
161 }
162
163 return null;
164 }
165
166 /**
167 * API password from client section.
168 *
169 * @return string|null Content.
170 */
171 public function get_api_password(): ?string {
172 return $this->get( 'api_password' );
173 }
174
175 /**
176 * Sender.
177 *
178 * @return string|null Content.
179 */
180 public function get_sender(): ?string {
181 return $this->get( 'sender' );
182 }
183
184 /**
185 * Carrier label format.
186 *
187 * @return string Content.
188 */
189 public function get_carrier_label_format(): string {
190 return $this->get( 'carrier_label_format' ) ?? self::DEFAULT_VALUE_CARRIER_LABEL_FORMAT;
191 }
192
193 /**
194 * Packeta label format.
195 *
196 * @return string Content.
197 */
198 public function get_packeta_label_format(): string {
199 return $this->get( 'packeta_label_format' ) ?? self::DEFAULT_VALUE_PACKETA_LABEL_FORMAT;
200 }
201
202 /**
203 * Does user allow label emailing?
204 *
205 * @return bool|null Content.
206 */
207 public function get_allow_label_emailing(): ?bool {
208 return (bool) $this->get( 'allow_label_emailing' );
209 }
210
211 /**
212 * Returns COD payment methods.
213 *
214 * @return string[] Values.
215 */
216 public function getCodPaymentMethods(): array {
217 $value = $this->get( 'cod_payment_methods' );
218 if ( $value === null ) {
219 return [];
220 }
221
222 return $value;
223 }
224
225 /**
226 * Returns the location of the widget button in the cart
227 *
228 * @return string|null
229 */
230 public function getCheckoutWidgetButtonLocation(): ?string {
231 $value = $this->get( 'checkout_widget_button_location' );
232 if ( $value === null ) {
233 return null;
234 }
235
236 return $value;
237 }
238
239 /**
240 * Returns which checkout detection to return
241 *
242 * @return string
243 */
244 public function getCheckoutDetection(): string {
245 $value = $this->get( 'checkout_detection' );
246 if ( $value === null ) {
247 return self::AUTOMATIC_CHECKOUT_DETECTION;
248 }
249
250 return $value;
251 }
252
253 /**
254 * Order packaging weight.
255 *
256 * @return float
257 */
258 public function getPackagingWeight(): float {
259 return (float) $this->get( 'packaging_weight' );
260 }
261
262 public function getDimensionsUnit(): string {
263 $value = $this->get( 'dimensions_unit' );
264
265 return $value ?? self::DEFAULT_DIMENSIONS_UNIT_MM;
266 }
267
268 public function getDimensionsNumberOfDecimals(): int {
269 if ( $this->getDimensionsUnit() === self::DIMENSIONS_UNIT_CM ) {
270 return 1;
271 }
272
273 return 0;
274 }
275
276 /**
277 * Sanitises and formats a dimension value.
278 *
279 * @param string|float $value Dimension value.
280 *
281 * @return float|null
282 */
283 public function getSanitizedDimensionValueInMm( $value ): ?float {
284 if ( ! is_numeric( $value ) ) {
285 return null;
286 }
287
288 $sanitizedValue = (float) number_format( (float) $value, $this->getDimensionsNumberOfDecimals(), '.', '' );
289 if ( $this->getDimensionsUnit() === self::DIMENSIONS_UNIT_CM ) {
290 return ModuleHelper::convertToMillimeters( $sanitizedValue );
291 }
292
293 return $sanitizedValue;
294 }
295
296 /**
297 * Order default weight enabled.
298 *
299 * @return bool
300 */
301 public function isDefaultWeightEnabled(): bool {
302 return (bool) $this->get( 'default_weight_enabled' );
303 }
304
305 /**
306 * Order default weight.
307 *
308 * @return float
309 */
310 public function getDefaultWeight(): float {
311 if ( $this->get( 'default_weight' ) === null ) {
312 return 0.0;
313 }
314
315 return (float) $this->get( 'default_weight' );
316 }
317
318 /**
319 * Consignment's default dimensions enabled.
320 *
321 * @return bool
322 */
323 public function isDefaultDimensionsEnabled(): bool {
324 return (bool) $this->get( 'default_dimensions_enabled' );
325 }
326
327 /**
328 * Consignment's default length.
329 *
330 * @return float
331 */
332 public function getDefaultLength(): float {
333 if ( $this->get( 'default_length' ) === null ) {
334 return 0.0;
335 }
336
337 return (float) $this->get( 'default_length' );
338 }
339
340 /**
341 * Consignment's default height.
342 *
343 * @return float
344 */
345 public function getDefaultHeight(): float {
346 if ( $this->get( 'default_height' ) === null ) {
347 return 0.0;
348 }
349
350 return (float) $this->get( 'default_height' );
351 }
352
353 /**
354 * Consignment's default width.
355 *
356 * @return float
357 */
358 public function getDefaultWidth(): float {
359 if ( $this->get( 'default_width' ) === null ) {
360 return 0.0;
361 }
362
363 return (float) $this->get( 'default_width' );
364 }
365
366 /**
367 * Max syncing packets.
368 *
369 * @return int
370 */
371 public function getMaxStatusSyncingPackets(): int {
372 $value = ( $this->syncData['max_status_syncing_packets'] ?? null );
373 if ( is_numeric( $value ) ) {
374 return (int) $value;
375 }
376
377 return self::MAX_STATUS_SYNCING_PACKETS_DEFAULT;
378 }
379
380 /**
381 * Max days of packet status syncing.
382 *
383 * @return int
384 */
385 public function getMaxDaysOfPacketStatusSyncing(): int {
386 $value = ( $this->syncData['max_days_of_packet_status_syncing'] ?? null );
387 if ( is_numeric( $value ) ) {
388 return (int) $value;
389 }
390
391 return self::MAX_DAYS_OF_PACKET_STATUS_SYNCING_DEFAULT;
392 }
393
394 /**
395 * Status syncing order statuses.
396 *
397 * @return array
398 */
399 public function getStatusSyncingOrderStatuses(): array {
400 $value = ( $this->syncData['status_syncing_order_statuses'] ?? null );
401 if ( is_array( $value ) ) {
402 return $value;
403 }
404
405 return [];
406 }
407
408 /**
409 * Status syncing order statuses.
410 *
411 * @return array
412 */
413 public function getExistingStatusSyncingOrderStatuses(): array {
414 $statuses = $this->getStatusSyncingOrderStatuses();
415 $choices = array_column( Page::getOrderStatusesChoiceData(), 'key' );
416
417 return array_intersect( $statuses, $choices );
418 }
419
420 /**
421 * Status syncing packet statuses.
422 *
423 * @param PacketStatus[] $expectedPacketStatuses Expected packet statuses.
424 *
425 * @return string[]
426 */
427 public function getStatusSyncingPacketStatuses( array $expectedPacketStatuses ): array {
428 $packetStatusNames = $this->syncData['status_syncing_packet_statuses'] ?? null;
429 $expectedPacketStatusNames = array_map(
430 static function ( PacketStatus $status ): string {
431 return $status->getName();
432 },
433 $expectedPacketStatuses
434 );
435
436 if ( is_array( $packetStatusNames ) ) {
437 return array_intersect( $packetStatusNames, $expectedPacketStatusNames );
438 }
439
440 return $expectedPacketStatusNames;
441 }
442
443 /**
444 * Transform shipping address to contain pickup point address?
445 *
446 * @return bool
447 */
448 public function replaceShippingAddressWithPickupPointAddress(): bool {
449 return (bool) $this->get( 'replace_shipping_address_with_pickup_point_address' );
450 }
451
452 /**
453 * Turns on/off free shipping text in checkout.
454 *
455 * @return bool
456 */
457 public function isFreeShippingShown(): bool {
458 $freeShippingStatus = $this->get( 'free_shipping_shown' );
459 if ( $freeShippingStatus !== null ) {
460 return (bool) $freeShippingStatus;
461 }
462
463 return self::DISPLAY_FREE_SHIPPING_IN_CHECKOUT_DEFAULT;
464 }
465
466 /**
467 * Tells if prices include tax.
468 *
469 * @return bool
470 */
471 public function arePricesTaxInclusive(): bool {
472 $pricesIncludeTax = $this->get( 'prices_include_tax' );
473 if ( $pricesIncludeTax !== null ) {
474 return (bool) $pricesIncludeTax;
475 }
476
477 return self::PRICES_INCLUDE_TAX_DEFAULT;
478 }
479
480 public function isCheckoutLogoHidden(): bool {
481 $hideCheckoutLogo = $this->get( 'hide_checkout_logo' );
482 if ( $hideCheckoutLogo !== null ) {
483 return (bool) $hideCheckoutLogo;
484 }
485
486 return self::HIDE_CHECKOUT_LOGO_DEFAULT;
487 }
488
489 public function isCheckoutLogoShown(): bool {
490 return ! $this->isCheckoutLogoHidden();
491 }
492
493 /**
494 * Tells if packet cancellation should be forced.
495 *
496 * @return bool
497 */
498 public function isPacketCancellationForced(): bool {
499 $value = $this->get( 'force_packet_cancel' );
500 if ( $value !== null ) {
501 return (bool) $value;
502 }
503
504 return self::FORCE_PACKET_CANCEL_DEFAULT;
505 }
506
507 /**
508 * Gets packet auto submission payment method and event mapping.
509 *
510 * @return array
511 */
512 private function getPacketAutoSubmissionPaymentMethodEventsMapping(): array {
513 return $this->autoSubmissionData['payment_method_events'] ?? [];
514 }
515
516 /**
517 * Gets array of mapped events.
518 *
519 * @return string[]
520 */
521 public function getPacketAutoSubmissionMappedUniqueEvents(): array {
522 $mapping = $this->getPacketAutoSubmissionPaymentMethodEventsMapping();
523 $result = [];
524
525 foreach ( $mapping as $gatewayMapping ) {
526 if ( $gatewayMapping['event'] === null ) {
527 continue;
528 }
529 $result[ $gatewayMapping['event'] ] = $gatewayMapping['event'];
530 }
531
532 return $result;
533 }
534
535 /**
536 * Gets packet auto-submission event by payment gateway ID.
537 *
538 * @param string $paymentGatewayId Payment gateway ID.
539 *
540 * @return string|null
541 */
542 public function getPacketAutoSubmissionEventForPaymentGateway( string $paymentGatewayId ): ?string {
543 return $this->getPacketAutoSubmissionPaymentMethodEventsMapping()[ $paymentGatewayId ]['event'] ?? null;
544 }
545
546 /**
547 * Tells if packet auto submission is enabled.
548 *
549 * @return bool
550 */
551 public function isPacketAutoSubmissionEnabled(): bool {
552 $value = $this->autoSubmissionData['allow'] ?? null;
553 if ( $value !== null ) {
554 return (bool) $value;
555 }
556
557 return self::PACKET_AUTO_SUBMISSION_ALLOWED_DEFAULT;
558 }
559
560 /**
561 * Provides available labels.
562 *
563 * @return array[]
564 */
565 public function getLabelFormats(): array {
566 return [
567 'A6 on A4' => [
568 'name' => __( '1/4 A4, print on A4, 4pcs/page', 'packeta' ),
569 'directLabels' => true,
570 'maxOffset' => 3,
571 ],
572 'A6 on A6' => [
573 'name' => __( '1/4 A4, direct print, 1pc/page', 'packeta' ),
574 'directLabels' => true,
575 'maxOffset' => 0,
576 ],
577 'A7 on A7' => [
578 'name' => __( '1/8 A4, direct print, 1pc/page', 'packeta' ),
579 'directLabels' => false,
580 'maxOffset' => 0,
581 ],
582 'A7 on A4' => [
583 'name' => __( '1/8 A4, print on A4, 8pcs/page', 'packeta' ),
584 'directLabels' => false,
585 'maxOffset' => 7,
586 ],
587 '105x35mm on A4' => [
588 'name' => __( '105x35mm, print on A4, 16 pcs/page', 'packeta' ),
589 'directLabels' => false,
590 'maxOffset' => 15,
591 ],
592 'A8 on A8' => [
593 'name' => __( '1/16 A4, direct print, 1pc/page', 'packeta' ),
594 'directLabels' => false,
595 'maxOffset' => 0,
596 ],
597 ];
598 }
599
600 /**
601 * Gets maximum offset for selected Packeta labels format.
602 *
603 * @param string $format Selected format.
604 *
605 * @return int
606 */
607 public function getLabelMaxOffset( string $format ): int {
608 if ( $format === '' ) {
609 return 0;
610 }
611 $availableFormats = $this->getLabelFormats();
612
613 return $availableFormats[ $format ]['maxOffset'];
614 }
615
616 /**
617 * Gets list of Packeta labels for select creation.
618 *
619 * @return array
620 */
621 public function getPacketaLabelFormats(): array {
622 $availableFormats = $this->getLabelFormats();
623
624 return array_filter( array_combine( array_keys( $availableFormats ), array_column( $availableFormats, 'name' ) ) );
625 }
626
627 /**
628 * Gets list of carrier labels for select creation.
629 *
630 * @return array
631 */
632 public function getCarrierLabelFormat(): array {
633 $availableFormats = $this->getLabelFormats();
634 $carrierLabelFormats = [];
635 foreach ( $availableFormats as $format => $formatData ) {
636 if ( $formatData['directLabels'] === true ) {
637 $carrierLabelFormats[ $format ] = $formatData['name'];
638 }
639 }
640
641 return $carrierLabelFormats;
642 }
643
644 /**
645 * Tells if widget should open automatically.
646 *
647 * @return bool
648 */
649 public function shouldWidgetOpenAutomatically(): bool {
650 $value = $this->get( 'widget_auto_open' );
651 if ( $value !== null ) {
652 return (bool) $value;
653 }
654
655 return self::WIDGET_AUTO_OPEN_DEFAULT;
656 }
657
658 /**
659 * Auto order status change on packet submit enabled. Used in upgrade only.
660 *
661 * @return bool
662 */
663 public function isOrderStatusAutoChangeEnabled(): bool {
664 $orderStatusAutoChange = $this->get( 'order_status_auto_change' );
665 if ( $orderStatusAutoChange !== null ) {
666 return (bool) $orderStatusAutoChange;
667 }
668
669 return false;
670 }
671
672 /**
673 * Auto order status change.
674 *
675 * @return bool
676 */
677 public function isOrderStatusChangeAllowed(): bool {
678 $allowOrderStatusChange = ( $this->syncData['allow_order_status_change'] ?? null );
679 if ( $allowOrderStatusChange !== null ) {
680 return (bool) $allowOrderStatusChange;
681 }
682
683 return false;
684 }
685
686 public function isWcCarrierConfigEnabled(): bool {
687 $isEnabled = ( $this->advancedData['new_carrier_settings_enabled'] ?? null );
688 if ( $isEnabled !== null ) {
689 return (bool) $isEnabled;
690 }
691
692 return false;
693 }
694
695 public function isWcCarrierConfigEnabledNullable(): ?bool {
696 $isEnabled = $this->advancedData['new_carrier_settings_enabled'] ?? null;
697 if ( $isEnabled !== null ) {
698 return (bool) $isEnabled;
699 }
700
701 return null;
702 }
703
704 /**
705 * Tells auto order status, if it is valid, otherwise empty string.
706 *
707 * @param string $packetStatus Packet status.
708 *
709 * @return string
710 */
711 public function getValidAutoOrderStatusFromMapping( string $packetStatus ): string {
712 $autoOrderStatus = $this->getAutoOrderStatusFromMapping( $packetStatus );
713 if ( wc_is_order_status( $autoOrderStatus ) ) {
714 return $autoOrderStatus;
715 }
716
717 return self::AUTO_ORDER_STATUS_DEFAULT;
718 }
719
720 /**
721 * Tells auto order status.
722 *
723 * @param string $packetStatus Packet status.
724 *
725 * @return string|null
726 */
727 public function getAutoOrderStatusFromMapping( string $packetStatus ): ?string {
728 return $this->syncData['order_status_change_packet_statuses'][ $packetStatus ] ?? null;
729 }
730
731 /**
732 * Tells auto order status. Used in upgrade only.
733 *
734 * @return string|null
735 */
736 public function getAutoOrderStatus(): ?string {
737 return $this->get( self::AUTO_ORDER_STATUS );
738 }
739
740 /**
741 * Gets email hook.
742 *
743 * @since 1.6.1
744 * @return string
745 */
746 public function getEmailHook(): string {
747 $emailHook = $this->get( 'email_hook' );
748
749 return $emailHook ?? self::EMAIL_HOOK_DEFAULT;
750 }
751
752 /**
753 * Performs replacements needed by Nette form to pass validation, see https://github.com/dg/nette-component-model/blob/master/src/ComponentModel/Container.php#L50 .
754 * There may be an edge case where a replacement causes a conflict with another method. We do not address this issue yet.
755 *
756 * @param string $id Payment gateway id.
757 *
758 * @return string
759 */
760 public function sanitizePaymentGatewayId( string $id ): string {
761 return preg_replace( '/\W/', '_', $id );
762 }
763 }
764