diff --git a/modules/ppcp-api-client/services.php b/modules/ppcp-api-client/services.php index b2f489da5..272bfdaf7 100644 --- a/modules/ppcp-api-client/services.php +++ b/modules/ppcp-api-client/services.php @@ -80,10 +80,19 @@ use WooCommerce\PayPalCommerce\ApiClient\Repository\PayeeRepository; use WooCommerce\PayPalCommerce\WcGateway\Settings\Settings; use WooCommerce\PayPalCommerce\ApiClient\Authentication\ConnectBearer; use WooCommerce\PayPalCommerce\WcGateway\Helper\EnvironmentConfig; +use WooCommerce\PayPalCommerce\Onboarding\State; +use WooCommerce\PayPalCommerce\WcGateway\Helper\Environment; return array( - 'api.host' => function( ContainerInterface $container ) : string { - return PAYPAL_API_URL; + 'api.host' => static function( ContainerInterface $container ) : string { + $environment = $container->get( 'onboarding.environment' ); + assert( $environment instanceof Environment ); + + if ( $environment->is_sandbox() ) { + return (string) $container->get( 'api.sandbox-host' ); + } + + return (string) $container->get( 'api.production-host' ); }, 'api.paypal-host' => function( ContainerInterface $container ) : string { return PAYPAL_API_URL; @@ -116,6 +125,12 @@ return array( return 'WC-'; }, 'api.bearer' => static function ( ContainerInterface $container ): Bearer { + $is_connected = $container->get( 'settings.flag.is-connected' ); + + if ( ! $is_connected ) { + return new ConnectBearer(); + } + return new PayPalBearer( $container->get( 'api.paypal-bearer-cache' ), $container->get( 'api.host' ), @@ -811,7 +826,7 @@ return array( return new OrderHelper(); }, 'api.helper.order-transient' => static function( ContainerInterface $container ): OrderTransient { - $cache = new Cache( 'ppcp-paypal-bearer' ); + $cache = $container->get( 'api.paypal-bearer-cache' ); $purchase_unit_sanitizer = $container->get( 'api.helper.purchase-unit-sanitizer' ); return new OrderTransient( $cache, $purchase_unit_sanitizer ); }, @@ -927,4 +942,22 @@ return array( $container->get( 'api.endpoint.partner-referrals-sandbox' ) ); }, + 'api.sandbox-host' => static function ( ContainerInterface $container ): string { + $is_connected = $container->get( 'settings.flag.is-connected' ); + + if ( $is_connected ) { + return PAYPAL_SANDBOX_API_URL; + } + + return CONNECT_WOO_SANDBOX_URL; + }, + 'api.production-host' => static function ( ContainerInterface $container ): string { + $is_connected = $container->get( 'settings.flag.is-connected' ); + + if ( $is_connected ) { + return PAYPAL_API_URL; + } + + return CONNECT_WOO_URL; + }, ); diff --git a/modules/ppcp-api-client/src/Helper/ProductStatus.php b/modules/ppcp-api-client/src/Helper/ProductStatus.php new file mode 100644 index 000000000..bab84ed24 --- /dev/null +++ b/modules/ppcp-api-client/src/Helper/ProductStatus.php @@ -0,0 +1,208 @@ +is_connected = $is_connected; + $this->partners_endpoint = $partners_endpoint; + $this->api_failure_registry = $api_failure_registry; + } + + /** + * Uses local data (DB values, hooks) to determine if the feature is eligible. + * + * Returns true when the feature is available, and false if ineligible. + * On failure, an RuntimeException is thrown. + * + * @return null|bool Boolean to indicate the status; null if the status not locally defined. + * @throws RuntimeException When the check failed. + * @throws NotFoundException When a relevant service or setting was not found. + */ + abstract protected function check_local_state() : ?bool; + + /** + * Inspects the API response of the SellerStatus to determine feature eligibility. + * + * Returns true when the feature is available, and false if ineligible. + * On failure, an RuntimeException is thrown. + * + * @param SellerStatus $seller_status The seller status, returned from the API. + * @return bool + * @throws RuntimeException When the check failed. + */ + abstract protected function check_active_state( SellerStatus $seller_status ) : bool; + + /** + * Clears the eligibility status from the local cache/DB to enforce a new + * API call on the next eligibility check. + * + * @param Settings|null $settings See description in {@see self::clear()}. + * @return void + */ + abstract protected function clear_state( Settings $settings = null ) : void; + + /** + * Whether the merchant has access to the feature. + * + * @return bool + */ + public function is_active() : bool { + if ( null !== $this->is_eligible ) { + return $this->is_eligible; + } + + $this->is_eligible = false; + $this->has_request_failure = false; + + if ( ! $this->is_onboarded() ) { + return $this->is_eligible; + } + + try { + // Try to use filters and DB values to determine the state. + $local_state = $this->check_local_state(); + if ( null !== $local_state ) { + $this->is_eligible = $local_state; + + return $this->is_eligible; + } + + // Check using the merchant-API. + $seller_status = $this->get_seller_status_object(); + $this->is_eligible = $this->check_active_state( $seller_status ); + } catch ( Exception $exception ) { + $this->has_request_failure = true; + } + + return $this->is_eligible; + } + + /** + * Fetches the seller-status object from the PayPal merchant API. + * + * @return SellerStatus + * @throws RuntimeException When the check failed. + */ + protected function get_seller_status_object() : SellerStatus { + if ( null === self::$seller_status ) { + // Check API failure registry to prevent multiple failed API requests. + if ( $this->api_failure_registry->has_failure_in_timeframe( FailureRegistry::SELLER_STATUS_KEY, MINUTE_IN_SECONDS ) ) { + throw new RuntimeException( 'Timeout for re-check not reached yet' ); + } + + // Request seller status via PayPal API, might throw an Exception. + self::$seller_status = $this->partners_endpoint->seller_status(); + } + + return self::$seller_status; + } + + /** + * Whether the merchant was fully onboarded, and we have valid API credentials. + * + * @return bool True, if we can use the merchant API endpoints. + */ + public function is_onboarded() : bool { + return $this->is_connected; + } + + /** + * Returns if there was a request failure. + * + * @return bool + */ + public function has_request_failure() : bool { + return $this->has_request_failure; + } + + /** + * Clears the persisted result to force a recheck. + * + * Accepts a Settings object to don't override other sequential settings that are being updated + * elsewhere. + * + * @param Settings|null $settings The settings object. + * @return void + */ + public function clear( Settings $settings = null ) : void { + $this->is_eligible = null; + $this->has_request_failure = false; + + $this->clear_state( $settings ); + } +} diff --git a/modules/ppcp-applepay/extensions.php b/modules/ppcp-applepay/extensions.php index 5eb6e47d6..53068c506 100644 --- a/modules/ppcp-applepay/extensions.php +++ b/modules/ppcp-applepay/extensions.php @@ -10,7 +10,7 @@ declare(strict_types=1); namespace WooCommerce\PayPalCommerce\Applepay; use WooCommerce\PayPalCommerce\Applepay\Assets\PropertiesDictionary; -use WooCommerce\PayPalCommerce\Onboarding\Environment; +use WooCommerce\PayPalCommerce\WcGateway\Helper\Environment; use WooCommerce\PayPalCommerce\Onboarding\State; use WooCommerce\PayPalCommerce\Vendor\Psr\Container\ContainerInterface; use WooCommerce\PayPalCommerce\WcGateway\Helper\DisplayManager; diff --git a/modules/ppcp-applepay/services.php b/modules/ppcp-applepay/services.php index 786953244..586a300ae 100644 --- a/modules/ppcp-applepay/services.php +++ b/modules/ppcp-applepay/services.php @@ -19,7 +19,7 @@ use WooCommerce\PayPalCommerce\Applepay\Assets\PropertiesDictionary; use WooCommerce\PayPalCommerce\Applepay\Helper\ApmApplies; use WooCommerce\PayPalCommerce\Applepay\Helper\AvailabilityNotice; use WooCommerce\PayPalCommerce\Common\Pattern\SingletonDecorator; -use WooCommerce\PayPalCommerce\Onboarding\Environment; +use WooCommerce\PayPalCommerce\WcGateway\Helper\Environment; use WooCommerce\PayPalCommerce\Onboarding\State; use WooCommerce\PayPalCommerce\Vendor\Psr\Container\ContainerInterface; @@ -79,7 +79,7 @@ return array( return new AppleProductStatus( $container->get( 'wcgateway.settings' ), $container->get( 'api.endpoint.partners' ), - $container->get( 'onboarding.state' ), + $container->get( 'settings.flag.is-connected' ), $container->get( 'api.helper.failure-registry' ) ); } diff --git a/modules/ppcp-applepay/src/ApplepayModule.php b/modules/ppcp-applepay/src/ApplepayModule.php index dc7b3cf11..8015e0a4d 100644 --- a/modules/ppcp-applepay/src/ApplepayModule.php +++ b/modules/ppcp-applepay/src/ApplepayModule.php @@ -17,7 +17,7 @@ use WooCommerce\PayPalCommerce\Applepay\Assets\PropertiesDictionary; use WooCommerce\PayPalCommerce\Button\Assets\ButtonInterface; use WooCommerce\PayPalCommerce\Button\Assets\SmartButtonInterface; use WooCommerce\PayPalCommerce\Applepay\Helper\AvailabilityNotice; -use WooCommerce\PayPalCommerce\Onboarding\Environment; +use WooCommerce\PayPalCommerce\WcGateway\Helper\Environment; use WooCommerce\PayPalCommerce\Vendor\Inpsyde\Modularity\Module\ExecutableModule; use WooCommerce\PayPalCommerce\Vendor\Inpsyde\Modularity\Module\ExtendingModule; use WooCommerce\PayPalCommerce\Vendor\Inpsyde\Modularity\Module\ModuleClassNameIdTrait; @@ -183,7 +183,7 @@ class ApplepayModule implements ServiceModule, ExtendingModule, ExecutableModule ); add_filter( - 'woocommerce_paypal_payments_rest_common_merchant_data', + 'woocommerce_paypal_payments_rest_common_merchant_features', function( array $features ) use ( $c ): array { $product_status = $c->get( 'applepay.apple-product-status' ); assert( $product_status instanceof AppleProductStatus ); diff --git a/modules/ppcp-applepay/src/Assets/AppleProductStatus.php b/modules/ppcp-applepay/src/Assets/AppleProductStatus.php index d5409ddaf..61668c26d 100644 --- a/modules/ppcp-applepay/src/Assets/AppleProductStatus.php +++ b/modules/ppcp-applepay/src/Assets/AppleProductStatus.php @@ -5,134 +5,70 @@ * @package WooCommerce\PayPalCommerce\Applepay\Assets */ -declare(strict_types=1); +declare( strict_types = 1 ); namespace WooCommerce\PayPalCommerce\Applepay\Assets; -use Throwable; use WooCommerce\PayPalCommerce\ApiClient\Endpoint\PartnersEndpoint; use WooCommerce\PayPalCommerce\ApiClient\Entity\SellerStatusCapability; use WooCommerce\PayPalCommerce\ApiClient\Helper\FailureRegistry; -use WooCommerce\PayPalCommerce\Onboarding\State; use WooCommerce\PayPalCommerce\WcGateway\Settings\Settings; +use WooCommerce\PayPalCommerce\ApiClient\Helper\ProductStatus; +use WooCommerce\PayPalCommerce\ApiClient\Entity\SellerStatus; /** * Class AppleProductStatus */ -class AppleProductStatus { - const CAPABILITY_NAME = 'APPLE_PAY'; - const SETTINGS_KEY = 'products_apple_enabled'; +class AppleProductStatus extends ProductStatus { + public const CAPABILITY_NAME = 'APPLE_PAY'; + public const SETTINGS_KEY = 'products_apple_enabled'; - const SETTINGS_VALUE_ENABLED = 'yes'; - const SETTINGS_VALUE_DISABLED = 'no'; - const SETTINGS_VALUE_UNDEFINED = ''; - - /** - * The current status stored in memory. - * - * @var bool|null - */ - private $current_status = null; - - /** - * If there was a request failure. - * - * @var bool - */ - private $has_request_failure = false; + public const SETTINGS_VALUE_ENABLED = 'yes'; + public const SETTINGS_VALUE_DISABLED = 'no'; + public const SETTINGS_VALUE_UNDEFINED = ''; /** * The settings. * * @var Settings */ - private $settings; - - /** - * The partners endpoint. - * - * @var PartnersEndpoint - */ - private $partners_endpoint; - - /** - * The onboarding status - * - * @var State - */ - private $onboarding_state; - - /** - * The API failure registry - * - * @var FailureRegistry - */ - private $api_failure_registry; + private Settings $settings; /** * AppleProductStatus constructor. * - * @param Settings $settings The Settings. - * @param PartnersEndpoint $partners_endpoint The Partner Endpoint. - * @param State $onboarding_state The onboarding state. + * @param Settings $settings The Settings. + * @param PartnersEndpoint $partners_endpoint The Partner Endpoint. + * @param bool $is_connected The onboarding state. * @param FailureRegistry $api_failure_registry The API failure registry. */ public function __construct( Settings $settings, PartnersEndpoint $partners_endpoint, - State $onboarding_state, + bool $is_connected, FailureRegistry $api_failure_registry ) { - $this->settings = $settings; - $this->partners_endpoint = $partners_endpoint; - $this->onboarding_state = $onboarding_state; - $this->api_failure_registry = $api_failure_registry; + parent::__construct( $is_connected, $partners_endpoint, $api_failure_registry ); + + $this->settings = $settings; } - /** - * Whether the active/subscribed products support Applepay. - * - * @return bool - */ - public function is_active() : bool { - - // If not onboarded then makes no sense to check status. - if ( ! $this->is_onboarded() ) { - return false; - } - + /** {@inheritDoc} */ + protected function check_local_state() : ?bool { $status_override = apply_filters( 'woocommerce_paypal_payments_apple_pay_product_status', null ); if ( null !== $status_override ) { return $status_override; } - // If status was already checked on this request return the same result. - if ( null !== $this->current_status ) { - return $this->current_status; - } - - // Check if status was checked on previous requests. if ( $this->settings->has( self::SETTINGS_KEY ) && ( $this->settings->get( self::SETTINGS_KEY ) ) ) { - $this->current_status = wc_string_to_bool( $this->settings->get( self::SETTINGS_KEY ) ); - return $this->current_status; + return wc_string_to_bool( $this->settings->get( self::SETTINGS_KEY ) ); } - // Check API failure registry to prevent multiple failed API requests. - if ( $this->api_failure_registry->has_failure_in_timeframe( FailureRegistry::SELLER_STATUS_KEY, HOUR_IN_SECONDS ) ) { - $this->has_request_failure = true; - $this->current_status = false; - return $this->current_status; - } - - // Request seller status via PayPal API. - try { - $seller_status = $this->partners_endpoint->seller_status(); - } catch ( Throwable $error ) { - $this->has_request_failure = true; - $this->current_status = false; - return $this->current_status; - } + return null; + } + /** {@inheritDoc} */ + protected function check_active_state( SellerStatus $seller_status ) : bool { // Check the seller status for the intended capability. $has_capability = false; foreach ( $seller_status->products() as $product ) { @@ -145,65 +81,33 @@ class AppleProductStatus { } } - foreach ( $seller_status->capabilities() as $capability ) { - if ( $capability->name() === self::CAPABILITY_NAME && $capability->status() === SellerStatusCapability::STATUS_ACTIVE ) { - $has_capability = true; + if ( ! $has_capability ) { + foreach ( $seller_status->capabilities() as $capability ) { + if ( $capability->name() === self::CAPABILITY_NAME && $capability->status() === SellerStatusCapability::STATUS_ACTIVE ) { + $has_capability = true; + } } } if ( $has_capability ) { - // Capability found, persist status and return true. $this->settings->set( self::SETTINGS_KEY, self::SETTINGS_VALUE_ENABLED ); - $this->settings->persist(); - - $this->current_status = true; - return $this->current_status; + } else { + $this->settings->set( self::SETTINGS_KEY, self::SETTINGS_VALUE_DISABLED ); } - - // Capability not found, persist status and return false. - $this->settings->set( self::SETTINGS_KEY, self::SETTINGS_VALUE_DISABLED ); $this->settings->persist(); - $this->current_status = false; - return $this->current_status; + return $has_capability; } - /** - * Returns if the seller is onboarded. - * - * @return bool - */ - public function is_onboarded(): bool { - return $this->onboarding_state->current_state() >= State::STATE_ONBOARDED; - } - - /** - * Returns if there was a request failure. - * - * @return bool - */ - public function has_request_failure(): bool { - return $this->has_request_failure; - } - - /** - * Clears the persisted result to force a recheck. - * - * @param Settings|null $settings The settings object. - * We accept a Settings object to don't override other sequential settings that are being updated elsewhere. - * @return void - */ - public function clear( Settings $settings = null ): void { + /** {@inheritDoc} */ + protected function clear_state( Settings $settings = null ) : void { if ( null === $settings ) { $settings = $this->settings; } - $this->current_status = null; - if ( $settings->has( self::SETTINGS_KEY ) ) { $settings->set( self::SETTINGS_KEY, self::SETTINGS_VALUE_UNDEFINED ); $settings->persist(); } } - } diff --git a/modules/ppcp-axo-block/src/AxoBlockPaymentMethod.php b/modules/ppcp-axo-block/src/AxoBlockPaymentMethod.php index 78bafdae3..db4d5438e 100644 --- a/modules/ppcp-axo-block/src/AxoBlockPaymentMethod.php +++ b/modules/ppcp-axo-block/src/AxoBlockPaymentMethod.php @@ -13,7 +13,7 @@ use WC_Payment_Gateway; use Automattic\WooCommerce\Blocks\Payments\Integrations\AbstractPaymentMethodType; use WooCommerce\PayPalCommerce\Axo\FrontendLoggerEndpoint; use WooCommerce\PayPalCommerce\Button\Assets\SmartButtonInterface; -use WooCommerce\PayPalCommerce\Onboarding\Environment; +use WooCommerce\PayPalCommerce\WcGateway\Helper\Environment; use WooCommerce\PayPalCommerce\Axo\Gateway\AxoGateway; use WooCommerce\PayPalCommerce\WcGateway\Settings\Settings; use WooCommerce\PayPalCommerce\WcGateway\Helper\DCCGatewayConfiguration; diff --git a/modules/ppcp-axo/src/Assets/AxoManager.php b/modules/ppcp-axo/src/Assets/AxoManager.php index d02e27355..0263adb3c 100644 --- a/modules/ppcp-axo/src/Assets/AxoManager.php +++ b/modules/ppcp-axo/src/Assets/AxoManager.php @@ -12,7 +12,7 @@ namespace WooCommerce\PayPalCommerce\Axo\Assets; use Psr\Log\LoggerInterface; use WooCommerce\PayPalCommerce\ApiClient\Helper\CurrencyGetter; use WooCommerce\PayPalCommerce\Axo\FrontendLoggerEndpoint; -use WooCommerce\PayPalCommerce\Onboarding\Environment; +use WooCommerce\PayPalCommerce\WcGateway\Helper\Environment; use WooCommerce\PayPalCommerce\Session\SessionHandler; use WooCommerce\PayPalCommerce\WcGateway\Helper\SettingsStatus; use WooCommerce\PayPalCommerce\WcGateway\Settings\Settings; diff --git a/modules/ppcp-axo/src/Gateway/AxoGateway.php b/modules/ppcp-axo/src/Gateway/AxoGateway.php index cd0ec8579..3f699a44a 100644 --- a/modules/ppcp-axo/src/Gateway/AxoGateway.php +++ b/modules/ppcp-axo/src/Gateway/AxoGateway.php @@ -19,7 +19,7 @@ use WooCommerce\PayPalCommerce\ApiClient\Entity\PaymentSource; use WooCommerce\PayPalCommerce\ApiClient\Factory\PurchaseUnitFactory; use WooCommerce\PayPalCommerce\ApiClient\Factory\ShippingPreferenceFactory; use WooCommerce\PayPalCommerce\ApiClient\Entity\Order; -use WooCommerce\PayPalCommerce\Onboarding\Environment; +use WooCommerce\PayPalCommerce\WcGateway\Helper\Environment; use WooCommerce\PayPalCommerce\Vendor\Psr\Container\ContainerInterface; use WooCommerce\PayPalCommerce\WcGateway\Gateway\GatewaySettingsRendererTrait; use WooCommerce\PayPalCommerce\WcGateway\Gateway\TransactionUrlProvider; diff --git a/modules/ppcp-button/services.php b/modules/ppcp-button/services.php index 6844a08d0..5a489d330 100644 --- a/modules/ppcp-button/services.php +++ b/modules/ppcp-button/services.php @@ -35,7 +35,7 @@ use WooCommerce\PayPalCommerce\Button\Exception\RuntimeException; use WooCommerce\PayPalCommerce\Button\Helper\EarlyOrderHandler; use WooCommerce\PayPalCommerce\Button\Helper\MessagesApply; use WooCommerce\PayPalCommerce\Button\Helper\ThreeDSecure; -use WooCommerce\PayPalCommerce\Onboarding\Environment; +use WooCommerce\PayPalCommerce\WcGateway\Helper\Environment; use WooCommerce\PayPalCommerce\Onboarding\State; use WooCommerce\PayPalCommerce\WcGateway\Helper\SettingsStatus; use WooCommerce\PayPalCommerce\WcGateway\Helper\DCCGatewayConfiguration; diff --git a/modules/ppcp-button/src/Assets/SmartButton.php b/modules/ppcp-button/src/Assets/SmartButton.php index fd1b93404..81ced3a68 100644 --- a/modules/ppcp-button/src/Assets/SmartButton.php +++ b/modules/ppcp-button/src/Assets/SmartButton.php @@ -36,7 +36,7 @@ use WooCommerce\PayPalCommerce\Button\Endpoint\ValidateCheckoutEndpoint; use WooCommerce\PayPalCommerce\Button\Helper\ContextTrait; use WooCommerce\PayPalCommerce\Button\Helper\DisabledFundingSources; use WooCommerce\PayPalCommerce\Button\Helper\MessagesApply; -use WooCommerce\PayPalCommerce\Onboarding\Environment; +use WooCommerce\PayPalCommerce\WcGateway\Helper\Environment; use WooCommerce\PayPalCommerce\PayLaterBlock\PayLaterBlockModule; use WooCommerce\PayPalCommerce\PayLaterWCBlocks\PayLaterWCBlocksModule; use WooCommerce\PayPalCommerce\SavePaymentMethods\Endpoint\CreatePaymentToken; diff --git a/modules/ppcp-compat/services.php b/modules/ppcp-compat/services.php index 7982366e0..65ee1e3d8 100644 --- a/modules/ppcp-compat/services.php +++ b/modules/ppcp-compat/services.php @@ -128,13 +128,6 @@ return array( } return array( - new SettingsMap( - $container->get( 'settings.data.general' ), - array( - 'client_id' => 'client_id', - 'client_secret' => 'client_secret', - ) - ), new SettingsMap( $container->get( 'settings.data.general' ), /** @@ -145,7 +138,10 @@ return array( * the credentials are used for. */ array( - 'is_sandbox' => 'sandbox_merchant', + 'merchant_id' => 'merchant_id', + 'client_id' => 'client_id', + 'client_secret' => 'client_secret', + 'sandbox_on' => 'sandbox_merchant', 'live_client_id' => 'client_id', 'live_client_secret' => 'client_secret', 'live_merchant_id' => 'merchant_id', diff --git a/modules/ppcp-googlepay/services.php b/modules/ppcp-googlepay/services.php index b1cccaebd..f92aa0bd8 100644 --- a/modules/ppcp-googlepay/services.php +++ b/modules/ppcp-googlepay/services.php @@ -18,7 +18,7 @@ use WooCommerce\PayPalCommerce\Googlepay\Endpoint\UpdatePaymentDataEndpoint; use WooCommerce\PayPalCommerce\Googlepay\Helper\ApmApplies; use WooCommerce\PayPalCommerce\Googlepay\Helper\ApmProductStatus; use WooCommerce\PayPalCommerce\Googlepay\Helper\AvailabilityNotice; -use WooCommerce\PayPalCommerce\Onboarding\Environment; +use WooCommerce\PayPalCommerce\WcGateway\Helper\Environment; use WooCommerce\PayPalCommerce\Onboarding\State; use WooCommerce\PayPalCommerce\Vendor\Psr\Container\ContainerInterface; @@ -75,7 +75,7 @@ return array( return new ApmProductStatus( $container->get( 'wcgateway.settings' ), $container->get( 'api.endpoint.partners' ), - $container->get( 'onboarding.state' ), + $container->get( 'settings.flag.is-connected' ), $container->get( 'api.helper.failure-registry' ) ); } diff --git a/modules/ppcp-googlepay/src/Assets/Button.php b/modules/ppcp-googlepay/src/Assets/Button.php index 1d85b982f..f3ff90611 100644 --- a/modules/ppcp-googlepay/src/Assets/Button.php +++ b/modules/ppcp-googlepay/src/Assets/Button.php @@ -16,7 +16,7 @@ use WooCommerce\PayPalCommerce\Button\Assets\ButtonInterface; use WooCommerce\PayPalCommerce\Button\Helper\ContextTrait; use WooCommerce\PayPalCommerce\Googlepay\Endpoint\UpdatePaymentDataEndpoint; use WooCommerce\PayPalCommerce\Googlepay\GooglePayGateway; -use WooCommerce\PayPalCommerce\Onboarding\Environment; +use WooCommerce\PayPalCommerce\WcGateway\Helper\Environment; use WooCommerce\PayPalCommerce\Session\SessionHandler; use WooCommerce\PayPalCommerce\WcGateway\Exception\NotFoundException; use WooCommerce\PayPalCommerce\WcGateway\Helper\SettingsStatus; diff --git a/modules/ppcp-googlepay/src/GooglepayModule.php b/modules/ppcp-googlepay/src/GooglepayModule.php index dd7320011..a50408bd3 100644 --- a/modules/ppcp-googlepay/src/GooglepayModule.php +++ b/modules/ppcp-googlepay/src/GooglepayModule.php @@ -233,7 +233,7 @@ class GooglepayModule implements ServiceModule, ExtendingModule, ExecutableModul ); add_filter( - 'woocommerce_paypal_payments_rest_common_merchant_data', + 'woocommerce_paypal_payments_rest_common_merchant_features', function ( array $features ) use ( $c ): array { $product_status = $c->get( 'googlepay.helpers.apm-product-status' ); assert( $product_status instanceof ApmProductStatus ); diff --git a/modules/ppcp-googlepay/src/Helper/ApmProductStatus.php b/modules/ppcp-googlepay/src/Helper/ApmProductStatus.php index 3639a1717..dbe812837 100644 --- a/modules/ppcp-googlepay/src/Helper/ApmProductStatus.php +++ b/modules/ppcp-googlepay/src/Helper/ApmProductStatus.php @@ -9,130 +9,66 @@ declare(strict_types=1); namespace WooCommerce\PayPalCommerce\Googlepay\Helper; -use Throwable; use WooCommerce\PayPalCommerce\ApiClient\Endpoint\PartnersEndpoint; use WooCommerce\PayPalCommerce\ApiClient\Entity\SellerStatusCapability; use WooCommerce\PayPalCommerce\ApiClient\Helper\FailureRegistry; -use WooCommerce\PayPalCommerce\Onboarding\State; use WooCommerce\PayPalCommerce\WcGateway\Settings\Settings; +use WooCommerce\PayPalCommerce\ApiClient\Helper\ProductStatus; +use WooCommerce\PayPalCommerce\ApiClient\Entity\SellerStatus; /** * Class ApmProductStatus */ -class ApmProductStatus { - const CAPABILITY_NAME = 'GOOGLE_PAY'; - const SETTINGS_KEY = 'products_googlepay_enabled'; +class ApmProductStatus extends ProductStatus { + public const CAPABILITY_NAME = 'GOOGLE_PAY'; + public const SETTINGS_KEY = 'products_googlepay_enabled'; - const SETTINGS_VALUE_ENABLED = 'yes'; - const SETTINGS_VALUE_DISABLED = 'no'; - const SETTINGS_VALUE_UNDEFINED = ''; - - /** - * The current status stored in memory. - * - * @var bool|null - */ - private $current_status = null; - - /** - * If there was a request failure. - * - * @var bool - */ - private $has_request_failure = false; + public const SETTINGS_VALUE_ENABLED = 'yes'; + public const SETTINGS_VALUE_DISABLED = 'no'; + public const SETTINGS_VALUE_UNDEFINED = ''; /** * The settings. * * @var Settings */ - private $settings; - - /** - * The partners endpoint. - * - * @var PartnersEndpoint - */ - private $partners_endpoint; - - /** - * The onboarding status - * - * @var State - */ - private $onboarding_state; - - /** - * The API failure registry - * - * @var FailureRegistry - */ - private $api_failure_registry; + private Settings $settings; /** * ApmProductStatus constructor. * - * @param Settings $settings The Settings. - * @param PartnersEndpoint $partners_endpoint The Partner Endpoint. - * @param State $onboarding_state The onboarding state. + * @param Settings $settings The Settings. + * @param PartnersEndpoint $partners_endpoint The Partner Endpoint. + * @param bool $is_connected The onboarding state. * @param FailureRegistry $api_failure_registry The API failure registry. */ public function __construct( Settings $settings, PartnersEndpoint $partners_endpoint, - State $onboarding_state, + bool $is_connected, FailureRegistry $api_failure_registry ) { - $this->settings = $settings; - $this->partners_endpoint = $partners_endpoint; - $this->onboarding_state = $onboarding_state; - $this->api_failure_registry = $api_failure_registry; + parent::__construct( $is_connected, $partners_endpoint, $api_failure_registry ); + + $this->settings = $settings; } - /** - * Whether the active/subscribed products support Googlepay. - * - * @return bool - */ - public function is_active() : bool { - - // If not onboarded then makes no sense to check status. - if ( ! $this->is_onboarded() ) { - return false; - } - + /** {@inheritDoc} */ + protected function check_local_state() : ?bool { $status_override = apply_filters( 'woocommerce_paypal_payments_google_pay_product_status', null ); if ( null !== $status_override ) { return $status_override; } - // If status was already checked on this request return the same result. - if ( null !== $this->current_status ) { - return $this->current_status; - } - - // Check if status was checked on previous requests. if ( $this->settings->has( self::SETTINGS_KEY ) && ( $this->settings->get( self::SETTINGS_KEY ) ) ) { - $this->current_status = wc_string_to_bool( $this->settings->get( self::SETTINGS_KEY ) ); - return $this->current_status; + return wc_string_to_bool( $this->settings->get( self::SETTINGS_KEY ) ); } - // Check API failure registry to prevent multiple failed API requests. - if ( $this->api_failure_registry->has_failure_in_timeframe( FailureRegistry::SELLER_STATUS_KEY, HOUR_IN_SECONDS ) ) { - $this->has_request_failure = true; - $this->current_status = false; - return $this->current_status; - } - - // Request seller status via PayPal API. - try { - $seller_status = $this->partners_endpoint->seller_status(); - } catch ( Throwable $error ) { - $this->has_request_failure = true; - $this->current_status = false; - return $this->current_status; - } + return null; + } + /** {@inheritDoc} */ + protected function check_active_state( SellerStatus $seller_status ) : bool { // Check the seller status for the intended capability. $has_capability = false; foreach ( $seller_status->products() as $product ) { @@ -145,65 +81,33 @@ class ApmProductStatus { } } - foreach ( $seller_status->capabilities() as $capability ) { - if ( $capability->name() === self::CAPABILITY_NAME && $capability->status() === SellerStatusCapability::STATUS_ACTIVE ) { - $has_capability = true; + if ( ! $has_capability ) { + foreach ( $seller_status->capabilities() as $capability ) { + if ( $capability->name() === self::CAPABILITY_NAME && $capability->status() === SellerStatusCapability::STATUS_ACTIVE ) { + $has_capability = true; + } } } if ( $has_capability ) { - // Capability found, persist status and return true. $this->settings->set( self::SETTINGS_KEY, self::SETTINGS_VALUE_ENABLED ); - $this->settings->persist(); - - $this->current_status = true; - return $this->current_status; + } else { + $this->settings->set( self::SETTINGS_KEY, self::SETTINGS_VALUE_DISABLED ); } - - // Capability not found, persist status and return false. - $this->settings->set( self::SETTINGS_KEY, self::SETTINGS_VALUE_DISABLED ); $this->settings->persist(); - $this->current_status = false; - return $this->current_status; + return $has_capability; } - /** - * Returns if the seller is onboarded. - * - * @return bool - */ - public function is_onboarded(): bool { - return $this->onboarding_state->current_state() >= State::STATE_ONBOARDED; - } - - /** - * Returns if there was a request failure. - * - * @return bool - */ - public function has_request_failure(): bool { - return $this->has_request_failure; - } - - /** - * Clears the persisted result to force a recheck. - * - * @param Settings|null $settings The settings object. - * We accept a Settings object to don't override other sequential settings that are being updated elsewhere. - * @return void - */ - public function clear( Settings $settings = null ): void { + /** {@inheritDoc} */ + protected function clear_state( Settings $settings = null ) : void { if ( null === $settings ) { $settings = $this->settings; } - $this->current_status = null; - if ( $settings->has( self::SETTINGS_KEY ) ) { $settings->set( self::SETTINGS_KEY, self::SETTINGS_VALUE_UNDEFINED ); $settings->persist(); } } - } diff --git a/modules/ppcp-local-alternative-payment-methods/services.php b/modules/ppcp-local-alternative-payment-methods/services.php index c0a66c11e..5408288c0 100644 --- a/modules/ppcp-local-alternative-payment-methods/services.php +++ b/modules/ppcp-local-alternative-payment-methods/services.php @@ -10,6 +10,7 @@ declare(strict_types=1); namespace WooCommerce\PayPalCommerce\LocalAlternativePaymentMethods; use WooCommerce\PayPalCommerce\Vendor\Psr\Container\ContainerInterface; +use WooCommerce\PayPalCommerce\LocalAlternativePaymentMethods\LocalApmProductStatus; return array( 'ppcp-local-apms.url' => static function ( ContainerInterface $container ): string { @@ -67,6 +68,14 @@ return array( ), ); }, + 'ppcp-local-apms.product-status' => static function ( ContainerInterface $container ): LocalApmProductStatus { + return new LocalApmProductStatus( + $container->get( 'wcgateway.settings' ), + $container->get( 'api.endpoint.partners' ), + $container->get( 'settings.flag.is-connected' ), + $container->get( 'api.helper.failure-registry' ) + ); + }, 'ppcp-local-apms.bancontact.wc-gateway' => static function ( ContainerInterface $container ): BancontactGateway { return new BancontactGateway( $container->get( 'api.endpoint.orders' ), diff --git a/modules/ppcp-local-alternative-payment-methods/src/LocalApmProductStatus.php b/modules/ppcp-local-alternative-payment-methods/src/LocalApmProductStatus.php new file mode 100644 index 000000000..2a89146be --- /dev/null +++ b/modules/ppcp-local-alternative-payment-methods/src/LocalApmProductStatus.php @@ -0,0 +1,95 @@ +settings = $settings; + } + + /** {@inheritDoc} */ + protected function check_local_state() : ?bool { + 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 { + $has_capability = false; + + foreach ( $seller_status->products() as $product ) { + if ( $product->name() === 'PAYMENT_METHODS' ) { + $has_capability = true; + break; + } + } + + if ( $has_capability ) { + $this->settings->set( self::SETTINGS_KEY, self::SETTINGS_VALUE_ENABLED ); + } else { + $this->settings->set( self::SETTINGS_KEY, self::SETTINGS_VALUE_DISABLED ); + } + $this->settings->persist(); + + return $has_capability; + } + + /** {@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(); + } + } +} diff --git a/modules/ppcp-onboarding/services.php b/modules/ppcp-onboarding/services.php index 2a6de82d8..cbbd02da5 100644 --- a/modules/ppcp-onboarding/services.php +++ b/modules/ppcp-onboarding/services.php @@ -11,58 +11,15 @@ namespace WooCommerce\PayPalCommerce\Onboarding; use WooCommerce\PayPalCommerce\Onboarding\Render\OnboardingOptionsRenderer; use WooCommerce\PayPalCommerce\Vendor\Psr\Container\ContainerInterface; -use WooCommerce\PayPalCommerce\ApiClient\Authentication\Bearer; -use WooCommerce\PayPalCommerce\ApiClient\Authentication\ConnectBearer; -use WooCommerce\PayPalCommerce\ApiClient\Authentication\PayPalBearer; use WooCommerce\PayPalCommerce\ApiClient\Helper\Cache; use WooCommerce\PayPalCommerce\Onboarding\Assets\OnboardingAssets; use WooCommerce\PayPalCommerce\Onboarding\Endpoint\LoginSellerEndpoint; use WooCommerce\PayPalCommerce\Onboarding\Endpoint\UpdateSignupLinksEndpoint; use WooCommerce\PayPalCommerce\Onboarding\Render\OnboardingSendOnlyNoticeRenderer; use WooCommerce\PayPalCommerce\Onboarding\Render\OnboardingRenderer; +use WooCommerce\PayPalCommerce\WcGateway\Helper\Environment; return array( - 'api.sandbox-host' => static function ( ContainerInterface $container ): string { - - $state = $container->get( 'onboarding.state' ); - - /** - * The State object. - * - * @var State $state - */ - if ( $state->current_state() >= State::STATE_ONBOARDED ) { - return PAYPAL_SANDBOX_API_URL; - } - return CONNECT_WOO_SANDBOX_URL; - }, - 'api.production-host' => static function ( ContainerInterface $container ): string { - - $state = $container->get( 'onboarding.state' ); - - /** - * The Environment and State variables. - * - * @var Environment $environment - * @var State $state - */ - if ( $state->current_state() >= State::STATE_ONBOARDED ) { - return PAYPAL_API_URL; - } - return CONNECT_WOO_URL; - }, - 'api.host' => static function ( ContainerInterface $container ): string { - $environment = $container->get( 'onboarding.environment' ); - - /** - * The Environment and State variables. - * - * @var Environment $environment - */ - return $environment->current_environment_is( Environment::SANDBOX ) - ? (string) $container->get( 'api.sandbox-host' ) : (string) $container->get( 'api.production-host' ); - - }, 'api.paypal-host' => function( ContainerInterface $container ) : string { $environment = $container->get( 'onboarding.environment' ); /** @@ -85,38 +42,20 @@ return array( return $container->get( 'api.paypal-website-url-production' ); }, - - 'api.bearer' => static function ( ContainerInterface $container ): Bearer { - - $state = $container->get( 'onboarding.state' ); - - /** - * The State. - * - * @var State $state - */ - if ( $state->current_state() < State::STATE_ONBOARDED ) { - return new ConnectBearer(); - } - $cache = new Cache( 'ppcp-paypal-bearer' ); - $key = $container->get( 'api.key' ); - $secret = $container->get( 'api.secret' ); - $host = $container->get( 'api.host' ); - $logger = $container->get( 'woocommerce.logger.woocommerce' ); - $settings = $container->get( 'wcgateway.settings' ); - return new PayPalBearer( - $cache, - $host, - $key, - $secret, - $logger, - $settings - ); - }, 'onboarding.state' => function( ContainerInterface $container ) : State { $settings = $container->get( 'wcgateway.settings' ); return new State( $settings ); }, + /** + * Checks if the onboarding process is completed and the merchant API can be used. + * This service is overwritten by the ppcp-settings module, when it's active. + */ + 'settings.flag.is-connected' => static function ( ContainerInterface $container ) : bool { + $state = $container->get( 'onboarding.state' ); + assert( $state instanceof State ); + + return $state->current_state() >= State::STATE_ONBOARDED; + }, 'onboarding.environment' => function( ContainerInterface $container ) : Environment { $settings = $container->get( 'wcgateway.settings' ); return new Environment( $settings ); @@ -149,8 +88,8 @@ return array( $login_seller_sandbox = $container->get( 'api.endpoint.login-seller-sandbox' ); $partner_referrals_data = $container->get( 'api.repository.partner-referrals-data' ); $settings = $container->get( 'wcgateway.settings' ); - $cache = new Cache( 'ppcp-paypal-bearer' ); - $logger = $container->get( 'woocommerce.logger.woocommerce' ); + $cache = $container->get( 'api.paypal-bearer-cache' ); + $logger = $container->get( 'woocommerce.logger.woocommerce' ); return new LoginSellerEndpoint( $request_data, $login_seller_production, diff --git a/modules/ppcp-onboarding/src/Assets/OnboardingAssets.php b/modules/ppcp-onboarding/src/Assets/OnboardingAssets.php index 663bdfee1..959aad775 100644 --- a/modules/ppcp-onboarding/src/Assets/OnboardingAssets.php +++ b/modules/ppcp-onboarding/src/Assets/OnboardingAssets.php @@ -11,7 +11,7 @@ namespace WooCommerce\PayPalCommerce\Onboarding\Assets; use WooCommerce\PayPalCommerce\Onboarding\Endpoint\LoginSellerEndpoint; use WooCommerce\PayPalCommerce\Onboarding\Endpoint\UpdateSignupLinksEndpoint; -use WooCommerce\PayPalCommerce\Onboarding\Environment; +use WooCommerce\PayPalCommerce\WcGateway\Helper\Environment; use WooCommerce\PayPalCommerce\Onboarding\State; use WooCommerce\PayPalCommerce\WcGateway\Settings\Settings; diff --git a/modules/ppcp-onboarding/src/Environment.php b/modules/ppcp-onboarding/src/Environment.php deleted file mode 100644 index 9bd136ed0..000000000 --- a/modules/ppcp-onboarding/src/Environment.php +++ /dev/null @@ -1,60 +0,0 @@ -settings = $settings; - } - - /** - * Returns the current environment. - * - * @return string - */ - public function current_environment(): string { - return ( - $this->settings->has( 'sandbox_on' ) && $this->settings->get( 'sandbox_on' ) - ) ? self::SANDBOX : self::PRODUCTION; - } - - /** - * Detect whether the current environment equals $environment - * - * @param string $environment The value to check against. - * - * @return bool - */ - public function current_environment_is( string $environment ): bool { - return $this->current_environment() === $environment; - } -} diff --git a/modules/ppcp-onboarding/src/State.php b/modules/ppcp-onboarding/src/State.php index 492d180b6..59963dcdf 100644 --- a/modules/ppcp-onboarding/src/State.php +++ b/modules/ppcp-onboarding/src/State.php @@ -10,6 +10,7 @@ declare(strict_types=1); namespace WooCommerce\PayPalCommerce\Onboarding; use WooCommerce\PayPalCommerce\Vendor\Psr\Container\ContainerInterface; +use WooCommerce\PayPalCommerce\WcGateway\Helper\Environment; /** * Class State diff --git a/modules/ppcp-paylater-configurator/src/Endpoint/SaveConfig.php b/modules/ppcp-paylater-configurator/src/Endpoint/SaveConfig.php index df4e4affa..b1f77de85 100644 --- a/modules/ppcp-paylater-configurator/src/Endpoint/SaveConfig.php +++ b/modules/ppcp-paylater-configurator/src/Endpoint/SaveConfig.php @@ -94,7 +94,7 @@ class SaveConfig { * * @param array $config The configurator config. */ - private function save_config( array $config ): void { + public function save_config( array $config ): void { $this->settings->set( 'pay_later_enable_styling_per_messaging_location', true ); $this->settings->set( 'pay_later_messaging_enabled', true ); diff --git a/modules/ppcp-paypal-subscriptions/src/PayPalSubscriptionsModule.php b/modules/ppcp-paypal-subscriptions/src/PayPalSubscriptionsModule.php index 48c3a71af..0d55965f7 100644 --- a/modules/ppcp-paypal-subscriptions/src/PayPalSubscriptionsModule.php +++ b/modules/ppcp-paypal-subscriptions/src/PayPalSubscriptionsModule.php @@ -21,7 +21,7 @@ use WC_Subscriptions_Product; use WooCommerce\PayPalCommerce\ApiClient\Endpoint\BillingSubscriptions; use WooCommerce\PayPalCommerce\ApiClient\Exception\PayPalApiException; use WooCommerce\PayPalCommerce\ApiClient\Exception\RuntimeException; -use WooCommerce\PayPalCommerce\Onboarding\Environment; +use WooCommerce\PayPalCommerce\WcGateway\Helper\Environment; use WooCommerce\PayPalCommerce\Vendor\Inpsyde\Modularity\Module\ExecutableModule; use WooCommerce\PayPalCommerce\Vendor\Inpsyde\Modularity\Module\ExtendingModule; use WooCommerce\PayPalCommerce\Vendor\Inpsyde\Modularity\Module\ModuleClassNameIdTrait; diff --git a/modules/ppcp-settings/resources/js/Components/Screens/Overview/TabPayLaterMessaging.js b/modules/ppcp-settings/resources/js/Components/Screens/Overview/TabPayLaterMessaging.js index a3a3083c9..274ef91c2 100644 --- a/modules/ppcp-settings/resources/js/Components/Screens/Overview/TabPayLaterMessaging.js +++ b/modules/ppcp-settings/resources/js/Components/Screens/Overview/TabPayLaterMessaging.js @@ -1,7 +1,16 @@ import React, { useEffect } from 'react'; +import { PayLaterMessagingHooks } from '../../../data'; const TabPayLaterMessaging = () => { - const config = {}; // Replace with the appropriate/saved configuration. + const { + config, + setCart, + setCheckout, + setProduct, + setShop, + setHome, + setCustom_placement, + } = PayLaterMessagingHooks.usePayLaterMessaging(); const PcpPayLaterConfigurator = window.ppcpSettings?.PcpPayLaterConfigurator; @@ -27,17 +36,16 @@ const TabPayLaterMessaging = () => { subheader: 'ppcp-r-paylater-configurator__subheader', }, onSave: ( data ) => { - /* - TODO: - - The saving will be handled in a separate PR. - - One option could be: - - When saving the settings, programmatically click on the configurator's - "Save Changes" button and send the request to PHP. - */ + setCart( data.config.cart ); + setCheckout( data.config.checkout ); + setProduct( data.config.product ); + setShop( data.config.shop ); + setHome( data.config.home ); + setCustom_placement( data.config.custom_placement ); }, } ); } - }, [ PcpPayLaterConfigurator ] ); + }, [ PcpPayLaterConfigurator, config ] ); return (
{ }; }; -export const useState = () => { +export const useStore = () => { const { persist, isReady } = useHooks(); return { persist, isReady }; }; diff --git a/modules/ppcp-settings/resources/js/data/index.js b/modules/ppcp-settings/resources/js/data/index.js index 0985aa972..227a62226 100644 --- a/modules/ppcp-settings/resources/js/data/index.js +++ b/modules/ppcp-settings/resources/js/data/index.js @@ -5,8 +5,17 @@ import * as Payment from './payment'; import * as Settings from './settings'; import * as Styling from './styling'; import * as Todos from './todos'; +import * as PayLaterMessaging from './pay-later-messaging'; -const stores = [ Onboarding, Common, Payment, Settings, Styling, Todos ]; +const stores = [ + Onboarding, + Common, + Payment, + Settings, + Styling, + Todos, + PayLaterMessaging, +]; stores.forEach( ( store ) => { try { @@ -30,6 +39,7 @@ export const PaymentHooks = Payment.hooks; export const SettingsHooks = Settings.hooks; export const StylingHooks = Styling.hooks; export const TodosHooks = Todos.hooks; +export const PayLaterMessagingHooks = PayLaterMessaging.hooks; export const OnboardingStoreName = Onboarding.STORE_NAME; export const CommonStoreName = Common.STORE_NAME; @@ -37,6 +47,7 @@ export const PaymentStoreName = Payment.STORE_NAME; export const SettingsStoreName = Settings.STORE_NAME; export const StylingStoreName = Styling.STORE_NAME; export const TodosStoreName = Todos.STORE_NAME; +export const PayLaterMessagingStoreName = PayLaterMessaging.STORE_NAME; export * from './configuration'; diff --git a/modules/ppcp-settings/resources/js/data/pay-later-messaging/action-types.js b/modules/ppcp-settings/resources/js/data/pay-later-messaging/action-types.js new file mode 100644 index 000000000..70913ddd6 --- /dev/null +++ b/modules/ppcp-settings/resources/js/data/pay-later-messaging/action-types.js @@ -0,0 +1,18 @@ +/** + * Action Types: Define unique identifiers for actions across all store modules. + * + * @file + */ + +export default { + // Transient data. + SET_TRANSIENT: 'PAY_LATER_MESSAGING:SET_TRANSIENT', + + // Persistent data. + SET_PERSISTENT: 'PAY_LATER_MESSAGING:SET_PERSISTENT', + RESET: 'PAY_LATER_MESSAGING:RESET', + HYDRATE: 'PAY_LATER_MESSAGING:HYDRATE', + + // Controls - always start with "DO_". + DO_PERSIST_DATA: 'PAY_LATER_MESSAGING:DO_PERSIST_DATA', +}; diff --git a/modules/ppcp-settings/resources/js/data/pay-later-messaging/actions.js b/modules/ppcp-settings/resources/js/data/pay-later-messaging/actions.js new file mode 100644 index 000000000..59d68d37c --- /dev/null +++ b/modules/ppcp-settings/resources/js/data/pay-later-messaging/actions.js @@ -0,0 +1,80 @@ +/** + * Action Creators: Define functions to create action objects. + * + * These functions update state or trigger side effects (e.g., async operations). + * Actions are categorized as Transient, Persistent, or Side effect. + * + * @file + */ + +import { select } from '@wordpress/data'; + +import ACTION_TYPES from './action-types'; +import { STORE_NAME } from './constants'; + +/** + * @typedef {Object} Action An action object that is handled by a reducer or control. + * @property {string} type - The action type. + * @property {Object?} payload - Optional payload for the action. + */ + +/** + * Special. Resets all values in the store to initial defaults. + * + * @return {Action} The action. + */ +export const reset = () => ( { type: ACTION_TYPES.RESET } ); + +/** + * Persistent. Set the full store details during app initialization. + * + * @param {{data: {}, flags?: {}}} payload + * @return {Action} The action. + */ +export const hydrate = ( payload ) => ( { + type: ACTION_TYPES.HYDRATE, + payload, +} ); + +/** + * Generic transient-data updater. + * + * @param {string} prop Name of the property to update. + * @param {any} value The new value of the property. + * @return {Action} The action. + */ +export const setTransient = ( prop, value ) => ( { + type: ACTION_TYPES.SET_TRANSIENT, + payload: { [ prop ]: value }, +} ); + +/** + * Generic persistent-data updater. + * + * @param {string} prop Name of the property to update. + * @param {any} value The new value of the property. + * @return {Action} The action. + */ +export const setPersistent = ( prop, value ) => ( { + type: ACTION_TYPES.SET_PERSISTENT, + payload: { [ prop ]: value }, +} ); + +/** + * Transient. Marks the store as "ready", i.e., fully initialized. + * + * @param {boolean} isReady + * @return {Action} The action. + */ +export const setIsReady = ( isReady ) => setTransient( 'isReady', isReady ); + +/** + * Side effect. Triggers the persistence of store data to the server. + * + * @return {Action} The action. + */ +export const persist = function* () { + const data = yield select( STORE_NAME ).persistentData(); + + yield { type: ACTION_TYPES.DO_PERSIST_DATA, data }; +}; diff --git a/modules/ppcp-settings/resources/js/data/pay-later-messaging/constants.js b/modules/ppcp-settings/resources/js/data/pay-later-messaging/constants.js new file mode 100644 index 000000000..09f3bab52 --- /dev/null +++ b/modules/ppcp-settings/resources/js/data/pay-later-messaging/constants.js @@ -0,0 +1,28 @@ +/** + * Name of the Redux store module. + * + * Used by: Reducer, Selector, Index + * + * @type {string} + */ +export const STORE_NAME = 'wc/paypal/pay_later_messaging'; + +/** + * REST path to hydrate data of this module by loading data from the WP DB. + * + * Used by: Resolvers + * See: PayLaterMessagingEndpoint.php + * + * @type {string} + */ +export const REST_HYDRATE_PATH = '/wc/v3/wc_paypal/pay_later_messaging'; + +/** + * REST path to persist data of this module to the WP DB. + * + * Used by: Controls + * See: PayLaterMessagingEndpoint.php + * + * @type {string} + */ +export const REST_PERSIST_PATH = '/wc/v3/wc_paypal/pay_later_messaging'; diff --git a/modules/ppcp-settings/resources/js/data/pay-later-messaging/controls.js b/modules/ppcp-settings/resources/js/data/pay-later-messaging/controls.js new file mode 100644 index 000000000..9295b62bc --- /dev/null +++ b/modules/ppcp-settings/resources/js/data/pay-later-messaging/controls.js @@ -0,0 +1,23 @@ +/** + * Controls: Implement side effects, typically asynchronous operations. + * + * Controls use ACTION_TYPES keys as identifiers. + * They are triggered by corresponding actions and handle external interactions. + * + * @file + */ + +import apiFetch from '@wordpress/api-fetch'; + +import { REST_PERSIST_PATH } from './constants'; +import ACTION_TYPES from './action-types'; + +export const controls = { + async [ ACTION_TYPES.DO_PERSIST_DATA ]( { data } ) { + return await apiFetch( { + path: REST_PERSIST_PATH, + method: 'POST', + data, + } ); + }, +}; diff --git a/modules/ppcp-settings/resources/js/data/pay-later-messaging/hooks.js b/modules/ppcp-settings/resources/js/data/pay-later-messaging/hooks.js new file mode 100644 index 000000000..0f51051cd --- /dev/null +++ b/modules/ppcp-settings/resources/js/data/pay-later-messaging/hooks.js @@ -0,0 +1,89 @@ +/** + * Hooks: Provide the main API for components to interact with the store. + * + * These encapsulate store interactions, offering a consistent interface. + * Hooks simplify data access and manipulation for components. + * + * @file + */ + +import { useDispatch } from '@wordpress/data'; + +import { createHooksForStore } from '../utils'; +import { STORE_NAME } from './constants'; + +const useHooks = () => { + const { useTransient, usePersistent } = createHooksForStore( STORE_NAME ); + const { persist } = useDispatch( STORE_NAME ); + + // Read-only flags and derived state. + // Nothing here yet. + + // Transient accessors. + const [ isReady ] = useTransient( 'isReady' ); + + // Persistent accessors. + const [ cart, setCart ] = usePersistent( 'cart' ); + const [ checkout, setCheckout ] = usePersistent( 'checkout' ); + const [ product, setProduct ] = usePersistent( 'product' ); + const [ shop, setShop ] = usePersistent( 'shop' ); + const [ home, setHome ] = usePersistent( 'home' ); + const [ custom_placement, setCustom_placement ] = + usePersistent( 'custom_placement' ); + + return { + persist, + isReady, + cart, + setCart, + checkout, + setCheckout, + product, + setProduct, + shop, + setShop, + home, + setHome, + custom_placement, + setCustom_placement, + }; +}; + +export const useStore = () => { + const { persist, isReady } = useHooks(); + return { persist, isReady }; +}; + +export const usePayLaterMessaging = () => { + const { + cart, + setCart, + checkout, + setCheckout, + product, + setProduct, + shop, + setShop, + home, + setHome, + custom_placement, + setCustom_placement, + } = useHooks(); + + return { + config: { + cart, + checkout, + product, + shop, + home, + custom_placement, + }, + setCart, + setCheckout, + setProduct, + setShop, + setHome, + setCustom_placement, + }; +}; diff --git a/modules/ppcp-settings/resources/js/data/pay-later-messaging/index.js b/modules/ppcp-settings/resources/js/data/pay-later-messaging/index.js new file mode 100644 index 000000000..3bd6e4459 --- /dev/null +++ b/modules/ppcp-settings/resources/js/data/pay-later-messaging/index.js @@ -0,0 +1,32 @@ +import { createReduxStore, register } from '@wordpress/data'; +import { controls as wpControls } from '@wordpress/data-controls'; + +import { STORE_NAME } from './constants'; +import reducer from './reducer'; +import * as selectors from './selectors'; +import * as actions from './actions'; +import * as hooks from './hooks'; +import { resolvers } from './resolvers'; +import { controls } from './controls'; + +/** + * Initializes and registers the settings store with WordPress data layer. + * Combines custom controls with WordPress data controls. + * + * @return {boolean} True if initialization succeeded, false otherwise. + */ +export const initStore = () => { + const store = createReduxStore( STORE_NAME, { + reducer, + controls: { ...wpControls, ...controls }, + actions, + selectors, + resolvers, + } ); + + register( store ); + + return Boolean( wp.data.select( STORE_NAME ) ); +}; + +export { hooks, selectors, STORE_NAME }; diff --git a/modules/ppcp-settings/resources/js/data/pay-later-messaging/reducer.js b/modules/ppcp-settings/resources/js/data/pay-later-messaging/reducer.js new file mode 100644 index 000000000..5843ef400 --- /dev/null +++ b/modules/ppcp-settings/resources/js/data/pay-later-messaging/reducer.js @@ -0,0 +1,60 @@ +/** + * Reducer: Defines store structure and state updates for this module. + * + * Manages both transient (temporary) and persistent (saved) state. + * The initial state must define all properties, as dynamic additions are not supported. + * + * @file + */ + +import { createReducer, createReducerSetters } from '../utils'; +import ACTION_TYPES from './action-types'; + +// Store structure. + +// Transient: Values that are _not_ saved to the DB (like app lifecycle-flags). +const defaultTransient = Object.freeze( { + isReady: false, +} ); + +// Persistent: Values that are loaded from the DB. +const defaultPersistent = Object.freeze( { + cart: {}, + checkout: {}, + product: {}, + shop: {}, + home: {}, + custom_placement: [], +} ); + +// Reducer logic. + +const [ changeTransient, changePersistent ] = createReducerSetters( + defaultTransient, + defaultPersistent +); + +const reducer = createReducer( defaultTransient, defaultPersistent, { + [ ACTION_TYPES.SET_TRANSIENT ]: ( state, payload ) => + changeTransient( state, payload ), + + [ ACTION_TYPES.SET_PERSISTENT ]: ( state, payload ) => + changePersistent( state, payload ), + + [ ACTION_TYPES.RESET ]: ( state ) => { + const cleanState = changeTransient( + changePersistent( state, defaultPersistent ), + defaultTransient + ); + + // Keep "read-only" details and initialization flags. + cleanState.isReady = true; + + return cleanState; + }, + + [ ACTION_TYPES.HYDRATE ]: ( state, payload ) => + changePersistent( state, payload.data ), +} ); + +export default reducer; diff --git a/modules/ppcp-settings/resources/js/data/pay-later-messaging/resolvers.js b/modules/ppcp-settings/resources/js/data/pay-later-messaging/resolvers.js new file mode 100644 index 000000000..39ff6c343 --- /dev/null +++ b/modules/ppcp-settings/resources/js/data/pay-later-messaging/resolvers.js @@ -0,0 +1,37 @@ +/** + * Resolvers: Handle asynchronous data fetching for the store. + * + * These functions update store state with data from external sources. + * Each resolver corresponds to a specific selector (selector with same name must exist). + * Resolvers are called automatically when selectors request unavailable data. + * + * @file + */ + +import { dispatch } from '@wordpress/data'; +import { __ } from '@wordpress/i18n'; +import { apiFetch } from '@wordpress/data-controls'; + +import { STORE_NAME, REST_HYDRATE_PATH } from './constants'; + +export const resolvers = { + /** + * Retrieve settings from the site's REST API. + */ + *persistentData() { + try { + const result = yield apiFetch( { path: REST_HYDRATE_PATH } ); + + yield dispatch( STORE_NAME ).hydrate( result ); + yield dispatch( STORE_NAME ).setIsReady( true ); + } catch ( e ) { + yield dispatch( 'core/notices' ).createErrorNotice( + // TODO: Add the module name to the error message. + __( + 'Error retrieving Pay Later Messaging config details.', + 'woocommerce-paypal-payments' + ) + ); + } + }, +}; diff --git a/modules/ppcp-settings/resources/js/data/pay-later-messaging/selectors.js b/modules/ppcp-settings/resources/js/data/pay-later-messaging/selectors.js new file mode 100644 index 000000000..14334fcf3 --- /dev/null +++ b/modules/ppcp-settings/resources/js/data/pay-later-messaging/selectors.js @@ -0,0 +1,21 @@ +/** + * Selectors: Extract specific pieces of state from the store. + * + * These functions provide a consistent interface for accessing store data. + * They allow components to retrieve data without knowing the store structure. + * + * @file + */ + +const EMPTY_OBJ = Object.freeze( {} ); + +const getState = ( state ) => state || EMPTY_OBJ; + +export const persistentData = ( state ) => { + return getState( state ).data || EMPTY_OBJ; +}; + +export const transientData = ( state ) => { + const { data, ...transientState } = getState( state ); + return transientState || EMPTY_OBJ; +}; diff --git a/modules/ppcp-settings/resources/js/hooks/useSaveSettings.js b/modules/ppcp-settings/resources/js/hooks/useSaveSettings.js index 61c130b81..aca1b7de1 100644 --- a/modules/ppcp-settings/resources/js/hooks/useSaveSettings.js +++ b/modules/ppcp-settings/resources/js/hooks/useSaveSettings.js @@ -2,6 +2,7 @@ import { useCallback } from '@wordpress/element'; import { CommonHooks, + PayLaterMessagingHooks, PaymentHooks, SettingsHooks, StylingHooks, @@ -15,8 +16,13 @@ export const useSaveSettings = () => { const { persist: persistSettings } = SettingsHooks.useStore(); const { persist: persistStyling } = StylingHooks.useStore(); const { persist: persistTodos } = TodosHooks.useStore(); + const { persist: persistPayLaterMessaging } = + PayLaterMessagingHooks.useStore(); const persistAll = useCallback( () => { + // Executes onSave on TabPayLaterMessaging component. + document.getElementById( 'configurator-publishButton' )?.click(); + withActivity( 'persist-methods', 'Save payment methods', @@ -33,11 +39,17 @@ export const useSaveSettings = () => { persistStyling ); withActivity( 'persist-todos', 'Save todos state', persistTodos ); + withActivity( + 'persist-pay-later-messaging', + 'Save pay later messaging details', + persistPayLaterMessaging + ); }, [ persistPayment, persistSettings, persistStyling, persistTodos, + persistPayLaterMessaging, withActivity, ] ); diff --git a/modules/ppcp-settings/resources/js/utils/countryPriceInfo.js b/modules/ppcp-settings/resources/js/utils/countryPriceInfo.js index c5cf52a3e..e32d8e6ce 100644 --- a/modules/ppcp-settings/resources/js/utils/countryPriceInfo.js +++ b/modules/ppcp-settings/resources/js/utils/countryPriceInfo.js @@ -2,139 +2,139 @@ export const countryPriceInfo = { US: { fixedFee: { USD: 0.49, - GBP: 0.39, - CAD: 0.59, - AUD: 0.59, - EUR: 0.39, + GBP: 0.39, + CAD: 0.59, + AUD: 0.59, + EUR: 0.39, }, checkout: 3.49, - plater: 4.99, - ccf: { - percentage: 2.59, - fixedFee: 0.29, - }, + plater: 4.99, + ccf: { + percentage: 2.59, + fixedFee: 0.29, + }, dw: { - percentage: 2.59, - fixedFee: 0.29, - }, + percentage: 2.59, + fixedFee: 0.29, + }, apm: { - percentage: 2.89, - fixedFee: 0.29, - }, - fast: { - percentage: 2.59, - fixedFee: 0.29, - }, + percentage: 2.89, + fixedFee: 0.29, + }, + fast: { + percentage: 2.59, + fixedFee: 0.29, + }, standardCardFields: 2.99, }, - UK: { + GB: { fixedFee: { GPB: 0.3, - USD: 0.3, - CAD: 0.3, - AUD: 0.3, - EUR: 0.35, + USD: 0.3, + CAD: 0.3, + AUD: 0.3, + EUR: 0.35, }, checkout: 2.9, - plater: 2.9, + plater: 2.9, ccf: 1.2, dw: 1.2, - fast: 1.2, + fast: 1.2, apm: 1.2, standardCardFields: 1.2, }, CA: { fixedFee: { CAD: 0.3, - USD: 0.3, - GBP: 0.2, - AUD: 0.3, - EUR: 0.35, + USD: 0.3, + GBP: 0.2, + AUD: 0.3, + EUR: 0.35, }, checkout: 2.9, ccf: 2.7, dw: 2.7, - fast: 2.7, + fast: 2.7, apm: 2.9, standardCardFields: 2.9, }, AU: { fixedFee: { AUD: 0.3, - USD: 0.3, - GBP: 0.2, - CAD: 0.3, - EUR: 0.35, + USD: 0.3, + GBP: 0.2, + CAD: 0.3, + EUR: 0.35, }, checkout: 2.6, - plater: 2.6, + plater: 2.6, ccf: 1.75, dw: 1.75, - fast: 1.75, + fast: 1.75, apm: 2.6, standardCardFields: 2.6, }, FR: { fixedFee: { EUR: 0.35, - USD: 0.3, - GBP: 0.3, - CAD: 0.3, - AUD: 0.3, + USD: 0.3, + GBP: 0.3, + CAD: 0.3, + AUD: 0.3, }, checkout: 2.9, - plater: 2.9, + plater: 2.9, ccf: 1.2, dw: 1.2, - fast: 1.2, + fast: 1.2, apm: 1.2, standardCardFields: 1.2, }, IT: { fixedFee: { - EUR: 0.35, - USD: 0.3, - GBP: 0.3, - CAD: 0.3, - AUD: 0.3, + EUR: 0.35, + USD: 0.3, + GBP: 0.3, + CAD: 0.3, + AUD: 0.3, }, checkout: 3.4, - plater: 3.4, + plater: 3.4, ccf: 1.2, dw: 1.2, - fast: 1.2, + fast: 1.2, apm: 1.2, standardCardFields: 1.2, }, DE: { fixedFee: { EUR: 0.39, - USD: 0.49, - GBP: 0.29, - CAD: 0.59, - AUD: 0.59, + USD: 0.49, + GBP: 0.29, + CAD: 0.59, + AUD: 0.59, }, checkout: 2.99, - plater: 2.99, + plater: 2.99, ccf: 2.99, dw: 2.99, - fast: 2.99, + fast: 2.99, apm: 2.99, standardCardFields: 2.99, }, ES: { fixedFee: { - EUR: 0.35, - USD: 0.3, - GBP: 0.3, - CAD: 0.3, - AUD: 0.3, + EUR: 0.35, + USD: 0.3, + GBP: 0.3, + CAD: 0.3, + AUD: 0.3, }, checkout: 2.9, - plater: 2.9, + plater: 2.9, ccf: 1.2, dw: 1.2, - fast: 1.2, + fast: 1.2, apm: 1.2, standardCardFields: 1.2, }, diff --git a/modules/ppcp-settings/services.php b/modules/ppcp-settings/services.php index 5a491a4e3..2857bb3db 100644 --- a/modules/ppcp-settings/services.php +++ b/modules/ppcp-settings/services.php @@ -22,6 +22,7 @@ use WooCommerce\PayPalCommerce\Settings\Endpoint\AuthenticationRestEndpoint; use WooCommerce\PayPalCommerce\Settings\Endpoint\CommonRestEndpoint; use WooCommerce\PayPalCommerce\Settings\Endpoint\LoginLinkRestEndpoint; use WooCommerce\PayPalCommerce\Settings\Endpoint\OnboardingRestEndpoint; +use WooCommerce\PayPalCommerce\Settings\Endpoint\PayLaterMessagingEndpoint; use WooCommerce\PayPalCommerce\Settings\Endpoint\PaymentRestEndpoint; use WooCommerce\PayPalCommerce\Settings\Endpoint\RefreshFeatureStatusEndpoint; use WooCommerce\PayPalCommerce\Settings\Endpoint\ResetDismissedTodosEndpoint; @@ -89,6 +90,15 @@ return array( $container->get( 'settings.service.sanitizer' ) ); }, + /** + * Checks if valid merchant connection details are stored in the DB. + */ + 'settings.flag.is-connected' => static function ( ContainerInterface $container ) : bool { + $data = $container->get( 'settings.data.general' ); + assert( $data instanceof GeneralSettings ); + + return $data->is_merchant_connected(); + }, 'settings.rest.onboarding' => static function ( ContainerInterface $container ) : OnboardingRestEndpoint { return new OnboardingRestEndpoint( $container->get( 'settings.data.onboarding' ) ); }, @@ -128,6 +138,12 @@ return array( $container->get( 'webhook.status.simulation' ) ); }, + 'settings.rest.pay_later_messaging' => static function ( ContainerInterface $container ) : PayLaterMessagingEndpoint { + return new PayLaterMessagingEndpoint( + $container->get( 'wcgateway.settings' ), + $container->get( 'paylater-configurator.endpoint.save-config' ) + ); + }, 'settings.rest.settings' => static function ( ContainerInterface $container ) : SettingsRestEndpoint { return new SettingsRestEndpoint( $container->get( 'settings.data.settings' ) diff --git a/modules/ppcp-settings/src/Endpoint/CommonRestEndpoint.php b/modules/ppcp-settings/src/Endpoint/CommonRestEndpoint.php index 35af6c093..e453a1a87 100644 --- a/modules/ppcp-settings/src/Endpoint/CommonRestEndpoint.php +++ b/modules/ppcp-settings/src/Endpoint/CommonRestEndpoint.php @@ -218,7 +218,7 @@ class CommonRestEndpoint extends RestEndpoint { if ( $this->settings->is_merchant_connected() ) { $extra_data['features'] = apply_filters( - 'woocommerce_paypal_payments_rest_common_merchant_data', + 'woocommerce_paypal_payments_rest_common_merchant_features', array(), ); } diff --git a/modules/ppcp-settings/src/Endpoint/PayLaterMessagingEndpoint.php b/modules/ppcp-settings/src/Endpoint/PayLaterMessagingEndpoint.php new file mode 100644 index 000000000..5713ce570 --- /dev/null +++ b/modules/ppcp-settings/src/Endpoint/PayLaterMessagingEndpoint.php @@ -0,0 +1,110 @@ +settings = $settings; + $this->save_config = $save_config; + } + + /** + * Configure REST API routes. + */ + public function register_routes() : void { + /** + * GET wc/v3/wc_paypal/pay_later_messaging + */ + register_rest_route( + $this->namespace, + '/' . $this->rest_base, + array( + 'methods' => WP_REST_Server::READABLE, + 'callback' => array( $this, 'get_details' ), + 'permission_callback' => array( $this, 'check_permission' ), + ) + ); + + /** + * POST wc/v3/wc_paypal/pay_later_messaging + */ + register_rest_route( + $this->namespace, + '/' . $this->rest_base, + array( + 'methods' => WP_REST_Server::EDITABLE, + 'callback' => array( $this, 'update_details' ), + 'permission_callback' => array( $this, 'check_permission' ), + ) + ); + } + + /** + * Returns Pay Later Messaging configuration details. + * + * @return WP_REST_Response The current payment methods details. + */ + public function get_details() : WP_REST_Response { + return $this->return_success( ( new ConfigFactory() )->from_settings( $this->settings ) ); + } + + /** + * Updates Pay Later Messaging configuration details based on the request. + * + * @param WP_REST_Request $request Full data about the request. + * + * @return WP_REST_Response The updated Pay Later Messaging configuration details. + */ + public function update_details( WP_REST_Request $request ) : WP_REST_Response { + $this->save_config->save_config( $request->get_json_params() ); + + return $this->get_details(); + } +} diff --git a/modules/ppcp-settings/src/SettingsModule.php b/modules/ppcp-settings/src/SettingsModule.php index d838dc595..3b1a435b0 100644 --- a/modules/ppcp-settings/src/SettingsModule.php +++ b/modules/ppcp-settings/src/SettingsModule.php @@ -239,6 +239,7 @@ class SettingsModule implements ServiceModule, ExecutableModule { 'styling' => $container->get( 'settings.rest.styling' ), 'todos' => $container->get( 'settings.rest.todos' ), 'reset_dismissed_todos' => $container->get( 'settings.rest.reset_dismissed_todos' ), + 'pay_later_messaging' => $container->get( 'settings.rest.pay_later_messaging' ), ); foreach ( $endpoints as $endpoint ) { @@ -300,7 +301,7 @@ class SettingsModule implements ServiceModule, ExecutableModule { assert( $dcc_applies instanceof DCCApplies ); // Unset BCDC if merchant is eligible for ACDC. - if ( $dcc_product_status->dcc_is_active() && ! $container->get( 'wcgateway.settings.allow_card_button_gateway' ) ) { + if ( $dcc_product_status->is_active() && ! $container->get( 'wcgateway.settings.allow_card_button_gateway' ) ) { unset( $payment_methods[ CardButtonGateway::ID ] ); } @@ -320,7 +321,7 @@ class SettingsModule implements ServiceModule, ExecutableModule { } // Unset Fastlane if store location is not United States or merchant is not eligible for ACDC. - if ( $container->get( 'api.shop.country' ) !== 'US' || ! $dcc_product_status->dcc_is_active() ) { + if ( $container->get( 'api.shop.country' ) !== 'US' || ! $dcc_product_status->is_active() ) { unset( $payment_methods['ppcp-axo-gateway'] ); } diff --git a/modules/ppcp-vaulting/src/VaultedCreditCardHandler.php b/modules/ppcp-vaulting/src/VaultedCreditCardHandler.php index 3261e4b8e..134d9f4e7 100644 --- a/modules/ppcp-vaulting/src/VaultedCreditCardHandler.php +++ b/modules/ppcp-vaulting/src/VaultedCreditCardHandler.php @@ -18,7 +18,7 @@ use WooCommerce\PayPalCommerce\ApiClient\Exception\RuntimeException; use WooCommerce\PayPalCommerce\ApiClient\Factory\PayerFactory; use WooCommerce\PayPalCommerce\ApiClient\Factory\PurchaseUnitFactory; use WooCommerce\PayPalCommerce\ApiClient\Factory\ShippingPreferenceFactory; -use WooCommerce\PayPalCommerce\Onboarding\Environment; +use WooCommerce\PayPalCommerce\WcGateway\Helper\Environment; use WooCommerce\PayPalCommerce\WcSubscriptions\FreeTrialHandlerTrait; use WooCommerce\PayPalCommerce\WcSubscriptions\Helper\SubscriptionHelper; use WooCommerce\PayPalCommerce\WcGateway\Processor\AuthorizedPaymentsProcessor; diff --git a/modules/ppcp-wc-gateway/extensions.php b/modules/ppcp-wc-gateway/extensions.php index fe2de006b..77fea0abd 100644 --- a/modules/ppcp-wc-gateway/extensions.php +++ b/modules/ppcp-wc-gateway/extensions.php @@ -9,7 +9,7 @@ declare(strict_types=1); namespace WooCommerce\PayPalCommerce\WcGateway; -use WooCommerce\PayPalCommerce\Onboarding\Environment; +use WooCommerce\PayPalCommerce\WcGateway\Helper\Environment; use WooCommerce\WooCommerce\Logging\Logger\NullLogger; use WooCommerce\WooCommerce\Logging\Logger\WooCommerceLogger; use WooCommerce\PayPalCommerce\Vendor\Psr\Container\ContainerInterface; diff --git a/modules/ppcp-wc-gateway/services.php b/modules/ppcp-wc-gateway/services.php index 1bac9b14e..77c6438e3 100644 --- a/modules/ppcp-wc-gateway/services.php +++ b/modules/ppcp-wc-gateway/services.php @@ -21,7 +21,7 @@ use WooCommerce\PayPalCommerce\Axo\Gateway\AxoGateway; use WooCommerce\PayPalCommerce\Button\Helper\MessagesDisclaimers; use WooCommerce\PayPalCommerce\Common\Pattern\SingletonDecorator; use WooCommerce\PayPalCommerce\Googlepay\GooglePayGateway; -use WooCommerce\PayPalCommerce\Onboarding\Environment; +use WooCommerce\PayPalCommerce\WcGateway\Helper\Environment; use WooCommerce\PayPalCommerce\Onboarding\Render\OnboardingOptionsRenderer; use WooCommerce\PayPalCommerce\Onboarding\State; use WooCommerce\PayPalCommerce\Settings\SettingsModule; @@ -570,10 +570,10 @@ return array( $settings = $container->get( 'wcgateway.settings' ); $fields = $container->get( 'wcgateway.settings.fields' ); $webhook_registrar = $container->get( 'webhook.registrar' ); - $state = $container->get( 'onboarding.state' ); - $cache = new Cache( 'ppcp-paypal-bearer' ); - $bearer = $container->get( 'api.bearer' ); - $page_id = $container->get( 'wcgateway.current-ppcp-settings-page-id' ); + $state = $container->get( 'onboarding.state' ); + $cache = $container->get( 'api.paypal-bearer-cache' ); + $bearer = $container->get( 'api.bearer' ); + $page_id = $container->get( 'wcgateway.current-ppcp-settings-page-id' ); $signup_link_cache = $container->get( 'onboarding.signup-link-cache' ); $signup_link_ids = $container->get( 'onboarding.signup-link-ids' ); $pui_status_cache = $container->get( 'pui.status-cache' ); @@ -1431,7 +1431,7 @@ return array( $partner_endpoint, $container->get( 'dcc.status-cache' ), $container->get( 'api.helpers.dccapplies' ), - $container->get( 'onboarding.state' ), + $container->get( 'settings.flag.is-connected' ), $container->get( 'api.helper.failure-registry' ) ); }, @@ -1515,7 +1515,7 @@ return array( $container->get( 'wcgateway.settings' ), $container->get( 'api.endpoint.partners' ), $container->get( 'pui.status-cache' ), - $container->get( 'onboarding.state' ), + $container->get( 'settings.flag.is-connected' ), $container->get( 'api.helper.failure-registry' ) ); }, @@ -1728,7 +1728,7 @@ return array( $environment = $container->get( 'onboarding.environment' ); assert( $environment instanceof Environment ); - $dcc_enabled = $dcc_product_status->dcc_is_active(); + $dcc_enabled = $dcc_product_status->is_active(); $enabled_status_text = esc_html__( 'Status: Available', 'woocommerce-paypal-payments' ); $disabled_status_text = esc_html__( 'Status: Not yet enabled', 'woocommerce-paypal-payments' ); @@ -1799,7 +1799,7 @@ return array( $environment = $container->get( 'onboarding.environment' ); assert( $environment instanceof Environment ); - $pui_enabled = $pui_product_status->pui_is_active(); + $pui_enabled = $pui_product_status->is_active(); $enabled_status_text = esc_html__( 'Status: Available', 'woocommerce-paypal-payments' ); $disabled_status_text = esc_html__( 'Status: Not yet enabled', 'woocommerce-paypal-payments' ); diff --git a/modules/ppcp-wc-gateway/src/Assets/FraudNetAssets.php b/modules/ppcp-wc-gateway/src/Assets/FraudNetAssets.php index 074a57c2e..3ee217887 100644 --- a/modules/ppcp-wc-gateway/src/Assets/FraudNetAssets.php +++ b/modules/ppcp-wc-gateway/src/Assets/FraudNetAssets.php @@ -10,7 +10,7 @@ declare(strict_types=1); namespace WooCommerce\PayPalCommerce\WcGateway\Assets; use WooCommerce\PayPalCommerce\Button\Helper\ContextTrait; -use WooCommerce\PayPalCommerce\Onboarding\Environment; +use WooCommerce\PayPalCommerce\WcGateway\Helper\Environment; use WooCommerce\PayPalCommerce\Session\SessionHandler; use WooCommerce\PayPalCommerce\WcGateway\Exception\NotFoundException; use WooCommerce\PayPalCommerce\WcGateway\FraudNet\FraudNet; diff --git a/modules/ppcp-wc-gateway/src/Assets/SettingsPageAssets.php b/modules/ppcp-wc-gateway/src/Assets/SettingsPageAssets.php index bfda515ac..4ab12b13b 100644 --- a/modules/ppcp-wc-gateway/src/Assets/SettingsPageAssets.php +++ b/modules/ppcp-wc-gateway/src/Assets/SettingsPageAssets.php @@ -11,7 +11,7 @@ namespace WooCommerce\PayPalCommerce\WcGateway\Assets; use WooCommerce\PayPalCommerce\ApiClient\Endpoint\BillingAgreementsEndpoint; use WooCommerce\PayPalCommerce\ApiClient\Helper\CurrencyGetter; -use WooCommerce\PayPalCommerce\Onboarding\Environment; +use WooCommerce\PayPalCommerce\WcGateway\Helper\Environment; use WooCommerce\PayPalCommerce\WcGateway\Endpoint\RefreshFeatureStatusEndpoint; use WooCommerce\PayPalCommerce\WcSubscriptions\Helper\SubscriptionHelper; diff --git a/modules/ppcp-wc-gateway/src/Gateway/CardButtonGateway.php b/modules/ppcp-wc-gateway/src/Gateway/CardButtonGateway.php index ffb0fe55c..846f8e7e3 100644 --- a/modules/ppcp-wc-gateway/src/Gateway/CardButtonGateway.php +++ b/modules/ppcp-wc-gateway/src/Gateway/CardButtonGateway.php @@ -13,8 +13,7 @@ use Exception; use Psr\Log\LoggerInterface; use WC_Order; use WooCommerce\PayPalCommerce\ApiClient\Exception\PayPalApiException; -use WooCommerce\PayPalCommerce\ApiClient\Exception\RuntimeException; -use WooCommerce\PayPalCommerce\Onboarding\Environment; +use WooCommerce\PayPalCommerce\WcGateway\Helper\Environment; use WooCommerce\PayPalCommerce\Onboarding\State; use WooCommerce\PayPalCommerce\Session\SessionHandler; use WooCommerce\PayPalCommerce\WcSubscriptions\FreeTrialHandlerTrait; diff --git a/modules/ppcp-wc-gateway/src/Gateway/CreditCardGateway.php b/modules/ppcp-wc-gateway/src/Gateway/CreditCardGateway.php index a5e897548..7a41a40ef 100644 --- a/modules/ppcp-wc-gateway/src/Gateway/CreditCardGateway.php +++ b/modules/ppcp-wc-gateway/src/Gateway/CreditCardGateway.php @@ -18,7 +18,7 @@ use WooCommerce\PayPalCommerce\ApiClient\Endpoint\PaymentsEndpoint; use WooCommerce\PayPalCommerce\ApiClient\Endpoint\PaymentTokensEndpoint; use WooCommerce\PayPalCommerce\ApiClient\Exception\PayPalApiException; use WooCommerce\PayPalCommerce\ApiClient\Exception\RuntimeException; -use WooCommerce\PayPalCommerce\Onboarding\Environment; +use WooCommerce\PayPalCommerce\WcGateway\Helper\Environment; use WooCommerce\PayPalCommerce\Onboarding\State; use WooCommerce\PayPalCommerce\Session\SessionHandler; use WooCommerce\PayPalCommerce\Vaulting\PaymentTokenRepository; diff --git a/modules/ppcp-wc-gateway/src/Gateway/OXXO/OXXOGateway.php b/modules/ppcp-wc-gateway/src/Gateway/OXXO/OXXOGateway.php index 009018558..dfc2d6a24 100644 --- a/modules/ppcp-wc-gateway/src/Gateway/OXXO/OXXOGateway.php +++ b/modules/ppcp-wc-gateway/src/Gateway/OXXO/OXXOGateway.php @@ -17,7 +17,7 @@ use WooCommerce\PayPalCommerce\ApiClient\Exception\PayPalApiException; use WooCommerce\PayPalCommerce\ApiClient\Exception\RuntimeException; use WooCommerce\PayPalCommerce\ApiClient\Factory\PurchaseUnitFactory; use WooCommerce\PayPalCommerce\ApiClient\Factory\ShippingPreferenceFactory; -use WooCommerce\PayPalCommerce\Onboarding\Environment; +use WooCommerce\PayPalCommerce\WcGateway\Helper\Environment; use WooCommerce\PayPalCommerce\WcGateway\Gateway\TransactionUrlProvider; use WooCommerce\PayPalCommerce\WcGateway\Processor\OrderMetaTrait; diff --git a/modules/ppcp-wc-gateway/src/Gateway/PayPalGateway.php b/modules/ppcp-wc-gateway/src/Gateway/PayPalGateway.php index 5ffbeec9d..192955d80 100644 --- a/modules/ppcp-wc-gateway/src/Gateway/PayPalGateway.php +++ b/modules/ppcp-wc-gateway/src/Gateway/PayPalGateway.php @@ -18,7 +18,7 @@ use WooCommerce\PayPalCommerce\ApiClient\Endpoint\PaymentTokensEndpoint; use WooCommerce\PayPalCommerce\ApiClient\Entity\OrderStatus; use WooCommerce\PayPalCommerce\ApiClient\Entity\PaymentToken; use WooCommerce\PayPalCommerce\ApiClient\Exception\PayPalApiException; -use WooCommerce\PayPalCommerce\Onboarding\Environment; +use WooCommerce\PayPalCommerce\WcGateway\Helper\Environment; use WooCommerce\PayPalCommerce\Onboarding\State; use WooCommerce\PayPalCommerce\Session\SessionHandler; use WooCommerce\PayPalCommerce\Vaulting\WooCommercePaymentTokens; diff --git a/modules/ppcp-wc-gateway/src/Gateway/PayUponInvoice/PayUponInvoice.php b/modules/ppcp-wc-gateway/src/Gateway/PayUponInvoice/PayUponInvoice.php index 94ed7240a..5b1fc0d36 100644 --- a/modules/ppcp-wc-gateway/src/Gateway/PayUponInvoice/PayUponInvoice.php +++ b/modules/ppcp-wc-gateway/src/Gateway/PayUponInvoice/PayUponInvoice.php @@ -445,7 +445,7 @@ class PayUponInvoice { } if ( - ! $this->pui_product_status->pui_is_active() + ! $this->pui_product_status->is_active() || ! $this->pui_helper->is_checkout_ready_for_pui() ) { unset( $methods[ PayUponInvoiceGateway::ID ] ); @@ -478,7 +478,7 @@ class PayUponInvoice { function() { if ( PayUponInvoiceGateway::ID === $this->current_ppcp_settings_page_id - && $this->pui_product_status->pui_is_active() + && $this->pui_product_status->is_active() ) { $error_messages = array(); $pui_gateway = WC()->payment_gateways->payment_gateways()[ PayUponInvoiceGateway::ID ]; diff --git a/modules/ppcp-wc-gateway/src/Gateway/PayUponInvoice/PayUponInvoiceGateway.php b/modules/ppcp-wc-gateway/src/Gateway/PayUponInvoice/PayUponInvoiceGateway.php index dbd6629bd..ecd6c1df1 100644 --- a/modules/ppcp-wc-gateway/src/Gateway/PayUponInvoice/PayUponInvoiceGateway.php +++ b/modules/ppcp-wc-gateway/src/Gateway/PayUponInvoice/PayUponInvoiceGateway.php @@ -16,7 +16,7 @@ use WC_Payment_Gateway; use WooCommerce\PayPalCommerce\ApiClient\Endpoint\PayUponInvoiceOrderEndpoint; use WooCommerce\PayPalCommerce\ApiClient\Exception\PayPalApiException; use WooCommerce\PayPalCommerce\ApiClient\Factory\PurchaseUnitFactory; -use WooCommerce\PayPalCommerce\Onboarding\Environment; +use WooCommerce\PayPalCommerce\WcGateway\Helper\Environment; use WooCommerce\PayPalCommerce\Onboarding\State; use WooCommerce\PayPalCommerce\WcGateway\Gateway\TransactionUrlProvider; use WooCommerce\PayPalCommerce\WcGateway\Helper\CheckoutHelper; diff --git a/modules/ppcp-wc-gateway/src/Helper/DCCProductStatus.php b/modules/ppcp-wc-gateway/src/Helper/DCCProductStatus.php index 3ca5b9998..d82271b60 100644 --- a/modules/ppcp-wc-gateway/src/Helper/DCCProductStatus.php +++ b/modules/ppcp-wc-gateway/src/Helper/DCCProductStatus.php @@ -9,86 +9,55 @@ declare( strict_types=1 ); namespace WooCommerce\PayPalCommerce\WcGateway\Helper; -use Throwable; use WooCommerce\PayPalCommerce\ApiClient\Endpoint\PartnersEndpoint; use WooCommerce\PayPalCommerce\ApiClient\Entity\SellerStatusProduct; use WooCommerce\PayPalCommerce\ApiClient\Helper\Cache; use WooCommerce\PayPalCommerce\ApiClient\Helper\DccApplies; use WooCommerce\PayPalCommerce\ApiClient\Helper\FailureRegistry; -use WooCommerce\PayPalCommerce\Onboarding\State; use WooCommerce\PayPalCommerce\WcGateway\Settings\Settings; +use WooCommerce\PayPalCommerce\ApiClient\Helper\ProductStatus; +use WooCommerce\PayPalCommerce\ApiClient\Entity\SellerStatus; /** * Class DccProductStatus */ -class DCCProductStatus { +class DCCProductStatus extends ProductStatus { + public const SETTINGS_KEY = 'products_dcc_enabled'; + public const DCC_STATUS_CACHE_KEY = 'dcc_status_cache'; - const DCC_STATUS_CACHE_KEY = 'dcc_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; - - /** - * Caches the status for the current load. - * - * @var bool|null - */ - private $current_status_cache; - - /** - * If there was a request failure. - * - * @var bool - */ - private $has_request_failure = false; + protected Cache $cache; /** * The settings. * * @var Settings */ - private $settings; - - /** - * The partners endpoint. - * - * @var PartnersEndpoint - */ - private $partners_endpoint; + private Settings $settings; /** * The dcc applies helper. * * @var DccApplies */ - protected $dcc_applies; - - /** - * The onboarding state. - * - * @var State - */ - private $onboarding_state; - - /** - * The API failure registry - * - * @var FailureRegistry - */ - private $api_failure_registry; + protected DccApplies $dcc_applies; /** * DccProductStatus constructor. * - * @param Settings $settings The Settings. - * @param PartnersEndpoint $partners_endpoint The Partner Endpoint. - * @param Cache $cache The cache. - * @param DccApplies $dcc_applies The dcc applies helper. - * @param State $onboarding_state The onboarding state. + * @param Settings $settings The Settings. + * @param PartnersEndpoint $partners_endpoint The Partner Endpoint. + * @param Cache $cache The cache. + * @param DccApplies $dcc_applies The dcc applies helper. + * @param bool $is_connected The onboarding state. * @param FailureRegistry $api_failure_registry The API failure registry. */ public function __construct( @@ -96,55 +65,31 @@ class DCCProductStatus { PartnersEndpoint $partners_endpoint, Cache $cache, DccApplies $dcc_applies, - State $onboarding_state, + bool $is_connected, FailureRegistry $api_failure_registry ) { - $this->settings = $settings; - $this->partners_endpoint = $partners_endpoint; - $this->cache = $cache; - $this->dcc_applies = $dcc_applies; - $this->onboarding_state = $onboarding_state; - $this->api_failure_registry = $api_failure_registry; + parent::__construct( $is_connected, $partners_endpoint, $api_failure_registry ); + + $this->settings = $settings; + $this->cache = $cache; + $this->dcc_applies = $dcc_applies; } - /** - * Whether the active/subscribed products support DCC. - * - * @return bool - */ - public function dcc_is_active() : bool { - if ( $this->onboarding_state->current_state() < State::STATE_ONBOARDED ) { - return false; - } - + /** {@inheritDoc} */ + protected function check_local_state() : ?bool { if ( $this->cache->has( self::DCC_STATUS_CACHE_KEY ) ) { - return $this->cache->get( self::DCC_STATUS_CACHE_KEY ) === 'true'; + return wc_string_to_bool( $this->cache->get( self::DCC_STATUS_CACHE_KEY ) ); } - if ( $this->current_status_cache === true ) { - return $this->current_status_cache; + if ( $this->settings->has( self::SETTINGS_KEY ) && ( $this->settings->get( self::SETTINGS_KEY ) ) ) { + return wc_string_to_bool( $this->settings->get( self::SETTINGS_KEY ) ); } - if ( $this->settings->has( 'products_dcc_enabled' ) && $this->settings->get( 'products_dcc_enabled' ) === true ) { - $this->current_status_cache = true; - return true; - } - - // Check API failure registry to prevent multiple failed API requests. - if ( $this->api_failure_registry->has_failure_in_timeframe( FailureRegistry::SELLER_STATUS_KEY, HOUR_IN_SECONDS ) ) { - $this->has_request_failure = true; - $this->current_status_cache = false; - return $this->current_status_cache; - } - - try { - $seller_status = $this->partners_endpoint->seller_status(); - } catch ( Throwable $error ) { - $this->has_request_failure = true; - $this->current_status_cache = false; - return false; - } + return null; + } + /** {@inheritDoc} */ + protected function check_active_state( SellerStatus $seller_status ) : bool { foreach ( $seller_status->products() as $product ) { if ( ! in_array( $product->vetting_status(), @@ -159,57 +104,37 @@ class DCCProductStatus { } if ( in_array( 'CUSTOM_CARD_PROCESSING', $product->capabilities(), true ) ) { - $this->settings->set( 'products_dcc_enabled', true ); + $this->settings->set( self::SETTINGS_KEY, self::SETTINGS_VALUE_ENABLED ); $this->settings->persist(); - $this->current_status_cache = true; - $this->cache->set( self::DCC_STATUS_CACHE_KEY, 'true', MONTH_IN_SECONDS ); + + $this->cache->set( self::DCC_STATUS_CACHE_KEY, self::SETTINGS_VALUE_ENABLED, MONTH_IN_SECONDS ); + return true; } } - $expiration = MONTH_IN_SECONDS; if ( $this->dcc_applies->for_country_currency() ) { $expiration = 3 * HOUR_IN_SECONDS; + } else { + $expiration = MONTH_IN_SECONDS; } - $this->cache->set( self::DCC_STATUS_CACHE_KEY, 'false', $expiration ); - $this->current_status_cache = false; + $this->cache->set( self::DCC_STATUS_CACHE_KEY, self::SETTINGS_VALUE_DISABLED, $expiration ); + return false; } - /** - * Returns if there was a request failure. - * - * @return bool - */ - public function has_request_failure(): bool { - return $this->has_request_failure; - } - - /** - * Clears the persisted result to force a recheck. - * - * @param Settings|null $settings The settings object. - * We accept a Settings object to don't override other sequential settings that are being updated elsewhere. - * @return void - */ - public function clear( Settings $settings = null ): void { + /** {@inheritDoc} */ + protected function clear_state( Settings $settings = null ): void { if ( null === $settings ) { $settings = $this->settings; } - // Unset check stored in memory. - $this->current_status_cache = null; - - // Unset settings flag. - $settings_key = 'products_dcc_enabled'; - if ( $settings->has( $settings_key ) ) { - $settings->set( $settings_key, false ); + if ( $settings->has( self::SETTINGS_KEY ) ) { + $settings->set( self::SETTINGS_KEY, self::SETTINGS_VALUE_UNDEFINED ); $settings->persist(); } - // Delete cached value. $this->cache->delete( self::DCC_STATUS_CACHE_KEY ); } - } diff --git a/modules/ppcp-wc-gateway/src/Helper/Environment.php b/modules/ppcp-wc-gateway/src/Helper/Environment.php new file mode 100644 index 000000000..143ebd843 --- /dev/null +++ b/modules/ppcp-wc-gateway/src/Helper/Environment.php @@ -0,0 +1,87 @@ +settings = $settings; + } + + /** + * Returns the current environment. + * + * @return string + */ + public function current_environment() : string { + return ( + $this->settings->has( 'sandbox_on' ) && $this->settings->get( 'sandbox_on' ) + ) ? self::SANDBOX : self::PRODUCTION; + } + + /** + * Detect whether the current environment equals $environment + * + * @deprecated Use the is_sandbox() and is_production() methods instead. + * These methods provide better encapsulation, are less error-prone, + * and improve code readability by removing the need to pass environment constants. + * @param string $environment The value to check against. + * + * @return bool + */ + public function current_environment_is( string $environment ) : bool { + return $this->current_environment() === $environment; + } + + /** + * Returns whether the current environment is sandbox. + * + * @return bool + */ + public function is_sandbox() : bool { + return $this->current_environment() === self::SANDBOX; + } + + /** + * Returns whether the current environment is production. + * + * @return bool + */ + public function is_production() : bool { + return $this->current_environment() === self::PRODUCTION; + } +} diff --git a/modules/ppcp-wc-gateway/src/Helper/EnvironmentConfig.php b/modules/ppcp-wc-gateway/src/Helper/EnvironmentConfig.php index 1542de783..c05776603 100644 --- a/modules/ppcp-wc-gateway/src/Helper/EnvironmentConfig.php +++ b/modules/ppcp-wc-gateway/src/Helper/EnvironmentConfig.php @@ -70,10 +70,14 @@ class EnvironmentConfig { /** * Get the value for the specified environment. * - * @param bool $for_sandbox Whether to get the sandbox value. + * @param bool|Environment $for_sandbox Whether to get the sandbox value. * @return T The value for the specified environment. */ - public function get_value( bool $for_sandbox = false ) { + public function get_value( $for_sandbox = false ) { + if ( $for_sandbox instanceof Environment ) { + return $for_sandbox->is_sandbox() ? $this->sandbox_value : $this->production_value; + } + return $for_sandbox ? $this->sandbox_value : $this->production_value; } } diff --git a/modules/ppcp-wc-gateway/src/Helper/PayUponInvoiceProductStatus.php b/modules/ppcp-wc-gateway/src/Helper/PayUponInvoiceProductStatus.php index dfbcb0380..250138089 100644 --- a/modules/ppcp-wc-gateway/src/Helper/PayUponInvoiceProductStatus.php +++ b/modules/ppcp-wc-gateway/src/Helper/PayUponInvoiceProductStatus.php @@ -9,130 +9,76 @@ declare( strict_types=1 ); namespace WooCommerce\PayPalCommerce\WcGateway\Helper; -use Throwable; 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\Onboarding\State; use WooCommerce\PayPalCommerce\WcGateway\Settings\Settings; +use WooCommerce\PayPalCommerce\ApiClient\Helper\ProductStatus; +use WooCommerce\PayPalCommerce\ApiClient\Entity\SellerStatus; /** * Class PayUponInvoiceProductStatus */ -class PayUponInvoiceProductStatus { +class PayUponInvoiceProductStatus extends ProductStatus { + public const SETTINGS_KEY = 'products_pui_enabled'; + public const PUI_STATUS_CACHE_KEY = 'pui_status_cache'; - const PUI_STATUS_CACHE_KEY = 'pui_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; - - /** - * Caches the status for the current load. - * - * @var bool|null - */ - private $current_status_cache; - - /** - * If there was a request failure. - * - * @var bool - */ - private $has_request_failure = false; + protected Cache $cache; /** * The settings. * * @var Settings */ - private $settings; - - /** - * The partners endpoint. - * - * @var PartnersEndpoint - */ - private $partners_endpoint; - - /** - * The onboarding status - * - * @var State - */ - private $onboarding_state; - - /** - * The API failure registry - * - * @var FailureRegistry - */ - private $api_failure_registry; + private Settings $settings; /** * PayUponInvoiceProductStatus constructor. * - * @param Settings $settings The Settings. - * @param PartnersEndpoint $partners_endpoint The Partner Endpoint. - * @param Cache $cache The cache. - * @param State $onboarding_state The onboarding state. + * @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, - State $onboarding_state, + bool $is_connected, FailureRegistry $api_failure_registry ) { - $this->settings = $settings; - $this->partners_endpoint = $partners_endpoint; - $this->cache = $cache; - $this->onboarding_state = $onboarding_state; - $this->api_failure_registry = $api_failure_registry; + parent::__construct( $is_connected, $partners_endpoint, $api_failure_registry ); + + $this->settings = $settings; + $this->cache = $cache; } - /** - * Whether the active/subscribed products support PUI. - * - * @return bool - */ - public function pui_is_active() : bool { - if ( $this->onboarding_state->current_state() < State::STATE_ONBOARDED ) { - return false; - } - + /** {@inheritDoc} */ + protected function check_local_state() : ?bool { if ( $this->cache->has( self::PUI_STATUS_CACHE_KEY ) ) { - return $this->cache->get( self::PUI_STATUS_CACHE_KEY ) === 'true'; + return wc_string_to_bool( $this->cache->get( self::PUI_STATUS_CACHE_KEY ) ); } - if ( $this->current_status_cache === true ) { - return $this->current_status_cache; - } - if ( $this->settings->has( 'products_pui_enabled' ) && $this->settings->get( 'products_pui_enabled' ) === true ) { - $this->current_status_cache = true; - return true; + if ( $this->settings->has( self::SETTINGS_KEY ) && ( $this->settings->get( self::SETTINGS_KEY ) ) ) { + return wc_string_to_bool( $this->settings->get( self::SETTINGS_KEY ) ); } - // Check API failure registry to prevent multiple failed API requests. - if ( $this->api_failure_registry->has_failure_in_timeframe( FailureRegistry::SELLER_STATUS_KEY, HOUR_IN_SECONDS ) ) { - $this->has_request_failure = true; - $this->current_status_cache = false; - return $this->current_status_cache; - } - - try { - $seller_status = $this->partners_endpoint->seller_status(); - } catch ( Throwable $error ) { - $this->has_request_failure = true; - $this->current_status_cache = false; - return false; - } + return null; + } + /** {@inheritDoc} */ + protected function check_active_state( SellerStatus $seller_status ) : bool { foreach ( $seller_status->products() as $product ) { if ( $product->name() !== 'PAYMENT_METHODS' ) { continue; @@ -151,52 +97,29 @@ class PayUponInvoiceProductStatus { } if ( in_array( 'PAY_UPON_INVOICE', $product->capabilities(), true ) ) { - $this->settings->set( 'products_pui_enabled', true ); + $this->settings->set( self::SETTINGS_KEY, self::SETTINGS_VALUE_ENABLED ); $this->settings->persist(); - $this->current_status_cache = true; - $this->cache->set( self::PUI_STATUS_CACHE_KEY, 'true', MONTH_IN_SECONDS ); + $this->cache->set( self::PUI_STATUS_CACHE_KEY, self::SETTINGS_VALUE_ENABLED, MONTH_IN_SECONDS ); return true; } } - $this->cache->set( self::PUI_STATUS_CACHE_KEY, 'false', MONTH_IN_SECONDS ); - $this->current_status_cache = false; + $this->cache->set( self::PUI_STATUS_CACHE_KEY, self::SETTINGS_VALUE_DISABLED, MONTH_IN_SECONDS ); + return false; } - /** - * Returns if there was a request failure. - * - * @return bool - */ - public function has_request_failure(): bool { - return $this->has_request_failure; - } - - /** - * Clears the persisted result to force a recheck. - * - * @param Settings|null $settings The settings object. - * We accept a Settings object to don't override other sequential settings that are being updated elsewhere. - * @return void - */ - public function clear( Settings $settings = null ): void { + /** {@inheritDoc} */ + protected function clear_state( Settings $settings = null ) : void { if ( null === $settings ) { $settings = $this->settings; } - // Unset check stored in memory. - $this->current_status_cache = null; - - // Unset settings flag. - $settings_key = 'products_pui_enabled'; - if ( $settings->has( $settings_key ) ) { - $settings->set( $settings_key, false ); + if ( $settings->has( self::SETTINGS_KEY ) ) { + $settings->set( self::SETTINGS_KEY, self::SETTINGS_VALUE_UNDEFINED ); $settings->persist(); } - // Delete cached value. $this->cache->delete( self::PUI_STATUS_CACHE_KEY ); } - } diff --git a/modules/ppcp-wc-gateway/src/Processor/OrderMetaTrait.php b/modules/ppcp-wc-gateway/src/Processor/OrderMetaTrait.php index 62a80456a..35b90bf47 100644 --- a/modules/ppcp-wc-gateway/src/Processor/OrderMetaTrait.php +++ b/modules/ppcp-wc-gateway/src/Processor/OrderMetaTrait.php @@ -12,7 +12,7 @@ namespace WooCommerce\PayPalCommerce\WcGateway\Processor; use WC_Order; use WooCommerce\PayPalCommerce\ApiClient\Entity\Order; use WooCommerce\PayPalCommerce\ApiClient\Helper\OrderTransient; -use WooCommerce\PayPalCommerce\Onboarding\Environment; +use WooCommerce\PayPalCommerce\WcGateway\Helper\Environment; use WooCommerce\PayPalCommerce\WcGateway\Gateway\PayPalGateway; /** diff --git a/modules/ppcp-wc-gateway/src/Processor/OrderProcessor.php b/modules/ppcp-wc-gateway/src/Processor/OrderProcessor.php index 82183e0d4..a64c0314f 100644 --- a/modules/ppcp-wc-gateway/src/Processor/OrderProcessor.php +++ b/modules/ppcp-wc-gateway/src/Processor/OrderProcessor.php @@ -24,7 +24,7 @@ use WooCommerce\PayPalCommerce\ApiClient\Factory\PurchaseUnitFactory; use WooCommerce\PayPalCommerce\ApiClient\Factory\ShippingPreferenceFactory; use WooCommerce\PayPalCommerce\ApiClient\Helper\OrderHelper; use WooCommerce\PayPalCommerce\Button\Helper\ThreeDSecure; -use WooCommerce\PayPalCommerce\Onboarding\Environment; +use WooCommerce\PayPalCommerce\WcGateway\Helper\Environment; use WooCommerce\PayPalCommerce\Session\SessionHandler; use WooCommerce\PayPalCommerce\WcSubscriptions\Helper\SubscriptionHelper; use WooCommerce\PayPalCommerce\Vaulting\PaymentTokenRepository; diff --git a/modules/ppcp-wc-gateway/src/Settings/Fields/connection-tab-fields.php b/modules/ppcp-wc-gateway/src/Settings/Fields/connection-tab-fields.php index 710246d9f..409fde543 100644 --- a/modules/ppcp-wc-gateway/src/Settings/Fields/connection-tab-fields.php +++ b/modules/ppcp-wc-gateway/src/Settings/Fields/connection-tab-fields.php @@ -15,7 +15,7 @@ use WooCommerce\PayPalCommerce\ApiClient\Helper\PurchaseUnitSanitizer; use WooCommerce\PayPalCommerce\Onboarding\Render\OnboardingOptionsRenderer; use WooCommerce\PayPalCommerce\Vendor\Psr\Container\ContainerInterface; use WooCommerce\PayPalCommerce\ApiClient\Helper\DccApplies; -use WooCommerce\PayPalCommerce\Onboarding\Environment; +use WooCommerce\PayPalCommerce\WcGateway\Helper\Environment; use WooCommerce\PayPalCommerce\Onboarding\Render\OnboardingSendOnlyNoticeRenderer; use WooCommerce\PayPalCommerce\Onboarding\State; use WooCommerce\PayPalCommerce\WcGateway\Helper\DisplayManager; diff --git a/modules/ppcp-wc-gateway/src/Settings/SectionsRenderer.php b/modules/ppcp-wc-gateway/src/Settings/SectionsRenderer.php index bc61c64a9..f8f05f4ff 100644 --- a/modules/ppcp-wc-gateway/src/Settings/SectionsRenderer.php +++ b/modules/ppcp-wc-gateway/src/Settings/SectionsRenderer.php @@ -168,7 +168,7 @@ class SectionsRenderer { } } - if ( ! $this->dcc_product_status->dcc_is_active() || ! $this->dcc_applies->for_country_currency() ) { + if ( ! $this->dcc_product_status->is_active() || ! $this->dcc_applies->for_country_currency() ) { unset( $sections['ppcp-credit-card-gateway'] ); } @@ -176,7 +176,7 @@ class SectionsRenderer { unset( $sections[ Settings::PAY_LATER_TAB_ID ] ); } - if ( ! $this->pui_product_status->pui_is_active() ) { + if ( ! $this->pui_product_status->is_active() ) { unset( $sections[ PayUponInvoiceGateway::ID ] ); } diff --git a/modules/ppcp-wc-gateway/src/Settings/SettingsRenderer.php b/modules/ppcp-wc-gateway/src/Settings/SettingsRenderer.php index ccf91d019..e32cbf0c4 100644 --- a/modules/ppcp-wc-gateway/src/Settings/SettingsRenderer.php +++ b/modules/ppcp-wc-gateway/src/Settings/SettingsRenderer.php @@ -465,7 +465,7 @@ $data_rows_html if ( $this->dcc_applies->for_country_currency() ) { if ( State::STATE_ONBOARDED > $this->state->current_state() ) { $this->render_dcc_onboarding_info(); - } elseif ( ! $this->dcc_product_status->dcc_is_active() ) { + } elseif ( ! $this->dcc_product_status->is_active() ) { $this->render_dcc_not_active_yet(); } } else { diff --git a/modules/ppcp-wc-gateway/src/WCGatewayModule.php b/modules/ppcp-wc-gateway/src/WCGatewayModule.php index da8bf00cb..f8b54f534 100644 --- a/modules/ppcp-wc-gateway/src/WCGatewayModule.php +++ b/modules/ppcp-wc-gateway/src/WCGatewayModule.php @@ -63,6 +63,7 @@ use WooCommerce\PayPalCommerce\Vendor\Interop\Container\ServiceProviderInterface use WooCommerce\PayPalCommerce\Vendor\Psr\Container\ContainerInterface; use WooCommerce\PayPalCommerce\WcGateway\Settings\WcTasks\Registrar\TaskRegistrarInterface; use WooCommerce\PayPalCommerce\WcGateway\Helper\DCCGatewayConfiguration; +use WooCommerce\PayPalCommerce\LocalAlternativePaymentMethods\LocalApmProductStatus; /** * Class WcGatewayModule @@ -341,11 +342,11 @@ class WCGatewayModule implements ServiceModule, ExtendingModule, ExecutableModul // Update caches. $dcc_status = $c->get( 'wcgateway.helper.dcc-product-status' ); assert( $dcc_status instanceof DCCProductStatus ); - $dcc_status->dcc_is_active(); + $dcc_status->is_active(); $pui_status = $c->get( 'wcgateway.pay-upon-invoice-product-status' ); assert( $pui_status instanceof PayUponInvoiceProductStatus ); - $pui_status->pui_is_active(); + $pui_status->is_active(); } ); @@ -550,43 +551,37 @@ class WCGatewayModule implements ServiceModule, ExtendingModule, ExecutableModul ); add_filter( - 'woocommerce_paypal_payments_rest_common_merchant_data', - function( array $features ) use ( $c ): array { + 'woocommerce_paypal_payments_rest_common_merchant_features', + static function ( array $features ) use ( $c ) : array { + $is_connected = $c->get( 'settings.flag.is-connected' ); + + if ( ! $is_connected ) { + return $features; + } + $billing_agreements_endpoint = $c->get( 'api.endpoint.billing-agreements' ); assert( $billing_agreements_endpoint instanceof BillingAgreementsEndpoint ); - $reference_transactions_enabled = $billing_agreements_endpoint->reference_transaction_enabled(); - $features['save_paypal_and_venmo'] = array( - 'enabled' => $reference_transactions_enabled, - ); - $dcc_product_status = $c->get( 'wcgateway.helper.dcc-product-status' ); assert( $dcc_product_status instanceof DCCProductStatus ); - $dcc_enabled = $dcc_product_status->dcc_is_active(); - $features['advanced_credit_and_debit_cards'] = array( - 'enabled' => $dcc_enabled, + $apms_product_status = $c->get( 'ppcp-local-apms.product-status' ); + assert( $apms_product_status instanceof LocalApmProductStatus ); + + $features['save_paypal_and_venmo'] = array( + 'enabled' => $billing_agreements_endpoint->reference_transaction_enabled(), ); - $partners_endpoint = $c->get( 'api.endpoint.partners' ); - assert( $partners_endpoint instanceof PartnersEndpoint ); - $seller_status = $partners_endpoint->seller_status(); - - $apms_enabled = false; - foreach ( $seller_status->products() as $product ) { - if ( $product->name() === 'PAYMENT_METHODS' ) { - $apms_enabled = true; - break; - } - } + $features['advanced_credit_and_debit_cards'] = array( + 'enabled' => $dcc_product_status->is_active(), + ); $features['alternative_payment_methods'] = array( - 'enabled' => $apms_enabled, + 'enabled' => $apms_product_status->is_active(), ); - $features['pay_later_messaging'] = array( - 'enabled' => true, - ); + // When local APMs are available, then PayLater messaging is also available. + $features['pay_later_messaging'] = $features['alternative_payment_methods']; return $features; } @@ -646,7 +641,7 @@ class WCGatewayModule implements ServiceModule, ExtendingModule, ExecutableModul // Performing the full DCCProductStatus check only when on the gateway list page // to avoid sending the API requests all the time. ( $is_our_page || - ( $is_gateways_list_page && $dcc_product_status->dcc_is_active() ) || + ( $is_gateways_list_page && $dcc_product_status->is_active() ) || ( $settings->has( 'products_dcc_enabled' ) && $settings->get( 'products_dcc_enabled' ) ) ) ) { @@ -664,7 +659,7 @@ class WCGatewayModule implements ServiceModule, ExtendingModule, ExecutableModul if ( 'DE' === $shop_country && ( $is_our_page || - ( $is_gateways_list_page && $pui_product_status->pui_is_active() ) || + ( $is_gateways_list_page && $pui_product_status->is_active() ) || ( $settings->has( 'products_pui_enabled' ) && $settings->get( 'products_pui_enabled' ) ) ) ) { diff --git a/modules/ppcp-wc-subscriptions/src/RenewalHandler.php b/modules/ppcp-wc-subscriptions/src/RenewalHandler.php index e82491904..f0900881d 100644 --- a/modules/ppcp-wc-subscriptions/src/RenewalHandler.php +++ b/modules/ppcp-wc-subscriptions/src/RenewalHandler.php @@ -23,7 +23,7 @@ use WooCommerce\PayPalCommerce\ApiClient\Exception\PayPalApiException; use WooCommerce\PayPalCommerce\ApiClient\Factory\PayerFactory; use WooCommerce\PayPalCommerce\ApiClient\Factory\PurchaseUnitFactory; use WooCommerce\PayPalCommerce\ApiClient\Factory\ShippingPreferenceFactory; -use WooCommerce\PayPalCommerce\Onboarding\Environment; +use WooCommerce\PayPalCommerce\WcGateway\Helper\Environment; use WooCommerce\PayPalCommerce\Vaulting\PaymentTokenApplePay; use WooCommerce\PayPalCommerce\Vaulting\PaymentTokenPayPal; use WooCommerce\PayPalCommerce\Vaulting\PaymentTokenRepository; diff --git a/modules/ppcp-webhooks/src/Status/Assets/WebhooksStatusPageAssets.php b/modules/ppcp-webhooks/src/Status/Assets/WebhooksStatusPageAssets.php index 475c2a85e..81aedd86c 100644 --- a/modules/ppcp-webhooks/src/Status/Assets/WebhooksStatusPageAssets.php +++ b/modules/ppcp-webhooks/src/Status/Assets/WebhooksStatusPageAssets.php @@ -9,7 +9,7 @@ declare(strict_types=1); namespace WooCommerce\PayPalCommerce\Webhooks\Status\Assets; -use WooCommerce\PayPalCommerce\Onboarding\Environment; +use WooCommerce\PayPalCommerce\WcGateway\Helper\Environment; use WooCommerce\PayPalCommerce\Webhooks\Endpoint\ResubscribeEndpoint; use WooCommerce\PayPalCommerce\Webhooks\Endpoint\SimulateEndpoint; use WooCommerce\PayPalCommerce\Webhooks\Endpoint\SimulationStateEndpoint; diff --git a/tests/PHPUnit/ApiClient/Entity/PayerTest.php b/tests/PHPUnit/ApiClient/Entity/PayerTest.php index affdc206d..9efc603d5 100644 --- a/tests/PHPUnit/ApiClient/Entity/PayerTest.php +++ b/tests/PHPUnit/ApiClient/Entity/PayerTest.php @@ -18,7 +18,7 @@ class PayerTest extends TestCase ->andReturn(['address']); $address ->expects('country_code') - ->andReturn('UK'); + ->andReturn('GB'); $phone = Mockery::mock(PhoneWithType::class); $phone ->expects('to_array') @@ -70,7 +70,7 @@ class PayerTest extends TestCase ->andReturn(['address']); $address ->expects('country_code') - ->andReturn('UK'); + ->andReturn('GB'); $phone = Mockery::mock(PhoneWithType::class); $phone ->expects('to_array') @@ -110,7 +110,7 @@ class PayerTest extends TestCase ->andReturn(['address']); $address ->expects('country_code') - ->andReturn('UK'); + ->andReturn('GB'); $phone = null; $taxInfo = Mockery::mock(PayerTaxInfo::class); $taxInfo @@ -147,7 +147,7 @@ class PayerTest extends TestCase ->andReturn(['address']); $address ->expects('country_code') - ->andReturn('UK'); + ->andReturn('GB'); $phone = Mockery::mock(PhoneWithType::class); $phone ->expects('to_array') @@ -184,7 +184,7 @@ class PayerTest extends TestCase ->andReturn(['address']); $address ->expects('country_code') - ->andReturn('UK'); + ->andReturn('GB'); $phone = Mockery::mock(PhoneWithType::class); $phone ->expects('to_array') diff --git a/tests/PHPUnit/Vaulting/VaultedCreditCardHandlerTest.php b/tests/PHPUnit/Vaulting/VaultedCreditCardHandlerTest.php index c7d176c8e..c084559a4 100644 --- a/tests/PHPUnit/Vaulting/VaultedCreditCardHandlerTest.php +++ b/tests/PHPUnit/Vaulting/VaultedCreditCardHandlerTest.php @@ -19,7 +19,7 @@ use WooCommerce\PayPalCommerce\ApiClient\Entity\PurchaseUnit; use WooCommerce\PayPalCommerce\ApiClient\Factory\PayerFactory; use WooCommerce\PayPalCommerce\ApiClient\Factory\PurchaseUnitFactory; use WooCommerce\PayPalCommerce\ApiClient\Factory\ShippingPreferenceFactory; -use WooCommerce\PayPalCommerce\Onboarding\Environment; +use WooCommerce\PayPalCommerce\WcGateway\Helper\Environment; use WooCommerce\PayPalCommerce\WcSubscriptions\Helper\SubscriptionHelper; use WooCommerce\PayPalCommerce\TestCase; use WooCommerce\PayPalCommerce\Vaulting\PaymentTokenRepository; diff --git a/tests/PHPUnit/WcGateway/Gateway/CreditCardGatewayTest.php b/tests/PHPUnit/WcGateway/Gateway/CreditCardGatewayTest.php index 1489da4ff..72b90e030 100644 --- a/tests/PHPUnit/WcGateway/Gateway/CreditCardGatewayTest.php +++ b/tests/PHPUnit/WcGateway/Gateway/CreditCardGatewayTest.php @@ -9,7 +9,7 @@ use WC_Order; use WooCommerce\PayPalCommerce\ApiClient\Endpoint\OrderEndpoint; use WooCommerce\PayPalCommerce\ApiClient\Endpoint\PaymentsEndpoint; use WooCommerce\PayPalCommerce\ApiClient\Endpoint\PaymentTokensEndpoint; -use WooCommerce\PayPalCommerce\Onboarding\Environment; +use WooCommerce\PayPalCommerce\WcGateway\Helper\Environment; use WooCommerce\PayPalCommerce\Onboarding\State; use WooCommerce\PayPalCommerce\Session\SessionHandler; use WooCommerce\PayPalCommerce\TestCase; diff --git a/tests/PHPUnit/WcGateway/Gateway/OXXO/OXXOGatewayTest.php b/tests/PHPUnit/WcGateway/Gateway/OXXO/OXXOGatewayTest.php index 0f70f801c..30e106152 100644 --- a/tests/PHPUnit/WcGateway/Gateway/OXXO/OXXOGatewayTest.php +++ b/tests/PHPUnit/WcGateway/Gateway/OXXO/OXXOGatewayTest.php @@ -12,7 +12,7 @@ use WooCommerce\PayPalCommerce\ApiClient\Entity\PurchaseUnit; use WooCommerce\PayPalCommerce\ApiClient\Exception\RuntimeException; use WooCommerce\PayPalCommerce\ApiClient\Factory\PurchaseUnitFactory; use WooCommerce\PayPalCommerce\ApiClient\Factory\ShippingPreferenceFactory; -use WooCommerce\PayPalCommerce\Onboarding\Environment; +use WooCommerce\PayPalCommerce\WcGateway\Helper\Environment; use WooCommerce\PayPalCommerce\TestCase; use WooCommerce\PayPalCommerce\WcGateway\Gateway\TransactionUrlProvider; use function Brain\Monkey\Functions\when; diff --git a/tests/PHPUnit/WcGateway/Gateway/PayUponInvoice/PayUponInvoiceGatewayTest.php b/tests/PHPUnit/WcGateway/Gateway/PayUponInvoice/PayUponInvoiceGatewayTest.php index 82c88449f..d806037ee 100644 --- a/tests/PHPUnit/WcGateway/Gateway/PayUponInvoice/PayUponInvoiceGatewayTest.php +++ b/tests/PHPUnit/WcGateway/Gateway/PayUponInvoice/PayUponInvoiceGatewayTest.php @@ -10,7 +10,7 @@ use WooCommerce\PayPalCommerce\ApiClient\Endpoint\PayUponInvoiceOrderEndpoint; use WooCommerce\PayPalCommerce\ApiClient\Entity\Order; use WooCommerce\PayPalCommerce\ApiClient\Entity\PurchaseUnit; use WooCommerce\PayPalCommerce\ApiClient\Factory\PurchaseUnitFactory; -use WooCommerce\PayPalCommerce\Onboarding\Environment; +use WooCommerce\PayPalCommerce\WcGateway\Helper\Environment; use WooCommerce\PayPalCommerce\Onboarding\State; use WooCommerce\PayPalCommerce\TestCase; use WooCommerce\PayPalCommerce\WcGateway\Gateway\TransactionUrlProvider; diff --git a/tests/PHPUnit/WcGateway/Gateway/WcGatewayTest.php b/tests/PHPUnit/WcGateway/Gateway/WcGatewayTest.php index 8c8a238ae..a9e64ebb0 100644 --- a/tests/PHPUnit/WcGateway/Gateway/WcGatewayTest.php +++ b/tests/PHPUnit/WcGateway/Gateway/WcGatewayTest.php @@ -9,7 +9,7 @@ use WooCommerce\PayPalCommerce\ApiClient\Endpoint\OrderEndpoint; use WooCommerce\PayPalCommerce\ApiClient\Endpoint\PaymentTokensEndpoint; use WooCommerce\PayPalCommerce\ApiClient\Entity\Order; use WooCommerce\PayPalCommerce\ApiClient\Entity\OrderStatus; -use WooCommerce\PayPalCommerce\Onboarding\Environment; +use WooCommerce\PayPalCommerce\WcGateway\Helper\Environment; use WooCommerce\PayPalCommerce\Onboarding\State; use WooCommerce\PayPalCommerce\Session\SessionHandler; use WooCommerce\PayPalCommerce\Vaulting\WooCommercePaymentTokens; diff --git a/tests/PHPUnit/WcGateway/Processor/OrderProcessorTest.php b/tests/PHPUnit/WcGateway/Processor/OrderProcessorTest.php index 207d31967..951c3d9af 100644 --- a/tests/PHPUnit/WcGateway/Processor/OrderProcessorTest.php +++ b/tests/PHPUnit/WcGateway/Processor/OrderProcessorTest.php @@ -20,7 +20,7 @@ use WooCommerce\PayPalCommerce\ApiClient\Entity\PurchaseUnit; use WooCommerce\PayPalCommerce\ApiClient\Factory\OrderFactory; use WooCommerce\PayPalCommerce\ApiClient\Helper\OrderHelper; use WooCommerce\PayPalCommerce\Button\Helper\ThreeDSecure; -use WooCommerce\PayPalCommerce\Onboarding\Environment; +use WooCommerce\PayPalCommerce\WcGateway\Helper\Environment; use WooCommerce\PayPalCommerce\Session\SessionHandler; use WooCommerce\PayPalCommerce\Vendor\Inpsyde\Modularity\Container\ReadOnlyContainer; use WooCommerce\PayPalCommerce\WcSubscriptions\Helper\SubscriptionHelper;