PluginProbe
Fluent Forms – Customizable Contact Forms, Survey, Quiz, & Conversational Form Builder / 6.2.13
Fluent Forms – Customizable Contact Forms, Survey, Quiz, & Conversational Form Builder v6.2.13
6.2.14 6.2.13 6.2.12 6.2.10 6.2.11 6.2.9 6.2.8 6.2.7 6.2.6 6.2.5 6.2.4 6.2.3 6.2.2 3.6.22 3.6.31 3.6.40 3.6.41 3.6.42 3.6.50 3.6.51 3.6.60 3.6.61 3.6.62 3.6.64 3.6.65 All 196 releases
fluentform / app / Modules / Payments / PaymentMethods / Stripe / StripeProcessor.php

StripeProcessor.php in Fluent Forms – Customizable Contact Forms, Survey, Quiz, & Conversational Form Builder 6.2.13, at app/Modules/Payments/PaymentMethods/Stripe/StripeProcessor.php

782 lines 28.3 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2
3 namespace FluentForm\App\Modules\Payments\PaymentMethods\Stripe;
4
5 if (!defined('ABSPATH')) {
6 exit; // Exit if accessed directly.
7 }
8
9 use FluentForm\App\Helpers\Helper;
10 use FluentForm\App\Models\Submission;
11 use FluentForm\App\Models\Transaction;
12 use FluentForm\App\Services\FormBuilder\ShortCodeParser;
13 use FluentForm\Framework\Helpers\ArrayHelper;
14 use FluentForm\App\Modules\Payments\PaymentHelper;
15 use FluentForm\App\Modules\Payments\PaymentMethods\BaseProcessor;
16 use FluentForm\App\Modules\Payments\PaymentMethods\Stripe\API\CheckoutSession;
17 use FluentForm\App\Modules\Payments\PaymentMethods\Stripe\API\Plan;
18
19 class StripeProcessor extends BaseProcessor
20 {
21 public $method = 'stripe';
22
23 protected $form;
24
25 public function init()
26 {
27 add_action('fluentform/process_payment_stripe_hosted', array($this, 'handlePaymentAction'), 10, 6);
28 add_action('fluentform/payment_frameless_' . $this->method, array($this, 'handleSessionRedirectBack'));
29 }
30
31 public function handlePaymentAction($submissionId, $submissionData, $form, $methodSettings, $hasSubscriptions, $totalPayable)
32 {
33 $this->setSubmissionId($submissionId);
34 $this->form = $form;
35 $submission = $this->getSubmission();
36 $paymentTotal = $this->getAmountTotal();
37
38 if (!$paymentTotal && !$hasSubscriptions) {
39 return false;
40 }
41
42 // Create the initial transaction here
43 $transaction = $this->createInitialPendingTransaction($submission, $hasSubscriptions);
44
45 $this->handleCheckoutSession($transaction, $submission, $form, $methodSettings);
46 }
47
48 public function handleCheckoutSession($transaction, $submission, $form, $methodSettings)
49 {
50
51 $formSettings = PaymentHelper::getFormSettings($form->id);
52
53 $args = [
54 'fluentform_payment' => $submission->id,
55 'payment_method' => $this->method,
56 'transaction_hash' => $transaction->transaction_hash,
57 'type' => 'success'
58 ];
59
60
61 $successUrl = add_query_arg($args, site_url('index.php'));
62
63 $cancelUrl = $submission->source_url;
64
65 if (!wp_http_validate_url($cancelUrl)) {
66 $cancelUrl = site_url($cancelUrl);
67 }
68
69
70 $checkoutArgs = [
71 'cancel_url' => wp_sanitize_redirect($cancelUrl),
72 'success_url' => wp_sanitize_redirect($successUrl),
73 'locale' => 'auto',
74 'billing_address_collection' => 'auto',
75 'client_reference_id' => $submission->id,
76 'customer_email' => $transaction->payer_email,
77 'metadata' => [
78 'submission_id' => $submission->id,
79 'form_id' => $form->id,
80 'transaction_id' => ($transaction) ? $transaction->id : ''
81 ]
82 ];
83
84 if (ArrayHelper::get($methodSettings, 'settings.require_billing_info.value') == 'yes') {
85 $checkoutArgs['billing_address_collection'] = 'required';
86 }
87
88 if (ArrayHelper::get($methodSettings, 'settings.require_shipping_info.value') == 'yes') {
89 $checkoutArgs['shipping_address_collection'] = [
90 'allowed_countries' => StripeSettings::supportedShippingCountries()
91 ];
92 }
93
94 if ($lineItems = $this->getFormattedItems($submission->currency)) {
95 $checkoutArgs['line_items'] = $lineItems;
96 }
97
98 $receiptEmail = PaymentHelper::getCustomerEmail($submission, $form);
99
100 if ($receiptEmail) {
101 $checkoutArgs['customer_email'] = $receiptEmail;
102 }
103
104 if ($transaction->transaction_type == 'subscription') {
105 unset($checkoutArgs['submit_type']);
106
107 $subscriptions = $this->getSubscriptions();
108 $subscription = $subscriptions[0];
109
110 if ($subscription->initial_amount) {
111 if (!isset($checkoutArgs['line_items'])) {
112 $checkoutArgs['line_items'] = [];
113 }
114 $price = $subscription->initial_amount;
115 if (PaymentHelper::isZeroDecimal($transaction->currency)) {
116 $price = intval($price / 100);
117 }
118 $checkoutArgs['line_items'][] = [
119 'amount' => $price,
120 'currency' => $transaction->currency,
121 /* translators: %s is the plan name */
122 'name' => sprintf(__('Signup fee for %s', 'fluentform'), $subscription->plan_name),
123 'quantity' => 1
124 ];
125 }
126
127 $stripePlan = Plan::getSubscriptionPlanBySubscription($subscription, $transaction->currency);
128
129 if(is_wp_error($stripePlan)) {
130 $this->handlePaymentChargeError($stripePlan->get_error_message(), $submission, $transaction);
131 }
132
133 $this->updateSubscription($subscription->id, [
134 'vendor_plan_id' => $stripePlan->id
135 ]);
136
137 $subsArgs = [
138 'items' => [
139 [
140 'plan' => $stripePlan->id,
141 'quantity' => $subscription->quantity ? $subscription->quantity : 1
142 ]
143 ]
144 ];
145
146 if ($subscription->trial_days) {
147 $subsArgs['trial_period_days'] = $subscription->trial_days;
148 }
149
150 $subsArgs['metadata'] = $this->getIntentMetaData($submission, $form, $transaction);
151
152 $checkoutArgs['subscription_data'] = $subsArgs;
153
154 } else {
155 $checkoutArgs['submit_type'] = 'auto';
156 $checkoutArgs['payment_intent_data'] = $this->getPaymentIntentData($transaction, $submission, $form);
157 if ($receiptEmail && ArrayHelper::get($formSettings, 'disable_stripe_payment_receipt') != 'yes') {
158 $checkoutArgs['payment_intent_data']['receipt_email'] = $receiptEmail;
159 }
160 }
161 if ($formSettings['transaction_type'] == 'donation' && $transaction->transaction_type != 'subscription') {
162 $checkoutArgs['submit_type'] = 'donate';
163 }
164
165 $checkoutArgs = apply_filters_deprecated(
166 'fluentform_stripe_checkout_args',
167 [
168 $checkoutArgs,
169 $submission,
170 $transaction,
171 $form
172 ],
173 FLUENTFORM_FRAMEWORK_UPGRADE,
174 'fluentform/stripe_checkout_args',
175 'Use fluentform/stripe_checkout_args instead of fluentform_stripe_checkout_args.'
176 );
177
178 $checkoutArgs = apply_filters('fluentform/stripe_checkout_args', $checkoutArgs, $submission, $transaction, $form);
179
180 // If FluentForm Pro is not installed, apply the fee 1.9%
181 if (!Helper::hasPro()) {
182 if ($transaction->transaction_type == 'subscription') {
183 $checkoutArgs['subscription_data']['application_fee_percent'] = 1.9; // 1.9%
184 } else {
185 // Total amount of 1.9%
186 $applicationFeeAmount = $this->calculateApplicationFeeAmount(
187 $transaction->payment_total,
188 $transaction->currency
189 );
190 $checkoutArgs['payment_intent_data']['application_fee_amount'] = $applicationFeeAmount;
191 }
192 }
193
194 $session = CheckoutSession::create($checkoutArgs);
195
196 if (!empty($session->error) || is_wp_error($session)) {
197 $error = __('Something is wrong', 'fluentform');
198 if (is_wp_error($session)) {
199 $error = $session->get_error_message();
200 } else if (!empty($session->error->message)) {
201 $error = $session->error->message;
202 }
203 $errorMessage = __('Stripe Error: ', 'fluentform') . $error;
204 wp_send_json([
205 'errors' => apply_filters('fluentform/payment_error_message', $errorMessage, $submission, $this->form)
206 ], 423);
207 }
208
209 $this->setMetaData('stripe_session_id', $session->id);
210
211 $logData = [
212 'parent_source_id' => $submission->form_id,
213 'source_type' => 'submission_item',
214 'source_id' => $submission->id,
215 'component' => 'Payment',
216 'status' => 'info',
217 'title' => __('Redirect to Stripe', 'fluentform'),
218 'description' => __('User redirect to Stripe for completing the payment', 'fluentform')
219 ];
220 do_action('fluentform/log_data', $logData);
221
222 wp_send_json_success([
223 'nextAction' => 'payment',
224 'actionName' => 'stripeRedirectToCheckout',
225 'sessionId' => $session->id,
226 'message' => __('You are redirecting to stripe.com to complete the purchase. Please wait while you are redirecting....', 'fluentform'),
227 'result' => [
228 'insert_id' => $submission->id
229 ]
230 ], 200);
231 }
232
233 protected function calculateApplicationFeeAmount($paymentTotal, $currency)
234 {
235 if (PaymentHelper::isZeroDecimal($currency)) {
236 $paymentTotal = intval($paymentTotal / 100);
237 }
238
239 return (int) ($paymentTotal * 0.019);
240 }
241
242 protected function getPaymentIntentData($transaction, $submission, $form)
243 {
244 $data = [
245 'capture_method' => 'automatic',
246 'description' => $form->title,
247 'statement_descriptor_suffix' => StripeSettings::getPaymentDescriptor($form),
248 ];
249
250 $paymentSettings = PaymentHelper::getFormSettings($form->id, 'admin');
251 $intentMeta = $this->getIntentMetaData($submission, $form, $transaction, $paymentSettings);
252
253 $data['metadata'] = $intentMeta;
254 return $data;
255 }
256
257 public function getFormattedItems($currency)
258 {
259 $orderItems = $this->getOrderItems();
260
261 $discountItems = $this->getDiscountItems();
262
263 $discountTotal = 0;
264 foreach ($discountItems as $item) {
265 $discountTotal += $item->line_total;
266 }
267
268 $orderTotal = 0;
269 foreach ($orderItems as $orderItem) {
270 $orderTotal += $orderItem->line_total;
271 }
272
273 $formattedItems = [];
274 $discountDistributed = 0;
275 $itemCount = count($orderItems);
276
277 foreach ($orderItems as $index => $item) {
278 $price = $item->item_price;
279 $quantity = $item->quantity ?: 1;
280
281 if ($discountTotal && $orderTotal) {
282 if ($index === $itemCount - 1) {
283 // Last item absorbs any remaining discount not yet distributed.
284 // intval floors the per-unit price, so (unitPrice * quantity) may be
285 // less than lineTotal. The difference (remainder) is 0..quantity-1 cents.
286 // When remainder > 0 we split into two Stripe line items:
287 // (quantity - remainder) units at the floor price, and
288 // remainder units at floor + 1 cent,
289 // so the total adds up exactly. e.g. $28.00 / 3 → 2×$9.33 + 1×$9.34 = $28.00
290 $remainingDiscount = $discountTotal - $discountDistributed;
291 $lineTotal = ($price * $quantity) - $remainingDiscount;
292 $unitPrice = intval($lineTotal / $quantity);
293 $remainder = $lineTotal - ($unitPrice * $quantity);
294
295 if ($remainder > 0 && $quantity > 1) {
296 $basePrice = $unitPrice;
297 $extraPrice = $unitPrice + 1;
298
299 if (PaymentHelper::isZeroDecimal($currency)) {
300 $basePrice = intval($basePrice / 100);
301 $extraPrice = intval($extraPrice / 100);
302 }
303
304 $formattedItems[] = [
305 'amount' => $basePrice,
306 'currency' => $currency,
307 'name' => $item->item_name,
308 'quantity' => $quantity - $remainder
309 ];
310 $formattedItems[] = [
311 'amount' => $extraPrice,
312 'currency' => $currency,
313 'name' => $item->item_name,
314 'quantity' => $remainder
315 ];
316 continue;
317 }
318
319 $price = $unitPrice;
320 } else {
321 $itemDiscount = (int) round(($discountTotal / $orderTotal) * $price);
322 $discountDistributed += $itemDiscount * $quantity;
323 $price = $price - $itemDiscount;
324 }
325 }
326
327 if (PaymentHelper::isZeroDecimal($currency)) {
328 $price = intval($price / 100);
329 }
330
331 $stripeLine = [
332 'amount' => $price,
333 'currency' => $currency,
334 'name' => $item->item_name,
335 'quantity' => $quantity
336 ];
337
338 $formattedItems[] = $stripeLine;
339 }
340
341 return $formattedItems;
342 }
343
344 public function handleSessionRedirectBack($data)
345 {
346 $type = sanitize_text_field($data['type']);
347 $submissionId = intval($data['fluentform_payment']);
348 $this->setSubmissionId($submissionId);
349
350 $submission = $this->getSubmission();
351
352 if (!$submission) {
353 return;
354 }
355
356 if ($type == 'success') {
357 if ($this->getMetaData('is_form_action_fired') == 'yes') {
358 $returnData = $this->getReturnData();
359 } else {
360 $sessionId = $this->getMetaData('stripe_session_id');
361 $session = CheckoutSession::retrieve($sessionId, [
362 'expand' => [
363 'subscription.latest_invoice.payment_intent',
364 'payment_intent'
365 ]
366 ], $submission->form_id);
367
368 if ($session && !is_wp_error($session) && $session->customer) {
369 $transactionHash = sanitize_text_field($data['transaction_hash']);
370 $transaction = $this->getTransaction($transactionHash, 'transaction_hash');
371 $returnData = $this->processStripeSession($session, $submission, $transaction);
372 } else {
373 $error = __('Sorry! No Valid payment session found. Please try again','fluentform');
374 if (is_wp_error($session)) {
375 $error = $session->get_error_message();
376 }
377 $returnData = [
378 'insert_id' => $submission->id,
379 'title' => __('Failed to retrieve session data', 'fluentform'),
380 'result' => false,
381 'error' => $error
382 ];
383 }
384 }
385 } else {
386 $returnData = [
387 'insert_id' => $submission->id,
388 'result' => false,
389 'error' => apply_filters('fluentform/stripe_payment_cancelled_message', __('Looks like you have cancelled the payment. Please try again!', 'fluentform'), $submission, $this->form)
390 ];
391 }
392
393 $returnData['type'] = $type;
394
395 if (!isset($returnData['is_new'])) {
396 $returnData['is_new'] = false;
397 }
398
399 $this->showPaymentView($returnData);
400 }
401
402 public function processStripeSession($session, $submission, $transaction)
403 {
404 $this->setSubmissionId($submission->id);
405
406 if ($transaction->status == 'paid' && $submission->payment_status == 'paid') {
407 return $this->getReturnData();
408 }
409
410 $invoice = empty($session->subscription->latest_invoice) ? $session : $session->subscription->latest_invoice;
411
412 $paymentStatus = $this->getIntentSuccessName($invoice->payment_intent);
413
414 $this->changeSubmissionPaymentStatus($paymentStatus);
415
416 if($transaction->transaction_type == 'subscription') {
417 $subscriptions = $this->getSubscriptions();
418
419 if($subscriptions) {
420 $this->processSubscriptionSuccess($subscriptions, $invoice, $submission);
421
422 $vendorSubscription = $session->subscription;
423 if($vendorSubscription) {
424 Plan::maybeSetCancelAt($subscriptions[0], $vendorSubscription);
425 }
426 }
427 }
428
429 $this->processOneTimeSuccess($invoice, $transaction, $paymentStatus);
430
431 $returnData = $this->completePaymentSubmission(false);
432 $this->recalculatePaidTotal();
433 $returnData['is_new'] = $this->getMetaData('is_form_action_fired') === 'yes';
434
435 return $returnData;
436 }
437
438 protected function getIntentSuccessName($intent)
439 {
440 if (!$intent || !$intent->status) {
441 return false;
442 }
443
444 $successStatuses = [
445 'succeeded' => 'paid',
446 'requires_capture' => 'requires_capture'
447 ];
448
449 if (isset($successStatuses[$intent->status])) {
450 return $successStatuses[$intent->status];
451 }
452
453 return false;
454 }
455
456 protected function getDescriptor($title)
457 {
458 $illegal = array('<', '>', '"', "'");
459 // Remove slashes
460 $descriptor = stripslashes($title);
461 // Remove illegal characters
462 $descriptor = str_replace($illegal, '', $descriptor);
463 // Trim to 22 characters max
464 return substr($descriptor, 0, 22);
465 }
466
467 protected function formatAddress($address)
468 {
469 $addressArray = [
470 'line1' => $address->line1,
471 'line2' => $address->line2,
472 'city' => $address->city,
473 'state' => $address->state,
474 'postal_code' => $address->postal_code,
475 'country' => $address->country,
476 ];
477 return implode(', ', array_filter($addressArray));
478 }
479
480 public function handleRefund($event)
481 {
482 $data = $event->data->object;
483
484 $chargeId = $data->payment_intent;
485 // Get the Transaction from database
486 $transaction = Transaction::where('charge_id', $chargeId)
487 ->where('payment_method', 'stripe')
488 ->first();
489
490 if (!$transaction) {
491 // Not our transaction
492 return;
493 }
494
495 $submission = Submission::find($transaction->submission_id);
496
497 if (!$submission) {
498 return;
499 }
500
501 $this->setSubmissionId($submission->id);
502 $amountRefunded = $data->amount_refunded;
503 if (PaymentHelper::isZeroDecimal($data->currency)) {
504 $amountRefunded = $amountRefunded * 100;
505 }
506
507 // Remove All Existing Refunds
508 Transaction::bySubmission($submission->id)->refunds()->delete();
509
510 $this->refund($amountRefunded, $transaction, $submission, 'stripe', $chargeId, 'Refund from Stripe');
511
512 }
513
514 public function getPaymentMode()
515 {
516 $stripeSettings = StripeSettings::getSettings();
517 return $stripeSettings['payment_mode'];
518 }
519
520 public function processSubscriptionSuccess($subscriptions, $invoice, $submission)
521 {
522 foreach ($subscriptions as $subscription) {
523 $subscriptionStatus = 'active';
524
525 if ($subscription->trial_days) {
526 $subscriptionStatus = 'trialling';
527 }
528
529 $updateData = [
530 'vendor_customer_id' => $invoice->customer,
531 'vendor_response' => maybe_serialize($invoice),
532 ];
533
534 if(!$subscription->bill_count && $subscriptionStatus == 'active') {
535 $updateData['bill_count'] = 1;
536 }
537
538 if (!$subscription->vendor_subscription_id) {
539 $updateData['vendor_subscription_id'] = $invoice->subscription;
540 }
541
542 $this->updateSubscription($subscription->id, $updateData);
543 $subscription = fluentFormApi('submissions')->getSubscription($subscription->id);
544 $this->updateSubscriptionStatus($subscription, $subscriptionStatus);
545 }
546
547 $logData = [
548 'parent_source_id' => $submission->form_id,
549 'source_type' => 'submission_item',
550 'source_id' => $submission->id,
551 'component' => 'Payment',
552 'status' => 'success',
553 'title' => __('Stripe Subscription Charged', 'fluentform'),
554 'description' => __('Stripe recurring subscription successfully initiated', 'fluentform')
555 ];
556
557 do_action('fluentform/log_data', $logData);
558
559 if (!empty($invoice->payment_intent->charges->data[0])) {
560 $charge = $invoice->payment_intent->charges->data[0];
561 $this->recordStripeBillingAddress($charge, $submission);
562 }
563 }
564
565 protected function recordStripeBillingAddress($charge, $submission)
566 {
567 if(!is_array($submission->response)) {
568 $submission->response = json_decode($submission->response, true);
569 }
570
571 if (isset($submission->response['__checkout_billing_address_details'])) {
572 return;
573 }
574
575 if (empty($charge->billing_details)) {
576 return;
577 }
578
579 $billingDetails = $charge->billing_details;
580 if (!empty($billingDetails->address)) {
581 $submission->response['__checkout_billing_address_details'] = $billingDetails->address;
582 }
583 if (!empty($billingDetails->phone)) {
584 $submission->response['__stripe_phone'] = $billingDetails->phone;
585 }
586 if (!empty($billingDetails->name)) {
587 $submission->response['__stripe_name'] = $billingDetails->name;
588 }
589 if (!empty($billingDetails->email)) {
590 $submission->response['__stripe_email'] = $billingDetails->email;
591 }
592
593 $this->updateSubmission($submission->id, [
594 'response' => json_encode($submission->response)
595 ]);
596
597 $logData = [
598 'parent_source_id' => $submission->form_id,
599 'source_type' => 'submission_item',
600 'source_id' => $submission->id,
601 'component' => 'Payment',
602 'status' => 'info',
603 'title' => __('Stripe Billing Address Logged', 'fluentform'),
604 'description' => __('Billing address from stripe has been logged in the submission data', 'fluentform')
605 ];
606
607 do_action('fluentform/log_data', $logData);
608 }
609
610 protected function processOneTimeSuccess($invoice, $transaction, $paymentStatus)
611 {
612 if ($transaction) {
613 $updateData = [
614 'charge_id' => $invoice->payment_intent ? $invoice->payment_intent->id : null,
615 'status' => 'paid',
616 'payment_note' => maybe_serialize($invoice->payment_intent)
617 ];
618
619 $updateData = array_merge($updateData, $this->retrieveCustomerDetailsFromInvoice($invoice));
620
621 $this->updateTransaction($transaction->id, $updateData);
622
623 $this->changeTransactionStatus($transaction->id, $paymentStatus);
624 }
625 }
626
627 protected function getIntentMetaData($submission, $form, $transaction, $paymentSettings = false)
628 {
629 if (!$paymentSettings) {
630 $paymentSettings = PaymentHelper::getFormSettings($form->id, 'admin');
631 }
632
633 $intentMeta = [
634 'submission_id' => $submission->id,
635 'form_id' => $form->id,
636 'transaction_id' => $transaction->id,
637 'wp_plugin' => 'Fluent Forms Pro',
638 'form_title' => $form->title
639 ];
640
641 $metaItems = ArrayHelper::get($paymentSettings, 'stripe_meta_data', []);
642 if ((ArrayHelper::get($paymentSettings, 'push_meta_to_stripe') == 'yes') && !empty($metaItems)) {
643
644 $metaData = [];
645
646 foreach ($metaItems as $metaItem) {
647 if ($itemValue = ArrayHelper::get($metaItem, 'item_value')) {
648 $metaData[ArrayHelper::get($metaItem, 'label', 'item')] = $itemValue;
649 }
650 }
651
652 $metaData = ShortCodeParser::parse($metaData, $submission->id, $submission->response);
653
654 $metaData = is_array($metaData) ? array_filter($metaData) : [];
655
656 foreach ($metaData as $itemKey => $value) {
657 if (is_string($value) || is_numeric($value)) {
658 $metaData[$itemKey] = wp_strip_all_tags($value);
659 }
660 }
661
662 $intentMeta = array_merge($intentMeta, $metaData);
663 }
664
665 return $intentMeta;
666 }
667
668 protected function retrieveCustomerDetailsFromInvoice($invoice)
669 {
670 $customer = [];
671
672 if (!empty($invoice->payment_intent->charges->data[0])) {
673 $charge = $invoice->payment_intent->charges->data[0];
674
675 $customer = $this->retrieveCustomerDetailsFromCharge($charge);
676
677 $customerName = isset($charge->billing_details->name) &&
678 !empty($charge->billing_details->name) ?
679 $charge->billing_details->name : (
680 isset($invoice->customer_name) &&
681 !empty($invoice->customer_name) ?
682 $invoice->customer_name : ''
683 );
684
685 $customer = array_merge($customer, [
686 'payer_email' => $invoice->customer_email,
687 'payer_name' => $customerName,
688 ]);
689 }
690
691 return $customer;
692 }
693
694 protected function retrieveCustomerDetailsFromCharge($charge)
695 {
696 $customer = [];
697
698 if (!empty($charge->billing_details)) {
699 $customer['billing_address'] = $this->formatAddress($charge->billing_details->address);
700 }
701
702 if (!empty($charge->shipping) && !empty($charge->shipping->address)) {
703 $customer['shipping_address'] = $this->formatAddress($charge->shipping->address);
704 }
705
706 if (!empty($charge->payment_method_details->card)) {
707 $card = $charge->payment_method_details->card;
708 $customer['card_brand'] = $card->brand;
709 $customer['card_last_4'] = $card->last4;
710 }
711
712 return $customer;
713 }
714
715 protected function handlePaymentChargeError($message, $submission, $transaction, $charge = false, $type = 'general')
716 {
717 do_action_deprecated(
718 'fluentform_payment_stripe_failed',
719 [
720 $submission,
721 $transaction,
722 $this->form->id,
723 $charge,
724 $type
725 ],
726 FLUENTFORM_FRAMEWORK_UPGRADE,
727 'fluentform/payment_stripe_failed',
728 'Use fluentform/payment_stripe_failed instead of fluentform_payment_stripe_failed.'
729 );
730
731 do_action('fluentform/payment_stripe_failed', $submission, $transaction, $this->form->id, $charge, $type);
732
733 do_action_deprecated(
734 'fluentform_payment_failed',
735 [
736 $submission,
737 $transaction,
738 $this->form->id,
739 $charge,
740 $type
741 ],
742 FLUENTFORM_FRAMEWORK_UPGRADE,
743 'fluentform/payment_failed',
744 'Use fluentform/payment_failed instead of fluentform_payment_failed.'
745 );
746 do_action('fluentform/payment_failed', $submission, $transaction, $this->form->id, $charge, $type);
747
748 if ($transaction) {
749 $this->changeTransactionStatus($transaction->id, 'failed');
750 }
751
752 $this->changeSubmissionPaymentStatus('failed');
753
754 if ($message) {
755 $logData = [
756 'parent_source_id' => $submission->form_id,
757 'source_type' => 'submission_item',
758 'source_id' => $submission->id,
759 'component' => 'Payment',
760 'status' => 'error',
761 'title' => __('Stripe Payment Error', 'fluentform'),
762 'description' => $message
763 ];
764
765 do_action('fluentform/log_data', $logData);
766 }
767
768 wp_send_json([
769 'errors' => __('Stripe Error: ', 'fluentform') . $message,
770 'append_data' => [
771 '__entry_intermediate_hash' => Helper::getSubmissionMeta($submission->id, '__entry_intermediate_hash')
772 ]
773 ], 423);
774 }
775
776 public function recordSubscriptionCharge($subscription, $transactionData)
777 {
778 $this->setSubmissionId($subscription->submission_id);
779 return $this->maybeInsertSubscriptionCharge($transactionData);
780 }
781 }
782