diff --git a/modules/ppcp-button/services.php b/modules/ppcp-button/services.php index bd3c8bac7..40d735d4e 100644 --- a/modules/ppcp-button/services.php +++ b/modules/ppcp-button/services.php @@ -139,13 +139,15 @@ return array( $three_d_secure = $container->get( 'button.helper.three-d-secure' ); $settings = $container->get( 'wcgateway.settings' ); $dcc_applies = $container->get( 'api.helpers.dccapplies' ); + $logger = $container->get( 'woocommerce.logger.woocommerce' ); return new ApproveOrderEndpoint( $request_data, $order_endpoint, $session_handler, $three_d_secure, $settings, - $dcc_applies + $dcc_applies, + $logger ); }, 'button.endpoint.data-client-id' => static function( $container ) : DataClientIdEndpoint { diff --git a/modules/ppcp-button/src/Endpoint/class-approveorderendpoint.php b/modules/ppcp-button/src/Endpoint/class-approveorderendpoint.php index 4dbdeb8e5..6953b3a6d 100644 --- a/modules/ppcp-button/src/Endpoint/class-approveorderendpoint.php +++ b/modules/ppcp-button/src/Endpoint/class-approveorderendpoint.php @@ -10,6 +10,7 @@ declare(strict_types=1); namespace WooCommerce\PayPalCommerce\Button\Endpoint; +use Psr\Log\LoggerInterface; use WooCommerce\PayPalCommerce\ApiClient\Endpoint\OrderEndpoint; use WooCommerce\PayPalCommerce\ApiClient\Entity\OrderStatus; use WooCommerce\PayPalCommerce\ApiClient\Exception\PayPalApiException; @@ -69,15 +70,23 @@ class ApproveOrderEndpoint implements EndpointInterface { */ private $dcc_applies; + /** + * The logger. + * + * @var LoggerInterface + */ + protected $logger; + /** * ApproveOrderEndpoint constructor. * - * @param RequestData $request_data The request data helper. - * @param OrderEndpoint $order_endpoint The order endpoint. - * @param SessionHandler $session_handler The session handler. - * @param ThreeDSecure $three_d_secure The 3d secure helper object. - * @param Settings $settings The settings. - * @param DccApplies $dcc_applies The DCC applies object. + * @param RequestData $request_data The request data helper. + * @param OrderEndpoint $order_endpoint The order endpoint. + * @param SessionHandler $session_handler The session handler. + * @param ThreeDSecure $three_d_secure The 3d secure helper object. + * @param Settings $settings The settings. + * @param DccApplies $dcc_applies The DCC applies object. + * @param LoggerInterface $logger The logger. */ public function __construct( RequestData $request_data, @@ -85,7 +94,8 @@ class ApproveOrderEndpoint implements EndpointInterface { SessionHandler $session_handler, ThreeDSecure $three_d_secure, Settings $settings, - DccApplies $dcc_applies + DccApplies $dcc_applies, + LoggerInterface $logger ) { $this->request_data = $request_data; @@ -94,6 +104,7 @@ class ApproveOrderEndpoint implements EndpointInterface { $this->threed_secure = $three_d_secure; $this->settings = $settings; $this->dcc_applies = $dcc_applies; + $this->logger = $logger; } /** @@ -171,13 +182,14 @@ class ApproveOrderEndpoint implements EndpointInterface { } if ( ! $order->status()->is( OrderStatus::APPROVED ) ) { - throw new RuntimeException( - sprintf( - // translators: %s is the id of the order. - __( 'Order %s is not approved yet.', 'woocommerce-paypal-payments' ), - $data['order_id'] - ) + $message = sprintf( + // translators: %s is the id of the order. + __( 'Order %s is not approved yet.', 'woocommerce-paypal-payments' ), + $data['order_id'] ); + + $this->logger->log( 'error', $message ); + throw new RuntimeException( $message ); } $this->session_handler->replace_order( $order ); diff --git a/modules/ppcp-subscription/src/class-renewalhandler.php b/modules/ppcp-subscription/src/class-renewalhandler.php index bb8aca5b8..af23691b6 100644 --- a/modules/ppcp-subscription/src/class-renewalhandler.php +++ b/modules/ppcp-subscription/src/class-renewalhandler.php @@ -203,6 +203,19 @@ class RenewalHandler { ); } + $subscription = wcs_get_subscription( $wc_order->get_meta( '_subscription_renewal' ) ); + if ( $subscription ) { + $subscription_id = $subscription->get_id(); + $token_id = get_post_meta( $subscription_id, 'payment_token_id', true ); + if ( $token_id ) { + foreach ( $tokens as $token ) { + if ( $token_id === $token->id() ) { + return $token; + } + } + } + } + return current( $tokens ); } diff --git a/modules/ppcp-subscription/src/class-subscriptionmodule.php b/modules/ppcp-subscription/src/class-subscriptionmodule.php index 130f688b3..c9d527197 100644 --- a/modules/ppcp-subscription/src/class-subscriptionmodule.php +++ b/modules/ppcp-subscription/src/class-subscriptionmodule.php @@ -11,8 +11,9 @@ namespace WooCommerce\PayPalCommerce\Subscription; use Dhii\Container\ServiceProvider; use Dhii\Modular\Module\ModuleInterface; -use WooCommerce\PayPalCommerce\ApiClient\Endpoint\PaymentTokenEndpoint; +use Psr\Log\LoggerInterface; use WooCommerce\PayPalCommerce\ApiClient\Exception\RuntimeException; +use WooCommerce\PayPalCommerce\Subscription\Repository\PaymentTokenRepository; use WooCommerce\PayPalCommerce\WcGateway\Gateway\PayPalGateway; use WooCommerce\PayPalCommerce\WcGateway\Gateway\CreditCardGateway; use Interop\Container\ServiceProviderInterface; @@ -58,6 +59,16 @@ class SubscriptionModule implements ModuleInterface { 10, 2 ); + + add_action( + 'woocommerce_subscription_payment_complete', + function ( $subscription ) use ( $container ) { + $payment_token_repository = $container->get( 'subscription.repository.payment-token' ); + $logger = $container->get( 'woocommerce.logger.woocommerce' ); + + $this->add_payment_token_id( $subscription, $payment_token_repository, $logger ); + } + ); } /** @@ -83,4 +94,38 @@ class SubscriptionModule implements ModuleInterface { */ public function getKey() { } + + /** + * Adds Payment token ID to subscription. + * + * @param \WC_Subscription $subscription The subscription. + * @param PaymentTokenRepository $payment_token_repository The payment repository. + * @param LoggerInterface $logger The logger. + */ + private function add_payment_token_id( + \WC_Subscription $subscription, + PaymentTokenRepository $payment_token_repository, + LoggerInterface $logger + ) { + try { + $tokens = $payment_token_repository->all_for_user_id( $subscription->get_customer_id() ); + if ( $tokens ) { + $subscription_id = $subscription->get_id(); + $latest_token_id = end( $tokens )->id() ?: ''; + update_post_meta( $subscription_id, 'payment_token_id', $latest_token_id, true ); + } + } catch ( RuntimeException $error ) { + $message = sprintf( + // translators: %1$s is the payment token Id, %2$s is the error message. + __( + 'Could not add token Id to subscription %1$s: %2$s', + 'woocommerce-paypal-payments' + ), + $subscription->get_id(), + $error->getMessage() + ); + + $logger->log( 'warning', $message ); + } + } } diff --git a/modules/ppcp-wc-gateway/services.php b/modules/ppcp-wc-gateway/services.php index 124b1ab98..c3dfa1548 100644 --- a/modules/ppcp-wc-gateway/services.php +++ b/modules/ppcp-wc-gateway/services.php @@ -145,7 +145,7 @@ return array( $settings = $container->get( 'wcgateway.settings' ); $environment = $container->get( 'onboarding.environment' ); $logger = $container->get( 'woocommerce.logger.woocommerce' ); - + $payment_token_repository = $container->get( 'subscription.repository.payment-token' ); return new OrderProcessor( $session_handler, $order_endpoint, @@ -154,7 +154,8 @@ return array( $authorized_payments_processor, $settings, $logger, - $environment->current_environment_is( Environment::SANDBOX ) + $environment->current_environment_is( Environment::SANDBOX ), + $payment_token_repository ); }, 'wcgateway.processor.refunds' => static function ( $container ): RefundProcessor { diff --git a/modules/ppcp-wc-gateway/src/Gateway/class-processpaymenttrait.php b/modules/ppcp-wc-gateway/src/Gateway/class-processpaymenttrait.php index 34334ab3c..037852bfa 100644 --- a/modules/ppcp-wc-gateway/src/Gateway/class-processpaymenttrait.php +++ b/modules/ppcp-wc-gateway/src/Gateway/class-processpaymenttrait.php @@ -42,10 +42,11 @@ trait ProcessPaymentTrait { } /** - * If customer has chosed a saved credit card payment. + * If customer has chosen a saved credit card payment. */ $saved_credit_card = filter_input( INPUT_POST, 'saved_credit_card', FILTER_SANITIZE_STRING ); - if ( $saved_credit_card ) { + $pay_for_order = filter_input( INPUT_GET, 'pay_for_order', FILTER_SANITIZE_STRING ); + if ( $saved_credit_card && ! isset( $pay_for_order ) ) { $user_id = (int) $wc_order->get_customer_id(); $customer = new \WC_Customer( $user_id ); diff --git a/modules/ppcp-wc-gateway/src/Processor/class-orderprocessor.php b/modules/ppcp-wc-gateway/src/Processor/class-orderprocessor.php index bdbbe533f..5f09505e5 100644 --- a/modules/ppcp-wc-gateway/src/Processor/class-orderprocessor.php +++ b/modules/ppcp-wc-gateway/src/Processor/class-orderprocessor.php @@ -16,6 +16,7 @@ use WooCommerce\PayPalCommerce\ApiClient\Entity\OrderStatus; use WooCommerce\PayPalCommerce\ApiClient\Factory\OrderFactory; use WooCommerce\PayPalCommerce\Button\Helper\ThreeDSecure; use WooCommerce\PayPalCommerce\Session\SessionHandler; +use WooCommerce\PayPalCommerce\Subscription\Repository\PaymentTokenRepository; use WooCommerce\PayPalCommerce\WcGateway\Gateway\PayPalGateway; use WooCommerce\PayPalCommerce\WcGateway\Settings\Settings; @@ -31,6 +32,13 @@ class OrderProcessor { */ protected $sandbox_mode; + /** + * The payment token repository. + * + * @var PaymentTokenRepository + */ + protected $payment_token_repository; + /** * The Session Handler. * @@ -98,6 +106,7 @@ class OrderProcessor { * @param Settings $settings The Settings. * @param LoggerInterface $logger A logger service. * @param bool $sandbox_mode Whether sandbox mode enabled. + * @param PaymentTokenRepository $payment_token_repository The payment token repository. */ public function __construct( SessionHandler $session_handler, @@ -107,7 +116,8 @@ class OrderProcessor { AuthorizedPaymentsProcessor $authorized_payments_processor, Settings $settings, LoggerInterface $logger, - bool $sandbox_mode + bool $sandbox_mode, + PaymentTokenRepository $payment_token_repository ) { $this->session_handler = $session_handler; @@ -118,6 +128,7 @@ class OrderProcessor { $this->settings = $settings; $this->sandbox_mode = $sandbox_mode; $this->logger = $logger; + $this->payment_token_repository = $payment_token_repository; } /**