PluginProbe
FluentCart A New Era of eCommerce – Faster, Lighter, and Simpler / 1.3.26
FluentCart A New Era of eCommerce – Faster, Lighter, and Simpler v1.3.26
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
fluent-cart / app / Hooks / Handlers / CustomCheckout / CustomCheckout.php

CustomCheckout.php in FluentCart A New Era of eCommerce – Faster, Lighter, and Simpler 1.3.26, at app/Hooks/Handlers/CustomCheckout/CustomCheckout.php

193 lines 7.7 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2
3 namespace FluentCart\App\Hooks\Handlers\CustomCheckout;
4
5 use FluentCart\Api\StoreSettings;
6 use FluentCart\App\Helpers\CartHelper;
7 use FluentCart\App\Helpers\Status;
8 use FluentCart\App\Models\Cart;
9 use FluentCart\App\Models\Order;
10 use FluentCart\App\Services\ProductItemService;
11 use FluentCart\Framework\Support\Arr;
12
13 class CustomCheckout
14 {
15 public function register()
16 {
17 add_action('fluent_cart_action_custom_checkout', [$this, 'handleCustomCheckoutRedirect'], 10, 1);
18 }
19
20 /*
21 * 1. validation
22 * 2. create cart
23 * - subscription
24 * discount, signup etc.
25 * - onetime
26 * 3. redirect to the checkout with cart
27 */
28 public function handleCustomCheckoutRedirect($data)
29 {
30 $orderHash = sanitize_text_field(Arr::get($data, 'order_hash', ''));
31 $order = Order::query()->where('uuid', $orderHash)->first();
32 if (!$order) {
33 die('Invalid order!');
34 }
35
36 if ($order->payment_status === Status::PAYMENT_PAID || $order->status === Status::ORDER_COMPLETED) {
37 die('Order already completed!');
38 }
39
40 $totalDue = $order->total_amount - $order->paid;
41
42 if ($totalDue <= 0) {
43 die('No due amount found!');
44 }
45
46 if ($order->type === Status::ORDER_TYPE_SUBSCRIPTION) {
47 $orderItem = $order->order_items->filter(function ($item) {
48 return !in_array($item->payment_type, ['signup_fee', 'fee']);
49 })->first();
50
51 if (!$orderItem) {
52 die('Subscription order item not found!');
53 }
54
55 $subscriptionItemData = ProductItemService::getItem([
56 'order_id' => $orderItem->order_id,
57 'product_id' => $orderItem->post_id,
58 'variation_id' => $orderItem->object_id,
59 ]);
60
61 if (!$subscriptionItemData || !$subscriptionItemData->variation) {
62 die('Failed to load product data for custom checkout!');
63 }
64
65 $newItem = $subscriptionItemData->variation->toArray();
66 $isCustom = $subscriptionItemData->is_custom;
67
68 Arr::set($newItem, 'item_price', $orderItem->unit_price);
69
70 // Keep the variation's other_info as-is (trial_days, signup_fee, repeat_interval, times).
71 // The variation's other_info has the clean product-level config that CheckoutProcessor
72 // expects when processing the cart.
73
74 if ($isCustom) {
75 Arr::set($newItem, 'post_title', $subscriptionItemData->variation->post_title);
76 Arr::set($newItem, 'variation_type', $subscriptionItemData->variation->variation_type);
77 } else {
78 Arr::set($newItem, 'post_title', $subscriptionItemData->variation->product->post_title);
79 Arr::set($newItem, 'variation_type', $subscriptionItemData->variation->product_detail->variation_type);
80 }
81
82 if ($order->coupon_discount_total > 0 || $order->manual_discount_total > 0) {
83 Arr::set($newItem, 'coupon_discount', (int) $order->coupon_discount_total);
84 Arr::set($newItem, 'manual_discount', (int) $order->manual_discount_total);
85 }
86
87 $instantCart = CartHelper::generateCartFromCustomVariation($newItem, $orderItem->quantity);
88
89 } else {
90 $items = [];
91 $productItems = $order->order_items->filter(function ($orderItem) {
92 return !in_array($orderItem->payment_type, ['fee', 'signup_fee']);
93 });
94 foreach ($productItems as $orderItem) {
95 $itemData = ProductItemService::getItem([
96 'order_id' => $orderItem->order_id,
97 'product_id' => $orderItem->post_id,
98 'variation_id' => $orderItem->object_id,
99 ]);
100 if (!$itemData || !$itemData->variation) {
101 die('Failed to load product data for custom checkout!');
102 }
103 $item = $itemData->variation->toArray();
104
105
106 Arr::set($item, 'coupon_discount', (string)($orderItem->discount_total)); // item discount total is always coupon discount + manual discount
107 Arr::set($item, 'tax_amount', $orderItem->tax_amount);
108 Arr::set($item, 'post_title', $orderItem->post_title);
109
110 if ($order->manual_discount_total) {
111 $subtotal = Arr::get($orderItem, 'subtotal');
112 $manualDiscount = ($subtotal * $order->manual_discount_total) / $order->subtotal;
113 $couponDiscount = max(0, $orderItem->discount_total - $manualDiscount);
114 Arr::set($item, 'manual_discount', $manualDiscount);
115 Arr::set($item, 'coupon_discount', $couponDiscount);
116 }
117
118 $items[] = CartHelper::generateCartItemCustomItem($item, $orderItem->quantity);
119 }
120
121 $instantCart = new Cart();
122 $instantCart->cart_data = $items;
123 }
124
125 $primaryBillingAddress = [];
126 if ($order->billing_address) {
127 $primaryBillingAddress = $order->billing_address
128 ->getFormattedDataForCheckout('billing_');
129 }
130 $instantCart->cart_group = 'instant';
131 $instantCart->first_name = $order->customer->first_name;
132 $instantCart->last_name = $order->customer->last_name;
133 $instantCart->email = $order->customer->email;
134 $instantCart->customer_id = $order->customer->customer_id;
135 $instantCart->user_id = $order->customer->user_id;
136 $instantCart->order_id = $order->id;
137 $instantCart->cart_hash = md5('custom_payment_cart_' . wp_generate_uuid4() . time());
138
139 // Preserve original order fees so the custom payment checkout
140 // shows exactly what was charged, not whatever the current filter returns
141 $originalFees = [];
142 $feeOrderItems = $order->order_items->filter(function ($item) {
143 return $item->payment_type === 'fee';
144 });
145
146 foreach ($feeOrderItems as $feeItem) {
147 $otherInfo = $feeItem->other_info ?? [];
148 $originalFees[] = [
149 'key' => Arr::get($otherInfo, 'fee_key', ''),
150 'label' => $feeItem->title,
151 'amount' => (int) $feeItem->unit_price,
152 'source' => Arr::get($otherInfo, 'source', 'custom'),
153 'taxable' => !empty(Arr::get($otherInfo, 'taxable')),
154 'meta' => Arr::get($otherInfo, 'meta', []),
155 ];
156 }
157
158 $instantCart->checkout_data = [
159 'is_locked' => 'yes',
160 'disable_coupons' => 'yes',
161 'custom_checkout' => 'yes',
162 'form_data' => $primaryBillingAddress,
163 'fees' => $originalFees,
164 'custom_checkout_data' => [
165 'coupon_discount_total' => $order->coupon_discount_total,
166 'manual_discount_total' => $order->manual_discount_total,
167 'discount_total' => $order->coupon_discount_total + $order->manual_discount_total,
168 'shipping_total' => $order->shipping_total,
169 ],
170 '__cart_notices' => [
171 [
172 'id' => 'custom_payment_notice',
173 'type' => 'info',
174 'content' => 'You are making payment for your order (#' . $order->uuid . ').',
175 ]
176 ]
177 ];
178
179 $instantCart->save();
180
181 $cartHash = $instantCart->cart_hash;
182
183 $checkoutUrl = add_query_arg(
184 [
185 'fct_cart_hash' => $cartHash,
186 ],
187 (new StoreSettings())->getCheckoutPage()
188 );
189
190 wp_redirect($checkoutUrl);
191 exit();
192 }
193 }