PluginProbe
Formidable Forms – WordPress Form Builder for Contact Forms, Calculators, Quizzes & More / 6.25.1
Formidable Forms – WordPress Form Builder for Contact Forms, Calculators, Quizzes & More v6.25.1
6.35 6.34 6.33.1 6.33 6.32.1 6.32 6.31 6.25 6.25.1 6.26 6.26.1 6.27 6.28 6.29 6.3 6.3.1 6.3.2 6.30 6.4 6.4.1 6.4.2 6.5 6.5.1 6.5.2 6.5.3 All 141 releases
formidable / square / controllers / FrmSquareLiteActionsController.php

FrmSquareLiteActionsController.php in Formidable Forms – WordPress Form Builder for Contact Forms, Calculators, Quizzes & More 6.25.1, at square/controllers/FrmSquareLiteActionsController.php

687 lines 19.2 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 if ( ! defined( 'ABSPATH' ) ) {
3 die( 'You are not allowed to call this page directly.' );
4 }
5
6 class FrmSquareLiteActionsController extends FrmTransLiteActionsController {
7
8 /**
9 * @since 6.22
10 *
11 * @param string $callback
12 * @param array|false|object $field
13 * @return string
14 */
15 public static function maybe_show_card( $callback, $field = false ) {
16 if ( false === $field ) {
17 // Pro isn't up to date.
18 return $callback;
19 }
20
21 $form_id = is_object( $field ) ? $field->form_id : $field['form_id'];
22 $actions = self::get_actions_before_submit( $form_id );
23 if ( empty( $actions ) ) {
24 return $callback;
25 }
26
27 $field_id = is_object( $field ) ? $field->id : $field['id'];
28 foreach ( $actions as $action ) {
29 if ( (int) $action->post_content['credit_card'] === (int) $field_id ) {
30 return self::class . '::show_card';
31 }
32 }
33
34 return $callback;
35 }
36
37 /**
38 * Override the credit card field HTML if there is a Square action.
39 *
40 * @since 6.22
41 *
42 * @param array $field
43 * @param string $field_name
44 * @param array $atts
45 * @return void
46 */
47 public static function show_card( $field, $field_name, $atts ) {
48 $actions = self::get_actions_before_submit( $field['form_id'] );
49
50 if ( $actions ) {
51 self::load_scripts( (int) $field['form_id'] );
52
53 $html_id = $atts['html_id'];
54 include FrmStrpLiteAppHelper::plugin_path() . '/views/payments/card-field.php';
55 return;
56 }
57
58 // Use the Pro function when there are no Stripe actions.
59 // This is required for other gateways like Authorize.Net.
60 if ( is_callable( 'FrmProCreditCardsController::show_in_form' ) ) {
61 FrmProCreditCardsController::show_in_form( $field, $field_name, $atts );
62 }
63 }
64
65 /**
66 * Get all published payment actions with the Square gateway that have an amount set.
67 *
68 * @since 6.22
69 *
70 * @param int|string $form_id
71 * @return array
72 */
73 public static function get_actions_before_submit( $form_id ) {
74 $payment_actions = self::get_actions_for_form( $form_id );
75 foreach ( $payment_actions as $k => $payment_action ) {
76 $gateway = $payment_action->post_content['gateway'];
77 $is_square = $gateway === 'square' || ( is_array( $gateway ) && in_array( 'square', $gateway, true ) );
78 if ( ! $is_square || empty( $payment_action->post_content['amount'] ) ) {
79 unset( $payment_actions[ $k ] );
80 }
81 }
82 return $payment_actions;
83 }
84
85 /**
86 * Trigger a Square payment after a form is submitted.
87 * This is called for both one time and recurring payments.
88 *
89 * @param WP_Post $action
90 * @param stdClass $entry
91 * @param mixed $form
92 * @return array
93 */
94 public static function trigger_gateway( $action, $entry, $form ) {
95 $response = array(
96 'success' => false,
97 'run_triggers' => false,
98 'show_errors' => true,
99 );
100 $atts = compact( 'action', 'entry', 'form' );
101
102 $amount = self::prepare_amount( $action->post_content['amount'], $atts );
103 if ( empty( $amount ) || $amount == 000 ) {
104 $response['error'] = __( 'Please specify an amount for the payment', 'formidable' );
105 return $response;
106 }
107
108 if ( ! self::square_is_configured() ) {
109 $response['error'] = __( 'There was a problem communicating with Square. Please try again.', 'formidable' );
110 return $response;
111 }
112
113 $payment_args = compact( 'form', 'entry', 'action', 'amount' );
114
115 // Attempt to charge the customer's card.
116 if ( 'recurring' === $action->post_content['type'] ) {
117 $charge = self::trigger_recurring_payment( $payment_args );
118 } else {
119 $charge = self::trigger_one_time_payment( $payment_args );
120 }
121
122 if ( $charge === true ) {
123 $response['success'] = true;
124 } else {
125 $response['error'] = $charge;
126 }
127
128 return $response;
129 }
130
131 /**
132 * Trigger a one time payment.
133 *
134 * @param array $atts The arguments for the payment.
135 * @return string|true string on error, true on success.
136 */
137 private static function trigger_one_time_payment( $atts ) {
138 if ( empty( $_POST['square-token'] ) || empty( $_POST['square-verification-token'] ) ) { // phpcs:ignore WordPress.Security.NonceVerification.Missing
139 return __( 'Please enter a valid credit card', 'formidable' );
140 }
141
142 $currency = strtoupper( $atts['action']->post_content['currency'] );
143 $square_token = sanitize_text_field( $_POST['square-token'] ); // phpcs:ignore WordPress.Security.NonceVerification.Missing
144 $verification_token = sanitize_text_field( $_POST['square-verification-token'] ); // phpcs:ignore WordPress.Security.NonceVerification.Missing
145 $description = FrmTransLiteAppHelper::process_shortcodes(
146 array(
147 'entry' => $atts['entry'],
148 'form' => $atts['entry']->form_id,
149 'value' => $atts['action']->post_content['description'],
150 )
151 );
152 $result = FrmSquareLiteConnectHelper::create_payment( $atts['amount'], $currency, $square_token, $verification_token, $description );
153
154 if ( false === $result ) {
155 return FrmSquareLiteConnectHelper::get_latest_error_from_square_api();
156 }
157
158 $atts['status'] = $result->status === 'COMPLETED' ? 'complete' : 'failed';
159 $atts['charge'] = new stdClass();
160 $atts['charge']->id = $result->id;
161 $atts['charge']->amount = $atts['amount'];
162
163 $payment_id = self::create_new_payment( $atts );
164 $frm_payment = new FrmTransLitePayment();
165 $payment = $frm_payment->get_one( $payment_id );
166 $status = $atts['status'];
167
168 FrmTransLiteActionsController::trigger_payment_status_change( compact( 'status', 'payment' ) );
169
170 return true;
171 }
172
173 /**
174 * Add a payment row for the payments table.
175 *
176 * @param array $atts The arguments for the payment.
177 * @return int
178 */
179 private static function create_new_payment( $atts ) {
180 $atts['charge'] = (object) $atts['charge'];
181
182 $new_values = array(
183 'amount' => FrmTransLiteAppHelper::get_formatted_amount_for_currency( $atts['charge']->amount, $atts['action'] ),
184 'status' => $atts['status'],
185 'paysys' => 'square',
186 'item_id' => $atts['entry']->id,
187 'action_id' => $atts['action']->ID,
188 'receipt_id' => $atts['charge']->id,
189 'sub_id' => isset( $atts['charge']->sub_id ) ? $atts['charge']->sub_id : '',
190 'test' => 'test' === FrmSquareLiteAppHelper::active_mode() ? 1 : 0,
191 );
192
193 $frm_payment = new FrmTransLitePayment();
194 $payment_id = $frm_payment->create( $new_values );
195 return $payment_id;
196 }
197
198 /**
199 * Create a new Square subscription and a subscription and payment for the payments tables.
200 *
201 * @param array $atts Includes 'customer', 'entry', 'action', 'amount'.
202 * @return bool|string True on success, error message on failure
203 */
204 private static function trigger_recurring_payment( $atts ) {
205 if ( empty( $_POST['square-token'] ) || empty( $_POST['square-verification-token'] ) ) { // phpcs:ignore WordPress.Security.NonceVerification.Missing
206 return __( 'Please enter a valid credit card', 'formidable' );
207 }
208
209 $currency = strtoupper( $atts['action']->post_content['currency'] );
210 $square_token = sanitize_text_field( $_POST['square-token'] ); // phpcs:ignore WordPress.Security.NonceVerification.Missing
211 $verification_token = sanitize_text_field( $_POST['square-verification-token'] ); // phpcs:ignore WordPress.Security.NonceVerification.Missing
212
213 // We can put this all behind our API.
214 // It will require that we pass the customer info and the catalog info.
215 // 1. Call the API with the customer and catalog info.
216 // 2. Add the database rows.
217
218 $action = $atts['action'];
219 $billing_contact = FrmSquareLiteAppController::get_billing_contact( $action );
220
221 $info = array(
222 'payment' => array(
223 'token' => $square_token,
224 'verificationToken' => $verification_token,
225 ),
226 'customer' => array(
227 'givenName' => $billing_contact['givenName'],
228 'familyName' => $billing_contact['familyName'],
229 'emailAddress' => $billing_contact['email'],
230 ),
231 'catalog' => array(
232 'name' => self::prepare_subscription_description( $action->post_content['description'], $atts ),
233 'trialDays' => $action->post_content['trial_interval_count'],
234 'limit' => $action->post_content['payment_limit'],
235 'amount' => $atts['amount'],
236 'currency' => $currency,
237 'cadence' => $action->post_content['repeat_cadence'] ?? 'DAILY',
238 ),
239 );
240
241 if ( isset( $billing_contact['addressLines'] ) ) {
242 $info['customer']['address'] = array(
243 'addressLine1' => $billing_contact['addressLines'][0],
244 'addressLine2' => $billing_contact['addressLines'][1],
245 'locality' => $billing_contact['city'],
246 'administrativeDistrictLevel1' => $billing_contact['state'],
247 'postalCode' => $billing_contact['postalCode'],
248 'country' => $billing_contact['countryCode'],
249 );
250 }
251
252 $response = FrmSquareLiteConnectHelper::create_subscription( $info );
253 if ( false === $response ) {
254 return FrmSquareLiteConnectHelper::get_latest_error_from_square_api();
255 }
256
257 if ( is_string( $response ) ) {
258 return $response;
259 }
260
261 if ( ! is_object( $response ) || ! isset( $response->id ) ) {
262 return __( 'There was a problem creating the subscription', 'formidable' );
263 }
264
265 // Add subscription database row.
266 // We do not add a payment row at this time. This is handled with our webhook handling.
267 $subscription_id = self::create_new_subscription( $response->id, $atts );
268
269 return true;
270 }
271
272 /**
273 * Prepare the description for a subscription.
274 *
275 * @param string $description
276 * @param array $atts
277 * @return string
278 */
279 private static function prepare_subscription_description( $description, $atts ) {
280 $shortcode_atts = array(
281 'entry' => $atts['entry'],
282 'form' => $atts['entry']->form_id,
283 'value' => $description,
284 );
285 return FrmTransLiteAppHelper::process_shortcodes( $shortcode_atts );
286 }
287
288 /**
289 * Create a new subscription and payment for the payments tables.
290 *
291 * @param string $subscription_id
292 * @param array $atts
293 * @return int
294 */
295 private static function create_new_subscription( $subscription_id, $atts ) {
296 $repeat_cadence = $atts['action']->post_content['repeat_cadence'] ?? 'DAILY';
297 $interval_count = self::get_interval_count_from_repeat_cadence( $repeat_cadence );
298 $interval = self::get_interval_from_repeat_cadence( $repeat_cadence );
299
300 $new_values = array(
301 'amount' => FrmTransLiteAppHelper::get_formatted_amount_for_currency( $atts['amount'], $atts['action'] ),
302 'paysys' => 'square',
303 'item_id' => $atts['entry']->id,
304 'action_id' => $atts['action']->ID,
305 'sub_id' => $subscription_id,
306 'interval_count' => $interval_count,
307 'time_interval' => $interval,
308 'status' => 'active',
309 'next_bill_date' => gmdate( 'Y-m-d' ),
310 'test' => 'test' === FrmSquareLiteAppHelper::active_mode() ? 1 : 0,
311 );
312
313 $frm_payment = new FrmTransLiteSubscription();
314 $payment_id = $frm_payment->create( $new_values );
315
316 return $payment_id;
317 }
318
319 /**
320 * @param string $repeat_cadence
321 * @return int
322 */
323 private static function get_interval_count_from_repeat_cadence( $repeat_cadence ) {
324 switch ( $repeat_cadence ) {
325 case 'NINETY_DAYS':
326 return 90;
327 case 'SIXTY_DAYS':
328 return 60;
329 case 'THIRTY_DAYS':
330 return 30;
331 case 'EVERY_SIX_MONTHS':
332 return 6;
333 case 'EVERY_FOUR_MONTHS':
334 return 4;
335 case 'QUARTERLY':
336 return 3;
337 case 'EVERY_TWO_WEEKS':
338 case 'EVERY_TWO_MONTHS':
339 case 'EVERY_TWO_YEARS':
340 return 2;
341 case 'DAILY':
342 case 'ANNUAL':
343 case 'MONTHLY':
344 case 'WEEKLY':
345 default:
346 return 1;
347 }//end switch
348 }
349
350 /**
351 * @param string $repeat_cadence
352 * @return string
353 */
354 private static function get_interval_from_repeat_cadence( $repeat_cadence ) {
355 switch ( $repeat_cadence ) {
356 case 'ANNUAL':
357 case 'EVERY_TWO_YEARS':
358 return 'year';
359
360 case 'MONTHLY':
361 case 'EVERY_TWO_MONTHS':
362 case 'QUARTERLY':
363 case 'EVERY_FOUR_MONTHS':
364 case 'EVERY_SIX_MONTHS':
365 return 'month';
366
367 case 'WEEKLY':
368 case 'EVERY_TWO_WEEKS':
369 return 'week';
370
371 case 'DAILY':
372 case 'THIRTY_DAYS':
373 case 'SIXTY_DAYS':
374 case 'NINETY_DAYS':
375 default:
376 return 'day';
377 }//end switch
378 }
379
380 /**
381 * Check if Square integration is enabled.
382 *
383 * @return bool true if Square is set up.
384 */
385 private static function square_is_configured() {
386 return (bool) FrmSquareLiteConnectHelper::get_merchant_id();
387 }
388
389 /**
390 * Replace an [email] shortcode with the current user email.
391 *
392 * @param string $email
393 * @return string
394 */
395 private static function replace_email_shortcode( $email ) {
396 if ( false === strpos( $email, '[email]' ) ) {
397 return $email;
398 }
399
400 global $current_user;
401 return str_replace(
402 '[email]',
403 ! empty( $current_user->user_email ) ? $current_user->user_email : '',
404 $email
405 );
406 }
407
408 /**
409 * Convert the amount from 10.00 to 1000.
410 *
411 * @param mixed $amount
412 * @param array $atts
413 * @return string
414 */
415 public static function prepare_amount( $amount, $atts = array() ) {
416 $amount = parent::prepare_amount( $amount, $atts );
417 $currency = self::get_currency_for_action( $atts );
418 return number_format( $amount, $currency['decimals'], '', '' );
419 }
420
421 /**
422 * If this form submits with ajax, load the scripts on the first page.
423 *
424 * @param array $params
425 * @return void
426 */
427 public static function maybe_load_scripts( $params ) {
428 if ( $params['form_id'] == $params['posted_form_id'] ) {
429 // This form has already been posted, so we aren't on the first page.
430 return;
431 }
432
433 $form = FrmForm::getOne( $params['form_id'] );
434 if ( ! $form ) {
435 return;
436 }
437
438 $credit_card_field = FrmField::getAll(
439 array(
440 'fi.form_id' => $form->id,
441 'type' => 'credit_card',
442 )
443 );
444 if ( ! $credit_card_field ) {
445 return;
446 }
447
448 $payment_actions = self::get_actions_before_submit( $form->id );
449 if ( ! $payment_actions ) {
450 return;
451 }
452
453 $found_gateway = false;
454 foreach ( $payment_actions as $action ) {
455 $gateways = $action->post_content['gateway'];
456 if ( in_array( 'square', (array) $gateways, true ) ) {
457 $found_gateway = true;
458 break;
459 }
460 }
461
462 if ( ! $found_gateway ) {
463 return;
464 }
465
466 self::load_scripts( (int) $form->id );
467 }
468
469 /**
470 * Load front end JavaScript for a Stripe form.
471 *
472 * @param int $form_id
473 * @return void
474 */
475 public static function load_scripts( $form_id ) {
476 if ( FrmAppHelper::is_admin_page( 'formidable-entries' ) ) {
477 return;
478 }
479
480 if ( wp_script_is( 'formidable-square', 'enqueued' ) ) {
481 return;
482 }
483
484 if ( ! $form_id || ! is_int( $form_id ) ) {
485 _doing_it_wrong( __METHOD__, '$form_id parameter must be a non-zero integer', '6.22' );
486 return;
487 }
488
489 $action_settings = self::prepare_settings_for_js( $form_id );
490 $found_gateway = false;
491 foreach ( $action_settings as $action ) {
492 $gateways = $action['gateways'];
493 if ( ! $gateways || in_array( 'square', (array) $gateways, true ) ) {
494 $found_gateway = true;
495 break;
496 }
497 }
498
499 if ( ! $found_gateway ) {
500 return;
501 }
502
503 wp_register_script(
504 'square',
505 FrmSquareLiteAppHelper::active_mode() === 'live' ? 'https://web.squarecdn.com/v1/square.js' : 'https://sandbox.web.squarecdn.com/v1/square.js',
506 array(),
507 '1.0',
508 false
509 );
510
511 $dependencies = array( 'square', 'formidable' );
512 $script_url = FrmSquareLiteAppHelper::plugin_url() . 'js/frontend.js';
513
514 wp_enqueue_script(
515 'formidable-square',
516 $script_url,
517 $dependencies,
518 FrmAppHelper::plugin_version(),
519 false
520 );
521
522 $square_vars = array(
523 'formId' => $form_id,
524 'nonce' => wp_create_nonce( 'frm_square_ajax' ),
525 'ajax' => esc_url_raw( FrmAppHelper::get_ajax_url() ),
526 'settings' => $action_settings,
527 'appId' => self::get_app_id(),
528 'locationId' => self::get_location_id(),
529 'style' => self::get_style( $form_id ),
530 );
531
532 wp_localize_script( 'formidable-square', 'frmSquareVars', $square_vars );
533 }
534
535 /**
536 * Get the app ID for the Square app.
537 *
538 * @return string
539 */
540 private static function get_app_id() {
541 $mode = FrmSquareLiteAppHelper::active_mode();
542 if ( 'live' === $mode ) {
543 return 'sq0idp-eR4XI1xgNduJAXcBvjemTg';
544 }
545 return 'sandbox-sq0idb-MXl8ilzmhAgsHWKV9c6ycQ';
546 }
547
548 /**
549 * Get the location ID for the Square app.
550 *
551 * @return string
552 */
553 private static function get_location_id() {
554 return FrmSquareLiteConnectHelper::get_location_id();
555 }
556
557 /**
558 * @param int $form_id
559 * @return array
560 */
561 private static function get_style( $form_id ) {
562 $settings = self::get_style_settings_for_form( $form_id );
563 $style = array(
564 'input' => array(
565 'fontSize' => $settings['field_font_size'],
566 'color' => $settings['text_color'],
567 'backgroundColor' => $settings['bg_color'],
568 'fontWeight' => $settings['field_weight'],
569 ),
570 // How does input placeholder work??
571 'input::placeholder' => array(
572 'color' => $settings['text_color_disabled'],
573 ),
574 '.input-container' => array(
575 'borderRadius' => self::get_border_radius( $settings ),
576 ),
577 '.input-container.is-focus' => array(
578 'borderColor' => $settings['border_color_active'],
579 ),
580 );
581
582 if ( ! empty( $settings['font'] ) ) {
583 $style['input']['fontFamily'] = $settings['font'];
584 }
585
586 /**
587 * @since 6.22
588 *
589 * @param array $style
590 * @param array $settings
591 * @param int $form_id
592 */
593 return apply_filters( 'frm_square_style', $style, $settings, $form_id );
594 }
595
596 /**
597 * Get the border radius for Stripe elements.
598 *
599 * @since 6.22
600 *
601 * @param array $settings
602 * @return string
603 */
604 private static function get_border_radius( $settings ) {
605 if ( ! empty( $settings['field_shape_type'] ) ) {
606 switch ( $settings['field_shape_type'] ) {
607 case 'underline':
608 case 'regular':
609 return '0px';
610 case 'circle':
611 return '30px';
612 }
613 }
614 return $settings['border_radius'];
615 }
616
617 /**
618 * Get and format the style settings for JavaScript to use with the get_style function.
619 *
620 * @since 6.22
621 *
622 * @param int $form_id
623 * @return array
624 */
625 private static function get_style_settings_for_form( $form_id ) {
626 if ( ! $form_id ) {
627 return array();
628 }
629
630 $style = FrmStylesController::get_form_style( $form_id );
631 if ( ! $style ) {
632 return array();
633 }
634
635 $settings = FrmStylesHelper::get_settings_for_output( $style );
636 $disallowed = array( ';', ':', '!important' );
637 foreach ( $settings as $k => $s ) {
638 if ( is_string( $s ) ) {
639 $settings[ $k ] = str_replace( $disallowed, '', $s );
640 }
641 }
642
643 return $settings;
644 }
645
646 /**
647 * If the names are being used on the CC fields,
648 * make sure it doesn't prevent the submission if Stripe has approved.
649 *
650 * @since 6.22
651 *
652 * @param array $errors
653 * @param stdClass $field
654 * @param array $values
655 * @return array
656 */
657 public static function remove_cc_validation( $errors, $field, $values ) {
658 $has_processed = ! empty( $_POST['square-token'] ) && ! empty( $_POST['square-verification-token'] ); // phpcs:ignore WordPress.Security.NonceVerification.Missing
659 if ( ! $has_processed ) {
660 return $errors;
661 }
662
663 $field_id = isset( $field->temp_id ) ? $field->temp_id : $field->id;
664
665 if ( isset( $errors[ 'field' . $field_id . '-cc' ] ) ) {
666 unset( $errors[ 'field' . $field_id . '-cc' ] );
667 }
668 if ( isset( $errors[ 'field' . $field_id ] ) ) {
669 unset( $errors[ 'field' . $field_id ] );
670 }
671
672 return $errors;
673 }
674
675 /**
676 * @return void
677 */
678 public static function actions_js() {
679 wp_enqueue_script(
680 'frm_square_admin',
681 FrmSquareLiteAppHelper::plugin_url() . 'js/action.js',
682 array( 'wp-hooks', 'wp-i18n' ),
683 FrmAppHelper::plugin_version()
684 );
685 }
686 }
687