PluginProbe
Fluent Forms – Customizable Contact Forms, Survey, Quiz, & Conversational Form Builder / 6.2.7
Fluent Forms – Customizable Contact Forms, Survey, Quiz, & Conversational Form Builder v6.2.7
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 / PaymentHandler.php

PaymentHandler.php in Fluent Forms – Customizable Contact Forms, Survey, Quiz, & Conversational Form Builder 6.2.7, at app/Modules/Payments/PaymentHandler.php

739 lines 30.1 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;
4
5 if (!defined('ABSPATH')) {
6 exit; // Exit if accessed directly.
7 }
8
9 use FluentForm\App\Helpers\Helper;
10 use FluentForm\App\Modules\Acl\Acl;
11 use FluentForm\App\Modules\Form\FormFieldsParser;
12 use FluentForm\App\Modules\Payments\Orders\OrderData;
13 use FluentForm\App\Services\FormBuilder\ShortCodeParser;
14 use FluentForm\Framework\Helpers\ArrayHelper;
15 use FluentForm\App\Modules\Payments\Classes\PaymentAction;
16 use FluentForm\App\Modules\Payments\Classes\PaymentEntries;
17 use FluentForm\App\Modules\Payments\Classes\PaymentReceipt;
18 use FluentForm\App\Modules\Payments\Components\CustomPaymentComponent;
19 use FluentForm\App\Modules\Payments\Components\ItemQuantity;
20 use FluentForm\App\Modules\Payments\Components\MultiPaymentComponent;
21 use FluentForm\App\Modules\Payments\Components\PaymentMethods;
22 use FluentForm\App\Modules\Payments\Components\PaymentSummaryComponent;
23 use FluentForm\App\Modules\Payments\Components\Subscription;
24 use FluentForm\App\Modules\Payments\PaymentMethods\Stripe\Components\StripeInline;
25 use FluentForm\App\Modules\Payments\PaymentMethods\Stripe\ConnectConfig;
26 use FluentForm\App\Modules\Payments\PaymentMethods\Stripe\StripeHandler;
27 use FluentForm\App\Modules\Payments\PaymentMethods\Stripe\StripeSettings;
28
29 class PaymentHandler
30 {
31 public function init()
32 {
33
34 add_filter('fluentform/global_settings_components', [$this, 'pushGlobalSettings'], 1, 1);
35
36 add_filter('fluentform/global_settings_component_settings_data', [$this, 'getGlobalSettingsPaymentVars']);
37
38 add_action('wp_ajax_fluentform_handle_payment_ajax_endpoint', [$this, 'handleAjaxEndpoints']);
39
40 if (!$this->isEnabled()) {
41 return;
42 }
43
44 add_filter('fluentform/show_payment_entries', '__return_true');
45
46 add_filter('fluentform/form_settings_menu', array($this, 'maybeAddPaymentSettings'), 10, 2);
47 // Let's load Payment Methods here
48 (new StripeHandler())->init();
49
50 // Let's load the payment method component here
51 new MultiPaymentComponent();
52 new Subscription();
53 new CustomPaymentComponent();
54 new ItemQuantity();
55 new PaymentMethods();
56 new PaymentSummaryComponent();
57
58 add_filter('fluentform/editor_components', function ($components) {
59 if (!Helper::hasPro()) {
60 $components['payments'][] = [
61 'index' => 6,
62 'element' => 'payment_coupon',
63 'attributes' => [],
64 'settings' => [],
65 'editor_options' => [
66 'title' => __('Coupon', 'fluentform'),
67 'icon_class' => 'el-icon-postcard',
68 'template' => 'inputText',
69 ],
70 ];
71 }
72 return $components;
73 }, 11);
74
75 new StripeInline();
76
77 add_action('fluentform/before_insert_payment_form', array($this, 'maybeHandlePayment'), 10, 3);
78
79 add_filter('fluentform/submission_order_data', function ($data, $submission) {
80 return OrderData::getSummary($submission, $submission->form);
81 }, 10, 2);
82
83 add_filter('fluentform/entries_vars', function ($vars, $form) {
84 if ($form->has_payment) {
85 $vars['has_payment'] = $form->has_payment;
86 $vars['currency_config'] = PaymentHelper::getCurrencyConfig($form->id);
87 $vars['currency_symbols'] = PaymentHelper::getCurrencySymbols();
88 $vars['payment_statuses'] = PaymentHelper::getPaymentStatuses();
89 }
90 return $vars;
91 }, 10, 2);
92
93 add_filter(
94 'fluentform/submission_labels',
95 [$this, 'modifySingleEntryLabels'],
96 10,
97 3
98 );
99
100
101 add_filter('fluentform/all_entry_labels_with_payment', array($this, 'modifySingleEntryLabels'), 10, 3);
102
103 add_action('fluentform/rendering_payment_form', function ($form) {
104 if (Helper::isElementorEditor()) {
105 return;
106 }
107
108 $src = fluentFormMix('js/payment_handler.js');
109 $version = FLUENTFORM_VERSION;
110
111 // If pro is installed and script is compatible, load script from pro
112 if (Helper::isProPaymentScriptCompatible()) {
113 $src = FLUENTFORMPRO_DIR_URL . 'public/js/payment_handler_pro.js';
114 $version = FLUENTFORMPRO_VERSION;
115 }
116
117 wp_enqueue_script('fluentform-payment-handler',
118 $src,
119 array('jquery'),
120 $version,
121 true
122 );
123
124 wp_enqueue_style(
125 'fluentform-payment-skin',
126 fluentFormMix('css/payment_skin.css'),
127 array(),
128 FLUENTFORM_VERSION
129 );
130
131 wp_localize_script('fluentform-payment-handler', 'fluentform_payment_config', [
132 'i18n' => [
133 'item' => __('Item', 'fluentform'),
134 'price' => __('Price', 'fluentform'),
135 'qty' => __('Qty', 'fluentform'),
136 'line_total' => __('Line Total', 'fluentform'),
137 'total' => __('Total', 'fluentform'),
138 'not_found' => __('No payment item selected yet', 'fluentform'),
139 'discount:' => __('Discount:', 'fluentform'),
140 'processing_text' => __('Processing payment. Please wait...', 'fluentform'),
141 'confirming_text' => __('Confirming payment. Please wait...', 'fluentform'),
142 /* translators: %s is the item name */
143 'Signup Fee for %s' => __('Signup Fee for %s', 'fluentform'),
144 /* translators: 1: item name, 2: plan name */
145 'Signup Fee for %1$s - %2$s' => __('Signup Fee for %1$s - %2$s', 'fluentform'),
146 ]
147 ]);
148
149 $secretKey = apply_filters_deprecated(
150 'fluentform-payment_stripe_publishable_key',
151 [
152 StripeSettings::getPublishableKey($form->id),
153 $form->id
154 ],
155 FLUENTFORM_FRAMEWORK_UPGRADE,
156 'fluentform/payment_stripe_publishable_key',
157 'Use fluentform/payment_stripe_publishable_key instead of fluentform-payment_stripe_publishable_key.'
158 );
159
160 $publishableKey = apply_filters('fluentform/payment_stripe_publishable_key', $secretKey, $form->id);
161
162 $stripeCustomCss = [
163 'styles' => [
164 'base' => [
165 'backgroundColor' => 'white',
166 'color' => '#32325d',
167 'fontFamily' => "-apple-system, \"system-ui\", \"Segoe UI\", Roboto, Oxygen-Sans, Ubuntu, Cantarell, \"Helvetica Neue\", sans-serif",
168 'fontSize' => '14px',
169 'fontSmoothing' => 'antialiased',
170 'iconColor' => '#32325d',
171 'textDecoration' => 'none',
172 '::placeholder' => [
173 'color'=> "#aab7c4"
174 ],
175 ":focus" => [
176 'backgroundColor' => 'white',
177 'color' => '#32325d',
178 'fontFamily' => "-apple-system, \"system-ui\", \"Segoe UI\", Roboto, Oxygen-Sans, Ubuntu, Cantarell, \"Helvetica Neue\", sans-serif",
179 'fontSize' => '14px',
180 'fontSmoothing' => 'antialiased',
181 'iconColor' => '#32325d',
182 'textDecoration' => 'none',
183 ],
184 ],
185 'invalid' => [
186 'color' => "#fa755a",
187 'iconColor' => "#fa755a"
188 ]
189 ]
190 ];
191
192 $paymentConfig = [
193 'currency_settings' => PaymentHelper::getCurrencyConfig($form->id),
194 'stripe' => [
195 'publishable_key' => $publishableKey,
196 'inlineConfig' => PaymentHelper::getStripeInlineConfig($form->id),
197 'custom_style' => apply_filters(
198 'fluentform/stripe_inline_custom_css',
199 $stripeCustomCss,
200 $form->id
201 ),
202 'locale' => 'en'
203 ],
204 'stripe_app_info' => [
205 'name' => 'Fluent Forms',
206 'version' => FLUENTFORM_VERSION,
207 'url' => site_url(),
208 'partner_id' => 'pp_partner_FN62GfRLM2Kx5d'
209 ],
210 ];
211 $paymentConfig = apply_filters('fluentform/payment_config', $paymentConfig, $form->id);
212
213 wp_localize_script('fluentform-payment-handler', 'fluentform_payment_config_' . $form->id, $paymentConfig);
214
215 }, 11, 1);
216
217 // phpcs:disable WordPress.Security.NonceVerification.Recommended -- Public payment callback from gateway, nonce not applicable, verified by transaction_hash in validateFrameLessPage()
218 if (isset($_GET['fluentform_payment']) && isset($_GET['payment_method'])) {
219 add_action('wp', function () {
220 $data = $_GET; // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- Data sanitized below and verified by validateFrameLessPage()
221
222 $type = isset($_GET['fluentform_payment']) ? sanitize_text_field(wp_unslash($_GET['fluentform_payment'])) : '';
223
224 if ($type == 'view' && $route = ArrayHelper::get($data, 'route')) {
225 do_action_deprecated(
226 'fluent_payment_view_' . $route,
227 [
228 $data
229 ],
230 FLUENTFORM_FRAMEWORK_UPGRADE,
231 'fluentform/payment_view_' . $route,
232 'Use fluentform/payment_view_' . $route . ' instead of fluent_payment_view_' . $route
233 );
234 do_action('fluentform/payment_view_' . $route, $data);
235 }
236
237 $this->validateFrameLessPage($data);
238 $paymentMethod = isset($_GET['payment_method']) ? sanitize_text_field(wp_unslash($_GET['payment_method'])) : '';
239 do_action_deprecated(
240 'fluent_payment_frameless_' . $paymentMethod,
241 [
242 $data
243 ],
244 FLUENTFORM_FRAMEWORK_UPGRADE,
245 'fluentform/payment_frameless_' . $paymentMethod,
246 'Use fluentform/payment_frameless_' . $paymentMethod . ' instead of fluent_payment_frameless_' . $paymentMethod
247 );
248 do_action('fluentform/payment_frameless_' . $paymentMethod, $data);
249 });
250 }
251 // phpcs:enable WordPress.Security.NonceVerification.Recommended -- End of payment callback processing
252
253 // phpcs:disable WordPress.Security.NonceVerification.Recommended -- IPN callback from payment gateway, verified by gateway signature
254 if (isset($_REQUEST['fluentform_payment_api_notify'])) {
255 add_action('wp', function () {
256 $paymentMethod = isset($_REQUEST['payment_method']) ? sanitize_text_field(wp_unslash($_REQUEST['payment_method'])) : '';
257 do_action_deprecated(
258 'fluentform_ipn_endpoint_' . $paymentMethod,
259 [
260 ],
261 FLUENTFORM_FRAMEWORK_UPGRADE,
262 'fluentform/ipn_endpoint_' . $paymentMethod,
263 'Use fluentform/ipn_endpoint_' . $paymentMethod . ' instead of fluentform_ipn_endpoint_' . $paymentMethod
264 );
265 do_action('fluentform/ipn_endpoint_' . $paymentMethod);
266 });
267 }
268 // phpcs:enable WordPress.Security.NonceVerification.Recommended -- End of IPN webhook processing
269
270 add_filter('fluentform/editor_vars', function ($vars) {
271 $settings = PaymentHelper::getCurrencyConfig($vars['form_id']);
272 $vars['payment_settings'] = $settings;
273 $vars['has_payment_features'] = !!$settings;
274 return $vars;
275 });
276
277 add_filter('fluentform/admin_i18n', array($this, 'paymentTranslations'), 10, 1);
278
279 add_filter('fluentform/payment_smartcode', array($this, 'paymentReceiptView'), 10, 3);
280
281 add_action('user_register', array($this, 'maybeAssignTransactions'), 99, 1);
282
283 (new PaymentEntries())->init();
284
285 /*
286 * Transactions and subscriptions Shortcode
287 */
288 (new TransactionShortcodes())->init();
289
290 add_filter(
291 'fluentform/validate_input_item_subscription_payment_component',
292 [$this, 'validateSubscriptionInputs'],
293 10,
294 3
295 );
296
297 add_filter(
298 'fluentform/validate_input_item_multi_payment_component',
299 [$this, 'validatePaymentInputs'],
300 10,
301 3
302 );
303
304 add_filter(
305 'fluentform/validate_input_item_payment_method',
306 [$this, 'validatePaymentMethod'],
307 10,
308 5
309 );
310 }
311
312 public function pushGlobalSettings($components)
313 {
314 $subMenuItems = [
315 [
316 'title' => 'Settings',
317 'hash' => 'payments/general_settings',
318 ],
319 [
320 'title' => 'Payment Methods',
321 'hash' => 'payments/payment_methods',
322 ]
323 ];
324 $subMenuItems = apply_filters('fluentform/global_settings_payment_sub_menu_items', $subMenuItems);
325
326 $components['payment_settings'] = [
327 'title' => __('Payment Settings', 'fluentform'),
328 'sub_menu'=> $subMenuItems
329 ];
330 return $components;
331 }
332
333 public function getGlobalSettingsPaymentVars($globalSettingVars)
334 {
335 // phpcs:disable WordPress.Security.NonceVerification.Recommended -- Admin page, nonce verified by WordPress admin
336 if (isset($_GET['ff_stripe_connect'])) {
337 $data = ArrayHelper::only($_GET, ['ff_stripe_connect', 'mode', 'state', 'code']);
338 ConnectConfig::verifyAuthorizeSuccess($data);
339 }
340
341 $paymentSettings = PaymentHelper::getPaymentSettings();
342 $isSettingsAvailable = PaymentHelper::hasPaymentSettings();
343
344 $nav = 'general';
345
346 if (isset($_REQUEST['nav'])) {
347 $nav = sanitize_text_field(wp_unslash($_REQUEST['nav']));
348 }
349 // phpcs:enable WordPress.Security.NonceVerification.Recommended -- End of admin page GET parameter processing
350
351 $paymentMethods = apply_filters_deprecated(
352 'fluentformpro_available_payment_methods',
353 [
354 []
355 ],
356 FLUENTFORM_FRAMEWORK_UPGRADE,
357 'fluentform/available_payment_methods',
358 'Use fluentform/available_payment_methods instead of fluentformpro_available_payment_methods.'
359 );
360
361 $globalSettings = apply_filters_deprecated(
362 'fluentformpro_payment_methods_global_settings',
363 [
364 []
365 ],
366 FLUENTFORM_FRAMEWORK_UPGRADE,
367 'fluentform/payment_methods_global_settings',
368 'Use fluentform/payment_methods_global_settings instead of fluentformpro_payment_methods_global_settings.'
369 );
370
371 $paymentVars = [
372 'is_setup' => $isSettingsAvailable,
373 'general' => $paymentSettings,
374 'payment_methods' => apply_filters('fluentform/available_payment_methods', $paymentMethods),
375 'available_payment_methods' => apply_filters('fluentform/payment_methods_global_settings', $globalSettings),
376 'currencies' => PaymentHelper::getCurrencies(),
377 'active_nav' => $nav,
378 'stripe_webhook_url' => add_query_arg([
379 'fluentform_payment_api_notify' => '1',
380 'payment_method' => 'stripe'
381 ], site_url('index.php')),
382 'paypal_webhook_url' => add_query_arg([
383 'fluentform_payment_api_notify' => '1',
384 'payment_method' => 'paypal'
385 ], site_url('index.php'))
386 ];
387
388 // Enqueue payment global settings css
389 wp_enqueue_style('ff-payment-settings', fluentFormMix('css/payment_settings.css'), [], FLUENTFORM_VERSION);
390
391 $globalSettingVars['payment_vars'] = apply_filters('fluentform/global_settings_component_payment_vars', $paymentVars);
392 return $globalSettingVars;
393 }
394
395 public function handleAjaxEndpoints()
396 {
397 // phpcs:disable WordPress.Security.NonceVerification.Recommended -- Nonce verified by Acl::verify()
398 $route = isset($_REQUEST['route']) ? sanitize_text_field(wp_unslash($_REQUEST['route'])) : '';
399 $paymentMutationRoutes = [
400 'update_transaction',
401 'cancel_subscription'
402 ];
403 $formSettingRoutes = [
404 'get_form_settings',
405 'save_form_settings'
406 ];
407
408 if (in_array($route, $paymentMutationRoutes, true)) {
409 Acl::verify('fluentform_manage_payments', $this->resolveRouteFormId($route));
410 } elseif (in_array($route, $formSettingRoutes, true)) {
411 Acl::verify('fluentform_forms_manager', $this->resolveRouteFormId($route));
412 } else {
413 Acl::verify('fluentform_settings_manager');
414 }
415 // phpcs:enable WordPress.Security.NonceVerification.Recommended -- End of AJAX endpoint nonce verification by Acl::verify()
416
417 (new AjaxEndpoints())->handleEndpoint($route);
418 }
419
420 private function resolveRouteFormId($route)
421 {
422 switch ($route) {
423 case 'get_form_settings':
424 case 'save_form_settings':
425 return Acl::verifyFormId(wpFluentForm()->request->get('form_id'));
426 case 'update_transaction':
427 return $this->resolveTransactionFormId();
428 case 'cancel_subscription':
429 return $this->resolveSubscriptionFormId();
430 default:
431 return null;
432 }
433 }
434
435 private function resolveTransactionFormId()
436 {
437 $transactionData = wpFluentForm()->request->get('transaction', []);
438 $transactionId = absint(ArrayHelper::get($transactionData, 'id'));
439
440 if (!$transactionId) {
441 return -1;
442 }
443
444 $transaction = \FluentForm\App\Models\Transaction::select('form_id')->find($transactionId);
445
446 return $transaction ? (int) $transaction->form_id : -1;
447 }
448
449 private function resolveSubscriptionFormId()
450 {
451 $subscriptionId = absint(wpFluentForm()->request->get('subscription_id'));
452
453 if (!$subscriptionId) {
454 return -1;
455 }
456
457 $subscription = \FluentForm\App\Models\Subscription::select('form_id')->find($subscriptionId);
458
459 return $subscription ? (int) $subscription->form_id : -1;
460 }
461
462 public function maybeHandlePayment($insertData, $data, $form)
463 {
464 // Let's get selected Payment Method
465 if (!FormFieldsParser::hasPaymentFields($form)) {
466 return;
467 }
468
469 $paymentAction = new PaymentAction($form, $insertData, $data);
470
471 if (!$paymentAction->getSubscriptionItems() && !$paymentAction->getCalculatedAmount()) {
472 return;
473 }
474
475 /*
476 * We have to check if
477 * 1. has payment method
478 * 2. if user selected payment method
479 * 3. or maybe has a conditional logic on it
480 */
481 if ($paymentAction->isConditionPass()) {
482 if (FormFieldsParser::hasElement($form, 'payment_method') &&
483 !$paymentAction->selectedPaymentMethod
484 ) {
485 wp_send_json([
486 'errors' => [__('Sorry! No selected payment method found. Please select a valid payment method', 'fluentform')]
487 ], 423);
488 }
489 }
490
491 /*
492 * Some Payment Gateway like Razorpay, Square not supported $subscriptionItems.
493 * So we are providing filter hook to validate payment fields.
494 */
495 $errors = apply_filters(
496 'fluentform/validate_payment_items_' . $paymentAction->selectedPaymentMethod,
497 [],
498 $paymentAction->getOrderItems(),
499 $paymentAction->getSubscriptionItems(),
500 $form
501 );
502
503 if ($errors) {
504 wp_send_json([
505 'errors' => $errors
506 ], 423);
507 }
508
509 $paymentAction->draftFormEntry();
510 }
511
512 public function isEnabled()
513 {
514 $paymentSettings = PaymentHelper::getPaymentSettings();
515 return $paymentSettings['status'] == 'yes';
516 }
517
518 public function modifySingleEntryLabels($labels, $submission, $form)
519 {
520 $formFields = FormFieldsParser::getPaymentFields($form);
521 if ($formFields && is_array($formFields)) {
522 $labels = ArrayHelper::except($labels, array_keys($formFields));
523 }
524 return $labels;
525 }
526
527 public function maybeAddPaymentSettings($menus, $formId)
528 {
529 $form = \FluentForm\App\Models\Form::find($formId);
530 if ($form->has_payment) {
531 $menus = array_merge(array_slice($menus, 0, 1), array(
532 'payment_settings' => [
533 'title' => __('Payment Settings', 'fluentform'),
534 'slug' => 'form_settings',
535 'hash' => 'payment_settings',
536 'route' => '/payment-settings',
537 ]
538 ), array_slice($menus, 1));
539 }
540 return $menus;
541 }
542
543
544 /**
545 * @param $html string
546 * @param $property string
547 * @param $instance ShortCodeParser
548 * @return false|string
549 */
550 public function paymentReceiptView($html, $property, $instance)
551 {
552 $entry = $instance::getEntry();
553 $receiptClass = new PaymentReceipt($entry);
554 return $receiptClass->getItem($property);
555 }
556
557 private function validateFrameLessPage($data)
558 {
559 // We should verify the transaction hash from the URL
560 $transactionHash = sanitize_text_field(ArrayHelper::get($data, 'transaction_hash'));
561 $submissionId = intval(ArrayHelper::get($data, 'fluentform_payment'));
562 if (!$submissionId) {
563 die('Validation Failed');
564 }
565
566 if ($transactionHash) {
567 $transaction = \FluentForm\App\Models\Transaction::bySubmission($submissionId)
568 ->where('transaction_hash', $transactionHash)
569 ->first();
570 if ($transaction) {
571 return true;
572 }
573
574 die('Transaction hash is invalid');
575 }
576
577 $uid = sanitize_text_field(ArrayHelper::get($data, 'entry_uid'));
578 if (!$uid) {
579 die('Validation Failed');
580 }
581
582 $originalUid = Helper::getSubmissionMeta($submissionId, '_entry_uid_hash');
583
584 if ($originalUid != $uid) {
585 die(esc_html__('Transaction UID is invalid', 'fluentform'));
586 }
587
588 return true;
589 }
590
591 public function maybeAssignTransactions($userId)
592 {
593 $user = get_user_by('ID', $userId);
594 if (!$user) {
595 return false;
596 }
597 $userEmail = $user->user_email;
598
599 $transactions = \FluentForm\App\Models\Transaction::where('payer_email', $userEmail)
600 ->where(function ($query) {
601 $query->whereNull('user_id')
602 ->orWhere('user_id', '');
603 })
604 ->get();
605
606 if (count($transactions) === 0) {
607 return false;
608 }
609
610 $submissionIds = [];
611 $transactionIds = [];
612 foreach ($transactions as $transaction) {
613 $submissionIds[] = $transaction->submission_id;
614 $transactionIds[] = $transaction->id;
615 }
616
617 $submissionIds = array_unique($submissionIds);
618 $transactionIds = array_unique($transactionIds);
619
620 \FluentForm\App\Models\Submission::whereIn('id', $submissionIds)
621 ->update([
622 'user_id' => $userId,
623 'updated_at' => current_time('mysql')
624 ]);
625
626 \FluentForm\App\Models\Transaction::whereIn('id', $transactionIds)
627 ->update([
628 'user_id' => $userId,
629 'updated_at' => current_time('mysql')
630 ]);
631
632 return true;
633 }
634
635 public function paymentTranslations($i18n)
636 {
637 $paymentI18n = array(
638 'Order Details' => __('Order Details', 'fluentform'),
639 'Product' => __('Product', 'fluentform'),
640 'Qty' => __('Qty', 'fluentform'),
641 'Unit Price' => __('Unit Price', 'fluentform'),
642 'Total' => __('Total', 'fluentform'),
643 'Sub-Total' => __('Sub-Total', 'fluentform'),
644 'Discount' => __('Discount', 'fluentform'),
645 'Price' => __('Price', 'fluentform'),
646 'Payment Details' => __('Payment Details', 'fluentform'),
647 'From Subscriptions' => __('From Subscriptions', 'fluentform'),
648 'Card Last 4' => __('Card Last 4', 'fluentform'),
649 'Payment Total' => __('Payment Total', 'fluentform'),
650 'Payment Status' => __('Payment Status', 'fluentform'),
651 'Transaction ID' => __('Transaction ID', 'fluentform'),
652 'Payment Method' => __('Payment Method', 'fluentform'),
653 'Transaction' => __('Transaction', 'fluentform'),
654 'Refunds' => __('Refunds', 'fluentform'),
655 'Refund' => __('Refund', 'fluentform'),
656 'at' => __('at', 'fluentform'),
657 'View' => __('View', 'fluentform'),
658 'has been refunded via' => __('has been refunded via', 'fluentform'),
659 'Note' => __('Note', 'fluentform'),
660 'Edit Transaction' => __('Edit Transaction', 'fluentform'),
661 'Billing Name' => __('Billing Name', 'fluentform'),
662 'Billing Email' => __('Billing Email', 'fluentform'),
663 'Billing Address' => __('Billing Address', 'fluentform'),
664 'Shipping Address' => __('Shipping Address', 'fluentform'),
665 'Reference ID' => __('Reference ID', 'fluentform'),
666 'refunds-to-be-handled-from-provider-text' => __('Please note that, Actual Refund needs to be handled in your Payment Service Provider.', 'fluentform'),
667 'Please Provide new refund amount only.' => __('Please Provide new refund amount only.', 'fluentform'),
668 'Refund Note' => __('Refund Note', 'fluentform'),
669 'Cancel' => __('Cancel', 'fluentform'),
670 'Confirm' => __('Confirm', 'fluentform'),
671 );
672 return array_merge($i18n,$paymentI18n);
673 }
674
675 public function validateSubscriptionInputs($error, $field, $formData)
676 {
677 if (isset($formData[$field['name']])) {
678 $subscriptionOptions = ArrayHelper::get($field, 'raw.settings.subscription_options', []);
679 $selectedPlanIndex = $formData[$field['name']];
680 $acceptedSubscriptionPlan = is_numeric($selectedPlanIndex) && in_array($selectedPlanIndex, array_keys($subscriptionOptions));
681 if (!$acceptedSubscriptionPlan) {
682 $error = __('This subscription plan is invalid', 'fluentform');
683 }
684 $selectedPlan = ArrayHelper::get($subscriptionOptions, $selectedPlanIndex, []);
685 if ('yes' === ArrayHelper::get($selectedPlan, 'user_input')) {
686 $userGivenValue = ArrayHelper::get($formData, "{$field['name']}_custom_$selectedPlanIndex");
687 $userGivenValue = $userGivenValue ?: 0;
688 $planMinValue = ArrayHelper::get($selectedPlan, 'user_input_min_value');
689 if (!is_numeric($userGivenValue) || ($planMinValue && $userGivenValue < $planMinValue)) {
690 $error = __('This subscription plan value is invalid', 'fluentform');
691 }
692 }
693 }
694
695 return $error;
696 }
697
698 public function validatePaymentInputs($error, $field, $formData)
699 {
700 if (ArrayHelper::get($formData, $field['name'])) {
701 $fieldType = ArrayHelper::get($field, 'raw.attributes.type');
702
703 if (in_array($fieldType, ['radio', 'select', 'checkbox'])) {
704 $pricingOptions = array_column(
705 ArrayHelper::get($field, 'raw.settings.pricing_options', []),
706 'label'
707 );
708
709 $pricingOptions = array_map('sanitize_text_field', $pricingOptions);
710
711 if (in_array($fieldType, ['radio', 'select'])) {
712 $acceptedPaymentPlan = in_array($formData[$field['name']], $pricingOptions);
713 } else {
714 $acceptedPaymentPlan = array_diff($formData[$field['name']], $pricingOptions);
715
716 $acceptedPaymentPlan = empty($acceptedPaymentPlan);
717 }
718
719 if (!$acceptedPaymentPlan) {
720 $error = __('This payment item is invalid', 'fluentform');
721 }
722 }
723 }
724
725 return $error;
726 }
727
728 public function validatePaymentMethod($error, $field, $formData, $fields, $form)
729 {
730 if ($selectedMethod = ArrayHelper::get($formData, $field['name'])) {
731 $activeMethods = array_keys(PaymentHelper::getFormPaymentMethods($form->id));
732 if (!in_array($selectedMethod, $activeMethods)) {
733 $error = __('This payment method is invalid', 'fluentform');
734 }
735 }
736 return $error;
737 }
738 }
739