Add Installments todo and feature for Mexico

This commit is contained in:
Daniel Dudzic 2025-05-22 12:16:57 +02:00
parent 82af3c07c9
commit edcb0f7b4c
No known key found for this signature in database
GPG key ID: 31B40D33E3465483
8 changed files with 210 additions and 18 deletions

View file

@ -481,12 +481,13 @@ return array(
assert( $general_settings instanceof GeneralSettings );
return array(
'apple_pay' => ( $features['apple_pay']['enabled'] ?? false ) && ! $general_settings->own_brand_only(),
'google_pay' => ( $features['google_pay']['enabled'] ?? false ) && ! $general_settings->own_brand_only(),
'acdc' => ( $features['advanced_credit_and_debit_cards']['enabled'] ?? false ) && ! $general_settings->own_brand_only(),
'save_paypal' => $features['save_paypal_and_venmo']['enabled'] ?? false,
'apm' => $features['alternative_payment_methods']['enabled'] ?? false,
'paylater' => $features['pay_later_messaging']['enabled'] ?? false,
'apple_pay' => ( $features['apple_pay']['enabled'] ?? false ) && ! $general_settings->own_brand_only(),
'google_pay' => ( $features['google_pay']['enabled'] ?? false ) && ! $general_settings->own_brand_only(),
'acdc' => ( $features['advanced_credit_and_debit_cards']['enabled'] ?? false ) && ! $general_settings->own_brand_only(),
'save_paypal' => $features['save_paypal_and_venmo']['enabled'] ?? false,
'apm' => $features['alternative_payment_methods']['enabled'] ?? false,
'paylater' => $features['pay_later_messaging']['enabled'] ?? false,
'installments' => $features['installments']['enabled'] ?? false,
);
},
@ -545,6 +546,7 @@ return array(
$container->get( 'googlepay.eligible' ) && $capabilities['acdc'] && ! $capabilities['google_pay'], // Add Google Pay to your account.
$container->get( 'applepay.eligible' ) && $capabilities['apple_pay'] && ! $gateways['apple_pay'], // Enable Apple Pay.
$container->get( 'googlepay.eligible' ) && $capabilities['google_pay'] && ! $gateways['google_pay'],
! $capabilities['installments'] && 'MX' === $container->get( 'settings.data.general' )->get_merchant_country() // Enable Installments for Mexico.
);
},
'settings.rest.features' => static function ( ContainerInterface $container ) : FeaturesRestEndpoint {
@ -568,19 +570,21 @@ 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,
'installments' => $features['installments']['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.
'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.
'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.
'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.
'installments' => $capabilities['installments'], // Installments eligibility.
);
return new FeaturesDefinition(
$container->get( 'settings.service.features_eligibilities' ),
@ -606,6 +610,7 @@ return array(
$container->get( 'googlepay.eligibility.check' ), // Google Pay eligibility.
$container->get( 'applepay.eligibility.check' ), // Apple Pay eligibility.
$pay_later_eligible, // Pay Later eligibility.
'MX' === $container->get( 'settings.data.general' )->get_merchant_country(), // Installments eligibility.
);
},
'settings.service.todos_sorting' => static function ( ContainerInterface $container ) : TodosSortingAndFilteringService {

View file

@ -317,6 +317,27 @@ class FeaturesDefinition {
),
),
),
'installments' => array(
'title' => __( 'Installments', 'woocommerce-paypal-payments' ),
'description' =>
__( 'Allow your customers to pay in installments without interest while you receive the full payment.*', 'woocommerce-paypal-payments' ) .
'<p>' . __( 'Activate your Installments without interest with PayPal.', 'woocommerce-paypal-payments' ) . '</p>' .
'<p>' . sprintf(
/* translators: %s: Link to terms and conditions */
__( '*You will receive the full payment minus the applicable PayPal fee. See %s.', 'woocommerce-paypal-payments' ),
'<a href="https://www.paypal.com/mx/webapps/mpp/merchant-fees">' . __( 'terms and conditions', 'woocommerce-paypal-payments' ) . '</a>'
) . '</p>',
'enabled' => $this->merchant_capabilities['installments'],
'buttons' => array(
array(
'type' => 'secondary',
'text' => __( 'Sign up', 'woocommerce-paypal-payments' ),
'url' => 'https://www.paypal.com/businessmanage/preferences/installmentplan',
'showWhen' => 'disabled',
'class' => 'small-button',
),
),
),
);
}
}

View file

@ -217,6 +217,16 @@ class TodosDefinition {
),
'priority' => 12,
),
'enable_installments' => array(
'title' => __( 'Enable Installments', 'woocommerce-paypal-payments' ),
'description' => __( 'Allow your customers to pay in installments without interest while you receive the full payment in a single transaction', 'woocommerce-paypal-payments' ),
'isEligible' => $eligibility_checks['enable_installments'],
'action' => array(
'type' => 'external',
'url' => 'https://www.paypal.com/businessmanage/preferences/installmentplan',
),
'priority' => 13,
),
);
}
}

View file

@ -59,6 +59,13 @@ class FeaturesEligibilityService {
*/
private bool $is_pay_later_eligible;
/**
* Whether Installments is eligible.
*
* @var bool
*/
private bool $is_installments_eligible;
/**
* Constructor.
*
@ -68,6 +75,7 @@ class FeaturesEligibilityService {
* @param callable $check_google_pay_eligible If Google Pay is eligible.
* @param callable $check_apple_pay_eligible If Apple Pay is eligible.
* @param bool $is_pay_later_eligible If Pay Later is eligible.
* @param bool $is_installments_eligible If Installments is eligible.
*/
public function __construct(
bool $is_save_paypal_eligible,
@ -75,7 +83,8 @@ class FeaturesEligibilityService {
bool $is_apm_eligible,
callable $check_google_pay_eligible,
callable $check_apple_pay_eligible,
bool $is_pay_later_eligible
bool $is_pay_later_eligible,
bool $is_installments_eligible
) {
$this->is_save_paypal_eligible = $is_save_paypal_eligible;
$this->check_acdc_eligible = $check_acdc_eligible;
@ -83,6 +92,7 @@ class FeaturesEligibilityService {
$this->check_google_pay_eligible = $check_google_pay_eligible;
$this->check_apple_pay_eligible = $check_apple_pay_eligible;
$this->is_pay_later_eligible = $is_pay_later_eligible;
$this->is_installments_eligible = $is_installments_eligible;
}
/**
@ -98,6 +108,7 @@ class FeaturesEligibilityService {
'google_pay' => $this->check_google_pay_eligible,
'apple_pay' => $this->check_apple_pay_eligible,
'pay_later' => fn() => $this->is_pay_later_eligible,
'installments' => fn() => $this->is_installments_eligible,
);
}
}

View file

@ -122,6 +122,13 @@ class TodosEligibilityService {
*/
private bool $is_enable_google_pay_eligible;
/**
* Whether Enabling Installments is eligible.
*
* @var bool
*/
private bool $is_enable_installments_eligible;
/**
* Constructor.
*
@ -140,6 +147,7 @@ class TodosEligibilityService {
* @param bool $is_google_pay_eligible Whether Google Pay is eligible.
* @param bool $is_enable_apple_pay_eligible Whether enabling Apple Pay is eligible.
* @param bool $is_enable_google_pay_eligible Whether enabling Google Pay is eligible.
* @param bool $is_enable_installments_eligible Whether enabling Installments is eligible.
*/
public function __construct(
bool $is_fastlane_eligible,
@ -156,7 +164,8 @@ class TodosEligibilityService {
bool $is_apple_pay_eligible,
bool $is_google_pay_eligible,
bool $is_enable_apple_pay_eligible,
bool $is_enable_google_pay_eligible
bool $is_enable_google_pay_eligible,
bool $is_enable_installments_eligible
) {
$this->is_fastlane_eligible = $is_fastlane_eligible;
$this->is_pay_later_messaging_eligible = $is_pay_later_messaging_eligible;
@ -173,6 +182,7 @@ class TodosEligibilityService {
$this->is_google_pay_eligible = $is_google_pay_eligible;
$this->is_enable_apple_pay_eligible = $is_enable_apple_pay_eligible;
$this->is_enable_google_pay_eligible = $is_enable_google_pay_eligible;
$this->is_enable_installments_eligible = $is_enable_installments_eligible;
}
/**
@ -197,6 +207,7 @@ class TodosEligibilityService {
'add_google_pay' => fn() => $this->is_google_pay_eligible,
'enable_apple_pay' => fn() => $this->is_enable_apple_pay_eligible,
'enable_google_pay' => fn() => $this->is_enable_google_pay_eligible,
'enable_installments' => fn() => $this->is_enable_installments_eligible,
);
}
}

View file

@ -67,6 +67,7 @@ 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\InstallmentsProductStatus;
use WooCommerce\PayPalCommerce\WcGateway\Helper\RefundFeesUpdater;
use WooCommerce\PayPalCommerce\WcGateway\Helper\SettingsStatus;
use WooCommerce\PayPalCommerce\WcGateway\Notice\AuthorizeOrderActionNotice;
@ -1468,6 +1469,15 @@ return array(
$container->get( 'api.helper.failure-registry' )
);
},
'wcgateway.installments-product-status' => static function ( ContainerInterface $container ): InstallmentsProductStatus {
return new InstallmentsProductStatus(
$container->get( 'wcgateway.settings' ),
$container->get( 'api.endpoint.partners' ),
$container->get( 'installments.status-cache' ),
$container->get( 'settings.flag.is-connected' ),
$container->get( 'api.helper.failure-registry' )
);
},
'wcgateway.pay-upon-invoice' => static function ( ContainerInterface $container ): PayUponInvoice {
return new PayUponInvoice(
$container->get( 'wcgateway.pay-upon-invoice-order-endpoint' ),
@ -1787,6 +1797,9 @@ return array(
'pui.status-cache' => static function( ContainerInterface $container ): Cache {
return new Cache( 'ppcp-paypal-pui-status-cache' );
},
'installments.status-cache' => static function( ContainerInterface $container ): Cache {
return new Cache( 'ppcp-paypal-installments-status-cache' );
},
'dcc.status-cache' => static function( ContainerInterface $container ): Cache {
return new Cache( 'ppcp-paypal-dcc-status-cache' );
},

View file

@ -0,0 +1,113 @@
<?php
/**
* Manage the Seller status for Installments.
*
* @package WooCommerce\PayPalCommerce\WcGateway\Helper
*/
declare( strict_types=1 );
namespace WooCommerce\PayPalCommerce\WcGateway\Helper;
use WooCommerce\PayPalCommerce\ApiClient\Endpoint\PartnersEndpoint;
use WooCommerce\PayPalCommerce\ApiClient\Entity\SellerStatusProduct;
use WooCommerce\PayPalCommerce\ApiClient\Helper\Cache;
use WooCommerce\PayPalCommerce\ApiClient\Helper\FailureRegistry;
use WooCommerce\PayPalCommerce\WcGateway\Settings\Settings;
use WooCommerce\PayPalCommerce\ApiClient\Helper\ProductStatus;
use WooCommerce\PayPalCommerce\ApiClient\Entity\SellerStatus;
/**
* Class InstallmentsProductStatus
*/
class InstallmentsProductStatus extends ProductStatus {
public const SETTINGS_KEY = 'products_installments_enabled';
public const INSTALLMENTS_STATUS_CACHE_KEY = 'installments_status_cache';
public const SETTINGS_VALUE_ENABLED = 'yes';
public const SETTINGS_VALUE_DISABLED = 'no';
public const SETTINGS_VALUE_UNDEFINED = '';
/**
* The Cache.
*
* @var Cache
*/
protected Cache $cache;
/**
* The settings.
*
* @var Settings
*/
private Settings $settings;
/**
* InstallmentsProductStatus constructor.
*
* @param Settings $settings The Settings.
* @param PartnersEndpoint $partners_endpoint The Partner Endpoint.
* @param Cache $cache The cache.
* @param bool $is_connected The onboarding state.
* @param FailureRegistry $api_failure_registry The API failure registry.
*/
public function __construct(
Settings $settings,
PartnersEndpoint $partners_endpoint,
Cache $cache,
bool $is_connected,
FailureRegistry $api_failure_registry
) {
parent::__construct( $is_connected, $partners_endpoint, $api_failure_registry );
$this->settings = $settings;
$this->cache = $cache;
}
/** {@inheritDoc} */
protected function check_local_state() : ?bool {
if ( $this->cache->has( self::INSTALLMENTS_STATUS_CACHE_KEY ) ) {
return wc_string_to_bool( $this->cache->get( self::INSTALLMENTS_STATUS_CACHE_KEY ) );
}
if ( $this->settings->has( self::SETTINGS_KEY ) && ( $this->settings->get( self::SETTINGS_KEY ) ) ) {
return wc_string_to_bool( $this->settings->get( self::SETTINGS_KEY ) );
}
return null;
}
/** {@inheritDoc} */
protected function check_active_state( SellerStatus $seller_status ) : bool {
foreach ( $seller_status->capabilities() as $capability ) {
if ( $capability->name() !== 'INSTALLMENTS' ) {
continue;
}
if ( $capability->status() === 'ACTIVE' ) {
$this->settings->set( self::SETTINGS_KEY, self::SETTINGS_VALUE_ENABLED );
$this->settings->persist();
$this->cache->set( self::INSTALLMENTS_STATUS_CACHE_KEY, self::SETTINGS_VALUE_ENABLED, MONTH_IN_SECONDS );
return true;
}
}
$this->cache->set( self::INSTALLMENTS_STATUS_CACHE_KEY, self::SETTINGS_VALUE_DISABLED, MONTH_IN_SECONDS );
return false;
}
/** {@inheritDoc} */
protected function clear_state( Settings $settings = null ) : void {
if ( null === $settings ) {
$settings = $this->settings;
}
if ( $settings->has( self::SETTINGS_KEY ) ) {
$settings->set( self::SETTINGS_KEY, self::SETTINGS_VALUE_UNDEFINED );
$settings->persist();
}
$this->cache->delete( self::INSTALLMENTS_STATUS_CACHE_KEY );
}
}

View file

@ -24,6 +24,7 @@ use WooCommerce\PayPalCommerce\Vendor\Inpsyde\Modularity\Module\ServiceModule;
use WooCommerce\PayPalCommerce\WcGateway\Assets\VoidButtonAssets;
use WooCommerce\PayPalCommerce\WcGateway\Endpoint\RefreshFeatureStatusEndpoint;
use WooCommerce\PayPalCommerce\WcGateway\Endpoint\VoidOrderEndpoint;
use WooCommerce\PayPalCommerce\WcGateway\Helper\InstallmentsProductStatus;
use WooCommerce\PayPalCommerce\WcGateway\Notice\SendOnlyCountryNotice;
use WooCommerce\PayPalCommerce\WcGateway\Processor\CreditCardOrderInfoHandlingTrait;
use WC_Order;
@ -569,6 +570,9 @@ class WCGatewayModule implements ServiceModule, ExtendingModule, ExecutableModul
$apms_product_status = $c->get( 'ppcp-local-apms.product-status' );
assert( $apms_product_status instanceof LocalApmProductStatus );
$installments_product_status = $c->get( 'wcgateway.installments-product-status' );
assert( $installments_product_status instanceof InstallmentsProductStatus );
$features['save_paypal_and_venmo'] = array(
'enabled' => $billing_agreements_endpoint->reference_transaction_enabled(),
);
@ -584,6 +588,10 @@ class WCGatewayModule implements ServiceModule, ExtendingModule, ExecutableModul
// When local APMs are available, then PayLater messaging is also available.
$features['pay_later_messaging'] = $features['alternative_payment_methods'];
$features['installments'] = array(
'enabled' => $installments_product_status->is_active(),
);
return $features;
}
);