Merge pull request #1986 from woocommerce/PCP-2521-apple-pay-recurring-payments

Apple Pay recurring payments (2521)
This commit is contained in:
Emili Castells 2024-02-07 10:47:08 +01:00 committed by GitHub
commit 037f650288
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
20 changed files with 437 additions and 37 deletions

View file

@ -27,6 +27,7 @@ return array(
$environment = $container->get( 'onboarding.environment' );
$settings = $container->get( 'wcgateway.settings' );
$authorized_payments_processor = $container->get( 'wcgateway.processor.authorized-payments' );
$funding_source_renderer = $container->get( 'wcgateway.funding-source.renderer' );
return new RenewalHandler(
$logger,
$repository,
@ -36,7 +37,8 @@ return array(
$payer_factory,
$environment,
$settings,
$authorized_payments_processor
$authorized_payments_processor,
$funding_source_renderer
);
},
'wc-subscriptions.repository.payment-token' => static function ( ContainerInterface $container ): PaymentTokenRepository {

View file

@ -22,9 +22,13 @@ 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\Vaulting\PaymentTokenApplePay;
use WooCommerce\PayPalCommerce\Vaulting\PaymentTokenPayPal;
use WooCommerce\PayPalCommerce\Vaulting\PaymentTokenRepository;
use Psr\Log\LoggerInterface;
use WooCommerce\PayPalCommerce\Vaulting\PaymentTokenVenmo;
use WooCommerce\PayPalCommerce\WcGateway\Exception\NotFoundException;
use WooCommerce\PayPalCommerce\WcGateway\FundingSource\FundingSourceRenderer;
use WooCommerce\PayPalCommerce\WcGateway\Gateway\CreditCardGateway;
use WooCommerce\PayPalCommerce\WcGateway\Gateway\PayPalGateway;
use WooCommerce\PayPalCommerce\WcGateway\Processor\AuthorizedPaymentsProcessor;
@ -105,6 +109,13 @@ class RenewalHandler {
*/
protected $authorized_payments_processor;
/**
* The funding source renderer.
*
* @var FundingSourceRenderer
*/
protected $funding_source_renderer;
/**
* RenewalHandler constructor.
*
@ -117,6 +128,7 @@ class RenewalHandler {
* @param Environment $environment The environment.
* @param Settings $settings The Settings.
* @param AuthorizedPaymentsProcessor $authorized_payments_processor The Authorized Payments Processor.
* @param FundingSourceRenderer $funding_source_renderer The funding source renderer.
*/
public function __construct(
LoggerInterface $logger,
@ -127,7 +139,8 @@ class RenewalHandler {
PayerFactory $payer_factory,
Environment $environment,
Settings $settings,
AuthorizedPaymentsProcessor $authorized_payments_processor
AuthorizedPaymentsProcessor $authorized_payments_processor,
FundingSourceRenderer $funding_source_renderer
) {
$this->logger = $logger;
@ -139,6 +152,7 @@ class RenewalHandler {
$this->environment = $environment;
$this->settings = $settings;
$this->authorized_payments_processor = $authorized_payments_processor;
$this->funding_source_renderer = $funding_source_renderer;
}
/**
@ -202,11 +216,31 @@ class RenewalHandler {
if ( $wc_order->get_payment_method() === PayPalGateway::ID ) {
$wc_tokens = WC_Payment_Tokens::get_customer_tokens( $wc_order->get_customer_id(), PayPalGateway::ID );
foreach ( $wc_tokens as $token ) {
$name = 'paypal';
$properties = array(
'vault_id' => $token->get_token(),
);
if ( $token instanceof PaymentTokenPayPal ) {
$name = 'paypal';
}
if ( $token instanceof PaymentTokenVenmo ) {
$name = 'venmo';
}
if ( $token instanceof PaymentTokenApplePay ) {
$name = 'apple_pay';
$properties['stored_credential'] = array(
'payment_initiator' => 'MERCHANT',
'payment_type' => 'RECURRING',
'usage' => 'SUBSEQUENT',
);
}
$payment_source = new PaymentSource(
'paypal',
(object) array(
'vault_id' => $token->get_token(),
)
$name,
(object) $properties
);
break;
@ -387,6 +421,11 @@ class RenewalHandler {
if ( $transaction_id ) {
$this->update_transaction_id( $transaction_id, $wc_order );
$payment_source = $order->payment_source();
if ( $payment_source instanceof PaymentSource ) {
$this->update_payment_source( $payment_source, $wc_order );
}
$subscriptions = wcs_get_subscriptions_for_order( $wc_order->get_id(), array( 'order_type' => 'any' ) );
foreach ( $subscriptions as $id => $subscription ) {
$subscription->update_meta_data( 'ppcp_previous_transaction_reference', $transaction_id );
@ -440,4 +479,29 @@ class RenewalHandler {
(object) $properties
);
}
/**
* Updates the payment source name to the one really used for the payment.
*
* @param PaymentSource $payment_source The Payment Source.
* @param \WC_Order $wc_order WC order.
* @return void
*/
private function update_payment_source( PaymentSource $payment_source, \WC_Order $wc_order ): void {
if ( ! $payment_source->name() ) {
return;
}
try {
$wc_order->set_payment_method_title( $this->funding_source_renderer->render_name( $payment_source->name() ) );
$wc_order->save();
} catch ( \Exception $e ) {
$this->logger->error(
sprintf(
'Failed to update payment source to "%1$s" on order %2$d',
$payment_source->name(),
$wc_order->get_id()
)
);
}
}
}

View file

@ -111,6 +111,17 @@ class WcSubscriptionsModule implements ModuleInterface {
$subscription->update_meta_data( 'ppcp_previous_transaction_reference', $transaction_id );
$subscription->save();
}
// Update the initial payment method title if not the same as the first order.
$payment_method_title = $parent_order->get_payment_method_title();
if (
$payment_method_title
&& $subscription instanceof \WC_Subscription
&& $subscription->get_payment_method_title() !== $payment_method_title
) {
$subscription->set_payment_method_title( $payment_method_title );
$subscription->save();
}
}
}
}
@ -311,7 +322,7 @@ class WcSubscriptionsModule implements ModuleInterface {
foreach ( $tokens as $token ) {
$output .= '<li>';
$output .= sprintf( '<input name="saved_paypal_payment" type="radio" value="%s" style="width:auto;" checked="checked">', $token->get_id() );
$output .= sprintf( '<label for="saved_paypal_payment">%s</label>', $token->get_meta( 'email' ) ?? '' );
$output .= sprintf( '<label for="saved_paypal_payment">%s / %s</label>', $token->get_type(), $token->get_meta( 'email' ) ?? '' );
$output .= '</li>';
}
$output .= '</ul>';