mirror of
https://github.com/woocommerce/woocommerce-paypal-payments.git
synced 2025-09-05 08:59:14 +08:00
Add card button gateway
This commit is contained in:
parent
0ff11054f8
commit
d4e8bd453c
15 changed files with 454 additions and 31 deletions
|
@ -15,6 +15,7 @@ use WooCommerce\PayPalCommerce\ApiClient\Entity\Item;
|
|||
use WooCommerce\PayPalCommerce\ApiClient\Entity\Money;
|
||||
use WooCommerce\PayPalCommerce\ApiClient\Exception\RuntimeException;
|
||||
use WooCommerce\PayPalCommerce\Subscription\FreeTrialHandlerTrait;
|
||||
use WooCommerce\PayPalCommerce\WcGateway\Gateway\CardButtonGateway;
|
||||
use WooCommerce\PayPalCommerce\WcGateway\Gateway\CreditCardGateway;
|
||||
use WooCommerce\PayPalCommerce\WcGateway\Gateway\PayPalGateway;
|
||||
|
||||
|
@ -132,7 +133,7 @@ class AmountFactory {
|
|||
|
||||
$total_value = (float) $order->get_total();
|
||||
if ( (
|
||||
CreditCardGateway::ID === $order->get_payment_method()
|
||||
in_array( $order->get_payment_method(), array( CreditCardGateway::ID, CardButtonGateway::ID ), true )
|
||||
|| ( PayPalGateway::ID === $order->get_payment_method() && 'card' === $order->get_meta( PayPalGateway::ORDER_PAYMENT_SOURCE_META_KEY ) )
|
||||
)
|
||||
&& $this->is_free_trial_order( $order )
|
||||
|
|
|
@ -18,7 +18,9 @@ import {hide, setVisible} from "./modules/Helper/Hiding";
|
|||
import {isChangePaymentPage} from "./modules/Helper/Subscriptions";
|
||||
import FreeTrialHandler from "./modules/ActionHandler/FreeTrialHandler";
|
||||
|
||||
const buttonsSpinner = new Spinner('.ppc-button-wrapper');
|
||||
// TODO: could be a good idea to have a separate spinner for each gateway,
|
||||
// but I think we care mainly about the script loading, so one spinner should be enough.
|
||||
const buttonsSpinner = new Spinner(document.querySelector('.ppc-button-wrapper'));
|
||||
const cardsSpinner = new Spinner('#ppcp-hosted-fields');
|
||||
|
||||
const bootstrap = () => {
|
||||
|
@ -138,6 +140,11 @@ document.addEventListener(
|
|||
return;
|
||||
}
|
||||
|
||||
const paypalButtonGatewayIds = [
|
||||
PaymentMethods.PAYPAL,
|
||||
...Object.entries(PayPalCommerceGateway.separate_buttons).map(([k, data]) => data.id),
|
||||
]
|
||||
|
||||
// Sometimes PayPal script takes long time to load,
|
||||
// so we additionally hide the standard order button here to avoid failed orders.
|
||||
// Normally it is hidden later after the script load.
|
||||
|
@ -153,12 +160,12 @@ document.addEventListener(
|
|||
}
|
||||
|
||||
const currentPaymentMethod = getCurrentPaymentMethod();
|
||||
const isPaypal = currentPaymentMethod === PaymentMethods.PAYPAL;
|
||||
const isPaypalButton = paypalButtonGatewayIds.includes(currentPaymentMethod);
|
||||
const isCards = currentPaymentMethod === PaymentMethods.CARDS;
|
||||
|
||||
setVisible(ORDER_BUTTON_SELECTOR, !isPaypal && !isCards, true);
|
||||
setVisible(ORDER_BUTTON_SELECTOR, !isPaypalButton && !isCards, true);
|
||||
|
||||
if (isPaypal) {
|
||||
if (isPaypalButton) {
|
||||
// stopped after the first rendering of the buttons, in onInit
|
||||
buttonsSpinner.block();
|
||||
} else {
|
||||
|
|
|
@ -82,16 +82,27 @@ class CheckoutBootstap {
|
|||
const currentPaymentMethod = getCurrentPaymentMethod();
|
||||
const isPaypal = currentPaymentMethod === PaymentMethods.PAYPAL;
|
||||
const isCard = currentPaymentMethod === PaymentMethods.CARDS;
|
||||
const isSeparateButtonGateway = [PaymentMethods.CARD_BUTTON].includes(currentPaymentMethod);
|
||||
const isSavedCard = isCard && isSavedCardSelected();
|
||||
const isNotOurGateway = !isPaypal && !isCard;
|
||||
const isNotOurGateway = !isPaypal && !isCard && !isSeparateButtonGateway;
|
||||
const isFreeTrial = PayPalCommerceGateway.is_free_trial_cart;
|
||||
const hasVaultedPaypal = PayPalCommerceGateway.vaulted_paypal_email !== '';
|
||||
|
||||
const paypalButtonWrappers = {
|
||||
...Object.entries(PayPalCommerceGateway.separate_buttons)
|
||||
.reduce((result, [k, data]) => {
|
||||
return {...result, [data.id]: data.wrapper}
|
||||
}, {}),
|
||||
};
|
||||
|
||||
setVisible(this.standardOrderButtonSelector, (isPaypal && isFreeTrial && hasVaultedPaypal) || isNotOurGateway || isSavedCard, true);
|
||||
setVisible('.ppcp-vaulted-paypal-details', isPaypal);
|
||||
setVisible(this.gateway.button.wrapper, isPaypal && !(isFreeTrial && hasVaultedPaypal));
|
||||
setVisible(this.gateway.messages.wrapper, isPaypal && !isFreeTrial);
|
||||
setVisible(this.gateway.hosted_fields.wrapper, isCard && !isSavedCard);
|
||||
for (const [gatewayId, wrapper] of Object.entries(paypalButtonWrappers)) {
|
||||
setVisible(wrapper, gatewayId === currentPaymentMethod);
|
||||
}
|
||||
|
||||
if (isPaypal && !isFreeTrial) {
|
||||
this.messages.render();
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
export const PaymentMethods = {
|
||||
PAYPAL: 'ppcp-gateway',
|
||||
CARDS: 'ppcp-credit-card-gateway',
|
||||
CARD_BUTTON: 'ppcp-card-button-gateway',
|
||||
};
|
||||
|
||||
export const ORDER_BUTTON_SELECTOR = '#place_order';
|
||||
|
|
|
@ -13,6 +13,16 @@ class Renderer {
|
|||
|
||||
this.renderButtons(settings.button.wrapper, settings.button.style, contextConfig);
|
||||
this.creditCardRenderer.render(settings.hosted_fields.wrapper, contextConfig);
|
||||
for (const [fundingSource, data] of Object.entries(settings.separate_buttons)) {
|
||||
this.renderButtons(
|
||||
data.wrapper,
|
||||
data.style,
|
||||
{
|
||||
...contextConfig,
|
||||
fundingSource: fundingSource,
|
||||
}
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
renderButtons(wrapper, style, contextConfig) {
|
||||
|
@ -20,12 +30,17 @@ class Renderer {
|
|||
return;
|
||||
}
|
||||
|
||||
paypal.Buttons({
|
||||
const btn = paypal.Buttons({
|
||||
style,
|
||||
...contextConfig,
|
||||
onClick: this.onSmartButtonClick,
|
||||
onInit: this.onSmartButtonsInit,
|
||||
}).render(wrapper);
|
||||
});
|
||||
if (!btn.isEligible()) {
|
||||
return;
|
||||
}
|
||||
|
||||
btn.render(wrapper);
|
||||
}
|
||||
|
||||
isAlreadyRendered(wrapper) {
|
||||
|
|
|
@ -28,7 +28,9 @@ use WooCommerce\PayPalCommerce\Session\SessionHandler;
|
|||
use WooCommerce\PayPalCommerce\Subscription\FreeTrialHandlerTrait;
|
||||
use WooCommerce\PayPalCommerce\Subscription\Helper\SubscriptionHelper;
|
||||
use WooCommerce\PayPalCommerce\Vaulting\PaymentTokenRepository;
|
||||
use WooCommerce\PayPalCommerce\WcGateway\Gateway\CardButtonGateway;
|
||||
use WooCommerce\PayPalCommerce\WcGateway\Gateway\CreditCardGateway;
|
||||
use WooCommerce\PayPalCommerce\WcGateway\Gateway\PayPalGateway;
|
||||
use WooCommerce\PayPalCommerce\WcGateway\Helper\SettingsStatus;
|
||||
use WooCommerce\PayPalCommerce\WcGateway\Settings\Settings;
|
||||
|
||||
|
@ -421,15 +423,20 @@ class SmartButton implements SmartButtonInterface {
|
|||
) {
|
||||
add_action(
|
||||
$this->single_product_renderer_hook(),
|
||||
array(
|
||||
$this,
|
||||
'button_renderer',
|
||||
),
|
||||
function () {
|
||||
$this->button_renderer( PayPalGateway::ID );
|
||||
},
|
||||
31
|
||||
);
|
||||
}
|
||||
|
||||
add_action( $this->pay_order_renderer_hook(), array( $this, 'button_renderer' ), 10 );
|
||||
add_action(
|
||||
$this->pay_order_renderer_hook(),
|
||||
function (): void {
|
||||
$this->button_renderer( PayPalGateway::ID );
|
||||
$this->button_renderer( CardButtonGateway::ID );
|
||||
}
|
||||
);
|
||||
|
||||
$not_enabled_on_minicart = $this->settings->has( 'button_mini_cart_enabled' ) &&
|
||||
! $this->settings->get( 'button_mini_cart_enabled' );
|
||||
|
@ -457,7 +464,13 @@ class SmartButton implements SmartButtonInterface {
|
|||
);
|
||||
}
|
||||
|
||||
add_action( $this->checkout_button_renderer_hook(), array( $this, 'button_renderer' ), 10 );
|
||||
add_action(
|
||||
$this->checkout_button_renderer_hook(),
|
||||
function (): void {
|
||||
$this->button_renderer( PayPalGateway::ID );
|
||||
$this->button_renderer( CardButtonGateway::ID );
|
||||
}
|
||||
);
|
||||
|
||||
$not_enabled_on_cart = $this->settings->has( 'button_cart_enabled' ) &&
|
||||
! $this->settings->get( 'button_cart_enabled' );
|
||||
|
@ -468,7 +481,7 @@ class SmartButton implements SmartButtonInterface {
|
|||
return;
|
||||
}
|
||||
|
||||
$this->button_renderer();
|
||||
$this->button_renderer( PayPalGateway::ID );
|
||||
},
|
||||
20
|
||||
);
|
||||
|
@ -524,8 +537,10 @@ class SmartButton implements SmartButtonInterface {
|
|||
|
||||
/**
|
||||
* Renders the HTML for the buttons.
|
||||
*
|
||||
* @param string $gateway_id The gateway ID, like 'ppcp-gateway'.
|
||||
*/
|
||||
public function button_renderer() {
|
||||
public function button_renderer( string $gateway_id ) {
|
||||
|
||||
if ( ! $this->can_save_vault_token() && $this->has_subscriptions() ) {
|
||||
return;
|
||||
|
@ -543,13 +558,13 @@ class SmartButton implements SmartButtonInterface {
|
|||
|
||||
$available_gateways = WC()->payment_gateways->get_available_payment_gateways();
|
||||
|
||||
if ( ! isset( $available_gateways['ppcp-gateway'] ) ) {
|
||||
if ( ! isset( $available_gateways[ $gateway_id ] ) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
// The wrapper is needed for the loading spinner,
|
||||
// otherwise jQuery block() prevents buttons rendering.
|
||||
echo '<div class="ppc-button-wrapper"><div id="ppc-button"></div></div>';
|
||||
echo '<div class="ppc-button-wrapper"><div id="ppc-button-' . esc_attr( $gateway_id ) . '"></div></div>';
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -810,7 +825,7 @@ class SmartButton implements SmartButtonInterface {
|
|||
'bn_codes' => $this->bn_codes(),
|
||||
'payer' => $this->payerData(),
|
||||
'button' => array(
|
||||
'wrapper' => '#ppc-button',
|
||||
'wrapper' => '#ppc-button-' . PayPalGateway::ID,
|
||||
'mini_cart_wrapper' => '#ppc-button-minicart',
|
||||
'cancel_wrapper' => '#ppcp-cancel',
|
||||
'url' => $this->url(),
|
||||
|
@ -830,6 +845,16 @@ class SmartButton implements SmartButtonInterface {
|
|||
'tagline' => $this->style_for_context( 'tagline', $this->context() ),
|
||||
),
|
||||
),
|
||||
'separate_buttons' => array(
|
||||
'card' => array(
|
||||
'id' => CardButtonGateway::ID,
|
||||
'wrapper' => '#ppc-button-' . CardButtonGateway::ID,
|
||||
'style' => array(
|
||||
'shape' => $this->style_for_context( 'shape', $this->context() ),
|
||||
// TODO: color black, white from the gateway settings.
|
||||
),
|
||||
),
|
||||
),
|
||||
'hosted_fields' => array(
|
||||
'wrapper' => '#ppcp-hosted-fields',
|
||||
'labels' => array(
|
||||
|
@ -1018,6 +1043,7 @@ class SmartButton implements SmartButtonInterface {
|
|||
|
||||
if ( $this->load_button_component() ) {
|
||||
$components[] = 'buttons';
|
||||
$components[] = 'funding-eligibility';
|
||||
}
|
||||
if (
|
||||
$this->messages_apply->for_country()
|
||||
|
@ -1112,6 +1138,9 @@ class SmartButton implements SmartButtonInterface {
|
|||
if ( $source && $source->card() ) {
|
||||
return false; // Ignore for DCC.
|
||||
}
|
||||
if ( 'card' === $this->session_handler->funding_source() ) {
|
||||
return false; // Ignore for card buttons.
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
|
@ -28,6 +28,7 @@ use WooCommerce\PayPalCommerce\Button\Helper\EarlyOrderHandler;
|
|||
use WooCommerce\PayPalCommerce\Session\SessionHandler;
|
||||
use WooCommerce\PayPalCommerce\Subscription\FreeTrialHandlerTrait;
|
||||
use WooCommerce\PayPalCommerce\WcGateway\Exception\NotFoundException;
|
||||
use WooCommerce\PayPalCommerce\WcGateway\Gateway\CardButtonGateway;
|
||||
use WooCommerce\PayPalCommerce\WcGateway\Gateway\CreditCardGateway;
|
||||
use WooCommerce\PayPalCommerce\WcGateway\Gateway\PayPalGateway;
|
||||
use WooCommerce\PayPalCommerce\WcGateway\Settings\Settings;
|
||||
|
@ -204,7 +205,7 @@ class CreateOrderEndpoint implements EndpointInterface {
|
|||
|
||||
// The cart does not have any info about payment method, so we must handle free trial here.
|
||||
if ( (
|
||||
CreditCardGateway::ID === $payment_method
|
||||
in_array( $payment_method, array( CreditCardGateway::ID, CardButtonGateway::ID ), true )
|
||||
|| ( PayPalGateway::ID === $payment_method && 'card' === $funding_source )
|
||||
)
|
||||
&& $this->is_free_trial_cart()
|
||||
|
|
|
@ -70,6 +70,10 @@ class CancelController {
|
|||
return; // Ignore for DCC.
|
||||
}
|
||||
|
||||
if ( 'card' === $this->session_handler->funding_source() ) {
|
||||
return; // Ignore for card buttons.
|
||||
}
|
||||
|
||||
$url = add_query_arg( array( $param_name => wp_create_nonce( $nonce ) ), wc_get_checkout_url() );
|
||||
add_action(
|
||||
'woocommerce_review_order_after_submit',
|
||||
|
|
|
@ -16,6 +16,7 @@ use WC_Order;
|
|||
use WooCommerce\PayPalCommerce\ApiClient\Endpoint\PaymentsEndpoint;
|
||||
use WooCommerce\PayPalCommerce\ApiClient\Repository\OrderRepository;
|
||||
use WooCommerce\PayPalCommerce\Subscription\FreeTrialHandlerTrait;
|
||||
use WooCommerce\PayPalCommerce\WcGateway\Gateway\CardButtonGateway;
|
||||
use WooCommerce\PayPalCommerce\WcGateway\Gateway\CreditCardGateway;
|
||||
use WooCommerce\PayPalCommerce\WcGateway\Gateway\PayPalGateway;
|
||||
use WooCommerce\PayPalCommerce\WcGateway\Processor\AuthorizedPaymentsProcessor;
|
||||
|
@ -118,7 +119,7 @@ class PaymentTokenChecker {
|
|||
if ( $tokens ) {
|
||||
try {
|
||||
if ( $this->is_free_trial_order( $wc_order ) ) {
|
||||
if ( CreditCardGateway::ID === $wc_order->get_payment_method()
|
||||
if ( in_array( $wc_order->get_payment_method(), array( CreditCardGateway::ID, CardButtonGateway::ID ), true )
|
||||
|| ( PayPalGateway::ID === $wc_order->get_payment_method() && 'card' === $wc_order->get_meta( PayPalGateway::ORDER_PAYMENT_SOURCE_META_KEY ) )
|
||||
) {
|
||||
$order = $this->order_repository->for_wc_order( $wc_order );
|
||||
|
|
|
@ -29,6 +29,7 @@ use WooCommerce\PayPalCommerce\WcGateway\Checkout\CheckoutPayPalAddressPreset;
|
|||
use WooCommerce\PayPalCommerce\WcGateway\Checkout\DisableGateways;
|
||||
use WooCommerce\PayPalCommerce\WcGateway\Endpoint\ReturnUrlEndpoint;
|
||||
use WooCommerce\PayPalCommerce\WcGateway\FundingSource\FundingSourceRenderer;
|
||||
use WooCommerce\PayPalCommerce\WcGateway\Gateway\CardButtonGateway;
|
||||
use WooCommerce\PayPalCommerce\WcGateway\Gateway\CreditCardGateway;
|
||||
use WooCommerce\PayPalCommerce\WcGateway\Gateway\PayPalGateway;
|
||||
use WooCommerce\PayPalCommerce\WcGateway\Gateway\PayUponInvoice\FraudNet;
|
||||
|
@ -126,6 +127,20 @@ return array(
|
|||
$payments_endpoint
|
||||
);
|
||||
},
|
||||
'wcgateway.card-button-gateway' => static function ( ContainerInterface $container ): CardButtonGateway {
|
||||
return new CardButtonGateway(
|
||||
$container->get( 'wcgateway.order-processor' ),
|
||||
$container->get( 'wcgateway.settings' ),
|
||||
$container->get( 'session.handler' ),
|
||||
$container->get( 'wcgateway.processor.refunds' ),
|
||||
$container->get( 'onboarding.state' ),
|
||||
$container->get( 'wcgateway.transaction-url-provider' ),
|
||||
$container->get( 'subscription.helper' ),
|
||||
$container->get( 'onboarding.environment' ),
|
||||
$container->get( 'vaulting.repository.payment-token' ),
|
||||
$container->get( 'woocommerce.logger.woocommerce' )
|
||||
);
|
||||
},
|
||||
'wcgateway.disabler' => static function ( ContainerInterface $container ): DisableGateways {
|
||||
$session_handler = $container->get( 'session.handler' );
|
||||
$settings = $container->get( 'wcgateway.settings' );
|
||||
|
@ -143,7 +158,7 @@ return array(
|
|||
}
|
||||
|
||||
$section = isset( $_GET['section'] ) ? sanitize_text_field( wp_unslash( $_GET['section'] ) ) : '';
|
||||
return in_array( $section, array( PayPalGateway::ID, CreditCardGateway::ID, WebhooksStatusPage::ID, PayUponInvoiceGateway::ID ), true );
|
||||
return in_array( $section, array( PayPalGateway::ID, CreditCardGateway::ID, WebhooksStatusPage::ID, PayUponInvoiceGateway::ID, CardButtonGateway::ID ), true );
|
||||
},
|
||||
|
||||
'wcgateway.current-ppcp-settings-page-id' => static function ( ContainerInterface $container ): string {
|
||||
|
|
|
@ -10,6 +10,7 @@ declare(strict_types=1);
|
|||
namespace WooCommerce\PayPalCommerce\WcGateway\Checkout;
|
||||
|
||||
use WooCommerce\PayPalCommerce\Session\SessionHandler;
|
||||
use WooCommerce\PayPalCommerce\WcGateway\Gateway\CardButtonGateway;
|
||||
use WooCommerce\PayPalCommerce\WcGateway\Gateway\CreditCardGateway;
|
||||
use WooCommerce\PayPalCommerce\WcGateway\Gateway\PayPalGateway;
|
||||
use Psr\Container\ContainerInterface;
|
||||
|
@ -59,9 +60,10 @@ class DisableGateways {
|
|||
if ( ! isset( $methods[ PayPalGateway::ID ] ) && ! isset( $methods[ CreditCardGateway::ID ] ) ) {
|
||||
return $methods;
|
||||
}
|
||||
if ( $this->disable_both_gateways() ) {
|
||||
if ( $this->disable_all_gateways() ) {
|
||||
unset( $methods[ PayPalGateway::ID ] );
|
||||
unset( $methods[ CreditCardGateway::ID ] );
|
||||
unset( $methods[ CardButtonGateway::ID ] );
|
||||
return $methods;
|
||||
}
|
||||
|
||||
|
@ -87,11 +89,11 @@ class DisableGateways {
|
|||
}
|
||||
|
||||
/**
|
||||
* Whether both gateways should be disabled or not.
|
||||
* Whether all gateways should be disabled or not.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
private function disable_both_gateways() : bool {
|
||||
private function disable_all_gateways() : bool {
|
||||
if ( ! $this->settings->has( 'enabled' ) || ! $this->settings->get( 'enabled' ) ) {
|
||||
return true;
|
||||
}
|
||||
|
@ -110,7 +112,8 @@ class DisableGateways {
|
|||
* @return bool
|
||||
*/
|
||||
private function needs_to_disable_gateways(): bool {
|
||||
return $this->session_handler->order() !== null;
|
||||
return $this->session_handler->order() !== null &&
|
||||
'card' !== $this->session_handler->funding_source();
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
331
modules/ppcp-wc-gateway/src/Gateway/CardButtonGateway.php
Normal file
331
modules/ppcp-wc-gateway/src/Gateway/CardButtonGateway.php
Normal file
|
@ -0,0 +1,331 @@
|
|||
<?php
|
||||
/**
|
||||
* The PayPal Card Button Gateway
|
||||
*
|
||||
* @package WooCommerce\PayPalCommerce\WcGateway\Gateway
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace WooCommerce\PayPalCommerce\WcGateway\Gateway;
|
||||
|
||||
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\Onboarding\State;
|
||||
use WooCommerce\PayPalCommerce\Session\SessionHandler;
|
||||
use WooCommerce\PayPalCommerce\Subscription\FreeTrialHandlerTrait;
|
||||
use WooCommerce\PayPalCommerce\Subscription\Helper\SubscriptionHelper;
|
||||
use WooCommerce\PayPalCommerce\Vaulting\PaymentTokenRepository;
|
||||
use WooCommerce\PayPalCommerce\WcGateway\Exception\GatewayGenericException;
|
||||
use WooCommerce\PayPalCommerce\WcGateway\Processor\OrderProcessor;
|
||||
use WooCommerce\PayPalCommerce\WcGateway\Processor\RefundProcessor;
|
||||
use Psr\Container\ContainerInterface;
|
||||
|
||||
/**
|
||||
* Class CardButtonGateway
|
||||
*/
|
||||
class CardButtonGateway extends \WC_Payment_Gateway {
|
||||
|
||||
use ProcessPaymentTrait, FreeTrialHandlerTrait;
|
||||
|
||||
const ID = 'ppcp-card-button-gateway';
|
||||
|
||||
/**
|
||||
* The processor for orders.
|
||||
*
|
||||
* @var OrderProcessor
|
||||
*/
|
||||
protected $order_processor;
|
||||
|
||||
/**
|
||||
* The settings.
|
||||
*
|
||||
* @var ContainerInterface
|
||||
*/
|
||||
protected $config;
|
||||
|
||||
/**
|
||||
* The Session Handler.
|
||||
*
|
||||
* @var SessionHandler
|
||||
*/
|
||||
protected $session_handler;
|
||||
|
||||
/**
|
||||
* The Refund Processor.
|
||||
*
|
||||
* @var RefundProcessor
|
||||
*/
|
||||
private $refund_processor;
|
||||
|
||||
/**
|
||||
* The state.
|
||||
*
|
||||
* @var State
|
||||
*/
|
||||
protected $state;
|
||||
|
||||
/**
|
||||
* Service able to provide transaction url for an order.
|
||||
*
|
||||
* @var TransactionUrlProvider
|
||||
*/
|
||||
protected $transaction_url_provider;
|
||||
|
||||
/**
|
||||
* The subscription helper.
|
||||
*
|
||||
* @var SubscriptionHelper
|
||||
*/
|
||||
protected $subscription_helper;
|
||||
|
||||
/**
|
||||
* The payment token repository.
|
||||
*
|
||||
* @var PaymentTokenRepository
|
||||
*/
|
||||
protected $payment_token_repository;
|
||||
|
||||
/**
|
||||
* Whether the plugin is in onboarded state.
|
||||
*
|
||||
* @var bool
|
||||
*/
|
||||
private $onboarded;
|
||||
|
||||
/**
|
||||
* The environment.
|
||||
*
|
||||
* @var Environment
|
||||
*/
|
||||
protected $environment;
|
||||
|
||||
/**
|
||||
* The logger.
|
||||
*
|
||||
* @var LoggerInterface
|
||||
*/
|
||||
private $logger;
|
||||
|
||||
/**
|
||||
* CardButtonGateway constructor.
|
||||
*
|
||||
* @param OrderProcessor $order_processor The Order Processor.
|
||||
* @param ContainerInterface $config The settings.
|
||||
* @param SessionHandler $session_handler The Session Handler.
|
||||
* @param RefundProcessor $refund_processor The Refund Processor.
|
||||
* @param State $state The state.
|
||||
* @param TransactionUrlProvider $transaction_url_provider Service providing transaction view URL based on order.
|
||||
* @param SubscriptionHelper $subscription_helper The subscription helper.
|
||||
* @param Environment $environment The environment.
|
||||
* @param PaymentTokenRepository $payment_token_repository The payment token repository.
|
||||
* @param LoggerInterface $logger The logger.
|
||||
*/
|
||||
public function __construct(
|
||||
OrderProcessor $order_processor,
|
||||
ContainerInterface $config,
|
||||
SessionHandler $session_handler,
|
||||
RefundProcessor $refund_processor,
|
||||
State $state,
|
||||
TransactionUrlProvider $transaction_url_provider,
|
||||
SubscriptionHelper $subscription_helper,
|
||||
Environment $environment,
|
||||
PaymentTokenRepository $payment_token_repository,
|
||||
LoggerInterface $logger
|
||||
) {
|
||||
$this->id = self::ID;
|
||||
$this->order_processor = $order_processor;
|
||||
$this->config = $config;
|
||||
$this->session_handler = $session_handler;
|
||||
$this->refund_processor = $refund_processor;
|
||||
$this->state = $state;
|
||||
$this->transaction_url_provider = $transaction_url_provider;
|
||||
$this->subscription_helper = $subscription_helper;
|
||||
$this->environment = $environment;
|
||||
$this->onboarded = $state->current_state() === State::STATE_ONBOARDED;
|
||||
$this->payment_token_repository = $payment_token_repository;
|
||||
$this->logger = $logger;
|
||||
|
||||
if ( $this->onboarded ) {
|
||||
$this->supports = array( 'refunds' );
|
||||
}
|
||||
if (
|
||||
defined( 'PPCP_FLAG_SUBSCRIPTION' )
|
||||
&& PPCP_FLAG_SUBSCRIPTION
|
||||
&& $this->gateways_enabled()
|
||||
&& $this->vault_setting_enabled()
|
||||
) {
|
||||
$this->supports = array(
|
||||
'refunds',
|
||||
'products',
|
||||
'subscriptions',
|
||||
'subscription_cancellation',
|
||||
'subscription_suspension',
|
||||
'subscription_reactivation',
|
||||
'subscription_amount_changes',
|
||||
'subscription_date_changes',
|
||||
'subscription_payment_method_change',
|
||||
'subscription_payment_method_change_customer',
|
||||
'subscription_payment_method_change_admin',
|
||||
'multiple_subscriptions',
|
||||
);
|
||||
}
|
||||
|
||||
$this->method_title = __( 'PayPal Card Button', 'woocommerce-paypal-payments' );
|
||||
$this->method_description = __( 'The separate payment gateway with the card button. If disabled, the button is included in the PayPal gateway.', 'woocommerce-paypal-payments' );
|
||||
$this->title = $this->get_option( 'title', __( 'Debit & Credit Cards', 'woocommerce-paypal-payments' ) );
|
||||
$this->description = $this->get_option( 'description', '' );
|
||||
|
||||
$this->init_form_fields();
|
||||
$this->init_settings();
|
||||
|
||||
add_action(
|
||||
'woocommerce_update_options_payment_gateways_' . $this->id,
|
||||
array(
|
||||
$this,
|
||||
'process_admin_options',
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Whether the Gateway needs to be setup.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function needs_setup(): bool {
|
||||
return ! $this->onboarded;
|
||||
}
|
||||
|
||||
/**
|
||||
* Initializes the form fields.
|
||||
*/
|
||||
public function init_form_fields() {
|
||||
$this->form_fields = array(
|
||||
'enabled' => array(
|
||||
'title' => __( 'Enable/Disable', 'woocommerce-paypal-payments' ),
|
||||
'type' => 'checkbox',
|
||||
'label' => __( 'PayPal Card Button', 'woocommerce-paypal-payments' ),
|
||||
'default' => 'no',
|
||||
'desc_tip' => true,
|
||||
'description' => __( 'Enable/Disable the separate payment gateway with the card button.', 'woocommerce-paypal-payments' ),
|
||||
),
|
||||
'title' => array(
|
||||
'title' => __( 'Title', 'woocommerce-paypal-payments' ),
|
||||
'type' => 'text',
|
||||
'default' => $this->title,
|
||||
'desc_tip' => true,
|
||||
'description' => __( 'This controls the title which the user sees during checkout.', 'woocommerce-paypal-payments' ),
|
||||
),
|
||||
'description' => array(
|
||||
'title' => __( 'Description', 'woocommerce-paypal-payments' ),
|
||||
'type' => 'text',
|
||||
'default' => $this->description,
|
||||
'desc_tip' => true,
|
||||
'description' => __( 'This controls the description which the user sees during checkout.', 'woocommerce-paypal-payments' ),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Process payment for a WooCommerce order.
|
||||
*
|
||||
* @param int $order_id The WooCommerce order id.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function process_payment( $order_id ) {
|
||||
$wc_order = wc_get_order( $order_id );
|
||||
if ( ! is_a( $wc_order, WC_Order::class ) ) {
|
||||
return $this->handle_payment_failure(
|
||||
null,
|
||||
new GatewayGenericException( new Exception( 'WC order was not found.' ) )
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* If customer has chosen change Subscription payment.
|
||||
*/
|
||||
if ( $this->subscription_helper->has_subscription( $order_id ) && $this->subscription_helper->is_subscription_change_payment() ) {
|
||||
$saved_paypal_payment = filter_input( INPUT_POST, 'saved_paypal_payment', FILTER_SANITIZE_STRING );
|
||||
if ( $saved_paypal_payment ) {
|
||||
update_post_meta( $order_id, 'payment_token_id', $saved_paypal_payment );
|
||||
|
||||
return $this->handle_payment_success( $wc_order );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* If the WC_Order is paid through the approved webhook.
|
||||
*/
|
||||
//phpcs:disable WordPress.Security.NonceVerification.Recommended
|
||||
if ( isset( $_REQUEST['ppcp-resume-order'] ) && $wc_order->has_status( 'processing' ) ) {
|
||||
return $this->handle_payment_success( $wc_order );
|
||||
}
|
||||
//phpcs:enable WordPress.Security.NonceVerification.Recommended
|
||||
|
||||
try {
|
||||
if ( ! $this->order_processor->process( $wc_order ) ) {
|
||||
return $this->handle_payment_failure(
|
||||
$wc_order,
|
||||
new Exception(
|
||||
$this->order_processor->last_error()
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
if ( $this->subscription_helper->has_subscription( $order_id ) ) {
|
||||
$this->schedule_saved_payment_check( $order_id, $wc_order->get_customer_id() );
|
||||
}
|
||||
|
||||
return $this->handle_payment_success( $wc_order );
|
||||
} catch ( PayPalApiException $error ) {
|
||||
return $this->handle_payment_failure(
|
||||
$wc_order,
|
||||
new Exception(
|
||||
Messages::generic_payment_error_message() . ' ' . $error->getMessage(),
|
||||
$error->getCode(),
|
||||
$error
|
||||
)
|
||||
);
|
||||
} catch ( RuntimeException $error ) {
|
||||
return $this->handle_payment_failure( $wc_order, $error );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Process refund.
|
||||
*
|
||||
* If the gateway declares 'refunds' support, this will allow it to refund.
|
||||
* a passed in amount.
|
||||
*
|
||||
* @param int $order_id Order ID.
|
||||
* @param float $amount Refund amount.
|
||||
* @param string $reason Refund reason.
|
||||
* @return boolean True or false based on success, or a WP_Error object.
|
||||
*/
|
||||
public function process_refund( $order_id, $amount = null, $reason = '' ) {
|
||||
$order = wc_get_order( $order_id );
|
||||
if ( ! is_a( $order, \WC_Order::class ) ) {
|
||||
return false;
|
||||
}
|
||||
return $this->refund_processor->process( $order, (float) $amount, (string) $reason );
|
||||
}
|
||||
|
||||
/**
|
||||
* Return transaction url for this gateway and given order.
|
||||
*
|
||||
* @param \WC_Order $order WC order to get transaction url by.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function get_transaction_url( $order ): string {
|
||||
$this->view_transaction_url = $this->transaction_url_provider->get_transaction_url_base( $order );
|
||||
|
||||
return parent::get_transaction_url( $order );
|
||||
}
|
||||
}
|
|
@ -9,6 +9,7 @@ declare( strict_types=1 );
|
|||
|
||||
namespace WooCommerce\PayPalCommerce\WcGateway\Settings;
|
||||
|
||||
use WooCommerce\PayPalCommerce\WcGateway\Gateway\CardButtonGateway;
|
||||
use WooCommerce\PayPalCommerce\WcGateway\Gateway\CreditCardGateway;
|
||||
use WooCommerce\PayPalCommerce\WcGateway\Gateway\PayPalGateway;
|
||||
use WooCommerce\PayPalCommerce\WcGateway\Gateway\PayUponInvoice\PayUponInvoiceGateway;
|
||||
|
@ -58,7 +59,7 @@ class SectionsRenderer {
|
|||
/**
|
||||
* Renders the Sections tab.
|
||||
*/
|
||||
public function render() {
|
||||
public function render(): void {
|
||||
if ( ! $this->should_render() ) {
|
||||
return;
|
||||
}
|
||||
|
@ -66,6 +67,7 @@ class SectionsRenderer {
|
|||
$sections = array(
|
||||
PayPalGateway::ID => __( 'PayPal Checkout', 'woocommerce-paypal-payments' ),
|
||||
CreditCardGateway::ID => __( 'PayPal Card Processing', 'woocommerce-paypal-payments' ),
|
||||
CardButtonGateway::ID => __( 'PayPal Card Button', 'woocommerce-paypal-payments' ),
|
||||
PayUponInvoiceGateway::ID => __( 'Pay upon Invoice', 'woocommerce-paypal-payments' ),
|
||||
WebhooksStatusPage::ID => __( 'Webhooks Status', 'woocommerce-paypal-payments' ),
|
||||
);
|
||||
|
@ -80,8 +82,8 @@ class SectionsRenderer {
|
|||
|
||||
foreach ( $sections as $id => $label ) {
|
||||
$url = admin_url( 'admin.php?page=wc-settings&tab=checkout§ion=ppcp-gateway&' . self::KEY . '=' . $id );
|
||||
if ( PayUponInvoiceGateway::ID === $id ) {
|
||||
$url = admin_url( 'admin.php?page=wc-settings&tab=checkout§ion=ppcp-pay-upon-invoice-gateway' );
|
||||
if ( in_array( $id, array( PayUponInvoiceGateway::ID, CardButtonGateway::ID ), true ) ) {
|
||||
$url = admin_url( 'admin.php?page=wc-settings&tab=checkout§ion=' . $id );
|
||||
}
|
||||
echo '<li><a href="' . esc_url( $url ) . '" class="' . ( $this->page_id === $id ? 'current' : '' ) . '">' . esc_html( $label ) . '</a> ' . ( end( $array_keys ) === $id ? '' : '|' ) . ' </li>';
|
||||
}
|
||||
|
|
|
@ -284,6 +284,8 @@ class WCGatewayModule implements ModuleInterface {
|
|||
$methods[] = $container->get( 'wcgateway.credit-card-gateway' );
|
||||
}
|
||||
|
||||
$methods[] = $container->get( 'wcgateway.card-button-gateway' );
|
||||
|
||||
if ( 'DE' === $container->get( 'api.shop.country' ) && 'EUR' === $container->get( 'api.shop.currency' ) ) {
|
||||
$methods[] = $container->get( 'wcgateway.pay-upon-invoice-gateway' );
|
||||
}
|
||||
|
|
|
@ -4,7 +4,7 @@ declare(strict_types=1);
|
|||
class WC_Payment_Gateway
|
||||
{
|
||||
|
||||
protected function get_option(string $key) : string {
|
||||
public function get_option(string $key, $empty_value = null) {
|
||||
return $key;
|
||||
}
|
||||
|
||||
|
@ -19,4 +19,4 @@ class WC_Payment_Gateway
|
|||
public function process_admin_options() {
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue