mirror of
https://github.com/woocommerce/woocommerce-paypal-payments.git
synced 2025-08-31 06:52:50 +08:00
Merge pull request #1717 from woocommerce/feat/PCP-154-apple-pay-payment
Feat/pcp 154 apple pay payment
This commit is contained in:
commit
af7a02f387
27 changed files with 978 additions and 169 deletions
|
@ -12,6 +12,7 @@ namespace WooCommerce\PayPalCommerce\Applepay;
|
|||
use WooCommerce\PayPalCommerce\Applepay\Assets\PropertiesDictionary;
|
||||
use WooCommerce\PayPalCommerce\Onboarding\State;
|
||||
use WooCommerce\PayPalCommerce\Vendor\Psr\Container\ContainerInterface;
|
||||
use WooCommerce\PayPalCommerce\WcGateway\Helper\DisplayManager;
|
||||
|
||||
|
||||
return array(
|
||||
|
@ -23,12 +24,55 @@ return array(
|
|||
|
||||
return array_merge( array_slice( $array, 0, $pos ), $new, array_slice( $array, $pos ) );
|
||||
};
|
||||
$display_manager = $container->get( 'wcgateway.display-manager' );
|
||||
assert( $display_manager instanceof DisplayManager );
|
||||
|
||||
if ( ! $container->has( 'applepay.eligible' ) || ! $container->get( 'applepay.eligible' ) ) {
|
||||
$connection_url = admin_url( 'admin.php?page=wc-settings&tab=checkout§ion=ppcp-gateway&ppcp-tab=ppcp-connection#field-credentials_feature_onboarding_heading' );
|
||||
$connection_link = '<a href="' . $connection_url . '" target="_blank">';
|
||||
return $insert_after(
|
||||
$fields,
|
||||
'allow_card_button_gateway',
|
||||
array(
|
||||
'applepay_button_enabled' => array(
|
||||
'title' => __( 'Apple Pay Button', 'woocommerce-paypal-payments' ),
|
||||
'type' => 'checkbox',
|
||||
'class' => array( 'ppcp-grayed-out-text' ),
|
||||
'input_class' => array( 'ppcp-disabled-checkbox' ),
|
||||
'label' => __( 'Enable Apple Pay button', 'woocommerce-paypal-payments' )
|
||||
. '<p class="description">'
|
||||
. sprintf(
|
||||
// translators: %1$s and %2$s are the opening and closing of HTML <a> tag.
|
||||
__( 'Your PayPal account %1$srequires additional permissions%2$s to enable Apple Pay.', 'woocommerce-paypal-payments' ),
|
||||
$connection_link,
|
||||
'</a>'
|
||||
)
|
||||
. '</p>',
|
||||
'default' => 'yes',
|
||||
'screens' => array( State::STATE_ONBOARDED ),
|
||||
'gateway' => 'paypal',
|
||||
'requirements' => array(),
|
||||
'custom_attributes' => array(
|
||||
'data-ppcp-display' => wp_json_encode(
|
||||
array(
|
||||
$display_manager
|
||||
->rule()
|
||||
->condition_element( 'applepay_button_enabled', '1' )
|
||||
->action_enable( 'applepay_button_enabled' )
|
||||
->to_array(),
|
||||
)
|
||||
),
|
||||
),
|
||||
),
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
return $insert_after(
|
||||
$fields,
|
||||
'allow_card_button_gateway',
|
||||
array(
|
||||
'applepay_button_enabled' => array(
|
||||
'applepay_button_enabled' => array(
|
||||
'title' => __( 'Apple Pay Button', 'woocommerce-paypal-payments' ),
|
||||
'type' => 'checkbox',
|
||||
'label' => __( 'Enable Apple Pay button', 'woocommerce-paypal-payments' )
|
||||
|
@ -45,40 +89,20 @@ return array(
|
|||
'gateway' => 'paypal',
|
||||
'requirements' => array(),
|
||||
'custom_attributes' => array(
|
||||
'data-ppcp-handlers' => wp_json_encode(
|
||||
'data-ppcp-display' => wp_json_encode(
|
||||
array(
|
||||
array(
|
||||
'handler' => 'SubElementsHandler',
|
||||
'options' => array(
|
||||
'values' => array( '1' ),
|
||||
'elements' => array( '#field-applepay_sandbox_validation_file', '#field-applepay_live_validation_file', '#field-applepay_button_color', '#field-applepay_button_type', '#field-applepay_button_language' ),
|
||||
),
|
||||
),
|
||||
$display_manager
|
||||
->rule()
|
||||
->condition_element( 'applepay_button_enabled', '1' )
|
||||
->action_visible( 'applepay_button_color' )
|
||||
->action_visible( 'applepay_button_type' )
|
||||
->action_visible( 'applepay_button_language' )
|
||||
->to_array(),
|
||||
)
|
||||
),
|
||||
),
|
||||
),
|
||||
'applepay_live_validation_file' => array(
|
||||
'title' => __( 'Apple Pay Live Validation File', 'woocommerce-paypal-payments' ),
|
||||
'type' => 'text',
|
||||
'desc_tip' => true,
|
||||
'description' => __( 'Paste here the validation file content', 'woocommerce-paypal-payments' ),
|
||||
'default' => null,
|
||||
'screens' => array( State::STATE_ONBOARDED ),
|
||||
'gateway' => 'paypal',
|
||||
'requirements' => array(),
|
||||
),
|
||||
'applepay_sandbox_validation_file' => array(
|
||||
'title' => __( 'Apple Pay Sandbox Validation File', 'woocommerce-paypal-payments' ),
|
||||
'type' => 'text',
|
||||
'desc_tip' => true,
|
||||
'description' => __( 'Paste here the validation file content', 'woocommerce-paypal-payments' ),
|
||||
'default' => null,
|
||||
'screens' => array( State::STATE_ONBOARDED ),
|
||||
'gateway' => 'paypal',
|
||||
'requirements' => array(),
|
||||
),
|
||||
'applepay_button_type' => array(
|
||||
'applepay_button_type' => array(
|
||||
'title' => str_repeat( ' ', 6 ) . __( 'Button Label', 'woocommerce-paypal-payments' ),
|
||||
'type' => 'select',
|
||||
'desc_tip' => true,
|
||||
|
@ -94,7 +118,7 @@ return array(
|
|||
'gateway' => 'paypal',
|
||||
'requirements' => array(),
|
||||
),
|
||||
'applepay_button_color' => array(
|
||||
'applepay_button_color' => array(
|
||||
'title' => str_repeat( ' ', 6 ) . __( 'Button Color', 'woocommerce-paypal-payments' ),
|
||||
'type' => 'select',
|
||||
'desc_tip' => true,
|
||||
|
@ -111,7 +135,7 @@ return array(
|
|||
'gateway' => 'paypal',
|
||||
'requirements' => array(),
|
||||
),
|
||||
'applepay_button_language' => array(
|
||||
'applepay_button_language' => array(
|
||||
'title' => str_repeat( ' ', 6 ) . __( 'Button Language', 'woocommerce-paypal-payments' ),
|
||||
'type' => 'select',
|
||||
'desc_tip' => true,
|
||||
|
|
|
@ -2,6 +2,8 @@ import ContextHandlerFactory from "./Context/ContextHandlerFactory";
|
|||
import {createAppleErrors} from "./Helper/applePayError";
|
||||
import {setVisible} from '../../../ppcp-button/resources/js/modules/Helper/Hiding';
|
||||
import {setEnabled} from '../../../ppcp-button/resources/js/modules/Helper/ButtonDisabler';
|
||||
import FormValidator from "../../../ppcp-button/resources/js/modules/Helper/FormValidator";
|
||||
import ErrorHandler from '../../../ppcp-button/resources/js/modules/ErrorHandler';
|
||||
|
||||
class ApplepayButton {
|
||||
|
||||
|
@ -13,6 +15,7 @@ class ApplepayButton {
|
|||
this.buttonConfig = buttonConfig;
|
||||
this.ppcpConfig = ppcpConfig;
|
||||
this.paymentsClient = null;
|
||||
this.form_saved = false;
|
||||
|
||||
this.contextHandler = ContextHandlerFactory.create(
|
||||
this.context,
|
||||
|
@ -42,14 +45,14 @@ class ApplepayButton {
|
|||
if (isEligible) {
|
||||
this.fetchTransactionInfo().then(() => {
|
||||
const isSubscriptionProduct = this.ppcpConfig.data_client_id.has_subscriptions === true;
|
||||
if(isSubscriptionProduct) {
|
||||
if (isSubscriptionProduct) {
|
||||
return;
|
||||
}
|
||||
this.addButton();
|
||||
const id_minicart = "#apple-" + this.buttonConfig.button.mini_cart_wrapper;
|
||||
const id = "#apple-" + this.buttonConfig.button.wrapper;
|
||||
|
||||
if(this.context === 'mini-cart') {
|
||||
if (this.context === 'mini-cart') {
|
||||
document.querySelector(id_minicart).addEventListener('click', (evt) => {
|
||||
evt.preventDefault();
|
||||
this.onButtonClick();
|
||||
|
@ -60,10 +63,13 @@ class ApplepayButton {
|
|||
this.onButtonClick();
|
||||
});
|
||||
}
|
||||
|
||||
// Listen for changes on any input within the WooCommerce checkout form
|
||||
jQuery('form.checkout').on('change', 'input, select, textarea', () => {
|
||||
this.fetchTransactionInfo();
|
||||
});
|
||||
});
|
||||
}
|
||||
console.log('[ApplePayButton] init done', this.buttonConfig.ajax_url);
|
||||
|
||||
}
|
||||
async fetchTransactionInfo() {
|
||||
this.transactionInfo = await this.contextHandler.transactionInfo();
|
||||
|
@ -94,11 +100,12 @@ class ApplepayButton {
|
|||
}
|
||||
initEventHandlers() {
|
||||
const { wrapper, ppcpButtonWrapper } = this.contextConfig();
|
||||
const wrapper_id = '#' + wrapper;
|
||||
|
||||
const syncButtonVisibility = () => {
|
||||
const $ppcpButtonWrapper = jQuery(ppcpButtonWrapper);
|
||||
setVisible(wrapper, $ppcpButtonWrapper.is(':visible'));
|
||||
setEnabled(wrapper, !$ppcpButtonWrapper.hasClass('ppcp-disabled'));
|
||||
setVisible(wrapper_id, $ppcpButtonWrapper.is(':visible'));
|
||||
setEnabled(wrapper_id, !$ppcpButtonWrapper.hasClass('ppcp-disabled'));
|
||||
}
|
||||
|
||||
jQuery(document).on('ppcp-shown ppcp-hidden ppcp-enabled ppcp-disabled', (ev, data) => {
|
||||
|
@ -120,6 +127,7 @@ class ApplepayButton {
|
|||
}
|
||||
session.onvalidatemerchant = this.onvalidatemerchant(session);
|
||||
session.onpaymentauthorized = this.onpaymentauthorized(session);
|
||||
return session;
|
||||
}
|
||||
|
||||
|
||||
|
@ -129,19 +137,15 @@ class ApplepayButton {
|
|||
* Add a Apple Pay purchase button
|
||||
*/
|
||||
addButton() {
|
||||
console.log('[ApplePayButton] context', this.context);
|
||||
const wrapper =
|
||||
(this.context === 'mini-cart')
|
||||
? this.buttonConfig.button.mini_cart_wrapper
|
||||
: this.buttonConfig.button.wrapper;
|
||||
console.log('[ApplePayButton] wrapper', wrapper)
|
||||
const shape =
|
||||
(this.context === 'mini-cart')
|
||||
? this.ppcpConfig.button.mini_cart_style.shape
|
||||
: this.ppcpConfig.button.style.shape;
|
||||
const appleContainer = this.context === 'mini-cart' ? document.getElementById("applepay-container-minicart") : document.getElementById("applepay-container");
|
||||
console.log('[ApplePayButton] shape', shape)
|
||||
console.log('[ApplePayButton] container', appleContainer)
|
||||
const type = this.buttonConfig.button.type;
|
||||
const language = this.buttonConfig.button.lang;
|
||||
const color = this.buttonConfig.button.color;
|
||||
|
@ -150,7 +154,6 @@ console.log('[ApplePayButton] wrapper', wrapper)
|
|||
|
||||
jQuery('#' + wrapper).addClass('ppcp-button-' + shape);
|
||||
jQuery(wrapper).append(appleContainer);
|
||||
console.log('[ApplePayButton] addButton', wrapper, appleContainer);
|
||||
}
|
||||
|
||||
//------------------------
|
||||
|
@ -160,13 +163,58 @@ console.log('[ApplePayButton] wrapper', wrapper)
|
|||
/**
|
||||
* Show Apple Pay payment sheet when Apple Pay payment button is clicked
|
||||
*/
|
||||
onButtonClick() {
|
||||
async onButtonClick() {
|
||||
const paymentDataRequest = this.paymentDataRequest();
|
||||
console.log('[ApplePayButton] onButtonClick: paymentDataRequest', paymentDataRequest, this.context);
|
||||
|
||||
// trigger woocommerce validation if we are in the checkout page
|
||||
if (this.context === 'checkout') {
|
||||
const checkoutFormSelector = 'form.woocommerce-checkout';
|
||||
const errorHandler = new ErrorHandler(
|
||||
PayPalCommerceGateway.labels.error.generic,
|
||||
document.querySelector('.woocommerce-notices-wrapper')
|
||||
);
|
||||
try {
|
||||
const formData = new FormData(document.querySelector(checkoutFormSelector));
|
||||
this.form_saved = Object.fromEntries(formData.entries());
|
||||
this.update_request_data_with_form(paymentDataRequest);
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
}
|
||||
const session = this.applePaySession(paymentDataRequest)
|
||||
console.log("session", session)
|
||||
const formValidator = PayPalCommerceGateway.early_checkout_validation_enabled ?
|
||||
new FormValidator(
|
||||
PayPalCommerceGateway.ajax.validate_checkout.endpoint,
|
||||
PayPalCommerceGateway.ajax.validate_checkout.nonce,
|
||||
) : null;
|
||||
if (formValidator) {
|
||||
try {
|
||||
const errors = await formValidator.validate(document.querySelector(checkoutFormSelector));
|
||||
if (errors.length > 0) {
|
||||
errorHandler.messages(errors);
|
||||
// fire WC event for other plugins
|
||||
jQuery( document.body ).trigger( 'checkout_error' , [ errorHandler.currentHtml() ] );
|
||||
// stop Apple Pay payment sheet from showing
|
||||
session.abort();
|
||||
return;
|
||||
}
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
this.applePaySession(paymentDataRequest)
|
||||
}
|
||||
|
||||
update_request_data_with_form(paymentDataRequest) {
|
||||
paymentDataRequest.billingContact = this.fill_billing_contact(this.form_saved);
|
||||
paymentDataRequest.applicationData = this.fill_application_data(this.form_saved);
|
||||
if (!this.buttonConfig.product.needShipping) {
|
||||
return;
|
||||
}
|
||||
paymentDataRequest.shippingContact = this.fill_shipping_contact(this.form_saved);
|
||||
}
|
||||
|
||||
paymentDataRequest() {
|
||||
const applepayConfig = this.applePayConfig
|
||||
const buttonConfig = this.buttonConfig
|
||||
|
@ -174,12 +222,9 @@ console.log('[ApplePayButton] wrapper', wrapper)
|
|||
countryCode: applepayConfig.countryCode,
|
||||
merchantCapabilities: applepayConfig.merchantCapabilities,
|
||||
supportedNetworks: applepayConfig.supportedNetworks,
|
||||
requiredShippingContactFields: ["name", "phone",
|
||||
"email", "postalAddress"],
|
||||
requiredBillingContactFields: ["name", "phone", "email",
|
||||
"postalAddress"]
|
||||
requiredShippingContactFields: ["postalAddress"],
|
||||
requiredBillingContactFields: ["postalAddress"]
|
||||
}
|
||||
console.log('[ApplePayButton] paymentDataRequest', applepayConfig, buttonConfig);
|
||||
const paymentDataRequest = Object.assign({}, baseRequest);
|
||||
paymentDataRequest.currencyCode = buttonConfig.shop.currencyCode;
|
||||
paymentDataRequest.total = {
|
||||
|
@ -197,6 +242,7 @@ console.log('[ApplePayButton] wrapper', wrapper)
|
|||
//------------------------
|
||||
|
||||
onvalidatemerchant(session) {
|
||||
console.log("onvalidatemerchant")
|
||||
return (applePayValidateMerchantEvent) => {
|
||||
paypal.Applepay().validateMerchant({
|
||||
validationUrl: applePayValidateMerchantEvent.validationURL
|
||||
|
@ -234,7 +280,6 @@ console.log('[ApplePayButton] wrapper', wrapper)
|
|||
onshippingmethodselected(session) {
|
||||
const ajax_url = this.buttonConfig.ajax_url
|
||||
console.log('[ApplePayButton] onshippingmethodselected');
|
||||
|
||||
return (event) => {
|
||||
const data = this.getShippingMethodData(event);
|
||||
jQuery.ajax({
|
||||
|
@ -271,7 +316,7 @@ console.log('[ApplePayButton] wrapper', wrapper)
|
|||
}
|
||||
onshippingcontactselected(session) {
|
||||
const ajax_url = this.buttonConfig.ajax_url
|
||||
|
||||
console.log('[ApplePayButton] onshippingcontactselected', ajax_url, session)
|
||||
return (event) => {
|
||||
const data = this.getShippingContactData(event);
|
||||
console.log('shipping contact selected', data, event)
|
||||
|
@ -514,6 +559,44 @@ console.log('[ApplePayButton] wrapper', wrapper)
|
|||
return response;
|
||||
}*/
|
||||
|
||||
fill_billing_contact(form_saved) {
|
||||
return {
|
||||
givenName: form_saved.billing_first_name ?? '',
|
||||
familyName: form_saved.billing_last_name ?? '',
|
||||
emailAddress: form_saved.billing_email ?? '',
|
||||
phoneNumber: form_saved.billing_phone ?? '',
|
||||
addressLines: [form_saved.billing_address_1, form_saved.billing_address_2],
|
||||
locality: form_saved.billing_city ?? '',
|
||||
postalCode: form_saved.billing_postcode ?? '',
|
||||
countryCode: form_saved.billing_country ?? '',
|
||||
administrativeArea: form_saved.billing_state ?? '',
|
||||
}
|
||||
}
|
||||
fill_shipping_contact(form_saved) {
|
||||
if (form_saved.shipping_first_name === "") {
|
||||
return this.fill_billing_contact(form_saved)
|
||||
}
|
||||
return {
|
||||
givenName: (form_saved?.shipping_first_name && form_saved.shipping_first_name !== "") ? form_saved.shipping_first_name : form_saved?.billing_first_name,
|
||||
familyName: (form_saved?.shipping_last_name && form_saved.shipping_last_name !== "") ? form_saved.shipping_last_name : form_saved?.billing_last_name,
|
||||
emailAddress: (form_saved?.shipping_email && form_saved.shipping_email !== "") ? form_saved.shipping_email : form_saved?.billing_email,
|
||||
phoneNumber: (form_saved?.shipping_phone && form_saved.shipping_phone !== "") ? form_saved.shipping_phone : form_saved?.billing_phone,
|
||||
addressLines: [form_saved.shipping_address_1 ?? '', form_saved.shipping_address_2 ?? ''],
|
||||
locality: (form_saved?.shipping_city && form_saved.shipping_city !== "") ? form_saved.shipping_city : form_saved?.billing_city,
|
||||
postalCode: (form_saved?.shipping_postcode && form_saved.shipping_postcode !== "") ? form_saved.shipping_postcode : form_saved?.billing_postcode,
|
||||
countryCode: (form_saved?.shipping_country && form_saved.shipping_country !== "") ? form_saved.shipping_country : form_saved?.billing_country,
|
||||
administrativeArea: (form_saved?.shipping_state && form_saved.shipping_state !== "") ? form_saved.shipping_state : form_saved?.billing_state,
|
||||
}
|
||||
}
|
||||
|
||||
fill_application_data(form_saved) {
|
||||
const jsonString = JSON.stringify(form_saved);
|
||||
let utf8Str = encodeURIComponent(jsonString).replace(/%([0-9A-F]{2})/g, (match, p1) => {
|
||||
return String.fromCharCode('0x' + p1);
|
||||
});
|
||||
|
||||
return btoa(utf8Str);
|
||||
}
|
||||
}
|
||||
|
||||
export default ApplepayButton;
|
||||
|
|
|
@ -15,14 +15,28 @@ use WooCommerce\PayPalCommerce\Applepay\Assets\ApplePayButton;
|
|||
use WooCommerce\PayPalCommerce\Applepay\Assets\AppleProductStatus;
|
||||
use WooCommerce\PayPalCommerce\Applepay\Assets\DataToAppleButtonScripts;
|
||||
use WooCommerce\PayPalCommerce\Applepay\Assets\BlocksPaymentMethod;
|
||||
use WooCommerce\PayPalCommerce\Applepay\Helper\ApmApplies;
|
||||
use WooCommerce\PayPalCommerce\Vendor\Psr\Container\ContainerInterface;
|
||||
use WooCommerce\PayPalCommerce\WcGateway\Settings\Settings;
|
||||
|
||||
return array(
|
||||
'applepay.status-cache' => static function( ContainerInterface $container ): Cache {
|
||||
'applepay.eligible' => static function ( ContainerInterface $container ): bool {
|
||||
$apm_applies = $container->get( 'applepay.helpers.apm-applies' );
|
||||
assert( $apm_applies instanceof ApmApplies );
|
||||
|
||||
return $apm_applies->for_country_currency();
|
||||
},
|
||||
'applepay.helpers.apm-applies' => static function ( ContainerInterface $container ) : ApmApplies {
|
||||
return new ApmApplies(
|
||||
$container->get( 'applepay.supported-country-currency-matrix' ),
|
||||
$container->get( 'api.shop.currency' ),
|
||||
$container->get( 'api.shop.country' )
|
||||
);
|
||||
},
|
||||
'applepay.status-cache' => static function( ContainerInterface $container ): Cache {
|
||||
return new Cache( 'ppcp-paypal-apple-status-cache' );
|
||||
},
|
||||
'applepay.apple-product-status' => static function( ContainerInterface $container ): AppleProductStatus {
|
||||
'applepay.apple-product-status' => static function( ContainerInterface $container ): AppleProductStatus {
|
||||
return new AppleProductStatus(
|
||||
$container->get( 'wcgateway.settings' ),
|
||||
$container->get( 'api.endpoint.partners' ),
|
||||
|
@ -30,18 +44,21 @@ return array(
|
|||
$container->get( 'onboarding.state' )
|
||||
);
|
||||
},
|
||||
'applepay.enabled' => static function ( ContainerInterface $container ): bool {
|
||||
$status = $container->get( 'applepay.apple-product-status' );
|
||||
assert( $status instanceof AppleProductStatus );
|
||||
/**
|
||||
* If merchant isn't onboarded via /v1/customer/partner-referrals this returns false as the API call fails.
|
||||
*/
|
||||
return apply_filters( 'woocommerce_paypal_payments_applepay_product_status', $status->apple_is_active() );
|
||||
'applepay.enabled' => static function ( ContainerInterface $container ): bool {
|
||||
if ( apply_filters( 'woocommerce_paypal_payments_applepay_validate_product_status', false ) ) {
|
||||
$status = $container->get( 'applepay.apple-product-status' );
|
||||
assert( $status instanceof AppleProductStatus );
|
||||
/**
|
||||
* If merchant isn't onboarded via /v1/customer/partner-referrals this returns false as the API call fails.
|
||||
*/
|
||||
return apply_filters( 'woocommerce_paypal_payments_applepay_product_status', $status->apple_is_active() );
|
||||
}
|
||||
return true;
|
||||
},
|
||||
'applepay.server_supported' => static function ( ContainerInterface $container ): bool {
|
||||
'applepay.server_supported' => static function ( ContainerInterface $container ): bool {
|
||||
return ! empty( $_SERVER['HTTPS'] ) && $_SERVER['HTTPS'] !== 'off';
|
||||
},
|
||||
'applepay.url' => static function ( ContainerInterface $container ): string {
|
||||
'applepay.url' => static function ( ContainerInterface $container ): string {
|
||||
$path = realpath( __FILE__ );
|
||||
if ( false === $path ) {
|
||||
return '';
|
||||
|
@ -51,13 +68,13 @@ return array(
|
|||
dirname( $path, 3 ) . '/woocommerce-paypal-payments.php'
|
||||
);
|
||||
},
|
||||
'applepay.sdk_script_url' => static function ( ContainerInterface $container ): string {
|
||||
'applepay.sdk_script_url' => static function ( ContainerInterface $container ): string {
|
||||
return 'https://applepay.cdn-apple.com/jsapi/v1/apple-pay-sdk.js';
|
||||
},
|
||||
'applepay.data_to_scripts' => static function ( ContainerInterface $container ): DataToAppleButtonScripts {
|
||||
'applepay.data_to_scripts' => static function ( ContainerInterface $container ): DataToAppleButtonScripts {
|
||||
return new DataToAppleButtonScripts( $container->get( 'applepay.sdk_script_url' ), $container->get( 'wcgateway.settings' ) );
|
||||
},
|
||||
'applepay.button' => static function ( ContainerInterface $container ): ApplePayButton {
|
||||
'applepay.button' => static function ( ContainerInterface $container ): ApplePayButton {
|
||||
|
||||
return new ApplePayButton(
|
||||
$container->get( 'wcgateway.settings' ),
|
||||
|
@ -69,7 +86,7 @@ return array(
|
|||
$container->get( 'wcgateway.settings.status' )
|
||||
);
|
||||
},
|
||||
'applepay.blocks-payment-method' => static function ( ContainerInterface $container ): PaymentMethodTypeInterface {
|
||||
'applepay.blocks-payment-method' => static function ( ContainerInterface $container ): PaymentMethodTypeInterface {
|
||||
return new BlocksPaymentMethod(
|
||||
'ppcp-applepay',
|
||||
$container->get( 'applepay.url' ),
|
||||
|
@ -78,4 +95,25 @@ return array(
|
|||
$container->get( 'blocks.method' )
|
||||
);
|
||||
},
|
||||
/**
|
||||
* The matrix which countries and currency combinations can be used for ApplePay.
|
||||
*/
|
||||
'applepay.supported-country-currency-matrix' => static function ( ContainerInterface $container ) : array {
|
||||
/**
|
||||
* Returns which countries and currency combinations can be used for ApplePay.
|
||||
*/
|
||||
return apply_filters(
|
||||
'woocommerce_paypal_payments_applepay_supported_country_currency_matrix',
|
||||
array(
|
||||
'US' => array(
|
||||
'AUD',
|
||||
'CAD',
|
||||
'EUR',
|
||||
'GBP',
|
||||
'JPY',
|
||||
'USD',
|
||||
),
|
||||
)
|
||||
);
|
||||
},
|
||||
);
|
||||
|
|
File diff suppressed because one or more lines are too long
|
@ -173,11 +173,19 @@ class DataToAppleButtonScripts {
|
|||
'<div id="applepay-container">'
|
||||
. $nonce
|
||||
. '</div>';
|
||||
$type = $this->settings->has( 'applepay_button_type' ) ? $this->settings->get( 'applepay_button_type' ) : '';
|
||||
$color = $this->settings->has( 'applepay_button_color' ) ? $this->settings->get( 'applepay_button_color' ) : '';
|
||||
$lang = $this->settings->has( 'applepay_button_language' ) ? $this->settings->get( 'applepay_button_language' ) : '';
|
||||
$lang = apply_filters( 'woocommerce_paypal_payments_applepay_button_language', $lang );
|
||||
|
||||
return array(
|
||||
'sdk_url' => $this->sdk_url,
|
||||
'button' => array(
|
||||
'wrapper' => 'applepay-container',
|
||||
'mini_cart_wrapper' => 'applepay-container-minicart',
|
||||
'type' => $type,
|
||||
'color' => $color,
|
||||
'lang' => $lang,
|
||||
),
|
||||
'product' => array(
|
||||
'needShipping' => $cart->needs_shipping(),
|
||||
|
|
67
modules/ppcp-applepay/src/Helper/ApmApplies.php
Normal file
67
modules/ppcp-applepay/src/Helper/ApmApplies.php
Normal file
|
@ -0,0 +1,67 @@
|
|||
<?php
|
||||
/**
|
||||
* ApmApplies helper.
|
||||
*
|
||||
* @package WooCommerce\PayPalCommerce\ApplePay\Helper
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace WooCommerce\PayPalCommerce\Applepay\Helper;
|
||||
|
||||
/**
|
||||
* Class ApmApplies
|
||||
*/
|
||||
class ApmApplies {
|
||||
|
||||
/**
|
||||
* The matrix which countries and currency combinations can be used for DCC.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
private $allowed_country_currency_matrix;
|
||||
|
||||
/**
|
||||
* 3-letter currency code of the shop.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
private $currency;
|
||||
|
||||
/**
|
||||
* 2-letter country code of the shop.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
private $country;
|
||||
|
||||
/**
|
||||
* ApmApplies constructor.
|
||||
*
|
||||
* @param array $allowed_country_currency_matrix The matrix which countries and currency combinations can be used for DCC.
|
||||
* @param string $currency 3-letter currency code of the shop.
|
||||
* @param string $country 2-letter country code of the shop.
|
||||
*/
|
||||
public function __construct(
|
||||
array $allowed_country_currency_matrix,
|
||||
string $currency,
|
||||
string $country
|
||||
) {
|
||||
$this->allowed_country_currency_matrix = $allowed_country_currency_matrix;
|
||||
$this->currency = $currency;
|
||||
$this->country = $country;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether ApplePay can be used in the current country and the current currency used.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function for_country_currency(): bool {
|
||||
if ( ! in_array( $this->country, array_keys( $this->allowed_country_currency_matrix ), true ) ) {
|
||||
return false;
|
||||
}
|
||||
return in_array( $this->currency, $this->allowed_country_currency_matrix[ $this->country ], true );
|
||||
}
|
||||
|
||||
}
|
|
@ -12,6 +12,7 @@ namespace WooCommerce\PayPalCommerce\Googlepay;
|
|||
use WooCommerce\PayPalCommerce\Googlepay\Helper\PropertiesDictionary;
|
||||
use WooCommerce\PayPalCommerce\Onboarding\State;
|
||||
use WooCommerce\PayPalCommerce\Vendor\Psr\Container\ContainerInterface;
|
||||
use WooCommerce\PayPalCommerce\WcGateway\Helper\DisplayManager;
|
||||
|
||||
|
||||
return array(
|
||||
|
@ -31,6 +32,9 @@ return array(
|
|||
return array_merge( array_slice( $array, 0, $pos ), $new, array_slice( $array, $pos ) );
|
||||
};
|
||||
|
||||
$display_manager = $container->get( 'wcgateway.display-manager' );
|
||||
assert( $display_manager instanceof DisplayManager );
|
||||
|
||||
return $insert_after(
|
||||
$fields,
|
||||
'allow_card_button_gateway',
|
||||
|
@ -52,20 +56,16 @@ return array(
|
|||
'gateway' => 'paypal',
|
||||
'requirements' => array(),
|
||||
'custom_attributes' => array(
|
||||
'data-ppcp-handlers' => wp_json_encode(
|
||||
'data-ppcp-display' => wp_json_encode(
|
||||
array(
|
||||
array(
|
||||
'handler' => 'SubElementsHandler',
|
||||
'options' => array(
|
||||
'values' => array( '1' ),
|
||||
'elements' => array(
|
||||
'#field-googlepay_button_color',
|
||||
'#field-googlepay_button_type',
|
||||
'#field-googlepay_button_language',
|
||||
'#field-googlepay_button_shipping_enabled',
|
||||
),
|
||||
),
|
||||
),
|
||||
$display_manager
|
||||
->rule()
|
||||
->condition_element( 'googlepay_button_enabled', '1' )
|
||||
->action_visible( 'googlepay_button_type' )
|
||||
->action_visible( 'googlepay_button_color' )
|
||||
->action_visible( 'googlepay_button_language' )
|
||||
->action_visible( 'googlepay_button_shipping_enabled' )
|
||||
->to_array(),
|
||||
)
|
||||
),
|
||||
),
|
||||
|
|
11
modules/ppcp-wc-gateway/resources/css/common.scss
Normal file
11
modules/ppcp-wc-gateway/resources/css/common.scss
Normal file
|
@ -0,0 +1,11 @@
|
|||
|
||||
.ppcp-field-hidden {
|
||||
display: none !important;
|
||||
}
|
||||
|
||||
.ppcp-field-disabled {
|
||||
cursor: not-allowed;
|
||||
-webkit-filter: grayscale(100%);
|
||||
filter: grayscale(100%);
|
||||
opacity: 0.5;
|
||||
}
|
|
@ -1,51 +0,0 @@
|
|||
|
||||
class SubElementsHandler {
|
||||
constructor(element, options) {
|
||||
const fieldSelector = 'input, select, textarea';
|
||||
|
||||
this.element = element;
|
||||
this.values = options.values;
|
||||
this.elements = options.elements;
|
||||
|
||||
this.elementsSelector = this.elements.join(',');
|
||||
|
||||
this.input = jQuery(this.element).is(fieldSelector)
|
||||
? this.element
|
||||
: jQuery(this.element).find(fieldSelector).get(0);
|
||||
|
||||
this.updateElementsVisibility();
|
||||
|
||||
jQuery(this.input).change(() => {
|
||||
this.updateElementsVisibility();
|
||||
});
|
||||
}
|
||||
|
||||
updateElementsVisibility() {
|
||||
const $elements = jQuery(this.elementsSelector);
|
||||
|
||||
let value = this.getValue(this.input);
|
||||
value = (value !== null ? value.toString() : value);
|
||||
|
||||
if (this.values.indexOf(value) !== -1) {
|
||||
$elements.removeClass('hide');
|
||||
} else {
|
||||
$elements.addClass('hide');
|
||||
}
|
||||
}
|
||||
|
||||
getValue(element) {
|
||||
const $el = jQuery(element);
|
||||
|
||||
if ($el.is(':checkbox') || $el.is(':radio')) {
|
||||
if ($el.is(':checked')) {
|
||||
return $el.val();
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
} else {
|
||||
return $el.val();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export default SubElementsHandler;
|
|
@ -1,10 +1,28 @@
|
|||
import DisplayManager from "./common/display-manager/DisplayManager";
|
||||
import moveWrappedElements from "./common/wrapped-elements";
|
||||
|
||||
document.addEventListener(
|
||||
'DOMContentLoaded',
|
||||
() => {
|
||||
|
||||
// Wait for current execution context to end.
|
||||
setTimeout(function () {
|
||||
moveWrappedElements();
|
||||
}, 0);
|
||||
|
||||
// Initialize DisplayManager.
|
||||
const displayManager = new DisplayManager();
|
||||
|
||||
jQuery( '*[data-ppcp-display]' ).each( (index, el) => {
|
||||
const rules = jQuery(el).data('ppcpDisplay');
|
||||
|
||||
console.log('rules', rules);
|
||||
|
||||
for (const rule of rules) {
|
||||
displayManager.addRule(rule);
|
||||
}
|
||||
});
|
||||
|
||||
displayManager.register();
|
||||
}
|
||||
);
|
||||
|
|
|
@ -0,0 +1,14 @@
|
|||
import ElementAction from "./action/ElementAction";
|
||||
|
||||
class ActionFactory {
|
||||
static make(actionConfig) {
|
||||
switch (actionConfig.type) {
|
||||
case 'element':
|
||||
return new ElementAction(actionConfig);
|
||||
}
|
||||
|
||||
throw new Error('[ActionFactory] Unknown action: ' + actionConfig.type);
|
||||
}
|
||||
}
|
||||
|
||||
export default ActionFactory;
|
|
@ -0,0 +1,17 @@
|
|||
import ElementCondition from "./condition/ElementCondition";
|
||||
import BoolCondition from "./condition/BoolCondition";
|
||||
|
||||
class ConditionFactory {
|
||||
static make(conditionConfig, triggerUpdate) {
|
||||
switch (conditionConfig.type) {
|
||||
case 'element':
|
||||
return new ElementCondition(conditionConfig, triggerUpdate);
|
||||
case 'bool':
|
||||
return new BoolCondition(conditionConfig, triggerUpdate);
|
||||
}
|
||||
|
||||
throw new Error('[ConditionFactory] Unknown condition: ' + conditionConfig.type);
|
||||
}
|
||||
}
|
||||
|
||||
export default ConditionFactory;
|
|
@ -0,0 +1,32 @@
|
|||
import Rule from "./Rule";
|
||||
|
||||
class DisplayManager {
|
||||
|
||||
constructor() {
|
||||
this.rules = {};
|
||||
this.ruleStatus = {}; // The current status for each rule. Maybe not necessary, for now just for logging.
|
||||
|
||||
document.ppcpDisplayManagerLog = () => {
|
||||
console.log('DisplayManager', this);
|
||||
}
|
||||
}
|
||||
|
||||
addRule(ruleConfig) {
|
||||
const updateStatus = () => {
|
||||
this.ruleStatus[ruleConfig.key] = this.rules[ruleConfig.key].status;
|
||||
console.log('ruleStatus', this.ruleStatus);
|
||||
}
|
||||
|
||||
this.rules[ruleConfig.key] = new Rule(ruleConfig, updateStatus.bind(this));
|
||||
console.log('Rule', this.rules[ruleConfig.key]);
|
||||
}
|
||||
|
||||
register() {
|
||||
this.ruleStatus = {};
|
||||
for (const [key, rule] of Object.entries(this.rules)) {
|
||||
rule.register();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export default DisplayManager;
|
|
@ -0,0 +1,68 @@
|
|||
import ConditionFactory from "./ConditionFactory";
|
||||
import ActionFactory from "./ActionFactory";
|
||||
|
||||
class Rule {
|
||||
|
||||
constructor(config, triggerUpdate) {
|
||||
this.config = config;
|
||||
this.conditions = {};
|
||||
this.actions = {};
|
||||
this.triggerUpdate = triggerUpdate;
|
||||
this.status = null;
|
||||
|
||||
const updateStatus = this.updateStatus.bind(this);
|
||||
for (const conditionConfig of this.config.conditions) {
|
||||
const condition = ConditionFactory.make(conditionConfig, updateStatus);
|
||||
this.conditions[condition.key] = condition;
|
||||
|
||||
console.log('Condition', condition);
|
||||
}
|
||||
|
||||
for (const actionConfig of this.config.actions) {
|
||||
const action = ActionFactory.make(actionConfig);
|
||||
this.actions[action.key] = action;
|
||||
|
||||
console.log('Action', action);
|
||||
}
|
||||
}
|
||||
|
||||
get key() {
|
||||
return this.config.key;
|
||||
}
|
||||
|
||||
updateStatus(forceRunActions = false) {
|
||||
let status = true;
|
||||
|
||||
for (const [key, condition] of Object.entries(this.conditions)) {
|
||||
status &= condition.status;
|
||||
}
|
||||
|
||||
if (status !== this.status) {
|
||||
this.status = status;
|
||||
this.triggerUpdate();
|
||||
this.runActions();
|
||||
} else if (forceRunActions) {
|
||||
this.runActions();
|
||||
}
|
||||
}
|
||||
|
||||
runActions() {
|
||||
for (const [key, action] of Object.entries(this.actions)) {
|
||||
action.run(this.status);
|
||||
}
|
||||
}
|
||||
|
||||
register() {
|
||||
for (const [key, condition] of Object.entries(this.conditions)) {
|
||||
condition.register(this.updateStatus.bind(this));
|
||||
}
|
||||
for (const [key, action] of Object.entries(this.actions)) {
|
||||
action.register();
|
||||
}
|
||||
|
||||
this.updateStatus(true);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export default Rule;
|
|
@ -0,0 +1,21 @@
|
|||
|
||||
class BaseAction {
|
||||
|
||||
constructor(config) {
|
||||
this.config = config;
|
||||
}
|
||||
|
||||
get key() {
|
||||
return this.config.key;
|
||||
}
|
||||
|
||||
register() {
|
||||
// To override.
|
||||
}
|
||||
|
||||
run(status) {
|
||||
// To override.
|
||||
}
|
||||
}
|
||||
|
||||
export default BaseAction;
|
|
@ -0,0 +1,35 @@
|
|||
import BaseAction from "./BaseAction";
|
||||
|
||||
class ElementAction extends BaseAction {
|
||||
|
||||
run(status) {
|
||||
|
||||
if (status) {
|
||||
if (this.config.action === 'visible') {
|
||||
jQuery(this.config.selector).removeClass('ppcp-field-hidden');
|
||||
}
|
||||
if (this.config.action === 'enable') {
|
||||
jQuery(this.config.selector).removeClass('ppcp-field-disabled')
|
||||
.off('mouseup')
|
||||
.find('> *')
|
||||
.css('pointer-events', '');
|
||||
}
|
||||
} else {
|
||||
if (this.config.action === 'visible') {
|
||||
jQuery(this.config.selector).addClass('ppcp-field-hidden');
|
||||
}
|
||||
if (this.config.action === 'enable') {
|
||||
jQuery(this.config.selector).addClass('ppcp-field-disabled')
|
||||
.on('mouseup', function(event) {
|
||||
event.stopImmediatePropagation();
|
||||
})
|
||||
.find('> *')
|
||||
.css('pointer-events', 'none');
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export default ElementAction;
|
|
@ -0,0 +1,19 @@
|
|||
|
||||
class BaseCondition {
|
||||
|
||||
constructor(config, triggerUpdate) {
|
||||
this.config = config;
|
||||
this.status = false;
|
||||
this.triggerUpdate = triggerUpdate;
|
||||
}
|
||||
|
||||
get key() {
|
||||
return this.config.key;
|
||||
}
|
||||
|
||||
register() {
|
||||
// To override.
|
||||
}
|
||||
}
|
||||
|
||||
export default BaseCondition;
|
|
@ -0,0 +1,15 @@
|
|||
import BaseCondition from "./BaseCondition";
|
||||
|
||||
class BoolCondition extends BaseCondition {
|
||||
|
||||
register() {
|
||||
this.status = this.check();
|
||||
}
|
||||
|
||||
check() {
|
||||
return !! this.config.value;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export default BoolCondition;
|
|
@ -0,0 +1,27 @@
|
|||
import BaseCondition from "./BaseCondition";
|
||||
import {inputValue} from "../../../helper/form";
|
||||
|
||||
class ElementCondition extends BaseCondition {
|
||||
|
||||
register() {
|
||||
jQuery(document).on('change', this.config.selector, () => {
|
||||
const status = this.check();
|
||||
if (status !== this.status) {
|
||||
this.status = status;
|
||||
this.triggerUpdate();
|
||||
}
|
||||
});
|
||||
|
||||
this.status = this.check();
|
||||
}
|
||||
|
||||
check() {
|
||||
let value = inputValue(this.config.selector);
|
||||
value = (value !== null ? value.toString() : value);
|
||||
|
||||
return this.config.value === value;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export default ElementCondition;
|
|
@ -4,7 +4,6 @@ import Renderer from '../../../ppcp-button/resources/js/modules/Renderer/Rendere
|
|||
import MessageRenderer from "../../../ppcp-button/resources/js/modules/Renderer/MessageRenderer";
|
||||
import {setVisibleByClass, isVisible} from "../../../ppcp-button/resources/js/modules/Helper/Hiding";
|
||||
import widgetBuilder from "../../../ppcp-button/resources/js/modules/Renderer/WidgetBuilder";
|
||||
import SubElementsHandler from "./SettingsHandler/SubElementsHandler";
|
||||
|
||||
document.addEventListener(
|
||||
'DOMContentLoaded',
|
||||
|
@ -308,16 +307,5 @@ document.addEventListener(
|
|||
createButtonPreview(() => getButtonDefaultSettings('#ppcpPayLaterButtonPreview'));
|
||||
});
|
||||
}
|
||||
|
||||
// Generic behaviours, can be moved to common.js once it's on trunk branch.
|
||||
jQuery( '*[data-ppcp-handlers]' ).each( (index, el) => {
|
||||
const handlers = jQuery(el).data('ppcpHandlers');
|
||||
for (const handlerConfig of handlers) {
|
||||
new {
|
||||
SubElementsHandler: SubElementsHandler
|
||||
}[handlerConfig.handler](el, handlerConfig.options)
|
||||
}
|
||||
});
|
||||
|
||||
}
|
||||
);
|
||||
|
|
13
modules/ppcp-wc-gateway/resources/js/helper/form.js
Normal file
13
modules/ppcp-wc-gateway/resources/js/helper/form.js
Normal file
|
@ -0,0 +1,13 @@
|
|||
export const inputValue = (element) => {
|
||||
const $el = jQuery(element);
|
||||
|
||||
if ($el.is(':checkbox') || $el.is(':radio')) {
|
||||
if ($el.is(':checked')) {
|
||||
return $el.val();
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
} else {
|
||||
return $el.val();
|
||||
}
|
||||
}
|
|
@ -11,21 +11,18 @@ declare(strict_types=1);
|
|||
|
||||
namespace WooCommerce\PayPalCommerce\WcGateway;
|
||||
|
||||
use WooCommerce\PayPalCommerce\ApiClient\Endpoint\BillingAgreementsEndpoint;
|
||||
use WooCommerce\PayPalCommerce\Session\SessionHandler;
|
||||
use WooCommerce\PayPalCommerce\Vendor\Psr\Container\ContainerInterface;
|
||||
use WooCommerce\PayPalCommerce\ApiClient\Authentication\Bearer;
|
||||
use WooCommerce\PayPalCommerce\ApiClient\Endpoint\PayUponInvoiceOrderEndpoint;
|
||||
use WooCommerce\PayPalCommerce\ApiClient\Entity\ApplicationContext;
|
||||
use WooCommerce\PayPalCommerce\ApiClient\Exception\RuntimeException;
|
||||
use WooCommerce\PayPalCommerce\ApiClient\Helper\Cache;
|
||||
use WooCommerce\PayPalCommerce\ApiClient\Helper\DccApplies;
|
||||
use WooCommerce\PayPalCommerce\Button\Helper\MessagesApply;
|
||||
use WooCommerce\PayPalCommerce\Button\Helper\MessagesDisclaimers;
|
||||
use WooCommerce\PayPalCommerce\Common\Pattern\SingletonDecorator;
|
||||
use WooCommerce\PayPalCommerce\Onboarding\Environment;
|
||||
use WooCommerce\PayPalCommerce\Onboarding\Render\OnboardingOptionsRenderer;
|
||||
use WooCommerce\PayPalCommerce\Onboarding\State;
|
||||
use WooCommerce\PayPalCommerce\Subscription\Helper\SubscriptionHelper;
|
||||
use WooCommerce\PayPalCommerce\Vendor\Psr\Container\ContainerInterface;
|
||||
use WooCommerce\PayPalCommerce\WcGateway\Admin\FeesRenderer;
|
||||
use WooCommerce\PayPalCommerce\WcGateway\Admin\OrderTablePaymentStatusColumn;
|
||||
use WooCommerce\PayPalCommerce\WcGateway\Admin\PaymentStatusOrderDetail;
|
||||
|
@ -35,6 +32,9 @@ use WooCommerce\PayPalCommerce\WcGateway\Checkout\CheckoutPayPalAddressPreset;
|
|||
use WooCommerce\PayPalCommerce\WcGateway\Checkout\DisableGateways;
|
||||
use WooCommerce\PayPalCommerce\WcGateway\Cli\SettingsCommand;
|
||||
use WooCommerce\PayPalCommerce\WcGateway\Endpoint\ReturnUrlEndpoint;
|
||||
use WooCommerce\PayPalCommerce\WcGateway\FraudNet\FraudNet;
|
||||
use WooCommerce\PayPalCommerce\WcGateway\FraudNet\FraudNetSessionId;
|
||||
use WooCommerce\PayPalCommerce\WcGateway\FraudNet\FraudNetSourceWebsiteId;
|
||||
use WooCommerce\PayPalCommerce\WcGateway\FundingSource\FundingSourceRenderer;
|
||||
use WooCommerce\PayPalCommerce\WcGateway\Gateway\CardButtonGateway;
|
||||
use WooCommerce\PayPalCommerce\WcGateway\Gateway\CreditCardGateway;
|
||||
|
@ -42,15 +42,13 @@ use WooCommerce\PayPalCommerce\WcGateway\Gateway\GatewayRepository;
|
|||
use WooCommerce\PayPalCommerce\WcGateway\Gateway\OXXO\OXXO;
|
||||
use WooCommerce\PayPalCommerce\WcGateway\Gateway\OXXO\OXXOGateway;
|
||||
use WooCommerce\PayPalCommerce\WcGateway\Gateway\PayPalGateway;
|
||||
use WooCommerce\PayPalCommerce\WcGateway\FraudNet\FraudNet;
|
||||
use WooCommerce\PayPalCommerce\WcGateway\FraudNet\FraudNetSessionId;
|
||||
use WooCommerce\PayPalCommerce\WcGateway\FraudNet\FraudNetSourceWebsiteId;
|
||||
use WooCommerce\PayPalCommerce\WcGateway\Gateway\PayUponInvoice\PaymentSourceFactory;
|
||||
use WooCommerce\PayPalCommerce\WcGateway\Gateway\PayUponInvoice\PayUponInvoice;
|
||||
use WooCommerce\PayPalCommerce\WcGateway\Gateway\PayUponInvoice\PayUponInvoiceGateway;
|
||||
use WooCommerce\PayPalCommerce\WcGateway\Gateway\TransactionUrlProvider;
|
||||
use WooCommerce\PayPalCommerce\WcGateway\Helper\CheckoutHelper;
|
||||
use WooCommerce\PayPalCommerce\WcGateway\Helper\DCCProductStatus;
|
||||
use WooCommerce\PayPalCommerce\WcGateway\Helper\DisplayManager;
|
||||
use WooCommerce\PayPalCommerce\WcGateway\Helper\PayUponInvoiceHelper;
|
||||
use WooCommerce\PayPalCommerce\WcGateway\Helper\PayUponInvoiceProductStatus;
|
||||
use WooCommerce\PayPalCommerce\WcGateway\Helper\RefundFeesUpdater;
|
||||
|
@ -933,6 +931,7 @@ return array(
|
|||
'wcgateway.extra-funding-sources' => static function( ContainerInterface $container ): array {
|
||||
return array(
|
||||
'googlepay' => _x( 'Google Pay', 'Name of payment method', 'woocommerce-paypal-payments' ),
|
||||
'applepay' => _x( 'Apple Pay', 'Name of payment method', 'woocommerce-paypal-payments' ),
|
||||
);
|
||||
},
|
||||
|
||||
|
@ -1399,4 +1398,10 @@ return array(
|
|||
$container->get( 'wcgateway.settings' )
|
||||
);
|
||||
},
|
||||
'wcgateway.display-manager' => SingletonDecorator::make(
|
||||
static function( ContainerInterface $container ): DisplayManager {
|
||||
$settings = $container->get( 'wcgateway.settings' );
|
||||
return new DisplayManager( $settings );
|
||||
}
|
||||
),
|
||||
);
|
||||
|
|
|
@ -229,6 +229,13 @@ class SettingsPageAssets {
|
|||
* Register assets for PayPal admin pages.
|
||||
*/
|
||||
private function register_admin_assets(): void {
|
||||
wp_enqueue_style(
|
||||
'ppcp-admin-common',
|
||||
trailingslashit( $this->module_url ) . 'assets/css/common.css',
|
||||
array(),
|
||||
$this->version
|
||||
);
|
||||
|
||||
wp_enqueue_script(
|
||||
'ppcp-admin-common',
|
||||
trailingslashit( $this->module_url ) . 'assets/js/common.js',
|
||||
|
|
60
modules/ppcp-wc-gateway/src/Helper/DisplayManager.php
Normal file
60
modules/ppcp-wc-gateway/src/Helper/DisplayManager.php
Normal file
|
@ -0,0 +1,60 @@
|
|||
<?php
|
||||
/**
|
||||
* Helper to manage the field display behaviour.
|
||||
*
|
||||
* @package WooCommerce\PayPalCommerce\WcGateway\Helper;
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace WooCommerce\PayPalCommerce\WcGateway\Helper;
|
||||
|
||||
use WooCommerce\PayPalCommerce\WcGateway\Settings\Settings;
|
||||
|
||||
/**
|
||||
* DisplayManager class.
|
||||
*/
|
||||
class DisplayManager {
|
||||
|
||||
/**
|
||||
* The settings.
|
||||
*
|
||||
* @var Settings
|
||||
*/
|
||||
private $settings;
|
||||
|
||||
/**
|
||||
* The rules.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $rules = array();
|
||||
|
||||
/**
|
||||
* FieldDisplayManager constructor.
|
||||
*
|
||||
* @param Settings $settings The settings.
|
||||
* @return void
|
||||
*/
|
||||
public function __construct( Settings $settings ) {
|
||||
$this->settings = $settings;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates and returns a rule.
|
||||
*
|
||||
* @param string|null $key The rule key.
|
||||
* @return DisplayRule
|
||||
*/
|
||||
public function rule( string $key = null ): DisplayRule {
|
||||
if ( null === $key ) {
|
||||
$key = '_rule_' . ( (string) count( $this->rules ) );
|
||||
}
|
||||
|
||||
$rule = new DisplayRule( $key, $this->settings );
|
||||
|
||||
$this->rules[ $key ] = $rule;
|
||||
return $rule;
|
||||
}
|
||||
|
||||
}
|
262
modules/ppcp-wc-gateway/src/Helper/DisplayRule.php
Normal file
262
modules/ppcp-wc-gateway/src/Helper/DisplayRule.php
Normal file
|
@ -0,0 +1,262 @@
|
|||
<?php
|
||||
/**
|
||||
* Element used by field display manager.
|
||||
*
|
||||
* @package WooCommerce\PayPalCommerce\WcGateway\Helper;
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace WooCommerce\PayPalCommerce\WcGateway\Helper;
|
||||
|
||||
use WooCommerce\PayPalCommerce\WcGateway\Settings\Settings;
|
||||
|
||||
/**
|
||||
* DisplayRule class.
|
||||
*/
|
||||
class DisplayRule {
|
||||
|
||||
const CONDITION_TYPE_ELEMENT = 'element';
|
||||
const CONDITION_TYPE_BOOL = 'bool';
|
||||
|
||||
const CONDITION_OPERATION_EQUALS = 'equals';
|
||||
const CONDITION_OPERATION_NOT_EQUALS = 'not_equals';
|
||||
const CONDITION_OPERATION_IN = 'in';
|
||||
const CONDITION_OPERATION_NOT_IN = 'not_in';
|
||||
const CONDITION_OPERATION_EMPTY = 'empty';
|
||||
const CONDITION_OPERATION_NOT_EMPTY = 'not_empty';
|
||||
|
||||
const ACTION_TYPE_ELEMENT = 'element';
|
||||
|
||||
const ACTION_VISIBLE = 'visible';
|
||||
const ACTION_ENABLE = 'enable';
|
||||
|
||||
/**
|
||||
* The element selector.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $key;
|
||||
|
||||
/**
|
||||
* The settings.
|
||||
*
|
||||
* @var Settings
|
||||
*/
|
||||
private $settings;
|
||||
|
||||
/**
|
||||
* The conditions of this rule.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $conditions = array();
|
||||
|
||||
/**
|
||||
* The actions of this rule.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $actions = array();
|
||||
|
||||
/**
|
||||
* Indicates if this class should add selector prefixes.
|
||||
*
|
||||
* @var bool
|
||||
*/
|
||||
protected $add_selector_prefixes = true;
|
||||
|
||||
/**
|
||||
* FieldDisplayElement constructor.
|
||||
*
|
||||
* @param string $key The rule key.
|
||||
* @param Settings $settings The settings.
|
||||
*/
|
||||
public function __construct( string $key, Settings $settings ) {
|
||||
$this->key = $key;
|
||||
$this->settings = $settings;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a condition related to an HTML element.
|
||||
*
|
||||
* @param string $selector The condition selector.
|
||||
* @param mixed $value The value to compare against.
|
||||
* @param string $operation The condition operation (ex: equals, differs, in, not_empty, empty).
|
||||
* @return self
|
||||
*/
|
||||
public function condition_element( string $selector, $value, string $operation = self::CONDITION_OPERATION_EQUALS ): self {
|
||||
$this->add_condition(
|
||||
array(
|
||||
'type' => self::CONDITION_TYPE_ELEMENT,
|
||||
'selector' => $selector,
|
||||
'operation' => $operation,
|
||||
'value' => $value,
|
||||
)
|
||||
);
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a condition related to a bool check.
|
||||
*
|
||||
* @param bool $value The value to enable / disable the condition.
|
||||
* @return self
|
||||
*/
|
||||
public function condition_is_true( bool $value ): self {
|
||||
$this->add_condition(
|
||||
array(
|
||||
'type' => self::CONDITION_TYPE_BOOL,
|
||||
'value' => $value,
|
||||
)
|
||||
);
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a condition related to the settings.
|
||||
*
|
||||
* @param string $settings_key The settings key.
|
||||
* @param mixed $value The value to compare against.
|
||||
* @param string $operation The condition operation (ex: equals, differs, in, not_empty, empty).
|
||||
* @return self
|
||||
*/
|
||||
public function condition_is_settings( string $settings_key, $value, string $operation = self::CONDITION_OPERATION_EQUALS ): self {
|
||||
$settings_value = null;
|
||||
|
||||
if ( $this->settings->has( $settings_key ) ) {
|
||||
$settings_value = $this->settings->get( $settings_key );
|
||||
}
|
||||
|
||||
$this->condition_is_true( $this->resolve_operation( $settings_value, $value, $operation ) );
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a condition to show/hide the element.
|
||||
*
|
||||
* @param string $selector The condition selector.
|
||||
*/
|
||||
public function action_visible( string $selector ): self {
|
||||
$this->add_action(
|
||||
array(
|
||||
'type' => self::ACTION_TYPE_ELEMENT,
|
||||
'selector' => $selector,
|
||||
'action' => self::ACTION_VISIBLE,
|
||||
)
|
||||
);
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a condition to enable/disable the element.
|
||||
*
|
||||
* @param string $selector The condition selector.
|
||||
*/
|
||||
public function action_enable( string $selector ): self {
|
||||
$this->add_action(
|
||||
array(
|
||||
'type' => self::ACTION_TYPE_ELEMENT,
|
||||
'selector' => $selector,
|
||||
'action' => self::ACTION_ENABLE,
|
||||
)
|
||||
);
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a condition to the rule.
|
||||
*
|
||||
* @param array $options The condition options.
|
||||
* @return void
|
||||
*/
|
||||
private function add_condition( array $options ): void {
|
||||
if ( $this->add_selector_prefixes && isset( $options['selector'] ) ) {
|
||||
$options['selector'] = '#ppcp-' . $options['selector']; // Refers to the input.
|
||||
}
|
||||
|
||||
if ( ! isset( $options['key'] ) ) {
|
||||
$options['key'] = '_condition_' . ( (string) count( $this->conditions ) );
|
||||
}
|
||||
|
||||
$this->conditions[] = $options;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds an action to do.
|
||||
*
|
||||
* @param array $options The action options.
|
||||
* @return void
|
||||
*/
|
||||
private function add_action( array $options ): void {
|
||||
if ( $this->add_selector_prefixes && isset( $options['selector'] ) ) {
|
||||
$options['selector'] = '#field-' . $options['selector']; // Refers to the whole field.
|
||||
}
|
||||
|
||||
if ( ! isset( $options['key'] ) ) {
|
||||
$options['key'] = '_action_' . ( (string) count( $this->actions ) );
|
||||
}
|
||||
|
||||
$this->actions[] = $options;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set if selector prefixes like, "#ppcp-" or "#field-" should be added to condition or action selectors.
|
||||
*
|
||||
* @param bool $add_selector_prefixes If should add prefixes.
|
||||
* @return self
|
||||
*/
|
||||
public function should_add_selector_prefixes( bool $add_selector_prefixes = true ): self {
|
||||
$this->add_selector_prefixes = $add_selector_prefixes;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a condition related to the settings.
|
||||
*
|
||||
* @param mixed $value_1 The value 1.
|
||||
* @param mixed $value_2 The value 2.
|
||||
* @param string $operation The condition operation (ex: equals, differs, in, not_empty, empty).
|
||||
* @return bool
|
||||
*/
|
||||
private function resolve_operation( $value_1, $value_2, string $operation ): bool {
|
||||
switch ( $operation ) {
|
||||
case self::CONDITION_OPERATION_EQUALS:
|
||||
return $value_1 === $value_2;
|
||||
case self::CONDITION_OPERATION_NOT_EQUALS:
|
||||
return $value_1 !== $value_2;
|
||||
case self::CONDITION_OPERATION_IN:
|
||||
return in_array( $value_1, $value_2, true );
|
||||
case self::CONDITION_OPERATION_NOT_IN:
|
||||
return ! in_array( $value_1, $value_2, true );
|
||||
case self::CONDITION_OPERATION_EMPTY:
|
||||
return empty( $value_1 );
|
||||
case self::CONDITION_OPERATION_NOT_EMPTY:
|
||||
return ! empty( $value_1 );
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns array representation.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function to_array(): array {
|
||||
return array(
|
||||
'key' => $this->key,
|
||||
'conditions' => $this->conditions,
|
||||
'actions' => $this->actions,
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns JSON representation.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function json(): string {
|
||||
return wp_json_encode( $this->to_array() ) ?: '';
|
||||
}
|
||||
|
||||
}
|
|
@ -17,6 +17,7 @@ use WooCommerce\PayPalCommerce\ApiClient\Helper\DccApplies;
|
|||
use WooCommerce\PayPalCommerce\Onboarding\Environment;
|
||||
use WooCommerce\PayPalCommerce\Onboarding\Render\OnboardingOptionsRenderer;
|
||||
use WooCommerce\PayPalCommerce\Onboarding\State;
|
||||
use WooCommerce\PayPalCommerce\WcGateway\Helper\DisplayManager;
|
||||
|
||||
return function ( ContainerInterface $container, array $fields ): array {
|
||||
|
||||
|
@ -39,6 +40,9 @@ return function ( ContainerInterface $container, array $fields ): array {
|
|||
|
||||
$module_url = $container->get( 'wcgateway.url' );
|
||||
|
||||
$display_manager = $container->get( 'wcgateway.display-manager' );
|
||||
assert( $display_manager instanceof DisplayManager );
|
||||
|
||||
$connection_fields = array(
|
||||
'ppcp_onboarading_header' => array(
|
||||
'type' => 'ppcp-text',
|
||||
|
@ -504,15 +508,13 @@ return function ( ContainerInterface $container, array $fields ): array {
|
|||
'requirements' => array(),
|
||||
'gateway' => Settings::CONNECTION_TAB_ID,
|
||||
'custom_attributes' => array(
|
||||
'data-ppcp-handlers' => wp_json_encode(
|
||||
'data-ppcp-display' => wp_json_encode(
|
||||
array(
|
||||
array(
|
||||
'handler' => 'SubElementsHandler',
|
||||
'options' => array(
|
||||
'values' => array( PurchaseUnitSanitizer::MODE_EXTRA_LINE ),
|
||||
'elements' => array( '#field-subtotal_mismatch_line_name' ),
|
||||
),
|
||||
),
|
||||
$display_manager
|
||||
->rule()
|
||||
->condition_element( 'subtotal_mismatch_behavior', PurchaseUnitSanitizer::MODE_EXTRA_LINE )
|
||||
->action_visible( 'subtotal_mismatch_line_name' )
|
||||
->to_array(),
|
||||
)
|
||||
),
|
||||
),
|
||||
|
|
|
@ -11,6 +11,7 @@ module.exports = {
|
|||
'fraudnet': path.resolve('./resources/js/fraudnet.js'),
|
||||
'oxxo': path.resolve('./resources/js/oxxo.js'),
|
||||
'gateway-settings-style': path.resolve('./resources/css/gateway-settings.scss'),
|
||||
'common-style': path.resolve('./resources/css/common.scss'),
|
||||
},
|
||||
output: {
|
||||
path: path.resolve(__dirname, 'assets/'),
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue