mirror of
https://github.com/woocommerce/woocommerce-paypal-payments.git
synced 2025-09-05 08:59:14 +08:00
Merge branch 'trunk' into PCP-726-add-oxxo-apm-alternative-payment
This commit is contained in:
commit
1049fda586
49 changed files with 1586 additions and 668 deletions
|
@ -1,6 +1,6 @@
|
|||
*** Changelog ***
|
||||
|
||||
= 1.9.1 - TBD =
|
||||
= 1.9.1 - 2022-07-25 =
|
||||
* Fix - ITEM_TOTAL_MISMATCH error when checking out with multiple products #721
|
||||
* Fix - Unable to purchase a product with Credit card button in pay for order page #718
|
||||
* Fix - Pay Later messaging only displayed when smart button is active on the same page #283
|
||||
|
|
|
@ -400,6 +400,60 @@ return array(
|
|||
);
|
||||
},
|
||||
|
||||
|
||||
'api.shop.is-latin-america' => static function ( ContainerInterface $container ): bool {
|
||||
return in_array(
|
||||
$container->get( 'api.shop.country' ),
|
||||
array(
|
||||
'AI',
|
||||
'AG',
|
||||
'AR',
|
||||
'AW',
|
||||
'BS',
|
||||
'BB',
|
||||
'BZ',
|
||||
'BM',
|
||||
'BO',
|
||||
'BR',
|
||||
'VG',
|
||||
'KY',
|
||||
'CL',
|
||||
'CO',
|
||||
'CR',
|
||||
'DM',
|
||||
'DO',
|
||||
'EC',
|
||||
'SV',
|
||||
'FK',
|
||||
'GF',
|
||||
'GD',
|
||||
'GP',
|
||||
'GT',
|
||||
'GY',
|
||||
'HN',
|
||||
'JM',
|
||||
'MQ',
|
||||
'MX',
|
||||
'MS',
|
||||
'AN',
|
||||
'NI',
|
||||
'PA',
|
||||
'PY',
|
||||
'PE',
|
||||
'KN',
|
||||
'LC',
|
||||
'PM',
|
||||
'VC',
|
||||
'SR',
|
||||
'TT',
|
||||
'TC',
|
||||
'UY',
|
||||
'VE',
|
||||
),
|
||||
true
|
||||
);
|
||||
},
|
||||
|
||||
/**
|
||||
* Currencies supported by PayPal.
|
||||
*
|
||||
|
|
|
@ -106,7 +106,7 @@ class IdentityToken {
|
|||
&& defined( 'PPCP_FLAG_SUBSCRIPTION' ) && PPCP_FLAG_SUBSCRIPTION
|
||||
) {
|
||||
$customer_id = $this->customer_repository->customer_id_for_user( ( $user_id ) );
|
||||
|
||||
update_user_meta( $user_id, 'ppcp_customer_id', $customer_id );
|
||||
$args['body'] = wp_json_encode(
|
||||
array(
|
||||
'customer_id' => $customer_id,
|
||||
|
|
|
@ -194,7 +194,7 @@ class OrderEndpoint {
|
|||
'application_context' => $this->application_context_repository
|
||||
->current_context( $shipping_preference )->to_array(),
|
||||
);
|
||||
if ( $payer && ! empty( $payer->email_address() ) && ! empty( $payer->name() ) ) {
|
||||
if ( $payer && ! empty( $payer->email_address() ) ) {
|
||||
$data['payer'] = $payer->to_array();
|
||||
}
|
||||
if ( $payment_token ) {
|
||||
|
|
|
@ -18,7 +18,7 @@ class Payer {
|
|||
/**
|
||||
* The name.
|
||||
*
|
||||
* @var PayerName
|
||||
* @var PayerName|null
|
||||
*/
|
||||
private $name;
|
||||
|
||||
|
@ -46,7 +46,7 @@ class Payer {
|
|||
/**
|
||||
* The address.
|
||||
*
|
||||
* @var Address
|
||||
* @var Address|null
|
||||
*/
|
||||
private $address;
|
||||
|
||||
|
@ -67,7 +67,7 @@ class Payer {
|
|||
/**
|
||||
* Payer constructor.
|
||||
*
|
||||
* @param PayerName $name The name.
|
||||
* @param PayerName|null $name The name.
|
||||
* @param string $email_address The email.
|
||||
* @param string $payer_id The payer id.
|
||||
* @param Address|null $address The address.
|
||||
|
@ -76,7 +76,7 @@ class Payer {
|
|||
* @param PayerTaxInfo|null $tax_info The tax info.
|
||||
*/
|
||||
public function __construct(
|
||||
PayerName $name,
|
||||
?PayerName $name,
|
||||
string $email_address,
|
||||
string $payer_id,
|
||||
Address $address = null,
|
||||
|
@ -97,12 +97,21 @@ class Payer {
|
|||
/**
|
||||
* Returns the name.
|
||||
*
|
||||
* @return PayerName
|
||||
* @return PayerName|null
|
||||
*/
|
||||
public function name(): PayerName {
|
||||
public function name(): ?PayerName {
|
||||
return $this->name;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the name.
|
||||
*
|
||||
* @param PayerName|null $name The value.
|
||||
*/
|
||||
public function set_name( ?PayerName $name ): void {
|
||||
$this->name = $name;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the email address.
|
||||
*
|
||||
|
@ -139,6 +148,15 @@ class Payer {
|
|||
return $this->address;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the address.
|
||||
*
|
||||
* @param Address|null $address The value.
|
||||
*/
|
||||
public function set_address( ?Address $address ): void {
|
||||
$this->address = $address;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the phone.
|
||||
*
|
||||
|
@ -164,27 +182,26 @@ class Payer {
|
|||
*/
|
||||
public function to_array() {
|
||||
$payer = array(
|
||||
'name' => $this->name()->to_array(),
|
||||
'email_address' => $this->email_address(),
|
||||
);
|
||||
if ( $this->address() ) {
|
||||
$payer['address'] = $this->address->to_array();
|
||||
if ( 2 !== strlen( $this->address()->country_code() ) ) {
|
||||
unset( $payer['address'] );
|
||||
}
|
||||
if ( $this->name ) {
|
||||
$payer['name'] = $this->name->to_array();
|
||||
}
|
||||
if ( $this->payer_id() ) {
|
||||
$payer['payer_id'] = $this->payer_id();
|
||||
if ( $this->address && 2 === strlen( $this->address->country_code() ) ) {
|
||||
$payer['address'] = $this->address->to_array();
|
||||
}
|
||||
if ( $this->payer_id ) {
|
||||
$payer['payer_id'] = $this->payer_id;
|
||||
}
|
||||
|
||||
if ( $this->phone() ) {
|
||||
$payer['phone'] = $this->phone()->to_array();
|
||||
if ( $this->phone ) {
|
||||
$payer['phone'] = $this->phone->to_array();
|
||||
}
|
||||
if ( $this->tax_info() ) {
|
||||
$payer['tax_info'] = $this->tax_info()->to_array();
|
||||
if ( $this->tax_info ) {
|
||||
$payer['tax_info'] = $this->tax_info->to_array();
|
||||
}
|
||||
if ( $this->birthdate() ) {
|
||||
$payer['birth_date'] = $this->birthdate()->format( 'Y-m-d' );
|
||||
if ( $this->birthdate ) {
|
||||
$payer['birth_date'] = $this->birthdate->format( 'Y-m-d' );
|
||||
}
|
||||
return $payer;
|
||||
}
|
||||
|
|
|
@ -111,15 +111,6 @@ class PayPalApiException extends RuntimeException {
|
|||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns response issues.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function issues(): array {
|
||||
return $this->response->issues ?? array();
|
||||
}
|
||||
|
||||
/**
|
||||
* The HTTP status code.
|
||||
*
|
||||
|
|
|
@ -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 )
|
||||
|
|
|
@ -57,6 +57,6 @@ class CustomerRepository {
|
|||
return $guest_customer_id;
|
||||
}
|
||||
|
||||
return $this->prefix . (string) $user_id;
|
||||
return get_user_meta( $user_id, 'ppcp_customer_id', true ) ?: $this->prefix . (string) $user_id;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -3,6 +3,9 @@
|
|||
"version": "1.0.0",
|
||||
"license": "GPL-3.0-or-later",
|
||||
"main": "resources/js/button.js",
|
||||
"dependencies": {
|
||||
"deepmerge": "^4.2.2"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@babel/core": "^7.9.0",
|
||||
"@babel/preset-env": "^7.9.5",
|
||||
|
|
|
@ -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 = () => {
|
||||
|
@ -38,9 +40,36 @@ const bootstrap = () => {
|
|||
requiredFields.each((i, input) => {
|
||||
jQuery(input).trigger('validate');
|
||||
});
|
||||
if (jQuery('form.woocommerce-checkout .validate-required.woocommerce-invalid:visible').length) {
|
||||
const invalidFields = Array.from(jQuery('form.woocommerce-checkout .validate-required.woocommerce-invalid:visible'));
|
||||
if (invalidFields.length) {
|
||||
const billingFieldsContainer = document.querySelector('.woocommerce-billing-fields');
|
||||
const shippingFieldsContainer = document.querySelector('.woocommerce-shipping-fields');
|
||||
|
||||
const nameMessageMap = PayPalCommerceGateway.labels.error.required.elements;
|
||||
const messages = invalidFields.map(el => {
|
||||
const name = el.querySelector('[name]')?.getAttribute('name');
|
||||
if (name && name in nameMessageMap) {
|
||||
return nameMessageMap[name];
|
||||
}
|
||||
let label = el.querySelector('label').textContent
|
||||
.replaceAll('*', '')
|
||||
.trim();
|
||||
if (billingFieldsContainer?.contains(el)) {
|
||||
label = PayPalCommerceGateway.labels.billing_field.replace('%s', label);
|
||||
}
|
||||
if (shippingFieldsContainer?.contains(el)) {
|
||||
label = PayPalCommerceGateway.labels.shipping_field.replace('%s', label);
|
||||
}
|
||||
return PayPalCommerceGateway.labels.error.required.field
|
||||
.replace('%s', `<strong>${label}</strong>`)
|
||||
}).filter(s => s.length > 2);
|
||||
|
||||
errorHandler.clear();
|
||||
errorHandler.message(PayPalCommerceGateway.labels.error.js_validation);
|
||||
if (messages.length) {
|
||||
messages.forEach(s => errorHandler.message(s));
|
||||
} else {
|
||||
errorHandler.message(PayPalCommerceGateway.labels.error.required.generic);
|
||||
}
|
||||
|
||||
return actions.reject();
|
||||
}
|
||||
|
@ -83,7 +112,7 @@ const bootstrap = () => {
|
|||
PayPalCommerceGateway,
|
||||
renderer,
|
||||
messageRenderer,
|
||||
);
|
||||
);w
|
||||
|
||||
singleProductBootstrap.init();
|
||||
}
|
||||
|
@ -138,6 +167,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 +187,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 {
|
||||
|
|
|
@ -26,6 +26,9 @@ class CheckoutActionHandler {
|
|||
|
||||
const createaccount = jQuery('#createaccount').is(":checked") ? true : false;
|
||||
|
||||
const paymentMethod = getCurrentPaymentMethod();
|
||||
const fundingSource = window.ppcpFundingSource;
|
||||
|
||||
return fetch(this.config.ajax.create_order.endpoint, {
|
||||
method: 'POST',
|
||||
body: JSON.stringify({
|
||||
|
@ -34,8 +37,8 @@ class CheckoutActionHandler {
|
|||
bn_code:bnCode,
|
||||
context:this.config.context,
|
||||
order_id:this.config.order_id,
|
||||
payment_method: getCurrentPaymentMethod(),
|
||||
funding_source: window.ppcpFundingSource,
|
||||
payment_method: paymentMethod,
|
||||
funding_source: fundingSource,
|
||||
form: formJsonObj,
|
||||
createaccount: createaccount
|
||||
})
|
||||
|
|
|
@ -32,9 +32,7 @@ class CartBootstrap {
|
|||
);
|
||||
|
||||
this.renderer.render(
|
||||
this.gateway.button.wrapper,
|
||||
this.gateway.hosted_fields.wrapper,
|
||||
actionHandler.configuration(),
|
||||
actionHandler.configuration()
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -69,9 +69,7 @@ class CheckoutBootstap {
|
|||
);
|
||||
|
||||
this.renderer.render(
|
||||
this.gateway.button.wrapper,
|
||||
this.gateway.hosted_fields.wrapper,
|
||||
actionHandler.configuration(),
|
||||
actionHandler.configuration()
|
||||
);
|
||||
|
||||
this.buttonChangeObserver.observe(
|
||||
|
@ -84,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();
|
||||
|
|
|
@ -32,9 +32,13 @@ class MiniCartBootstap {
|
|||
}
|
||||
|
||||
this.renderer.render(
|
||||
this.gateway.button.mini_cart_wrapper,
|
||||
this.gateway.hosted_fields.mini_cart_wrapper,
|
||||
this.actionHandler.configuration()
|
||||
this.actionHandler.configuration(),
|
||||
{
|
||||
button: {
|
||||
wrapper: this.gateway.button.mini_cart_wrapper,
|
||||
style: this.gateway.button.mini_cart_style,
|
||||
},
|
||||
}
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -85,9 +85,7 @@ class SingleProductBootstap {
|
|||
);
|
||||
|
||||
this.renderer.render(
|
||||
this.gateway.button.wrapper,
|
||||
this.gateway.hosted_fields.wrapper,
|
||||
actionHandler.configuration(),
|
||||
actionHandler.configuration()
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2,6 +2,7 @@ export const PaymentMethods = {
|
|||
PAYPAL: 'ppcp-gateway',
|
||||
CARDS: 'ppcp-credit-card-gateway',
|
||||
OXXO: 'ppcp-oxxo-gateway',
|
||||
CARD_BUTTON: 'ppcp-card-button-gateway',
|
||||
};
|
||||
|
||||
export const ORDER_BUTTON_SELECTOR = '#place_order';
|
||||
|
|
|
@ -1,33 +1,86 @@
|
|||
import merge from "deepmerge";
|
||||
|
||||
class Renderer {
|
||||
constructor(creditCardRenderer, defaultConfig, onSmartButtonClick, onSmartButtonsInit) {
|
||||
this.defaultConfig = defaultConfig;
|
||||
constructor(creditCardRenderer, defaultSettings, onSmartButtonClick, onSmartButtonsInit) {
|
||||
this.defaultSettings = defaultSettings;
|
||||
this.creditCardRenderer = creditCardRenderer;
|
||||
this.onSmartButtonClick = onSmartButtonClick;
|
||||
this.onSmartButtonsInit = onSmartButtonsInit;
|
||||
|
||||
this.renderedSources = new Set();
|
||||
}
|
||||
|
||||
render(wrapper, hostedFieldsWrapper, contextConfig) {
|
||||
render(contextConfig, settingsOverride = {}) {
|
||||
const settings = merge(this.defaultSettings, settingsOverride);
|
||||
|
||||
this.renderButtons(wrapper, contextConfig);
|
||||
this.creditCardRenderer.render(hostedFieldsWrapper, contextConfig);
|
||||
const enabledSeparateGateways = Object.fromEntries(Object.entries(
|
||||
settings.separate_buttons).filter(([s, data]) => document.querySelector(data.wrapper)
|
||||
));
|
||||
const hasEnabledSeparateGateways = Object.keys(enabledSeparateGateways).length !== 0;
|
||||
|
||||
if (!hasEnabledSeparateGateways) {
|
||||
this.renderButtons(
|
||||
settings.button.wrapper,
|
||||
settings.button.style,
|
||||
contextConfig
|
||||
);
|
||||
} else {
|
||||
// render each button separately
|
||||
for (const fundingSource of paypal.getFundingSources().filter(s => !(s in enabledSeparateGateways))) {
|
||||
let style = settings.button.style;
|
||||
if (fundingSource !== 'paypal') {
|
||||
style = {
|
||||
shape: style.shape,
|
||||
};
|
||||
}
|
||||
|
||||
this.renderButtons(
|
||||
settings.button.wrapper,
|
||||
style,
|
||||
contextConfig,
|
||||
fundingSource
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
this.creditCardRenderer.render(settings.hosted_fields.wrapper, contextConfig);
|
||||
|
||||
for (const [fundingSource, data] of Object.entries(enabledSeparateGateways)) {
|
||||
this.renderButtons(
|
||||
data.wrapper,
|
||||
data.style,
|
||||
contextConfig,
|
||||
fundingSource
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
renderButtons(wrapper, contextConfig) {
|
||||
if (! document.querySelector(wrapper) || this.isAlreadyRendered(wrapper) || 'undefined' === typeof paypal.Buttons ) {
|
||||
renderButtons(wrapper, style, contextConfig, fundingSource = null) {
|
||||
if (! document.querySelector(wrapper) || this.isAlreadyRendered(wrapper, fundingSource) || 'undefined' === typeof paypal.Buttons ) {
|
||||
return;
|
||||
}
|
||||
|
||||
const style = wrapper === this.defaultConfig.button.wrapper ? this.defaultConfig.button.style : this.defaultConfig.button.mini_cart_style;
|
||||
paypal.Buttons({
|
||||
if (fundingSource) {
|
||||
contextConfig.fundingSource = fundingSource;
|
||||
}
|
||||
|
||||
const btn = paypal.Buttons({
|
||||
style,
|
||||
...contextConfig,
|
||||
onClick: this.onSmartButtonClick,
|
||||
onInit: this.onSmartButtonsInit,
|
||||
}).render(wrapper);
|
||||
});
|
||||
if (!btn.isEligible()) {
|
||||
return;
|
||||
}
|
||||
|
||||
btn.render(wrapper);
|
||||
|
||||
this.renderedSources.add(wrapper + fundingSource ?? '');
|
||||
}
|
||||
|
||||
isAlreadyRendered(wrapper) {
|
||||
return document.querySelector(wrapper).hasChildNodes();
|
||||
isAlreadyRendered(wrapper, fundingSource) {
|
||||
return this.renderedSources.has(wrapper + fundingSource ?? '');
|
||||
}
|
||||
|
||||
hideButtons(element) {
|
||||
|
|
|
@ -133,6 +133,7 @@ return array(
|
|||
$settings,
|
||||
$early_order_handler,
|
||||
$registration_needed,
|
||||
$container->get( 'wcgateway.settings.card_billing_data_mode' ),
|
||||
$logger
|
||||
);
|
||||
},
|
||||
|
|
|
@ -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,10 +845,19 @@ 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',
|
||||
'mini_cart_wrapper' => '#ppcp-hosted-fields-mini-cart',
|
||||
'labels' => array(
|
||||
'wrapper' => '#ppcp-hosted-fields',
|
||||
'labels' => array(
|
||||
'credit_card_number' => '',
|
||||
'cvv' => '',
|
||||
'mm_yy' => __( 'MM/YY', 'woocommerce-paypal-payments' ),
|
||||
|
@ -847,21 +871,36 @@ class SmartButton implements SmartButtonInterface {
|
|||
),
|
||||
'cardholder_name_required' => __( 'Cardholder\'s first and last name are required, please fill the checkout form required fields.', 'woocommerce-paypal-payments' ),
|
||||
),
|
||||
'valid_cards' => $this->dcc_applies->valid_cards(),
|
||||
'contingency' => $this->get_3ds_contingency(),
|
||||
'valid_cards' => $this->dcc_applies->valid_cards(),
|
||||
'contingency' => $this->get_3ds_contingency(),
|
||||
),
|
||||
'messages' => $this->message_values(),
|
||||
'labels' => array(
|
||||
'error' => array(
|
||||
'generic' => __(
|
||||
'error' => array(
|
||||
'generic' => __(
|
||||
'Something went wrong. Please try again or choose another payment source.',
|
||||
'woocommerce-paypal-payments'
|
||||
),
|
||||
'js_validation' => __(
|
||||
'Required form fields are not filled or invalid.',
|
||||
'woocommerce-paypal-payments'
|
||||
'required' => array(
|
||||
'generic' => __(
|
||||
'Required form fields are not filled.',
|
||||
'woocommerce-paypal-payments'
|
||||
),
|
||||
// phpcs:ignore WordPress.WP.I18n
|
||||
'field' => __( '%s is a required field.', 'woocommerce' ),
|
||||
'elements' => array( // Map <form element name> => text for error messages.
|
||||
'terms' => __(
|
||||
'Please read and accept the terms and conditions to proceed with your order.',
|
||||
// phpcs:ignore WordPress.WP.I18n.TextDomainMismatch
|
||||
'woocommerce'
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
// phpcs:ignore WordPress.WP.I18n
|
||||
'billing_field' => _x( 'Billing %s', 'checkout-validation', 'woocommerce' ),
|
||||
// phpcs:ignore WordPress.WP.I18n
|
||||
'shipping_field' => _x( 'Shipping %s', 'checkout-validation', 'woocommerce' ),
|
||||
),
|
||||
'order_id' => 'pay-now' === $this->context() ? absint( $wp->query_vars['order-pay'] ) : 0,
|
||||
'single_product_buttons_enabled' => $this->settings->has( 'button_product_enabled' ) && $this->settings->get( 'button_product_enabled' ),
|
||||
|
@ -933,7 +972,10 @@ class SmartButton implements SmartButtonInterface {
|
|||
|
||||
$is_dcc_enabled = $this->settings->has( 'dcc_enabled' ) && $this->settings->get( 'dcc_enabled' );
|
||||
|
||||
if ( is_checkout() && $is_dcc_enabled ) {
|
||||
$available_gateways = WC()->payment_gateways->get_available_payment_gateways();
|
||||
$is_separate_card_enabled = isset( $available_gateways[ CardButtonGateway::ID ] );
|
||||
|
||||
if ( is_checkout() && ( $is_dcc_enabled || $is_separate_card_enabled ) ) {
|
||||
$key = array_search( 'card', $disable_funding, true );
|
||||
if ( false !== $key ) {
|
||||
unset( $disable_funding[ $key ] );
|
||||
|
@ -1018,6 +1060,7 @@ class SmartButton implements SmartButtonInterface {
|
|||
|
||||
if ( $this->load_button_component() ) {
|
||||
$components[] = 'buttons';
|
||||
$components[] = 'funding-eligibility';
|
||||
}
|
||||
if (
|
||||
$this->messages_apply->for_country()
|
||||
|
@ -1112,6 +1155,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;
|
||||
}
|
||||
|
||||
|
|
|
@ -14,6 +14,7 @@ use Psr\Log\LoggerInterface;
|
|||
use stdClass;
|
||||
use WooCommerce\PayPalCommerce\ApiClient\Endpoint\OrderEndpoint;
|
||||
use WooCommerce\PayPalCommerce\ApiClient\Entity\Amount;
|
||||
use WooCommerce\PayPalCommerce\ApiClient\Entity\ApplicationContext;
|
||||
use WooCommerce\PayPalCommerce\ApiClient\Entity\Money;
|
||||
use WooCommerce\PayPalCommerce\ApiClient\Entity\Order;
|
||||
use WooCommerce\PayPalCommerce\ApiClient\Entity\Payer;
|
||||
|
@ -27,7 +28,9 @@ use WooCommerce\PayPalCommerce\ApiClient\Factory\ShippingPreferenceFactory;
|
|||
use WooCommerce\PayPalCommerce\Button\Helper\EarlyOrderHandler;
|
||||
use WooCommerce\PayPalCommerce\Session\SessionHandler;
|
||||
use WooCommerce\PayPalCommerce\Subscription\FreeTrialHandlerTrait;
|
||||
use WooCommerce\PayPalCommerce\WcGateway\CardBillingMode;
|
||||
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;
|
||||
|
@ -118,6 +121,13 @@ class CreateOrderEndpoint implements EndpointInterface {
|
|||
*/
|
||||
private $registration_needed;
|
||||
|
||||
/**
|
||||
* The value of card_billing_data_mode from the settings.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $card_billing_data_mode;
|
||||
|
||||
/**
|
||||
* The logger.
|
||||
*
|
||||
|
@ -137,6 +147,7 @@ class CreateOrderEndpoint implements EndpointInterface {
|
|||
* @param Settings $settings The Settings object.
|
||||
* @param EarlyOrderHandler $early_order_handler The EarlyOrderHandler object.
|
||||
* @param bool $registration_needed Whether a new user must be registered during checkout.
|
||||
* @param string $card_billing_data_mode The value of card_billing_data_mode from the settings.
|
||||
* @param LoggerInterface $logger The logger.
|
||||
*/
|
||||
public function __construct(
|
||||
|
@ -149,6 +160,7 @@ class CreateOrderEndpoint implements EndpointInterface {
|
|||
Settings $settings,
|
||||
EarlyOrderHandler $early_order_handler,
|
||||
bool $registration_needed,
|
||||
string $card_billing_data_mode,
|
||||
LoggerInterface $logger
|
||||
) {
|
||||
|
||||
|
@ -161,6 +173,7 @@ class CreateOrderEndpoint implements EndpointInterface {
|
|||
$this->settings = $settings;
|
||||
$this->early_order_handler = $early_order_handler;
|
||||
$this->registration_needed = $registration_needed;
|
||||
$this->card_billing_data_mode = $card_billing_data_mode;
|
||||
$this->logger = $logger;
|
||||
}
|
||||
|
||||
|
@ -204,7 +217,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()
|
||||
|
@ -331,18 +344,40 @@ class CreateOrderEndpoint implements EndpointInterface {
|
|||
private function create_paypal_order( \WC_Order $wc_order = null ): Order {
|
||||
assert( $this->purchase_unit instanceof PurchaseUnit );
|
||||
|
||||
$funding_source = $this->parsed_request_data['funding_source'] ?? '';
|
||||
$payer = $this->payer( $this->parsed_request_data, $wc_order );
|
||||
|
||||
$shipping_preference = $this->shipping_preference_factory->from_state(
|
||||
$this->purchase_unit,
|
||||
$this->parsed_request_data['context'],
|
||||
WC()->cart,
|
||||
$this->parsed_request_data['funding_source'] ?? ''
|
||||
$funding_source
|
||||
);
|
||||
|
||||
if ( 'card' === $funding_source ) {
|
||||
if ( CardBillingMode::MINIMAL_INPUT === $this->card_billing_data_mode ) {
|
||||
if ( ApplicationContext::SHIPPING_PREFERENCE_SET_PROVIDED_ADDRESS === $shipping_preference ) {
|
||||
if ( $payer ) {
|
||||
$payer->set_address( null );
|
||||
}
|
||||
}
|
||||
if ( ApplicationContext::SHIPPING_PREFERENCE_NO_SHIPPING === $shipping_preference ) {
|
||||
if ( $payer ) {
|
||||
$payer->set_name( null );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ( CardBillingMode::NO_WC === $this->card_billing_data_mode ) {
|
||||
$payer = null;
|
||||
}
|
||||
}
|
||||
|
||||
try {
|
||||
return $this->api_endpoint->create(
|
||||
array( $this->purchase_unit ),
|
||||
$shipping_preference,
|
||||
$this->payer( $this->parsed_request_data, $wc_order ),
|
||||
$payer,
|
||||
null,
|
||||
$this->payment_method()
|
||||
);
|
||||
|
@ -364,7 +399,7 @@ class CreateOrderEndpoint implements EndpointInterface {
|
|||
return $this->api_endpoint->create(
|
||||
array( $this->purchase_unit ),
|
||||
$shipping_preference,
|
||||
$this->payer( $this->parsed_request_data, $wc_order ),
|
||||
$payer,
|
||||
null,
|
||||
$this->payment_method()
|
||||
);
|
||||
|
|
|
@ -1353,6 +1353,11 @@ debug@^4.1.0, debug@^4.1.1:
|
|||
dependencies:
|
||||
ms "2.1.2"
|
||||
|
||||
deepmerge@^4.2.2:
|
||||
version "4.2.2"
|
||||
resolved "https://registry.yarnpkg.com/deepmerge/-/deepmerge-4.2.2.tgz#44d2ea3679b8f4d4ffba33f03d865fc1e7bf4955"
|
||||
integrity sha512-FJ3UgI4gIl+PHZm53knsuSFpE+nESMr7M4v9QcgB7S63Kj/6WqMiFQJpBBYz1Pt+66bZpP3Q7Lye0Oo9MPKEdg==
|
||||
|
||||
define-properties@^1.1.3:
|
||||
version "1.1.3"
|
||||
resolved "https://registry.yarnpkg.com/define-properties/-/define-properties-1.1.3.tgz#cf88da6cbee26fe6db7094f61d870cbd84cee9f1"
|
||||
|
|
|
@ -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',
|
||||
|
|
|
@ -24,6 +24,8 @@ return array(
|
|||
$purchase_unit_factory = $container->get( 'api.factory.purchase-unit' );
|
||||
$payer_factory = $container->get( 'api.factory.payer' );
|
||||
$environment = $container->get( 'onboarding.environment' );
|
||||
$settings = $container->get( 'wcgateway.settings' );
|
||||
$authorized_payments_processor = $container->get( 'wcgateway.processor.authorized-payments' );
|
||||
return new RenewalHandler(
|
||||
$logger,
|
||||
$repository,
|
||||
|
@ -31,7 +33,9 @@ return array(
|
|||
$purchase_unit_factory,
|
||||
$container->get( 'api.factory.shipping-preference' ),
|
||||
$payer_factory,
|
||||
$environment
|
||||
$environment,
|
||||
$settings,
|
||||
$authorized_payments_processor
|
||||
);
|
||||
},
|
||||
'subscription.repository.payment-token' => static function ( ContainerInterface $container ): PaymentTokenRepository {
|
||||
|
|
|
@ -10,6 +10,7 @@ declare(strict_types=1);
|
|||
namespace WooCommerce\PayPalCommerce\Subscription;
|
||||
|
||||
use WooCommerce\PayPalCommerce\ApiClient\Endpoint\OrderEndpoint;
|
||||
use WooCommerce\PayPalCommerce\ApiClient\Entity\Order;
|
||||
use WooCommerce\PayPalCommerce\ApiClient\Entity\PaymentToken;
|
||||
use WooCommerce\PayPalCommerce\ApiClient\Factory\PayerFactory;
|
||||
use WooCommerce\PayPalCommerce\ApiClient\Factory\PurchaseUnitFactory;
|
||||
|
@ -17,10 +18,12 @@ use WooCommerce\PayPalCommerce\ApiClient\Factory\ShippingPreferenceFactory;
|
|||
use WooCommerce\PayPalCommerce\Onboarding\Environment;
|
||||
use WooCommerce\PayPalCommerce\Vaulting\PaymentTokenRepository;
|
||||
use Psr\Log\LoggerInterface;
|
||||
use WooCommerce\PayPalCommerce\WcGateway\Exception\NotFoundException;
|
||||
use WooCommerce\PayPalCommerce\WcGateway\Processor\AuthorizedPaymentsProcessor;
|
||||
use WooCommerce\PayPalCommerce\WcGateway\Processor\OrderMetaTrait;
|
||||
use WooCommerce\PayPalCommerce\WcGateway\Processor\PaymentsStatusHandlingTrait;
|
||||
use WooCommerce\PayPalCommerce\WcGateway\Processor\TransactionIdHandlingTrait;
|
||||
use WooCommerce\PayPalCommerce\WcGateway\Settings\Settings;
|
||||
|
||||
/**
|
||||
* Class RenewalHandler
|
||||
|
@ -80,16 +83,32 @@ class RenewalHandler {
|
|||
*/
|
||||
protected $environment;
|
||||
|
||||
/**
|
||||
* The settings
|
||||
*
|
||||
* @var Settings
|
||||
*/
|
||||
protected $settings;
|
||||
|
||||
/**
|
||||
* The processor for authorized payments.
|
||||
*
|
||||
* @var AuthorizedPaymentsProcessor
|
||||
*/
|
||||
protected $authorized_payments_processor;
|
||||
|
||||
/**
|
||||
* RenewalHandler constructor.
|
||||
*
|
||||
* @param LoggerInterface $logger The logger.
|
||||
* @param PaymentTokenRepository $repository The payment token repository.
|
||||
* @param OrderEndpoint $order_endpoint The order endpoint.
|
||||
* @param PurchaseUnitFactory $purchase_unit_factory The purchase unit factory.
|
||||
* @param ShippingPreferenceFactory $shipping_preference_factory The shipping_preference factory.
|
||||
* @param PayerFactory $payer_factory The payer factory.
|
||||
* @param Environment $environment The environment.
|
||||
* @param LoggerInterface $logger The logger.
|
||||
* @param PaymentTokenRepository $repository The payment token repository.
|
||||
* @param OrderEndpoint $order_endpoint The order endpoint.
|
||||
* @param PurchaseUnitFactory $purchase_unit_factory The purchase unit factory.
|
||||
* @param ShippingPreferenceFactory $shipping_preference_factory The shipping_preference factory.
|
||||
* @param PayerFactory $payer_factory The payer factory.
|
||||
* @param Environment $environment The environment.
|
||||
* @param Settings $settings The Settings.
|
||||
* @param AuthorizedPaymentsProcessor $authorized_payments_processor The Authorized Payments Processor.
|
||||
*/
|
||||
public function __construct(
|
||||
LoggerInterface $logger,
|
||||
|
@ -98,16 +117,20 @@ class RenewalHandler {
|
|||
PurchaseUnitFactory $purchase_unit_factory,
|
||||
ShippingPreferenceFactory $shipping_preference_factory,
|
||||
PayerFactory $payer_factory,
|
||||
Environment $environment
|
||||
Environment $environment,
|
||||
Settings $settings,
|
||||
AuthorizedPaymentsProcessor $authorized_payments_processor
|
||||
) {
|
||||
|
||||
$this->logger = $logger;
|
||||
$this->repository = $repository;
|
||||
$this->order_endpoint = $order_endpoint;
|
||||
$this->purchase_unit_factory = $purchase_unit_factory;
|
||||
$this->shipping_preference_factory = $shipping_preference_factory;
|
||||
$this->payer_factory = $payer_factory;
|
||||
$this->environment = $environment;
|
||||
$this->logger = $logger;
|
||||
$this->repository = $repository;
|
||||
$this->order_endpoint = $order_endpoint;
|
||||
$this->purchase_unit_factory = $purchase_unit_factory;
|
||||
$this->shipping_preference_factory = $shipping_preference_factory;
|
||||
$this->payer_factory = $payer_factory;
|
||||
$this->environment = $environment;
|
||||
$this->settings = $settings;
|
||||
$this->authorized_payments_processor = $authorized_payments_processor;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -179,6 +202,14 @@ class RenewalHandler {
|
|||
}
|
||||
|
||||
$this->handle_new_order_status( $order, $wc_order );
|
||||
|
||||
if ( $this->capture_authorized_downloads( $order ) && AuthorizedPaymentsProcessor::SUCCESSFUL === $this->authorized_payments_processor->process( $wc_order ) ) {
|
||||
$wc_order->add_order_note(
|
||||
__( 'Payment successfully captured.', 'woocommerce-paypal-payments' )
|
||||
);
|
||||
$wc_order->update_meta_data( AuthorizedPaymentsProcessor::CAPTURED_META_KEY, 'true' );
|
||||
$wc_order->update_status( 'completed' );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -229,4 +260,39 @@ class RenewalHandler {
|
|||
|
||||
return current( $tokens );
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns if an order should be captured immediately.
|
||||
*
|
||||
* @param Order $order The PayPal order.
|
||||
*
|
||||
* @return bool
|
||||
* @throws NotFoundException When a setting was not found.
|
||||
*/
|
||||
protected function capture_authorized_downloads( Order $order ): bool {
|
||||
if (
|
||||
! $this->settings->has( 'capture_for_virtual_only' )
|
||||
|| ! $this->settings->get( 'capture_for_virtual_only' )
|
||||
) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if ( $order->intent() === 'CAPTURE' ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* We fetch the order again as the authorize endpoint (from which the Order derives)
|
||||
* drops the item's category, making it impossible to check, if purchase units contain
|
||||
* physical goods.
|
||||
*/
|
||||
$order = $this->order_endpoint->order( $order->id() );
|
||||
|
||||
foreach ( $order->purchase_units() as $unit ) {
|
||||
if ( $unit->contains_physical_goods() ) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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\OXXO\OXXO;
|
||||
use WooCommerce\PayPalCommerce\WcGateway\Gateway\OXXO\OXXOEndpoint;
|
||||
|
@ -48,7 +49,7 @@ use WooCommerce\PayPalCommerce\WcGateway\Helper\PayUponInvoiceProductStatus;
|
|||
use WooCommerce\PayPalCommerce\WcGateway\Helper\SettingsStatus;
|
||||
use WooCommerce\PayPalCommerce\WcGateway\Notice\AuthorizeOrderActionNotice;
|
||||
use WooCommerce\PayPalCommerce\WcGateway\Notice\ConnectAdminNotice;
|
||||
use WooCommerce\PayPalCommerce\WcGateway\Notice\DccWithoutPayPalAdminNotice;
|
||||
use WooCommerce\PayPalCommerce\WcGateway\Notice\GatewayWithoutPayPalAdminNotice;
|
||||
use WooCommerce\PayPalCommerce\WcGateway\Processor\AuthorizedPaymentsProcessor;
|
||||
use WooCommerce\PayPalCommerce\WcGateway\Processor\OrderProcessor;
|
||||
use WooCommerce\PayPalCommerce\WcGateway\Processor\RefundProcessor;
|
||||
|
@ -59,11 +60,10 @@ use WooCommerce\PayPalCommerce\WcGateway\Settings\SettingsRenderer;
|
|||
use WooCommerce\PayPalCommerce\Webhooks\Status\WebhooksStatusPage;
|
||||
|
||||
return array(
|
||||
'wcgateway.paypal-gateway' => static function ( ContainerInterface $container ): PayPalGateway {
|
||||
'wcgateway.paypal-gateway' => static function ( ContainerInterface $container ): PayPalGateway {
|
||||
$order_processor = $container->get( 'wcgateway.order-processor' );
|
||||
$settings_renderer = $container->get( 'wcgateway.settings.render' );
|
||||
$funding_source_renderer = $container->get( 'wcgateway.funding-source.renderer' );
|
||||
$authorized_payments = $container->get( 'wcgateway.processor.authorized-payments' );
|
||||
$settings = $container->get( 'wcgateway.settings' );
|
||||
$session_handler = $container->get( 'session.handler' );
|
||||
$refund_processor = $container->get( 'wcgateway.processor.refunds' );
|
||||
|
@ -72,8 +72,6 @@ return array(
|
|||
$subscription_helper = $container->get( 'subscription.helper' );
|
||||
$page_id = $container->get( 'wcgateway.current-ppcp-settings-page-id' );
|
||||
$payment_token_repository = $container->get( 'vaulting.repository.payment-token' );
|
||||
$payments_endpoint = $container->get( 'api.endpoint.payments' );
|
||||
$order_endpoint = $container->get( 'api.endpoint.order' );
|
||||
$environment = $container->get( 'onboarding.environment' );
|
||||
$logger = $container->get( 'woocommerce.logger.woocommerce' );
|
||||
$api_shop_country = $container->get( 'api.shop.country' );
|
||||
|
@ -81,7 +79,6 @@ return array(
|
|||
$settings_renderer,
|
||||
$funding_source_renderer,
|
||||
$order_processor,
|
||||
$authorized_payments,
|
||||
$settings,
|
||||
$session_handler,
|
||||
$refund_processor,
|
||||
|
@ -91,14 +88,11 @@ return array(
|
|||
$page_id,
|
||||
$environment,
|
||||
$payment_token_repository,
|
||||
$container->get( 'api.factory.shipping-preference' ),
|
||||
$logger,
|
||||
$payments_endpoint,
|
||||
$order_endpoint,
|
||||
$api_shop_country
|
||||
);
|
||||
},
|
||||
'wcgateway.credit-card-gateway' => static function ( ContainerInterface $container ): CreditCardGateway {
|
||||
'wcgateway.credit-card-gateway' => static function ( ContainerInterface $container ): CreditCardGateway {
|
||||
$order_processor = $container->get( 'wcgateway.order-processor' );
|
||||
$settings_renderer = $container->get( 'wcgateway.settings.render' );
|
||||
$authorized_payments = $container->get( 'wcgateway.processor.authorized-payments' );
|
||||
|
@ -137,27 +131,43 @@ return array(
|
|||
$payments_endpoint
|
||||
);
|
||||
},
|
||||
'wcgateway.disabler' => static function ( ContainerInterface $container ): DisableGateways {
|
||||
'wcgateway.card-button-gateway' => static function ( ContainerInterface $container ): CardButtonGateway {
|
||||
return new CardButtonGateway(
|
||||
$container->get( 'wcgateway.settings.render' ),
|
||||
$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( 'wcgateway.settings.allow_card_button_gateway.default' ),
|
||||
$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' );
|
||||
return new DisableGateways( $session_handler, $settings );
|
||||
},
|
||||
'wcgateway.is-wc-payments-page' => static function ( ContainerInterface $container ): bool {
|
||||
'wcgateway.is-wc-payments-page' => static function ( ContainerInterface $container ): bool {
|
||||
$page = isset( $_GET['page'] ) ? sanitize_text_field( wp_unslash( $_GET['page'] ) ) : '';
|
||||
$tab = isset( $_GET['tab'] ) ? sanitize_text_field( wp_unslash( $_GET['tab'] ) ) : '';
|
||||
return 'wc-settings' === $page && 'checkout' === $tab;
|
||||
},
|
||||
|
||||
'wcgateway.is-ppcp-settings-page' => static function ( ContainerInterface $container ): bool {
|
||||
'wcgateway.is-ppcp-settings-page' => static function ( ContainerInterface $container ): bool {
|
||||
if ( ! $container->get( 'wcgateway.is-wc-payments-page' ) ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$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 {
|
||||
'wcgateway.current-ppcp-settings-page-id' => static function ( ContainerInterface $container ): string {
|
||||
if ( ! $container->get( 'wcgateway.is-ppcp-settings-page' ) ) {
|
||||
return '';
|
||||
}
|
||||
|
@ -168,36 +178,47 @@ return array(
|
|||
return $ppcp_tab ? $ppcp_tab : $section;
|
||||
},
|
||||
|
||||
'wcgateway.settings' => static function ( ContainerInterface $container ): Settings {
|
||||
'wcgateway.settings' => static function ( ContainerInterface $container ): Settings {
|
||||
return new Settings();
|
||||
},
|
||||
'wcgateway.notice.connect' => static function ( ContainerInterface $container ): ConnectAdminNotice {
|
||||
'wcgateway.notice.connect' => static function ( ContainerInterface $container ): ConnectAdminNotice {
|
||||
$state = $container->get( 'onboarding.state' );
|
||||
$settings = $container->get( 'wcgateway.settings' );
|
||||
return new ConnectAdminNotice( $state, $settings );
|
||||
},
|
||||
'wcgateway.notice.dcc-without-paypal' => static function ( ContainerInterface $container ): DccWithoutPayPalAdminNotice {
|
||||
$state = $container->get( 'onboarding.state' );
|
||||
$settings = $container->get( 'wcgateway.settings' );
|
||||
$is_payments_page = $container->get( 'wcgateway.is-wc-payments-page' );
|
||||
$is_ppcp_settings_page = $container->get( 'wcgateway.is-ppcp-settings-page' );
|
||||
return new DccWithoutPayPalAdminNotice( $state, $settings, $is_payments_page, $is_ppcp_settings_page );
|
||||
'wcgateway.notice.dcc-without-paypal' => static function ( ContainerInterface $container ): GatewayWithoutPayPalAdminNotice {
|
||||
return new GatewayWithoutPayPalAdminNotice(
|
||||
CreditCardGateway::ID,
|
||||
$container->get( 'onboarding.state' ),
|
||||
$container->get( 'wcgateway.settings' ),
|
||||
$container->get( 'wcgateway.is-wc-payments-page' ),
|
||||
$container->get( 'wcgateway.is-ppcp-settings-page' )
|
||||
);
|
||||
},
|
||||
'wcgateway.notice.authorize-order-action' =>
|
||||
'wcgateway.notice.card-button-without-paypal' => static function ( ContainerInterface $container ): GatewayWithoutPayPalAdminNotice {
|
||||
return new GatewayWithoutPayPalAdminNotice(
|
||||
CardButtonGateway::ID,
|
||||
$container->get( 'onboarding.state' ),
|
||||
$container->get( 'wcgateway.settings' ),
|
||||
$container->get( 'wcgateway.is-wc-payments-page' ),
|
||||
$container->get( 'wcgateway.is-ppcp-settings-page' )
|
||||
);
|
||||
},
|
||||
'wcgateway.notice.authorize-order-action' =>
|
||||
static function ( ContainerInterface $container ): AuthorizeOrderActionNotice {
|
||||
return new AuthorizeOrderActionNotice();
|
||||
},
|
||||
'wcgateway.settings.sections-renderer' => static function ( ContainerInterface $container ): SectionsRenderer {
|
||||
'wcgateway.settings.sections-renderer' => static function ( ContainerInterface $container ): SectionsRenderer {
|
||||
return new SectionsRenderer(
|
||||
$container->get( 'wcgateway.current-ppcp-settings-page-id' ),
|
||||
$container->get( 'api.shop.country' )
|
||||
);
|
||||
},
|
||||
'wcgateway.settings.status' => static function ( ContainerInterface $container ): SettingsStatus {
|
||||
'wcgateway.settings.status' => static function ( ContainerInterface $container ): SettingsStatus {
|
||||
$settings = $container->get( 'wcgateway.settings' );
|
||||
return new SettingsStatus( $settings );
|
||||
},
|
||||
'wcgateway.settings.render' => static function ( ContainerInterface $container ): SettingsRenderer {
|
||||
'wcgateway.settings.render' => static function ( ContainerInterface $container ): SettingsRenderer {
|
||||
$settings = $container->get( 'wcgateway.settings' );
|
||||
$state = $container->get( 'onboarding.state' );
|
||||
$fields = $container->get( 'wcgateway.settings.fields' );
|
||||
|
@ -217,7 +238,7 @@ return array(
|
|||
$page_id
|
||||
);
|
||||
},
|
||||
'wcgateway.settings.listener' => static function ( ContainerInterface $container ): SettingsListener {
|
||||
'wcgateway.settings.listener' => static function ( ContainerInterface $container ): SettingsListener {
|
||||
$settings = $container->get( 'wcgateway.settings' );
|
||||
$fields = $container->get( 'wcgateway.settings.fields' );
|
||||
$webhook_registrar = $container->get( 'webhook.registrar' );
|
||||
|
@ -239,7 +260,7 @@ return array(
|
|||
$signup_link_ids
|
||||
);
|
||||
},
|
||||
'wcgateway.order-processor' => static function ( ContainerInterface $container ): OrderProcessor {
|
||||
'wcgateway.order-processor' => static function ( ContainerInterface $container ): OrderProcessor {
|
||||
|
||||
$session_handler = $container->get( 'session.handler' );
|
||||
$order_endpoint = $container->get( 'api.endpoint.order' );
|
||||
|
@ -264,13 +285,13 @@ return array(
|
|||
$order_helper
|
||||
);
|
||||
},
|
||||
'wcgateway.processor.refunds' => static function ( ContainerInterface $container ): RefundProcessor {
|
||||
'wcgateway.processor.refunds' => static function ( ContainerInterface $container ): RefundProcessor {
|
||||
$order_endpoint = $container->get( 'api.endpoint.order' );
|
||||
$payments_endpoint = $container->get( 'api.endpoint.payments' );
|
||||
$logger = $container->get( 'woocommerce.logger.woocommerce' );
|
||||
return new RefundProcessor( $order_endpoint, $payments_endpoint, $logger );
|
||||
},
|
||||
'wcgateway.processor.authorized-payments' => static function ( ContainerInterface $container ): AuthorizedPaymentsProcessor {
|
||||
'wcgateway.processor.authorized-payments' => static function ( ContainerInterface $container ): AuthorizedPaymentsProcessor {
|
||||
$order_endpoint = $container->get( 'api.endpoint.order' );
|
||||
$payments_endpoint = $container->get( 'api.endpoint.payments' );
|
||||
$logger = $container->get( 'woocommerce.logger.woocommerce' );
|
||||
|
@ -286,23 +307,23 @@ return array(
|
|||
$subscription_helper
|
||||
);
|
||||
},
|
||||
'wcgateway.admin.render-authorize-action' => static function ( ContainerInterface $container ): RenderAuthorizeAction {
|
||||
'wcgateway.admin.render-authorize-action' => static function ( ContainerInterface $container ): RenderAuthorizeAction {
|
||||
$column = $container->get( 'wcgateway.admin.orders-payment-status-column' );
|
||||
return new RenderAuthorizeAction( $column );
|
||||
},
|
||||
'wcgateway.admin.order-payment-status' => static function ( ContainerInterface $container ): PaymentStatusOrderDetail {
|
||||
'wcgateway.admin.order-payment-status' => static function ( ContainerInterface $container ): PaymentStatusOrderDetail {
|
||||
$column = $container->get( 'wcgateway.admin.orders-payment-status-column' );
|
||||
return new PaymentStatusOrderDetail( $column );
|
||||
},
|
||||
'wcgateway.admin.orders-payment-status-column' => static function ( ContainerInterface $container ): OrderTablePaymentStatusColumn {
|
||||
'wcgateway.admin.orders-payment-status-column' => static function ( ContainerInterface $container ): OrderTablePaymentStatusColumn {
|
||||
$settings = $container->get( 'wcgateway.settings' );
|
||||
return new OrderTablePaymentStatusColumn( $settings );
|
||||
},
|
||||
'wcgateway.admin.fees-renderer' => static function ( ContainerInterface $container ): FeesRenderer {
|
||||
'wcgateway.admin.fees-renderer' => static function ( ContainerInterface $container ): FeesRenderer {
|
||||
return new FeesRenderer();
|
||||
},
|
||||
|
||||
'wcgateway.settings.fields' => static function ( ContainerInterface $container ): array {
|
||||
'wcgateway.settings.fields' => static function ( ContainerInterface $container ): array {
|
||||
|
||||
$state = $container->get( 'onboarding.state' );
|
||||
assert( $state instanceof State );
|
||||
|
@ -865,6 +886,40 @@ return array(
|
|||
'requirements' => array(),
|
||||
'gateway' => 'paypal',
|
||||
),
|
||||
'card_billing_data_mode' => array(
|
||||
'title' => __( 'Card billing data handling', 'woocommerce-paypal-payments' ),
|
||||
'type' => 'select',
|
||||
'class' => array(),
|
||||
'input_class' => array( 'wc-enhanced-select' ),
|
||||
'desc_tip' => true,
|
||||
'description' => __( 'Using the WC form data increases convenience for the customers, but can cause issues if card details do not match the billing data in the checkout form.', 'woocommerce-paypal-payments' ),
|
||||
'default' => $container->get( 'wcgateway.settings.card_billing_data_mode.default' ),
|
||||
'options' => array(
|
||||
CardBillingMode::USE_WC => __( 'Use WC checkout form data (do not show any address fields)', 'woocommerce-paypal-payments' ),
|
||||
CardBillingMode::MINIMAL_INPUT => __( 'Request only name and postal code', 'woocommerce-paypal-payments' ),
|
||||
CardBillingMode::NO_WC => __( 'Do not use WC checkout form data (request all address fields)', 'woocommerce-paypal-payments' ),
|
||||
),
|
||||
'screens' => array(
|
||||
State::STATE_START,
|
||||
State::STATE_ONBOARDED,
|
||||
),
|
||||
'requirements' => array(),
|
||||
'gateway' => array( 'paypal', CardButtonGateway::ID ),
|
||||
),
|
||||
'allow_card_button_gateway' => array(
|
||||
'title' => __( 'Separate Card Button from PayPal gateway', 'woocommerce-paypal-payments' ),
|
||||
'type' => 'checkbox',
|
||||
'desc_tip' => true,
|
||||
'label' => __( 'Enable a separate payment gateway for the branded PayPal Debit or Credit Card button.', 'woocommerce-paypal-payments' ),
|
||||
'description' => __( 'By default, the Debit or Credit Card button is displayed in the PayPal Checkout payment gateway. This setting creates a second gateway for the Card button.', 'woocommerce-paypal-payments' ),
|
||||
'default' => $container->get( 'wcgateway.settings.allow_card_button_gateway.default' ),
|
||||
'screens' => array(
|
||||
State::STATE_START,
|
||||
State::STATE_ONBOARDED,
|
||||
),
|
||||
'requirements' => array(),
|
||||
'gateway' => 'paypal',
|
||||
),
|
||||
|
||||
// General button styles.
|
||||
'button_style_heading' => array(
|
||||
|
@ -2078,7 +2133,7 @@ return array(
|
|||
return $fields;
|
||||
},
|
||||
|
||||
'wcgateway.all-funding-sources' => static function( ContainerInterface $container ): array {
|
||||
'wcgateway.all-funding-sources' => static function( ContainerInterface $container ): array {
|
||||
return array(
|
||||
'card' => _x( 'Credit or debit cards', 'Name of payment method', 'woocommerce-paypal-payments' ),
|
||||
'credit' => _x( 'Pay Later', 'Name of payment method', 'woocommerce-paypal-payments' ),
|
||||
|
@ -2096,28 +2151,28 @@ return array(
|
|||
);
|
||||
},
|
||||
|
||||
'wcgateway.checkout.address-preset' => static function( ContainerInterface $container ): CheckoutPayPalAddressPreset {
|
||||
'wcgateway.checkout.address-preset' => static function( ContainerInterface $container ): CheckoutPayPalAddressPreset {
|
||||
|
||||
return new CheckoutPayPalAddressPreset(
|
||||
$container->get( 'session.handler' )
|
||||
);
|
||||
},
|
||||
'wcgateway.url' => static function ( ContainerInterface $container ): string {
|
||||
'wcgateway.url' => static function ( ContainerInterface $container ): string {
|
||||
return plugins_url(
|
||||
$container->get( 'wcgateway.relative-path' ),
|
||||
dirname( realpath( __FILE__ ), 3 ) . '/woocommerce-paypal-payments.php'
|
||||
);
|
||||
},
|
||||
'wcgateway.relative-path' => static function( ContainerInterface $container ): string {
|
||||
'wcgateway.relative-path' => static function( ContainerInterface $container ): string {
|
||||
return 'modules/ppcp-wc-gateway/';
|
||||
},
|
||||
'wcgateway.absolute-path' => static function( ContainerInterface $container ): string {
|
||||
'wcgateway.absolute-path' => static function( ContainerInterface $container ): string {
|
||||
return plugin_dir_path(
|
||||
dirname( realpath( __FILE__ ), 3 ) . '/woocommerce-paypal-payments.php'
|
||||
) .
|
||||
$container->get( 'wcgateway.relative-path' );
|
||||
},
|
||||
'wcgateway.endpoint.return-url' => static function ( ContainerInterface $container ) : ReturnUrlEndpoint {
|
||||
'wcgateway.endpoint.return-url' => static function ( ContainerInterface $container ) : ReturnUrlEndpoint {
|
||||
$gateway = $container->get( 'wcgateway.paypal-gateway' );
|
||||
$endpoint = $container->get( 'api.endpoint.order' );
|
||||
$prefix = $container->get( 'api.prefix' );
|
||||
|
@ -2128,43 +2183,43 @@ return array(
|
|||
);
|
||||
},
|
||||
|
||||
'wcgateway.transaction-url-sandbox' => static function ( ContainerInterface $container ): string {
|
||||
'wcgateway.transaction-url-sandbox' => static function ( ContainerInterface $container ): string {
|
||||
return 'https://www.sandbox.paypal.com/cgi-bin/webscr?cmd=_view-a-trans&id=%s';
|
||||
},
|
||||
|
||||
'wcgateway.transaction-url-live' => static function ( ContainerInterface $container ): string {
|
||||
'wcgateway.transaction-url-live' => static function ( ContainerInterface $container ): string {
|
||||
return 'https://www.paypal.com/cgi-bin/webscr?cmd=_view-a-trans&id=%s';
|
||||
},
|
||||
|
||||
'wcgateway.transaction-url-provider' => static function ( ContainerInterface $container ): TransactionUrlProvider {
|
||||
'wcgateway.transaction-url-provider' => static function ( ContainerInterface $container ): TransactionUrlProvider {
|
||||
$sandbox_url_base = $container->get( 'wcgateway.transaction-url-sandbox' );
|
||||
$live_url_base = $container->get( 'wcgateway.transaction-url-live' );
|
||||
|
||||
return new TransactionUrlProvider( $sandbox_url_base, $live_url_base );
|
||||
},
|
||||
|
||||
'wcgateway.helper.dcc-product-status' => static function ( ContainerInterface $container ) : DCCProductStatus {
|
||||
'wcgateway.helper.dcc-product-status' => static function ( ContainerInterface $container ) : DCCProductStatus {
|
||||
|
||||
$settings = $container->get( 'wcgateway.settings' );
|
||||
$partner_endpoint = $container->get( 'api.endpoint.partners' );
|
||||
return new DCCProductStatus( $settings, $partner_endpoint );
|
||||
},
|
||||
|
||||
'button.helper.messages-disclaimers' => static function ( ContainerInterface $container ): MessagesDisclaimers {
|
||||
'button.helper.messages-disclaimers' => static function ( ContainerInterface $container ): MessagesDisclaimers {
|
||||
return new MessagesDisclaimers(
|
||||
$container->get( 'api.shop.country' )
|
||||
);
|
||||
},
|
||||
|
||||
'wcgateway.funding-source.renderer' => function ( ContainerInterface $container ) : FundingSourceRenderer {
|
||||
'wcgateway.funding-source.renderer' => function ( ContainerInterface $container ) : FundingSourceRenderer {
|
||||
return new FundingSourceRenderer(
|
||||
$container->get( 'wcgateway.settings' )
|
||||
);
|
||||
},
|
||||
'wcgateway.checkout-helper' => static function ( ContainerInterface $container ): CheckoutHelper {
|
||||
'wcgateway.checkout-helper' => static function ( ContainerInterface $container ): CheckoutHelper {
|
||||
return new CheckoutHelper();
|
||||
},
|
||||
'wcgateway.pay-upon-invoice-order-endpoint' => static function ( ContainerInterface $container ): PayUponInvoiceOrderEndpoint {
|
||||
'wcgateway.pay-upon-invoice-order-endpoint' => static function ( ContainerInterface $container ): PayUponInvoiceOrderEndpoint {
|
||||
return new PayUponInvoiceOrderEndpoint(
|
||||
$container->get( 'api.host' ),
|
||||
$container->get( 'api.bearer' ),
|
||||
|
@ -2173,10 +2228,10 @@ return array(
|
|||
$container->get( 'woocommerce.logger.woocommerce' )
|
||||
);
|
||||
},
|
||||
'wcgateway.pay-upon-invoice-payment-source-factory' => static function ( ContainerInterface $container ): PaymentSourceFactory {
|
||||
'wcgateway.pay-upon-invoice-payment-source-factory' => static function ( ContainerInterface $container ): PaymentSourceFactory {
|
||||
return new PaymentSourceFactory();
|
||||
},
|
||||
'wcgateway.pay-upon-invoice-gateway' => static function ( ContainerInterface $container ): PayUponInvoiceGateway {
|
||||
'wcgateway.pay-upon-invoice-gateway' => static function ( ContainerInterface $container ): PayUponInvoiceGateway {
|
||||
return new PayUponInvoiceGateway(
|
||||
$container->get( 'wcgateway.pay-upon-invoice-order-endpoint' ),
|
||||
$container->get( 'api.factory.purchase-unit' ),
|
||||
|
@ -2188,13 +2243,13 @@ return array(
|
|||
$container->get( 'wcgateway.checkout-helper' )
|
||||
);
|
||||
},
|
||||
'wcgateway.pay-upon-invoice-fraudnet-session-id' => static function ( ContainerInterface $container ): FraudNetSessionId {
|
||||
'wcgateway.pay-upon-invoice-fraudnet-session-id' => static function ( ContainerInterface $container ): FraudNetSessionId {
|
||||
return new FraudNetSessionId();
|
||||
},
|
||||
'wcgateway.pay-upon-invoice-fraudnet-source-website-id' => static function ( ContainerInterface $container ): FraudNetSourceWebsiteId {
|
||||
return new FraudNetSourceWebsiteId( $container->get( 'api.merchant_id' ) );
|
||||
},
|
||||
'wcgateway.pay-upon-invoice-fraudnet' => static function ( ContainerInterface $container ): FraudNet {
|
||||
'wcgateway.pay-upon-invoice-fraudnet' => static function ( ContainerInterface $container ): FraudNet {
|
||||
$session_id = $container->get( 'wcgateway.pay-upon-invoice-fraudnet-session-id' );
|
||||
$source_website_id = $container->get( 'wcgateway.pay-upon-invoice-fraudnet-source-website-id' );
|
||||
return new FraudNet(
|
||||
|
@ -2202,18 +2257,18 @@ return array(
|
|||
(string) $source_website_id()
|
||||
);
|
||||
},
|
||||
'wcgateway.pay-upon-invoice-helper' => static function( ContainerInterface $container ): PayUponInvoiceHelper {
|
||||
'wcgateway.pay-upon-invoice-helper' => static function( ContainerInterface $container ): PayUponInvoiceHelper {
|
||||
return new PayUponInvoiceHelper(
|
||||
$container->get( 'wcgateway.checkout-helper' )
|
||||
);
|
||||
},
|
||||
'wcgateway.pay-upon-invoice-product-status' => static function( ContainerInterface $container ): PayUponInvoiceProductStatus {
|
||||
'wcgateway.pay-upon-invoice-product-status' => static function( ContainerInterface $container ): PayUponInvoiceProductStatus {
|
||||
return new PayUponInvoiceProductStatus(
|
||||
$container->get( 'wcgateway.settings' ),
|
||||
$container->get( 'api.endpoint.partners' )
|
||||
);
|
||||
},
|
||||
'wcgateway.pay-upon-invoice' => static function ( ContainerInterface $container ): PayUponInvoice {
|
||||
'wcgateway.pay-upon-invoice' => static function ( ContainerInterface $container ): PayUponInvoice {
|
||||
return new PayUponInvoice(
|
||||
$container->get( 'wcgateway.url' ),
|
||||
$container->get( 'wcgateway.pay-upon-invoice-fraudnet' ),
|
||||
|
@ -2231,14 +2286,14 @@ return array(
|
|||
$container->get( 'api.factory.capture' )
|
||||
);
|
||||
},
|
||||
'wcgateway.oxxo' => static function( ContainerInterface $container ): OXXO {
|
||||
'wcgateway.oxxo' => static function( ContainerInterface $container ): OXXO {
|
||||
return new OXXO(
|
||||
$container->get( 'wcgateway.checkout-helper' ),
|
||||
$container->get( 'wcgateway.url' ),
|
||||
$container->get( 'ppcp.asset-version' )
|
||||
);
|
||||
},
|
||||
'wcgateway.oxxo-gateway' => static function( ContainerInterface $container ): OXXOGateway {
|
||||
'wcgateway.oxxo-gateway' => static function( ContainerInterface $container ): OXXOGateway {
|
||||
return new OXXOGateway(
|
||||
$container->get( 'api.endpoint.order' ),
|
||||
$container->get( 'api.factory.purchase-unit' ),
|
||||
|
@ -2246,7 +2301,7 @@ return array(
|
|||
$container->get( 'woocommerce.logger.woocommerce' )
|
||||
);
|
||||
},
|
||||
'wcgateway.endpoint.oxxo' => static function ( ContainerInterface $container ): OXXOEndpoint {
|
||||
'wcgateway.endpoint.oxxo' => static function ( ContainerInterface $container ): OXXOEndpoint {
|
||||
return new OXXOEndpoint(
|
||||
$container->get( 'button.request-data' ),
|
||||
$container->get( 'api.endpoint.order' ),
|
||||
|
@ -2255,7 +2310,7 @@ return array(
|
|||
$container->get( 'woocommerce.logger.woocommerce' )
|
||||
);
|
||||
},
|
||||
'wcgateway.logging.is-enabled' => function ( ContainerInterface $container ) : bool {
|
||||
'wcgateway.logging.is-enabled' => function ( ContainerInterface $container ) : bool {
|
||||
$settings = $container->get( 'wcgateway.settings' );
|
||||
|
||||
/**
|
||||
|
@ -2267,7 +2322,7 @@ return array(
|
|||
);
|
||||
},
|
||||
|
||||
'wcgateway.helper.vaulting-scope' => static function ( ContainerInterface $container ): bool {
|
||||
'wcgateway.helper.vaulting-scope' => static function ( ContainerInterface $container ): bool {
|
||||
try {
|
||||
$token = $container->get( 'api.bearer' )->bearer();
|
||||
return $token->vaulting_available();
|
||||
|
@ -2276,7 +2331,7 @@ return array(
|
|||
}
|
||||
},
|
||||
|
||||
'button.helper.vaulting-label' => static function ( ContainerInterface $container ): string {
|
||||
'button.helper.vaulting-label' => static function ( ContainerInterface $container ): string {
|
||||
$vaulting_label = __( 'Enable saved cards and subscription features on your store.', 'woocommerce-paypal-payments' );
|
||||
|
||||
if ( ! $container->get( 'wcgateway.helper.vaulting-scope' ) ) {
|
||||
|
@ -2298,7 +2353,7 @@ return array(
|
|||
return $vaulting_label;
|
||||
},
|
||||
|
||||
'wcgateway.settings.fields.pay-later-label' => static function ( ContainerInterface $container ): string {
|
||||
'wcgateway.settings.fields.pay-later-label' => static function ( ContainerInterface $container ): string {
|
||||
$pay_later_label = '<span class="ppcp-pay-later-enabled-label">%s</span>';
|
||||
$pay_later_label .= '<span class="ppcp-pay-later-disabled-label">';
|
||||
$pay_later_label .= __( "You have PayPal vaulting enabled, that's why Pay Later Messaging options are unavailable now. You cannot use both features at the same time.", 'woocommerce-paypal-payments' );
|
||||
|
@ -2306,4 +2361,28 @@ return array(
|
|||
|
||||
return $pay_later_label;
|
||||
},
|
||||
|
||||
'wcgateway.settings.card_billing_data_mode.default' => static function ( ContainerInterface $container ): string {
|
||||
return $container->get( 'api.shop.is-latin-america' ) ? CardBillingMode::MINIMAL_INPUT : CardBillingMode::USE_WC;
|
||||
},
|
||||
'wcgateway.settings.card_billing_data_mode' => static function ( ContainerInterface $container ): string {
|
||||
$settings = $container->get( 'wcgateway.settings' );
|
||||
assert( $settings instanceof ContainerInterface );
|
||||
|
||||
return $settings->has( 'card_billing_data_mode' ) ?
|
||||
(string) $settings->get( 'card_billing_data_mode' ) :
|
||||
$container->get( 'wcgateway.settings.card_billing_data_mode.default' );
|
||||
},
|
||||
|
||||
'wcgateway.settings.allow_card_button_gateway.default' => static function ( ContainerInterface $container ): bool {
|
||||
return $container->get( 'api.shop.is-latin-america' );
|
||||
},
|
||||
'wcgateway.settings.allow_card_button_gateway' => static function ( ContainerInterface $container ): bool {
|
||||
$settings = $container->get( 'wcgateway.settings' );
|
||||
assert( $settings instanceof ContainerInterface );
|
||||
|
||||
return $settings->has( 'allow_card_button_gateway' ) ?
|
||||
(bool) $settings->get( 'allow_card_button_gateway' ) :
|
||||
$container->get( 'wcgateway.settings.allow_card_button_gateway.default' );
|
||||
},
|
||||
);
|
||||
|
|
19
modules/ppcp-wc-gateway/src/CardBillingMode.php
Normal file
19
modules/ppcp-wc-gateway/src/CardBillingMode.php
Normal file
|
@ -0,0 +1,19 @@
|
|||
<?php
|
||||
/**
|
||||
* Possible values of card_billing_data_mode.
|
||||
*
|
||||
* @package WooCommerce\PayPalCommerce\WcGateway
|
||||
*/
|
||||
|
||||
declare( strict_types=1 );
|
||||
|
||||
namespace WooCommerce\PayPalCommerce\WcGateway;
|
||||
|
||||
/**
|
||||
* Class CardBillingMode
|
||||
*/
|
||||
interface CardBillingMode {
|
||||
public const USE_WC = 'use_wc';
|
||||
public const MINIMAL_INPUT = 'minimal_input';
|
||||
public const NO_WC = 'no_wc';
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -77,21 +79,15 @@ class DisableGateways {
|
|||
return $methods;
|
||||
}
|
||||
|
||||
if ( $this->is_credit_card() ) {
|
||||
return array(
|
||||
CreditCardGateway::ID => $methods[ CreditCardGateway::ID ],
|
||||
PayPalGateway::ID => $methods[ PayPalGateway::ID ],
|
||||
);
|
||||
}
|
||||
return array( PayPalGateway::ID => $methods[ PayPalGateway::ID ] );
|
||||
}
|
||||
|
||||
/**
|
||||
* 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,22 +106,20 @@ class DisableGateways {
|
|||
* @return bool
|
||||
*/
|
||||
private function needs_to_disable_gateways(): bool {
|
||||
return $this->session_handler->order() !== null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Whether the current PayPal session is done via DCC payment.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
private function is_credit_card(): bool {
|
||||
$order = $this->session_handler->order();
|
||||
if ( ! $order ) {
|
||||
return false;
|
||||
}
|
||||
if ( ! $order->payment_source() || ! $order->payment_source()->card() ) {
|
||||
return false;
|
||||
|
||||
$source = $order->payment_source();
|
||||
if ( $source && $source->card() ) {
|
||||
return false; // DCC.
|
||||
}
|
||||
|
||||
if ( 'card' === $this->session_handler->funding_source() ) {
|
||||
return false; // Card buttons.
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -52,7 +52,7 @@ class ReturnUrlEndpoint {
|
|||
/**
|
||||
* Handles the incoming request.
|
||||
*/
|
||||
public function handle_request() {
|
||||
public function handle_request(): void {
|
||||
|
||||
// phpcs:disable WordPress.Security.NonceVerification.Recommended
|
||||
if ( ! isset( $_GET['token'] ) ) {
|
||||
|
|
|
@ -0,0 +1,32 @@
|
|||
<?php
|
||||
/**
|
||||
* Wrapper for more detailed gateway error.
|
||||
*
|
||||
* @package WooCommerce\PayPalCommerce\WcGateway\Exception
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace WooCommerce\PayPalCommerce\WcGateway\Exception;
|
||||
|
||||
use Exception;
|
||||
use Throwable;
|
||||
use WooCommerce\PayPalCommerce\WcGateway\Gateway\Messages;
|
||||
|
||||
/**
|
||||
* Class GatewayGenericException
|
||||
*/
|
||||
class GatewayGenericException extends Exception {
|
||||
/**
|
||||
* GatewayGenericException constructor.
|
||||
*
|
||||
* @param Throwable|null $inner The exception.
|
||||
*/
|
||||
public function __construct( ?Throwable $inner = null ) {
|
||||
parent::__construct(
|
||||
Messages::generic_payment_error_message(),
|
||||
$inner ? (int) $inner->getCode() : 0,
|
||||
$inner
|
||||
);
|
||||
}
|
||||
}
|
364
modules/ppcp-wc-gateway/src/Gateway/CardButtonGateway.php
Normal file
364
modules/ppcp-wc-gateway/src/Gateway/CardButtonGateway.php
Normal file
|
@ -0,0 +1,364 @@
|
|||
<?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;
|
||||
use WooCommerce\PayPalCommerce\WcGateway\Settings\SettingsRenderer;
|
||||
|
||||
/**
|
||||
* Class CardButtonGateway
|
||||
*/
|
||||
class CardButtonGateway extends \WC_Payment_Gateway {
|
||||
|
||||
use ProcessPaymentTrait, FreeTrialHandlerTrait, GatewaySettingsRendererTrait;
|
||||
|
||||
const ID = 'ppcp-card-button-gateway';
|
||||
|
||||
/**
|
||||
* The Settings Renderer.
|
||||
*
|
||||
* @var SettingsRenderer
|
||||
*/
|
||||
protected $settings_renderer;
|
||||
|
||||
/**
|
||||
* 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;
|
||||
|
||||
/**
|
||||
* Whether the gateway should be enabled by default.
|
||||
*
|
||||
* @var bool
|
||||
*/
|
||||
private $default_enabled;
|
||||
|
||||
/**
|
||||
* The environment.
|
||||
*
|
||||
* @var Environment
|
||||
*/
|
||||
protected $environment;
|
||||
|
||||
/**
|
||||
* The logger.
|
||||
*
|
||||
* @var LoggerInterface
|
||||
*/
|
||||
private $logger;
|
||||
|
||||
/**
|
||||
* CardButtonGateway constructor.
|
||||
*
|
||||
* @param SettingsRenderer $settings_renderer The Settings Renderer.
|
||||
* @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 bool $default_enabled Whether the gateway should be enabled by default.
|
||||
* @param Environment $environment The environment.
|
||||
* @param PaymentTokenRepository $payment_token_repository The payment token repository.
|
||||
* @param LoggerInterface $logger The logger.
|
||||
*/
|
||||
public function __construct(
|
||||
SettingsRenderer $settings_renderer,
|
||||
OrderProcessor $order_processor,
|
||||
ContainerInterface $config,
|
||||
SessionHandler $session_handler,
|
||||
RefundProcessor $refund_processor,
|
||||
State $state,
|
||||
TransactionUrlProvider $transaction_url_provider,
|
||||
SubscriptionHelper $subscription_helper,
|
||||
bool $default_enabled,
|
||||
Environment $environment,
|
||||
PaymentTokenRepository $payment_token_repository,
|
||||
LoggerInterface $logger
|
||||
) {
|
||||
$this->id = self::ID;
|
||||
$this->settings_renderer = $settings_renderer;
|
||||
$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->default_enabled = $default_enabled;
|
||||
$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' => __( 'Enable PayPal Card Button', 'woocommerce-paypal-payments' ),
|
||||
'default' => $this->default_enabled ? 'yes' : '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' ),
|
||||
),
|
||||
'ppcp' => array(
|
||||
'type' => 'ppcp',
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* 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 );
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the settings renderer.
|
||||
*
|
||||
* @return SettingsRenderer
|
||||
*/
|
||||
protected function settings_renderer(): SettingsRenderer {
|
||||
return $this->settings_renderer;
|
||||
}
|
||||
}
|
|
@ -9,20 +9,30 @@ declare(strict_types=1);
|
|||
|
||||
namespace WooCommerce\PayPalCommerce\WcGateway\Gateway;
|
||||
|
||||
use Exception;
|
||||
use Psr\Log\LoggerInterface;
|
||||
use WC_Order;
|
||||
use WooCommerce\PayPalCommerce\ApiClient\Endpoint\OrderEndpoint;
|
||||
use WooCommerce\PayPalCommerce\ApiClient\Endpoint\PaymentsEndpoint;
|
||||
use WooCommerce\PayPalCommerce\ApiClient\Entity\OrderStatus;
|
||||
use WooCommerce\PayPalCommerce\ApiClient\Exception\PayPalApiException;
|
||||
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\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\AuthorizedPaymentsProcessor;
|
||||
use WooCommerce\PayPalCommerce\WcGateway\Processor\OrderMetaTrait;
|
||||
use WooCommerce\PayPalCommerce\WcGateway\Processor\OrderProcessor;
|
||||
use WooCommerce\PayPalCommerce\WcGateway\Processor\PaymentsStatusHandlingTrait;
|
||||
use WooCommerce\PayPalCommerce\WcGateway\Processor\RefundProcessor;
|
||||
use WooCommerce\PayPalCommerce\WcGateway\Processor\TransactionIdHandlingTrait;
|
||||
use WooCommerce\PayPalCommerce\WcGateway\Settings\SettingsRenderer;
|
||||
use Psr\Container\ContainerInterface;
|
||||
|
||||
|
@ -31,7 +41,8 @@ use Psr\Container\ContainerInterface;
|
|||
*/
|
||||
class CreditCardGateway extends \WC_Payment_Gateway_CC {
|
||||
|
||||
use ProcessPaymentTrait;
|
||||
use ProcessPaymentTrait, OrderMetaTrait, TransactionIdHandlingTrait, PaymentsStatusHandlingTrait, FreeTrialHandlerTrait,
|
||||
GatewaySettingsRendererTrait;
|
||||
|
||||
const ID = 'ppcp-credit-card-gateway';
|
||||
|
||||
|
@ -203,15 +214,25 @@ class CreditCardGateway extends \WC_Payment_Gateway_CC {
|
|||
Environment $environment,
|
||||
PaymentsEndpoint $payments_endpoint
|
||||
) {
|
||||
|
||||
$this->id = self::ID;
|
||||
$this->settings_renderer = $settings_renderer;
|
||||
$this->order_processor = $order_processor;
|
||||
$this->authorized_payments_processor = $authorized_payments_processor;
|
||||
$this->settings_renderer = $settings_renderer;
|
||||
$this->config = $config;
|
||||
$this->module_url = $module_url;
|
||||
$this->session_handler = $session_handler;
|
||||
$this->refund_processor = $refund_processor;
|
||||
$this->state = $state;
|
||||
$this->transaction_url_provider = $transaction_url_provider;
|
||||
$this->payment_token_repository = $payment_token_repository;
|
||||
$this->purchase_unit_factory = $purchase_unit_factory;
|
||||
$this->shipping_preference_factory = $shipping_preference_factory;
|
||||
$this->payer_factory = $payer_factory;
|
||||
$this->order_endpoint = $order_endpoint;
|
||||
$this->subscription_helper = $subscription_helper;
|
||||
$this->logger = $logger;
|
||||
$this->environment = $environment;
|
||||
$this->payments_endpoint = $payments_endpoint;
|
||||
|
||||
if ( $state->current_state() === State::STATE_ONBOARDED ) {
|
||||
$this->supports = array( 'refunds' );
|
||||
|
@ -261,18 +282,6 @@ class CreditCardGateway extends \WC_Payment_Gateway_CC {
|
|||
'process_admin_options',
|
||||
)
|
||||
);
|
||||
|
||||
$this->module_url = $module_url;
|
||||
$this->payment_token_repository = $payment_token_repository;
|
||||
$this->purchase_unit_factory = $purchase_unit_factory;
|
||||
$this->shipping_preference_factory = $shipping_preference_factory;
|
||||
$this->payer_factory = $payer_factory;
|
||||
$this->order_endpoint = $order_endpoint;
|
||||
$this->transaction_url_provider = $transaction_url_provider;
|
||||
$this->subscription_helper = $subscription_helper;
|
||||
$this->logger = $logger;
|
||||
$this->payments_endpoint = $payments_endpoint;
|
||||
$this->state = $state;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -295,20 +304,6 @@ class CreditCardGateway extends \WC_Payment_Gateway_CC {
|
|||
remove_action( 'gettext', 'replace_credit_card_cvv_label' );
|
||||
}
|
||||
|
||||
/**
|
||||
* Renders the settings.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function generate_ppcp_html(): string {
|
||||
|
||||
ob_start();
|
||||
$this->settings_renderer->render();
|
||||
$content = ob_get_contents();
|
||||
ob_end_clean();
|
||||
return $content;
|
||||
}
|
||||
|
||||
/**
|
||||
* Replace WooCommerce credit card field label.
|
||||
*
|
||||
|
@ -409,6 +404,158 @@ class CreditCardGateway extends \WC_Payment_Gateway_CC {
|
|||
return $this->is_enabled();
|
||||
}
|
||||
|
||||
/**
|
||||
* 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 a saved credit card payment.
|
||||
*/
|
||||
$saved_credit_card = filter_input( INPUT_POST, 'saved_credit_card', FILTER_SANITIZE_STRING );
|
||||
$change_payment = filter_input( INPUT_POST, 'woocommerce_change_payment', FILTER_SANITIZE_STRING );
|
||||
if ( $saved_credit_card && ! isset( $change_payment ) ) {
|
||||
|
||||
$user_id = (int) $wc_order->get_customer_id();
|
||||
$customer = new \WC_Customer( $user_id );
|
||||
$tokens = $this->payment_token_repository->all_for_user_id( (int) $customer->get_id() );
|
||||
|
||||
$selected_token = null;
|
||||
foreach ( $tokens as $token ) {
|
||||
if ( $token->id() === $saved_credit_card ) {
|
||||
$selected_token = $token;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if ( ! $selected_token ) {
|
||||
return $this->handle_payment_failure(
|
||||
$wc_order,
|
||||
new GatewayGenericException( new Exception( 'Saved card token not found.' ) )
|
||||
);
|
||||
}
|
||||
|
||||
$purchase_unit = $this->purchase_unit_factory->from_wc_order( $wc_order );
|
||||
$payer = $this->payer_factory->from_customer( $customer );
|
||||
|
||||
$shipping_preference = $this->shipping_preference_factory->from_state(
|
||||
$purchase_unit,
|
||||
''
|
||||
);
|
||||
|
||||
try {
|
||||
$order = $this->order_endpoint->create(
|
||||
array( $purchase_unit ),
|
||||
$shipping_preference,
|
||||
$payer,
|
||||
$selected_token
|
||||
);
|
||||
|
||||
$this->add_paypal_meta( $wc_order, $order, $this->environment );
|
||||
|
||||
if ( ! $order->status()->is( OrderStatus::COMPLETED ) ) {
|
||||
return $this->handle_payment_failure(
|
||||
$wc_order,
|
||||
new GatewayGenericException( new Exception( "Unexpected status for order {$order->id()} using a saved card: {$order->status()->name()}." ) )
|
||||
);
|
||||
}
|
||||
|
||||
if ( ! in_array(
|
||||
$order->intent(),
|
||||
array( 'CAPTURE', 'AUTHORIZE' ),
|
||||
true
|
||||
) ) {
|
||||
return $this->handle_payment_failure(
|
||||
$wc_order,
|
||||
new GatewayGenericException( new Exception( "Could neither capture nor authorize order {$order->id()} using a saved card. Status: {$order->status()->name()}. Intent: {$order->intent()}." ) )
|
||||
);
|
||||
}
|
||||
|
||||
if ( $order->intent() === 'AUTHORIZE' ) {
|
||||
$order = $this->order_endpoint->authorize( $order );
|
||||
|
||||
$wc_order->update_meta_data( AuthorizedPaymentsProcessor::CAPTURED_META_KEY, 'false' );
|
||||
}
|
||||
|
||||
$transaction_id = $this->get_paypal_order_transaction_id( $order );
|
||||
if ( $transaction_id ) {
|
||||
$this->update_transaction_id( $transaction_id, $wc_order );
|
||||
}
|
||||
|
||||
$this->handle_new_order_status( $order, $wc_order );
|
||||
|
||||
if ( $this->is_free_trial_order( $wc_order ) ) {
|
||||
$this->authorized_payments_processor->void_authorizations( $order );
|
||||
$wc_order->payment_complete();
|
||||
} elseif ( $this->config->has( 'intent' ) && strtoupper( (string) $this->config->get( 'intent' ) ) === 'CAPTURE' ) {
|
||||
$this->authorized_payments_processor->capture_authorized_payment( $wc_order );
|
||||
}
|
||||
|
||||
return $this->handle_payment_success( $wc_order );
|
||||
} catch ( RuntimeException $error ) {
|
||||
return $this->handle_payment_failure( $wc_order, $error );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* If customer has chosen change Subscription payment.
|
||||
*/
|
||||
if ( $this->subscription_helper->has_subscription( $order_id ) && $this->subscription_helper->is_subscription_change_payment() ) {
|
||||
if ( $saved_credit_card ) {
|
||||
update_post_meta( $order_id, 'payment_token_id', $saved_credit_card );
|
||||
|
||||
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.
|
||||
|
@ -500,11 +647,11 @@ class CreditCardGateway extends \WC_Payment_Gateway_CC {
|
|||
}
|
||||
|
||||
/**
|
||||
* Returns the environment.
|
||||
* Returns the settings renderer.
|
||||
*
|
||||
* @return Environment
|
||||
* @return SettingsRenderer
|
||||
*/
|
||||
protected function environment(): Environment {
|
||||
return $this->environment;
|
||||
protected function settings_renderer(): SettingsRenderer {
|
||||
return $this->settings_renderer;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,37 @@
|
|||
<?php
|
||||
/**
|
||||
* Adds generate_ppcp_html method for rendering settings.
|
||||
*
|
||||
* @package WooCommerce\PayPalCommerce\WcGateway\Gateway
|
||||
*/
|
||||
|
||||
declare( strict_types=1 );
|
||||
|
||||
namespace WooCommerce\PayPalCommerce\WcGateway\Gateway;
|
||||
|
||||
use WooCommerce\PayPalCommerce\WcGateway\Settings\SettingsRenderer;
|
||||
|
||||
/**
|
||||
* Trait GatewaySettingsRendererTrait
|
||||
*/
|
||||
trait GatewaySettingsRendererTrait {
|
||||
/**
|
||||
* Renders the settings.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function generate_ppcp_html(): string {
|
||||
ob_start();
|
||||
$this->settings_renderer()->render();
|
||||
$content = ob_get_contents();
|
||||
ob_end_clean();
|
||||
return $content;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the settings renderer.
|
||||
*
|
||||
* @return SettingsRenderer
|
||||
*/
|
||||
abstract protected function settings_renderer(): SettingsRenderer;
|
||||
}
|
27
modules/ppcp-wc-gateway/src/Gateway/Messages.php
Normal file
27
modules/ppcp-wc-gateway/src/Gateway/Messages.php
Normal file
|
@ -0,0 +1,27 @@
|
|||
<?php
|
||||
/**
|
||||
* Common messages.
|
||||
*
|
||||
* @package WooCommerce\PayPalCommerce\WcGateway\Gateway
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace WooCommerce\PayPalCommerce\WcGateway\Gateway;
|
||||
|
||||
/**
|
||||
* Class Messages
|
||||
*/
|
||||
class Messages {
|
||||
/**
|
||||
* The generic payment failure message.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public static function generic_payment_error_message(): string {
|
||||
return apply_filters(
|
||||
'woocommerce_paypal_payments_generic_payment_error_message',
|
||||
__( 'Failed to process the payment. Please try again or contact the shop admin.', 'woocommerce-paypal-payments' )
|
||||
);
|
||||
}
|
||||
}
|
|
@ -9,18 +9,21 @@ declare(strict_types=1);
|
|||
|
||||
namespace WooCommerce\PayPalCommerce\WcGateway\Gateway;
|
||||
|
||||
use Exception;
|
||||
use Psr\Log\LoggerInterface;
|
||||
use WooCommerce\PayPalCommerce\ApiClient\Endpoint\OrderEndpoint;
|
||||
use WooCommerce\PayPalCommerce\ApiClient\Endpoint\PaymentsEndpoint;
|
||||
use WooCommerce\PayPalCommerce\ApiClient\Factory\ShippingPreferenceFactory;
|
||||
use WC_Order;
|
||||
use WooCommerce\PayPalCommerce\ApiClient\Entity\PaymentToken;
|
||||
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\FundingSource\FundingSourceRenderer;
|
||||
use WooCommerce\PayPalCommerce\WcGateway\Gateway\PayUponInvoice\PayUponInvoiceGateway;
|
||||
use WooCommerce\PayPalCommerce\WcGateway\Processor\AuthorizedPaymentsProcessor;
|
||||
use WooCommerce\PayPalCommerce\WcGateway\Processor\OrderProcessor;
|
||||
use WooCommerce\PayPalCommerce\WcGateway\Processor\RefundProcessor;
|
||||
use WooCommerce\PayPalCommerce\WcGateway\Settings\SettingsRenderer;
|
||||
|
@ -32,7 +35,7 @@ use WooCommerce\PayPalCommerce\Webhooks\Status\WebhooksStatusPage;
|
|||
*/
|
||||
class PayPalGateway extends \WC_Payment_Gateway {
|
||||
|
||||
use ProcessPaymentTrait;
|
||||
use ProcessPaymentTrait, FreeTrialHandlerTrait, GatewaySettingsRendererTrait;
|
||||
|
||||
const ID = 'ppcp-gateway';
|
||||
const INTENT_META_KEY = '_ppcp_paypal_intent';
|
||||
|
@ -63,13 +66,6 @@ class PayPalGateway extends \WC_Payment_Gateway {
|
|||
*/
|
||||
protected $order_processor;
|
||||
|
||||
/**
|
||||
* The processor for authorized payments.
|
||||
*
|
||||
* @var AuthorizedPaymentsProcessor
|
||||
*/
|
||||
protected $authorized_payments_processor;
|
||||
|
||||
/**
|
||||
* The settings.
|
||||
*
|
||||
|
@ -119,27 +115,6 @@ class PayPalGateway extends \WC_Payment_Gateway {
|
|||
*/
|
||||
protected $payment_token_repository;
|
||||
|
||||
/**
|
||||
* The shipping_preference factory.
|
||||
*
|
||||
* @var ShippingPreferenceFactory
|
||||
*/
|
||||
private $shipping_preference_factory;
|
||||
|
||||
/**
|
||||
* The payments endpoint
|
||||
*
|
||||
* @var PaymentsEndpoint
|
||||
*/
|
||||
protected $payments_endpoint;
|
||||
|
||||
/**
|
||||
* The order endpoint.
|
||||
*
|
||||
* @var OrderEndpoint
|
||||
*/
|
||||
protected $order_endpoint;
|
||||
|
||||
/**
|
||||
* Whether the plugin is in onboarded state.
|
||||
*
|
||||
|
@ -178,30 +153,25 @@ class PayPalGateway extends \WC_Payment_Gateway {
|
|||
/**
|
||||
* PayPalGateway constructor.
|
||||
*
|
||||
* @param SettingsRenderer $settings_renderer The Settings Renderer.
|
||||
* @param FundingSourceRenderer $funding_source_renderer The funding source renderer.
|
||||
* @param OrderProcessor $order_processor The Order Processor.
|
||||
* @param AuthorizedPaymentsProcessor $authorized_payments_processor The Authorized Payments 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 string $page_id ID of the current PPCP gateway settings page, or empty if it is not such page.
|
||||
* @param Environment $environment The environment.
|
||||
* @param PaymentTokenRepository $payment_token_repository The payment token repository.
|
||||
* @param ShippingPreferenceFactory $shipping_preference_factory The shipping_preference factory.
|
||||
* @param LoggerInterface $logger The logger.
|
||||
* @param PaymentsEndpoint $payments_endpoint The payments endpoint.
|
||||
* @param OrderEndpoint $order_endpoint The order endpoint.
|
||||
* @param string $api_shop_country The api shop country.
|
||||
* @param SettingsRenderer $settings_renderer The Settings Renderer.
|
||||
* @param FundingSourceRenderer $funding_source_renderer The funding source renderer.
|
||||
* @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 string $page_id ID of the current PPCP gateway settings page, or empty if it is not such page.
|
||||
* @param Environment $environment The environment.
|
||||
* @param PaymentTokenRepository $payment_token_repository The payment token repository.
|
||||
* @param LoggerInterface $logger The logger.
|
||||
* @param string $api_shop_country The api shop country.
|
||||
*/
|
||||
public function __construct(
|
||||
SettingsRenderer $settings_renderer,
|
||||
FundingSourceRenderer $funding_source_renderer,
|
||||
OrderProcessor $order_processor,
|
||||
AuthorizedPaymentsProcessor $authorized_payments_processor,
|
||||
ContainerInterface $config,
|
||||
SessionHandler $session_handler,
|
||||
RefundProcessor $refund_processor,
|
||||
|
@ -211,37 +181,25 @@ class PayPalGateway extends \WC_Payment_Gateway {
|
|||
string $page_id,
|
||||
Environment $environment,
|
||||
PaymentTokenRepository $payment_token_repository,
|
||||
ShippingPreferenceFactory $shipping_preference_factory,
|
||||
LoggerInterface $logger,
|
||||
PaymentsEndpoint $payments_endpoint,
|
||||
OrderEndpoint $order_endpoint,
|
||||
string $api_shop_country
|
||||
) {
|
||||
|
||||
$this->id = self::ID;
|
||||
$this->order_processor = $order_processor;
|
||||
$this->authorized_payments_processor = $authorized_payments_processor;
|
||||
$this->settings_renderer = $settings_renderer;
|
||||
$this->funding_source_renderer = $funding_source_renderer;
|
||||
$this->config = $config;
|
||||
$this->session_handler = $session_handler;
|
||||
$this->refund_processor = $refund_processor;
|
||||
$this->transaction_url_provider = $transaction_url_provider;
|
||||
$this->page_id = $page_id;
|
||||
$this->environment = $environment;
|
||||
$this->onboarded = $state->current_state() === State::STATE_ONBOARDED;
|
||||
$this->id = self::ID;
|
||||
$this->order_processor = $order_processor;
|
||||
$this->authorized_payments = $authorized_payments_processor;
|
||||
$this->shipping_preference_factory = $shipping_preference_factory;
|
||||
$this->settings_renderer = $settings_renderer;
|
||||
$this->config = $config;
|
||||
$this->session_handler = $session_handler;
|
||||
$this->refund_processor = $refund_processor;
|
||||
$this->transaction_url_provider = $transaction_url_provider;
|
||||
$this->page_id = $page_id;
|
||||
$this->environment = $environment;
|
||||
$this->logger = $logger;
|
||||
$this->id = self::ID;
|
||||
$this->settings_renderer = $settings_renderer;
|
||||
$this->funding_source_renderer = $funding_source_renderer;
|
||||
$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->page_id = $page_id;
|
||||
$this->environment = $environment;
|
||||
$this->onboarded = $state->current_state() === State::STATE_ONBOARDED;
|
||||
$this->payment_token_repository = $payment_token_repository;
|
||||
$this->logger = $logger;
|
||||
$this->api_shop_country = $api_shop_country;
|
||||
|
||||
if ( $this->onboarded ) {
|
||||
$this->supports = array( 'refunds' );
|
||||
|
@ -291,13 +249,6 @@ class PayPalGateway extends \WC_Payment_Gateway {
|
|||
'process_admin_options',
|
||||
)
|
||||
);
|
||||
$this->subscription_helper = $subscription_helper;
|
||||
$this->payment_token_repository = $payment_token_repository;
|
||||
$this->logger = $logger;
|
||||
$this->payments_endpoint = $payments_endpoint;
|
||||
$this->order_endpoint = $order_endpoint;
|
||||
$this->state = $state;
|
||||
$this->api_shop_country = $api_shop_country;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -306,7 +257,6 @@ class PayPalGateway extends \WC_Payment_Gateway {
|
|||
* @return bool
|
||||
*/
|
||||
public function needs_setup(): bool {
|
||||
|
||||
return ! $this->onboarded;
|
||||
}
|
||||
|
||||
|
@ -334,20 +284,6 @@ class PayPalGateway extends \WC_Payment_Gateway {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Renders the settings.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function generate_ppcp_html(): string {
|
||||
|
||||
ob_start();
|
||||
$this->settings_renderer->render( false );
|
||||
$content = ob_get_contents();
|
||||
ob_end_clean();
|
||||
return $content;
|
||||
}
|
||||
|
||||
/**
|
||||
* Defines the method title. If we are on the credit card tab in the settings, we want to change this.
|
||||
*
|
||||
|
@ -450,6 +386,118 @@ class PayPalGateway extends \WC_Payment_Gateway {
|
|||
}
|
||||
// phpcs:enable WordPress.Security.NonceVerification.Recommended
|
||||
|
||||
/**
|
||||
* 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.' ) )
|
||||
);
|
||||
}
|
||||
|
||||
$funding_source = filter_input( INPUT_POST, 'ppcp-funding-source', FILTER_SANITIZE_STRING );
|
||||
|
||||
if ( 'card' !== $funding_source && $this->is_free_trial_order( $wc_order ) ) {
|
||||
$user_id = (int) $wc_order->get_customer_id();
|
||||
$tokens = $this->payment_token_repository->all_for_user_id( $user_id );
|
||||
if ( ! array_filter(
|
||||
$tokens,
|
||||
function ( PaymentToken $token ): bool {
|
||||
return isset( $token->source()->paypal );
|
||||
}
|
||||
) ) {
|
||||
return $this->handle_payment_failure( $wc_order, new Exception( 'No saved PayPal account.' ) );
|
||||
}
|
||||
|
||||
$wc_order->payment_complete();
|
||||
|
||||
return $this->handle_payment_success( $wc_order );
|
||||
}
|
||||
|
||||
/**
|
||||
* 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 ) {
|
||||
if ( $error->has_detail( 'INSTRUMENT_DECLINED' ) ) {
|
||||
$wc_order->update_status(
|
||||
'failed',
|
||||
__( 'Instrument declined. ', 'woocommerce-paypal-payments' ) . $error->details()[0]->description ?? ''
|
||||
);
|
||||
|
||||
$this->session_handler->increment_insufficient_funding_tries();
|
||||
if ( $this->session_handler->insufficient_funding_tries() >= 3 ) {
|
||||
return $this->handle_payment_failure(
|
||||
null,
|
||||
new Exception(
|
||||
__( 'Please use a different payment method.', 'woocommerce-paypal-payments' ),
|
||||
$error->getCode(),
|
||||
$error
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
$host = $this->config->has( 'sandbox_on' ) && $this->config->get( 'sandbox_on' ) ?
|
||||
'https://www.sandbox.paypal.com/' : 'https://www.paypal.com/';
|
||||
$url = $host . 'checkoutnow?token=' . $this->session_handler->order()->id();
|
||||
return array(
|
||||
'result' => 'success',
|
||||
'redirect' => $url,
|
||||
);
|
||||
}
|
||||
|
||||
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.
|
||||
*
|
||||
|
@ -503,11 +551,11 @@ class PayPalGateway extends \WC_Payment_Gateway {
|
|||
}
|
||||
|
||||
/**
|
||||
* Returns the environment.
|
||||
* Returns the settings renderer.
|
||||
*
|
||||
* @return Environment
|
||||
* @return SettingsRenderer
|
||||
*/
|
||||
protected function environment(): Environment {
|
||||
return $this->environment;
|
||||
protected function settings_renderer(): SettingsRenderer {
|
||||
return $this->settings_renderer;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -10,279 +10,14 @@ declare( strict_types=1 );
|
|||
namespace WooCommerce\PayPalCommerce\WcGateway\Gateway;
|
||||
|
||||
use Exception;
|
||||
use WooCommerce\PayPalCommerce\ApiClient\Entity\OrderStatus;
|
||||
use WooCommerce\PayPalCommerce\ApiClient\Entity\PaymentToken;
|
||||
use WooCommerce\PayPalCommerce\ApiClient\Exception\PayPalApiException;
|
||||
use WooCommerce\PayPalCommerce\ApiClient\Exception\RuntimeException;
|
||||
use WooCommerce\PayPalCommerce\Onboarding\Environment;
|
||||
use WooCommerce\PayPalCommerce\Subscription\FreeTrialHandlerTrait;
|
||||
use WooCommerce\PayPalCommerce\WcGateway\Processor\AuthorizedPaymentsProcessor;
|
||||
use WooCommerce\PayPalCommerce\WcGateway\Processor\OrderMetaTrait;
|
||||
use WooCommerce\PayPalCommerce\WcGateway\Processor\PaymentsStatusHandlingTrait;
|
||||
use WooCommerce\PayPalCommerce\WcGateway\Processor\TransactionIdHandlingTrait;
|
||||
use Throwable;
|
||||
use WC_Order;
|
||||
use WooCommerce\PayPalCommerce\WcGateway\Exception\GatewayGenericException;
|
||||
|
||||
/**
|
||||
* Trait ProcessPaymentTrait
|
||||
*/
|
||||
trait ProcessPaymentTrait {
|
||||
|
||||
use OrderMetaTrait, PaymentsStatusHandlingTrait, TransactionIdHandlingTrait, FreeTrialHandlerTrait;
|
||||
|
||||
/**
|
||||
* Process a payment for an WooCommerce order.
|
||||
*
|
||||
* @param int $order_id The WooCommerce order id.
|
||||
*
|
||||
* @return array
|
||||
*
|
||||
* @throws RuntimeException When processing payment fails.
|
||||
*/
|
||||
public function process_payment( $order_id ) {
|
||||
|
||||
$failure_data = array(
|
||||
'result' => 'failure',
|
||||
'redirect' => wc_get_checkout_url(),
|
||||
);
|
||||
|
||||
$wc_order = wc_get_order( $order_id );
|
||||
if ( ! is_a( $wc_order, \WC_Order::class ) ) {
|
||||
wc_add_notice(
|
||||
__( 'Couldn\'t find order to process', 'woocommerce-paypal-payments' ),
|
||||
'error'
|
||||
);
|
||||
|
||||
return $failure_data;
|
||||
}
|
||||
|
||||
$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.
|
||||
*/
|
||||
$saved_credit_card = filter_input( INPUT_POST, 'saved_credit_card', FILTER_SANITIZE_STRING );
|
||||
$change_payment = filter_input( INPUT_POST, 'woocommerce_change_payment', FILTER_SANITIZE_STRING );
|
||||
if ( CreditCardGateway::ID === $payment_method && $saved_credit_card && ! isset( $change_payment ) ) {
|
||||
|
||||
$user_id = (int) $wc_order->get_customer_id();
|
||||
$customer = new \WC_Customer( $user_id );
|
||||
$tokens = $this->payment_token_repository->all_for_user_id( (int) $customer->get_id() );
|
||||
|
||||
$selected_token = null;
|
||||
foreach ( $tokens as $token ) {
|
||||
if ( $token->id() === $saved_credit_card ) {
|
||||
$selected_token = $token;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if ( ! $selected_token ) {
|
||||
return null;
|
||||
}
|
||||
|
||||
$purchase_unit = $this->purchase_unit_factory->from_wc_order( $wc_order );
|
||||
$payer = $this->payer_factory->from_customer( $customer );
|
||||
|
||||
$shipping_preference = $this->shipping_preference_factory->from_state(
|
||||
$purchase_unit,
|
||||
''
|
||||
);
|
||||
|
||||
try {
|
||||
$order = $this->order_endpoint->create(
|
||||
array( $purchase_unit ),
|
||||
$shipping_preference,
|
||||
$payer,
|
||||
$selected_token
|
||||
);
|
||||
|
||||
$this->add_paypal_meta( $wc_order, $order, $this->environment() );
|
||||
|
||||
if ( ! $order->status()->is( OrderStatus::COMPLETED ) ) {
|
||||
$this->logger->warning( "Unexpected status for order {$order->id()} using a saved credit card: " . $order->status()->name() );
|
||||
return null;
|
||||
}
|
||||
|
||||
if ( ! in_array(
|
||||
$order->intent(),
|
||||
array( 'CAPTURE', 'AUTHORIZE' ),
|
||||
true
|
||||
) ) {
|
||||
$this->logger->warning( "Could neither capture nor authorize order {$order->id()} using a saved credit card:" . 'Status: ' . $order->status()->name() . ' Intent: ' . $order->intent() );
|
||||
return null;
|
||||
}
|
||||
|
||||
if ( $order->intent() === 'AUTHORIZE' ) {
|
||||
$order = $this->order_endpoint->authorize( $order );
|
||||
|
||||
$wc_order->update_meta_data( AuthorizedPaymentsProcessor::CAPTURED_META_KEY, 'false' );
|
||||
}
|
||||
|
||||
$transaction_id = $this->get_paypal_order_transaction_id( $order );
|
||||
if ( $transaction_id ) {
|
||||
$this->update_transaction_id( $transaction_id, $wc_order );
|
||||
}
|
||||
|
||||
$this->handle_new_order_status( $order, $wc_order );
|
||||
|
||||
if ( $this->is_free_trial_order( $wc_order ) ) {
|
||||
$this->authorized_payments_processor->void_authorizations( $order );
|
||||
$wc_order->payment_complete();
|
||||
} elseif ( $this->config->has( 'intent' ) && strtoupper( (string) $this->config->get( 'intent' ) ) === 'CAPTURE' ) {
|
||||
$this->authorized_payments_processor->capture_authorized_payment( $wc_order );
|
||||
}
|
||||
|
||||
$this->session_handler->destroy_session_data();
|
||||
return array(
|
||||
'result' => 'success',
|
||||
'redirect' => $this->get_return_url( $wc_order ),
|
||||
);
|
||||
} catch ( RuntimeException $error ) {
|
||||
$this->handle_failure( $wc_order, $error );
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
if ( PayPalGateway::ID === $payment_method && 'card' !== $funding_source && $this->is_free_trial_order( $wc_order ) ) {
|
||||
$user_id = (int) $wc_order->get_customer_id();
|
||||
$tokens = $this->payment_token_repository->all_for_user_id( $user_id );
|
||||
if ( ! array_filter(
|
||||
$tokens,
|
||||
function ( PaymentToken $token ): bool {
|
||||
return isset( $token->source()->paypal );
|
||||
}
|
||||
) ) {
|
||||
$this->handle_failure( $wc_order, new Exception( 'No saved PayPal account.' ) );
|
||||
return null;
|
||||
}
|
||||
|
||||
$wc_order->payment_complete();
|
||||
|
||||
$this->session_handler->destroy_session_data();
|
||||
return array(
|
||||
'result' => 'success',
|
||||
'redirect' => $this->get_return_url( $wc_order ),
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* If customer has chosen change Subscription payment.
|
||||
*/
|
||||
if ( $this->subscription_helper->has_subscription( $order_id ) && $this->subscription_helper->is_subscription_change_payment() ) {
|
||||
if ( 'ppcp-credit-card-gateway' === $this->id && $saved_credit_card ) {
|
||||
update_post_meta( $order_id, 'payment_token_id', $saved_credit_card );
|
||||
|
||||
$this->session_handler->destroy_session_data();
|
||||
return array(
|
||||
'result' => 'success',
|
||||
'redirect' => $this->get_return_url( $wc_order ),
|
||||
);
|
||||
}
|
||||
|
||||
$saved_paypal_payment = filter_input( INPUT_POST, 'saved_paypal_payment', FILTER_SANITIZE_STRING );
|
||||
if ( 'ppcp-gateway' === $this->id && $saved_paypal_payment ) {
|
||||
update_post_meta( $order_id, 'payment_token_id', $saved_paypal_payment );
|
||||
|
||||
$this->session_handler->destroy_session_data();
|
||||
return array(
|
||||
'result' => 'success',
|
||||
'redirect' => $this->get_return_url( $wc_order ),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* If the WC_Order is payed through the approved webhook.
|
||||
*/
|
||||
//phpcs:disable WordPress.Security.NonceVerification.Recommended
|
||||
if ( isset( $_REQUEST['ppcp-resume-order'] ) && $wc_order->has_status( 'processing' ) ) {
|
||||
$this->session_handler->destroy_session_data();
|
||||
return array(
|
||||
'result' => 'success',
|
||||
'redirect' => $this->get_return_url( $wc_order ),
|
||||
);
|
||||
}
|
||||
//phpcs:enable WordPress.Security.NonceVerification.Recommended
|
||||
|
||||
try {
|
||||
if ( $this->order_processor->process( $wc_order ) ) {
|
||||
if ( $this->subscription_helper->has_subscription( $order_id ) ) {
|
||||
as_schedule_single_action(
|
||||
time() + ( 1 * MINUTE_IN_SECONDS ),
|
||||
'woocommerce_paypal_payments_check_saved_payment',
|
||||
array(
|
||||
'order_id' => $order_id,
|
||||
'customer_id' => $wc_order->get_customer_id(),
|
||||
'intent' => $this->config->has( 'intent' ) ? $this->config->get( 'intent' ) : '',
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
WC()->cart->empty_cart();
|
||||
$this->session_handler->destroy_session_data();
|
||||
|
||||
return array(
|
||||
'result' => 'success',
|
||||
'redirect' => $this->get_return_url( $wc_order ),
|
||||
);
|
||||
}
|
||||
} catch ( PayPalApiException $error ) {
|
||||
if ( $error->has_detail( 'INSTRUMENT_DECLINED' ) ) {
|
||||
$wc_order->update_status(
|
||||
'failed',
|
||||
__( 'Instrument declined. ', 'woocommerce-paypal-payments' ) . $error->details()[0]->description ?? ''
|
||||
);
|
||||
|
||||
$this->session_handler->increment_insufficient_funding_tries();
|
||||
$host = $this->config->has( 'sandbox_on' ) && $this->config->get( 'sandbox_on' ) ?
|
||||
'https://www.sandbox.paypal.com/' : 'https://www.paypal.com/';
|
||||
$url = $host . 'checkoutnow?token=' . $this->session_handler->order()->id();
|
||||
if ( $this->session_handler->insufficient_funding_tries() >= 3 ) {
|
||||
$this->session_handler->destroy_session_data();
|
||||
wc_add_notice(
|
||||
__( 'Please use a different payment method.', 'woocommerce-paypal-payments' ),
|
||||
'error'
|
||||
);
|
||||
return $failure_data;
|
||||
}
|
||||
return array(
|
||||
'result' => 'success',
|
||||
'redirect' => $url,
|
||||
);
|
||||
}
|
||||
|
||||
$error_message = $error->getMessage();
|
||||
if ( $error->issues() ) {
|
||||
$error_message = implode(
|
||||
array_map(
|
||||
function( $issue ) {
|
||||
return $issue->issue . ' ' . $issue->description . '<br/>';
|
||||
},
|
||||
$error->issues()
|
||||
)
|
||||
);
|
||||
}
|
||||
wc_add_notice( $error_message, 'error' );
|
||||
|
||||
$this->session_handler->destroy_session_data();
|
||||
} catch ( RuntimeException $error ) {
|
||||
$this->handle_failure( $wc_order, $error );
|
||||
return $failure_data;
|
||||
}
|
||||
|
||||
wc_add_notice(
|
||||
$this->order_processor->last_error(),
|
||||
'error'
|
||||
);
|
||||
|
||||
$wc_order->update_status(
|
||||
'failed',
|
||||
__( 'Could not process order. ', 'woocommerce-paypal-payments' ) . $this->order_processor->last_error()
|
||||
);
|
||||
|
||||
return $failure_data;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if PayPal or Credit Card gateways are enabled.
|
||||
*
|
||||
|
@ -311,29 +46,86 @@ trait ProcessPaymentTrait {
|
|||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Scheduled the vaulted payment check.
|
||||
*
|
||||
* @param int $wc_order_id The WC order ID.
|
||||
* @param int $customer_id The customer ID.
|
||||
*/
|
||||
protected function schedule_saved_payment_check( int $wc_order_id, int $customer_id ): void {
|
||||
as_schedule_single_action(
|
||||
time() + ( 1 * MINUTE_IN_SECONDS ),
|
||||
'woocommerce_paypal_payments_check_saved_payment',
|
||||
array(
|
||||
'order_id' => $wc_order_id,
|
||||
'customer_id' => $customer_id,
|
||||
'intent' => $this->config->has( 'intent' ) ? $this->config->get( 'intent' ) : '',
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles the payment failure.
|
||||
*
|
||||
* @param \WC_Order $wc_order The order.
|
||||
* @param Exception $error The error causing the failure.
|
||||
* @param WC_Order|null $wc_order The order.
|
||||
* @param Exception $error The error causing the failure.
|
||||
* @return array The data that can be returned by the gateway process_payment method.
|
||||
*/
|
||||
protected function handle_failure( \WC_Order $wc_order, Exception $error ): void {
|
||||
$this->logger->error( 'Payment failed: ' . $error->getMessage() );
|
||||
protected function handle_payment_failure( ?WC_Order $wc_order, Exception $error ): array {
|
||||
$this->logger->error( 'Payment failed: ' . $this->format_exception( $error ) );
|
||||
|
||||
$wc_order->update_status(
|
||||
'failed',
|
||||
__( 'Could not process order. ', 'woocommerce-paypal-payments' ) . $error->getMessage()
|
||||
);
|
||||
if ( $wc_order ) {
|
||||
$wc_order->update_status(
|
||||
'failed',
|
||||
$this->format_exception( $error )
|
||||
);
|
||||
}
|
||||
|
||||
$this->session_handler->destroy_session_data();
|
||||
|
||||
wc_add_notice( $error->getMessage(), 'error' );
|
||||
|
||||
return array(
|
||||
'result' => 'failure',
|
||||
'redirect' => wc_get_checkout_url(),
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the environment.
|
||||
* Handles the payment completion.
|
||||
*
|
||||
* @return Environment
|
||||
* @param WC_Order|null $wc_order The order.
|
||||
* @param string|null $url The redirect URL.
|
||||
* @return array The data that can be returned by the gateway process_payment method.
|
||||
*/
|
||||
abstract protected function environment(): Environment;
|
||||
protected function handle_payment_success( ?WC_Order $wc_order, string $url = null ): array {
|
||||
if ( ! $url ) {
|
||||
$url = $this->get_return_url( $wc_order );
|
||||
}
|
||||
|
||||
$this->session_handler->destroy_session_data();
|
||||
|
||||
return array(
|
||||
'result' => 'success',
|
||||
'redirect' => $url,
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Outputs the exception, including the inner exception.
|
||||
*
|
||||
* @param Throwable $exception The exception to format.
|
||||
* @return string
|
||||
*/
|
||||
protected function format_exception( Throwable $exception ): string {
|
||||
$output = $exception->getMessage() . ' ' . $exception->getFile() . ':' . $exception->getLine();
|
||||
$prev = $exception->getPrevious();
|
||||
if ( ! $prev ) {
|
||||
return $output;
|
||||
}
|
||||
if ( $exception instanceof GatewayGenericException ) {
|
||||
$output = '';
|
||||
}
|
||||
return $output . ' ' . $this->format_exception( $prev );
|
||||
}
|
||||
}
|
||||
|
|
|
@ -98,6 +98,9 @@ class CheckoutHelper {
|
|||
if ( $date_time && time() < strtotime( '+18 years', $date_time ) ) {
|
||||
return false;
|
||||
}
|
||||
if ( $date_time < strtotime( '-100 years', time() ) ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
<?php
|
||||
/**
|
||||
* Creates the admin message about the DCC gateway being enabled without the PayPal gateway.
|
||||
* Creates the admin message about the gateway being enabled without the PayPal gateway.
|
||||
*
|
||||
* @package WooCommerce\PayPalCommerce\WcGateway\Notice
|
||||
*/
|
||||
|
@ -9,14 +9,21 @@ declare(strict_types=1);
|
|||
|
||||
namespace WooCommerce\PayPalCommerce\WcGateway\Notice;
|
||||
|
||||
use WC_Payment_Gateway;
|
||||
use WooCommerce\PayPalCommerce\AdminNotices\Entity\Message;
|
||||
use WooCommerce\PayPalCommerce\Onboarding\State;
|
||||
use Psr\Container\ContainerInterface;
|
||||
|
||||
/**
|
||||
* Creates the admin message about the DCC gateway being enabled without the PayPal gateway.
|
||||
* Creates the admin message about the gateway being enabled without the PayPal gateway.
|
||||
*/
|
||||
class DccWithoutPayPalAdminNotice {
|
||||
class GatewayWithoutPayPalAdminNotice {
|
||||
/**
|
||||
* The gateway ID.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
private $id;
|
||||
|
||||
/**
|
||||
* The state.
|
||||
|
@ -49,17 +56,20 @@ class DccWithoutPayPalAdminNotice {
|
|||
/**
|
||||
* ConnectAdminNotice constructor.
|
||||
*
|
||||
* @param string $id The gateway ID.
|
||||
* @param State $state The state.
|
||||
* @param ContainerInterface $settings The settings.
|
||||
* @param bool $is_payments_page Whether the current page is the WC payment page.
|
||||
* @param bool $is_ppcp_settings_page Whether the current page is the PPCP settings page.
|
||||
*/
|
||||
public function __construct(
|
||||
string $id,
|
||||
State $state,
|
||||
ContainerInterface $settings,
|
||||
bool $is_payments_page,
|
||||
bool $is_ppcp_settings_page
|
||||
) {
|
||||
$this->id = $id;
|
||||
$this->state = $state;
|
||||
$this->settings = $settings;
|
||||
$this->is_payments_page = $is_payments_page;
|
||||
|
@ -76,12 +86,20 @@ class DccWithoutPayPalAdminNotice {
|
|||
return null;
|
||||
}
|
||||
|
||||
$gateway = $this->get_gateway();
|
||||
if ( ! $gateway ) {
|
||||
return null;
|
||||
}
|
||||
|
||||
$name = $gateway->get_method_title();
|
||||
|
||||
$message = sprintf(
|
||||
/* translators: %1$s the gateway name. */
|
||||
/* translators: %1$s the gateway name, %2$s URL. */
|
||||
__(
|
||||
'PayPal Card Processing cannot be used without the PayPal gateway. <a href="%1$s">Enable the PayPal Gateway</a>.',
|
||||
'%1$s cannot be used without the PayPal gateway. <a href="%2$s">Enable the PayPal gateway</a>.',
|
||||
'woocommerce-paypal-payments'
|
||||
),
|
||||
$name,
|
||||
admin_url( 'admin.php?page=wc-settings&tab=checkout§ion=ppcp-gateway' )
|
||||
);
|
||||
return new Message( $message, 'warning' );
|
||||
|
@ -93,9 +111,29 @@ class DccWithoutPayPalAdminNotice {
|
|||
* @return bool
|
||||
*/
|
||||
protected function should_display(): bool {
|
||||
return State::STATE_ONBOARDED === $this->state->current_state()
|
||||
&& ( $this->is_payments_page || $this->is_ppcp_settings_page )
|
||||
&& ( $this->settings->has( 'dcc_enabled' ) && $this->settings->get( 'dcc_enabled' ) )
|
||||
&& ( ! $this->settings->has( 'enabled' ) || ! $this->settings->get( 'enabled' ) );
|
||||
if ( State::STATE_ONBOARDED !== $this->state->current_state() ||
|
||||
( ! $this->is_payments_page && ! $this->is_ppcp_settings_page ) ) {
|
||||
return false;
|
||||
}
|
||||
if ( $this->settings->has( 'enabled' ) && $this->settings->get( 'enabled' ) ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$gateway = $this->get_gateway();
|
||||
|
||||
return $gateway && wc_string_to_bool( $gateway->get_option( 'enabled' ) );
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the gateway object or null.
|
||||
*
|
||||
* @return WC_Payment_Gateway|null
|
||||
*/
|
||||
protected function get_gateway(): ?WC_Payment_Gateway {
|
||||
$gateways = WC()->payment_gateways->payment_gateways();
|
||||
if ( ! isset( $gateways[ $this->id ] ) ) {
|
||||
return null;
|
||||
}
|
||||
return $gateways[ $this->id ];
|
||||
}
|
||||
}
|
|
@ -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\Webhooks\Status\WebhooksStatusPage;
|
||||
|
@ -34,6 +35,7 @@ trait PageMatcherTrait {
|
|||
$gateway_page_id_map = array(
|
||||
PayPalGateway::ID => 'paypal',
|
||||
CreditCardGateway::ID => 'dcc', // TODO: consider using just the gateway ID for PayPal and DCC too.
|
||||
CardButtonGateway::ID => CardButtonGateway::ID,
|
||||
WebhooksStatusPage::ID => WebhooksStatusPage::ID,
|
||||
);
|
||||
return array_key_exists( $current_page_id, $gateway_page_id_map )
|
||||
|
|
|
@ -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>';
|
||||
}
|
||||
|
|
|
@ -29,7 +29,7 @@ use WooCommerce\PayPalCommerce\WcGateway\Exception\NotFoundException;
|
|||
use WooCommerce\PayPalCommerce\WcGateway\Gateway\CreditCardGateway;
|
||||
use WooCommerce\PayPalCommerce\WcGateway\Gateway\PayPalGateway;
|
||||
use WooCommerce\PayPalCommerce\WcGateway\Notice\ConnectAdminNotice;
|
||||
use WooCommerce\PayPalCommerce\WcGateway\Notice\DccWithoutPayPalAdminNotice;
|
||||
use WooCommerce\PayPalCommerce\WcGateway\Notice\GatewayWithoutPayPalAdminNotice;
|
||||
use WooCommerce\PayPalCommerce\WcGateway\Processor\AuthorizedPaymentsProcessor;
|
||||
use WooCommerce\PayPalCommerce\WcGateway\Settings\SectionsRenderer;
|
||||
use WooCommerce\PayPalCommerce\WcGateway\Settings\Settings;
|
||||
|
@ -164,11 +164,15 @@ class WCGatewayModule implements ModuleInterface {
|
|||
$notices[] = $connect_message;
|
||||
}
|
||||
|
||||
$dcc_without_paypal_notice = $c->get( 'wcgateway.notice.dcc-without-paypal' );
|
||||
assert( $dcc_without_paypal_notice instanceof DccWithoutPayPalAdminNotice );
|
||||
$dcc_without_paypal_message = $dcc_without_paypal_notice->message();
|
||||
if ( $dcc_without_paypal_message ) {
|
||||
$notices[] = $dcc_without_paypal_message;
|
||||
foreach ( array(
|
||||
$c->get( 'wcgateway.notice.dcc-without-paypal' ),
|
||||
$c->get( 'wcgateway.notice.card-button-without-paypal' ),
|
||||
) as $gateway_without_paypal_notice ) {
|
||||
assert( $gateway_without_paypal_notice instanceof GatewayWithoutPayPalAdminNotice );
|
||||
$message = $gateway_without_paypal_notice->message();
|
||||
if ( $message ) {
|
||||
$notices[] = $message;
|
||||
}
|
||||
}
|
||||
|
||||
$authorize_order_action = $c->get( 'wcgateway.notice.authorize-order-action' );
|
||||
|
@ -294,6 +298,10 @@ class WCGatewayModule implements ModuleInterface {
|
|||
$methods[] = $container->get( 'wcgateway.credit-card-gateway' );
|
||||
}
|
||||
|
||||
if ( $container->get( 'wcgateway.settings.allow_card_button_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' );
|
||||
}
|
||||
|
|
|
@ -46,7 +46,7 @@ class PaymentCaptureRefunded implements RequestHandler {
|
|||
* @return string[]
|
||||
*/
|
||||
public function event_types(): array {
|
||||
return array( 'PAYMENT.CAPTURE.REFUNDED' );
|
||||
return array( 'PAYMENT.CAPTURE.REFUNDED', 'PAYMENT.AUTHORIZATION.VOIDED' );
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -46,6 +46,7 @@ class IdentityTokenTest extends TestCase
|
|||
|
||||
public function testGenerateForCustomerReturnsToken()
|
||||
{
|
||||
$id = 1;
|
||||
define( 'PPCP_FLAG_SUBSCRIPTION', true );
|
||||
$token = Mockery::mock(Token::class);
|
||||
$token
|
||||
|
@ -60,6 +61,7 @@ class IdentityTokenTest extends TestCase
|
|||
$this->settings->shouldReceive('has')->andReturn(true);
|
||||
$this->settings->shouldReceive('get')->andReturn(true);
|
||||
$this->customer_repository->shouldReceive('customer_id_for_user')->andReturn('prefix1');
|
||||
expect('update_user_meta')->with($id, 'ppcp_customer_id', 'prefix1');
|
||||
|
||||
$rawResponse = [
|
||||
'body' => '{"client_token":"abc123", "expires_in":3600}',
|
||||
|
@ -97,6 +99,7 @@ class IdentityTokenTest extends TestCase
|
|||
|
||||
public function testGenerateForCustomerFailsBecauseWpError()
|
||||
{
|
||||
$id = 1;
|
||||
$token = Mockery::mock(Token::class);
|
||||
$token
|
||||
->expects('token')->andReturn('bearer');
|
||||
|
@ -111,7 +114,8 @@ class IdentityTokenTest extends TestCase
|
|||
$this->logger->shouldReceive('debug');
|
||||
$this->settings->shouldReceive('has')->andReturn(true);
|
||||
$this->settings->shouldReceive('get')->andReturn(true);
|
||||
$this->customer_repository->shouldReceive('customer_id_for_user');
|
||||
$this->customer_repository->shouldReceive('customer_id_for_user')->andReturn('prefix1');
|
||||
expect('update_user_meta')->with($id, 'ppcp_customer_id', 'prefix1');
|
||||
|
||||
$this->expectException(RuntimeException::class);
|
||||
$this->sut->generate_for_user(1);
|
||||
|
@ -119,6 +123,7 @@ class IdentityTokenTest extends TestCase
|
|||
|
||||
public function testGenerateForCustomerFailsBecauseResponseCodeIsNot200()
|
||||
{
|
||||
$id = 1;
|
||||
$token = Mockery::mock(Token::class);
|
||||
$token
|
||||
->expects('token')->andReturn('bearer');
|
||||
|
@ -137,7 +142,8 @@ class IdentityTokenTest extends TestCase
|
|||
$this->logger->shouldReceive('debug');
|
||||
$this->settings->shouldReceive('has')->andReturn(true);
|
||||
$this->settings->shouldReceive('get')->andReturn(true);
|
||||
$this->customer_repository->shouldReceive('customer_id_for_user');
|
||||
$this->customer_repository->shouldReceive('customer_id_for_user')->andReturn('prefix1');
|
||||
expect('update_user_meta')->with($id, 'ppcp_customer_id', 'prefix1');
|
||||
|
||||
$this->expectException(PayPalApiException::class);
|
||||
$this->sut->generate_for_user(1);
|
||||
|
|
|
@ -1046,8 +1046,6 @@ class OrderEndpointTest extends TestCase
|
|||
|
||||
$payer = Mockery::mock(Payer::class);
|
||||
$payer->expects('email_address')->andReturn('email@email.com');
|
||||
$payerName = Mockery::mock(PayerName::class);
|
||||
$payer->expects('name')->andReturn($payerName);
|
||||
$payer->expects('to_array')->andReturn(['payer']);
|
||||
$result = $testee->create([$purchaseUnit], ApplicationContext::SHIPPING_PREFERENCE_GET_FROM_FILE, $payer);
|
||||
$this->assertEquals($expectedOrder, $result);
|
||||
|
@ -1138,8 +1136,6 @@ class OrderEndpointTest extends TestCase
|
|||
|
||||
$payer = Mockery::mock(Payer::class);
|
||||
$payer->expects('email_address')->andReturn('email@email.com');
|
||||
$payerName = Mockery::mock(PayerName::class);
|
||||
$payer->expects('name')->andReturn($payerName);
|
||||
$payer->expects('to_array')->andReturn(['payer']);
|
||||
$testee->create([$purchaseUnit], ApplicationContext::SHIPPING_PREFERENCE_NO_SHIPPING, $payer);
|
||||
}
|
||||
|
@ -1229,8 +1225,6 @@ class OrderEndpointTest extends TestCase
|
|||
$this->expectException(RuntimeException::class);
|
||||
$payer = Mockery::mock(Payer::class);
|
||||
$payer->expects('email_address')->andReturn('email@email.com');
|
||||
$payerName = Mockery::mock(PayerName::class);
|
||||
$payer->expects('name')->andReturn($payerName);
|
||||
$payer->expects('to_array')->andReturn(['payer']);
|
||||
$testee->create([$purchaseUnit], ApplicationContext::SHIPPING_PREFERENCE_GET_FROM_FILE, $payer);
|
||||
}
|
||||
|
|
|
@ -14,6 +14,7 @@ use WooCommerce\PayPalCommerce\ApiClient\Factory\ShippingPreferenceFactory;
|
|||
use WooCommerce\PayPalCommerce\Button\Helper\EarlyOrderHandler;
|
||||
use WooCommerce\PayPalCommerce\Session\SessionHandler;
|
||||
use WooCommerce\PayPalCommerce\TestCase;
|
||||
use WooCommerce\PayPalCommerce\WcGateway\CardBillingMode;
|
||||
use WooCommerce\PayPalCommerce\WcGateway\Settings\Settings;
|
||||
|
||||
use WooCommerce\WooCommerce\Logging\Logger\NullLogger;
|
||||
|
@ -152,6 +153,7 @@ class CreateOrderEndpointTest extends TestCase
|
|||
$session_handler = Mockery::mock(SessionHandler::class);
|
||||
$settings = Mockery::mock(Settings::class);
|
||||
$early_order_handler = Mockery::mock(EarlyOrderHandler::class);
|
||||
$settings->shouldReceive('has')->andReturnFalse();
|
||||
|
||||
$testee = new CreateOrderEndpoint(
|
||||
$request_data,
|
||||
|
@ -163,6 +165,7 @@ class CreateOrderEndpointTest extends TestCase
|
|||
$settings,
|
||||
$early_order_handler,
|
||||
false,
|
||||
CardBillingMode::MINIMAL_INPUT,
|
||||
new NullLogger()
|
||||
);
|
||||
return array($payer_factory, $testee);
|
||||
|
|
|
@ -23,6 +23,8 @@ use Mockery;
|
|||
use Mockery\Adapter\Phpunit\MockeryPHPUnitIntegration;
|
||||
use WooCommerce\PayPalCommerce\Vaulting\PaymentTokenRepository;
|
||||
use WooCommerce\PayPalCommerce\WcGateway\Gateway\PayPalGateway;
|
||||
use WooCommerce\PayPalCommerce\WcGateway\Processor\AuthorizedPaymentsProcessor;
|
||||
use WooCommerce\PayPalCommerce\WcGateway\Settings\Settings;
|
||||
|
||||
class RenewalHandlerTest extends TestCase
|
||||
{
|
||||
|
@ -48,6 +50,11 @@ class RenewalHandlerTest extends TestCase
|
|||
$this->shippingPreferenceFactory = Mockery::mock(ShippingPreferenceFactory::class);
|
||||
$this->payerFactory = Mockery::mock(PayerFactory::class);
|
||||
$this->environment = new Environment(new Dictionary([]));
|
||||
$authorizedPaymentProcessor = Mockery::mock(AuthorizedPaymentsProcessor::class);
|
||||
$settings = Mockery::mock(Settings::class);
|
||||
$settings
|
||||
->shouldReceive('has')
|
||||
->andReturnFalse();
|
||||
|
||||
$this->logger->shouldReceive('error')->andReturnUsing(function ($msg) {
|
||||
throw new Exception($msg);
|
||||
|
@ -61,7 +68,9 @@ class RenewalHandlerTest extends TestCase
|
|||
$this->purchaseUnitFactory,
|
||||
$this->shippingPreferenceFactory,
|
||||
$this->payerFactory,
|
||||
$this->environment
|
||||
$this->environment,
|
||||
$settings,
|
||||
$authorizedPaymentProcessor
|
||||
);
|
||||
}
|
||||
|
||||
|
|
|
@ -3,14 +3,7 @@ declare(strict_types=1);
|
|||
|
||||
namespace WooCommerce\PayPalCommerce\WcGateway\Gateway;
|
||||
|
||||
use Psr\Container\ContainerInterface;
|
||||
use Psr\Log\LoggerInterface;
|
||||
use WooCommerce\PayPalCommerce\ApiClient\Endpoint\OrderEndpoint;
|
||||
use WooCommerce\PayPalCommerce\ApiClient\Endpoint\PaymentsEndpoint;
|
||||
use Psr\Log\NullLogger;
|
||||
use WooCommerce\PayPalCommerce\ApiClient\Entity\Capture;
|
||||
use WooCommerce\PayPalCommerce\ApiClient\Entity\CaptureStatus;
|
||||
use WooCommerce\PayPalCommerce\ApiClient\Factory\ShippingPreferenceFactory;
|
||||
use WooCommerce\PayPalCommerce\Onboarding\Environment;
|
||||
use WooCommerce\PayPalCommerce\Onboarding\State;
|
||||
use WooCommerce\PayPalCommerce\Session\SessionHandler;
|
||||
|
@ -37,7 +30,6 @@ class WcGatewayTest extends TestCase
|
|||
private $settingsRenderer;
|
||||
private $funding_source_renderer;
|
||||
private $orderProcessor;
|
||||
private $authorizedOrdersProcessor;
|
||||
private $settings;
|
||||
private $refundProcessor;
|
||||
private $onboardingState;
|
||||
|
@ -45,10 +37,7 @@ class WcGatewayTest extends TestCase
|
|||
private $subscriptionHelper;
|
||||
private $environment;
|
||||
private $paymentTokenRepository;
|
||||
private $shipping_preference_factory;
|
||||
private $logger;
|
||||
private $paymentsEndpoint;
|
||||
private $orderEndpoint;
|
||||
private $apiShopCountry;
|
||||
|
||||
public function setUp(): void {
|
||||
|
@ -60,7 +49,6 @@ class WcGatewayTest extends TestCase
|
|||
|
||||
$this->settingsRenderer = Mockery::mock(SettingsRenderer::class);
|
||||
$this->orderProcessor = Mockery::mock(OrderProcessor::class);
|
||||
$this->authorizedOrdersProcessor = Mockery::mock(AuthorizedPaymentsProcessor::class);
|
||||
$this->settings = Mockery::mock(Settings::class);
|
||||
$this->sessionHandler = Mockery::mock(SessionHandler::class);
|
||||
$this->refundProcessor = Mockery::mock(RefundProcessor::class);
|
||||
|
@ -69,10 +57,7 @@ class WcGatewayTest extends TestCase
|
|||
$this->subscriptionHelper = Mockery::mock(SubscriptionHelper::class);
|
||||
$this->environment = Mockery::mock(Environment::class);
|
||||
$this->paymentTokenRepository = Mockery::mock(PaymentTokenRepository::class);
|
||||
$this->shipping_preference_factory = Mockery::mock(ShippingPreferenceFactory::class);
|
||||
$this->logger = Mockery::mock(LoggerInterface::class);
|
||||
$this->paymentsEndpoint = Mockery::mock(PaymentsEndpoint::class);
|
||||
$this->orderEndpoint = Mockery::mock(OrderEndpoint::class);
|
||||
$this->funding_source_renderer = new FundingSourceRenderer($this->settings);
|
||||
$this->apiShopCountry = 'DE';
|
||||
|
||||
|
@ -87,6 +72,7 @@ class WcGatewayTest extends TestCase
|
|||
$this->settings->shouldReceive('has')->andReturnFalse();
|
||||
|
||||
$this->logger->shouldReceive('info');
|
||||
$this->logger->shouldReceive('error');
|
||||
}
|
||||
|
||||
private function createGateway()
|
||||
|
@ -95,7 +81,6 @@ class WcGatewayTest extends TestCase
|
|||
$this->settingsRenderer,
|
||||
$this->funding_source_renderer,
|
||||
$this->orderProcessor,
|
||||
$this->authorizedOrdersProcessor,
|
||||
$this->settings,
|
||||
$this->sessionHandler,
|
||||
$this->refundProcessor,
|
||||
|
@ -105,10 +90,7 @@ class WcGatewayTest extends TestCase
|
|||
PayPalGateway::ID,
|
||||
$this->environment,
|
||||
$this->paymentTokenRepository,
|
||||
$this->shipping_preference_factory,
|
||||
$this->logger,
|
||||
$this->paymentsEndpoint,
|
||||
$this->orderEndpoint,
|
||||
$this->apiShopCountry
|
||||
);
|
||||
}
|
||||
|
@ -173,8 +155,10 @@ class WcGatewayTest extends TestCase
|
|||
when('wc_get_checkout_url')
|
||||
->justReturn($redirectUrl);
|
||||
|
||||
expect('wc_add_notice')
|
||||
->with('Couldn\'t find order to process','error');
|
||||
$this->sessionHandler
|
||||
->shouldReceive('destroy_session_data');
|
||||
|
||||
expect('wc_add_notice');
|
||||
|
||||
$this->assertEquals(
|
||||
[
|
||||
|
@ -195,7 +179,6 @@ class WcGatewayTest extends TestCase
|
|||
->andReturnFalse();
|
||||
$this->orderProcessor
|
||||
->expects('last_error')
|
||||
->twice()
|
||||
->andReturn($lastError);
|
||||
$this->subscriptionHelper->shouldReceive('has_subscription')->with($orderId)->andReturn(true);
|
||||
$this->subscriptionHelper->shouldReceive('is_subscription_change_payment')->andReturn(true);
|
||||
|
@ -206,6 +189,8 @@ class WcGatewayTest extends TestCase
|
|||
expect('wc_get_order')
|
||||
->with($orderId)
|
||||
->andReturn($wcOrder);
|
||||
$this->sessionHandler
|
||||
->shouldReceive('destroy_session_data');
|
||||
expect('wc_add_notice')
|
||||
->with($lastError, 'error');
|
||||
|
||||
|
|
|
@ -27,6 +27,7 @@ class PayUponInvoiceHelperTest extends TestCase
|
|||
['1942-02-31', false],
|
||||
['01-01-1942', false],
|
||||
['1942-01-01', true],
|
||||
['0001-01-01', false],
|
||||
];
|
||||
}
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue