PluginProbe
FluentCart A New Era of eCommerce – Faster, Lighter, and Simpler / 1.6.5
FluentCart A New Era of eCommerce – Faster, Lighter, and Simpler v1.6.5
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 1.3.20 1.3.19 All 49 releases
← All changes | app/Hooks/Handlers/CustomCheckout/CustomCheckout.php +63 -43 1.6.0 → 1.6.5 View file →
@@ -93,51 +93,10 @@
93 93
94 94 $instantCart = CartHelper::generateCartFromCustomVariation($newItem, $orderItem->quantity);
95 95
96 96 } else {
97 - $items = [];
98 - $productItems = $order->order_items->filter(function ($orderItem) {
99 - return !in_array($orderItem->payment_type, ['fee', 'signup_fee']);
100 - });
101 - foreach ($productItems as $orderItem) {
102 - $itemData = ProductItemService::getItem([
103 - 'order_id' => $orderItem->order_id,
104 - 'product_id' => $orderItem->post_id,
105 - 'variation_id' => $orderItem->object_id,
106 - ]);
107 - if (!$itemData || !$itemData->variation) {
108 - die('Failed to load product data for custom checkout!');
109 - }
110 - $item = $itemData->variation->toArray();
111 -
112 -
113 - Arr::set($item, 'coupon_discount', (string)($orderItem->discount_total)); // item discount total is always coupon discount + manual discount
114 - Arr::set($item, 'tax_amount', $orderItem->tax_amount);
115 - Arr::set($item, 'post_title', $orderItem->post_title);
116 - Arr::set($item, 'variation_type', $itemData->variation->product_detail->variation_type);
117 -
118 - // For renewal invoices, use the order item's unit_price (matches subscription's recurring_amount)
119 - // and strip trial_days so CheckoutProcessor doesn't apply trial (0) pricing.
120 - if ($order->type === Status::ORDER_TYPE_RENEWAL) {
121 - Arr::set($item, 'item_price', $orderItem->unit_price);
122 - $otherInfo = Arr::get($item, 'other_info', []);
123 - $otherInfo['trial_days'] = 0;
124 - Arr::set($item, 'other_info', $otherInfo);
125 - }
126 -
127 - if ($itemManualDiscountTotal) {
128 - $subtotal = Arr::get($orderItem, 'subtotal');
129 - $manualDiscount = ($subtotal * $itemManualDiscountTotal) / $order->subtotal;
130 - $couponDiscount = max(0, $orderItem->discount_total - $manualDiscount);
131 - Arr::set($item, 'manual_discount', $manualDiscount);
132 - Arr::set($item, 'coupon_discount', $couponDiscount);
133 - }
134 -
135 - $items[] = CartHelper::generateCartItemCustomItem($item, $orderItem->quantity);
136 - }
137 -
138 97 $instantCart = new Cart();
139 - $instantCart->cart_data = $items;
98 + $instantCart->cart_data = static::buildOneTimeCartItems($order, $itemManualDiscountTotal);
140 99 }
141 100
142 101 $primaryBillingAddress = [];
143 102 if ($order->billing_address) {
@@ -187,9 +146,13 @@
187 146 '__cart_notices' => [
188 147 [
189 148 'id' => 'custom_payment_notice',
190 149 'type' => 'info',
191 - 'content' => 'You are making payment for your order (#' . $order->uuid . ').',
150 + 'content' => sprintf(
151 + /* translators: %1$s: the order UUID. */
152 + __('You are making payment for your order (#%1$s).', 'fluent-cart'),
153 + $order->uuid
154 + ),
192 155 ]
193 156 ]
194 157 ];
195 158
@@ -227,6 +190,63 @@
227 190 );
228 191
229 192 wp_redirect($checkoutUrl);
230 193 exit();
194 + }
195 +
196 + /**
197 + * Build cart items for a one-time (non-subscription) order re-pay, priced at the
198 + * order's own unit_price rather than the current catalogue price.
199 + */
200 + protected static function buildOneTimeCartItems(Order $order, $itemManualDiscountTotal)
201 + {
202 + $items = [];
203 + $productItems = $order->order_items->filter(function ($orderItem) {
204 + return !in_array($orderItem->payment_type, ['fee', 'signup_fee']);
205 + });
206 +
207 + foreach ($productItems as $orderItem) {
208 + $itemData = ProductItemService::getItem([
209 + 'order_id' => $orderItem->order_id,
210 + 'product_id' => $orderItem->post_id,
211 + 'variation_id' => $orderItem->object_id,
212 + ]);
213 + if (!$itemData || !$itemData->variation) {
214 + die('Failed to load product data for custom checkout!');
215 + }
216 + $item = $itemData->variation->toArray();
217 +
218 + Arr::set($item, 'coupon_discount', (string)($orderItem->discount_total)); // item discount total is always coupon discount + manual discount
219 + Arr::set($item, 'tax_amount', $orderItem->tax_amount);
220 + Arr::set($item, 'post_title', $orderItem->post_title);
221 + Arr::set($item, 'variation_type', $itemData->variation->product_detail->variation_type);
222 +
223 + // Use the order item's unit_price, not the current catalogue price — the order
224 + // may carry a price agreed at purchase time (adjusted unit_price, since expired
225 + // catalogue price) that differs from what the product sells for today.
226 + Arr::set($item, 'item_price', $orderItem->unit_price);
227 +
228 + // For renewal invoices, also strip trial_days so CheckoutProcessor doesn't
229 + // apply trial (0) pricing on a renewal.
230 + if ($order->type === Status::ORDER_TYPE_RENEWAL) {
231 + $otherInfo = Arr::get($item, 'other_info', []);
232 + $otherInfo['trial_days'] = 0;
233 + Arr::set($item, 'other_info', $otherInfo);
234 + }
235 +
236 + if ($itemManualDiscountTotal) {
237 + // Use the order item's own stored split rather than proportionally
238 + // redistributing the order-level manual_discount_total — a manual
239 + // discount concentrated on one item must stay on that item, or this
240 + // reconstruction both keeps it there AND leaves a duplicate slice
241 + // behind as "coupon_discount" on it.
242 + $manualDiscount = max(0, (int) $orderItem->discount_total - (int) $orderItem->coupon_discount);
243 + Arr::set($item, 'manual_discount', $manualDiscount);
244 + Arr::set($item, 'coupon_discount', (int) $orderItem->coupon_discount);
245 + }
246 +
247 + $items[] = CartHelper::generateCartItemCustomItem($item, $orderItem->quantity);
248 + }
249 +
250 + return $items;
231 251 }
232 252 }