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

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

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