From efbd36025d24e69408779053e935b28f2da613e8 Mon Sep 17 00:00:00 2001 From: Emili Castells Guasch Date: Wed, 24 Jul 2024 16:00:55 +0200 Subject: [PATCH] Add card payment token for free trial subscriptions (WIP) --- modules/ppcp-button/resources/js/button.js | 21 +++-- .../Renderer/CardFieldsFreeTrialRenderer.js | 91 +++++++++++++++++++ .../resources/js/Configuration.js | 9 ++ .../src/Endpoint/CreatePaymentToken.php | 5 + .../src/Gateway/CreditCardGateway.php | 14 +++ 5 files changed, 134 insertions(+), 6 deletions(-) create mode 100644 modules/ppcp-button/resources/js/modules/Renderer/CardFieldsFreeTrialRenderer.js diff --git a/modules/ppcp-button/resources/js/button.js b/modules/ppcp-button/resources/js/button.js index 9f5485b38..d252c4392 100644 --- a/modules/ppcp-button/resources/js/button.js +++ b/modules/ppcp-button/resources/js/button.js @@ -7,6 +7,7 @@ import Renderer from './modules/Renderer/Renderer'; import ErrorHandler from './modules/ErrorHandler'; import HostedFieldsRenderer from './modules/Renderer/HostedFieldsRenderer'; import CardFieldsRenderer from './modules/Renderer/CardFieldsRenderer'; +import CardFieldsFreeTrialRenderer from './modules/Renderer/CardFieldsFreeTrialRenderer'; import MessageRenderer from './modules/Renderer/MessageRenderer'; import Spinner from './modules/Helper/Spinner'; import { @@ -215,12 +216,20 @@ const bootstrap = () => { spinner ); if ( typeof paypal.CardFields !== 'undefined' ) { - creditCardRenderer = new CardFieldsRenderer( - PayPalCommerceGateway, - errorHandler, - spinner, - onCardFieldsBeforeSubmit - ); + if ( PayPalCommerceGateway.is_free_trial_cart ) { + creditCardRenderer = new CardFieldsFreeTrialRenderer( + PayPalCommerceGateway, + errorHandler, + spinner + ); + } else { + creditCardRenderer = new CardFieldsRenderer( + PayPalCommerceGateway, + errorHandler, + spinner, + onCardFieldsBeforeSubmit + ); + } } const renderer = new Renderer( diff --git a/modules/ppcp-button/resources/js/modules/Renderer/CardFieldsFreeTrialRenderer.js b/modules/ppcp-button/resources/js/modules/Renderer/CardFieldsFreeTrialRenderer.js new file mode 100644 index 000000000..c813e7fc7 --- /dev/null +++ b/modules/ppcp-button/resources/js/modules/Renderer/CardFieldsFreeTrialRenderer.js @@ -0,0 +1,91 @@ +import { show } from '../Helper/Hiding'; +import ErrorHandler from '../ErrorHandler'; +import RenderCardFields from '../../../../../ppcp-save-payment-methods/resources/js/RenderCardFields'; +import Configuration from '../../../../../ppcp-save-payment-methods/resources/js/Configuration'; + +class CardFieldsFreeTrialRenderer { + constructor( defaultConfig, errorHandler, spinner ) { + this.defaultConfig = defaultConfig; + this.errorHandler = errorHandler; + this.spinner = spinner; + } + + render( wrapper, contextConfig ) { + if ( + ( this.defaultConfig.context !== 'checkout' && + this.defaultConfig.context !== 'pay-now' ) || + wrapper === null || + document.querySelector( wrapper ) === null + ) { + return; + } + + const buttonSelector = wrapper + ' button'; + + const gateWayBox = document.querySelector( + '.payment_box.payment_method_ppcp-credit-card-gateway' + ); + if ( ! gateWayBox ) { + return; + } + + const oldDisplayStyle = gateWayBox.style.display; + gateWayBox.style.display = 'block'; + + const hideDccGateway = document.querySelector( '#ppcp-hide-dcc' ); + if ( hideDccGateway ) { + hideDccGateway.parentNode.removeChild( hideDccGateway ); + } + + const errorHandler = new ErrorHandler( + this.defaultConfig.labels.error.generic, + document.querySelector( '.woocommerce-notices-wrapper' ) + ); + errorHandler.clear(); + + const configuration = new Configuration( + this.defaultConfig, + errorHandler + ); + + const cardFields = paypal.CardFields( + configuration.cardFieldsConfiguration() + ); + + if ( cardFields.isEligible() ) { + const renderCardFields = new RenderCardFields( cardFields ); + renderCardFields.render(); + } + + gateWayBox.style.display = oldDisplayStyle; + + show( buttonSelector ); + + if ( this.defaultConfig.cart_contains_subscription ) { + const saveToAccount = document.querySelector( + '#wc-ppcp-credit-card-gateway-new-payment-method' + ); + if ( saveToAccount ) { + saveToAccount.checked = true; + saveToAccount.disabled = true; + } + } + + document + .querySelector( buttonSelector ) + ?.addEventListener( 'click', ( event ) => { + event.preventDefault(); + this.spinner.block(); + this.errorHandler.clear(); + + cardFields.submit().catch( ( error ) => { + console.error( error ); + } ); + } ); + } + + disableFields() {} + enableFields() {} +} + +export default CardFieldsFreeTrialRenderer; diff --git a/modules/ppcp-save-payment-methods/resources/js/Configuration.js b/modules/ppcp-save-payment-methods/resources/js/Configuration.js index 366314de1..e779dbdbc 100644 --- a/modules/ppcp-save-payment-methods/resources/js/Configuration.js +++ b/modules/ppcp-save-payment-methods/resources/js/Configuration.js @@ -108,6 +108,8 @@ class Configuration { ); }, onApprove: async ( { vaultSetupToken } ) => { + const isFreeTrialCart = + this.ppcp_add_payment_method?.is_free_trial_cart ?? false; const response = await fetch( this.ppcp_add_payment_method.ajax.create_payment_token .endpoint, @@ -122,12 +124,19 @@ class Configuration { .create_payment_token.nonce, vault_setup_token: vaultSetupToken, payment_method: PaymentMethods.CARDS, + is_free_trial_cart: isFreeTrialCart, } ), } ); const result = await response.json(); if ( result.success === true ) { + const context = this.ppcp_add_payment_method?.context ?? ''; + if ( context === 'checkout' ) { + document.querySelector( '#place_order' ).click(); + return; + } + if ( this.ppcp_add_payment_method .is_subscription_change_payment_page diff --git a/modules/ppcp-save-payment-methods/src/Endpoint/CreatePaymentToken.php b/modules/ppcp-save-payment-methods/src/Endpoint/CreatePaymentToken.php index 4fea1f188..acd4f988f 100644 --- a/modules/ppcp-save-payment-methods/src/Endpoint/CreatePaymentToken.php +++ b/modules/ppcp-save-payment-methods/src/Endpoint/CreatePaymentToken.php @@ -115,6 +115,11 @@ class CreatePaymentToken implements EndpointInterface { if ( isset( $result->payment_source->card ) ) { $wc_token_id = $this->wc_payment_tokens->create_payment_token_card( $current_user_id, $result ); + + $is_free_trial_cart = $data['is_free_trial_cart'] ?? ''; + if($is_free_trial_cart === '1') { + WC()->session->set( 'ppcp_card_payment_token_for_free_trial', $wc_token_id ); + } } } diff --git a/modules/ppcp-wc-gateway/src/Gateway/CreditCardGateway.php b/modules/ppcp-wc-gateway/src/Gateway/CreditCardGateway.php index b2ce4cbc5..319510b68 100644 --- a/modules/ppcp-wc-gateway/src/Gateway/CreditCardGateway.php +++ b/modules/ppcp-wc-gateway/src/Gateway/CreditCardGateway.php @@ -426,12 +426,26 @@ class CreditCardGateway extends \WC_Payment_Gateway_CC { public function process_payment( $order_id ) { $wc_order = wc_get_order( $order_id ); if ( ! is_a( $wc_order, WC_Order::class ) ) { + WC()->session->set( 'ppcp_card_payment_token_for_free_trial', null ); + return $this->handle_payment_failure( null, new GatewayGenericException( new Exception( 'WC order was not found.' ) ) ); } + $card_payment_token_for_free_trial = WC()->session->get( 'ppcp_card_payment_token_for_free_trial') ?? null; + WC()->session->set( 'ppcp_card_payment_token_for_free_trial', null ); + if($card_payment_token_for_free_trial) { + $tokens = WC_Payment_Tokens::get_customer_tokens( get_current_user_id() ); + foreach ( $tokens as $token ) { + if ( $token->get_id() === (int) $card_payment_token_for_free_trial ) { + $wc_order->payment_complete(); + return $this->handle_payment_success( $wc_order ); + } + } + } + // phpcs:ignore WordPress.Security.NonceVerification.Missing $card_payment_token_id = wc_clean( wp_unslash( $_POST['wc-ppcp-credit-card-gateway-payment-token'] ?? '' ) );