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 / ShippingRateFactory.php

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

274 lines 8.2 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\Entity;
8 use Packetery\Module\Carrier;
9 use Packetery\Module\Carrier\CarDeliveryConfig;
10 use Packetery\Module\Carrier\CarrierOptionsFactory;
11 use Packetery\Module\DiagnosticsLogger\DiagnosticsLogger;
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\Shipping\BaseShippingMethod;
17 use Packetery\Module\ShippingMethod;
18
19 class ShippingRateFactory {
20
21 /**
22 * @var WpAdapter
23 */
24 private $wpAdapter;
25
26 /**
27 * @var WcAdapter
28 */
29 private $wcAdapter;
30
31 /**
32 * @var CheckoutService
33 */
34 private $checkoutService;
35
36 /**
37 * @var Carrier\EntityRepository
38 */
39 private $carrierEntityRepository;
40
41 /**
42 * @var CartService
43 */
44 private $cartService;
45
46 /**
47 * @var CarrierOptionsFactory
48 */
49 private $carrierOptionsFactory;
50
51 /**
52 * @var CarDeliveryConfig
53 */
54 private $carDeliveryConfig;
55
56 /**
57 * @var RateCalculator
58 */
59 private $rateCalculator;
60
61 /**
62 * @var OptionsProvider
63 */
64 private $optionsProvider;
65
66 /**
67 * @var DiagnosticsLogger
68 */
69 private $diagnosticsLogger;
70
71 public function __construct(
72 WpAdapter $wpAdapter,
73 WcAdapter $wcAdapter,
74 CheckoutService $checkoutService,
75 Carrier\EntityRepository $carrierEntityRepository,
76 CartService $cartService,
77 CarrierOptionsFactory $carrierOptionsFactory,
78 CarDeliveryConfig $carDeliveryConfig,
79 RateCalculator $rateCalculator,
80 OptionsProvider $optionsProvider,
81 DiagnosticsLogger $diagnosticsLogger
82 ) {
83 $this->wpAdapter = $wpAdapter;
84 $this->wcAdapter = $wcAdapter;
85 $this->checkoutService = $checkoutService;
86 $this->carrierEntityRepository = $carrierEntityRepository;
87 $this->cartService = $cartService;
88 $this->carrierOptionsFactory = $carrierOptionsFactory;
89 $this->carDeliveryConfig = $carDeliveryConfig;
90 $this->rateCalculator = $rateCalculator;
91 $this->optionsProvider = $optionsProvider;
92 $this->diagnosticsLogger = $diagnosticsLogger;
93 }
94
95 /**
96 * Prepare shipping rates based on cart properties.
97 *
98 * @param array|null $allowedCarrierNames List of allowed carrier names.
99 * @param string $methodId Shipping method class id.
100 * @param int $instanceId Shipping method instance id.
101 *
102 * @return array<string, array<string, string|float|array>>
103 * @throws ProductNotFoundException Product not found.
104 */
105 public function createShippingRates( ?array $allowedCarrierNames, string $methodId, int $instanceId ): array {
106 $customerCountry = $this->checkoutService->getCustomerCountry();
107 $this->diagnosticsLogger->log(
108 'createShippingRates parameters',
109 [
110 'customerCountry' => $customerCountry,
111 'allowedCarrierNames' => $allowedCarrierNames,
112 'methodId' => $methodId,
113 'instanceId' => $instanceId,
114 ]
115 );
116 if ( $customerCountry === null ) {
117 return [];
118 }
119
120 $rateId = null;
121 if ( $methodId === ShippingMethod::PACKETERY_METHOD_ID ) {
122 $availableCarriers = $this->carrierEntityRepository->getByCountryIncludingNonFeed( $customerCountry, false );
123 } else {
124 $availableCarriers = [];
125 $carrierEntity = $this->carrierEntityRepository->getAnyById(
126 str_replace( BaseShippingMethod::PACKETA_METHOD_PREFIX, '', $methodId )
127 );
128 if ( $carrierEntity !== null && $carrierEntity->getCountry() === $customerCountry ) {
129 $availableCarriers[] = $carrierEntity;
130 }
131 $rateId = $methodId . ':' . $instanceId;
132 }
133
134 $customRates = [];
135 foreach ( $availableCarriers as $carrier ) {
136 $optionId = Carrier\OptionPrefixer::getOptionId( $carrier->getId() );
137 if ( $methodId === ShippingMethod::PACKETERY_METHOD_ID ) {
138 $rateId = $methodId . ':' . $optionId;
139 }
140 $shippingRate = $this->createShippingRateOfCarrier(
141 $carrier,
142 $allowedCarrierNames,
143 $optionId,
144 $rateId
145 );
146
147 $this->diagnosticsLogger->log(
148 'Shipping rate created or is null',
149 [
150 'shippingRate' => $shippingRate,
151 'carrier' => $carrier,
152 'allowedCarrierNames' => $allowedCarrierNames,
153 'rateId' => $rateId,
154 'optionId' => $optionId,
155 ]
156 );
157
158 if ( $shippingRate !== null ) {
159 $customRates[ $rateId ] = $shippingRate;
160 }
161 }
162
163 return $customRates;
164 }
165
166 /**
167 * @throws ProductNotFoundException
168 */
169 private function createShippingRateOfCarrier(
170 Entity\Carrier $carrier,
171 ?array $allowedCarrierNames,
172 string $optionId,
173 string $rateId
174 ): ?array {
175 if ( ! $this->canCreateShippingRate(
176 $carrier,
177 $allowedCarrierNames,
178 $optionId
179 ) ) {
180 return null;
181 }
182
183 $options = $this->carrierOptionsFactory->createByOptionId( $optionId );
184 $carrierName = $allowedCarrierNames[ $carrier->getId() ] ?? $options->getName();
185 $cartPrice = $this->cartService->getCartContentsTotalIncludingTax();
186 $cartWeight = $this->cartService->getCartWeightKg();
187 $totalCartProductValue = $this->cartService->getTotalCartProductValue();
188 $cost = $this->rateCalculator->getRateCost( $options, $cartPrice, $totalCartProductValue, $cartWeight );
189
190 return $cost !== null ? $this->createShippingRateAndApplyTaxes( $carrierName, $cost, $rateId ) : null;
191 }
192
193 /**
194 * @throws ProductNotFoundException
195 */
196 private function canCreateShippingRate(
197 Entity\Carrier $carrier,
198 ?array $allowedCarrierNames,
199 string $optionId
200 ): bool {
201 $isAgeVerificationRequired = $this->cartService->isAgeVerificationRequired();
202 if ( $isAgeVerificationRequired && ! $carrier->supportsAgeVerification() ) {
203 return false;
204 }
205
206 if ( $allowedCarrierNames !== null && ! array_key_exists( $carrier->getId(), $allowedCarrierNames ) ) {
207 return false;
208 }
209
210 $carrierOptions = $this->carrierOptionsFactory->createByOptionId( $optionId );
211 $disallowedShippingRateIds = $this->cartService->getDisallowedShippingRateIds();
212 $cartProducts = $this->wcAdapter->cartGetCartContents();
213
214 $isCarrierOptionInactive = $allowedCarrierNames === null && ! $carrierOptions->isActive();
215 $isCarDeliveryDisabled = $carrier->isCarDelivery() && $this->carDeliveryConfig->isDisabled();
216 $isOptionDisallowed = in_array( $optionId, $disallowedShippingRateIds, true );
217 $containsOversizedProduct = $this->cartService->cartContainsProductOversizedForCarrier( $carrierOptions );
218 $isRestrictedByCategory = $this->cartService->isShippingRateRestrictedByProductsCategory( $optionId, $cartProducts );
219
220 return $carrier->isAvailable() && ! ( $isCarrierOptionInactive || $isCarDeliveryDisabled || $isOptionDisallowed || $containsOversizedProduct || $isRestrictedByCategory );
221 }
222
223 /**
224 * @param string $carrierName
225 * @param float $cost
226 * @param string $rateId
227 *
228 * @return array{
229 * label: string,
230 * id: string,
231 * cost: float,
232 * taxes: array<int, float>,
233 * calc_tax: string
234 * }
235 */
236 private function createShippingRateAndApplyTaxes( string $carrierName, float $cost, string $rateId ): array {
237 if ( $this->isFreeShippingApplicable( $cost ) ) {
238 $carrierName = $this->formatCarrierNameWithFreeShipping( $carrierName );
239 }
240 $taxes = null;
241 if ( $cost > 0 && $this->optionsProvider->arePricesTaxInclusive() ) {
242 $rates = $this->wcAdapter->taxGetShippingTaxRates();
243 $taxes = $this->wcAdapter->taxCalcInclusiveTax( $cost, $rates );
244 $taxExclusiveCost = $cost - array_sum( $taxes );
245
246 /**
247 * Filters shipping taxes.
248 *
249 * @param array $taxes Taxes.
250 * @param float $taxExclusiveCost Tax exclusive cost.
251 * @param array $rates Rates.
252 *
253 * @since 1.6.5
254 */
255 $taxes = $this->wpAdapter->applyFilters( 'woocommerce_calc_shipping_tax', $taxes, $taxExclusiveCost, $rates );
256 if ( ! is_array( $taxes ) ) {
257 $taxes = [];
258 }
259
260 $cost -= array_sum( $taxes );
261 }
262
263 return $this->rateCalculator->createShippingRate( $carrierName, $rateId, $cost, $taxes );
264 }
265
266 private function formatCarrierNameWithFreeShipping( string $carrierName ): string {
267 return sprintf( '%s: %s', $carrierName, $this->wpAdapter->__( 'Free', 'packeta' ) );
268 }
269
270 private function isFreeShippingApplicable( float $cost ): bool {
271 return $cost === 0.0 && $this->optionsProvider->isFreeShippingShown();
272 }
273 }
274