PluginProbe
Packeta / 2.3.2
Packeta v2.3.2
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
← All changes | src/Packetery/Module/Carrier/OptionsPage.php +521 -187 1.5.32.3.2 View file →
@@ -8,19 +8,24 @@
8 8 declare( strict_types=1 );
9 9
10 10 namespace Packetery\Module\Carrier;
11 11
12 +use Packetery\Core\CoreHelper;
12 13 use Packetery\Core\Entity\Carrier;
13 -use Packetery\Core\Helper;
14 14 use Packetery\Core\Rounder;
15 +use Packetery\Latte\Engine;
16 +use Packetery\Module\Dashboard\DashboardPage;
15 17 use Packetery\Module\FormFactory;
16 18 use Packetery\Module\FormValidators;
19 +use Packetery\Module\Framework\WpAdapter;
17 20 use Packetery\Module\MessageManager;
18 -use Packetery\Module\Options\FeatureFlagManager;
19 -use PacketeryLatte\Engine;
20 -use PacketeryNette\Forms\Container;
21 -use PacketeryNette\Forms\Form;
22 -use PacketeryNette\Http\Request;
21 +use Packetery\Module\ModuleHelper;
22 +use Packetery\Module\PaymentGatewayHelper;
23 +use Packetery\Module\Views\UrlBuilder;
24 +use Packetery\Nette\Forms\Container;
25 +use Packetery\Nette\Forms\Control;
26 +use Packetery\Nette\Forms\Form;
27 +use Packetery\Nette\Http\Request;
23 28
24 29 /**
25 30 * Class OptionsPage
26 31 *
@@ -27,80 +32,79 @@
27 32 * @package Packetery\Options
28 33 */
29 34 class OptionsPage {
30 35
31 - public const FORM_FIELD_NAME = 'name';
36 + public const FORM_FIELD_NAME = 'name';
37 + public const FORM_FIELD_ACTIVE = 'active';
38 + public const FORM_FIELD_WEIGHT_LIMITS = 'weight_limits';
39 + public const FORM_FIELD_PRODUCT_VALUE_LIMITS = 'product_value_limits';
40 + public const FORM_FIELD_PRICING_TYPE = 'pricing_type';
41 +
32 42 public const SLUG = 'packeta-country';
43 + public const PARAMETER_COUNTRY_CODE = 'country_code';
44 + public const PARAMETER_CARRIER_ID = 'carrier_id';
33 45 public const MINIMUM_CHECKED_VENDORS = 2;
34 46
35 47 /**
36 - * PacketeryLatte_engine.
37 - *
38 - * @var Engine PacketeryLatte engine.
48 + * @var Engine
39 49 */
40 50 private $latteEngine;
41 51
42 52 /**
43 - * Carrier repository.
44 - *
45 - * @var EntityRepository Carrier repository.
53 + * @var EntityRepository
46 54 */
47 55 private $carrierRepository;
48 56
49 57 /**
50 - * Form factory.
51 - *
52 - * @var FormFactory Form factory.
58 + * @var FormFactory
53 59 */
54 60 private $formFactory;
55 61
56 62 /**
57 - * PacketeryNette Request.
58 - *
59 - * @var Request PacketeryNette Request.
63 + * @var Request
60 64 */
61 65 private $httpRequest;
62 66
63 67 /**
64 - * CountryListingPage.
65 - *
66 - * @var CountryListingPage CountryListingPage.
68 + * @var CountryListingPage
67 69 */
68 70 private $countryListingPage;
69 71
70 72 /**
71 - * Message manager.
72 - *
73 73 * @var MessageManager
74 74 */
75 75 private $messageManager;
76 76
77 77 /**
78 - * Internal pickup points config.
79 - *
80 78 * @var PacketaPickupPointsConfig
81 79 */
82 80 private $pickupPointsConfig;
83 81
84 82 /**
85 - * Feature flag.
86 - *
87 - * @var FeatureFlagManager
83 + * @var CarDeliveryConfig
88 84 */
89 - private $featureFlag;
85 + private $carDeliveryConfig;
90 86
91 87 /**
92 - * Plugin constructor.
93 - *
94 - * @param Engine $latteEngine PacketeryLatte_engine.
95 - * @param EntityRepository $carrierRepository Carrier repository.
96 - * @param FormFactory $formFactory Form factory.
97 - * @param Request $httpRequest PacketeryNette Request.
98 - * @param CountryListingPage $countryListingPage CountryListingPage.
99 - * @param MessageManager $messageManager Message manager.
100 - * @param PacketaPickupPointsConfig $pickupPointsConfig Internal pickup points config.
101 - * @param FeatureFlagManager $featureFlag Feature flag.
88 + * @var CarrierOptionsFactory
102 89 */
90 + private $carrierOptionsFactory;
91 +
92 + /**
93 + * @var ModuleHelper
94 + */
95 + private $moduleHelper;
96 +
97 + /**
98 + * @var UrlBuilder
99 + */
100 + private $urlBuilder;
101 +
102 + /**
103 + * @var WpAdapter
104 + */
105 + private $wpAdapter;
106 +
103 107 public function __construct(
104 108 Engine $latteEngine,
105 109 EntityRepository $carrierRepository,
106 110 FormFactory $formFactory,
@@ -107,18 +111,26 @@
107 111 Request $httpRequest,
108 112 CountryListingPage $countryListingPage,
109 113 MessageManager $messageManager,
110 114 PacketaPickupPointsConfig $pickupPointsConfig,
111 - FeatureFlagManager $featureFlag
115 + CarDeliveryConfig $carDeliveryConfig,
116 + CarrierOptionsFactory $carrierOptionsFactory,
117 + ModuleHelper $moduleHelper,
118 + UrlBuilder $urlBuilder,
119 + WpAdapter $wpAdapter
112 120 ) {
113 - $this->latteEngine = $latteEngine;
114 - $this->carrierRepository = $carrierRepository;
115 - $this->formFactory = $formFactory;
116 - $this->httpRequest = $httpRequest;
117 - $this->countryListingPage = $countryListingPage;
118 - $this->messageManager = $messageManager;
119 - $this->pickupPointsConfig = $pickupPointsConfig;
120 - $this->featureFlag = $featureFlag;
121 + $this->latteEngine = $latteEngine;
122 + $this->carrierRepository = $carrierRepository;
123 + $this->formFactory = $formFactory;
124 + $this->httpRequest = $httpRequest;
125 + $this->countryListingPage = $countryListingPage;
126 + $this->messageManager = $messageManager;
127 + $this->pickupPointsConfig = $pickupPointsConfig;
128 + $this->carDeliveryConfig = $carDeliveryConfig;
129 + $this->carrierOptionsFactory = $carrierOptionsFactory;
130 + $this->moduleHelper = $moduleHelper;
131 + $this->urlBuilder = $urlBuilder;
132 + $this->wpAdapter = $wpAdapter;
121 133 }
122 134
123 135 /**
124 136 * Registers WP callbacks.
@@ -124,9 +136,9 @@
124 136 * Registers WP callbacks.
125 137 */
126 138 public function register(): void {
127 139 add_submenu_page(
128 - \Packetery\Module\Options\Page::SLUG,
140 + DashboardPage::SLUG,
129 141 __( 'Carrier settings', 'packeta' ),
130 142 __( 'Carrier settings', 'packeta' ),
131 143 'manage_options',
132 144 self::SLUG,
@@ -150,9 +162,9 @@
150 162
151 163 $form = $this->formFactory->create( $optionId );
152 164
153 165 $form->addCheckbox(
154 - 'active',
166 + self::FORM_FIELD_ACTIVE,
155 167 __( 'Active carrier', 'packeta' ) . ':'
156 168 );
157 169
158 170 $form->addText( self::FORM_FIELD_NAME, __( 'Display name', 'packeta' ) . ':' )
@@ -157,37 +169,60 @@
157 169
158 170 $form->addText( self::FORM_FIELD_NAME, __( 'Display name', 'packeta' ) . ':' )
159 171 ->setRequired();
160 172
161 - $carrierOptions = get_option( $optionId );
162 - if ( $this->featureFlag->isSplitActive() ) {
163 - $vendorCheckboxes = $this->getVendorCheckboxesConfig( $carrierData['id'], ( $carrierOptions ? $carrierOptions : null ) );
164 - if ( $vendorCheckboxes ) {
165 - $vendorsContainer = $form->addContainer( 'vendor_groups' );
166 - foreach ( $vendorCheckboxes as $checkboxConfig ) {
167 - $checkboxControl = $vendorsContainer->addCheckbox( $checkboxConfig['group'], $checkboxConfig['name'] );
168 - if ( true === $checkboxConfig['disabled'] ) {
169 - $checkboxControl->setDisabled()->setOmitted( false );
170 - }
171 - if ( true === $checkboxConfig['default'] ) {
172 - $checkboxControl->setDefaultValue( true );
173 - }
173 + $carrierOptions = get_option( $optionId );
174 + $vendorCheckboxes = $this->getVendorCheckboxesConfig( $carrierData['id'], ( $carrierOptions !== false ? $carrierOptions : null ) );
175 + if ( count( $vendorCheckboxes ) > 0 ) {
176 + $vendorsContainer = $form->addContainer( 'vendor_groups' );
177 + foreach ( $vendorCheckboxes as $checkboxConfig ) {
178 + $checkboxControl = $vendorsContainer->addCheckbox( $checkboxConfig['group'], $checkboxConfig['name'] );
179 + if ( $checkboxConfig['disabled'] === true ) {
180 + $checkboxControl->setDisabled()->setOmitted( false );
174 181 }
182 + if ( $checkboxConfig['default'] === true ) {
183 + $checkboxControl->setDefaultValue( true );
184 + }
175 185 }
176 186 }
177 187
178 - $weightLimits = $form->addContainer( 'weight_limits' );
179 - if ( empty( $carrierData['weight_limits'] ) ) {
188 + $form->addSelect(
189 + self::FORM_FIELD_PRICING_TYPE,
190 + __( 'Pricing type', 'packeta' ),
191 + [
192 + Options::PRICING_TYPE_BY_WEIGHT => __( 'By weight', 'packeta' ),
193 + Options::PRICING_TYPE_BY_PRODUCT_VALUE => __( 'By product value', 'packeta' ),
194 + ]
195 + )
196 + ->setDefaultValue( Options::PRICING_TYPE_BY_WEIGHT )
197 + ->addCondition( Form::EQUAL, Options::PRICING_TYPE_BY_WEIGHT )
198 + ->toggle( $this->createFieldContainerId( $form, self::FORM_FIELD_WEIGHT_LIMITS ) )
199 + ->endCondition()
200 + ->addCondition( Form::EQUAL, Options::PRICING_TYPE_BY_PRODUCT_VALUE )
201 + ->toggle( $this->createFieldContainerId( $form, self::FORM_FIELD_PRODUCT_VALUE_LIMITS ) );
202 +
203 + $weightLimits = $form->addContainer( self::FORM_FIELD_WEIGHT_LIMITS );
204 + if ( ! isset( $carrierData[ self::FORM_FIELD_WEIGHT_LIMITS ] ) || count( $carrierData[ self::FORM_FIELD_WEIGHT_LIMITS ] ) === 0 ) {
180 205 $this->addWeightLimit( $weightLimits, 0 );
181 206 } else {
182 - foreach ( $carrierData['weight_limits'] as $index => $limit ) {
207 + foreach ( $carrierData[ self::FORM_FIELD_WEIGHT_LIMITS ] as $index => $limit ) {
183 208 $this->addWeightLimit( $weightLimits, $index );
184 209 }
185 210 }
186 211
212 + $productValueLimits = $form->addContainer( self::FORM_FIELD_PRODUCT_VALUE_LIMITS );
213 + if ( ! isset( $carrierData[ self::FORM_FIELD_PRODUCT_VALUE_LIMITS ] ) || count( $carrierData[ self::FORM_FIELD_PRODUCT_VALUE_LIMITS ] ) === 0 ) {
214 + $this->addProductValueLimit( $productValueLimits, 0 );
215 + } else {
216 + foreach ( $carrierData[ self::FORM_FIELD_PRODUCT_VALUE_LIMITS ] as $index => $limit ) {
217 + $this->addProductValueLimit( $productValueLimits, $index );
218 + }
219 + }
220 +
221 + // We don't expect id to be empty in this situation. This would indicate a data save error.
187 222 $carrier = $this->carrierRepository->getAnyById( (string) $carrierData['id'] );
188 223
189 - if ( null !== $carrier && $carrier->supportsCod() ) {
224 + if ( $carrier !== null && $carrier->supportsCod() ) {
190 225 $form->addText( 'default_COD_surcharge', __( 'Default COD surcharge', 'packeta' ) . ':' )
191 226 ->setRequired( false )
192 227 ->addRule( Form::FLOAT )
193 228 ->addRule( Form::MIN, null, 0 );
@@ -192,9 +227,9 @@
192 227 ->addRule( Form::FLOAT )
193 228 ->addRule( Form::MIN, null, 0 );
194 229
195 230 $surchargeLimits = $form->addContainer( 'surcharge_limits' );
196 - if ( ! empty( $carrierData['surcharge_limits'] ) ) {
231 + if ( isset( $carrierData['surcharge_limits'] ) && count( $carrierData['surcharge_limits'] ) > 0 ) {
197 232 foreach ( $carrierData['surcharge_limits'] as $index => $limit ) {
198 233 $this->addSurchargeLimit( $surchargeLimits, $index );
199 234 }
200 235 }
@@ -207,10 +242,27 @@
207 242 ->setDefaultValue( Rounder::DONT_ROUND );
208 243 }
209 244
210 245 $item = $form->addText( 'free_shipping_limit', __( 'Free shipping limit', 'packeta' ) . ':' );
211 - $item->addRule( $form::FLOAT, __( 'Please enter a valid decimal number.', 'packeta' ) );
246 + $item->setRequired( false )
247 + ->addRule( Form::FLOAT )
248 + ->addRule( Form::MIN, null, 0 );
212 249
250 + if ( $carrier !== null && $carrier->isCarDelivery() ) {
251 + $daysUntilShipping = $form->addText( 'days_until_shipping', __( 'Number of days until shipping', 'packeta' ) . ':' );
252 + $daysUntilShipping->setRequired()
253 + ->addRule( $form::INTEGER, __( 'Please, enter a full number.', 'packeta' ) )
254 + ->addRule( $form::MIN, null, 0 );
255 +
256 + $shippingTimeCutOff = $form->addText( 'shipping_time_cut_off', __( 'Shipping time cut off', 'packeta' ) . ':' );
257 + $shippingTimeCutOff->setHtmlAttribute( 'class', 'date-picker' )
258 + ->setHtmlType( 'time' )
259 + ->setRequired( false )
260 + ->setNullable()
261 + // translators: %s: Represents the time we stop taking more orders for next shipment.
262 + ->addRule( [ FormValidators::class, 'hasClockTimeFormat' ], __( 'Time must be between %1$s and %2$s.', 'packeta' ), [ '00:00', '23:59' ] );
263 + }
264 +
213 265 $couponFreeShipping = $form->addContainer( 'coupon_free_shipping' );
214 266 $couponFreeShipping->addCheckbox( 'active', __( 'Apply free shipping coupon', 'packeta' ) );
215 267 $couponFreeShipping->addCheckbox( 'allow_for_fees', __( 'Apply free shipping coupon for fees', 'packeta' ) )
216 268 ->addConditionOn( $form['coupon_free_shipping']['active'], Form::FILLED )
@@ -215,12 +267,69 @@
215 267 $couponFreeShipping->addCheckbox( 'allow_for_fees', __( 'Apply free shipping coupon for fees', 'packeta' ) )
216 268 ->addConditionOn( $form['coupon_free_shipping']['active'], Form::FILLED )
217 269 ->toggle( $this->createCouponFreeShippingForFeesContainerId( $form ) );
218 270
271 + $dimensionsRestrictions = $form->addContainer( 'dimensions_restrictions' );
272 + $dimensionsRestrictions->addCheckbox( 'active', $this->wpAdapter->__( 'Maximum package size', 'packeta' ) );
273 + if (
274 + strpos( $carrier->getId(), Carrier::VENDOR_GROUP_ZBOX ) !== false ||
275 + strpos( $carrier->getId(), Carrier::VENDOR_GROUP_ZPOINT ) === 0 ||
276 + ( $carrier->hasPickupPoints() && is_numeric( $carrier->getId() ) )
277 + ) {
278 + $dimensionsRestrictions->addText( 'length', $this->wpAdapter->__( 'Length (cm)', 'packeta' ) )
279 + ->setNullable()
280 + ->addConditionOn( $form['dimensions_restrictions']['active'], Form::FILLED )
281 + ->toggle( $this->createDimensionRestrictionContainerId( $form ) )
282 + ->setRequired()
283 + ->addRule( Form::INTEGER, $this->wpAdapter->__( 'Provide a full number!', 'packeta' ) )
284 + ->addRule( Form::MIN, 'Value must be greater than 0', 1 );
285 + $dimensionsRestrictions->addText( 'width', $this->wpAdapter->__( 'Width (cm)', 'packeta' ) )
286 + ->setNullable()
287 + ->addConditionOn( $form['dimensions_restrictions']['active'], Form::FILLED )
288 + ->toggle( $this->createDimensionRestrictionContainerId( $form ) )
289 + ->setRequired()
290 + ->addRule( Form::INTEGER, $this->wpAdapter->__( 'Provide a full number!', 'packeta' ) )
291 + ->addRule( Form::MIN, 'Value must be greater than 0', 1 );
292 + $dimensionsRestrictions->addText( 'height', $this->wpAdapter->__( 'Height (cm)', 'packeta' ) )
293 + ->setNullable()
294 + ->addConditionOn( $form['dimensions_restrictions']['active'], Form::FILLED )
295 + ->toggle( $this->createDimensionRestrictionContainerId( $form ) )
296 + ->setRequired()
297 + ->addRule( Form::INTEGER, $this->wpAdapter->__( 'Provide a full number!', 'packeta' ) )
298 + ->addRule( Form::MIN, 'Value must be greater than 0', 1 );
299 + } else {
300 +
301 + $maximumLength = $dimensionsRestrictions->addText( 'maximum_length', $this->wpAdapter->__( 'Maximum length (cm)', 'packeta' ) );
302 + $maximumLength->setNullable();
303 + $maximumLength->addConditionOn( $form['dimensions_restrictions']['active'], Form::FILLED )
304 + ->toggle( $this->createDimensionRestrictionContainerId( $form ) )
305 + ->addRule( Form::INTEGER, $this->wpAdapter->__( 'Provide a full number!', 'packeta' ) )
306 + ->addRule( Form::MIN, $this->wpAdapter->__( 'Value must be greater than 0', 'packeta' ), 1 );
307 +
308 + $dimensionsSum = $dimensionsRestrictions->addText( 'dimensions_sum', $this->wpAdapter->__( 'Sum of dimensions (cm)', 'packeta' ) );
309 + $dimensionsSum->setNullable();
310 + $dimensionsSum->addConditionOn( $form['dimensions_restrictions']['active'], Form::FILLED )
311 + ->toggle( $this->createDimensionRestrictionContainerId( $form ) )
312 + ->addRule( Form::INTEGER, $this->wpAdapter->__( 'Provide a full number!', 'packeta' ) )
313 + ->addRule( Form::MIN, $this->wpAdapter->__( 'Value must be greater than 0', 'packeta' ), 1 );
314 +
315 + $maximumLength->addConditionOn( $form['dimensions_restrictions']['active'], Form::FILLED )
316 + ->addConditionOn( $dimensionsSum, Form::BLANK )
317 + ->addRule( Form::FILLED, $this->wpAdapter->__( 'You have to fill in Maximum length or Sum of dimensions', 'packeta' ) );
318 +
319 + $dimensionsSum->addConditionOn( $form['dimensions_restrictions']['active'], Form::FILLED )
320 + ->addConditionOn( $maximumLength, Form::BLANK )
321 + ->addRule( Form::FILLED, $this->wpAdapter->__( 'You have to fill in Maximum length or Sum of dimensions', 'packeta' ) );
322 + }
323 +
219 324 $form->addHidden( 'id' )->setRequired();
220 325 $form->addSubmit( 'save' );
221 326
222 - if ( false === $carrier->hasPickupPoints() && in_array( $carrier->getCountry(), Carrier::ADDRESS_VALIDATION_COUNTRIES, true ) ) {
327 + if (
328 + $carrier->isCarDelivery() === false &&
329 + $carrier->hasPickupPoints() === false &&
330 + in_array( $carrier->getCountry(), Carrier::ADDRESS_VALIDATION_COUNTRIES, true )
331 + ) {
223 332 $addressValidationOptions = [
224 333 'none' => __( 'No address validation', 'packeta' ),
225 334 'optional' => __( 'Optional address validation', 'packeta' ),
226 335 'required' => __( 'Required address validation', 'packeta' ),
@@ -235,12 +344,18 @@
235 344 ->addRule( Form::FLOAT )
236 345 ->addRule( Form::MIN, null, 0 );
237 346 }
238 347
348 + $form->addMultiSelect(
349 + 'disallowed_checkout_payment_methods',
350 + __( 'Disallowed checkout payment methods', 'packeta' ),
351 + PaymentGatewayHelper::getAvailablePaymentGatewayChoices()
352 + )->checkDefaultValue( false );
353 +
239 354 $form->onValidate[] = [ $this, 'validateOptions' ];
240 355 $form->onSuccess[] = [ $this, 'updateOptions' ];
241 356
242 - if ( false === $carrierOptions ) {
357 + if ( $carrierOptions === false ) {
243 358 $carrierOptions = [
244 359 'id' => $carrierData['id'],
245 360 self::FORM_FIELD_NAME => $carrierData['name'],
246 361 ];
@@ -260,9 +375,25 @@
260 375 private function createCouponFreeShippingForFeesContainerId( Form $form ): string {
261 376 return sprintf( '%s_apply_free_shipping_coupon_allow_for_fees', $form->getName() );
262 377 }
263 378
379 + private function createDimensionRestrictionContainerId( Form $form ): string {
380 + return sprintf( '%s_dimension_restrictions', $form->getName() );
381 + }
382 +
264 383 /**
384 + * Creates container id for given field.
385 + *
386 + * @param Form $form Form.
387 + * @param string $field Field name.
388 + *
389 + * @return string
390 + */
391 + private function createFieldContainerId( Form $form, string $field ): string {
392 + return sprintf( '%s_%s_containerId', $form->getName(), $field );
393 + }
394 +
395 + /**
265 396 * Creates settings form.
266 397 *
267 398 * @param array $carrierData Carrier data.
268 399 *
@@ -272,11 +403,16 @@
272 403 $optionId = OptionPrefixer::getOptionId( $carrierData['id'] );
273 404
274 405 $form = $this->formFactory->create( $optionId . '_template' );
275 406
276 - $weightLimitsTemplate = $form->addContainer( 'weight_limits' );
407 + $form->addSelect( self::FORM_FIELD_PRICING_TYPE );
408 +
409 + $weightLimitsTemplate = $form->addContainer( self::FORM_FIELD_WEIGHT_LIMITS );
277 410 $this->addWeightLimit( $weightLimitsTemplate, 0 );
278 411
412 + $valueLimitsTemplate = $form->addContainer( self::FORM_FIELD_PRODUCT_VALUE_LIMITS );
413 + $this->addProductValueLimit( $valueLimitsTemplate, 0 );
414 +
279 415 $surchargeLimitsTemplate = $form->addContainer( 'surcharge_limits' );
280 416 $this->addSurchargeLimit( $surchargeLimitsTemplate, 0 );
281 417
282 418 return $form;
@@ -289,33 +425,45 @@
289 425 */
290 426 public function validateOptions( Form $form ): void {
291 427 if ( $form->hasErrors() ) {
292 428 add_settings_error( '', '', esc_attr( __( 'Some carrier data is invalid', 'packeta' ) ) );
429 +
293 430 return;
294 431 }
295 432
296 433 $options = $form->getValues( 'array' );
297 434
298 - if ( $this->featureFlag->isSplitActive() ) {
299 - $checkedVendors = $this->getCheckedVendors( $options );
300 - if (
301 - isset( $options['vendor_groups'] ) &&
302 - count( $options['vendor_groups'] ) >= self::MINIMUM_CHECKED_VENDORS &&
303 - count( $checkedVendors ) < self::MINIMUM_CHECKED_VENDORS
304 - ) {
305 - $vendorMessage = __( 'Check at least two types of pickup points or use a carrier which delivers to the desired pickup point type.', 'packeta' );
306 - add_settings_error( 'vendor_groups', 'vendor_groups', esc_attr( $vendorMessage ) );
307 - $form->addError( $vendorMessage );
308 - }
435 + $checkedVendors = $this->getCheckedVendors( $options );
436 + if (
437 + isset( $options['vendor_groups'] ) &&
438 + count( $options['vendor_groups'] ) >= self::MINIMUM_CHECKED_VENDORS &&
439 + count( $checkedVendors ) < self::MINIMUM_CHECKED_VENDORS
440 + ) {
441 + $vendorMessage = __( 'Check at least two types of pickup points or use a carrier which delivers to the desired pickup point type.', 'packeta' );
442 + add_settings_error( 'vendor_groups', 'vendor_groups', esc_attr( $vendorMessage ) );
443 + $form->addError( $vendorMessage );
309 444 }
310 445
311 - $this->checkOverlapping(
312 - $form,
313 - $options,
314 - 'weight_limits',
315 - 'weight',
316 - __( 'Weight rules are overlapping, please fix them.', 'packeta' )
317 - );
446 + if ( $options[ self::FORM_FIELD_PRICING_TYPE ] === Options::PRICING_TYPE_BY_WEIGHT ) {
447 + $this->checkOverlapping(
448 + $form,
449 + $options,
450 + self::FORM_FIELD_WEIGHT_LIMITS,
451 + 'weight',
452 + __( 'Weight rules are overlapping, please fix them.', 'packeta' )
453 + );
454 + }
455 +
456 + if ( $options[ self::FORM_FIELD_PRICING_TYPE ] === Options::PRICING_TYPE_BY_PRODUCT_VALUE ) {
457 + $this->checkOverlapping(
458 + $form,
459 + $options,
460 + self::FORM_FIELD_PRODUCT_VALUE_LIMITS,
461 + 'price',
462 + __( 'Product price rules are overlapping, please fix them.', 'packeta' )
463 + );
464 + }
465 +
318 466 if ( isset( $options['surcharge_limits'] ) ) {
319 467 $this->checkOverlapping(
320 468 $form,
321 469 $options,
@@ -335,14 +483,29 @@
335 483 */
336 484 public function updateOptions( Form $form ): void {
337 485 $options = $form->getValues( 'array' );
338 486 $newVendors = $this->getCheckedVendors( $options );
339 - if ( $newVendors ) {
487 + if ( count( $newVendors ) > 0 ) {
340 488 $options['vendor_groups'] = $newVendors;
341 489 }
342 490
343 - $options = $this->mergeNewLimits( $options, 'weight_limits' );
344 - $options = $this->sortLimits( $options, 'weight_limits', 'weight' );
491 + $persistedOptions = $this->carrierOptionsFactory->createByCarrierId( $options['id'] );
492 + $persistedOptionsArray = $persistedOptions->toArray();
493 +
494 + if ( $options[ self::FORM_FIELD_PRICING_TYPE ] === Options::PRICING_TYPE_BY_WEIGHT ) {
495 + $options = $this->mergeNewLimits( $options, self::FORM_FIELD_WEIGHT_LIMITS );
496 + $options = $this->sortLimits( $options, self::FORM_FIELD_WEIGHT_LIMITS, 'weight' );
497 +
498 + $options[ self::FORM_FIELD_PRODUCT_VALUE_LIMITS ] = $persistedOptionsArray[ self::FORM_FIELD_PRODUCT_VALUE_LIMITS ] ?? [];
499 + }
500 +
501 + if ( $options[ self::FORM_FIELD_PRICING_TYPE ] === Options::PRICING_TYPE_BY_PRODUCT_VALUE ) {
502 + $options = $this->mergeNewLimits( $options, self::FORM_FIELD_PRODUCT_VALUE_LIMITS );
503 + $options = $this->sortLimits( $options, self::FORM_FIELD_PRODUCT_VALUE_LIMITS, 'value' );
504 +
505 + $options[ self::FORM_FIELD_WEIGHT_LIMITS ] = $persistedOptionsArray[ self::FORM_FIELD_WEIGHT_LIMITS ] ?? [];
506 + }
507 +
345 508 if ( isset( $options['surcharge_limits'] ) ) {
346 509 $options = $this->mergeNewLimits( $options, 'surcharge_limits' );
347 510 $options = $this->sortLimits( $options, 'surcharge_limits', 'order_price' );
348 511 }
@@ -350,14 +513,11 @@
350 513 update_option( OptionPrefixer::getOptionId( $options['id'] ), $options );
351 514 $this->messageManager->flash_message( __( 'Settings saved', 'packeta' ), MessageManager::TYPE_SUCCESS, MessageManager::RENDERER_PACKETERY, 'carrier-country' );
352 515
353 516 if ( wp_safe_redirect(
354 - add_query_arg(
355 - [
356 - 'page' => self::SLUG,
357 - 'code' => $this->httpRequest->getQuery( 'code' ),
358 - ],
359 - get_admin_url( null, 'admin.php' )
517 + $this->createUrl(
518 + $this->httpRequest->getQuery( self::PARAMETER_COUNTRY_CODE ),
519 + $this->httpRequest->getQuery( self::PARAMETER_CARRIER_ID )
360 520 ),
361 521 303
362 522 ) ) {
363 523 exit;
@@ -364,76 +524,163 @@
364 524 }
365 525 }
366 526
367 527 /**
368 - * Renders page.
528 + * Gets carrier template params.
529 + *
530 + * @param Carrier|null $carrier Carrier.
531 + *
532 + * @return array|null
369 533 */
534 + private function getCarrierTemplateData( ?Carrier $carrier ): ?array {
535 + if ( $carrier === null ) {
536 + return null;
537 + }
538 +
539 + if ( $carrier->isCarDelivery() && $this->carDeliveryConfig->isDisabled() ) {
540 + return null;
541 + }
542 +
543 + $post = $this->httpRequest->getPost();
544 + if ( isset( $post['id'] ) && $post['id'] === $carrier->getId() ) {
545 + $formTemplate = $this->createFormTemplate( $post );
546 + $form = $this->createForm( $post );
547 + if ( $form->isSubmitted() ) {
548 + $form->fireEvents();
549 + }
550 + } else {
551 + $carrierData = $carrier->__toArray();
552 + $options = get_option( OptionPrefixer::getOptionId( $carrier->getId() ) );
553 + if ( $options !== false ) {
554 + $carrierData += $options;
555 + }
556 + $formTemplate = $this->createFormTemplate( $carrierData );
557 + $form = $this->createForm( $carrierData );
558 + }
559 +
560 + return [
561 + 'form' => $form,
562 + 'formTemplate' => $formTemplate,
563 + 'carrier' => $carrier,
564 + 'couponFreeShippingForFeesContainerId' => $this->createCouponFreeShippingForFeesContainerId( $form ),
565 + 'dimensionRestrictionContainerId' => $this->createDimensionRestrictionContainerId( $form ),
566 + 'weightLimitsContainerId' => $this->createFieldContainerId( $form, self::FORM_FIELD_WEIGHT_LIMITS ),
567 + 'productValueLimitsContainerId' => $this->createFieldContainerId( $form, self::FORM_FIELD_PRODUCT_VALUE_LIMITS ),
568 + 'isAvailableVendorsCountLow' => $this->isAvailableVendorsCountLowByCarrierId( $carrier->getId() ),
569 + ];
570 + }
571 +
370 572 public function render(): void {
371 - $countryIso = $this->httpRequest->getQuery( 'code' );
372 - if ( $countryIso ) {
373 - $countryCarriers = $this->carrierRepository->getByCountryIncludingNonFeed( $countryIso );
374 - $carriersData = [];
375 - $post = $this->httpRequest->getPost();
376 - foreach ( $countryCarriers as $carrier ) {
377 - if ( ! empty( $post ) && $post['id'] === $carrier->getId() ) {
378 - $formTemplate = $this->createFormTemplate( $post );
379 - $form = $this->createForm( $post );
380 - if ( $form->isSubmitted() ) {
381 - $form->fireEvents();
382 - }
383 - } else {
384 - $carrierData = $carrier->__toArray();
385 - $options = get_option( OptionPrefixer::getOptionId( $carrier->getId() ) );
386 - if ( false !== $options ) {
387 - $carrierData += $options;
388 - }
389 - $formTemplate = $this->createFormTemplate( $carrierData );
390 - $form = $this->createForm( $carrierData );
391 - }
573 + $countryIso = $this->httpRequest->getQuery( self::PARAMETER_COUNTRY_CODE );
574 + $carrierId = $this->httpRequest->getQuery( self::PARAMETER_CARRIER_ID );
392 575
393 - $carriersData[] = [
394 - 'form' => $form,
395 - 'formTemplate' => $formTemplate,
396 - 'carrier' => $carrier,
397 - 'couponFreeShippingForFeesContainerId' => $this->createCouponFreeShippingForFeesContainerId( $form ),
398 - ];
576 + if ( $carrierId !== null ) {
577 + $this->renderCarrierDetail( $carrierId );
578 + } elseif ( $countryIso !== null ) {
579 + $this->renderCountryCarriers( $countryIso );
580 + } else {
581 + $this->countryListingPage->render();
582 + }
583 + }
584 +
585 + private function renderCarrierDetail( string $carrierId ): void {
586 + $carrier = $this->carrierRepository->getAnyById( $carrierId );
587 + $carrierTemplateData = $this->getCarrierTemplateData( $carrier );
588 +
589 + if ( $carrier === null || $carrierTemplateData === null ) {
590 + $this->countryListingPage->render();
591 +
592 + return;
593 + }
594 +
595 + $this->latteEngine->render(
596 + PACKETERY_PLUGIN_DIR . '/template/carrier/detail.latte',
597 + array_merge_recursive(
598 + $this->getCommonTemplateParams(),
599 + [
600 + 'carrierTemplateData' => $carrierTemplateData,
601 + 'translations' => [
602 + 'title' => $carrier->getName(),
603 + ],
604 + ]
605 + )
606 + );
607 + }
608 +
609 + private function renderCountryCarriers( string $countryIso ): void {
610 + $countryCarriers = $this->carrierRepository->getByCountryIncludingNonFeed( $countryIso, true );
611 + $carriersData = [];
612 + foreach ( $countryCarriers as $carrier ) {
613 + $carrierTemplateData = $this->getCarrierTemplateData( $carrier );
614 + if ( $carrierTemplateData !== null ) {
615 + $carriersData[] = $carrierTemplateData;
399 616 }
617 + }
400 618
401 - $this->latteEngine->render(
402 - PACKETERY_PLUGIN_DIR . '/template/carrier/country.latte',
619 + $this->latteEngine->render(
620 + PACKETERY_PLUGIN_DIR . '/template/carrier/country.latte',
621 + array_merge_recursive(
622 + $this->getCommonTemplateParams(),
403 623 [
404 - 'forms' => $carriersData,
405 - 'country_iso' => $countryIso,
406 - 'globalCurrency' => get_woocommerce_currency_symbol(),
407 - 'flashMessages' => $this->messageManager->renderToString( MessageManager::RENDERER_PACKETERY, 'carrier-country' ),
408 - 'translations' => [
409 - 'cannotUseThisCarrierBecauseRequiresCustomsDeclaration' => __( 'This carrier cannot be used, because it requires a customs declaration.', 'packeta' ),
410 - 'delete' => __( 'Delete', 'packeta' ),
411 - 'weightRules' => __( 'Weight rules', 'packeta' ),
412 - 'addWeightRule' => __( 'Add weight rule', 'packeta' ),
413 - 'codSurchargeRules' => __( 'COD surcharge rules', 'packeta' ),
414 - 'addCodSurchargeRule' => __( 'Add COD surcharge rule', 'packeta' ),
415 - 'afterExceedingThisAmountShippingIsFree' => __( 'After exceeding this amount, shipping is free.', 'packeta' ),
416 - 'addressValidationDescription' => __( 'Customer address validation.', 'packeta' ),
417 - 'roundingDescription' => __( 'COD rounding for submitting data to Packeta', 'packeta' ),
418 - 'saveChanges' => __( 'Save changes', 'packeta' ),
419 - 'packeta' => __( 'Packeta', 'packeta' ),
420 - // translators: %s is country code.
421 - 'title' => sprintf( __( 'Country options: %s', 'packeta' ), strtoupper( $countryIso ) ),
422 - 'noKnownCarrierForThisCountry' => __( 'No carriers available for this country.', 'packeta' ),
423 - 'ageVerificationSupportedNotification' => __( 'When shipping via this carrier, you can order the Age Verification service. The service will get ordered automatically if there is at least 1 product in the order with the age verification setting.', 'packeta' ),
424 - 'carrierDoesNotSupportCod' => __( 'This carrier does not support COD payment.', 'packeta' ),
425 - 'allowedPickupPointTypes' => __( 'Pickup point types.', 'packeta' ),
426 - 'checkAtLeastTwo' => __( 'Check at least two types of pickup points or use a carrier which delivers to the desired pickup point type.', 'packeta' ),
624 + 'forms' => $carriersData,
625 + 'country_iso' => $countryIso,
626 + 'translations' => [
627 + 'title' => sprintf(
628 + // translators: %s is country code.
629 + $this->wpAdapter->__( 'Country options: %s', 'packeta' ),
630 + strtoupper( $countryIso )
631 + ),
427 632 ],
428 633 ]
429 - );
430 - } else {
431 - $this->countryListingPage->render();
432 - }
634 + )
635 + );
433 636 }
434 637
435 638 /**
639 + * @return array<string, null|string|bool|array<string, string>>
640 + */
641 + private function getCommonTemplateParams(): array {
642 + return [
643 + 'globalCurrency' => get_woocommerce_currency_symbol(),
644 + 'flashMessages' => $this->messageManager->renderToString( MessageManager::RENDERER_PACKETERY, 'carrier-country' ),
645 + 'isCzechLocale' => $this->moduleHelper->isCzechLocale(),
646 + 'logoZasilkovna' => $this->urlBuilder->buildAssetUrl( 'public/images/logo-zasilkovna.svg' ),
647 + 'logoPacketa' => $this->urlBuilder->buildAssetUrl( 'public/images/logo-packeta.svg' ),
648 + 'translations' => $this->getTranslations(),
649 + ];
650 + }
651 +
652 + /**
653 + * @return array<string, string>
654 + */
655 + private function getTranslations(): array {
656 + return [
657 + 'cannotUseThisCarrierBecauseRequiresCustomsDeclaration' => $this->wpAdapter->__( 'This carrier cannot be used, because it requires a customs declaration.', 'packeta' ),
658 + 'delete' => $this->wpAdapter->__( 'Delete', 'packeta' ),
659 + 'weightRules' => $this->wpAdapter->__( 'Weight rules', 'packeta' ),
660 + 'productValueRules' => $this->wpAdapter->__( 'Product value rules', 'packeta' ),
661 + 'addWeightRule' => $this->wpAdapter->__( 'Add weight rule', 'packeta' ),
662 + 'addProductValueRule' => $this->wpAdapter->__( 'Add product value rule', 'packeta' ),
663 + 'codSurchargeRules' => $this->wpAdapter->__( 'COD surcharge rules', 'packeta' ),
664 + 'addCodSurchargeRule' => $this->wpAdapter->__( 'Add COD surcharge rule', 'packeta' ),
665 + 'afterExceedingThisAmountShippingIsFree' => $this->wpAdapter->__( 'After exceeding this amount, shipping is free.', 'packeta' ),
666 + 'daysUntilShipping' => $this->wpAdapter->__( 'Number of business days it might take to process an order before shipping out a package.', 'packeta' ),
667 + 'shippingTimeCutOff' => $this->wpAdapter->__( 'A time of a day you stop taking in more orders for the next round of shipping.', 'packeta' ),
668 + 'addressValidationDescription' => $this->wpAdapter->__( 'Customer address validation.', 'packeta' ),
669 + 'roundingDescription' => $this->wpAdapter->__( 'COD rounding for submitting data to Packeta', 'packeta' ),
670 + 'saveChanges' => $this->wpAdapter->__( 'Save changes', 'packeta' ),
671 + 'packeta' => $this->wpAdapter->__( 'Packeta', 'packeta' ),
672 + 'noKnownCarrierForThisCountry' => $this->wpAdapter->__( 'No carriers available for this country.', 'packeta' ),
673 + 'ageVerificationSupportedNotification' => $this->wpAdapter->__( 'When shipping via this carrier, you can order the Age Verification service. The service will get ordered automatically if there is at least 1 product in the order with the age verification setting.', 'packeta' ),
674 + 'carrierDoesNotSupportCod' => $this->wpAdapter->__( 'This carrier does not support COD payment.', 'packeta' ),
675 + 'allowedPickupPointTypes' => $this->wpAdapter->__( 'Pickup point types', 'packeta' ),
676 + 'checkAtLeastTwo' => $this->wpAdapter->__( 'Check at least two types of pickup points or use a carrier which delivers to the desired pickup point type.', 'packeta' ),
677 + 'lowAvailableVendorsCount' => $this->wpAdapter->__( 'This carrier displays all types of pickup points at the same time in the checkout (retail store pickup points, Z-boxes).', 'packeta' ),
678 + 'carrierUnavailable' => $this->wpAdapter->__( 'This carrier is unavailable.', 'packeta' ),
679 + ];
680 + }
681 +
682 + /**
436 683 * Transforms new_ keys to common numeric.
437 684 *
438 685 * @param array $options Options to merge.
439 686 * @param string $limitsContainer Container id.
@@ -446,9 +693,9 @@
446 693 foreach ( $options[ $limitsContainer ] as $key => $option ) {
447 694 if ( is_int( $key ) ) {
448 695 $newOptions[ $key ] = $option;
449 696 }
450 - if ( 0 === strpos( (string) $key, 'new_' ) ) {
697 + if ( strpos( (string) $key, 'new_' ) === 0 ) {
451 698 $newOptions[] = $option;
452 699 }
453 700 }
454 701 $options[ $limitsContainer ] = $newOptions;
@@ -492,35 +739,98 @@
492 739 return $options;
493 740 }
494 741
495 742 /**
496 - * Adds limit fields to form.
743 + * @param Container $weightLimits
744 + * @param int|string $index
497 745 *
498 - * @param Container $weightLimits Container.
499 - * @param int|string $index Index.
500 - *
501 - * @return void
746 + * @throws \RuntimeException
502 747 */
503 748 private function addWeightLimit( Container $weightLimits, $index ): void {
504 - $limit = $weightLimits->addContainer( (string) $index );
505 - $item = $limit->addText( 'weight', __( 'Weight up to', 'packeta' ) . ':' );
506 - $item->setRequired();
507 - $item->addRule( Form::FLOAT, __( 'Please enter a valid decimal number.', 'packeta' ) );
749 + $form = $weightLimits->getForm();
750 + if ( $form === null ) {
751 + throw new \RuntimeException( 'Form is not attached to the container.' );
752 + }
753 +
754 + $pricingTypeComponent = $form->getComponent( self::FORM_FIELD_PRICING_TYPE, false );
755 +
756 + if ( ! $pricingTypeComponent instanceof Control ) {
757 + throw new \RuntimeException(
758 + sprintf(
759 + 'Component "%s" must be an instance of %s, %s given.',
760 + self::FORM_FIELD_PRICING_TYPE,
761 + Control::class,
762 + is_object( $pricingTypeComponent ) ? get_class( $pricingTypeComponent ) : gettype( $pricingTypeComponent )
763 + )
764 + );
765 + }
766 +
767 + $limit = $weightLimits->addContainer( (string) $index );
768 + $weightField = $limit->addText( 'weight', __( 'Weight up to', 'packeta' ) . ':' );
769 + $weightRules = $weightField->addConditionOn( $pricingTypeComponent, Form::EQUAL, Options::PRICING_TYPE_BY_WEIGHT );
770 + $weightRules->setRequired();
771 + $weightRules->addRule( Form::FLOAT, __( 'Please enter a valid decimal number.', 'packeta' ) );
772 + $weightRules->addRule( Form::MIN, null, 0 );
508 773 // translators: %d is numeric threshold.
509 - $item->addRule( [ FormValidators::class, 'greaterThan' ], __( 'Enter number greater than %d', 'packeta' ), 0.0 );
774 + $weightRules->addRule( [ FormValidators::class, 'greaterThan' ], __( 'Enter number greater than %d', 'packeta' ), 0.0 );
510 775
511 - $item->addFilter(
776 + $weightRules->addFilter(
512 777 function ( float $value ) {
513 - return Helper::simplifyWeight( $value );
778 + return CoreHelper::simplifyWeight( $value );
514 779 }
515 780 );
781 +
782 + $priceField = $limit->addText( 'price', __( 'Price', 'packeta' ) . ':' );
783 + $priceRules = $priceField->addConditionOn( $pricingTypeComponent, Form::EQUAL, Options::PRICING_TYPE_BY_WEIGHT );
784 + $priceRules->setRequired();
785 + $priceRules->addRule( Form::FLOAT, __( 'Please enter a valid decimal number.', 'packeta' ) );
786 + $priceRules->addRule( Form::MIN, null, 0 );
516 787 // translators: %d is numeric threshold.
517 - $item->addRule( [ FormValidators::class, 'greaterThan' ], __( 'Enter number greater than %d', 'packeta' ), 0.0 );
788 + $weightRules->addRule( [ FormValidators::class, 'greaterThan' ], __( 'Enter number greater than %d', 'packeta' ), 0.0 );
789 + }
518 790
519 - $item = $limit->addText( 'price', __( 'Price', 'packeta' ) . ':' );
520 - $item->setRequired();
521 - $item->addRule( Form::FLOAT, __( 'Please enter a valid decimal number.', 'packeta' ) );
522 - $item->addRule( Form::MIN, null, 0 );
791 + /**
792 + * @param Container $productValueLimits
793 + * @param int|string $index
794 + *
795 + * @throws \RuntimeException
796 + */
797 + private function addProductValueLimit( Container $productValueLimits, $index ): void {
798 + $form = $productValueLimits->getForm();
799 + if ( $form === null ) {
800 + throw new \RuntimeException( 'Form is not attached to the container.' );
801 + }
802 +
803 + $pricingTypeComponent = $form->getComponent( self::FORM_FIELD_PRICING_TYPE, false );
804 +
805 + if ( ! $pricingTypeComponent instanceof Control ) {
806 + throw new \RuntimeException(
807 + sprintf(
808 + 'Component "%s" must be an instance of %s, %s given.',
809 + self::FORM_FIELD_PRICING_TYPE,
810 + Control::class,
811 + is_object( $pricingTypeComponent ) ? get_class( $pricingTypeComponent ) : gettype( $pricingTypeComponent )
812 + )
813 + );
814 + }
815 +
816 + $limit = $productValueLimits->addContainer( $index );
817 +
818 + $valueField = $limit->addText( 'value', __( 'Product value up to', 'packeta' ) . ':' );
819 + $valueRules = $valueField->addConditionOn( $pricingTypeComponent, Form::EQUAL, Options::PRICING_TYPE_BY_PRODUCT_VALUE );
820 + $valueRules->setRequired();
821 + $valueRules->addRule( Form::FLOAT, __( 'Please enter a valid decimal number.', 'packeta' ) );
822 + // translators: %d is numeric threshold.
823 + $valueRules->addRule( Form::MIN, null, 0.0 );
824 + // translators: %d is numeric threshold.
825 + $valueRules->addRule( [ FormValidators::class, 'greaterThan' ], __( 'Enter number greater than %d', 'packeta' ), 0.0 );
826 +
827 + $priceField = $limit->addText( 'price', __( 'Price', 'packeta' ) . ':' );
828 + $priceRules = $priceField->addConditionOn( $pricingTypeComponent, Form::EQUAL, Options::PRICING_TYPE_BY_PRODUCT_VALUE );
829 + $priceRules->setRequired();
830 + $priceRules->addRule( Form::FLOAT, __( 'Please enter a valid decimal number.', 'packeta' ) );
831 + // translators: %d is numeric threshold.
832 + $priceRules->addRule( Form::MIN, null, 0.0 );
523 833 }
524 834
525 835 /**
526 836 * Adds limit fields to form.
@@ -550,20 +860,25 @@
550 860 /**
551 861 * Creates link to page.
552 862 *
553 863 * @param string|null $countryCode Country code.
864 + * @param string|null $carrierId Carrier ID.
554 865 *
555 866 * @return string
556 867 */
557 - public function createUrl( ?string $countryCode = null ): string {
868 + public function createUrl( ?string $countryCode = null, ?string $carrierId = null ): string {
558 869 $params = [
559 870 'page' => self::SLUG,
560 871 ];
561 872
562 - if ( null !== $countryCode ) {
563 - $params['code'] = $countryCode;
873 + if ( $countryCode !== null ) {
874 + $params[ self::PARAMETER_COUNTRY_CODE ] = $countryCode;
564 875 }
565 876
877 + if ( $carrierId !== null ) {
878 + $params[ self::PARAMETER_CARRIER_ID ] = $carrierId;
879 + }
880 +
566 881 return add_query_arg(
567 882 $params,
568 883 admin_url( 'admin.php' )
569 884 );
@@ -577,9 +892,9 @@
577 892 * @return array
578 893 */
579 894 private function getCheckedVendors( array $options ): array {
580 895 $vendorCodes = [];
581 - if ( ! empty( $options['vendor_groups'] ) ) {
896 + if ( isset( $options['vendor_groups'] ) ) {
582 897 $vendorCodes = $options['vendor_groups'];
583 898 }
584 899
585 900 $newVendors = [];
@@ -624,9 +939,9 @@
624 939 * @return array
625 940 */
626 941 private function getVendorCheckboxesConfig( string $carrierId, ?array $carrierOptions ): array {
627 942 $availableVendors = $this->getAvailableVendors( $carrierId );
628 - if ( null === $availableVendors ) {
943 + if ( $availableVendors === null || $this->isAvailableVendorsCountLowerThanRequiredMinimum( $availableVendors ) ) {
629 944 return [];
630 945 }
631 946
632 947 $vendorCheckboxes = [];
@@ -631,25 +946,21 @@
631 946
632 947 $vendorCheckboxes = [];
633 948 $vendorCarriers = $this->pickupPointsConfig->getVendorCarriers();
634 949 foreach ( $availableVendors as $vendorId ) {
635 - $vendorProvider = $vendorCarriers[ $vendorId ];
636 - $checkbox = [
950 + $vendorProvider = $vendorCarriers[ $vendorId ];
951 + $checkbox = [
637 952 'group' => $vendorProvider->getGroup(),
638 953 'name' => $vendorProvider->getName(),
639 954 'disabled' => null,
640 955 'default' => null,
641 956 ];
642 - $hasLowCountAvailable = count( $availableVendors ) <= self::MINIMUM_CHECKED_VENDORS;
643 - if ( $hasLowCountAvailable ) {
644 - $checkbox['disabled'] = true;
645 - }
646 957 $hasGroupSettingsSaved = isset( $carrierOptions['vendor_groups'] );
647 958 $hasTheGroupAllowed = (
648 959 $hasGroupSettingsSaved &&
649 960 in_array( $vendorProvider->getGroup(), $carrierOptions['vendor_groups'], true )
650 961 );
651 - if ( ! $hasGroupSettingsSaved || $hasLowCountAvailable || $hasTheGroupAllowed ) {
962 + if ( ! $hasGroupSettingsSaved || $hasTheGroupAllowed ) {
652 963 $checkbox['default'] = true;
653 964 }
654 965 $vendorCheckboxes[] = $checkbox;
655 966 }
@@ -656,5 +967,28 @@
656 967
657 968 return $vendorCheckboxes;
658 969 }
659 970
971 + /**
972 + * Check if the number of vendors is lower than the required minimum
973 + *
974 + * @param array $availableVendors Available vendors.
975 + *
976 + * @return bool
977 + */
978 + public function isAvailableVendorsCountLowerThanRequiredMinimum( array $availableVendors ): bool {
979 + return count( $availableVendors ) <= self::MINIMUM_CHECKED_VENDORS;
980 + }
981 +
982 + /**
983 + * Checks if the number of vendors is lower than the minimum required by the carrier id
984 + *
985 + * @param string $carrierId Carrier id.
986 + *
987 + * @return bool
988 + */
989 + public function isAvailableVendorsCountLowByCarrierId( string $carrierId ): bool {
990 + $availableVendors = $this->getAvailableVendors( $carrierId );
991 +
992 + return is_array( $availableVendors ) && $this->isAvailableVendorsCountLowerThanRequiredMinimum( $availableVendors );
993 + }
660 994 }