| @@ -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 | } |