PluginProbe
FluentCart A New Era of eCommerce – Faster, Lighter, and Simpler / 1.7.1
FluentCart A New Era of eCommerce – Faster, Lighter, and Simpler v1.7.1
1.7.1 1.7.0 1.6.6 1.6.5 1.6.4 1.6.3 1.6.2 1.6.1 1.6.0 1.5.4 1.5.5 1.5.3 1.5.2 1.5.1 1.5.0 1.4.2 1.4.1 1.4.0 1.3.28 1.3.27 1.3.26 1.3.25 1.3.23 1.3.22 1.3.21 All 51 releases
← All changes | api/Resource/OrderResource.php +53 -0 1.7.0 → 1.7.1 View file →
@@ -285,8 +285,15 @@
285 285 if (Arr::get($discount, 'value', 0) > 0) {
286 286 static::distributeManualDiscount($items, Helper::toCent(Arr::get($discount, 'value', 0)));
287 287 }
288 288
289 + $couponCheck = CouponResource::validateOrderCoupons($items, (array) Arr::get($data, 'applied_coupon', []), Arr::get($customer, 'email', ''));
290 + if (is_wp_error($couponCheck)) {
291 + return $couponCheck;
292 + }
293 + $items = $couponCheck['items'];
294 + $data['applied_coupon'] = $couponCheck['applied_coupons'];
295 +
289 296 // admin order processor
290 297 $adminOrderProcessor = new AdminOrderProcessor($items, [
291 298 'customer_id' => $customer->id,
292 299 'payment_method' => $paymentMethod,
@@ -1360,8 +1367,35 @@
1360 1367 }
1361 1368 $subscription->save();
1362 1369 }
1363 1370
1371 + /**
1372 + * Whether the submitted coupon and item discounts match the calculated ones, within a cent of rounding.
1373 + *
1374 + * @param array $submittedItems
1375 + * @param array $submittedCoupons Applied-coupon map keyed by coupon code.
1376 + * @param array $couponCheck Result of CouponResource::validateOrderCoupons().
1377 + * @return bool
1378 + */
1379 + private static function couponDiscountsMatch(array $submittedItems, array $submittedCoupons, array $couponCheck): bool
1380 + {
1381 + foreach ($couponCheck['applied_coupons'] as $code => $calculated) {
1382 + $submitted = isset($submittedCoupons[$code]['discount']) ? (float) $submittedCoupons[$code]['discount'] : 0;
1383 + if (abs($submitted - (float) $calculated['discount']) > 1) {
1384 + return false;
1385 + }
1386 + }
1387 +
1388 + foreach ($couponCheck['items'] as $index => $calculatedItem) {
1389 + $submitted = (float) Arr::get($submittedItems, $index . '.discount_total', 0);
1390 + if (abs($submitted - (float) Arr::get($calculatedItem, 'discount_total', 0)) > 1) {
1391 + return false;
1392 + }
1393 + }
1394 +
1395 + return true;
1396 + }
1397 +
1364 1398 private static function distributeManualDiscount(&$items, $manualDiscountTotal)
1365 1399 {
1366 1400 $totalSubtotal = array_reduce($items, function ($carry, $item) {
1367 1401 return $carry + ((int)Arr::get($item, 'unit_price', 0) * (int)Arr::get($item, 'quantity', 1));
@@ -1607,8 +1641,27 @@
1607 1641 $deletedItems = $data['deletedItems'];
1608 1642 $appliedCoupons = Arr::get($orderData, 'applied_coupon');
1609 1643 $discount = $data['discount'];
1610 1644 $shipping = $data['shipping'];
1645 +
1646 + if (!empty($appliedCoupons)) {
1647 + $submittedItems = Arr::except((array) Arr::get($orderData, 'order_items', []), ['*']);
1648 + $couponCheck = CouponResource::validateOrderCoupons(
1649 + $submittedItems,
1650 + (array) $appliedCoupons,
1651 + $order->customer ? $order->customer->email : ''
1652 + );
1653 + if (is_wp_error($couponCheck)) {
1654 + return $couponCheck;
1655 + }
1656 + // Update saves the submitted items and totals, so they must already carry the calculated discounts.
1657 + if (!static::couponDiscountsMatch($submittedItems, (array) $appliedCoupons, $couponCheck)) {
1658 + return static::makeErrorResponse([
1659 + ['code' => 'coupon_discount_changed', 'message' => __('Coupon discounts have changed. Please re-apply the coupons and save again.', 'fluent-cart')]
1660 + ], 422);
1661 + }
1662 + $appliedCoupons = $couponCheck['applied_coupons'];
1663 + }
1611 1664
1612 1665 $orderId = $order->id;
1613 1666
1614 1667 /**