PluginProbe
FluentCart A New Era of eCommerce – Faster, Lighter, and Simpler / 1.6.0
FluentCart A New Era of eCommerce – Faster, Lighter, and Simpler v1.6.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 1.3.20 1.3.19 All 49 releases
fluent-cart / app / Services / Payments / PaymentHelper.php

PaymentHelper.php in FluentCart A New Era of eCommerce – Faster, Lighter, and Simpler 1.6.0, at app/Services/Payments/PaymentHelper.php

274 lines 11.5 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\Services\Payments;
4
5 use FluentCart\Api\StoreSettings;
6 use FluentCart\App\Helpers\Helper;
7 use FluentCart\App\Helpers\Status;
8 use FluentCart\App\Modules\PaymentMethods\Core\GatewayManager;
9 use FluentCart\App\Services\URL;
10 use FluentCart\Framework\Support\Arr;
11
12 class PaymentHelper
13 {
14 public string $slug = '';
15
16 public function __construct($slug)
17 {
18 $this->slug = $slug;
19 }
20
21 public function listenerUrl($args = [])
22 {
23 $listener = '/?fct_payment_listener=1&method=' . $this->slug;
24 $data = apply_filters_deprecated('fluent_cart_ipn_url_' . $this->slug, [
25 ['listener_url' => site_url($listener)]
26 ], '1.3.16', 'fluent_cart/ipn_url_' . $this->slug, 'Use fluent_cart/ipn_url_' . $this->slug . ' instead of fluent_cart_ipn_url_' . $this->slug . '. It will be removed in v1.4.3.');
27
28 return apply_filters('fluent_cart/ipn_url_' . $this->slug, $data);
29 }
30
31 public function successUrl($uuid, $args = null)
32 {
33 $queryArgs = array_merge(
34 array(
35 'method' => $this->slug,
36 'trx_hash' => $uuid,
37 'fct_redirect' => 'yes'
38 ),
39 is_array($args) ? $args : []
40 );
41
42 $receiptUrl = (new StoreSettings())->getReceiptPage();
43
44 if (empty($receiptUrl)) {
45 $receiptUrl = site_url();
46 }
47
48 $context = [
49 'transaction_hash' => $uuid,
50 'args' => $args,
51 'payment_method' => $this->slug ?? ''
52 ];
53 $url = apply_filters_deprecated('fluentcart/payment/success_url', [add_query_arg($queryArgs, $receiptUrl), $context], '1.3.16', 'fluent_cart/payment/success_url', 'Use fluent_cart/payment/success_url instead of fluentcart/payment/success_url. It will be removed in v1.4.3.');
54
55 return apply_filters('fluent_cart/payment/success_url', $url, $context);
56 }
57
58 public static function getCustomPaymentLink($orderHash): string
59 {
60 return wp_sanitize_redirect(
61 URL::appendQueryParams(home_url('/?fluent-cart=custom_checkout'), [
62 'order_hash' => $orderHash,
63 ]));
64 }
65
66 /*
67 *This will be hooked from basePaymentMethod
68 * validate payment method is active for checkout items, before order creation
69 */
70 public static function validateAndGetPayMethod($cartCheckoutHelper, $orderData, $extraCharge = 0)
71 {
72 $paymentMethod = Arr::get($orderData, 'others._fct_pay_method');
73 $isZeroPayment = $cartCheckoutHelper->getItemsAmountTotal(false, false) + $extraCharge <= 0;
74 $zeroMethodForced = false;
75 if ($isZeroPayment && $cartCheckoutHelper->getCart()->getEstimatedRecurringTotal() <= 0) {
76 $paymentMethod = apply_filters('fluent_cart/default_payment_method_for_zero_payment', 'offline_payment', []);
77 $zeroMethodForced = true;
78 }
79
80 if (!GatewayManager::has($paymentMethod)) {
81 wp_send_json([
82 'status' => 'failed',
83 'message' => __('No valid payment method found!', 'fluent-cart'),
84 'data' => []
85 ], 423
86 );
87 };
88
89 $gateway = GatewayManager::getInstance($paymentMethod);
90 $status = $gateway->validatePaymentMethod([
91 'isValid' => false,
92 'reason' => __('No payment method found!', 'fluent-cart'),
93 'isZeroPayment' => $isZeroPayment
94 ]);
95
96 if (!Arr::get($status, 'isValid')) {
97 wp_send_json(
98 [
99 'status' => 'failed',
100 'message' => Arr::get($status, 'reason'),
101 'data' => []
102 ], 423
103 );
104 }
105
106 // The checkout gateway-visibility filters (manual-subscription admission,
107 // store-managed capability gate, renewal pre-due-date block, reactivation
108 // restriction) only hide gateways in the rendered UI. The POSTed method must
109 // pass the same gate, or a crafted request can start/convert a subscription
110 // through a gateway the store never offered. Only the forced-offline zero
111 // checkout (no recurring — the UI renders no method picker and the method is
112 // overridden above) is exempt; a zero-payable SUBSCRIPTION cart (free trial)
113 // keeps the customer-picked gateway and must pass the gate like any other.
114 $cart = $cartCheckoutHelper->getCart();
115 if ($cart && !$zeroMethodForced) {
116 $allowedGateways = apply_filters('fluent_cart/checkout_active_payment_methods', [$gateway], [
117 'cart' => $cart
118 ]);
119
120 if (!in_array($gateway, (array) $allowedGateways, true)) {
121 wp_send_json(
122 [
123 'status' => 'failed',
124 'message' => __('This payment method is not available for this order. Please choose another payment method!', 'fluent-cart'),
125 'data' => []
126 ], 423
127 );
128 }
129 }
130
131 return $paymentMethod;
132 }
133
134 public static function updateTransactionRefundedTotal($parentTransaction, $refundedAmount)
135 {
136 // update the transaction. only update refunded_total, in meta, if exist add
137 $meta = $parentTransaction->meta;
138 $alreadyRefunded = Arr::get($meta, 'refunded_total', 0);
139 $meta['refunded_total'] = $alreadyRefunded + $refundedAmount;
140 $parentTransaction->meta = $meta;
141 $parentTransaction->save();
142 }
143
144 // public static function updateOrderRefundedTotal($order, $refundedAmount, &$type): void
145 // {
146 // // update order data
147 // $netOrderPaidAmount = $order->total_paid - $order->total_refunded;
148 // $isFullRefund = $refundedAmount == $netOrderPaidAmount;
149 //
150 // if ($isFullRefund) {
151 // $order->payment_status = Status::PAYMENT_REFUNDED;
152 // $type = 'full';
153 // } else {
154 // $order->payment_status = Status::PAYMENT_PARTIALLY_REFUNDED;
155 // $type = 'partial';
156 // }
157 // $order->total_refund += $refundedAmount;
158 // $order->save();
159 // }
160
161 /**
162 * @param string $paymentMethod
163 * @param array $paymentMethodDetails
164 * @param array $additionalData
165 * @return array
166 * parse payment method details and return a common format
167 * filter hook: 'fluent_cart/payments/parse_payment_method_details'
168 */
169 public static function parsePaymentMethodDetails($paymentGateway, $paymentMethodDetails, $additionalData = []): array
170 {
171 $billingInfo = [
172 'method' => $paymentGateway,
173 'type' => null,
174 'details' => [],
175 'billing_details' => [
176 'name' => null,
177 'email' => null,
178 'phone' => null,
179 'address' => [
180 'country' => null,
181 'postal_code' => null,
182 'line1' => null,
183 'line2' => null,
184 'city' => null,
185 'state' => null,
186 ]
187 ]
188 ];
189
190 if ($paymentGateway === 'stripe') {
191 $type = Arr::get($paymentMethodDetails, 'type', 'card');
192 $billingInfo['type'] = $type;
193
194 if ($type === 'card') {
195 $billingInfo['details'] = [
196 'type' => 'card',
197 'brand' => sanitize_text_field(Arr::get($paymentMethodDetails, 'card.brand')),
198 'last_4' => sanitize_text_field(Arr::get($paymentMethodDetails, 'card.last4')),
199 'exp_month' => sanitize_text_field(Arr::get($paymentMethodDetails, 'card.exp_month')),
200 'exp_year' => sanitize_text_field(Arr::get($paymentMethodDetails, 'card.exp_year')),
201 'fingerprint' => sanitize_text_field(Arr::get($paymentMethodDetails, 'card.fingerprint')),
202 'payment_method_id' => sanitize_text_field(Arr::get($paymentMethodDetails, 'id'))
203 ];
204 } else {
205 // For other Stripe payment methods (ACH, SEPA, etc.)
206 $billingInfo['details'] = [
207 'payment_method_id' => sanitize_text_field(Arr::get($paymentMethodDetails, 'id')),
208 'type' => Arr::get($paymentMethodDetails, $type, [])
209 ];
210 }
211
212 // Common billing details for Stripe
213 $billingInfo['billing_details'] = [
214 'name' => sanitize_text_field(Arr::get($paymentMethodDetails, 'billing_details.name')),
215 'email' => sanitize_email(Arr::get($paymentMethodDetails, 'billing_details.email', '')),
216 'phone' => sanitize_text_field(Arr::get($paymentMethodDetails, 'billing_details.phone')),
217 'address' => [
218 'country' => sanitize_text_field(Arr::get($paymentMethodDetails, 'billing_details.address.country')),
219 'postal_code' => sanitize_text_field(Arr::get($paymentMethodDetails, 'billing_details.address.postal_code')),
220 'line1' => sanitize_text_field(Arr::get($paymentMethodDetails, 'billing_details.address.line1')),
221 'line2' => sanitize_text_field(Arr::get($paymentMethodDetails, 'billing_details.address.line2')),
222 'city' => sanitize_text_field(Arr::get($paymentMethodDetails, 'billing_details.address.city')),
223 'state' => sanitize_text_field(Arr::get($paymentMethodDetails, 'billing_details.address.state')),
224 ]
225 ];
226
227 } elseif ($paymentGateway === 'paypal') {
228 $billingInfo['type'] = 'standard';
229 $billingInfo['details'] = [
230 'email' => sanitize_email(Arr::get($paymentMethodDetails, 'email', '')),
231 'payer_id' => sanitize_text_field(Arr::get($paymentMethodDetails, 'payer_id')),
232 ];
233
234 // PayPal billing details
235 $billingInfo['billing_details'] = [
236 'name' => sanitize_text_field(Arr::get($paymentMethodDetails, 'name')),
237 'email' => sanitize_email(Arr::get($paymentMethodDetails, 'email', '')),
238 'phone' => sanitize_text_field(Arr::get($paymentMethodDetails, 'phone')),
239 'address' => [
240 'country' => sanitize_text_field(Arr::get($paymentMethodDetails, 'address.country_code')),
241 'postal_code' => sanitize_text_field(Arr::get($paymentMethodDetails, 'address.postal_code')),
242 'line1' => sanitize_text_field(Arr::get($paymentMethodDetails, 'address.address_line_1')),
243 'line2' => sanitize_text_field(Arr::get($paymentMethodDetails, 'address.address_line_2')),
244 ]
245 ];
246 }
247
248 return $billingInfo;
249 }
250
251
252 public static function getIntervalDays($interval = ''): int
253 {
254 if ($interval === 'yearly') {
255 $days = 365;
256 } elseif ($interval === 'monthly') {
257 $days = 30;
258 } elseif ($interval === 'weekly') {
259 $days = 7;
260 } elseif ($interval === 'quarterly') {
261 $days = 90;
262 } elseif ($interval === 'half_yearly') {
263 $days = 182;
264 } else {
265 $days = 1;
266 }
267
268 return apply_filters('fluent_cart/subscription_interval_in_days', $days, [
269 'interval' => $interval
270 ]);
271 }
272
273 }
274