mirror of
https://github.com/woocommerce/woocommerce-paypal-payments.git
synced 2025-09-05 08:59:14 +08:00
🇲🇽 Add Mexico-specific logic for the new UI
This commit is contained in:
parent
82af3c07c9
commit
6738f80efc
22 changed files with 456 additions and 87 deletions
|
@ -61,6 +61,7 @@ return array(
|
|||
'LT',
|
||||
'LU',
|
||||
'MT',
|
||||
'MX',
|
||||
'NL',
|
||||
'PL',
|
||||
'PT',
|
||||
|
|
|
@ -73,7 +73,8 @@ return array(
|
|||
$container->get( 'wcgateway.settings' ),
|
||||
$container->get( 'api.endpoint.partners' ),
|
||||
$container->get( 'settings.flag.is-connected' ),
|
||||
$container->get( 'api.helper.failure-registry' )
|
||||
$container->get( 'api.helper.failure-registry' ),
|
||||
$container->get( 'woocommerce.logger.woocommerce' )
|
||||
);
|
||||
},
|
||||
'ppcp-local-apms.bancontact.wc-gateway' => static function ( ContainerInterface $container ): BancontactGateway {
|
||||
|
|
16
modules/ppcp-settings/images/icon-button-oxxo.svg
Normal file
16
modules/ppcp-settings/images/icon-button-oxxo.svg
Normal file
|
@ -0,0 +1,16 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<svg width="30px" height="30px" viewBox="0 0 42 20" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
|
||||
<title>OXXO</title>
|
||||
<defs/>
|
||||
<g id="Page-1" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
|
||||
<g id="SPB_&_AltPay_NewAssets" transform="translate(-100.000000, -159.000000)">
|
||||
<g id="logo-OXXO" transform="translate(100.000000, 159.000000)">
|
||||
<path d="M0.142456528,1.48437917 C0.142456528,0.77043992 0.728159303,0.186243119 1.44446761,0.186243119 L40.6503931,0.186243119 C41.3667014,0.186243119 41.9524042,0.77043992 41.9524042,1.48437917 L41.9524042,18.1011373 C41.9524042,18.8150765 41.3667014,19.3990362 40.6503931,19.3990362 L1.44446761,19.3990362 C0.728159303,19.3990362 0.142456528,18.8150765 0.142456528,18.1011373 L0.142456528,1.48437917 Z" id="Fill-2" fill="#EDA42D"/>
|
||||
<polygon id="Fill-4" fill="#FEFEFE" points="0.142480318 17.5124813 41.952428 17.5124813 41.952428 2.07265562 0.142480318 2.07265562"/>
|
||||
<path d="M35.5752619,6.08262231 C33.662331,6.08262231 32.1029152,7.63763417 32.1029152,9.54463469 C32.1029152,11.4511608 33.662331,13.0064099 35.5752619,13.0064099 C37.4877171,13.0064099 39.0471329,11.4511608 39.0471329,9.54463469 C39.0471329,7.63763417 37.4877171,6.08262231 35.5752619,6.08262231" id="Fill-6" fill="#EC1D24"/>
|
||||
<path d="M6.95585459,6.08262231 C5.04268574,6.08262231 3.48326994,7.63763417 3.48326994,9.54463469 C3.48326994,11.4511608 5.04268574,13.0064099 6.95585459,13.0064099 C8.86807185,13.0064099 10.4277255,11.4511608 10.4277255,9.54463469 C10.4277255,7.63763417 8.86807185,6.08262231 6.95585459,6.08262231" id="Fill-7" fill="#EC1D24"/>
|
||||
<path d="M35.5752619,15.0141446 C32.5537303,15.0141446 30.0893537,12.5573397 30.0893537,9.54480072 C30.0893537,6.53155015 32.5537303,4.07521964 35.5752619,4.07521964 C38.5970315,4.07521964 41.0609322,6.53155015 41.0609322,9.54480072 C41.0609322,12.5573397 38.5970315,15.0141446 35.5752619,15.0141446 Z M12.4411918,9.54480072 C12.4411918,12.5573397 9.97729109,15.0141446 6.95575943,15.0141446 C3.93351408,15.0141446 1.46985124,12.5573397 1.46985124,9.54480072 C1.46985124,6.53155015 3.93351408,4.07521964 6.95575943,4.07521964 C9.97729109,4.07521964 12.4411918,6.53155015 12.4411918,9.54480072 Z M35.3028697,3.03585692 C32.0884035,2.9620911 30.5772808,5.01709763 28.384107,7.55170056 L26.3151155,9.94232969 L29.591435,13.8526295 C30.3719756,15.0542296 28.8822636,16.2465793 27.9580332,15.1472077 L24.9288888,11.5447794 L21.9772989,14.9562705 C21.0373673,16.0421223 19.5645461,14.8288999 20.3617394,13.6386849 L23.5659761,9.92382894 L21.4667717,7.42693908 L22.8173138,5.75949957 L24.9522028,8.31639828 L26.7923372,6.18217058 C27.6953948,5.13569219 28.6162946,3.74884741 29.8098246,3.03585692 L0.142385159,3.03585692 L0.142385159,16.549707 L7.07875226,16.549707 C10.2934564,16.549707 11.7529554,14.6332189 13.8866549,12.0492806 L15.8999784,9.61097649 L12.5334959,5.77752594 C11.726073,4.59418943 13.1874752,3.36815887 14.1371606,4.44594623 L17.2483795,7.9779294 L20.1209875,4.49931378 C21.0354641,3.39164059 22.5356435,4.57118208 21.7662842,5.77942346 L18.6486421,9.56757088 L20.8051797,12.0153626 L19.4463112,13.6197098 L17.2997653,11.2058361 L15.5095892,13.3813347 C14.6310351,14.4484486 13.7415376,15.8094397 12.5646605,16.549707 L41.9523328,16.549707 L41.9523328,3.03585692 L35.3028697,3.03585692 Z" id="Fill-8" fill="#EC1D24"/>
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
</svg>
|
After Width: | Height: | Size: 3.5 KiB |
|
@ -42,7 +42,8 @@ const PaymentFlow = ( {
|
|||
/>
|
||||
);
|
||||
}
|
||||
const description = useAcdc ? optionalDescription : '';
|
||||
const description =
|
||||
useAcdc && 'MX' !== storeCountry ? optionalDescription : '';
|
||||
return (
|
||||
<div className="ppcp-r-welcome-docs__wrapper">
|
||||
<DefaultMethodsSection
|
||||
|
|
|
@ -1,20 +1,29 @@
|
|||
import { __ } from '@wordpress/i18n';
|
||||
import { useWooSettings } from '../../../../../data/common/hooks';
|
||||
import PricingTitleBadge from '../../../../ReusableComponents/PricingTitleBadge';
|
||||
import BadgeBox from '../../../../ReusableComponents/BadgeBox';
|
||||
|
||||
const AlternativePaymentMethods = ( { learnMore = '' } ) => {
|
||||
const { storeCountry } = useWooSettings();
|
||||
|
||||
// Determine which icons to display based on the country code.
|
||||
const imageBadges =
|
||||
storeCountry === 'MX'
|
||||
? [ 'icon-button-oxxo.svg' ]
|
||||
: [
|
||||
// 'icon-button-sepa.svg', // Enable this when the SEPA-Gateway is ready.
|
||||
'icon-button-ideal.svg',
|
||||
'icon-button-blik.svg',
|
||||
'icon-button-bancontact.svg',
|
||||
];
|
||||
|
||||
return (
|
||||
<BadgeBox
|
||||
title={ __(
|
||||
'Alternative Payment Methods',
|
||||
'woocommerce-paypal-payments'
|
||||
) }
|
||||
imageBadge={ [
|
||||
// 'icon-button-sepa.svg', // Enable this when the SEPA-Gateway is ready.
|
||||
'icon-button-ideal.svg',
|
||||
'icon-button-blik.svg',
|
||||
'icon-button-bancontact.svg',
|
||||
] }
|
||||
imageBadge={ imageBadges }
|
||||
textBadge={ <PricingTitleBadge item="apm" /> }
|
||||
description={ __(
|
||||
'Seamless payments for customers across the globe using their preferred payment methods.',
|
||||
|
|
|
@ -10,13 +10,13 @@ import PaymentFlow from '../Components/PaymentFlow';
|
|||
const StepPaymentMethods = () => {
|
||||
const { optionalMethods, setOptionalMethods } =
|
||||
OnboardingHooks.useOptionalPaymentMethods();
|
||||
const { ownBrandOnly } = CommonHooks.useWooSettings();
|
||||
const { ownBrandOnly, storeCountry } = CommonHooks.useWooSettings();
|
||||
const { isCasualSeller } = OnboardingHooks.useBusiness();
|
||||
const { canUseCardPayments } = OnboardingHooks.useFlags();
|
||||
|
||||
const optionalMethodTitle = useMemo( () => {
|
||||
// The BCDC flow does not show a title. !acdc does not show a title.
|
||||
if ( isCasualSeller || ! canUseCardPayments ) {
|
||||
// The BCDC flow does not show a title. !acdc does not show a title. Mexico does not show a title.
|
||||
if ( isCasualSeller || ! canUseCardPayments || 'MX' === storeCountry ) {
|
||||
return null;
|
||||
}
|
||||
|
||||
|
@ -24,7 +24,7 @@ const StepPaymentMethods = () => {
|
|||
'Available with additional application',
|
||||
'woocommerce-paypal-payments'
|
||||
);
|
||||
}, [ isCasualSeller, canUseCardPayments ] );
|
||||
}, [ isCasualSeller, canUseCardPayments, storeCountry ] );
|
||||
|
||||
const methodChoices = [
|
||||
{
|
||||
|
@ -34,7 +34,7 @@ const StepPaymentMethods = () => {
|
|||
},
|
||||
{
|
||||
title:
|
||||
ownBrandOnly || ! canUseCardPayments
|
||||
ownBrandOnly || ! canUseCardPayments || 'MX' === storeCountry
|
||||
? __(
|
||||
'No thanks, I prefer to use a different provider for local payment methods',
|
||||
'woocommerce-paypal-payments'
|
||||
|
@ -87,7 +87,9 @@ const OptionalMethodDescription = () => {
|
|||
return (
|
||||
<PaymentFlow
|
||||
onlyOptional={ true }
|
||||
useAcdc={ ! isCasualSeller && canUseCardPayments }
|
||||
useAcdc={
|
||||
! isCasualSeller && canUseCardPayments && 'MX' !== storeCountry
|
||||
}
|
||||
isFastlane={ true }
|
||||
isPayLater={ true }
|
||||
ownBrandOnly={ ownBrandOnly }
|
||||
|
|
|
@ -14,6 +14,7 @@ import { usePaymentConfig } from '../hooks/usePaymentConfig';
|
|||
const StepWelcome = ( { setStep, currentStep } ) => {
|
||||
const { storeCountry, ownBrandOnly } = CommonHooks.useWooSettings();
|
||||
const { canUseCardPayments, canUseFastlane } = OnboardingHooks.useFlags();
|
||||
const { isCasualSeller } = OnboardingHooks.useBusiness();
|
||||
|
||||
const { icons } = usePaymentConfig(
|
||||
storeCountry,
|
||||
|
@ -23,7 +24,7 @@ const StepWelcome = ( { setStep, currentStep } ) => {
|
|||
);
|
||||
|
||||
const onboardingHeaderDescription =
|
||||
canUseCardPayments && ! ownBrandOnly
|
||||
canUseCardPayments && ! ownBrandOnly && 'MX' !== storeCountry
|
||||
? __(
|
||||
'Your all-in-one integration for PayPal checkout solutions that enable buyers to pay via PayPal, Pay Later, all major credit/debit cards, Apple Pay, Google Pay, and more.',
|
||||
'woocommerce-paypal-payments'
|
||||
|
|
|
@ -15,6 +15,8 @@ import {
|
|||
CreditDebitCards,
|
||||
} from '../Components/PaymentOptions';
|
||||
|
||||
import { useWooSettings } from '../../../../data/common/hooks';
|
||||
|
||||
// List of all payment icons and which requirements they have.
|
||||
const PAYMENT_ICONS = [
|
||||
{ name: 'paypal', always: true },
|
||||
|
@ -28,6 +30,7 @@ const PAYMENT_ICONS = [
|
|||
{ name: 'blik', isOwnBrand: true, onlyAcdc: true },
|
||||
{ name: 'ideal', isOwnBrand: true, onlyAcdc: true },
|
||||
{ name: 'bancontact', isOwnBrand: true, onlyAcdc: true },
|
||||
{ name: 'oxxo', isOwnBrand: true, onlyAcdc: false, countries: [ 'MX' ] },
|
||||
];
|
||||
|
||||
// Default configuration, used for all countries, unless they override individual attributes below.
|
||||
|
@ -211,6 +214,11 @@ const getRelevantIcons = ( country, includeAcdc, onlyBranded ) =>
|
|||
return true;
|
||||
}
|
||||
|
||||
// If we're in Mexico, only show OXXO from the APMs.
|
||||
if ( country === 'MX' && onlyAcdc ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if ( onlyBranded && ! isOwnBrand ) {
|
||||
return false;
|
||||
}
|
||||
|
@ -251,6 +259,7 @@ export const usePaymentConfig = (
|
|||
hasFastlane,
|
||||
ownBrandOnly
|
||||
) => {
|
||||
const { countryCode } = useWooSettings();
|
||||
return useMemo( () => {
|
||||
// eslint-disable-next-line no-console
|
||||
console.log( '[Payment Config]', {
|
||||
|
@ -277,8 +286,11 @@ export const usePaymentConfig = (
|
|||
const availableOptionalMethods = filterMethods(
|
||||
config.extendedMethods,
|
||||
[
|
||||
// Either include Acdc or non-Acdc methods.
|
||||
( method ) => method.isAcdc === canUseCardPayments,
|
||||
// Either include Acdc or non-Acdc methods except for Mexico.
|
||||
( method ) =>
|
||||
countryCode === 'MX'
|
||||
? ! method.isAcdc || canUseCardPayments
|
||||
: method.isAcdc === canUseCardPayments,
|
||||
// Only include own-brand methods when ownBrandOnly is true.
|
||||
( method ) => ! ownBrandOnly || method.isOwnBrand === true,
|
||||
// Only include Fastlane when hasFastlane is true.
|
||||
|
|
|
@ -6,7 +6,10 @@ import FeatureItem from './FeatureItem';
|
|||
import FeatureDescription from './FeatureDescription';
|
||||
import { ContentWrapper } from '../../../../../ReusableComponents/Elements';
|
||||
import SettingsCard from '../../../../../ReusableComponents/SettingsCard';
|
||||
import { useMerchantInfo } from '../../../../../../data/common/hooks';
|
||||
import {
|
||||
useMerchantInfo,
|
||||
useWooSettings,
|
||||
} from '../../../../../../data/common/hooks';
|
||||
import { STORE_NAME as COMMON_STORE_NAME } from '../../../../../../data/common';
|
||||
import {
|
||||
NOTIFICATION_ERROR,
|
||||
|
@ -17,6 +20,7 @@ import { useFeatures } from '../../../../../../data/features/hooks';
|
|||
const Features = () => {
|
||||
const [ isRefreshing, setIsRefreshing ] = useState( false );
|
||||
const { merchant } = useMerchantInfo();
|
||||
const { storeCountry } = useWooSettings();
|
||||
const { features, fetchFeatures } = useFeatures();
|
||||
const { refreshFeatureStatuses } = useDispatch( COMMON_STORE_NAME );
|
||||
const { createSuccessNotice, createErrorNotice } =
|
||||
|
@ -26,6 +30,13 @@ const Features = () => {
|
|||
return null;
|
||||
}
|
||||
|
||||
// Filter out ACDC for Mexico (when disabled).
|
||||
const filteredFeatures = features.filter(
|
||||
( feature ) =>
|
||||
feature.id !== 'advanced_credit_and_debit_cards' ||
|
||||
storeCountry !== 'MX'
|
||||
);
|
||||
|
||||
const refreshHandler = async () => {
|
||||
setIsRefreshing( true );
|
||||
try {
|
||||
|
@ -86,7 +97,7 @@ const Features = () => {
|
|||
aria-busy={ isRefreshing }
|
||||
>
|
||||
<ContentWrapper>
|
||||
{ features.map( ( { id, enabled, ...feature } ) => (
|
||||
{ filteredFeatures.map( ( { id, enabled, ...feature } ) => (
|
||||
<FeatureItem
|
||||
key={ id }
|
||||
isBusy={ isRefreshing }
|
||||
|
|
|
@ -4,9 +4,8 @@ import { PaymentMethodsBlock } from '../../../../ReusableComponents/SettingsBloc
|
|||
import usePaymentDependencyState from '../../../../../hooks/usePaymentDependencyState';
|
||||
import useSettingDependencyState from '../../../../../hooks/useSettingDependencyState';
|
||||
import usePaymentMethodsToggle from '../../../../../hooks/usePaymentMethodsToggle';
|
||||
import useDependencyMessages from '../../../../../hooks/useDependencyMessages';
|
||||
import BulkPaymentToggle from './BulkPaymentToggle';
|
||||
import PaymentDependencyMessage from './PaymentDependencyMessage';
|
||||
import SettingDependencyMessage from './SettingDependencyMessage';
|
||||
import SpinnerOverlay from '../../../../ReusableComponents/SpinnerOverlay';
|
||||
import {
|
||||
PaymentHooks,
|
||||
|
@ -60,6 +59,13 @@ const PaymentMethodCard = ( {
|
|||
|
||||
const settingDependencies = useSettingDependencyState( methods );
|
||||
|
||||
const dependencyMessagesMap = useDependencyMessages(
|
||||
methods,
|
||||
paymentDependencies,
|
||||
settingDependencies,
|
||||
isDisabled
|
||||
);
|
||||
|
||||
// Initialize the bulk toggle functionality.
|
||||
const { allEnabled, toggleAllMethods, methodCount } =
|
||||
usePaymentMethodsToggle( {
|
||||
|
@ -86,37 +92,17 @@ const PaymentMethodCard = ( {
|
|||
return <SpinnerOverlay asModal={ true } />;
|
||||
}
|
||||
|
||||
// Process methods with dependencies.
|
||||
// Process methods with dependencies from the pre-computed map.
|
||||
const processedMethods = methods.map( ( method ) => {
|
||||
const paymentDependency = paymentDependencies?.[ method.id ];
|
||||
const settingDependency = settingDependencies?.[ method.id ];
|
||||
|
||||
let dependencyMessage = null;
|
||||
let isMethodDisabled = method.isDisabled || isDisabled;
|
||||
|
||||
if ( paymentDependency ) {
|
||||
dependencyMessage = (
|
||||
<PaymentDependencyMessage
|
||||
parentId={ paymentDependency.parentId }
|
||||
parentName={ paymentDependency.parentName }
|
||||
/>
|
||||
);
|
||||
isMethodDisabled = true;
|
||||
} else if ( settingDependency?.isDisabled ) {
|
||||
dependencyMessage = (
|
||||
<SettingDependencyMessage
|
||||
settingId={ settingDependency.settingId }
|
||||
requiredValue={ settingDependency.requiredValue }
|
||||
methodId={ method.id }
|
||||
/>
|
||||
);
|
||||
isMethodDisabled = true;
|
||||
}
|
||||
const dependencyInfo = dependencyMessagesMap[ method.id ] || {};
|
||||
|
||||
return {
|
||||
...method,
|
||||
isDisabled: isMethodDisabled,
|
||||
disabledMessage: dependencyMessage,
|
||||
isDisabled:
|
||||
dependencyInfo.isMethodDisabled ||
|
||||
method.isDisabled ||
|
||||
isDisabled,
|
||||
disabledMessage: dependencyInfo.dependencyMessage,
|
||||
};
|
||||
} );
|
||||
|
||||
|
|
|
@ -0,0 +1,49 @@
|
|||
import { createInterpolateElement } from '@wordpress/element';
|
||||
import { __ } from '@wordpress/i18n';
|
||||
import { scrollAndHighlight } from '../../../../../utils/scrollAndHighlight';
|
||||
|
||||
/**
|
||||
* Component to display a payment method value dependency message
|
||||
*
|
||||
* @param {Object} props - Component props
|
||||
* @param {string} props.dependentMethodId - ID of the dependent payment method
|
||||
* @param {string} props.dependentMethodName - Display name of the dependent payment method
|
||||
* @param {boolean} props.requiredValue - Required value (enabled/disabled state) for the dependent method
|
||||
* @return {JSX.Element} The formatted message with link
|
||||
*/
|
||||
const PaymentMethodValueDependencyMessage = ( {
|
||||
dependentMethodId,
|
||||
dependentMethodName,
|
||||
requiredValue,
|
||||
} ) => {
|
||||
const displayName = dependentMethodName || dependentMethodId;
|
||||
|
||||
// Determine appropriate message template based on the required value
|
||||
const template = requiredValue
|
||||
? __(
|
||||
'Enable <methodLink /> to use this method.',
|
||||
'woocommerce-paypal-payments'
|
||||
)
|
||||
: __(
|
||||
'Disable <methodLink /> to use this method.',
|
||||
'woocommerce-paypal-payments'
|
||||
);
|
||||
|
||||
return createInterpolateElement( template, {
|
||||
methodLink: (
|
||||
<strong>
|
||||
<a
|
||||
href="#"
|
||||
onClick={ ( e ) => {
|
||||
e.preventDefault();
|
||||
scrollAndHighlight( dependentMethodId );
|
||||
} }
|
||||
>
|
||||
{ displayName }
|
||||
</a>
|
||||
</strong>
|
||||
),
|
||||
} );
|
||||
};
|
||||
|
||||
export default PaymentMethodValueDependencyMessage;
|
|
@ -2,15 +2,17 @@ import { __ } from '@wordpress/i18n';
|
|||
import { useCallback } from '@wordpress/element';
|
||||
|
||||
import { CommonHooks, OnboardingHooks, PaymentHooks } from '../../../../data';
|
||||
import { useActiveModal } from '../../../../data/common/hooks';
|
||||
import { useActiveModal, useWooSettings } from '../../../../data/common/hooks';
|
||||
import Modal from '../Components/Payment/Modal';
|
||||
import PaymentMethodCard from '../Components/Payment/PaymentMethodCard';
|
||||
import { useFeatures } from '../../../../data/features/hooks';
|
||||
|
||||
const TabPaymentMethods = () => {
|
||||
const methods = PaymentHooks.usePaymentMethods();
|
||||
const store = PaymentHooks.useStore();
|
||||
const { setPersistent, changePaymentSettings } = store;
|
||||
const { activeModal, setActiveModal } = useActiveModal();
|
||||
const { features } = useFeatures();
|
||||
|
||||
// Get all methods as a map for dependency checking
|
||||
const methodsMap = {};
|
||||
|
@ -52,12 +54,31 @@ const TabPaymentMethods = () => {
|
|||
);
|
||||
|
||||
const merchant = CommonHooks.useMerchant();
|
||||
const { storeCountry } = useWooSettings();
|
||||
const { canUseCardPayments } = OnboardingHooks.useFlags();
|
||||
|
||||
const showCardPayments =
|
||||
methods.cardPayment.length > 0 &&
|
||||
merchant.isBusinessSeller &&
|
||||
canUseCardPayments;
|
||||
canUseCardPayments &&
|
||||
// Show ACDC if the merchant has the feature enabled in PayPal account.
|
||||
features.some(
|
||||
( feature ) =>
|
||||
feature.id === 'advanced_credit_and_debit_cards' &&
|
||||
feature.enabled
|
||||
);
|
||||
|
||||
// Hide BCDC for all countries except Mexico when ACDC is turned on.
|
||||
const filteredPayPalMethods = methods.paypal.filter(
|
||||
( method ) =>
|
||||
method.id !== 'ppcp-card-button-gateway' ||
|
||||
storeCountry === 'MX' ||
|
||||
! features.some(
|
||||
( feature ) =>
|
||||
feature.id === 'advanced_credit_and_debit_cards' &&
|
||||
feature.enabled === true
|
||||
)
|
||||
);
|
||||
|
||||
const showApms = methods.apm.length > 0 && merchant.isBusinessSeller;
|
||||
return (
|
||||
|
@ -70,7 +91,7 @@ const TabPaymentMethods = () => {
|
|||
'woocommerce-paypal-payments'
|
||||
) }
|
||||
icon="icon-checkout-standard.svg"
|
||||
methods={ methods.paypal }
|
||||
methods={ filteredPayPalMethods }
|
||||
onTriggerModal={ setActiveModal }
|
||||
methodsMap={ methodsMap }
|
||||
/>
|
||||
|
|
|
@ -162,14 +162,15 @@ export const useNavigationState = () => {
|
|||
};
|
||||
};
|
||||
|
||||
export const useDetermineProducts = ( ownBrandOnly ) => {
|
||||
export const useDetermineProducts = ( ownBrandOnly, storeCountry ) => {
|
||||
return useSelect(
|
||||
( select ) => {
|
||||
return select( STORE_NAME ).determineProductsAndCaps(
|
||||
ownBrandOnly
|
||||
ownBrandOnly,
|
||||
storeCountry
|
||||
);
|
||||
},
|
||||
[ ownBrandOnly ]
|
||||
[ ownBrandOnly, storeCountry ]
|
||||
);
|
||||
};
|
||||
|
||||
|
|
|
@ -35,9 +35,14 @@ export const flags = ( state ) => {
|
|||
*
|
||||
* @param {{}} state
|
||||
* @param {boolean} ownBrandOnly
|
||||
* @param {string} storeCountry
|
||||
* @return {{products:string[], options:{}}} The ISU products, based on choices made in the onboarding wizard.
|
||||
*/
|
||||
export const determineProductsAndCaps = ( state, ownBrandOnly ) => {
|
||||
export const determineProductsAndCaps = (
|
||||
state,
|
||||
ownBrandOnly,
|
||||
storeCountry
|
||||
) => {
|
||||
/**
|
||||
* An array of product-names that are used to build an onboarding URL via the
|
||||
* PartnerReferrals API. To avoid confusion with the "products" property from the
|
||||
|
@ -80,7 +85,7 @@ export const determineProductsAndCaps = ( state, ownBrandOnly ) => {
|
|||
if ( canUseVaulting ) {
|
||||
apiModules.push( PAYPAL_PRODUCTS.VAULTING );
|
||||
}
|
||||
} else if ( isCasualSeller ) {
|
||||
} else if ( isCasualSeller || 'MX' === storeCountry ) {
|
||||
/**
|
||||
* Branch 2: Merchant has no business.
|
||||
* The store uses the Express-checkout product.
|
||||
|
|
|
@ -0,0 +1,83 @@
|
|||
// hooks/useDependencyMessages.js
|
||||
import { useMemo } from '@wordpress/element';
|
||||
import PaymentDependencyMessage from '../Components/Screens/Settings/Components/Payment/PaymentDependencyMessage';
|
||||
import PaymentMethodValueDependencyMessage from '../Components/Screens/Settings/Components/Payment/PaymentMethodValueDependencyMessage';
|
||||
import SettingDependencyMessage from '../Components/Screens/Settings/Components/Payment/SettingDependencyMessage';
|
||||
|
||||
/**
|
||||
* Hook to process dependency messages for all methods
|
||||
*
|
||||
* @param {Array} methods - List of payment methods
|
||||
* @param {Object} paymentDependencies - Payment method dependencies
|
||||
* @param {Object} settingDependencies - Setting dependencies
|
||||
* @param {boolean} isDisabled - Whether methods are globally disabled
|
||||
* @return {Object} Map of method IDs to their dependency messages and disabled states
|
||||
*/
|
||||
const useDependencyMessages = (
|
||||
methods,
|
||||
paymentDependencies,
|
||||
settingDependencies,
|
||||
isDisabled = false
|
||||
) => {
|
||||
return useMemo( () => {
|
||||
const result = {};
|
||||
|
||||
if ( ! methods || ! methods.length ) {
|
||||
return result;
|
||||
}
|
||||
|
||||
// Process each method once to create their dependency messages.
|
||||
methods.forEach( ( method ) => {
|
||||
if ( ! method || ! method.id ) {
|
||||
return;
|
||||
}
|
||||
|
||||
let dependencyMessage = null;
|
||||
let isMethodDisabled = method.isDisabled || isDisabled;
|
||||
|
||||
// Check payment dependencies
|
||||
const dependency = paymentDependencies?.[ method.id ];
|
||||
if ( dependency ) {
|
||||
if ( dependency.type === 'parent' ) {
|
||||
dependencyMessage = (
|
||||
<PaymentDependencyMessage
|
||||
parentId={ dependency.parentId }
|
||||
parentName={ dependency.parentName }
|
||||
/>
|
||||
);
|
||||
} else if ( dependency.type === 'value' ) {
|
||||
dependencyMessage = (
|
||||
<PaymentMethodValueDependencyMessage
|
||||
dependentMethodId={ dependency.dependentId }
|
||||
dependentMethodName={ dependency.dependentName }
|
||||
requiredValue={ dependency.requiredValue }
|
||||
/>
|
||||
);
|
||||
}
|
||||
isMethodDisabled = true;
|
||||
}
|
||||
// Check setting dependencies
|
||||
else if ( settingDependencies?.[ method.id ]?.isDisabled ) {
|
||||
const settingDependency = settingDependencies[ method.id ];
|
||||
dependencyMessage = (
|
||||
<SettingDependencyMessage
|
||||
settingId={ settingDependency.settingId }
|
||||
requiredValue={ settingDependency.requiredValue }
|
||||
methodId={ method.id }
|
||||
/>
|
||||
);
|
||||
isMethodDisabled = true;
|
||||
}
|
||||
|
||||
// Store the results for this method
|
||||
result[ method.id ] = {
|
||||
dependencyMessage,
|
||||
isMethodDisabled,
|
||||
};
|
||||
} );
|
||||
|
||||
return result;
|
||||
}, [ methods, paymentDependencies, settingDependencies, isDisabled ] );
|
||||
};
|
||||
|
||||
export default useDependencyMessages;
|
|
@ -31,9 +31,11 @@ export const useHandleOnboardingButton = ( isSandbox ) => {
|
|||
const { onboardingUrl } = isSandbox
|
||||
? CommonHooks.useSandbox()
|
||||
: CommonHooks.useProduction();
|
||||
const { ownBrandOnly } = CommonHooks.useWooSettings();
|
||||
const { products, options } =
|
||||
OnboardingHooks.useDetermineProducts( ownBrandOnly );
|
||||
const { ownBrandOnly, storeCountry } = CommonHooks.useWooSettings();
|
||||
const { products, options } = OnboardingHooks.useDetermineProducts(
|
||||
ownBrandOnly,
|
||||
storeCountry
|
||||
);
|
||||
const { startActivity } = CommonHooks.useBusyState();
|
||||
const { authenticateWithOAuth } = CommonHooks.useAuthentication();
|
||||
const [ onboardingUrlState, setOnboardingUrl ] = useState( '' );
|
||||
|
|
|
@ -6,15 +6,13 @@ import { useSelect } from '@wordpress/data';
|
|||
/**
|
||||
* Gets the display name for a parent payment method
|
||||
*
|
||||
* @param {string} parentId - ID of the parent payment method
|
||||
* @param {string} methodId - ID of the payment method
|
||||
* @param {Object} methodsMap - Map of all payment methods by ID
|
||||
* @return {string} The display name to use for the parent method
|
||||
* @return {string} The display name of the method
|
||||
*/
|
||||
const getParentMethodName = ( parentId, methodsMap ) => {
|
||||
const parentMethod = methodsMap[ parentId ];
|
||||
return parentMethod
|
||||
? parentMethod.itemTitle || parentMethod.title || ''
|
||||
: '';
|
||||
const getMethodName = ( methodId, methodsMap ) => {
|
||||
const method = methodsMap[ methodId ];
|
||||
return method ? method.itemTitle || method.title || '' : '';
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -38,7 +36,51 @@ const findDisabledParents = ( method, methodsMap ) => {
|
|||
};
|
||||
|
||||
/**
|
||||
* Hook to evaluate payment method dependencies
|
||||
* Checks if method should be disabled due to value dependencies
|
||||
*
|
||||
* @param {Object} method - The payment method to check
|
||||
* @param {Object} methodsMap - Map of all payment methods by ID
|
||||
* @return {Object|null} Value dependency info if should be disabled, null otherwise
|
||||
*/
|
||||
const checkValueDependencies = ( method, methodsMap ) => {
|
||||
const valueDependencies = method.depends_on_payment_methods_values;
|
||||
|
||||
if ( ! valueDependencies ) {
|
||||
return null;
|
||||
}
|
||||
|
||||
// Check each dependency against the actual state of the dependent method.
|
||||
for ( const [ dependentId, requiredValue ] of Object.entries(
|
||||
valueDependencies
|
||||
) ) {
|
||||
const dependent = methodsMap[ dependentId ];
|
||||
|
||||
if ( ! dependent ) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Example: card-button-gateway depends on credit-card-gateway being FALSE.
|
||||
// So if credit-card-gateway is TRUE (enabled), card-button-gateway should be disabled.
|
||||
|
||||
// If the dependency requires a method to be false but it's enabled (or vice versa).
|
||||
if (
|
||||
typeof requiredValue === 'boolean' &&
|
||||
dependent.enabled !== requiredValue
|
||||
) {
|
||||
// This dependency is violated - the dependent method is in the wrong state.
|
||||
return {
|
||||
dependentId,
|
||||
dependentName: getMethodName( dependentId, methodsMap ),
|
||||
requiredValue,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
};
|
||||
|
||||
/**
|
||||
* Hook to evaluate all payment method dependencies
|
||||
*
|
||||
* @param {Array} methods - List of payment methods
|
||||
* @param {Object} methodsMap - Map of payment methods by ID
|
||||
|
@ -51,6 +93,7 @@ const usePaymentDependencyState = ( methods, methodsMap ) => {
|
|||
if ( methods && methodsMap && Object.keys( methodsMap ).length > 0 ) {
|
||||
methods.forEach( ( method ) => {
|
||||
if ( method && method.id ) {
|
||||
// Check regular parent-child dependencies first.
|
||||
const disabledParents = findDisabledParents(
|
||||
method,
|
||||
methodsMap
|
||||
|
@ -59,18 +102,32 @@ const usePaymentDependencyState = ( methods, methodsMap ) => {
|
|||
if ( disabledParents.length > 0 ) {
|
||||
const parentId = disabledParents[ 0 ];
|
||||
result[ method.id ] = {
|
||||
type: 'parent',
|
||||
isDisabled: true,
|
||||
parentId,
|
||||
parentName: getParentMethodName(
|
||||
parentId,
|
||||
methodsMap
|
||||
),
|
||||
parentName: getMethodName( parentId, methodsMap ),
|
||||
};
|
||||
return; // Skip other checks if already disabled.
|
||||
}
|
||||
|
||||
// Check value dependencies.
|
||||
const valueDependency = checkValueDependencies(
|
||||
method,
|
||||
methodsMap
|
||||
);
|
||||
|
||||
if ( valueDependency ) {
|
||||
result[ method.id ] = {
|
||||
type: 'value',
|
||||
isDisabled: true,
|
||||
dependentId: valueDependency.dependentId,
|
||||
dependentName: valueDependency.dependentName,
|
||||
requiredValue: valueDependency.requiredValue,
|
||||
};
|
||||
}
|
||||
}
|
||||
} );
|
||||
}
|
||||
|
||||
return result;
|
||||
}, [ methods, methodsMap ] );
|
||||
};
|
||||
|
|
|
@ -568,16 +568,17 @@ return array(
|
|||
);
|
||||
// Merchant capabilities, serve to show active or inactive badge and buttons.
|
||||
$capabilities = array(
|
||||
'apple_pay' => $features['apple_pay']['enabled'] ?? false,
|
||||
'google_pay' => $features['google_pay']['enabled'] ?? false,
|
||||
'acdc' => $features['advanced_credit_and_debit_cards']['enabled'] ?? false,
|
||||
'save_paypal' => $features['save_paypal_and_venmo']['enabled'] ?? false,
|
||||
'apple_pay' => $features['apple_pay']['enabled'] ?? false,
|
||||
'google_pay' => $features['google_pay']['enabled'] ?? false,
|
||||
'acdc' => $features['advanced_credit_and_debit_cards']['enabled'] ?? false,
|
||||
'save_paypal' => $features['save_paypal_and_venmo']['enabled'] ?? false,
|
||||
'alternative_payment_methods' => $features['alternative_payment_methods']['enabled'] ?? false,
|
||||
);
|
||||
|
||||
$merchant_capabilities = array(
|
||||
'save_paypal' => $capabilities['save_paypal'], // Save PayPal and Venmo eligibility.
|
||||
'acdc' => $capabilities['acdc'] && ! $gateways['card-button'], // Advanced credit and debit cards eligibility.
|
||||
'apm' => ! $gateways['card-button'], // Alternative payment methods eligibility.
|
||||
'acdc' => $capabilities['acdc'], // Advanced credit and debit cards eligibility.
|
||||
'apm' => $capabilities['alternative_payment_methods'], // Alternative payment methods eligibility.
|
||||
'google_pay' => $capabilities['acdc'] && $capabilities['google_pay'], // Google Pay eligibility.
|
||||
'apple_pay' => $capabilities['acdc'] && $capabilities['apple_pay'], // Apple Pay eligibility.
|
||||
'pay_later' => $capabilities['acdc'] && ! $gateways['card-button'], // Pay Later eligibility.
|
||||
|
|
|
@ -107,6 +107,27 @@ class PaymentMethodsDependenciesDefinition {
|
|||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get payment method value dependencies for a specific method
|
||||
*
|
||||
* @return array Value dependencies for the method or empty array if none exist
|
||||
*/
|
||||
public function get_payment_method_value_dependencies(): array {
|
||||
$dependencies = array(
|
||||
CardButtonGateway::ID => array(
|
||||
CreditCardGateway::ID => false,
|
||||
),
|
||||
CreditCardGateway::ID => array(
|
||||
CardButtonGateway::ID => false,
|
||||
),
|
||||
);
|
||||
|
||||
return apply_filters(
|
||||
'woocommerce_paypal_payments_method_value_dependencies',
|
||||
$dependencies
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get method setting dependencies
|
||||
*
|
||||
|
@ -139,6 +160,15 @@ class PaymentMethodsDependenciesDefinition {
|
|||
$method['depends_on_payment_methods'] = $payment_method_dependencies;
|
||||
}
|
||||
|
||||
// Add payment method value dependency info if applicable.
|
||||
$all_payment_method_value_dependencies = $this->get_payment_method_value_dependencies();
|
||||
|
||||
// Only add dependencies that directly apply to this method.
|
||||
if ( isset( $all_payment_method_value_dependencies[ $method_id ] ) ) {
|
||||
// Direct dependencies on other method values.
|
||||
$method['depends_on_payment_methods_values'] = $all_payment_method_value_dependencies[ $method_id ];
|
||||
}
|
||||
|
||||
// Check if this method has setting dependencies.
|
||||
$method_setting_dependencies = $this->get_method_setting_dependencies( $method_id );
|
||||
if ( ! empty( $method_setting_dependencies ) ) {
|
||||
|
|
|
@ -197,6 +197,10 @@ class PaymentRestEndpoint extends RestEndpoint {
|
|||
$gateway_settings[ $key ]['depends_on_payment_methods'] = $payment_method['depends_on_payment_methods'];
|
||||
}
|
||||
|
||||
if ( isset( $payment_method['depends_on_payment_methods_values'] ) ) {
|
||||
$gateway_settings[ $key ]['depends_on_payment_methods_values'] = $payment_method['depends_on_payment_methods_values'];
|
||||
}
|
||||
|
||||
if ( isset( $payment_method['depends_on_settings'] ) ) {
|
||||
$gateway_settings[ $key ]['depends_on_settings'] = $payment_method['depends_on_settings'];
|
||||
}
|
||||
|
|
|
@ -270,10 +270,14 @@ class SettingsDataManager {
|
|||
$this->payment_methods->toggle_method_state( CardButtonGateway::ID, true );
|
||||
}
|
||||
|
||||
// Enable all APM methods.
|
||||
foreach ( $methods_apm as $method ) {
|
||||
$this->payment_methods->toggle_method_state( $method['id'], true );
|
||||
}
|
||||
/**
|
||||
* Allow plugins to modify apm payment gateway states before saving.
|
||||
*
|
||||
* @param PaymentSettings $payment_methods The payment methods object.
|
||||
* @param PaymentSettings $methods_apm List of APM methods.
|
||||
* @param ConfigurationFlagsDTO $flags Configuration flags that determine which gateways to enable.
|
||||
*/
|
||||
do_action( 'woocommerce_paypal_payments_toggle_payment_gateways_apms', $this->payment_methods, $methods_apm, $flags );
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -13,8 +13,10 @@ use WC_Payment_Gateway;
|
|||
use Psr\Log\LoggerInterface;
|
||||
use WooCommerce\PayPalCommerce\ApiClient\Helper\DccApplies;
|
||||
use WooCommerce\PayPalCommerce\ApiClient\Helper\PartnerAttribution;
|
||||
use WooCommerce\PayPalCommerce\Applepay\ApplePayGateway;
|
||||
use WooCommerce\PayPalCommerce\Applepay\Assets\AppleProductStatus;
|
||||
use WooCommerce\PayPalCommerce\Axo\Gateway\AxoGateway;
|
||||
use WooCommerce\PayPalCommerce\Googlepay\GooglePayGateway;
|
||||
use WooCommerce\PayPalCommerce\Googlepay\Helper\ApmProductStatus;
|
||||
use WooCommerce\PayPalCommerce\LocalAlternativePaymentMethods\BancontactGateway;
|
||||
use WooCommerce\PayPalCommerce\LocalAlternativePaymentMethods\BlikGateway;
|
||||
|
@ -321,11 +323,13 @@ class SettingsModule implements ServiceModule, ExecutableModule {
|
|||
|
||||
// Unset BCDC if merchant is eligible for ACDC and country is eligible for card fields.
|
||||
$card_fields_eligible = $container->get( 'card-fields.eligible' );
|
||||
if ( $dcc_product_status->is_active() && $card_fields_eligible ) {
|
||||
unset( $payment_methods[ CardButtonGateway::ID ] );
|
||||
} else {
|
||||
// For non-ACDC regions unset ACDC.
|
||||
unset( $payment_methods[ CreditCardGateway::ID ] );
|
||||
if ( 'MX' !== $container->get( 'api.shop.country' ) ) {
|
||||
if ( $dcc_product_status->is_active() && $card_fields_eligible ) {
|
||||
unset( $payment_methods[ CardButtonGateway::ID ] );
|
||||
} else {
|
||||
// For non-ACDC regions unset ACDC.
|
||||
unset( $payment_methods[ CreditCardGateway::ID ] );
|
||||
}
|
||||
}
|
||||
|
||||
// Unset Venmo when store location is not United States.
|
||||
|
@ -358,6 +362,18 @@ class SettingsModule implements ServiceModule, ExecutableModule {
|
|||
unset( $payment_methods[ PayUponInvoiceGateway::ID ] );
|
||||
}
|
||||
|
||||
// Unset all APMs other than OXXO for Mexico.
|
||||
if ( 'MX' === $merchant_country ) {
|
||||
unset( $payment_methods[ BancontactGateway::ID ] );
|
||||
unset( $payment_methods[ BlikGateway::ID ] );
|
||||
unset( $payment_methods[ EPSGateway::ID ] );
|
||||
unset( $payment_methods[ IDealGateway::ID ] );
|
||||
unset( $payment_methods[ MyBankGateway::ID ] );
|
||||
unset( $payment_methods[ P24Gateway::ID ] );
|
||||
unset( $payment_methods[ TrustlyGateway::ID ] );
|
||||
unset( $payment_methods[ MultibancoGateway::ID ] );
|
||||
}
|
||||
|
||||
return $payment_methods;
|
||||
}
|
||||
);
|
||||
|
@ -539,6 +555,62 @@ class SettingsModule implements ServiceModule, ExecutableModule {
|
|||
$payment_methods->toggle_method_state( AxoGateway::ID, true );
|
||||
}
|
||||
}
|
||||
|
||||
$general_settings = $container->get( 'settings.data.general' );
|
||||
assert( $general_settings instanceof GeneralSettings );
|
||||
|
||||
$merchant_data = $general_settings->get_merchant_data();
|
||||
$merchant_country = $merchant_data->merchant_country;
|
||||
|
||||
// Disable all extended checkout card methods if the store is in Mexico.
|
||||
if ( 'MX' === $merchant_country ) {
|
||||
$payment_methods->toggle_method_state( CreditCardGateway::ID, false );
|
||||
$payment_methods->toggle_method_state( ApplePayGateway::ID, false );
|
||||
$payment_methods->toggle_method_state( GooglePayGateway::ID, false );
|
||||
}
|
||||
},
|
||||
10,
|
||||
2
|
||||
);
|
||||
|
||||
// Enable APMs after onboarding if the country is compatible.
|
||||
add_action(
|
||||
'woocommerce_paypal_payments_toggle_payment_gateways_apms',
|
||||
function ( PaymentSettings $payment_methods, array $methods_apm ) use ( $container ) {
|
||||
|
||||
$general_settings = $container->get( 'settings.data.general' );
|
||||
assert( $general_settings instanceof GeneralSettings );
|
||||
|
||||
$merchant_data = $general_settings->get_merchant_data();
|
||||
$merchant_country = $merchant_data->merchant_country;
|
||||
|
||||
$logger = $container->get( 'woocommerce.logger.woocommerce' );
|
||||
assert( $logger instanceof LoggerInterface );
|
||||
|
||||
$logger->info( 'Merchant country: ' . $merchant_country );
|
||||
$logger->info( 'Merchant data: ' . json_encode( $merchant_data ) );
|
||||
$logger->info( '$methods_apm: ' . json_encode( $methods_apm ) );
|
||||
|
||||
// Enable all APM methods.
|
||||
foreach ( $methods_apm as $method ) {
|
||||
// Skip PayUponInvoice if merchant is not in Germany.
|
||||
if ( PayUponInvoiceGateway::ID === $method['id'] && 'DE' !== $merchant_country ) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// For OXXO: enable ONLY if merchant is in Mexico.
|
||||
if ( OXXO::ID === $method['id'] ) {
|
||||
if ( 'MX' === $merchant_country ) {
|
||||
$payment_methods->toggle_method_state( $method['id'], true );
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
// For all other APMs: enable only if merchant is NOT in Mexico.
|
||||
if ( 'MX' !== $merchant_country ) {
|
||||
$payment_methods->toggle_method_state( $method['id'], true );
|
||||
}
|
||||
}
|
||||
},
|
||||
10,
|
||||
2
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue