| @@ -5,8 +5,9 @@ | ||
| 5 | 5 | use FluentCart\App\Models\Coupon; |
| 6 | 6 | use FluentCart\App\Models\Product; |
| 7 | 7 | use FluentCart\App\Services\Coupon\Concerns\CanCalculateLineTotal; |
| 8 | 8 | use FluentCart\App\Services\Coupon\Concerns\CanValidateCoupon; |
| 9 | +use FluentCart\Framework\Support\Arr; | |
| 9 | 10 | use FluentCart\Framework\Support\Collection; |
| 10 | 11 | use WP_Error; |
| 11 | 12 | |
| 12 | 13 | /* |
| @@ -32,17 +33,20 @@ | ||
| 32 | 33 | protected array $lineItems = []; |
| 33 | 34 | protected array $calculatedLineItems = []; |
| 34 | 35 | protected bool $usingCart = true; |
| 35 | 36 | protected ?Collection $couponErrors = null; |
| 37 | + protected string $customerEmail = ''; | |
| 36 | 38 | |
| 37 | 39 | |
| 38 | 40 | /** |
| 39 | 41 | * @param array $lineItems |
| 40 | 42 | * @param ?Collection $previouslyAppliedCoupons |
| 41 | - * @param bool $usingCart | |
| 43 | + * @param array $applicableCouponCodes | |
| 44 | + * @param string $customerEmail | |
| 42 | 45 | */ |
| 43 | - public function __construct(array $lineItems = [], ?Collection $previouslyAppliedCoupons = null, $applicableCouponCodes = []) | |
| 46 | + public function __construct(array $lineItems = [], ?Collection $previouslyAppliedCoupons = null, $applicableCouponCodes = [], $customerEmail = '') | |
| 44 | 47 | { |
| 48 | + $this->customerEmail = (string) $customerEmail; | |
| 45 | 49 | $this->appliedCoupons = $previouslyAppliedCoupons; |
| 46 | 50 | $this->couponErrors = new Collection(); |
| 47 | 51 | |
| 48 | 52 | //Set Data from the parameters |
| @@ -55,8 +59,20 @@ | ||
| 55 | 59 | } |
| 56 | 60 | |
| 57 | 61 | private function init() |
| 58 | 62 | { |
| 63 | + // The admin UI submits subtotal as null for variation line items (the request | |
| 64 | + // guard deliberately preserves that null instead of floatval-ing it to 0), and | |
| 65 | + // the min/max purchase-amount gates in CanValidateCoupon sum these subtotals | |
| 66 | + // via OrderService::getItemsAmountTotal. An empty subtotal must therefore fall | |
| 67 | + // back to the item's real unit_price * quantity — the same contract | |
| 68 | + // OrderService::calculateItemTotal applies when the key is absent. | |
| 69 | + foreach ($this->lineItems as $index => $lineItem) { | |
| 70 | + if (!is_numeric(Arr::get($lineItem, 'subtotal'))) { | |
| 71 | + $this->lineItems[$index]['subtotal'] = intval(Arr::get($lineItem, 'unit_price', 0)) * max(1, intval(Arr::get($lineItem, 'quantity', 1))); | |
| 72 | + } | |
| 73 | + } | |
| 74 | + | |
| 59 | 75 | $this->calculatedLineItems = $this->lineItems; |
| 60 | 76 | $this->productIds = (new Collection($this->lineItems)) |
| 61 | 77 | ->pluck('post_id') |
| 62 | 78 | ->toArray(); |
| @@ -161,8 +177,15 @@ | ||
| 161 | 177 | |
| 162 | 178 | protected function apply(array $couponCodes = []): ?WP_Error |
| 163 | 179 | { |
| 164 | 180 | $this->initializeCoupons($couponCodes); |
| 181 | + | |
| 182 | + foreach ($couponCodes as $couponCode) { | |
| 183 | + if (!$this->applicableCoupons->has($couponCode)) { | |
| 184 | + $this->couponErrors->put($couponCode, $this->makeError(__('Coupon Not Found', 'fluent-cart'), 404)); | |
| 185 | + } | |
| 186 | + } | |
| 187 | + | |
| 165 | 188 | $this->calculateLineItems(); |
| 166 | 189 | return null; |
| 167 | 190 | } |
| 168 | 191 | |