Handle card smart button for free trial (1$ auth + void)

Disabling this funding source also disables DCC
This commit is contained in:
Alex P 2022-04-25 15:24:37 +03:00
parent a5191b04ff
commit 4a4f131325
13 changed files with 74 additions and 5 deletions

View file

@ -16,6 +16,7 @@ use WooCommerce\PayPalCommerce\ApiClient\Entity\Money;
use WooCommerce\PayPalCommerce\ApiClient\Exception\RuntimeException; use WooCommerce\PayPalCommerce\ApiClient\Exception\RuntimeException;
use WooCommerce\PayPalCommerce\Subscription\FreeTrialHandlerTrait; use WooCommerce\PayPalCommerce\Subscription\FreeTrialHandlerTrait;
use WooCommerce\PayPalCommerce\WcGateway\Gateway\CreditCardGateway; use WooCommerce\PayPalCommerce\WcGateway\Gateway\CreditCardGateway;
use WooCommerce\PayPalCommerce\WcGateway\Gateway\PayPalGateway;
/** /**
* Class AmountFactory * Class AmountFactory
@ -124,7 +125,12 @@ class AmountFactory {
$items = $this->item_factory->from_wc_order( $order ); $items = $this->item_factory->from_wc_order( $order );
$total_value = (float) $order->get_total(); $total_value = (float) $order->get_total();
if ( CreditCardGateway::ID === $order->get_payment_method() && $this->is_free_trial_order( $order ) ) { if ( (
CreditCardGateway::ID === $order->get_payment_method()
|| ( PayPalGateway::ID === $order->get_payment_method() && 'card' === $order->get_meta( PayPalGateway::ORDER_PAYMENT_SOURCE ) )
)
&& $this->is_free_trial_order( $order )
) {
$total_value = 1.0; $total_value = 1.0;
} }
$total = new Money( $total_value, $currency ); $total = new Money( $total_value, $currency );

View file

@ -31,8 +31,17 @@ const bootstrap = () => {
const onSmartButtonClick = (data, actions) => { const onSmartButtonClick = (data, actions) => {
window.ppcpFundingSource = data.fundingSource; window.ppcpFundingSource = data.fundingSource;
const form = document.querySelector('form.woocommerce-checkout');
if (form) {
jQuery('#ppcp-funding-source-form-input').remove();
form.insertAdjacentHTML(
'beforeend',
`<input type="hidden" name="ppcp-funding-source" value="${data.fundingSource}" id="ppcp-funding-source-form-input">`
)
}
const isFreeTrial = PayPalCommerceGateway.is_free_trial_cart; const isFreeTrial = PayPalCommerceGateway.is_free_trial_cart;
if (isFreeTrial) { if (isFreeTrial && data.fundingSource !== 'card') {
freeTrialHandler.handle(); freeTrialHandler.handle();
return actions.reject(); return actions.reject();
} }

View file

@ -20,6 +20,7 @@ class CartActionHandler {
nonce: this.config.ajax.create_order.nonce, nonce: this.config.ajax.create_order.nonce,
purchase_units: [], purchase_units: [],
payment_method: PaymentMethods.PAYPAL, payment_method: PaymentMethods.PAYPAL,
funding_source: window.ppcpFundingSource,
bn_code:bnCode, bn_code:bnCode,
payer, payer,
context:this.config.context context:this.config.context

View file

@ -33,6 +33,7 @@ class CheckoutActionHandler {
context:this.config.context, context:this.config.context,
order_id:this.config.order_id, order_id:this.config.order_id,
payment_method: getCurrentPaymentMethod(), payment_method: getCurrentPaymentMethod(),
funding_source: window.ppcpFundingSource,
form:formValues, form:formValues,
createaccount: createaccount createaccount: createaccount
}) })

View file

@ -86,6 +86,7 @@ class SingleProductActionHandler {
payer, payer,
bn_code:bnCode, bn_code:bnCode,
payment_method: PaymentMethods.PAYPAL, payment_method: PaymentMethods.PAYPAL,
funding_source: window.ppcpFundingSource,
context:this.config.context context:this.config.context
}) })
}).then(function (res) { }).then(function (res) {

View file

@ -28,6 +28,7 @@ use WooCommerce\PayPalCommerce\Session\SessionHandler;
use WooCommerce\PayPalCommerce\Subscription\FreeTrialHandlerTrait; use WooCommerce\PayPalCommerce\Subscription\FreeTrialHandlerTrait;
use WooCommerce\PayPalCommerce\WcGateway\Exception\NotFoundException; use WooCommerce\PayPalCommerce\WcGateway\Exception\NotFoundException;
use WooCommerce\PayPalCommerce\WcGateway\Gateway\CreditCardGateway; use WooCommerce\PayPalCommerce\WcGateway\Gateway\CreditCardGateway;
use WooCommerce\PayPalCommerce\WcGateway\Gateway\PayPalGateway;
use WooCommerce\PayPalCommerce\WcGateway\Settings\Settings; use WooCommerce\PayPalCommerce\WcGateway\Settings\Settings;
/** /**
@ -182,6 +183,7 @@ class CreateOrderEndpoint implements EndpointInterface {
$data = $this->request_data->read_request( $this->nonce() ); $data = $this->request_data->read_request( $this->nonce() );
$this->parsed_request_data = $data; $this->parsed_request_data = $data;
$payment_method = $data['payment_method'] ?? ''; $payment_method = $data['payment_method'] ?? '';
$funding_source = $data['funding_source'] ?? '';
$wc_order = null; $wc_order = null;
if ( 'pay-now' === $data['context'] ) { if ( 'pay-now' === $data['context'] ) {
$wc_order = wc_get_order( (int) $data['order_id'] ); $wc_order = wc_get_order( (int) $data['order_id'] );
@ -200,7 +202,12 @@ class CreateOrderEndpoint implements EndpointInterface {
$this->purchase_units = $this->cart_repository->all(); $this->purchase_units = $this->cart_repository->all();
// The cart does not have any info about payment method, so we must handle free trial here. // The cart does not have any info about payment method, so we must handle free trial here.
if ( CreditCardGateway::ID === $payment_method && $this->is_free_trial_cart() ) { if ( (
CreditCardGateway::ID === $payment_method
|| ( PayPalGateway::ID === $payment_method && 'card' === $funding_source )
)
&& $this->is_free_trial_cart()
) {
$this->purchase_units[0]->set_amount( $this->purchase_units[0]->set_amount(
new Amount( new Amount(
new Money( 1.0, $this->purchase_units[0]->amount()->currency_code() ), new Money( 1.0, $this->purchase_units[0]->amount()->currency_code() ),

View file

@ -17,6 +17,7 @@ use WooCommerce\PayPalCommerce\ApiClient\Endpoint\PaymentsEndpoint;
use WooCommerce\PayPalCommerce\ApiClient\Repository\OrderRepository; use WooCommerce\PayPalCommerce\ApiClient\Repository\OrderRepository;
use WooCommerce\PayPalCommerce\Subscription\FreeTrialHandlerTrait; use WooCommerce\PayPalCommerce\Subscription\FreeTrialHandlerTrait;
use WooCommerce\PayPalCommerce\WcGateway\Gateway\CreditCardGateway; use WooCommerce\PayPalCommerce\WcGateway\Gateway\CreditCardGateway;
use WooCommerce\PayPalCommerce\WcGateway\Gateway\PayPalGateway;
use WooCommerce\PayPalCommerce\WcGateway\Processor\AuthorizedPaymentsProcessor; use WooCommerce\PayPalCommerce\WcGateway\Processor\AuthorizedPaymentsProcessor;
use WooCommerce\PayPalCommerce\WcGateway\Settings\Settings; use WooCommerce\PayPalCommerce\WcGateway\Settings\Settings;
@ -117,7 +118,9 @@ class PaymentTokenChecker {
if ( $tokens ) { if ( $tokens ) {
try { try {
if ( $this->is_free_trial_order( $wc_order ) ) { if ( $this->is_free_trial_order( $wc_order ) ) {
if ( CreditCardGateway::ID === $wc_order->get_payment_method() ) { if ( CreditCardGateway::ID === $wc_order->get_payment_method()
|| ( PayPalGateway::ID === $wc_order->get_payment_method() && 'card' === $wc_order->get_meta( PayPalGateway::ORDER_PAYMENT_SOURCE ) )
) {
$order = $this->order_repository->for_wc_order( $wc_order ); $order = $this->order_repository->for_wc_order( $wc_order );
$this->authorized_payments_processor->void_authorizations( $order ); $this->authorized_payments_processor->void_authorizations( $order );
$wc_order->payment_complete(); $wc_order->payment_complete();

View file

@ -37,6 +37,7 @@ class PayPalGateway extends \WC_Payment_Gateway {
const INTENT_META_KEY = '_ppcp_paypal_intent'; const INTENT_META_KEY = '_ppcp_paypal_intent';
const ORDER_ID_META_KEY = '_ppcp_paypal_order_id'; const ORDER_ID_META_KEY = '_ppcp_paypal_order_id';
const ORDER_PAYMENT_MODE_META_KEY = '_ppcp_paypal_payment_mode'; const ORDER_PAYMENT_MODE_META_KEY = '_ppcp_paypal_payment_mode';
const ORDER_PAYMENT_SOURCE = '_ppcp_paypal_payment_source';
const FEES_META_KEY = '_ppcp_paypal_fees'; const FEES_META_KEY = '_ppcp_paypal_fees';
/** /**

View file

@ -55,6 +55,7 @@ trait ProcessPaymentTrait {
} }
$payment_method = filter_input( INPUT_POST, 'payment_method', FILTER_SANITIZE_STRING ); $payment_method = filter_input( INPUT_POST, 'payment_method', FILTER_SANITIZE_STRING );
$funding_source = filter_input( INPUT_POST, 'ppcp-funding-source', FILTER_SANITIZE_STRING );
/** /**
* If customer has chosen a saved credit card payment. * If customer has chosen a saved credit card payment.
@ -135,7 +136,7 @@ trait ProcessPaymentTrait {
} }
} }
if ( PayPalGateway::ID === $payment_method && $this->is_free_trial_order( $wc_order ) ) { if ( PayPalGateway::ID === $payment_method && 'card' !== $funding_source && $this->is_free_trial_order( $wc_order ) ) {
$user_id = (int) $wc_order->get_customer_id(); $user_id = (int) $wc_order->get_customer_id();
$tokens = $this->payment_token_repository->all_for_user_id( $user_id ); $tokens = $this->payment_token_repository->all_for_user_id( $user_id );
if ( ! array_filter( if ( ! array_filter(

View file

@ -37,5 +37,29 @@ trait OrderMetaTrait {
PayPalGateway::ORDER_PAYMENT_MODE_META_KEY, PayPalGateway::ORDER_PAYMENT_MODE_META_KEY,
$environment->current_environment_is( Environment::SANDBOX ) ? 'sandbox' : 'live' $environment->current_environment_is( Environment::SANDBOX ) ? 'sandbox' : 'live'
); );
$payment_source = $this->get_payment_source( $order );
if ( $payment_source ) {
$wc_order->update_meta_data( PayPalGateway::ORDER_PAYMENT_SOURCE, $payment_source );
}
}
/**
* Returns the payment source type or null,
*
* @param Order $order The PayPal order.
* @return string|null
*/
private function get_payment_source( Order $order ): ?string {
$source = $order->payment_source();
if ( $source ) {
if ( $source->card() ) {
return 'card';
}
if ( $source->wallet() ) {
return 'wallet';
}
}
return null;
} }
} }

View file

@ -162,6 +162,9 @@ class AmountFactoryTest extends TestCase
->shouldReceive('get_total_discount') ->shouldReceive('get_total_discount')
->with(false) ->with(false)
->andReturn(3); ->andReturn(3);
$order
->shouldReceive('get_meta')
->andReturn(null);
$result = $this->testee->from_wc_order($order); $result = $this->testee->from_wc_order($order);
$this->assertEquals((float) 3, $result->breakdown()->discount()->value()); $this->assertEquals((float) 3, $result->breakdown()->discount()->value());
@ -222,6 +225,9 @@ class AmountFactoryTest extends TestCase
->shouldReceive('get_total_discount') ->shouldReceive('get_total_discount')
->with(false) ->with(false)
->andReturn(0); ->andReturn(0);
$order
->shouldReceive('get_meta')
->andReturn(null);
$result = $this->testee->from_wc_order($order); $result = $this->testee->from_wc_order($order);
$this->assertNull($result->breakdown()->discount()); $this->assertNull($result->breakdown()->discount());

View file

@ -98,6 +98,9 @@ class RenewalHandlerTest extends TestCase
$order $order
->shouldReceive('purchase_units') ->shouldReceive('purchase_units')
->andReturn([$purchaseUnit]); ->andReturn([$purchaseUnit]);
$order
->shouldReceive('payment_source')
->andReturn(null);
$wcOrder $wcOrder
->shouldReceive('get_id') ->shouldReceive('get_id')

View file

@ -85,6 +85,9 @@ class OrderProcessorTest extends TestCase
->andReturn($orderStatus); ->andReturn($orderStatus);
$currentOrder->shouldReceive('purchase_units') $currentOrder->shouldReceive('purchase_units')
->andReturn([$purchaseUnit]); ->andReturn([$purchaseUnit]);
$currentOrder
->shouldReceive('payment_source')
->andReturn(null);
$sessionHandler = Mockery::mock(SessionHandler::class); $sessionHandler = Mockery::mock(SessionHandler::class);
$sessionHandler $sessionHandler
@ -202,6 +205,9 @@ class OrderProcessorTest extends TestCase
$currentOrder $currentOrder
->shouldReceive('purchase_units') ->shouldReceive('purchase_units')
->andReturn([$purchaseUnit]); ->andReturn([$purchaseUnit]);
$currentOrder
->shouldReceive('payment_source')
->andReturn(null);
$sessionHandler = Mockery::mock(SessionHandler::class); $sessionHandler = Mockery::mock(SessionHandler::class);
$sessionHandler $sessionHandler
->expects('order') ->expects('order')