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

CheckoutValidator.php in Packeta trunk, at src/Packetery/Module/Checkout/CheckoutValidator.php

302 lines 8.9 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2
3 declare( strict_types=1 );
4
5 namespace Packetery\Module\Checkout;
6
7 use Packetery\Core\Api\Rest\PickupPointValidateRequest;
8 use Packetery\Core\Entity;
9 use Packetery\Module\Carrier;
10 use Packetery\Module\Carrier\CarrierOptionsFactory;
11 use Packetery\Module\Carrier\EntityRepository;
12 use Packetery\Module\Exception\ProductNotFoundException;
13 use Packetery\Module\Framework\WcAdapter;
14 use Packetery\Module\Framework\WpAdapter;
15 use Packetery\Module\Options\OptionsProvider;
16 use Packetery\Module\Order;
17 use Packetery\Module\Order\PickupPointValidator;
18 use Packetery\Module\Payment\PaymentHelper;
19 use WC_REST_Exception;
20 use WP_Error;
21
22 class CheckoutValidator {
23
24 /**
25 * @var WpAdapter
26 */
27 private $wpAdapter;
28
29 /**
30 * @var WcAdapter
31 */
32 private $wcAdapter;
33
34 /**
35 * @var CheckoutService
36 */
37 private $checkoutService;
38
39 /**
40 * @var CartService
41 */
42 private $cartService;
43
44 /**
45 * @var SessionService
46 */
47 private $sessionService;
48
49 /**
50 * @var CheckoutStorage
51 */
52 private $storage;
53
54 /**
55 * @var CarrierOptionsFactory
56 */
57 private $carrierOptionsFactory;
58
59 /**
60 * @var EntityRepository
61 */
62 private $carrierEntityRepository;
63
64 /** @var OptionsProvider */
65 private $optionsProvider;
66
67 /** @var PickupPointValidator */
68 private $pickupPointValidator;
69
70 /** @var PaymentHelper */
71 private $paymentHelper;
72
73 /** @var Carrier\PacketaPickupPointsConfig */
74 private $pickupPointsConfig;
75
76 public function __construct(
77 WpAdapter $wpAdapter,
78 WcAdapter $wcAdapter,
79 CheckoutService $checkoutService,
80 CartService $cartService,
81 SessionService $sessionService,
82 CheckoutStorage $storage,
83 CarrierOptionsFactory $carrierOptionsFactory,
84 EntityRepository $carrierEntityRepository,
85 OptionsProvider $optionsProvider,
86 PickupPointValidator $pickupPointValidator,
87 PaymentHelper $paymentHelper,
88 Carrier\PacketaPickupPointsConfig $packetaPickupPointsConfig
89 ) {
90 $this->wpAdapter = $wpAdapter;
91 $this->wcAdapter = $wcAdapter;
92 $this->checkoutService = $checkoutService;
93 $this->cartService = $cartService;
94 $this->sessionService = $sessionService;
95 $this->storage = $storage;
96 $this->carrierOptionsFactory = $carrierOptionsFactory;
97 $this->carrierEntityRepository = $carrierEntityRepository;
98 $this->optionsProvider = $optionsProvider;
99 $this->pickupPointValidator = $pickupPointValidator;
100 $this->paymentHelper = $paymentHelper;
101 $this->pickupPointsConfig = $packetaPickupPointsConfig;
102 }
103
104 /**
105 * Using wc_add_notice is not safe because it can be cleared by other plugins.
106 *
107 * @param array<string, string|int|string[]|bool> $data
108 * @param WP_Error $wpError
109 *
110 * @throws ProductNotFoundException
111 */
112 public function actionValidateCheckoutData( array $data, WP_Error $wpError ): void {
113 $error = $this->getFirstError();
114 if ( $error !== null ) {
115 $wpError->add( 'packeta_cart_validation_failed', $error );
116 }
117 }
118
119 /**
120 * Using wc_add_notice works even for block checkout, but WC_REST_Exception is recommended.
121 *
122 * @throws WC_REST_Exception
123 * @throws ProductNotFoundException
124 */
125 public function actionValidateBlockCheckoutData(): void {
126 $error = $this->getFirstError();
127 if ( $error !== null ) {
128 throw new WC_REST_Exception( 'packeta_cart_validation_failed', $error );
129 }
130 }
131
132 /**
133 * @throws ProductNotFoundException
134 */
135 private function getFirstError(): ?string {
136 $chosenShippingMethod = $this->checkoutService->resolveChosenMethod();
137 $this->wcAdapter->sessionSet( PickupPointValidator::VALIDATION_HTTP_ERROR_SESSION_KEY, null );
138
139 if (
140 $chosenShippingMethod === null ||
141 $this->checkoutService->isPacketeryShippingMethod( $chosenShippingMethod ) === false
142 ) {
143 return null;
144 }
145
146 $checkoutData = $this->storage->getPostDataIncludingStoredData( $chosenShippingMethod );
147
148 if ( $this->cartService->isShippingRateRestrictedByProductsCategory( $chosenShippingMethod, $this->wcAdapter->cartGetCartContents() ) ) {
149 return $this->wpAdapter->__( 'Chosen delivery method is no longer available. Please choose another delivery method.', 'packeta' );
150 }
151
152 $carrierId = $this->checkoutService->getCarrierIdFromPacketeryShippingMethod( $chosenShippingMethod );
153 $carrierOptions = $this->carrierOptionsFactory->createByCarrierId( $carrierId );
154 $paymentMethod = $this->sessionService->getChosenPaymentMethod();
155
156 if ( $paymentMethod !== null && $carrierOptions->hasCheckoutPaymentMethodDisallowed( $paymentMethod ) ) {
157 return $this->wpAdapter->__( 'Chosen delivery method is no longer available. Please choose another delivery method.', 'packeta' );
158 }
159
160 if ( $this->checkoutService->isPickupPointOrder() ) {
161 return $this->validatePickupPoint(
162 $checkoutData,
163 $carrierId,
164 $paymentMethod,
165 $this->pickupPointsConfig->getFinalVendorGroups( $carrierOptions->getVendorGroups(), $carrierId )
166 );
167 }
168
169 if ( $this->checkoutService->isHomeDeliveryOrder() ) {
170 return $this->validateHomeDelivery( $checkoutData, $carrierId );
171 }
172
173 if (
174 ( ! isset( $checkoutData[ Order\Attribute::CAR_DELIVERY_ID ] ) || $checkoutData[ Order\Attribute::CAR_DELIVERY_ID ] === '' ) &&
175 $this->checkoutService->isCarDeliveryOrder()
176 ) {
177 return $this->wpAdapter->__( 'Delivery address has not been verified. Verification of delivery address is required by this carrier.', 'packeta' );
178 }
179
180 return null;
181 }
182
183 /**
184 * @param array $checkoutData
185 * @param string|null $carrierId
186 * @param string|null $paymentMethod
187 * @param string[]|null $vendorGroups
188 *
189 * @return string|null
190 * @throws ProductNotFoundException
191 */
192 private function validatePickupPoint(
193 array $checkoutData,
194 ?string $carrierId,
195 ?string $paymentMethod,
196 ?array $vendorGroups
197 ): ?string {
198 $requiredAttributes = array_filter(
199 array_combine(
200 array_column( Order\Attribute::$pickupPointAttributes, 'name' ),
201 array_column( Order\Attribute::$pickupPointAttributes, 'required' )
202 )
203 );
204 foreach ( $requiredAttributes as $attr => $required ) {
205 $attrValue = $checkoutData[ $attr ] ?? null;
206 if ( ! $attrValue ) {
207 return $this->wpAdapter->__( 'Pickup point is not chosen.', 'packeta' );
208 }
209 }
210
211 $customerCountry = $this->checkoutService->getCustomerCountry();
212 if ( $customerCountry === null ) {
213 return $this->wpAdapter->__( 'Customer country could not be obtained.', 'packeta' );
214 }
215
216 if (
217 ! $this->carrierEntityRepository->isValidForCountry(
218 $carrierId,
219 $customerCountry
220 )
221 ) {
222 return $this->wpAdapter->__( 'The selected Packeta carrier is not available for the selected delivery country.', 'packeta' );
223 }
224
225 if ( $this->optionsProvider->isPickupPointValidationEnabled() ) {
226 $pickupPointId = $checkoutData[ Order\Attribute::POINT_ID ];
227 if ( $carrierId === '' ) {
228 $carrierId = Entity\Carrier::INTERNAL_PICKUP_POINTS_ID;
229 }
230 $pickupPointValidationResponse = $this->pickupPointValidator->validate(
231 $this->createPickupPointValidateRequest(
232 $pickupPointId,
233 $carrierId,
234 ( is_numeric( $carrierId ) ? $pickupPointId : null ),
235 $paymentMethod,
236 $vendorGroups
237 )
238 );
239 if ( ! $pickupPointValidationResponse->isValid() ) {
240 return $this->wpAdapter->__( 'The selected Packeta pickup point could not be validated. Please select another.', 'packeta' );
241 }
242 }
243
244 return null;
245 }
246
247 /**
248 * @param string $pickupPointId
249 * @param string|null $carrierId
250 * @param string|null $pointCarrierId
251 * @param string|null $paymentMethod
252 * @param string[]|null $vendorGroups
253 *
254 * @return PickupPointValidateRequest
255 * @throws ProductNotFoundException
256 */
257 private function createPickupPointValidateRequest(
258 string $pickupPointId,
259 ?string $carrierId,
260 ?string $pointCarrierId,
261 ?string $paymentMethod,
262 ?array $vendorGroups
263 ): PickupPointValidateRequest {
264 return new PickupPointValidateRequest(
265 $pickupPointId,
266 $carrierId,
267 $pointCarrierId,
268 $this->checkoutService->getCustomerCountry(),
269 null,
270 null,
271 $this->cartService->getCartWeightKg(),
272 $this->cartService->isAgeVerificationRequired(),
273 null,
274 ( $paymentMethod !== null && $this->paymentHelper->isCodPaymentMethod( $paymentMethod ) === true ),
275 $this->cartService->getBiggestProductSize(),
276 $vendorGroups
277 );
278 }
279
280 private function validateHomeDelivery( array $checkoutData, ?string $carrierId ): ?string {
281 $optionId = Carrier\OptionPrefixer::getOptionId( $carrierId );
282 $carrierOption = $this->wpAdapter->getOption( $optionId );
283
284 $addressValidation = 'none';
285 if ( $carrierOption !== false ) {
286 $addressValidation = ( $carrierOption['address_validation'] ?? $addressValidation );
287 }
288
289 if (
290 $addressValidation === 'required' &&
291 (
292 ! isset( $checkoutData[ Order\Attribute::ADDRESS_IS_VALIDATED ] ) ||
293 $checkoutData[ Order\Attribute::ADDRESS_IS_VALIDATED ] !== '1'
294 )
295 ) {
296 return $this->wpAdapter->__( 'Delivery address has not been verified. Verification of delivery address is required by this carrier.', 'packeta' );
297 }
298
299 return null;
300 }
301 }
302