PluginProbe
Packeta / 2.0.9
Packeta v2.0.9
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 / Page.php

Page.php in Packeta 2.0.9, at src/Packetery/Module/Options/Page.php

988 lines 37.1 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 /**
3 * Class Page
4 *
5 * @package Packetery\Options
6 */
7
8 declare( strict_types=1 );
9
10 namespace Packetery\Module\Options;
11
12 use DateTime;
13 use Packetery\Core\Api;
14 use Packetery\Core\Api\Soap\Request\SenderGetReturnRouting;
15 use Packetery\Core\CoreHelper;
16 use Packetery\Core\Log;
17 use Packetery\Latte\Engine;
18 use Packetery\Module\FormFactory;
19 use Packetery\Module\MessageManager;
20 use Packetery\Module\ModuleHelper;
21 use Packetery\Module\Order\PacketAutoSubmitter;
22 use Packetery\Module\Order\PacketSynchronizer;
23 use Packetery\Module\PaymentGatewayHelper;
24 use Packetery\Module\Views\UrlBuilder;
25 use Packetery\Nette\Forms\Container;
26 use Packetery\Nette\Forms\Controls\BaseControl;
27 use Packetery\Nette\Forms\Controls\SubmitButton;
28 use Packetery\Nette\Forms\Form;
29 use Packetery\Nette\Http;
30
31 /**
32 * Class Page
33 *
34 * @package Packetery\Options
35 */
36 class Page {
37
38 private const FORM_FIELDS_CONTAINER = 'packetery';
39 private const FORM_FIELD_PACKETA_LABEL_FORMAT = 'packeta_label_format';
40 private const FORM_FIELD_CARRIER_LABEL_FORMAT = 'carrier_label_format';
41 private const FORM_FIELD_FREE_SHIPPING_SHOWN = 'free_shipping_shown';
42
43 public const ACTION_VALIDATE_SENDER = 'validate-sender';
44
45 public const SLUG = 'packeta-options';
46
47 public const TAB_GENERAL = 'general';
48 public const TAB_ADVANCED = 'advanced';
49 public const TAB_SUPPORT = 'support';
50 public const TAB_PACKET_STATUS_SYNC = 'packet-status-sync';
51 public const TAB_AUTO_SUBMISSION = 'auto-submission';
52
53 public const PARAM_TAB = 'tab';
54
55 /**
56 * PacketeryLatte_engine.
57 *
58 * @var Engine PacketeryLatte engine.
59 */
60 private $latteEngine;
61
62 /**
63 * Options Provider
64 *
65 * @var OptionsProvider
66 */
67 private $optionsProvider;
68
69 /**
70 * Form factory.
71 *
72 * @var FormFactory Form factory.
73 */
74 private $formFactory;
75
76 /**
77 * Packeta client.
78 *
79 * @var Api\Soap\Client
80 */
81 private $packetaClient;
82
83 /**
84 * Logger
85 *
86 * @var Log\ILogger
87 */
88 private $logger;
89
90 /**
91 * Message manager.
92 *
93 * @var MessageManager
94 */
95 private $messageManager;
96
97 /**
98 * @var Http\Request
99 */
100 private $httpRequest;
101
102 /**
103 * @var ModuleHelper
104 */
105 private $moduleHelper;
106
107 /**
108 * @var UrlBuilder
109 */
110 private $urlBuilder;
111
112 /**
113 * @var string
114 */
115 private $supportEmailAddress;
116
117 public function __construct(
118 Engine $latteEngine,
119 OptionsProvider $optionsProvider,
120 FormFactory $formFactory,
121 Api\Soap\Client $packetaClient,
122 Log\ILogger $logger,
123 MessageManager $messageManager,
124 Http\Request $httpRequest,
125 ModuleHelper $moduleHelper,
126 UrlBuilder $urlBuilder,
127 string $supportEmailAddress
128 ) {
129 $this->latteEngine = $latteEngine;
130 $this->optionsProvider = $optionsProvider;
131 $this->formFactory = $formFactory;
132 $this->packetaClient = $packetaClient;
133 $this->logger = $logger;
134 $this->messageManager = $messageManager;
135 $this->httpRequest = $httpRequest;
136 $this->moduleHelper = $moduleHelper;
137 $this->urlBuilder = $urlBuilder;
138 $this->supportEmailAddress = $supportEmailAddress;
139 }
140
141 /**
142 * Registers WP callbacks.
143 */
144 public function register(): void {
145 add_action( 'admin_init', array( $this, 'admin_init' ) );
146 $icon = 'data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0idXRmLTgiPz4KPCEtLSBHZW5lcmF0b3I6IEFkb2JlIElsbHVzdHJhdG9yIDI1LjEuMCwgU1ZHIEV4cG9ydCBQbHVnLUluIC4gU1ZHIFZlcnNpb246IDYuMDAgQnVpbGQgMCkgIC0tPgo8c3ZnIHZlcnNpb249IjEuMSIgaWQ9IlZyc3R2YV8xIiB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHhtbG5zOnhsaW5rPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5L3hsaW5rIiB4PSIwcHgiIHk9IjBweCIKCSB2aWV3Qm94PSIwIDAgMzcgNDAiIHN0eWxlPSJmaWxsOiNhN2FhYWQiIHhtbDpzcGFjZT0icHJlc2VydmUiPgo8c3R5bGUgdHlwZT0idGV4dC9jc3MiPgoJLnN0MHtmaWxsLXJ1bGU6ZXZlbm9kZDtjbGlwLXJ1bGU6ZXZlbm9kZDtmaWxsOiAjYTdhYWFkO30KPC9zdHlsZT4KPHBhdGggY2xhc3M9InN0MCIgZD0iTTE5LjQsMTYuMWwtMC45LDAuNGwtMC45LTAuNGwtMTMtNi41bDYuMi0yLjRsMTMuNCw2LjVMMTkuNCwxNi4xeiBNMzIuNSw5LjZsLTQuNywyLjNsLTEzLjUtNmw0LjItMS42CglMMzIuNSw5LjZ6Ii8+CjxwYXRoIGNsYXNzPSJzdDAiIGQ9Ik0xOSwwbDE3LjIsNi42bC0yLjQsMS45bC0xNS4yLTZMMy4yLDguNkwwLjgsNi42TDE4LDBMMTksMEwxOSwweiBNMzQuMSw5LjFsMi44LTEuMWwtMi4xLDE3LjZsLTAuNCwwLjgKCUwxOS40LDQwbC0wLjUtMy4xbDEzLjQtMTJMMzQuMSw5LjF6IE0yLjUsMjYuNWwtMC40LTAuOEwwLDguMWwyLjgsMS4xbDEuOSwxNS43bDEzLjQsMTJMMTcuNiw0MEwyLjUsMjYuNXoiLz4KPHBhdGggY2xhc3M9InN0MCIgZD0iTTI4LjIsMTIuNGw0LjMtMi43bC0xLjcsMTQuMkwxOC42LDM1bDAuNi0xN2w1LjQtMy4zTDI0LjMsMjNsMy4zLTIuM0wyOC4yLDEyLjR6Ii8+CjxwYXRoIGNsYXNzPSJzdDAiIGQ9Ik0xNy43LDE3LjlsMC42LDE3bC0xMi4yLTExTDQuNCw5LjhMMTcuNywxNy45eiIvPgo8L3N2Zz4K';
147 add_menu_page(
148 __( 'Packeta', 'packeta' ),
149 __( 'Packeta', 'packeta' ),
150 'manage_options',
151 self::SLUG,
152 function () {},
153 $icon
154 );
155 add_submenu_page(
156 self::SLUG,
157 __( 'Settings', 'packeta' ),
158 __( 'Settings', 'packeta' ),
159 'manage_options',
160 self::SLUG,
161 array(
162 $this,
163 'render',
164 ),
165 1
166 );
167 add_action( 'admin_init', [ $this, 'processActions' ] );
168
169 add_filter( 'custom_menu_order', '__return_true' );
170 add_filter( 'menu_order', [ $this, 'customMenuOrder' ] );
171 }
172
173 /**
174 * Returns menu_order with Packeta item in last position.
175 *
176 * @param array $menuOrder WP $menu_order.
177 *
178 * @return array
179 */
180 public function customMenuOrder( array $menuOrder ): array {
181 $currentPosition = array_search( self::SLUG, $menuOrder, true );
182
183 if ( $currentPosition !== false ) {
184 unset( $menuOrder[ $currentPosition ] );
185 $menuOrder[] = self::SLUG;
186 }
187
188 return $menuOrder;
189 }
190
191 /**
192 * Get chosen keys by hashed choice data.
193 *
194 * @param array $choiceData Choice data.
195 * @param array $chosenHashedFormOrderStatuses Picked items.
196 *
197 * @return array
198 */
199 private function getChosenKeys( array $choiceData, array $chosenHashedFormOrderStatuses ): array {
200 $statuses = [];
201 foreach ( $chosenHashedFormOrderStatuses as $hash => $chosen ) {
202 if ( $chosen ) {
203 $statuses[] = $choiceData[ $hash ]['key'];
204 }
205 }
206
207 return $statuses;
208 }
209
210 /**
211 * Translate hashes to packet status keys.
212 *
213 * @param array $choiceData Choice data.
214 * @param array $formData Picked items.
215 *
216 * @return array
217 */
218 private function translateStatuses( array $choiceData, array $formData ): array {
219 $statuses = [];
220 foreach ( $formData as $hash => $value ) {
221 if ( $value ) {
222 $statuses[ $choiceData[ $hash ]['key'] ] = $value;
223 }
224 }
225
226 return $statuses;
227 }
228
229 /**
230 * Gets all packet statuses.
231 *
232 * @return array
233 */
234 public function getPacketStatusesChoiceData(): array {
235 $statuses = PacketSynchronizer::getPacketStatuses();
236
237 $result = [];
238
239 foreach ( $statuses as $status => $statusEntity ) {
240 $result[ md5( $status ) ] = [
241 'key' => $status,
242 'default' => $statusEntity->hasDefaultSynchronization(),
243 'label' => $statusEntity->getTranslatedName(),
244 ];
245 }
246
247 return $result;
248 }
249
250 /**
251 * Gets order statuses for form.
252 *
253 * @return array<string, array<string, int|string>>
254 */
255 public static function getOrderStatusesChoiceData(): array {
256 $orderStatuses = wc_get_order_statuses();
257 $orderStatusesTransformed = [];
258
259 foreach ( $orderStatuses as $orderStatusKey => $orderStatusLabel ) {
260 $orderStatusesTransformed[ md5( $orderStatusKey ) ] = [
261 'key' => $orderStatusKey,
262 'label' => $orderStatusLabel,
263 ];
264 }
265
266 return $orderStatusesTransformed;
267 }
268
269 /**
270 * Creates auto submission form.
271 *
272 * @return Form
273 */
274 public function createAutoSubmissionForm(): Form {
275 $gateways = PaymentGatewayHelper::getAvailablePaymentGateways();
276 $form = $this->formFactory->create( 'packetery_auto_submission_form' );
277 $defaults = $this->optionsProvider->getOptionsByName( OptionsProvider::OPTION_NAME_PACKETERY_AUTO_SUBMISSION );
278
279 $form->addCheckbox( 'allow', __( 'Allow packet auto-submission', 'packeta' ) )
280 ->setRequired( false )
281 ->setDefaultValue( OptionsProvider::PACKET_AUTO_SUBMISSION_ALLOWED_DEFAULT );
282
283 $eventChoices = [
284 PacketAutoSubmitter::EVENT_ON_ORDER_CREATION_FE => __( 'On order creation at e-shop checkout', 'packeta' ),
285 PacketAutoSubmitter::EVENT_ON_ORDER_PROCESSING => __( 'On order processing', 'packeta' ),
286 PacketAutoSubmitter::EVENT_ON_ORDER_COMPLETED => __( 'On order completed', 'packeta' ),
287 ];
288
289 $paymentMethodEvents = $form->addContainer( 'payment_method_events' );
290 foreach ( $gateways as $gateway ) {
291 $paymentMethodEventsMethod = $paymentMethodEvents->addContainer(
292 $this->optionsProvider->sanitizePaymentGatewayId( $gateway->id )
293 );
294 $paymentMethodEventsMethod->addSelect( 'event', $gateway->get_method_title(), $eventChoices )
295 ->setPrompt( __( 'Select event', 'packeta' ) )
296 ->checkDefaultValue( false );
297 }
298
299 $form->addSubmit( 'save', __( 'Save changes', 'packeta' ) );
300
301 $form->setDefaults( $defaults );
302
303 $form->onSuccess[] = [ $this, 'onAutoSubmissionFormSuccess' ];
304
305 return $form;
306 }
307
308 /**
309 * On auto submission form success.
310 *
311 * @param Form $form Form.
312 * @param array $values Form values.
313 *
314 * @return void
315 */
316 public function onAutoSubmissionFormSuccess( Form $form, array $values ): void {
317 update_option( OptionsProvider::OPTION_NAME_PACKETERY_AUTO_SUBMISSION, $values );
318
319 $this->messageManager->flash_message( __( 'Settings saved.', 'packeta' ), MessageManager::TYPE_SUCCESS, MessageManager::RENDERER_PACKETERY, 'plugin-options' );
320
321 if ( wp_safe_redirect( $this->createLink( self::TAB_AUTO_SUBMISSION ) ) ) {
322 exit;
323 }
324 }
325
326 /**
327 * Creates settings form.
328 *
329 * @return Form
330 */
331 private function createPacketStatusSyncForm(): Form {
332 $form = $this->formFactory->create( 'packetery_packet_status_sync_form' );
333 $settings = $this->optionsProvider->getOptionsByName( OptionsProvider::OPTION_NAME_PACKETERY_SYNC );
334
335 $form->addText( 'max_status_syncing_packets', __( 'Number of orders synced during one cron call', 'packeta' ) )
336 ->setRequired( false )
337 ->addRule( Form::INTEGER )
338 ->addRule( Form::MIN, null, 0 )
339 ->setDefaultValue( OptionsProvider::MAX_STATUS_SYNCING_PACKETS_DEFAULT );
340
341 $form->addText( 'max_days_of_packet_status_syncing', __( 'Number of days for which the order status is checked', 'packeta' ) )
342 ->setRequired( false )
343 ->addRule( Form::INTEGER )
344 ->addRule( Form::MIN, null, 0 )
345 ->setDefaultValue( OptionsProvider::MAX_DAYS_OF_PACKET_STATUS_SYNCING_DEFAULT );
346
347 $orderStatusesTransformed = self::getOrderStatusesChoiceData();
348 $orderStatusesContainer = $form->addContainer( 'status_syncing_order_statuses' );
349
350 foreach ( $orderStatusesTransformed as $orderStatusKeyHash => $orderStatusData ) {
351 $item = $orderStatusesContainer->addCheckbox( $orderStatusKeyHash, $orderStatusData['label'] );
352 if ( isset( $settings['status_syncing_order_statuses'] ) && in_array( $orderStatusData['key'], $settings['status_syncing_order_statuses'], true ) ) {
353 $item->setDefaultValue( true );
354 }
355 }
356 unset( $settings['status_syncing_order_statuses'] );
357
358 $packetStatuses = $this->getPacketStatusesChoiceData();
359 $packetStatusesContainer = $form->addContainer( 'status_syncing_packet_statuses' );
360
361 foreach ( $packetStatuses as $packetStatusHash => $packetStatusData ) {
362 $item = $packetStatusesContainer->addCheckbox( $packetStatusHash, $packetStatusData['label'] );
363 if ( ! isset( $settings['status_syncing_packet_statuses'] ) ) {
364 $item->setDefaultValue( $packetStatusData['default'] );
365 } elseif ( in_array( $packetStatusData['key'], $settings['status_syncing_packet_statuses'], true ) ) {
366 $item->setDefaultValue( true );
367 }
368 }
369 unset( $settings['status_syncing_packet_statuses'] );
370
371 $form->addCheckbox( 'allow_order_status_change', __( 'Allow order status change', 'packeta' ) )
372 ->setRequired( false )
373 ->setDefaultValue( false )
374 ->addCondition( Form::EQUAL, true )
375 ->toggle( '.order_status_change_content' );
376
377 $orderStatusChangePacketStatuses = $form->addContainer( 'order_status_change_packet_statuses' );
378 $orderStatuses = wc_get_order_statuses();
379 foreach ( $packetStatuses as $packetStatusHash => $packetStatusData ) {
380 $item = $orderStatusChangePacketStatuses->addSelect( $packetStatusHash, $packetStatusData['label'], $orderStatuses )
381 ->setPrompt( __( 'Order status', 'packeta' ) );
382 $targetStatus = $settings['order_status_change_packet_statuses'][ $packetStatusData['key'] ] ?? null;
383 if ( $targetStatus !== null && array_key_exists( $targetStatus, $orderStatuses ) ) {
384 $item->setDefaultValue( $targetStatus );
385 }
386 }
387 unset( $settings['order_status_change_packet_statuses'] );
388
389 $form->setDefaults( $settings );
390
391 $form->addSubmit( 'save', __( 'Save changes', 'packeta' ) );
392
393 $form->onSuccess[] = [ $this, 'onPacketStatusSyncFormSuccess' ];
394
395 return $form;
396 }
397
398 /**
399 * On packet status sync form success.
400 *
401 * @param Form $form Form.
402 * @param array $values Values.
403 *
404 * @return void
405 */
406 public function onPacketStatusSyncFormSuccess( Form $form, array $values ): void {
407
408 $values['status_syncing_order_statuses'] = $this->getChosenKeys(
409 self::getOrderStatusesChoiceData(),
410 $values['status_syncing_order_statuses']
411 );
412 $values['status_syncing_packet_statuses'] = $this->getChosenKeys(
413 $this->getPacketStatusesChoiceData(),
414 $values['status_syncing_packet_statuses']
415 );
416 $values['order_status_change_packet_statuses'] = $this->translateStatuses(
417 $this->getPacketStatusesChoiceData(),
418 $values['order_status_change_packet_statuses']
419 );
420
421 if ( $values['max_status_syncing_packets'] === '' ) {
422 unset( $values['max_status_syncing_packets'] );
423 }
424
425 if ( $values['max_days_of_packet_status_syncing'] === '' ) {
426 unset( $values['max_days_of_packet_status_syncing'] );
427 }
428
429 update_option( OptionsProvider::OPTION_NAME_PACKETERY_SYNC, $values );
430
431 $this->messageManager->flash_message( __( 'Settings saved.', 'packeta' ), MessageManager::TYPE_SUCCESS, MessageManager::RENDERER_PACKETERY, 'plugin-options' );
432
433 if ( wp_safe_redirect( $this->createLink( self::TAB_PACKET_STATUS_SYNC ) ) ) {
434 exit;
435 }
436 }
437
438 public function createAdvancedForm(): Form {
439 $form = $this->formFactory->create( 'packetery_advanced_form' );
440 $defaults = $this->optionsProvider->getOptionsByName( OptionsProvider::OPTION_NAME_PACKETERY_ADVANCED );
441
442 $form->addCheckbox( 'new_carrier_settings_enabled', __( 'Advanced carrier settings', 'packeta' ) )
443 ->setRequired( false )
444 ->setDefaultValue( OptionsProvider::DEFAULT_VALUE_CARRIER_SETTINGS );
445
446 $form->addSubmit( 'save', __( 'Save changes', 'packeta' ) );
447
448 $form->setDefaults( $defaults );
449
450 $form->onSuccess[] = [ $this, 'onAdvancedFormSuccess' ];
451
452 return $form;
453 }
454
455 public function onAdvancedFormSuccess( Form $form, array $values ): void {
456 update_option( OptionsProvider::OPTION_NAME_PACKETERY_ADVANCED, $values );
457
458 $this->messageManager->flash_message( __( 'Settings saved.', 'packeta' ), MessageManager::TYPE_SUCCESS, MessageManager::RENDERER_PACKETERY, 'plugin-options' );
459
460 if ( wp_safe_redirect( $this->createLink( self::TAB_ADVANCED ) ) ) {
461 exit;
462 }
463 }
464
465 /**
466 * Creates settings form.
467 *
468 * @return Form
469 */
470 public function create_form(): Form {
471 $form = $this->formFactory->create();
472 $form->setAction( 'options.php' );
473
474 $container = $form->addContainer( self::FORM_FIELDS_CONTAINER );
475 $container->addText( 'api_password', __( 'API password', 'packeta' ) )
476 ->setRequired()
477 ->addRule( $form::PATTERN, __( 'API password must be 32 characters long and must contain valid characters!', 'packeta' ), '[a-z\d]{32}' );
478 $container->addText( 'sender', __( 'Sender', 'packeta' ) )
479 ->setRequired();
480
481 $packetaLabelFormats = $this->optionsProvider->getPacketaLabelFormats();
482 $container->addSelect(
483 self::FORM_FIELD_PACKETA_LABEL_FORMAT,
484 __( 'Packeta Label Format', 'packeta' ),
485 $packetaLabelFormats
486 )->checkDefaultValue( false )->setDefaultValue( OptionsProvider::DEFAULT_VALUE_PACKETA_LABEL_FORMAT );
487
488 $carrierLabelFormats = $this->optionsProvider->getCarrierLabelFormat();
489 $container->addSelect(
490 self::FORM_FIELD_CARRIER_LABEL_FORMAT,
491 __( 'Carrier Label Format', 'packeta' ),
492 $carrierLabelFormats
493 )->checkDefaultValue( false )->setDefaultValue( OptionsProvider::DEFAULT_VALUE_CARRIER_LABEL_FORMAT );
494
495 $gateways = PaymentGatewayHelper::getAvailablePaymentGateways();
496 $enabledGateways = [];
497 foreach ( $gateways as $gateway ) {
498 $enabledGateways[ $gateway->id ] = $gateway->get_method_title();
499 }
500 $container->addMultiSelect(
501 'cod_payment_methods',
502 __( 'Payment methods that represent cash on delivery', 'packeta' ),
503 $enabledGateways
504 )->checkDefaultValue( false );
505
506 $container->addText( 'packaging_weight', __( 'Weight of packaging material', 'packeta' ) . ' (kg)' )
507 ->setRequired()
508 ->addRule( Form::FLOAT )
509 ->addRule( Form::MIN, null, 0 )
510 ->setDefaultValue( 0 );
511
512 $container->addCheckbox( 'default_weight_enabled', __( 'Enable default weight', 'packeta' ) )
513 ->addCondition( Form::EQUAL, true )
514 ->toggle( '#packetery-default-weight-value' );
515
516 $container->addText( 'default_weight', __( 'Default weight', 'packeta' ) . ' (kg)' )
517 ->addConditionOn( $form[ self::FORM_FIELDS_CONTAINER ]['default_weight_enabled'], Form::EQUAL, true )
518 ->setRequired()
519 ->addRule( Form::FLOAT )
520 ->addRule( Form::MIN, null, 0.1 );
521
522 $container->addSelect(
523 'dimensions_unit',
524 __( 'Units used for dimensions', 'packeta' ),
525 [
526 OptionsProvider::DIMENSIONS_UNIT_CM => 'cm',
527 OptionsProvider::DEFAULT_DIMENSIONS_UNIT_MM => 'mm',
528 ]
529 )
530 ->setDefaultValue( $this->optionsProvider::DEFAULT_DIMENSIONS_UNIT_MM );
531
532 $container->addCheckbox( 'default_dimensions_enabled', __( 'Enable default dimensions', 'packeta' ) )
533 ->addCondition( Form::EQUAL, true )
534 ->toggle( '#packetery-default-dimensions-value' );
535
536 $container->addText( 'default_length', __( 'Length', 'packeta' ) )
537 ->addConditionOn( $form[ self::FORM_FIELDS_CONTAINER ]['default_dimensions_enabled'], Form::EQUAL, true )
538 ->setRequired()
539 ->addConditionOn( $form[ self::FORM_FIELDS_CONTAINER ]['dimensions_unit'], Form::EQUAL, $this->optionsProvider::DEFAULT_DIMENSIONS_UNIT_MM )
540 ->addRule( Form::INTEGER, __( 'Provide a full number!', 'packeta' ) )
541 ->addRule( Form::MIN, 'Value must be greater than 0', 1 )
542 ->elseCondition()
543 ->addRule( Form::FLOAT, __( 'Provide a decimal value!', 'packeta' ) )
544 ->addRule( Form::MIN, 'Value must be greater than 0', 0.1 )
545 ->endCondition();
546
547 $container->addText( 'default_height', __( 'Height', 'packeta' ) )
548 ->addConditionOn( $form[ self::FORM_FIELDS_CONTAINER ]['default_dimensions_enabled'], Form::EQUAL, true )
549 ->setRequired()
550 ->addConditionOn( $form[ self::FORM_FIELDS_CONTAINER ]['dimensions_unit'], Form::EQUAL, $this->optionsProvider::DEFAULT_DIMENSIONS_UNIT_MM )
551 ->addRule( Form::INTEGER, __( 'Provide a full number!', 'packeta' ) )
552 ->addRule( Form::MIN, 'Value must be greater than 0', 1 )
553 ->elseCondition()
554 ->addRule( Form::FLOAT, __( 'Provide a decimal value!', 'packeta' ) )
555 ->addRule( Form::MIN, 'Value must be greater than 0', 0.1 )
556 ->endCondition();
557
558 $container->addText( 'default_width', __( 'Width', 'packeta' ) )
559 ->addConditionOn( $form[ self::FORM_FIELDS_CONTAINER ]['default_dimensions_enabled'], Form::EQUAL, true )
560 ->setRequired()
561 ->addConditionOn( $form[ self::FORM_FIELDS_CONTAINER ]['dimensions_unit'], Form::EQUAL, $this->optionsProvider::DEFAULT_DIMENSIONS_UNIT_MM )
562 ->addRule( Form::INTEGER, __( 'Provide a full number!', 'packeta' ) )
563 ->addRule( Form::MIN, 'Value must be greater than 0', 1 )
564 ->elseCondition()
565 ->addRule( Form::FLOAT, __( 'Provide a decimal value!', 'packeta' ) )
566 ->addRule( Form::MIN, 'Value must be greater than 0', 0.1 )
567 ->endCondition();
568
569 $container->addCheckbox( 'replace_shipping_address_with_pickup_point_address', __( 'Replace shipping address with pickup point address', 'packeta' ) )
570 ->setRequired( false );
571
572 $container->addSelect(
573 'checkout_detection',
574 __( 'Force checkout type', 'packeta' ),
575 [
576 OptionsProvider::AUTOMATIC_CHECKOUT_DETECTION => __( 'Automatic detection', 'packeta' ),
577 OptionsProvider::CLASSIC_CHECKOUT_DETECTION => __( 'Classic checkout', 'packeta' ),
578 OptionsProvider::BLOCK_CHECKOUT_DETECTION => __( 'Block-based checkout', 'packeta' ),
579 ]
580 );
581
582 $container->addSelect(
583 'checkout_widget_button_location',
584 __( 'Widget button location in checkout', 'packeta' ),
585 [
586 'after_shipping_rate' => __( 'After shipping rate', 'packeta' ),
587 'after_transport_methods' => __( 'After transport methods', 'packeta' ),
588 ]
589 );
590
591 $container->addSelect(
592 'email_hook',
593 __( 'Hook used to view information in email', 'packeta' ),
594 [
595 'woocommerce_email_footer' => 'woocommerce_email_footer',
596 'woocommerce_email_before_order_table' => 'woocommerce_email_before_order_table',
597 'woocommerce_email_after_order_table' => 'woocommerce_email_after_order_table',
598 'woocommerce_email_order_meta' => 'woocommerce_email_order_meta',
599 ]
600 );
601
602 $container->addCheckbox( 'force_packet_cancel', __( 'Force order cancellation', 'packeta' ) )
603 ->setRequired( false )
604 ->setDefaultValue( OptionsProvider::FORCE_PACKET_CANCEL_DEFAULT );
605
606 $container->addCheckbox( 'widget_auto_open', __( 'Automatically open widget when shipping was selected', 'packeta' ) )
607 ->setRequired( false )
608 ->setDefaultValue( OptionsProvider::WIDGET_AUTO_OPEN_DEFAULT );
609
610 $container->addCheckbox( self::FORM_FIELD_FREE_SHIPPING_SHOWN, __( 'Display the FREE shipping text in checkout', 'packeta' ) )
611 ->setRequired( false )
612 ->setDefaultValue( OptionsProvider::DISPLAY_FREE_SHIPPING_IN_CHECKOUT_DEFAULT );
613
614 $container->addCheckbox( 'prices_include_tax', __( 'Prices include tax', 'packeta' ) )
615 ->setRequired( false )
616 ->setDefaultValue( OptionsProvider::PRICES_INCLUDE_TAX_DEFAULT );
617
618 $form->addSubmit( 'save', __( 'Save changes', 'packeta' ) );
619
620 if ( $this->optionsProvider->has_any( OptionsProvider::OPTION_NAME_PACKETERY ) ) {
621 $container->setDefaults( $this->optionsProvider->getOptionsByName( OptionsProvider::OPTION_NAME_PACKETERY ) );
622 }
623
624 return $form;
625 }
626
627 /**
628 * Admin_init callback.
629 */
630 public function admin_init(): void {
631 add_filter( 'pre_update_option_packetery', [ $this, 'validatePacketeryOptions' ] );
632 register_setting( self::FORM_FIELDS_CONTAINER, self::FORM_FIELDS_CONTAINER, [ $this, 'sanitizePacketeryOptions' ] );
633 add_settings_section( 'packetery_main', __( 'Main Settings', 'packeta' ), function () {}, self::SLUG );
634 }
635
636 /**
637 * Validates packetery options.
638 *
639 * @param array $options Options to be validated.
640 *
641 * @return array
642 */
643 public function validatePacketeryOptions( array $options ): array {
644 $form = $this->create_form();
645 /**
646 * Packetery container.
647 *
648 * @var Container $packeteryContainer
649 */
650 $packeteryContainer = $form[ self::FORM_FIELDS_CONTAINER ];
651 $packeteryContainer->setValues( $options );
652 if ( $form->isValid() === false ) {
653 foreach ( $packeteryContainer->getControls() as $control ) {
654 if ( $control->hasErrors() === false ) {
655 continue;
656 }
657
658 add_settings_error( OptionsProvider::OPTION_NAME_PACKETERY, esc_attr( $control->getName() ), "{$control->getCaption()}: {$control->getError()}" );
659 }
660 }
661
662 $apiPassword = $packeteryContainer['api_password'];
663 if ( $apiPassword instanceof BaseControl && $apiPassword->hasErrors() === false ) {
664 $this->packetaClient->setApiPassword( $apiPassword->getValue() );
665 }
666
667 $this->validateSender( $options['sender'] );
668
669 return $options;
670 }
671
672 /**
673 * Sanitize options.
674 *
675 * @param array $options Options to be sanitized.
676 *
677 * @return array
678 */
679 public function sanitizePacketeryOptions( array $options ): array {
680 $form = $this->create_form();
681 /**
682 * Packetery container.
683 *
684 * @var Container $packeteryContainer
685 */
686 $packeteryContainer = $form[ self::FORM_FIELDS_CONTAINER ];
687 $packeteryContainer->setValues( $options );
688 if ( $form->isValid() === false ) {
689 foreach ( $packeteryContainer->getControls() as $control ) {
690 if ( $control->hasErrors() === false ) {
691 continue;
692 }
693
694 $options[ $control->getName() ] = '';
695 }
696 }
697
698 $apiPassword = $packeteryContainer['api_password'];
699
700 if ( $apiPassword instanceof BaseControl && $apiPassword->hasErrors() === false ) {
701 $apiPass = $apiPassword->getValue();
702 $options['api_key'] = substr( $apiPass, 0, 16 );
703 $this->packetaClient->setApiPassword( $apiPass );
704 } else {
705 $options['api_key'] = '';
706 }
707
708 if ( $packeteryContainer['default_weight'] instanceof BaseControl ) {
709 $defaultWeight = $packeteryContainer['default_weight']->getValue();
710 $options['default_weight'] = is_numeric( $defaultWeight ) ? CoreHelper::trimDecimalPlaces( (float) $defaultWeight, 3 ) : $defaultWeight;
711 }
712
713 foreach ( [ 'default_length', 'default_width', 'default_height' ] as $dimension ) {
714 if ( $packeteryContainer[ $dimension ] instanceof BaseControl ) {
715 $options[ $dimension ] = is_numeric( $packeteryContainer[ $dimension ]->getValue() )
716 ? CoreHelper::trimDecimalPlaces( (float) $packeteryContainer[ $dimension ]->getValue(), 1 )
717 : $packeteryContainer[ $dimension ]->getValue();
718 }
719 }
720
721 if ( $packeteryContainer['force_packet_cancel'] instanceof BaseControl ) {
722 $options['force_packet_cancel'] = (int) $packeteryContainer['force_packet_cancel']->getValue();
723 }
724
725 if ( $packeteryContainer['free_shipping_shown'] instanceof BaseControl ) {
726 $options['free_shipping_shown'] = (int) $packeteryContainer['free_shipping_shown']->getValue();
727 }
728
729 $previousOptions = $this->optionsProvider->getOptionsByName( OptionsProvider::OPTION_NAME_PACKETERY );
730 if ( ! isset( $options['default_weight_enabled'] ) ) {
731 if ( isset( $previousOptions['default_weight'] ) ) {
732 $options['default_weight'] = $previousOptions['default_weight'];
733 } else {
734 unset( $options['default_weight'] );
735 }
736 }
737 if ( ! isset( $options['default_dimensions_enabled'] ) ) {
738 foreach ( [ 'default_length', 'default_width', 'default_height' ] as $dimension ) {
739 if ( isset( $previousOptions[ $dimension ] ) ) {
740 $options[ $dimension ] = $previousOptions[ $dimension ];
741 } else {
742 unset( $options[ $dimension ] );
743 }
744 }
745 }
746
747 return $options;
748 }
749
750 /**
751 * Validates sender.
752 *
753 * @param string $senderLabel Sender label.
754 *
755 * @return bool|null
756 */
757 private function validateSender( string $senderLabel ): ?bool {
758 $senderValidationRequest = new SenderGetReturnRouting( $senderLabel );
759 $senderValidationResponse = $this->packetaClient->senderGetReturnRouting( $senderValidationRequest );
760
761 $senderValidationLog = new Log\Record();
762 $senderValidationLog->action = Log\Record::ACTION_SENDER_VALIDATION;
763
764 $senderValidationLog->status = Log\Record::STATUS_SUCCESS;
765 $senderValidationLog->title = __( 'Sender validation was successful', 'packeta' );
766
767 if ( $senderValidationResponse->hasFault() ) {
768 $senderValidationLog->status = Log\Record::STATUS_ERROR;
769 $senderValidationLog->params = [
770 'errorMessage' => $senderValidationResponse->getFaultString(),
771 ];
772 $senderValidationLog->title = __( 'Sender could not be validated', 'packeta' );
773 }
774
775 $this->logger->add( $senderValidationLog );
776
777 $senderExists = $senderValidationResponse->senderExists();
778
779 if ( $senderExists === false ) {
780 $this->messageManager->flash_message( __( 'Specified sender does not exist', 'packeta' ), MessageManager::TYPE_INFO, MessageManager::RENDERER_PACKETERY, 'plugin-options' );
781 }
782
783 if ( $senderExists === null ) {
784 $this->messageManager->flash_message( __( 'Unable to check specified sender', 'packeta' ), MessageManager::TYPE_INFO, MessageManager::RENDERER_PACKETERY, 'plugin-options' );
785 }
786
787 return $senderExists;
788 }
789
790 /**
791 * Process actions.
792 *
793 * @return void
794 */
795 public function processActions(): void {
796 $action = $this->httpRequest->getQuery( 'action' );
797 if ( $action === self::ACTION_VALIDATE_SENDER ) {
798 $result = $this->validateSender( $this->optionsProvider->get_sender() );
799
800 if ( $result === true ) {
801 $this->messageManager->flash_message( __( 'Specified sender has been validated.', 'packeta' ), MessageManager::TYPE_SUCCESS, MessageManager::RENDERER_PACKETERY, 'plugin-options' );
802 }
803
804 $doRedirect = wp_safe_redirect(
805 add_query_arg(
806 [
807 'page' => self::SLUG,
808 ],
809 get_admin_url( null, 'admin.php' )
810 )
811 );
812
813 if ( $doRedirect ) {
814 exit;
815 }
816 }
817
818 $packetStatusSyncForm = $this->createPacketStatusSyncForm();
819 if (
820 $packetStatusSyncForm['save'] instanceof SubmitButton &&
821 $packetStatusSyncForm['save']->isSubmittedBy()
822 ) {
823 $packetStatusSyncForm->fireEvents();
824 }
825
826 $autoSubmissionForm = $this->createAutoSubmissionForm();
827 if (
828 $autoSubmissionForm['save'] instanceof SubmitButton &&
829 $autoSubmissionForm['save']->isSubmittedBy()
830 ) {
831 $autoSubmissionForm->fireEvents();
832 }
833
834 $advancedForm = $this->createAdvancedForm();
835 if (
836 $advancedForm['save'] instanceof SubmitButton &&
837 $advancedForm['save']->isSubmittedBy()
838 ) {
839 $advancedForm->fireEvents();
840 }
841 }
842
843 /**
844 * Renders page.
845 */
846 public function render(): void {
847 $activeTab = ( $this->httpRequest->getQuery( self::PARAM_TAB ) ?? self::TAB_GENERAL );
848
849 $latteParams = [];
850 if ( $activeTab === self::TAB_PACKET_STATUS_SYNC ) {
851 $latteParams = [ 'form' => $this->createPacketStatusSyncForm() ];
852 } elseif ( $activeTab === self::TAB_AUTO_SUBMISSION ) {
853 $latteParams = [ 'form' => $this->createAutoSubmissionForm() ];
854 } elseif ( $activeTab === self::TAB_ADVANCED ) {
855 $latteParams = [ 'form' => $this->createAdvancedForm() ];
856 } elseif ( $activeTab === self::TAB_GENERAL ) {
857 $latteParams = [ 'form' => $this->create_form() ];
858 }
859
860 if ( ! extension_loaded( 'soap' ) ) {
861 $latteParams['error'] = __( 'This plugin requires an active SOAP library for proper operation. Contact your web hosting administrator.', 'packeta' );
862 }
863
864 $latteParams['apiPasswordLink'] = trim( $this->latteEngine->renderToString( PACKETERY_PLUGIN_DIR . '/template/options/help-block-link.latte', [ 'href' => 'https://client.packeta.com/support' ] ) );
865
866 $latteParams['exportLink'] = add_query_arg(
867 [
868 'page' => self::SLUG,
869 'action' => Exporter::ACTION_EXPORT_SETTINGS,
870 ],
871 get_admin_url( null, 'admin.php' )
872 );
873
874 $latteParams['activeTab'] = ( $this->httpRequest->getQuery( self::PARAM_TAB ) ?? self::TAB_GENERAL );
875 $latteParams['generalTabLink'] = $this->createLink();
876 $latteParams['advancedTabLink'] = $this->createLink( self::TAB_ADVANCED );
877 $latteParams['supportTabLink'] = $this->createLink( self::TAB_SUPPORT );
878 $latteParams['packetStatusSyncTabLink'] = $this->createLink( self::TAB_PACKET_STATUS_SYNC );
879 $latteParams['autoSubmissionTabLink'] = $this->createLink( self::TAB_AUTO_SUBMISSION );
880
881 $latteParams['canValidateSender'] = (bool) $this->optionsProvider->get_sender();
882 $latteParams['senderValidationLink'] = add_query_arg(
883 [
884 'page' => self::SLUG,
885 'action' => self::ACTION_VALIDATE_SENDER,
886 ],
887 get_admin_url( null, 'admin.php' )
888 );
889
890 $lastExport = null;
891 $lastExportOption = get_option( Exporter::OPTION_LAST_SETTINGS_EXPORT );
892 if ( $lastExportOption !== false ) {
893 $date = DateTime::createFromFormat( DATE_ATOM, $lastExportOption );
894 if ( $date !== false ) {
895 $date->setTimezone( wp_timezone() );
896 $lastExport = $date->format( get_option( 'date_format' ) . ' ' . get_option( 'time_format' ) );
897 }
898 }
899 if ( $lastExport !== null ) {
900 $latteParams['lastExport'] = $lastExport;
901 }
902
903 $latteParams['forcePacketCancelDescription'] = __( 'Cancel the packet for an order even if the cancellation in the Packeta system will not be successful.', 'packeta' );
904 $latteParams['messages'] = $this->messageManager->renderToString( MessageManager::RENDERER_PACKETERY, 'plugin-options' );
905 $latteParams['isCzechLocale'] = $this->moduleHelper->isCzechLocale();
906 $latteParams['logoZasilkovna'] = $this->urlBuilder->buildAssetUrl( 'public/images/logo-zasilkovna.svg' );
907 $latteParams['logoPacketa'] = $this->urlBuilder->buildAssetUrl( 'public/images/logo-packeta.svg' );
908 $advancedCarrierSettingsDescription = sprintf(
909 // translators: first %s is line break, second one is e-mail address
910 __( 'BETA: Once enabled, Packeta carriers will appear as separate shipping methods in WooCommerce - Settings - Shipping. After enabling this feature, you will need to set up shipping methods in WooCommerce again.%1$sThis is an experimental feature. If you experience any issues, please email us at %2$s with a description of the issue.', 'packeta' ),
911 '<br>',
912 '<a href="mailto:' . $this->supportEmailAddress . '">' . $this->supportEmailAddress . '</a>'
913 );
914 $latteParams['translations'] = [
915 'packeta' => __( 'Packeta', 'packeta' ),
916 'title' => __( 'Options', 'packeta' ),
917 'general' => __( 'General', 'packeta' ),
918 'packetAutoSubmission' => __( 'Packet auto-submission', 'packeta' ),
919 'packetAutoSubmissionMappingDescription' => __( 'Choose events for payment methods that will trigger packet submission', 'packeta' ),
920 // translators: %s represents URL.
921 'apiPasswordCanBeFoundAt%sUrl' => __( 'API password can be found at %s', 'packeta' ),
922
923 'saveChanges' => __( 'Save changes', 'packeta' ),
924 'validateSender' => __( 'Validate sender', 'packeta' ),
925 'advanced' => __( 'Advanced', 'packeta' ),
926 'support' => __( 'Support', 'packeta' ),
927 'optionsExportInfo1' => __(
928 'By clicking the button, you will export the settings of your plugin into a separate file. The export does not contain any sensitive information about your e-shop. Please send the resulting file to the technical support of Packeta (you can find the e-mail address here:',
929 'packeta'
930 ),
931 'optionsExportInfo2' => __(
932 ') along with the description of your problem. For a better understanding of your problem, we recommend adding screenshots, which show the problem (if possible).',
933 'packeta'
934 ),
935 'exportPluginSettings' => __( 'Export the plugin settings', 'packeta' ),
936 'settingsExportDatetime' => __( 'Date and time of the last export of settings', 'packeta' ),
937 'settingsNotYetExported' => __( 'The settings have not been exported yet.', 'packeta' ),
938 'senderDescription' => sprintf(
939 /* translators: 1: emphasis start 2: emphasis end 3: client section link start 4: client section link end */
940 esc_html__( 'Fill here %1$ssender label%2$s - you will find it in %3$sclient section%4$s - user information - field \'Indication\'.', 'packeta' ),
941 '<strong>',
942 '</strong>',
943 '<a href="https://client.packeta.com/senders" target="_blank">',
944 '</a>'
945 ),
946 'advancedCarrierSettingsDescription' => $advancedCarrierSettingsDescription,
947 'packagingWeightDescription' => __( 'This parameter is used to determine the weight of the packaging material. This value is automatically added to the total weight of each order that contains products with non-zero weight. This value is also taken into account when evaluating the weight rules in the cart.', 'packeta' ),
948 'defaultWeightDescription' => __( 'This value is automatically added to the total weight of each order that contains products with zero weight.', 'packeta' ),
949 'defaultDimensionsDescription' => __( 'These dimensions will be applied to the packet by default, if required by the carrier.', 'packeta' ),
950 'setCheckoutDetectionDescription' => __( 'If you have trouble displaying the widget button in the checkout, you can force what type of checkout you are using.', 'packeta' ),
951 'packetStatusSyncTabLinkLabel' => __( 'Packet status tracking', 'packeta' ),
952 'statusSyncingOrderStatusesLabel' => __( 'Order statuses, for which cron will check the packet status', 'packeta' ),
953 'statusSyncingOrderStatusesDescription' => __( 'Cron will automatically track all orders with these statuses and check if the shipment status has changed.', 'packeta' ),
954 'statusSyncingPacketStatusesLabel' => __( 'Packet statuses that are being checked', 'packeta' ),
955 'statusSyncingPacketStatusesDescription' => __( 'If an order has a shipment with one of these selected statuses, the shipment status will be tracked.', 'packeta' ),
956 'numberOfDaysToCheckDescription' => __( 'Number of days after the creation of an order, during which the order status will be checked.', 'packeta' ),
957 'widgetAutoOpenDescription' => __( 'If this option is active, the widget for selecting pickup points will open automatically after selecting the shipping method at the checkout.', 'packeta' ),
958 'autoOrderStatusChangeDescription' => __( 'Change order status after data submission to Packeta.', 'packeta' ),
959 'freeShippingTextDescription' => __( 'If enabled, "FREE" will be displayed after the name of the shipping method, if free shipping is applied.', 'packeta' ),
960 'orderStatusChangeSettings' => __( 'Order status change settings', 'packeta' ),
961 'dimensionsLabel' => __( 'Dimensions', 'packeta' ),
962 ];
963
964 $this->latteEngine->render( PACKETERY_PLUGIN_DIR . '/template/options/page.latte', $latteParams );
965 }
966
967 /**
968 * Creates tab link.
969 *
970 * @param string|null $tab Tab ID.
971 * @return string
972 */
973 public function createLink( ?string $tab = null ): string {
974 $params = [
975 'page' => self::SLUG,
976 ];
977
978 if ( $tab !== null ) {
979 $params[ self::PARAM_TAB ] = $tab;
980 }
981
982 return add_query_arg(
983 $params,
984 get_admin_url( null, 'admin.php' )
985 );
986 }
987 }
988