🔀 Merge branch 'trunk'

# Conflicts:
#	modules/ppcp-api-client/services.php
#	modules/ppcp-card-fields/services.php
This commit is contained in:
Philipp Stracker 2024-09-06 16:10:58 +02:00
commit 05ee91e192
No known key found for this signature in database
297 changed files with 20730 additions and 3189 deletions

View file

@ -4,7 +4,7 @@
"description": "Save payment methods module for PPCP",
"license": "GPL-2.0",
"require": {
"php": "^7.2 | ^8.0",
"php": "^7.4 | ^8.0",
"dhii/module-interface": "^0.3.0-alpha1"
},
"autoload": {

View file

@ -9,6 +9,4 @@ declare(strict_types=1);
namespace WooCommerce\PayPalCommerce\SavePaymentMethods;
use WooCommerce\PayPalCommerce\Vendor\Psr\Container\ContainerInterface;
return array();

View file

@ -9,8 +9,6 @@ declare(strict_types=1);
namespace WooCommerce\PayPalCommerce\SavePaymentMethods;
use WooCommerce\PayPalCommerce\Vendor\Dhii\Modular\Module\ModuleInterface;
return static function (): ModuleInterface {
return static function (): SavePaymentMethodsModule {
return new SavePaymentMethodsModule();
};

View file

@ -0,0 +1,230 @@
import {
getCurrentPaymentMethod,
PaymentMethods,
} from '../../../ppcp-button/resources/js/modules/Helper/CheckoutMethodState';
export function buttonConfiguration( ppcp_add_payment_method, errorHandler ) {
return {
createVaultSetupToken: async () => {
const response = await fetch(
ppcp_add_payment_method.ajax.create_setup_token.endpoint,
{
method: 'POST',
credentials: 'same-origin',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify( {
nonce: ppcp_add_payment_method.ajax.create_setup_token
.nonce,
} ),
}
);
const result = await response.json();
if ( result.data.id ) {
return result.data.id;
}
errorHandler.message( ppcp_add_payment_method.error_message );
},
onApprove: async ( { vaultSetupToken } ) => {
const response = await fetch(
ppcp_add_payment_method.ajax.create_payment_token.endpoint,
{
method: 'POST',
credentials: 'same-origin',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify( {
nonce: ppcp_add_payment_method.ajax.create_payment_token
.nonce,
vault_setup_token: vaultSetupToken,
} ),
}
);
const result = await response.json();
if ( result.success === true ) {
window.location.href =
ppcp_add_payment_method.payment_methods_page;
return;
}
errorHandler.message( ppcp_add_payment_method.error_message );
},
onError: ( error ) => {
console.error( error );
errorHandler.message( ppcp_add_payment_method.error_message );
},
};
}
export function cardFieldsConfiguration(
ppcp_add_payment_method,
errorHandler
) {
return {
createVaultSetupToken: async () => {
const response = await fetch(
ppcp_add_payment_method.ajax.create_setup_token.endpoint,
{
method: 'POST',
credentials: 'same-origin',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify( {
nonce: ppcp_add_payment_method.ajax.create_setup_token
.nonce,
payment_method: PaymentMethods.CARDS,
verification_method:
ppcp_add_payment_method.verification_method,
} ),
}
);
const result = await response.json();
if ( result.data.id ) {
return result.data.id;
}
errorHandler.message( ppcp_add_payment_method.error_message );
},
onApprove: async ( { vaultSetupToken } ) => {
const isFreeTrialCart =
ppcp_add_payment_method?.is_free_trial_cart ?? false;
const response = await fetch(
ppcp_add_payment_method.ajax.create_payment_token.endpoint,
{
method: 'POST',
credentials: 'same-origin',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify( {
nonce: ppcp_add_payment_method.ajax.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 = ppcp_add_payment_method?.context ?? '';
if ( context === 'checkout' ) {
document.querySelector( '#place_order' ).click();
return;
}
if (
ppcp_add_payment_method.is_subscription_change_payment_page
) {
const subscriptionId =
ppcp_add_payment_method.subscription_id_to_change_payment;
if ( subscriptionId && result.data ) {
const req = await fetch(
ppcp_add_payment_method.ajax
.subscription_change_payment_method.endpoint,
{
method: 'POST',
credentials: 'same-origin',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify( {
nonce: ppcp_add_payment_method.ajax
.subscription_change_payment_method
.nonce,
subscription_id: subscriptionId,
payment_method: getCurrentPaymentMethod(),
wc_payment_token_id: result.data,
} ),
}
);
const res = await req.json();
if ( res.success === true ) {
window.location.href = `${ ppcp_add_payment_method.view_subscriptions_page }/${ subscriptionId }`;
return;
}
}
return;
}
window.location.href =
ppcp_add_payment_method.payment_methods_page;
return;
}
this.errorHandler.message( ppcp_add_payment_method.error_message );
},
onError: ( error ) => {
console.error( error );
errorHandler.message( ppcp_add_payment_method.error_message );
},
};
}
export function addPaymentMethodConfiguration( ppcp_add_payment_method ) {
return {
createVaultSetupToken: async () => {
const response = await fetch(
ppcp_add_payment_method.ajax.create_setup_token.endpoint,
{
method: 'POST',
credentials: 'same-origin',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify( {
nonce: ppcp_add_payment_method.ajax.create_setup_token
.nonce,
payment_method: getCurrentPaymentMethod(),
} ),
}
);
const result = await response.json();
if ( result.data.id ) {
return result.data.id;
}
console.error( result );
},
onApprove: async ( { vaultSetupToken } ) => {
const response = await fetch(
ppcp_add_payment_method.ajax.create_payment_token_for_guest
.endpoint,
{
method: 'POST',
credentials: 'same-origin',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify( {
nonce: ppcp_add_payment_method.ajax
.create_payment_token_for_guest.nonce,
vault_setup_token: vaultSetupToken,
} ),
}
);
const result = await response.json();
if ( result.success === true ) {
document.querySelector( '#place_order' ).click();
return;
}
console.error( result );
},
onError: ( error ) => {
console.error( error );
},
};
}

View file

@ -4,303 +4,108 @@ import {
PaymentMethods,
} from '../../../ppcp-button/resources/js/modules/Helper/CheckoutMethodState';
import { loadScript } from '@paypal/paypal-js';
import ErrorHandler from '../../../ppcp-button/resources/js/modules/ErrorHandler';
import { buttonConfiguration, cardFieldsConfiguration } from './Configuration';
import { renderFields } from '../../../ppcp-card-fields/resources/js/Render';
import {
setVisible,
setVisibleByClass,
} from '../../../ppcp-button/resources/js/modules/Helper/Hiding';
import ErrorHandler from '../../../ppcp-button/resources/js/modules/ErrorHandler';
import { cardFieldStyles } from '../../../ppcp-button/resources/js/modules/Helper/CardFieldsHelper';
const errorHandler = new ErrorHandler(
ppcp_add_payment_method.labels.error.generic,
document.querySelector( '.woocommerce-notices-wrapper' )
);
const init = () => {
setVisibleByClass(
ORDER_BUTTON_SELECTOR,
getCurrentPaymentMethod() !== PaymentMethods.PAYPAL,
'ppcp-hidden'
);
setVisible(
`#ppc-button-${ PaymentMethods.PAYPAL }-save-payment-method`,
getCurrentPaymentMethod() === PaymentMethods.PAYPAL
);
};
document.addEventListener( 'DOMContentLoaded', () => {
jQuery( document.body ).on(
'click init_add_payment_method',
'.payment_methods input.input-radio',
function () {
init();
}
);
if ( ppcp_add_payment_method.is_subscription_change_payment_page ) {
const saveToAccount = document.querySelector(
'#wc-ppcp-credit-card-gateway-new-payment-method'
);
if ( saveToAccount ) {
saveToAccount.checked = true;
saveToAccount.disabled = true;
}
}
setTimeout( () => {
loadScript( {
clientId: ppcp_add_payment_method.client_id,
merchantId: ppcp_add_payment_method.merchant_id,
dataUserIdToken: ppcp_add_payment_method.id_token,
components: 'buttons,card-fields',
} ).then( ( paypal ) => {
errorHandler.clear();
const paypalButtonContainer = document.querySelector(
`#ppc-button-${ PaymentMethods.PAYPAL }-save-payment-method`
);
if ( paypalButtonContainer ) {
paypal
.Buttons( {
createVaultSetupToken: async () => {
const response = await fetch(
ppcp_add_payment_method.ajax.create_setup_token
.endpoint,
{
method: 'POST',
credentials: 'same-origin',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify( {
nonce: ppcp_add_payment_method.ajax
.create_setup_token.nonce,
} ),
}
);
const result = await response.json();
if ( result.data.id ) {
return result.data.id;
}
errorHandler.message(
ppcp_add_payment_method.error_message
);
},
onApprove: async ( { vaultSetupToken } ) => {
const response = await fetch(
ppcp_add_payment_method.ajax
.create_payment_token.endpoint,
{
method: 'POST',
credentials: 'same-origin',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify( {
nonce: ppcp_add_payment_method.ajax
.create_payment_token.nonce,
vault_setup_token: vaultSetupToken,
} ),
}
);
const result = await response.json();
if ( result.success === true ) {
window.location.href =
ppcp_add_payment_method.payment_methods_page;
return;
}
errorHandler.message(
ppcp_add_payment_method.error_message
);
},
onError: ( error ) => {
console.error( error );
errorHandler.message(
ppcp_add_payment_method.error_message
);
},
} )
.render(
`#ppc-button-${ PaymentMethods.PAYPAL }-save-payment-method`
);
( function ( { ppcp_add_payment_method, jQuery } ) {
document.addEventListener( 'DOMContentLoaded', () => {
jQuery( document.body ).on(
'click init_add_payment_method',
'.payment_methods input.input-radio',
function () {
setVisibleByClass(
ORDER_BUTTON_SELECTOR,
getCurrentPaymentMethod() !== PaymentMethods.PAYPAL,
'ppcp-hidden'
);
setVisible(
`#ppc-button-${ PaymentMethods.PAYPAL }-save-payment-method`,
getCurrentPaymentMethod() === PaymentMethods.PAYPAL
);
}
);
const cardField = paypal.CardFields( {
createVaultSetupToken: async () => {
const response = await fetch(
ppcp_add_payment_method.ajax.create_setup_token
.endpoint,
{
method: 'POST',
credentials: 'same-origin',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify( {
nonce: ppcp_add_payment_method.ajax
.create_setup_token.nonce,
payment_method: PaymentMethods.CARDS,
verification_method:
ppcp_add_payment_method.verification_method,
} ),
}
);
// TODO move to wc subscriptions module
if ( ppcp_add_payment_method.is_subscription_change_payment_page ) {
const saveToAccount = document.querySelector(
'#wc-ppcp-credit-card-gateway-new-payment-method'
);
if ( saveToAccount ) {
saveToAccount.checked = true;
saveToAccount.disabled = true;
}
}
const result = await response.json();
if ( result.data.id ) {
return result.data.id;
}
setTimeout( () => {
loadScript( {
clientId: ppcp_add_payment_method.client_id,
merchantId: ppcp_add_payment_method.merchant_id,
dataUserIdToken: ppcp_add_payment_method.id_token,
components: 'buttons,card-fields',
} ).then( ( paypal ) => {
const errorHandler = new ErrorHandler(
ppcp_add_payment_method.labels.error.generic,
document.querySelector( '.woocommerce-notices-wrapper' )
);
errorHandler.clear();
errorHandler.message(
ppcp_add_payment_method.error_message
);
},
onApprove: async ( { vaultSetupToken } ) => {
const response = await fetch(
ppcp_add_payment_method.ajax.create_payment_token
.endpoint,
{
method: 'POST',
credentials: 'same-origin',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify( {
nonce: ppcp_add_payment_method.ajax
.create_payment_token.nonce,
vault_setup_token: vaultSetupToken,
payment_method: PaymentMethods.CARDS,
} ),
}
);
const paypalButtonContainer = document.querySelector(
`#ppc-button-${ PaymentMethods.PAYPAL }-save-payment-method`
);
const result = await response.json();
if ( result.success === true ) {
if ( paypalButtonContainer ) {
paypal
.Buttons(
buttonConfiguration(
ppcp_add_payment_method,
errorHandler
)
)
.render(
`#ppc-button-${ PaymentMethods.PAYPAL }-save-payment-method`
);
}
const cardFields = paypal.CardFields(
cardFieldsConfiguration(
ppcp_add_payment_method,
errorHandler
)
);
if ( cardFields.isEligible() ) {
renderFields( cardFields );
}
document
.querySelector( '#place_order' )
?.addEventListener( 'click', ( event ) => {
const cardPaymentToken = document.querySelector(
'input[name="wc-ppcp-credit-card-gateway-payment-token"]:checked'
)?.value;
if (
ppcp_add_payment_method.is_subscription_change_payment_page
getCurrentPaymentMethod() !==
'ppcp-credit-card-gateway' ||
( cardPaymentToken && cardPaymentToken !== 'new' )
) {
const subscriptionId =
ppcp_add_payment_method.subscription_id_to_change_payment;
if ( subscriptionId && result.data ) {
const req = await fetch(
ppcp_add_payment_method.ajax
.subscription_change_payment_method
.endpoint,
{
method: 'POST',
credentials: 'same-origin',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify( {
nonce: ppcp_add_payment_method.ajax
.subscription_change_payment_method
.nonce,
subscription_id: subscriptionId,
payment_method:
getCurrentPaymentMethod(),
wc_payment_token_id: result.data,
} ),
}
);
const res = await req.json();
if ( res.success === true ) {
window.location.href = `${ ppcp_add_payment_method.view_subscriptions_page }/${ subscriptionId }`;
return;
}
}
return;
}
window.location.href =
ppcp_add_payment_method.payment_methods_page;
return;
}
event.preventDefault();
errorHandler.message(
ppcp_add_payment_method.error_message
);
},
onError: ( error ) => {
console.error( error );
errorHandler.message(
ppcp_add_payment_method.error_message
);
},
} );
if ( cardField.isEligible() ) {
const nameField = document.getElementById(
'ppcp-credit-card-gateway-card-name'
);
if ( nameField ) {
const styles = cardFieldStyles( nameField );
cardField
.NameField( { style: { input: styles } } )
.render( nameField.parentNode );
nameField.hidden = true;
}
const numberField = document.getElementById(
'ppcp-credit-card-gateway-card-number'
);
if ( numberField ) {
const styles = cardFieldStyles( numberField );
cardField
.NumberField( { style: { input: styles } } )
.render( numberField.parentNode );
numberField.hidden = true;
}
const expiryField = document.getElementById(
'ppcp-credit-card-gateway-card-expiry'
);
if ( expiryField ) {
const styles = cardFieldStyles( expiryField );
cardField
.ExpiryField( { style: { input: styles } } )
.render( expiryField.parentNode );
expiryField.hidden = true;
}
const cvvField = document.getElementById(
'ppcp-credit-card-gateway-card-cvc'
);
if ( cvvField ) {
const styles = cardFieldStyles( cvvField );
cardField
.CVVField( { style: { input: styles } } )
.render( cvvField.parentNode );
cvvField.hidden = true;
}
}
document
.querySelector( '#place_order' )
?.addEventListener( 'click', ( event ) => {
const cardPaymentToken = document.querySelector(
'input[name="wc-ppcp-credit-card-gateway-payment-token"]:checked'
)?.value;
if (
getCurrentPaymentMethod() !==
'ppcp-credit-card-gateway' ||
( cardPaymentToken && cardPaymentToken !== 'new' )
) {
return;
}
event.preventDefault();
cardField.submit().catch( ( error ) => {
console.error( error );
cardFields.submit().catch( ( error ) => {
console.error( error );
} );
} );
} );
} );
}, 1000 );
} );
}, 1000 );
} );
} )( {
ppcp_add_payment_method: window.ppcp_add_payment_method,
jQuery: window.jQuery,
} );

View file

@ -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 );
}
}
}

View file

@ -22,10 +22,11 @@ use WooCommerce\PayPalCommerce\Button\Helper\ContextTrait;
use WooCommerce\PayPalCommerce\SavePaymentMethods\Endpoint\CreatePaymentToken;
use WooCommerce\PayPalCommerce\SavePaymentMethods\Endpoint\CreatePaymentTokenForGuest;
use WooCommerce\PayPalCommerce\SavePaymentMethods\Endpoint\CreateSetupToken;
use WooCommerce\PayPalCommerce\Vendor\Inpsyde\Modularity\Module\ExecutableModule;
use WooCommerce\PayPalCommerce\Vendor\Inpsyde\Modularity\Module\ExtendingModule;
use WooCommerce\PayPalCommerce\Vendor\Inpsyde\Modularity\Module\ModuleClassNameIdTrait;
use WooCommerce\PayPalCommerce\Vendor\Inpsyde\Modularity\Module\ServiceModule;
use WooCommerce\PayPalCommerce\Vaulting\WooCommercePaymentTokens;
use WooCommerce\PayPalCommerce\Vendor\Dhii\Container\ServiceProvider;
use WooCommerce\PayPalCommerce\Vendor\Dhii\Modular\Module\ModuleInterface;
use WooCommerce\PayPalCommerce\Vendor\Interop\Container\ServiceProviderInterface;
use WooCommerce\PayPalCommerce\Vendor\Psr\Container\ContainerInterface;
use WooCommerce\PayPalCommerce\WcGateway\Gateway\CreditCardGateway;
use WooCommerce\PayPalCommerce\WcGateway\Gateway\PayPalGateway;
@ -36,26 +37,30 @@ use WooCommerce\PayPalCommerce\WcSubscriptions\Helper\SubscriptionHelper;
/**
* Class SavePaymentMethodsModule
*/
class SavePaymentMethodsModule implements ModuleInterface {
class SavePaymentMethodsModule implements ServiceModule, ExtendingModule, ExecutableModule {
use ModuleClassNameIdTrait;
use ContextTrait;
/**
* {@inheritDoc}
*/
public function setup(): ServiceProviderInterface {
return new ServiceProvider(
require __DIR__ . '/../services.php',
require __DIR__ . '/../extensions.php'
);
public function services(): array {
return require __DIR__ . '/../services.php';
}
/**
* {@inheritDoc}
*/
public function run( ContainerInterface $c ): void {
public function extensions(): array {
return require __DIR__ . '/../extensions.php';
}
/**
* {@inheritDoc}
*/
public function run( ContainerInterface $c ): bool {
if ( ! $c->get( 'save-payment-methods.eligible' ) ) {
return;
return true;
}
$settings = $c->get( 'wcgateway.settings' );
@ -79,7 +84,7 @@ class SavePaymentMethodsModule implements ModuleInterface {
( ! $settings->has( 'vault_enabled' ) || ! $settings->get( 'vault_enabled' ) )
&& ( ! $settings->has( 'vault_enabled_dcc' ) || ! $settings->get( 'vault_enabled_dcc' ) )
) {
return;
return true;
}
add_filter(
@ -431,6 +436,8 @@ class SavePaymentMethodsModule implements ModuleInterface {
return true;
}
);
return true;
}
/**