| @@ -231,9 +231,10 @@ | ||
| 231 | 231 | $getAppliedCouponLists = array_diff($getAppliedCouponLists, $appliedKeys); |
| 232 | 232 | |
| 233 | 233 | if (!empty($getAppliedCouponLists)) { |
| 234 | 234 | $getAppliedCouponLists = Coupon::query()->whereIn('id', $getAppliedCouponLists)->get()->keyBy('code')->toArray(); |
| 235 | - $previouslyAppliedCouponCodes = $previouslyAppliedCouponCodes->merge($getAppliedCouponLists); | |
| 235 | + // Union keeps the coupon-code keys: the ORM merge() needs models, and array_merge renumbers numeric codes. | |
| 236 | + $previouslyAppliedCouponCodes = new Collection($previouslyAppliedCouponCodes->all() + $getAppliedCouponLists); | |
| 236 | 237 | } |
| 237 | 238 | |
| 238 | 239 | $couponService = new CouponServiceAdmin($lineItems, null, $previouslyAppliedCouponCodes->keys()->toArray(), $customerEmail); |
| 239 | 240 | $couponApplied = $couponService->applyCoupon($couponCode); |
| @@ -358,8 +359,62 @@ | ||
| 358 | 359 | ]; |
| 359 | 360 | } |
| 360 | 361 | |
| 361 | 362 | return new WP_Error(__('Something went wrong while updating the cart.', 'fluent-cart')); |
| 363 | + } | |
| 364 | + | |
| 365 | + /** | |
| 366 | + * Re-run the coupon rules on an admin order payload before it is saved. | |
| 367 | + * The payload's coupon discounts come from the client, so they are replaced with calculated ones. | |
| 368 | + * | |
| 369 | + * @param array $items Order line items. | |
| 370 | + * @param array $appliedCoupons Applied-coupon map keyed by coupon code. | |
| 371 | + * @param string $customerEmail | |
| 372 | + * @return array|WP_Error ['applied_coupons' => array, 'items' => array] | |
| 373 | + */ | |
| 374 | + public static function validateOrderCoupons(array $items, array $appliedCoupons, $customerEmail = '') | |
| 375 | + { | |
| 376 | + $codes = array_map('strval', array_keys(Arr::except($appliedCoupons, ['*']))); | |
| 377 | + | |
| 378 | + if (!$codes) { | |
| 379 | + return [ | |
| 380 | + 'applied_coupons' => $appliedCoupons, | |
| 381 | + 'items' => $items, | |
| 382 | + ]; | |
| 383 | + } | |
| 384 | + | |
| 385 | + $couponService = new CouponServiceAdmin($items, null, $codes, (string) $customerEmail); | |
| 386 | + $couponService->reapplyCoupons(); | |
| 387 | + | |
| 388 | + $discountData = $couponService->getDiscountData(); | |
| 389 | + $error = $couponService->getCouponErrors()->first(); | |
| 390 | + | |
| 391 | + if (!$error) { | |
| 392 | + foreach ($codes as $code) { | |
| 393 | + if (!isset($discountData[$code])) { | |
| 394 | + $error = new WP_Error('coupon_not_found', __('Coupon Not Found', 'fluent-cart')); | |
| 395 | + break; | |
| 396 | + } | |
| 397 | + } | |
| 398 | + } | |
| 399 | + | |
| 400 | + if ($error) { | |
| 401 | + return static::makeErrorResponse([ | |
| 402 | + ['code' => 'invalid_coupon', 'message' => $error->get_error_message()] | |
| 403 | + ], 422); | |
| 404 | + } | |
| 405 | + | |
| 406 | + // Calculated items are keyed by line item id. | |
| 407 | + $calculatedItems = $couponService->getCalculatedLineItems(); | |
| 408 | + foreach ($items as $index => $item) { | |
| 409 | + $calculated = Arr::get($calculatedItems, (string) Arr::get($item, 'id', '')); | |
| 410 | + $items[$index]['discount_total'] = $calculated ? $calculated['discount_total'] : 0; | |
| 411 | + } | |
| 412 | + | |
| 413 | + return [ | |
| 414 | + 'applied_coupons' => $discountData, | |
| 415 | + 'items' => $items, | |
| 416 | + ]; | |
| 362 | 417 | } |
| 363 | 418 | |
| 364 | 419 | /** |
| 365 | 420 | * Report whether a product may be bought while the given coupons are applied. |