mirror of
https://github.com/woocommerce/woocommerce-paypal-payments.git
synced 2025-08-30 05:00:51 +08:00
Merge branch 'trunk' into PCP-591-save-and-display-vaulted-payment-methods-in-woo-commerce-native-endpoint
This commit is contained in:
commit
4737f9d203
46 changed files with 1327 additions and 311 deletions
|
@ -1 +1,10 @@
|
|||
PPCP_E2E_WP_DIR=${ROOT_DIR}/.ddev/wordpress
|
||||
|
||||
BASEURL="https://woocommerce-paypal-payments.ddev.site"
|
||||
|
||||
CUSTOMER_EMAIL="customer@example.com"
|
||||
CUSTOMER_PASSWORD="password"
|
||||
|
||||
CREDIT_CARD_NUMBER="1234567890"
|
||||
CREDIT_CARD_EXPIRATION="01/2042"
|
||||
CREDIT_CARD_CVV="123"
|
||||
|
|
|
@ -1,5 +1,28 @@
|
|||
*** Changelog ***
|
||||
|
||||
= 2.0.3 - TBD =
|
||||
* Fix - `DEVICE_DATA_NOT_AVAILABLE` error message when FraudNet is enabled #1177
|
||||
* Fix - Redirect to connection tab after manual credentials input #1201
|
||||
* Fix - Asking for address fields in checkout when not using them #1089
|
||||
* Fix - Validate before free trial #1170
|
||||
* Fix - Validate new user creation #1131
|
||||
* Fix - After Updating to 2.0.2, Site Health reports REST API error #1195
|
||||
* Fix - Do not send buyer-country for previews in live mode to avoid error #1186
|
||||
* Fix - PPEC compatibility layer does not take over subscriptions #1193
|
||||
* Enhancement - Save checkout form before free trial redirect #1135
|
||||
* Enhancement - Add filter for controlling the ditching of items/breakdown #1146
|
||||
* Enhancement - Add patch order data filter #1147
|
||||
* Enhancement - Add filter for disabling fees on wc order admin pages #1153
|
||||
* Enhancement - Use wp_loaded for fraudnet loading to avoid warnings #1172
|
||||
* Enhancement - reCaptcha for WooCommerce support #1093
|
||||
* Enhancement - Make it possible to hide missing funding resource Trustly #1155
|
||||
* Enhancement - Add white color option #1167
|
||||
* Enhancement - Checkout validation for other fields #861
|
||||
* Enhancement - Mention PUI only for German shops and add line breaks #1169
|
||||
* Enhancement - Add filter to fallback tracking_data['carrier'] #1188
|
||||
* Enhancement - Error notices in checkout do not update / or are shown twice #1168
|
||||
* Enhancement - capture authorized payment by changing order status (or programmatically) #587
|
||||
|
||||
= 2.0.2 - 2023-01-31 =
|
||||
* Fix - Do not call PayPal get order by ID if it does not exist #1029
|
||||
* Fix - Type check error conflict with German Market #1056
|
||||
|
|
|
@ -518,6 +518,11 @@ class OrderEndpoint {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* The filter can be used to modify the order patching request body data (the final prices, items).
|
||||
*/
|
||||
$patches_array = apply_filters( 'ppcp_patch_order_request_body_data', $patches_array );
|
||||
|
||||
$bearer = $this->bearer->bearer();
|
||||
$url = trailingslashit( $this->host ) . 'v2/checkout/orders/' . $order_to_update->id();
|
||||
$args = array(
|
||||
|
|
|
@ -284,7 +284,14 @@ class PurchaseUnit {
|
|||
$this->items()
|
||||
),
|
||||
);
|
||||
if ( $ditch_items_when_mismatch && $this->ditch_items_when_mismatch( $this->amount(), ...$this->items() ) ) {
|
||||
|
||||
$ditch = $ditch_items_when_mismatch && $this->ditch_items_when_mismatch( $this->amount(), ...$this->items() );
|
||||
/**
|
||||
* The filter can be used to control when the items and totals breakdown are removed from PayPal order info.
|
||||
*/
|
||||
$ditch = apply_filters( 'ppcp_ditch_items_breakdown', $ditch, $this );
|
||||
|
||||
if ( $ditch ) {
|
||||
unset( $purchase_unit['items'] );
|
||||
unset( $purchase_unit['amount']['breakdown'] );
|
||||
}
|
||||
|
|
|
@ -17,6 +17,8 @@ import {
|
|||
import {hide, setVisible, setVisibleByClass} from "./modules/Helper/Hiding";
|
||||
import {isChangePaymentPage} from "./modules/Helper/Subscriptions";
|
||||
import FreeTrialHandler from "./modules/ActionHandler/FreeTrialHandler";
|
||||
import FormSaver from './modules/Helper/FormSaver';
|
||||
import FormValidator from "./modules/Helper/FormValidator";
|
||||
|
||||
// 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.
|
||||
|
@ -24,11 +26,27 @@ const buttonsSpinner = new Spinner(document.querySelector('.ppc-button-wrapper')
|
|||
const cardsSpinner = new Spinner('#ppcp-hosted-fields');
|
||||
|
||||
const bootstrap = () => {
|
||||
const errorHandler = new ErrorHandler(PayPalCommerceGateway.labels.error.generic);
|
||||
const checkoutFormSelector = 'form.woocommerce-checkout';
|
||||
|
||||
const errorHandler = new ErrorHandler(
|
||||
PayPalCommerceGateway.labels.error.generic,
|
||||
document.querySelector(checkoutFormSelector) ?? document.querySelector('.woocommerce-notices-wrapper')
|
||||
);
|
||||
const spinner = new Spinner();
|
||||
const creditCardRenderer = new CreditCardRenderer(PayPalCommerceGateway, errorHandler, spinner);
|
||||
|
||||
const freeTrialHandler = new FreeTrialHandler(PayPalCommerceGateway, spinner, errorHandler);
|
||||
const formSaver = new FormSaver(
|
||||
PayPalCommerceGateway.ajax.save_checkout_form.endpoint,
|
||||
PayPalCommerceGateway.ajax.save_checkout_form.nonce,
|
||||
);
|
||||
|
||||
const formValidator = PayPalCommerceGateway.early_checkout_validation_enabled ?
|
||||
new FormValidator(
|
||||
PayPalCommerceGateway.ajax.validate_checkout.endpoint,
|
||||
PayPalCommerceGateway.ajax.validate_checkout.nonce,
|
||||
) : null;
|
||||
|
||||
const freeTrialHandler = new FreeTrialHandler(PayPalCommerceGateway, checkoutFormSelector, formSaver, formValidator, spinner, errorHandler);
|
||||
|
||||
jQuery('form.woocommerce-checkout input').on('keydown', e => {
|
||||
if (e.key === 'Enter' && [
|
||||
|
@ -88,7 +106,7 @@ const bootstrap = () => {
|
|||
}
|
||||
}
|
||||
|
||||
const form = document.querySelector('form.woocommerce-checkout');
|
||||
const form = document.querySelector(checkoutFormSelector);
|
||||
if (form) {
|
||||
jQuery('#ppcp-funding-source-form-input').remove();
|
||||
form.insertAdjacentHTML(
|
||||
|
|
|
@ -62,9 +62,9 @@ class CheckoutActionHandler {
|
|||
if (data.data.errors?.length > 0) {
|
||||
errorHandler.messages(data.data.errors);
|
||||
} else if (data.data.details?.length > 0) {
|
||||
errorHandler.message(data.data.details.map(d => `${d.issue} ${d.description}`).join('<br/>'), true);
|
||||
errorHandler.message(data.data.details.map(d => `${d.issue} ${d.description}`).join('<br/>'));
|
||||
} else {
|
||||
errorHandler.message(data.data.message, true);
|
||||
errorHandler.message(data.data.message);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1,44 +1,73 @@
|
|||
import {PaymentMethods} from "../Helper/CheckoutMethodState";
|
||||
import errorHandler from "../ErrorHandler";
|
||||
|
||||
class FreeTrialHandler {
|
||||
/**
|
||||
* @param config
|
||||
* @param formSelector
|
||||
* @param {FormSaver} formSaver
|
||||
* @param {FormValidator|null} formValidator
|
||||
* @param {Spinner} spinner
|
||||
* @param {ErrorHandler} errorHandler
|
||||
*/
|
||||
constructor(
|
||||
config,
|
||||
formSelector,
|
||||
formSaver,
|
||||
formValidator,
|
||||
spinner,
|
||||
errorHandler
|
||||
) {
|
||||
this.config = config;
|
||||
this.formSelector = formSelector;
|
||||
this.formSaver = formSaver;
|
||||
this.formValidator = formValidator;
|
||||
this.spinner = spinner;
|
||||
this.errorHandler = errorHandler;
|
||||
}
|
||||
|
||||
handle()
|
||||
async handle()
|
||||
{
|
||||
this.spinner.block();
|
||||
|
||||
fetch(this.config.ajax.vault_paypal.endpoint, {
|
||||
method: 'POST',
|
||||
credentials: 'same-origin',
|
||||
body: JSON.stringify({
|
||||
nonce: this.config.ajax.vault_paypal.nonce,
|
||||
return_url: location.href
|
||||
}),
|
||||
}).then(res => {
|
||||
return res.json();
|
||||
}).then(data => {
|
||||
try {
|
||||
await this.formSaver.save(document.querySelector(this.formSelector));
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
}
|
||||
|
||||
try {
|
||||
if (this.formValidator) {
|
||||
try {
|
||||
const errors = await this.formValidator.validate(document.querySelector(this.formSelector));
|
||||
if (errors.length > 0) {
|
||||
this.spinner.unblock();
|
||||
this.errorHandler.messages(errors);
|
||||
return;
|
||||
}
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
}
|
||||
}
|
||||
|
||||
const res = await fetch(this.config.ajax.vault_paypal.endpoint, {
|
||||
method: 'POST',
|
||||
credentials: 'same-origin',
|
||||
body: JSON.stringify({
|
||||
nonce: this.config.ajax.vault_paypal.nonce,
|
||||
return_url: location.href,
|
||||
}),
|
||||
});
|
||||
|
||||
const data = await res.json();
|
||||
|
||||
if (!data.success) {
|
||||
this.spinner.unblock();
|
||||
console.error(data);
|
||||
this.errorHandler.message(data.data.message);
|
||||
throw Error(data.data.message);
|
||||
}
|
||||
|
||||
location.href = data.data.approve_link;
|
||||
}).catch(error => {
|
||||
} catch (error) {
|
||||
this.spinner.unblock();
|
||||
console.error(error);
|
||||
this.errorHandler.genericError();
|
||||
});
|
||||
this.errorHandler.message(data.data.message);
|
||||
}
|
||||
}
|
||||
}
|
||||
export default FreeTrialHandler;
|
||||
|
|
|
@ -1,47 +1,41 @@
|
|||
class ErrorHandler {
|
||||
|
||||
constructor(genericErrorText)
|
||||
/**
|
||||
* @param {String} genericErrorText
|
||||
* @param {Element} wrapper
|
||||
*/
|
||||
constructor(genericErrorText, wrapper)
|
||||
{
|
||||
this.genericErrorText = genericErrorText;
|
||||
this.wrapper = document.querySelector('.woocommerce-notices-wrapper');
|
||||
this.messagesList = document.querySelector('ul.woocommerce-error');
|
||||
this.wrapper = wrapper;
|
||||
}
|
||||
|
||||
genericError() {
|
||||
if (this.wrapper.classList.contains('ppcp-persist')) {
|
||||
return;
|
||||
}
|
||||
this.clear();
|
||||
this.message(this.genericErrorText)
|
||||
}
|
||||
|
||||
appendPreparedErrorMessageElement(errorMessageElement)
|
||||
{
|
||||
if (this.messagesList === null) {
|
||||
this._prepareMessagesList();
|
||||
}
|
||||
|
||||
this.messagesList.replaceWith(errorMessageElement);
|
||||
this._getMessageContainer().replaceWith(errorMessageElement);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {String} text
|
||||
* @param {Boolean} persist
|
||||
*/
|
||||
message(text, persist = false)
|
||||
message(text)
|
||||
{
|
||||
this._addMessage(text, persist);
|
||||
this._addMessage(text);
|
||||
|
||||
this._scrollToMessages();
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {Array} texts
|
||||
* @param {Boolean} persist
|
||||
*/
|
||||
messages(texts, persist = false)
|
||||
messages(texts)
|
||||
{
|
||||
texts.forEach(t => this._addMessage(t, persist));
|
||||
texts.forEach(t => this._addMessage(t));
|
||||
|
||||
this._scrollToMessages();
|
||||
}
|
||||
|
@ -49,26 +43,17 @@ class ErrorHandler {
|
|||
/**
|
||||
* @private
|
||||
* @param {String} text
|
||||
* @param {Boolean} persist
|
||||
*/
|
||||
_addMessage(text, persist = false)
|
||||
_addMessage(text)
|
||||
{
|
||||
if(! typeof String || text.length === 0) {
|
||||
throw new Error('A new message text must be a non-empty string.');
|
||||
}
|
||||
|
||||
if (this.messagesList === null){
|
||||
this._prepareMessagesList();
|
||||
}
|
||||
const messageContainer = this._getMessageContainer();
|
||||
|
||||
if (persist) {
|
||||
this.wrapper.classList.add('ppcp-persist');
|
||||
} else {
|
||||
this.wrapper.classList.remove('ppcp-persist');
|
||||
}
|
||||
|
||||
let messageNode = this._prepareMessagesListItem(text);
|
||||
this.messagesList.appendChild(messageNode);
|
||||
let messageNode = this._prepareMessageElement(text);
|
||||
messageContainer.appendChild(messageNode);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -76,26 +61,28 @@ class ErrorHandler {
|
|||
*/
|
||||
_scrollToMessages()
|
||||
{
|
||||
jQuery.scroll_to_notices(jQuery('.woocommerce-notices-wrapper'));
|
||||
jQuery.scroll_to_notices(jQuery('.woocommerce-error'));
|
||||
}
|
||||
|
||||
/**
|
||||
* @private
|
||||
*/
|
||||
_prepareMessagesList()
|
||||
_getMessageContainer()
|
||||
{
|
||||
if (this.messagesList === null) {
|
||||
this.messagesList = document.createElement('ul');
|
||||
this.messagesList.setAttribute('class', 'woocommerce-error');
|
||||
this.messagesList.setAttribute('role', 'alert');
|
||||
this.wrapper.appendChild(this.messagesList);
|
||||
let messageContainer = document.querySelector('ul.woocommerce-error');
|
||||
if (messageContainer === null) {
|
||||
messageContainer = document.createElement('ul');
|
||||
messageContainer.setAttribute('class', 'woocommerce-error');
|
||||
messageContainer.setAttribute('role', 'alert');
|
||||
jQuery(this.wrapper).prepend(messageContainer);
|
||||
}
|
||||
return messageContainer;
|
||||
}
|
||||
|
||||
/**
|
||||
* @private
|
||||
*/
|
||||
_prepareMessagesListItem(message)
|
||||
_prepareMessageElement(message)
|
||||
{
|
||||
const li = document.createElement('li');
|
||||
li.innerHTML = message;
|
||||
|
@ -105,11 +92,7 @@ class ErrorHandler {
|
|||
|
||||
clear()
|
||||
{
|
||||
if (this.messagesList === null) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.messagesList.innerHTML = '';
|
||||
jQuery( '.woocommerce-error, .woocommerce-message' ).remove();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
26
modules/ppcp-button/resources/js/modules/Helper/FormSaver.js
Normal file
26
modules/ppcp-button/resources/js/modules/Helper/FormSaver.js
Normal file
|
@ -0,0 +1,26 @@
|
|||
export default class FormSaver {
|
||||
constructor(url, nonce) {
|
||||
this.url = url;
|
||||
this.nonce = nonce;
|
||||
}
|
||||
|
||||
async save(form) {
|
||||
const formData = new FormData(form);
|
||||
const formJsonObj = Object.fromEntries(formData.entries());
|
||||
|
||||
const res = await fetch(this.url, {
|
||||
method: 'POST',
|
||||
credentials: 'same-origin',
|
||||
body: JSON.stringify({
|
||||
nonce: this.nonce,
|
||||
form: formJsonObj,
|
||||
}),
|
||||
});
|
||||
|
||||
const data = await res.json();
|
||||
|
||||
if (!data.success) {
|
||||
throw Error(data.data.message);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,31 @@
|
|||
export default class FormValidator {
|
||||
constructor(url, nonce) {
|
||||
this.url = url;
|
||||
this.nonce = nonce;
|
||||
}
|
||||
|
||||
async validate(form) {
|
||||
const formData = new FormData(form);
|
||||
const formJsonObj = Object.fromEntries(formData.entries());
|
||||
|
||||
const res = await fetch(this.url, {
|
||||
method: 'POST',
|
||||
credentials: 'same-origin',
|
||||
body: JSON.stringify({
|
||||
nonce: this.nonce,
|
||||
form: formJsonObj,
|
||||
}),
|
||||
});
|
||||
|
||||
const data = await res.json();
|
||||
|
||||
if (!data.success) {
|
||||
if (data.data.errors) {
|
||||
return data.data.errors;
|
||||
}
|
||||
throw Error(data.data.message);
|
||||
}
|
||||
|
||||
return [];
|
||||
}
|
||||
}
|
|
@ -234,15 +234,15 @@ class CreditCardRenderer {
|
|||
this.errorHandler.clear();
|
||||
|
||||
if (err.data?.details?.length) {
|
||||
this.errorHandler.message(err.data.details.map(d => `${d.issue} ${d.description}`).join('<br/>'), true);
|
||||
this.errorHandler.message(err.data.details.map(d => `${d.issue} ${d.description}`).join('<br/>'));
|
||||
} else if (err.details?.length) {
|
||||
this.errorHandler.message(err.details.map(d => `${d.issue} ${d.description}`).join('<br/>'), true);
|
||||
this.errorHandler.message(err.details.map(d => `${d.issue} ${d.description}`).join('<br/>'));
|
||||
} else if (err.data?.errors?.length > 0) {
|
||||
this.errorHandler.messages(err.data.errors);
|
||||
} else if (err.data?.message) {
|
||||
this.errorHandler.message(err.data.message, true);
|
||||
this.errorHandler.message(err.data.message);
|
||||
} else if (err.message) {
|
||||
this.errorHandler.message(err.message, true);
|
||||
this.errorHandler.message(err.message);
|
||||
} else {
|
||||
this.errorHandler.genericError();
|
||||
}
|
||||
|
|
|
@ -9,6 +9,10 @@ declare(strict_types=1);
|
|||
|
||||
namespace WooCommerce\PayPalCommerce\Button;
|
||||
|
||||
use WooCommerce\PayPalCommerce\Button\Helper\CheckoutFormSaver;
|
||||
use WooCommerce\PayPalCommerce\Button\Endpoint\SaveCheckoutFormEndpoint;
|
||||
use WooCommerce\PayPalCommerce\Button\Validation\CheckoutFormValidator;
|
||||
use WooCommerce\PayPalCommerce\Button\Endpoint\ValidateCheckoutEndpoint;
|
||||
use WooCommerce\PayPalCommerce\Vendor\Psr\Container\ContainerInterface;
|
||||
use WooCommerce\PayPalCommerce\Button\Assets\DisabledSmartButton;
|
||||
use WooCommerce\PayPalCommerce\Button\Assets\SmartButton;
|
||||
|
@ -104,6 +108,7 @@ return array(
|
|||
$currency,
|
||||
$container->get( 'wcgateway.all-funding-sources' ),
|
||||
$container->get( 'button.basic-checkout-validation-enabled' ),
|
||||
$container->get( 'button.early-wc-checkout-validation-enabled' ),
|
||||
$container->get( 'woocommerce.logger.woocommerce' )
|
||||
);
|
||||
},
|
||||
|
@ -181,6 +186,16 @@ return array(
|
|||
$logger
|
||||
);
|
||||
},
|
||||
'button.checkout-form-saver' => static function ( ContainerInterface $container ): CheckoutFormSaver {
|
||||
return new CheckoutFormSaver();
|
||||
},
|
||||
'button.endpoint.save-checkout-form' => static function ( ContainerInterface $container ): SaveCheckoutFormEndpoint {
|
||||
return new SaveCheckoutFormEndpoint(
|
||||
$container->get( 'button.request-data' ),
|
||||
$container->get( 'button.checkout-form-saver' ),
|
||||
$container->get( 'woocommerce.logger.woocommerce' )
|
||||
);
|
||||
},
|
||||
'button.endpoint.data-client-id' => static function( ContainerInterface $container ) : DataClientIdEndpoint {
|
||||
$request_data = $container->get( 'button.request-data' );
|
||||
$identity_token = $container->get( 'api.endpoint.identity-token' );
|
||||
|
@ -198,6 +213,13 @@ return array(
|
|||
$container->get( 'woocommerce.logger.woocommerce' )
|
||||
);
|
||||
},
|
||||
'button.endpoint.validate-checkout' => static function ( ContainerInterface $container ): ValidateCheckoutEndpoint {
|
||||
return new ValidateCheckoutEndpoint(
|
||||
$container->get( 'button.request-data' ),
|
||||
$container->get( 'button.validation.wc-checkout-validator' ),
|
||||
$container->get( 'woocommerce.logger.woocommerce' )
|
||||
);
|
||||
},
|
||||
'button.helper.three-d-secure' => static function ( ContainerInterface $container ): ThreeDSecure {
|
||||
$logger = $container->get( 'woocommerce.logger.woocommerce' );
|
||||
return new ThreeDSecure( $logger );
|
||||
|
@ -234,4 +256,7 @@ return array(
|
|||
*/
|
||||
return (bool) apply_filters( 'woocommerce_paypal_payments_early_wc_checkout_validation_enabled', true );
|
||||
},
|
||||
'button.validation.wc-checkout-validator' => static function ( ContainerInterface $container ): CheckoutFormValidator {
|
||||
return new CheckoutFormValidator();
|
||||
},
|
||||
);
|
||||
|
|
|
@ -21,7 +21,10 @@ use WooCommerce\PayPalCommerce\Button\Endpoint\ChangeCartEndpoint;
|
|||
use WooCommerce\PayPalCommerce\Button\Endpoint\CreateOrderEndpoint;
|
||||
use WooCommerce\PayPalCommerce\Button\Endpoint\DataClientIdEndpoint;
|
||||
use WooCommerce\PayPalCommerce\Button\Endpoint\RequestData;
|
||||
use WooCommerce\PayPalCommerce\Button\Endpoint\SaveCheckoutFormEndpoint;
|
||||
use WooCommerce\PayPalCommerce\Button\Endpoint\StartPayPalVaultingEndpoint;
|
||||
use WooCommerce\PayPalCommerce\Button\Endpoint\ValidateCheckoutEndpoint;
|
||||
use WooCommerce\PayPalCommerce\Button\Helper\ContextTrait;
|
||||
use WooCommerce\PayPalCommerce\Button\Helper\MessagesApply;
|
||||
use WooCommerce\PayPalCommerce\Onboarding\Environment;
|
||||
use WooCommerce\PayPalCommerce\Session\SessionHandler;
|
||||
|
@ -40,7 +43,7 @@ use WooCommerce\PayPalCommerce\WcGateway\Settings\Settings;
|
|||
*/
|
||||
class SmartButton implements SmartButtonInterface {
|
||||
|
||||
use FreeTrialHandlerTrait;
|
||||
use FreeTrialHandlerTrait, ContextTrait;
|
||||
|
||||
/**
|
||||
* The Settings status helper.
|
||||
|
@ -154,6 +157,13 @@ class SmartButton implements SmartButtonInterface {
|
|||
*/
|
||||
private $basic_checkout_validation_enabled;
|
||||
|
||||
/**
|
||||
* Whether to execute WC validation of the checkout form.
|
||||
*
|
||||
* @var bool
|
||||
*/
|
||||
protected $early_validation_enabled;
|
||||
|
||||
/**
|
||||
* The logger.
|
||||
*
|
||||
|
@ -187,6 +197,7 @@ class SmartButton implements SmartButtonInterface {
|
|||
* @param string $currency 3-letter currency code of the shop.
|
||||
* @param array $all_funding_sources All existing funding sources.
|
||||
* @param bool $basic_checkout_validation_enabled Whether the basic JS validation of the form iss enabled.
|
||||
* @param bool $early_validation_enabled Whether to execute WC validation of the checkout form.
|
||||
* @param LoggerInterface $logger The logger.
|
||||
*/
|
||||
public function __construct(
|
||||
|
@ -206,6 +217,7 @@ class SmartButton implements SmartButtonInterface {
|
|||
string $currency,
|
||||
array $all_funding_sources,
|
||||
bool $basic_checkout_validation_enabled,
|
||||
bool $early_validation_enabled,
|
||||
LoggerInterface $logger
|
||||
) {
|
||||
|
||||
|
@ -225,6 +237,7 @@ class SmartButton implements SmartButtonInterface {
|
|||
$this->currency = $currency;
|
||||
$this->all_funding_sources = $all_funding_sources;
|
||||
$this->basic_checkout_validation_enabled = $basic_checkout_validation_enabled;
|
||||
$this->early_validation_enabled = $early_validation_enabled;
|
||||
$this->logger = $logger;
|
||||
}
|
||||
|
||||
|
@ -761,22 +774,30 @@ class SmartButton implements SmartButtonInterface {
|
|||
'redirect' => wc_get_checkout_url(),
|
||||
'context' => $this->context(),
|
||||
'ajax' => array(
|
||||
'change_cart' => array(
|
||||
'change_cart' => array(
|
||||
'endpoint' => \WC_AJAX::get_endpoint( ChangeCartEndpoint::ENDPOINT ),
|
||||
'nonce' => wp_create_nonce( ChangeCartEndpoint::nonce() ),
|
||||
),
|
||||
'create_order' => array(
|
||||
'create_order' => array(
|
||||
'endpoint' => \WC_AJAX::get_endpoint( CreateOrderEndpoint::ENDPOINT ),
|
||||
'nonce' => wp_create_nonce( CreateOrderEndpoint::nonce() ),
|
||||
),
|
||||
'approve_order' => array(
|
||||
'approve_order' => array(
|
||||
'endpoint' => \WC_AJAX::get_endpoint( ApproveOrderEndpoint::ENDPOINT ),
|
||||
'nonce' => wp_create_nonce( ApproveOrderEndpoint::nonce() ),
|
||||
),
|
||||
'vault_paypal' => array(
|
||||
'vault_paypal' => array(
|
||||
'endpoint' => \WC_AJAX::get_endpoint( StartPayPalVaultingEndpoint::ENDPOINT ),
|
||||
'nonce' => wp_create_nonce( StartPayPalVaultingEndpoint::nonce() ),
|
||||
),
|
||||
'save_checkout_form' => array(
|
||||
'endpoint' => \WC_AJAX::get_endpoint( SaveCheckoutFormEndpoint::ENDPOINT ),
|
||||
'nonce' => wp_create_nonce( SaveCheckoutFormEndpoint::nonce() ),
|
||||
),
|
||||
'validate_checkout' => array(
|
||||
'endpoint' => \WC_AJAX::get_endpoint( ValidateCheckoutEndpoint::ENDPOINT ),
|
||||
'nonce' => wp_create_nonce( ValidateCheckoutEndpoint::nonce() ),
|
||||
),
|
||||
),
|
||||
'enforce_vault' => $this->has_subscriptions(),
|
||||
'can_save_vault_token' => $this->can_save_vault_token(),
|
||||
|
@ -866,6 +887,7 @@ class SmartButton implements SmartButtonInterface {
|
|||
'single_product_buttons_enabled' => $this->settings_status->is_smart_button_enabled_for_location( 'product' ),
|
||||
'mini_cart_buttons_enabled' => $this->settings_status->is_smart_button_enabled_for_location( 'mini-cart' ),
|
||||
'basic_checkout_validation_enabled' => $this->basic_checkout_validation_enabled,
|
||||
'early_checkout_validation_enabled' => $this->early_validation_enabled,
|
||||
);
|
||||
|
||||
if ( $this->style_for_context( 'layout', 'mini-cart' ) !== 'horizontal' ) {
|
||||
|
@ -1062,48 +1084,6 @@ class SmartButton implements SmartButtonInterface {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* The current context.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
private function context(): string {
|
||||
$context = 'mini-cart';
|
||||
if ( is_product() || wc_post_content_has_shortcode( 'product_page' ) ) {
|
||||
$context = 'product';
|
||||
}
|
||||
if ( is_cart() ) {
|
||||
$context = 'cart';
|
||||
}
|
||||
if ( is_checkout() && ! $this->is_paypal_continuation() ) {
|
||||
$context = 'checkout';
|
||||
}
|
||||
if ( is_checkout_pay_page() ) {
|
||||
$context = 'pay-now';
|
||||
}
|
||||
return $context;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if PayPal payment was already initiated (on the product or cart pages).
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
private function is_paypal_continuation(): bool {
|
||||
$order = $this->session_handler->order();
|
||||
if ( ! $order ) {
|
||||
return false;
|
||||
}
|
||||
$source = $order->payment_source();
|
||||
if ( $source && $source->card() ) {
|
||||
return false; // Ignore for DCC.
|
||||
}
|
||||
if ( 'card' === $this->session_handler->funding_source() ) {
|
||||
return false; // Ignore for card buttons.
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Whether DCC is enabled or not.
|
||||
*
|
||||
|
|
|
@ -9,6 +9,8 @@ declare(strict_types=1);
|
|||
|
||||
namespace WooCommerce\PayPalCommerce\Button;
|
||||
|
||||
use WooCommerce\PayPalCommerce\Button\Endpoint\SaveCheckoutFormEndpoint;
|
||||
use WooCommerce\PayPalCommerce\Button\Endpoint\ValidateCheckoutEndpoint;
|
||||
use WooCommerce\PayPalCommerce\Vendor\Dhii\Container\ServiceProvider;
|
||||
use WooCommerce\PayPalCommerce\Vendor\Dhii\Modular\Module\ModuleInterface;
|
||||
use WooCommerce\PayPalCommerce\Button\Assets\SmartButtonInterface;
|
||||
|
@ -95,7 +97,7 @@ class ButtonModule implements ModuleInterface {
|
|||
*
|
||||
* @param ContainerInterface $container The Container.
|
||||
*/
|
||||
private function register_ajax_endpoints( ContainerInterface $container ) {
|
||||
private function register_ajax_endpoints( ContainerInterface $container ): void {
|
||||
add_action(
|
||||
'wc_ajax_' . DataClientIdEndpoint::ENDPOINT,
|
||||
static function () use ( $container ) {
|
||||
|
@ -156,6 +158,25 @@ class ButtonModule implements ModuleInterface {
|
|||
$endpoint->handle_request();
|
||||
}
|
||||
);
|
||||
|
||||
add_action(
|
||||
'wc_ajax_' . SaveCheckoutFormEndpoint::ENDPOINT,
|
||||
static function () use ( $container ) {
|
||||
$endpoint = $container->get( 'button.endpoint.save-checkout-form' );
|
||||
assert( $endpoint instanceof SaveCheckoutFormEndpoint );
|
||||
|
||||
$endpoint->handle_request();
|
||||
}
|
||||
);
|
||||
|
||||
add_action(
|
||||
'wc_ajax_' . ValidateCheckoutEndpoint::ENDPOINT,
|
||||
static function () use ( $container ) {
|
||||
$endpoint = $container->get( 'button.endpoint.validate-checkout' );
|
||||
assert( $endpoint instanceof ValidateCheckoutEndpoint );
|
||||
$endpoint->handle_request();
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -0,0 +1,94 @@
|
|||
<?php
|
||||
/**
|
||||
* Saves the form data to the WC customer and session.
|
||||
*
|
||||
* @package WooCommerce\PayPalCommerce\Button\Endpoint
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace WooCommerce\PayPalCommerce\Button\Endpoint;
|
||||
|
||||
use Exception;
|
||||
use Psr\Log\LoggerInterface;
|
||||
use WooCommerce\PayPalCommerce\Button\Helper\CheckoutFormSaver;
|
||||
|
||||
/**
|
||||
* Class SaveCheckoutFormEndpoint
|
||||
*/
|
||||
class SaveCheckoutFormEndpoint implements EndpointInterface {
|
||||
const ENDPOINT = 'ppc-save-checkout-form';
|
||||
|
||||
/**
|
||||
* The Request Data Helper.
|
||||
*
|
||||
* @var RequestData
|
||||
*/
|
||||
private $request_data;
|
||||
|
||||
/**
|
||||
* The checkout form saver.
|
||||
*
|
||||
* @var CheckoutFormSaver
|
||||
*/
|
||||
private $checkout_form_saver;
|
||||
|
||||
/**
|
||||
* The logger.
|
||||
*
|
||||
* @var LoggerInterface
|
||||
*/
|
||||
protected $logger;
|
||||
|
||||
/**
|
||||
* SaveCheckoutFormEndpoint constructor.
|
||||
*
|
||||
* @param RequestData $request_data The Request Data Helper.
|
||||
* @param CheckoutFormSaver $checkout_form_saver The checkout form saver.
|
||||
* @param LoggerInterface $logger The logger.
|
||||
*/
|
||||
public function __construct(
|
||||
RequestData $request_data,
|
||||
CheckoutFormSaver $checkout_form_saver,
|
||||
LoggerInterface $logger
|
||||
) {
|
||||
|
||||
$this->request_data = $request_data;
|
||||
$this->checkout_form_saver = $checkout_form_saver;
|
||||
$this->logger = $logger;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the nonce.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public static function nonce(): string {
|
||||
return self::ENDPOINT;
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles the request.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function handle_request(): bool {
|
||||
try {
|
||||
$data = $this->request_data->read_request( $this->nonce() );
|
||||
|
||||
$this->checkout_form_saver->save( $data['form'] );
|
||||
|
||||
wp_send_json_success();
|
||||
return true;
|
||||
} catch ( Exception $error ) {
|
||||
$this->logger->error( 'Checkout form saving failed: ' . $error->getMessage() );
|
||||
|
||||
wp_send_json_error(
|
||||
array(
|
||||
'message' => $error->getMessage(),
|
||||
)
|
||||
);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
107
modules/ppcp-button/src/Endpoint/ValidateCheckoutEndpoint.php
Normal file
107
modules/ppcp-button/src/Endpoint/ValidateCheckoutEndpoint.php
Normal file
|
@ -0,0 +1,107 @@
|
|||
<?php
|
||||
/**
|
||||
* The endpoint for validating the checkout form.
|
||||
*
|
||||
* @package WooCommerce\PayPalCommerce\Button\Endpoint
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace WooCommerce\PayPalCommerce\Button\Endpoint;
|
||||
|
||||
use Psr\Log\LoggerInterface;
|
||||
use Throwable;
|
||||
use WooCommerce\PayPalCommerce\Button\Exception\ValidationException;
|
||||
use WooCommerce\PayPalCommerce\Button\Validation\CheckoutFormValidator;
|
||||
|
||||
/**
|
||||
* Class ValidateCheckoutEndpoint.
|
||||
*/
|
||||
class ValidateCheckoutEndpoint implements EndpointInterface {
|
||||
|
||||
|
||||
const ENDPOINT = 'ppc-validate-checkout';
|
||||
|
||||
/**
|
||||
* The Request Data Helper.
|
||||
*
|
||||
* @var RequestData
|
||||
*/
|
||||
private $request_data;
|
||||
|
||||
/**
|
||||
* The CheckoutFormValidator.
|
||||
*
|
||||
* @var CheckoutFormValidator
|
||||
*/
|
||||
private $checkout_form_validator;
|
||||
|
||||
/**
|
||||
* The logger.
|
||||
*
|
||||
* @var LoggerInterface
|
||||
*/
|
||||
private $logger;
|
||||
|
||||
/**
|
||||
* ValidateCheckoutEndpoint constructor.
|
||||
*
|
||||
* @param RequestData $request_data The Request Data Helper.
|
||||
* @param CheckoutFormValidator $checkout_form_validator The CheckoutFormValidator.
|
||||
* @param LoggerInterface $logger The logger.
|
||||
*/
|
||||
public function __construct(
|
||||
RequestData $request_data,
|
||||
CheckoutFormValidator $checkout_form_validator,
|
||||
LoggerInterface $logger
|
||||
) {
|
||||
$this->request_data = $request_data;
|
||||
$this->checkout_form_validator = $checkout_form_validator;
|
||||
$this->logger = $logger;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the nonce.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public static function nonce(): string {
|
||||
return self::ENDPOINT;
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles the request.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function handle_request(): bool {
|
||||
try {
|
||||
$data = $this->request_data->read_request( $this->nonce() );
|
||||
|
||||
$form_fields = $data['form'];
|
||||
|
||||
$this->checkout_form_validator->validate( $form_fields );
|
||||
|
||||
wp_send_json_success();
|
||||
|
||||
return true;
|
||||
} catch ( ValidationException $exception ) {
|
||||
wp_send_json_error(
|
||||
array(
|
||||
'message' => $exception->getMessage(),
|
||||
'errors' => $exception->errors(),
|
||||
)
|
||||
);
|
||||
return false;
|
||||
} catch ( Throwable $error ) {
|
||||
$this->logger->error( "Form validation execution failed. {$error->getMessage()} {$error->getFile()}:{$error->getLine()}" );
|
||||
|
||||
wp_send_json_error(
|
||||
array(
|
||||
'message' => $error->getMessage(),
|
||||
)
|
||||
);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
32
modules/ppcp-button/src/Helper/CheckoutFormSaver.php
Normal file
32
modules/ppcp-button/src/Helper/CheckoutFormSaver.php
Normal file
|
@ -0,0 +1,32 @@
|
|||
<?php
|
||||
/**
|
||||
* Saves the form data to the WC customer and session.
|
||||
*
|
||||
* @package WooCommerce\PayPalCommerce\Button\Helper
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace WooCommerce\PayPalCommerce\Button\Helper;
|
||||
|
||||
use WC_Checkout;
|
||||
|
||||
/**
|
||||
* Class CheckoutFormSaver
|
||||
*/
|
||||
class CheckoutFormSaver extends WC_Checkout {
|
||||
/**
|
||||
* Saves the form data to the WC customer and session.
|
||||
*
|
||||
* @param array $data The form data.
|
||||
* @return void
|
||||
*/
|
||||
public function save( array $data ) {
|
||||
foreach ( $data as $key => $value ) {
|
||||
$_POST[ $key ] = $value;
|
||||
}
|
||||
$data = $this->get_posted_data();
|
||||
|
||||
$this->update_session( $data );
|
||||
}
|
||||
}
|
62
modules/ppcp-button/src/Helper/ContextTrait.php
Normal file
62
modules/ppcp-button/src/Helper/ContextTrait.php
Normal file
|
@ -0,0 +1,62 @@
|
|||
<?php
|
||||
/**
|
||||
* Helper trait for context.
|
||||
*
|
||||
* @package WooCommerce\PayPalCommerce\Button\Helper
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace WooCommerce\PayPalCommerce\Button\Helper;
|
||||
|
||||
trait ContextTrait {
|
||||
|
||||
/**
|
||||
* The current context.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
protected function context(): string {
|
||||
$context = 'mini-cart';
|
||||
if ( is_product() || wc_post_content_has_shortcode( 'product_page' ) ) {
|
||||
$context = 'product';
|
||||
}
|
||||
|
||||
if ( is_cart() ) {
|
||||
$context = 'cart';
|
||||
}
|
||||
|
||||
if ( is_checkout() && ! $this->is_paypal_continuation() ) {
|
||||
$context = 'checkout';
|
||||
}
|
||||
|
||||
if ( is_checkout_pay_page() ) {
|
||||
$context = 'pay-now';
|
||||
}
|
||||
|
||||
return $context;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if PayPal payment was already initiated (on the product or cart pages).
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
private function is_paypal_continuation(): bool {
|
||||
$order = $this->session_handler->order();
|
||||
if ( ! $order ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$source = $order->payment_source();
|
||||
if ( $source && $source->card() ) {
|
||||
return false; // Ignore for DCC.
|
||||
}
|
||||
|
||||
if ( 'card' === $this->session_handler->funding_source() ) {
|
||||
return false; // Ignore for card buttons.
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
|
@ -27,20 +27,91 @@ class CheckoutFormValidator extends WC_Checkout {
|
|||
public function validate( array $data ) {
|
||||
$errors = new WP_Error();
|
||||
|
||||
// Some plugins check their fields using $_POST,
|
||||
// Some plugins check their fields using $_POST or $_REQUEST,
|
||||
// also WC terms checkbox https://github.com/woocommerce/woocommerce/issues/35328 .
|
||||
foreach ( $data as $key => $value ) {
|
||||
$_POST[ $key ] = $value;
|
||||
$_POST[ $key ] = $value;
|
||||
$_REQUEST[ $key ] = $value;
|
||||
}
|
||||
// And we must call get_posted_data because it handles the shipping address.
|
||||
$data = $this->get_posted_data();
|
||||
|
||||
// It throws some notices when checking fields etc., also from other plugins via hooks.
|
||||
// phpcs:ignore WordPress.PHP.NoSilencedErrors.Discouraged
|
||||
@$this->validate_checkout( $data, $errors );
|
||||
// Looks like without this WC()->shipping->get_packages() is empty which is used by some plugins.
|
||||
WC()->cart->calculate_shipping();
|
||||
|
||||
if ( $errors->has_errors() ) {
|
||||
throw new ValidationException( $errors->get_error_messages() );
|
||||
// Some plugins/filters check is_checkout().
|
||||
$is_checkout = function () {
|
||||
return true;
|
||||
};
|
||||
add_filter( 'woocommerce_is_checkout', $is_checkout );
|
||||
try {
|
||||
// And we must call get_posted_data because it handles the shipping address.
|
||||
$data = $this->get_posted_data();
|
||||
|
||||
// It throws some notices when checking fields etc., also from other plugins via hooks.
|
||||
// phpcs:ignore WordPress.PHP.NoSilencedErrors.Discouraged
|
||||
@$this->validate_checkout( $data, $errors );
|
||||
} finally {
|
||||
remove_filter( 'woocommerce_is_checkout', $is_checkout );
|
||||
}
|
||||
|
||||
if (
|
||||
apply_filters( 'woocommerce_paypal_payments_early_wc_checkout_account_creation_validation_enabled', true ) &&
|
||||
! is_user_logged_in() && ( $this->is_registration_required() || ! empty( $data['createaccount'] ) )
|
||||
) {
|
||||
$username = ! empty( $data['account_username'] ) ? $data['account_username'] : '';
|
||||
$email = $data['billing_email'] ?? '';
|
||||
|
||||
if ( email_exists( $email ) ) {
|
||||
$errors->add(
|
||||
'registration-error-email-exists',
|
||||
apply_filters(
|
||||
'woocommerce_registration_error_email_exists',
|
||||
// phpcs:ignore WordPress.WP.I18n.TextDomainMismatch
|
||||
__( 'An account is already registered with your email address. <a href="#" class="showlogin">Please log in.</a>', 'woocommerce' ),
|
||||
$email
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
if ( $username ) { // Empty username is already checked in validate_checkout, and it can be generated.
|
||||
$username = sanitize_user( $username );
|
||||
if ( empty( $username ) || ! validate_username( $username ) ) {
|
||||
$errors->add(
|
||||
'registration-error-invalid-username',
|
||||
// phpcs:ignore WordPress.WP.I18n.TextDomainMismatch
|
||||
__( 'Please enter a valid account username.', 'woocommerce' )
|
||||
);
|
||||
}
|
||||
|
||||
if ( username_exists( $username ) ) {
|
||||
$errors->add(
|
||||
'registration-error-username-exists',
|
||||
// phpcs:ignore WordPress.WP.I18n.TextDomainMismatch
|
||||
__( 'An account is already registered with that username. Please choose another.', 'woocommerce' )
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Some plugins call wc_add_notice directly.
|
||||
// We should retrieve such notices, and also clear them to avoid duplicates later.
|
||||
// TODO: Normally WC converts the messages from validate_checkout into notices,
|
||||
// maybe we should do the same for consistency, but it requires lots of changes in the way we handle/output errors.
|
||||
$messages = array_merge(
|
||||
$errors->get_error_messages(),
|
||||
array_map(
|
||||
function ( array $notice ): string {
|
||||
return $notice['notice'];
|
||||
},
|
||||
wc_get_notices( 'error' )
|
||||
)
|
||||
);
|
||||
|
||||
if ( wc_notice_count( 'error' ) > 0 ) {
|
||||
wc_clear_notices();
|
||||
}
|
||||
|
||||
if ( $messages ) {
|
||||
throw new ValidationException( $messages );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -155,7 +155,11 @@ class CompatModule implements ModuleInterface {
|
|||
|
||||
$provider = $shipment->get_shipping_provider();
|
||||
if ( ! empty( $provider ) && $provider !== 'none' ) {
|
||||
$tracking_data['carrier'] = 'DHL_DEUTSCHE_POST';
|
||||
/**
|
||||
* The filter allowing to change the default Germanized carrier for order tracking,
|
||||
* such as DHL_DEUTSCHE_POST, DPD_DE, ...
|
||||
*/
|
||||
$tracking_data['carrier'] = (string) apply_filters( 'woocommerce_paypal_payments_default_gzd_carrier', 'DHL_DEUTSCHE_POST', $provider );
|
||||
}
|
||||
|
||||
try {
|
||||
|
|
|
@ -142,7 +142,7 @@ class SettingsImporter {
|
|||
$value = array_values(
|
||||
array_intersect(
|
||||
array_map( 'strtolower', is_array( $option_value ) ? $option_value : array() ),
|
||||
array( 'card', 'sepa', 'bancontact', 'blik', 'eps', 'giropay', 'ideal', 'mercadopago', 'mybank', 'p24', 'sofort', 'venmo' )
|
||||
array( 'card', 'sepa', 'bancontact', 'blik', 'eps', 'giropay', 'ideal', 'mercadopago', 'mybank', 'p24', 'sofort', 'venmo', 'trustly' )
|
||||
)
|
||||
);
|
||||
|
||||
|
|
|
@ -183,18 +183,19 @@ class SubscriptionsHandler {
|
|||
return true;
|
||||
}
|
||||
|
||||
if ( function_exists( 'get_current_screen' ) && get_current_screen() ) {
|
||||
// Are we on the WC > Subscriptions screen?
|
||||
if ( 'edit-shop_subscription' === get_current_screen()->id ) {
|
||||
return true;
|
||||
}
|
||||
// Are we on the WC > Subscriptions screen?
|
||||
// phpcs:ignore WordPress.Security.NonceVerification.Missing
|
||||
$post_type = wc_clean( wp_unslash( $_GET['post_type'] ?? $_POST['post_type'] ?? '' ) );
|
||||
if ( $post_type === 'shop_subscription' ) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// Are we editing an order or subscription tied to PPEC?
|
||||
if ( in_array( get_current_screen()->id, array( 'shop_subscription', 'shop_order' ), true ) ) {
|
||||
$order = wc_get_order( $GLOBALS['post']->ID );
|
||||
|
||||
return ( $order && PPECHelper::PPEC_GATEWAY_ID === $order->get_payment_method() );
|
||||
}
|
||||
// Are we editing an order or subscription tied to PPEC?
|
||||
// phpcs:ignore WordPress.Security.NonceVerification.Missing
|
||||
$order_id = wc_clean( wp_unslash( $_GET['post'] ?? $_POST['post_ID'] ?? '' ) );
|
||||
if ( $order_id ) {
|
||||
$order = wc_get_order( $order_id );
|
||||
return ( $order && PPECHelper::PPEC_GATEWAY_ID === $order->get_payment_method() );
|
||||
}
|
||||
|
||||
return false;
|
||||
|
|
|
@ -396,6 +396,10 @@ document.addEventListener(
|
|||
{
|
||||
value:'authorize',
|
||||
selector:'#field-capture_for_virtual_only'
|
||||
},
|
||||
{
|
||||
value:'authorize',
|
||||
selector:'#field-capture_on_status_change'
|
||||
}
|
||||
]
|
||||
);
|
||||
|
|
|
@ -114,10 +114,13 @@ import {setVisibleByClass, isVisible} from "../../../ppcp-button/resources/js/mo
|
|||
'integration-date': PayPalCommerceGatewaySettings.integration_date,
|
||||
'components': ['buttons', 'funding-eligibility', 'messages'],
|
||||
'enable-funding': ['venmo', 'paylater'],
|
||||
'buyer-country': PayPalCommerceGatewaySettings.country,
|
||||
};
|
||||
|
||||
if(payLaterButtonPreview?.length) {
|
||||
if (PayPalCommerceGatewaySettings.environment === 'sandbox') {
|
||||
settings['buyer-country'] = PayPalCommerceGatewaySettings.country;
|
||||
}
|
||||
|
||||
if (payLaterButtonPreview?.length) {
|
||||
disabledSources = Object.keys(PayPalCommerceGatewaySettings.all_funding_sources);
|
||||
}
|
||||
|
||||
|
|
|
@ -36,6 +36,7 @@ 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\GatewayRepository;
|
||||
use WooCommerce\PayPalCommerce\WcGateway\Gateway\OXXO\OXXO;
|
||||
use WooCommerce\PayPalCommerce\WcGateway\Gateway\OXXO\OXXOEndpoint;
|
||||
use WooCommerce\PayPalCommerce\WcGateway\Gateway\OXXO\OXXOGateway;
|
||||
|
@ -538,6 +539,23 @@ return array(
|
|||
'requirements' => array(),
|
||||
'gateway' => 'paypal',
|
||||
),
|
||||
'capture_on_status_change' => array(
|
||||
'title' => __( 'Capture On Status Change', 'woocommerce-paypal-payments' ),
|
||||
'type' => 'checkbox',
|
||||
'default' => false,
|
||||
'desc_tip' => true,
|
||||
'description' => __(
|
||||
'The transaction will be captured automatically when the order status changes to Processing or Completed.',
|
||||
'woocommerce-paypal-payments'
|
||||
),
|
||||
'label' => __( 'Capture On Status Change', 'woocommerce-paypal-payments' ),
|
||||
'screens' => array(
|
||||
State::STATE_START,
|
||||
State::STATE_ONBOARDED,
|
||||
),
|
||||
'requirements' => array(),
|
||||
'gateway' => 'paypal',
|
||||
),
|
||||
'capture_for_virtual_only' => array(
|
||||
'title' => __( 'Capture Virtual-Only Orders ', 'woocommerce-paypal-payments' ),
|
||||
'type' => 'checkbox',
|
||||
|
@ -593,7 +611,7 @@ return array(
|
|||
'type' => 'select',
|
||||
'class' => array(),
|
||||
'input_class' => array( 'wc-enhanced-select' ),
|
||||
'default' => 'gold',
|
||||
'default' => ApplicationContext::LANDING_PAGE_LOGIN,
|
||||
'desc_tip' => true,
|
||||
'description' => __(
|
||||
'Type of PayPal page to display.',
|
||||
|
@ -862,6 +880,7 @@ return array(
|
|||
'p24' => _x( 'Przelewy24', 'Name of payment method', 'woocommerce-paypal-payments' ),
|
||||
'sofort' => _x( 'Sofort', 'Name of payment method', 'woocommerce-paypal-payments' ),
|
||||
'venmo' => _x( 'Venmo', 'Name of payment method', 'woocommerce-paypal-payments' ),
|
||||
'trustly' => _x( 'Trustly', 'Name of payment method', 'woocommerce-paypal-payments' ),
|
||||
);
|
||||
},
|
||||
|
||||
|
@ -1157,20 +1176,49 @@ return array(
|
|||
|
||||
return false;
|
||||
},
|
||||
'wcgateway.settings.tracking-label' => static function ( ContainerInterface $container ): string {
|
||||
$tracking_label = sprintf(
|
||||
// translators: %1$s and %2$s are the opening and closing of HTML <a> tag.
|
||||
__( 'Enable shipment tracking information to be sent to PayPal for seller protection features. Required when %1$sPay upon Invoice%2$s is used.', 'woocommerce-paypal-payments' ),
|
||||
'<a href="https://woocommerce.com/document/woocommerce-paypal-payments/#pay-upon-invoice-PUI" target="_blank">',
|
||||
'wcgateway.settings.fraudnet-label' => static function ( ContainerInterface $container ): string {
|
||||
$label = sprintf(
|
||||
// translators: %1$s and %2$s are the opening and closing of HTML <a> tag.
|
||||
__( 'Manage online risk with %1$sFraudNet%2$s.', 'woocommerce-paypal-payments' ),
|
||||
'<a href="https://woocommerce.com/document/woocommerce-paypal-payments/#fraudnet" target="_blank">',
|
||||
'</a>'
|
||||
);
|
||||
|
||||
if ( 'DE' === $container->get( 'api.shop.country' ) ) {
|
||||
$label .= '<br/>' . sprintf(
|
||||
// translators: %1$s and %2$s are the opening and closing of HTML <a> tag.
|
||||
__( 'Required when %1$sPay upon Invoice%2$s is used.', 'woocommerce-paypal-payments' ),
|
||||
'<a href="https://woocommerce.com/document/woocommerce-paypal-payments/#pay-upon-invoice-PUI" target="_blank">',
|
||||
'</a>'
|
||||
);
|
||||
}
|
||||
|
||||
return $label;
|
||||
},
|
||||
'wcgateway.settings.tracking-label' => static function ( ContainerInterface $container ): string {
|
||||
$tracking_label = sprintf(
|
||||
// translators: %1$s and %2$s are the opening and closing of HTML <a> tag.
|
||||
__( 'Enable %1$sshipment tracking information%2$s to be sent to PayPal for seller protection features.', 'woocommerce-paypal-payments' ),
|
||||
'<a href="https://woocommerce.com/document/woocommerce-paypal-payments/#shipment-tracking" target="_blank">',
|
||||
'</a>'
|
||||
);
|
||||
|
||||
if ( 'DE' === $container->get( 'api.shop.country' ) ) {
|
||||
$tracking_label .= '<br/>' . sprintf(
|
||||
// translators: %1$s and %2$s are the opening and closing of HTML <a> tag.
|
||||
__( 'Required when %1$sPay upon Invoice%2$s is used.', 'woocommerce-paypal-payments' ),
|
||||
'<a href="https://woocommerce.com/document/woocommerce-paypal-payments/#pay-upon-invoice-PUI" target="_blank">',
|
||||
'</a>'
|
||||
);
|
||||
}
|
||||
|
||||
$is_tracking_available = $container->get( 'order-tracking.is-tracking-available' );
|
||||
|
||||
if ( $is_tracking_available ) {
|
||||
return $tracking_label;
|
||||
}
|
||||
|
||||
$tracking_label .= sprintf(
|
||||
$tracking_label .= '<br/>' . sprintf(
|
||||
// translators: %1$s and %2$s are the opening and closing of HTML <a> tag.
|
||||
__(
|
||||
' To use tracking features, you must %1$senable tracking on your account%2$s.',
|
||||
|
@ -1318,52 +1366,10 @@ return array(
|
|||
OXXOGateway::ID,
|
||||
);
|
||||
},
|
||||
'wcgateway.enabled-ppcp-gateways' => static function ( ContainerInterface $container ): array {
|
||||
$available_gateways = WC()->payment_gateways->get_available_payment_gateways();
|
||||
$ppcp_gateways = $container->get( 'wcgateway.ppcp-gateways' );
|
||||
$enabled_ppcp_gateways = array();
|
||||
|
||||
foreach ( $ppcp_gateways as $gateway ) {
|
||||
if ( ! isset( $available_gateways[ $gateway ] ) ) {
|
||||
continue;
|
||||
}
|
||||
$enabled_ppcp_gateways[] = $gateway;
|
||||
}
|
||||
|
||||
return $enabled_ppcp_gateways;
|
||||
},
|
||||
'wcgateway.is-paypal-continuation' => static function ( ContainerInterface $container ): bool {
|
||||
$session_handler = $container->get( 'session.handler' );
|
||||
assert( $session_handler instanceof SessionHandler );
|
||||
|
||||
$order = $session_handler->order();
|
||||
if ( ! $order ) {
|
||||
return false;
|
||||
}
|
||||
$source = $order->payment_source();
|
||||
if ( $source && $source->card() ) {
|
||||
return false; // Ignore for DCC.
|
||||
}
|
||||
if ( 'card' === $session_handler->funding_source() ) {
|
||||
return false; // Ignore for card buttons.
|
||||
}
|
||||
return true;
|
||||
},
|
||||
'wcgateway.current-context' => static function ( ContainerInterface $container ): string {
|
||||
$context = 'mini-cart';
|
||||
if ( is_product() || wc_post_content_has_shortcode( 'product_page' ) ) {
|
||||
$context = 'product';
|
||||
}
|
||||
if ( is_cart() ) {
|
||||
$context = 'cart';
|
||||
}
|
||||
if ( is_checkout() && ! $container->get( 'wcgateway.is-paypal-continuation' ) ) {
|
||||
$context = 'checkout';
|
||||
}
|
||||
if ( is_checkout_pay_page() ) {
|
||||
$context = 'pay-now';
|
||||
}
|
||||
return $context;
|
||||
'wcgateway.gateway-repository' => static function ( ContainerInterface $container ): GatewayRepository {
|
||||
return new GatewayRepository(
|
||||
$container->get( 'wcgateway.ppcp-gateways' )
|
||||
);
|
||||
},
|
||||
'wcgateway.is-fraudnet-enabled' => static function ( ContainerInterface $container ): bool {
|
||||
$settings = $container->get( 'wcgateway.settings' );
|
||||
|
@ -1378,8 +1384,8 @@ return array(
|
|||
$container->get( 'wcgateway.fraudnet' ),
|
||||
$container->get( 'onboarding.environment' ),
|
||||
$container->get( 'wcgateway.settings' ),
|
||||
$container->get( 'wcgateway.enabled-ppcp-gateways' ),
|
||||
$container->get( 'wcgateway.current-context' ),
|
||||
$container->get( 'wcgateway.gateway-repository' ),
|
||||
$container->get( 'session.handler' ),
|
||||
$container->get( 'wcgateway.is-fraudnet-enabled' )
|
||||
);
|
||||
},
|
||||
|
|
|
@ -9,8 +9,12 @@ declare(strict_types=1);
|
|||
|
||||
namespace WooCommerce\PayPalCommerce\WcGateway\Assets;
|
||||
|
||||
use WooCommerce\PayPalCommerce\Button\Helper\ContextTrait;
|
||||
use WooCommerce\PayPalCommerce\Onboarding\Environment;
|
||||
use WooCommerce\PayPalCommerce\Session\SessionHandler;
|
||||
use WooCommerce\PayPalCommerce\WcGateway\Exception\NotFoundException;
|
||||
use WooCommerce\PayPalCommerce\WcGateway\FraudNet\FraudNet;
|
||||
use WooCommerce\PayPalCommerce\WcGateway\Gateway\GatewayRepository;
|
||||
use WooCommerce\PayPalCommerce\WcGateway\Gateway\PayPalGateway;
|
||||
use WooCommerce\PayPalCommerce\WcGateway\Gateway\PayUponInvoice\PayUponInvoiceGateway;
|
||||
use WooCommerce\PayPalCommerce\WcGateway\Settings\Settings;
|
||||
|
@ -20,6 +24,8 @@ use WooCommerce\PayPalCommerce\WcGateway\Settings\Settings;
|
|||
*/
|
||||
class FraudNetAssets {
|
||||
|
||||
use ContextTrait;
|
||||
|
||||
/**
|
||||
* The URL of this module.
|
||||
*
|
||||
|
@ -58,16 +64,23 @@ class FraudNetAssets {
|
|||
/**
|
||||
* The list of enabled PayPal gateways.
|
||||
*
|
||||
* @var string[]
|
||||
* @var string[]|null
|
||||
*/
|
||||
protected $enabled_ppcp_gateways;
|
||||
|
||||
/**
|
||||
* The current context.
|
||||
* The GatewayRepository.
|
||||
*
|
||||
* @var string
|
||||
* @var GatewayRepository
|
||||
*/
|
||||
protected $context;
|
||||
protected $gateway_repository;
|
||||
|
||||
/**
|
||||
* The session handler
|
||||
*
|
||||
* @var SessionHandler
|
||||
*/
|
||||
protected $session_handler;
|
||||
|
||||
/**
|
||||
* True if FraudNet support is enabled in settings, otherwise false.
|
||||
|
@ -79,14 +92,14 @@ class FraudNetAssets {
|
|||
/**
|
||||
* Assets constructor.
|
||||
*
|
||||
* @param string $module_url The url of this module.
|
||||
* @param string $version The assets version.
|
||||
* @param FraudNet $fraud_net The FraudNet entity.
|
||||
* @param Environment $environment The environment.
|
||||
* @param Settings $settings The Settings.
|
||||
* @param string[] $enabled_ppcp_gateways The list of enabled PayPal gateways.
|
||||
* @param string $context The current context.
|
||||
* @param bool $is_fraudnet_enabled true if FraudNet support is enabled in settings, otherwise false.
|
||||
* @param string $module_url The url of this module.
|
||||
* @param string $version The assets version.
|
||||
* @param FraudNet $fraud_net The FraudNet entity.
|
||||
* @param Environment $environment The environment.
|
||||
* @param Settings $settings The Settings.
|
||||
* @param GatewayRepository $gateway_repository The GatewayRepository.
|
||||
* @param SessionHandler $session_handler The session handler.
|
||||
* @param bool $is_fraudnet_enabled true if FraudNet support is enabled in settings, otherwise false.
|
||||
*/
|
||||
public function __construct(
|
||||
string $module_url,
|
||||
|
@ -94,18 +107,18 @@ class FraudNetAssets {
|
|||
FraudNet $fraud_net,
|
||||
Environment $environment,
|
||||
Settings $settings,
|
||||
array $enabled_ppcp_gateways,
|
||||
string $context,
|
||||
GatewayRepository $gateway_repository,
|
||||
SessionHandler $session_handler,
|
||||
bool $is_fraudnet_enabled
|
||||
) {
|
||||
$this->module_url = $module_url;
|
||||
$this->version = $version;
|
||||
$this->fraud_net = $fraud_net;
|
||||
$this->environment = $environment;
|
||||
$this->settings = $settings;
|
||||
$this->enabled_ppcp_gateways = $enabled_ppcp_gateways;
|
||||
$this->context = $context;
|
||||
$this->is_fraudnet_enabled = $is_fraudnet_enabled;
|
||||
$this->module_url = $module_url;
|
||||
$this->version = $version;
|
||||
$this->fraud_net = $fraud_net;
|
||||
$this->environment = $environment;
|
||||
$this->settings = $settings;
|
||||
$this->gateway_repository = $gateway_repository;
|
||||
$this->session_handler = $session_handler;
|
||||
$this->is_fraudnet_enabled = $is_fraudnet_enabled;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -144,19 +157,18 @@ class FraudNetAssets {
|
|||
* @return bool true if FraudNet script should be loaded, otherwise false.
|
||||
*/
|
||||
protected function should_load_fraudnet_script(): bool {
|
||||
if ( empty( $this->enabled_ppcp_gateways ) ) {
|
||||
if ( empty( $this->enabled_ppcp_gateways() ) ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$is_pui_gateway_enabled = in_array( PayUponInvoiceGateway::ID, $this->enabled_ppcp_gateways, true );
|
||||
$is_only_standard_gateway_enabled = $this->enabled_ppcp_gateways === array( PayPalGateway::ID );
|
||||
$is_pui_gateway_enabled = in_array( PayUponInvoiceGateway::ID, $this->enabled_ppcp_gateways(), true );
|
||||
$is_only_standard_gateway_enabled = $this->enabled_ppcp_gateways() === array( PayPalGateway::ID );
|
||||
|
||||
if ( $this->context !== 'checkout' || $is_only_standard_gateway_enabled ) {
|
||||
if ( $this->context() !== 'checkout' || $is_only_standard_gateway_enabled ) {
|
||||
return $this->is_fraudnet_enabled && $this->are_buttons_enabled_for_context();
|
||||
}
|
||||
|
||||
return $is_pui_gateway_enabled ? true : $this->is_fraudnet_enabled;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -165,22 +177,35 @@ class FraudNetAssets {
|
|||
* @return bool true if enabled, otherwise false.
|
||||
*/
|
||||
protected function are_buttons_enabled_for_context() : bool {
|
||||
if ( ! in_array( PayPalGateway::ID, $this->enabled_ppcp_gateways, true ) ) {
|
||||
if ( ! in_array( PayPalGateway::ID, $this->enabled_ppcp_gateways(), true ) ) {
|
||||
return false;
|
||||
}
|
||||
try {
|
||||
$button_locations = $this->settings->get( 'smart_button_locations' );
|
||||
} catch ( NotFoundException $exception ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$location_prefix = $this->context === 'checkout' ? '' : "{$this->context}_";
|
||||
$setting_name = "button_{$location_prefix}enabled";
|
||||
$buttons_enabled_for_context = $this->settings->has( $setting_name ) && $this->settings->get( $setting_name );
|
||||
|
||||
if ( $this->context === 'product' ) {
|
||||
return $buttons_enabled_for_context || $this->settings->has( 'mini-cart' ) && $this->settings->get( 'mini-cart' );
|
||||
}
|
||||
|
||||
if ( $this->context === 'pay-now' ) {
|
||||
if ( $this->context() === 'pay-now' ) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return $buttons_enabled_for_context;
|
||||
if ( $this->context() === 'product' ) {
|
||||
return in_array( 'product', $button_locations, true ) || in_array( 'mini-cart', $button_locations, true );
|
||||
}
|
||||
|
||||
return in_array( $this->context(), $button_locations, true );
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns IDs of the currently enabled PPCP gateways.
|
||||
*
|
||||
* @return string[]
|
||||
*/
|
||||
protected function enabled_ppcp_gateways(): array {
|
||||
if ( null === $this->enabled_ppcp_gateways ) {
|
||||
$this->enabled_ppcp_gateways = $this->gateway_repository->get_enabled_ppcp_gateway_ids();
|
||||
}
|
||||
return $this->enabled_ppcp_gateways;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -9,6 +9,7 @@ declare(strict_types=1);
|
|||
|
||||
namespace WooCommerce\PayPalCommerce\WcGateway\Assets;
|
||||
|
||||
use WooCommerce\PayPalCommerce\Onboarding\Environment;
|
||||
use WooCommerce\PayPalCommerce\Subscription\Helper\SubscriptionHelper;
|
||||
|
||||
/**
|
||||
|
@ -58,6 +59,13 @@ class SettingsPageAssets {
|
|||
*/
|
||||
private $country;
|
||||
|
||||
/**
|
||||
* The environment object.
|
||||
*
|
||||
* @var Environment
|
||||
*/
|
||||
private $environment;
|
||||
|
||||
/**
|
||||
* Whether Pay Later button is enabled either for checkout, cart or product page.
|
||||
*
|
||||
|
@ -88,6 +96,7 @@ class SettingsPageAssets {
|
|||
* @param string $client_id The PayPal SDK client ID.
|
||||
* @param string $currency 3-letter currency code of the shop.
|
||||
* @param string $country 2-letter country code of the shop.
|
||||
* @param Environment $environment The environment object.
|
||||
* @param bool $is_pay_later_button_enabled Whether Pay Later button is enabled either for checkout, cart or product page.
|
||||
* @param array $disabled_sources The list of disabled funding sources.
|
||||
* @param array $all_funding_sources The list of all existing funding sources.
|
||||
|
@ -99,6 +108,7 @@ class SettingsPageAssets {
|
|||
string $client_id,
|
||||
string $currency,
|
||||
string $country,
|
||||
Environment $environment,
|
||||
bool $is_pay_later_button_enabled,
|
||||
array $disabled_sources,
|
||||
array $all_funding_sources
|
||||
|
@ -109,6 +119,7 @@ class SettingsPageAssets {
|
|||
$this->client_id = $client_id;
|
||||
$this->currency = $currency;
|
||||
$this->country = $country;
|
||||
$this->environment = $environment;
|
||||
$this->is_pay_later_button_enabled = $is_pay_later_button_enabled;
|
||||
$this->disabled_sources = $disabled_sources;
|
||||
$this->all_funding_sources = $all_funding_sources;
|
||||
|
@ -191,6 +202,7 @@ class SettingsPageAssets {
|
|||
'client_id' => $this->client_id,
|
||||
'currency' => $this->currency,
|
||||
'country' => $this->country,
|
||||
'environment' => $this->environment->current_environment(),
|
||||
'integration_date' => PAYPAL_INTEGRATION_DATE,
|
||||
'is_pay_later_button_enabled' => $this->is_pay_later_button_enabled,
|
||||
'disabled_sources' => $this->disabled_sources,
|
||||
|
|
47
modules/ppcp-wc-gateway/src/Gateway/GatewayRepository.php
Normal file
47
modules/ppcp-wc-gateway/src/Gateway/GatewayRepository.php
Normal file
|
@ -0,0 +1,47 @@
|
|||
<?php
|
||||
/**
|
||||
* Operations with the WC gateways.
|
||||
*
|
||||
* @package WooCommerce\PayPalCommerce\WcGateway\Gateway
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace WooCommerce\PayPalCommerce\WcGateway\Gateway;
|
||||
|
||||
/**
|
||||
* Class GatewayRepository
|
||||
*/
|
||||
class GatewayRepository {
|
||||
/**
|
||||
* IDs of our gateways.
|
||||
*
|
||||
* @var string[]
|
||||
*/
|
||||
protected $ppcp_gateway_ids;
|
||||
|
||||
/**
|
||||
* GatewayRepository constructor.
|
||||
*
|
||||
* @param string[] $ppcp_gateway_ids IDs of our gateways.
|
||||
*/
|
||||
public function __construct( array $ppcp_gateway_ids ) {
|
||||
$this->ppcp_gateway_ids = $ppcp_gateway_ids;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns IDs of the currently enabled PPCP gateways.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function get_enabled_ppcp_gateway_ids(): array {
|
||||
$available_gateways = WC()->payment_gateways->get_available_payment_gateways();
|
||||
|
||||
return array_filter(
|
||||
$this->ppcp_gateway_ids,
|
||||
function ( string $id ) use ( $available_gateways ): bool {
|
||||
return isset( $available_gateways[ $id ] );
|
||||
}
|
||||
);
|
||||
}
|
||||
}
|
|
@ -422,7 +422,7 @@ class PayUponInvoice {
|
|||
*
|
||||
* @psalm-suppress MissingClosureParamType
|
||||
*/
|
||||
function ( $methods ): array {
|
||||
function ( $methods ) {
|
||||
if ( ! is_array( $methods ) || State::STATE_ONBOARDED !== $this->state->current_state() ) {
|
||||
return $methods;
|
||||
}
|
||||
|
|
|
@ -398,12 +398,7 @@ return function ( ContainerInterface $container, array $fields ): array {
|
|||
'title' => __( 'FraudNet', 'woocommerce-paypal-payments' ),
|
||||
'type' => 'checkbox',
|
||||
'desc_tip' => true,
|
||||
'label' => sprintf(
|
||||
// translators: %1$s and %2$s are the opening and closing of HTML <a> tag.
|
||||
__( 'Manage online risk with %1$sFraudNet%2$s.', 'woocommerce-paypal-payments' ),
|
||||
'<a href="https://woocommerce.com/document/woocommerce-paypal-payments/#FraudNet" target="_blank">',
|
||||
'</a>'
|
||||
),
|
||||
'label' => $container->get( 'wcgateway.settings.fraudnet-label' ),
|
||||
'description' => __( 'FraudNet is a JavaScript library developed by PayPal and embedded into a merchant’s web page to collect browser-based data to help reduce fraud.', 'woocommerce-paypal-payments' ),
|
||||
'default' => false,
|
||||
'screens' => array(
|
||||
|
|
|
@ -49,7 +49,7 @@ return function ( ContainerInterface $container, array $fields ): array {
|
|||
'description' => sprintf(
|
||||
// translators: %1$s and %2$s are the opening and closing of HTML <a> tag.
|
||||
__(
|
||||
'Customize the appearance of the PayPal smart buttons on the
|
||||
'Customize the appearance of the PayPal smart buttons on the
|
||||
%1$sCheckout page%5$s, %2$sSingle Product Page%5$s, %3$sCart page%5$s or on %4$sMini Cart%5$s.',
|
||||
'woocommerce-paypal-payments'
|
||||
),
|
||||
|
@ -163,6 +163,7 @@ return function ( ContainerInterface $container, array $fields ): array {
|
|||
'blue' => __( 'Blue', 'woocommerce-paypal-payments' ),
|
||||
'silver' => __( 'Silver', 'woocommerce-paypal-payments' ),
|
||||
'black' => __( 'Black', 'woocommerce-paypal-payments' ),
|
||||
'white' => __( 'White', 'woocommerce-paypal-payments' ),
|
||||
),
|
||||
'screens' => array(
|
||||
State::STATE_START,
|
||||
|
@ -308,6 +309,7 @@ return function ( ContainerInterface $container, array $fields ): array {
|
|||
'blue' => __( 'Blue', 'woocommerce-paypal-payments' ),
|
||||
'silver' => __( 'Silver', 'woocommerce-paypal-payments' ),
|
||||
'black' => __( 'Black', 'woocommerce-paypal-payments' ),
|
||||
'white' => __( 'White', 'woocommerce-paypal-payments' ),
|
||||
),
|
||||
'screens' => array(
|
||||
State::STATE_START,
|
||||
|
@ -447,6 +449,7 @@ return function ( ContainerInterface $container, array $fields ): array {
|
|||
'blue' => __( 'Blue', 'woocommerce-paypal-payments' ),
|
||||
'silver' => __( 'Silver', 'woocommerce-paypal-payments' ),
|
||||
'black' => __( 'Black', 'woocommerce-paypal-payments' ),
|
||||
'white' => __( 'White', 'woocommerce-paypal-payments' ),
|
||||
),
|
||||
'screens' => array(
|
||||
State::STATE_START,
|
||||
|
@ -586,6 +589,7 @@ return function ( ContainerInterface $container, array $fields ): array {
|
|||
'blue' => __( 'Blue', 'woocommerce-paypal-payments' ),
|
||||
'silver' => __( 'Silver', 'woocommerce-paypal-payments' ),
|
||||
'black' => __( 'Black', 'woocommerce-paypal-payments' ),
|
||||
'white' => __( 'White', 'woocommerce-paypal-payments' ),
|
||||
),
|
||||
'screens' => array(
|
||||
State::STATE_START,
|
||||
|
@ -725,6 +729,7 @@ return function ( ContainerInterface $container, array $fields ): array {
|
|||
'blue' => __( 'Blue', 'woocommerce-paypal-payments' ),
|
||||
'silver' => __( 'Silver', 'woocommerce-paypal-payments' ),
|
||||
'black' => __( 'Black', 'woocommerce-paypal-payments' ),
|
||||
'white' => __( 'White', 'woocommerce-paypal-payments' ),
|
||||
),
|
||||
'screens' => array(
|
||||
State::STATE_START,
|
||||
|
|
|
@ -193,10 +193,7 @@ class SettingsListener {
|
|||
*/
|
||||
do_action( 'woocommerce_paypal_payments_onboarding_before_redirect' );
|
||||
|
||||
/**
|
||||
* The URL opened at the end of onboarding after saving the merchant ID/email.
|
||||
*/
|
||||
$redirect_url = apply_filters( 'woocommerce_paypal_payments_onboarding_redirect_url', admin_url( 'admin.php?page=wc-settings&tab=checkout§ion=ppcp-gateway&ppcp-tab=' . Settings::CONNECTION_TAB_ID ) );
|
||||
$redirect_url = $this->get_onboarding_redirect_url();
|
||||
if ( ! $this->settings->has( 'client_id' ) || ! $this->settings->get( 'client_id' ) ) {
|
||||
$redirect_url = add_query_arg( 'ppcp-onboarding-error', '1', $redirect_url );
|
||||
}
|
||||
|
@ -347,9 +344,17 @@ class SettingsListener {
|
|||
$this->dcc_status_cache->delete( DCCProductStatus::DCC_STATUS_CACHE_KEY );
|
||||
}
|
||||
|
||||
$redirect_url = false;
|
||||
if ( self::CREDENTIALS_ADDED === $credentials_change_status ) {
|
||||
$redirect_url = $this->get_onboarding_redirect_url();
|
||||
}
|
||||
|
||||
if ( isset( $_GET['ppcp-onboarding-error'] ) ) {
|
||||
$url = remove_query_arg( 'ppcp-onboarding-error' );
|
||||
wp_safe_redirect( $url, 302 );
|
||||
$redirect_url = remove_query_arg( 'ppcp-onboarding-error', $redirect_url );
|
||||
}
|
||||
|
||||
if ( $redirect_url ) {
|
||||
wp_safe_redirect( $redirect_url, 302 );
|
||||
exit;
|
||||
}
|
||||
|
||||
|
@ -357,6 +362,18 @@ class SettingsListener {
|
|||
// phpcs:enable WordPress.Security.NonceVerification.Recommended
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the URL opened at the end of onboarding.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
private function get_onboarding_redirect_url(): string {
|
||||
/**
|
||||
* The URL opened at the end of onboarding after saving the merchant ID/email.
|
||||
*/
|
||||
return apply_filters( 'woocommerce_paypal_payments_onboarding_redirect_url', admin_url( 'admin.php?page=wc-settings&tab=checkout§ion=ppcp-gateway&ppcp-tab=' . Settings::CONNECTION_TAB_ID ) );
|
||||
}
|
||||
|
||||
/**
|
||||
* The actual used client credentials are stored in 'client_secret', 'client_id', 'merchant_id' and 'merchant_email'.
|
||||
* This method populates those fields depending on the sandbox status.
|
||||
|
|
|
@ -9,6 +9,8 @@ declare(strict_types=1);
|
|||
|
||||
namespace WooCommerce\PayPalCommerce\WcGateway;
|
||||
|
||||
use Psr\Log\LoggerInterface;
|
||||
use Throwable;
|
||||
use WooCommerce\PayPalCommerce\Vendor\Dhii\Container\ServiceProvider;
|
||||
use WooCommerce\PayPalCommerce\Vendor\Dhii\Modular\Module\ModuleInterface;
|
||||
use WC_Order;
|
||||
|
@ -148,6 +150,12 @@ class WCGatewayModule implements ModuleInterface {
|
|||
if ( ! $wc_order instanceof WC_Order ) {
|
||||
return;
|
||||
}
|
||||
/**
|
||||
* The filter can be used to remove the rows with PayPal fees in WC orders.
|
||||
*/
|
||||
if ( ! apply_filters( 'woocommerce_paypal_payments_show_fees_on_order_admin_page', true, $wc_order ) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
// phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
|
||||
echo $fees_renderer->render( $wc_order );
|
||||
|
@ -168,6 +176,7 @@ class WCGatewayModule implements ModuleInterface {
|
|||
$c->get( 'button.client_id_for_admin' ),
|
||||
$c->get( 'api.shop.currency' ),
|
||||
$c->get( 'api.shop.country' ),
|
||||
$c->get( 'onboarding.environment' ),
|
||||
$settings_status->is_pay_later_button_enabled(),
|
||||
$settings->has( 'disable_funding' ) ? $settings->get( 'disable_funding' ) : array(),
|
||||
$c->get( 'wcgateway.all-funding-sources' )
|
||||
|
@ -252,7 +261,7 @@ class WCGatewayModule implements ModuleInterface {
|
|||
);
|
||||
|
||||
add_action(
|
||||
'init',
|
||||
'wp_loaded',
|
||||
function () use ( $c ) {
|
||||
if ( 'DE' === $c->get( 'api.shop.country' ) ) {
|
||||
( $c->get( 'wcgateway.pay-upon-invoice' ) )->init();
|
||||
|
@ -300,6 +309,57 @@ class WCGatewayModule implements ModuleInterface {
|
|||
$endpoint->handle_request();
|
||||
}
|
||||
);
|
||||
|
||||
add_action(
|
||||
'woocommerce_order_status_changed',
|
||||
static function ( int $order_id, string $from, string $to ) use ( $c ) {
|
||||
$wc_order = wc_get_order( $order_id );
|
||||
if ( ! $wc_order instanceof WC_Order ) {
|
||||
return;
|
||||
}
|
||||
|
||||
$settings = $c->get( 'wcgateway.settings' );
|
||||
assert( $settings instanceof ContainerInterface );
|
||||
|
||||
if ( ! $settings->has( 'capture_on_status_change' ) || ! $settings->get( 'capture_on_status_change' ) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
$intent = strtoupper( (string) $wc_order->get_meta( PayPalGateway::INTENT_META_KEY ) );
|
||||
$captured = wc_string_to_bool( $wc_order->get_meta( AuthorizedPaymentsProcessor::CAPTURED_META_KEY ) );
|
||||
if ( $intent !== 'AUTHORIZE' || $captured ) {
|
||||
return;
|
||||
}
|
||||
|
||||
/**
|
||||
* The filter returning the WC order statuses which trigger capturing of payment authorization.
|
||||
*/
|
||||
$capture_statuses = apply_filters( 'woocommerce_paypal_payments_auto_capture_statuses', array( 'processing', 'completed' ), $wc_order );
|
||||
if ( ! in_array( $to, $capture_statuses, true ) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
$authorized_payment_processor = $c->get( 'wcgateway.processor.authorized-payments' );
|
||||
assert( $authorized_payment_processor instanceof AuthorizedPaymentsProcessor );
|
||||
|
||||
try {
|
||||
if ( $authorized_payment_processor->capture_authorized_payment( $wc_order ) ) {
|
||||
return;
|
||||
}
|
||||
} catch ( Throwable $error ) {
|
||||
$logger = $c->get( 'woocommerce.logger.woocommerce' );
|
||||
assert( $logger instanceof LoggerInterface );
|
||||
$logger->error( "Capture failed. {$error->getMessage()} {$error->getFile()}:{$error->getLine()}" );
|
||||
}
|
||||
|
||||
$wc_order->update_status(
|
||||
'failed',
|
||||
__( 'Could not capture the payment.', 'woocommerce-paypal-payments' )
|
||||
);
|
||||
},
|
||||
10,
|
||||
3
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
17
package.json
17
package.json
|
@ -7,7 +7,6 @@
|
|||
"author": "WooCommerce",
|
||||
"scripts": {
|
||||
"postinstall": "run-s install:modules:* && run-s build:modules",
|
||||
|
||||
"install:modules:ppcp-button": "cd modules/ppcp-button && yarn install",
|
||||
"install:modules:ppcp-wc-gateway": "cd modules/ppcp-wc-gateway && yarn install",
|
||||
"install:modules:ppcp-webhooks": "cd modules/ppcp-webhooks && yarn install",
|
||||
|
@ -15,7 +14,6 @@
|
|||
"install:modules:ppcp-onboarding": "cd modules/ppcp-onboarding && yarn install",
|
||||
"install:modules:ppcp-compat": "cd modules/ppcp-compat && yarn install",
|
||||
"install:modules:ppcp-uninstall": "cd modules/ppcp-uninstall && yarn install",
|
||||
|
||||
"build:modules:ppcp-button": "cd modules/ppcp-button && yarn run build",
|
||||
"build:modules:ppcp-wc-gateway": "cd modules/ppcp-wc-gateway && yarn run build",
|
||||
"build:modules:ppcp-webhooks": "cd modules/ppcp-webhooks && yarn run build",
|
||||
|
@ -24,7 +22,6 @@
|
|||
"build:modules:ppcp-compat": "cd modules/ppcp-compat && yarn run build",
|
||||
"build:modules:ppcp-uninstall": "cd modules/ppcp-uninstall && yarn run build",
|
||||
"build:modules": "run-p build:modules:*",
|
||||
|
||||
"watch:modules:ppcp-button": "cd modules/ppcp-button && yarn run watch",
|
||||
"watch:modules:ppcp-wc-gateway": "cd modules/ppcp-wc-gateway && yarn run watch",
|
||||
"watch:modules:ppcp-webhooks": "cd modules/ppcp-webhooks && yarn run watch",
|
||||
|
@ -33,7 +30,6 @@
|
|||
"watch:modules:ppcp-compat": "cd modules/ppcp-compat && yarn run watch",
|
||||
"watch:modules:ppcp-uninstall": "cd modules/ppcp-uninstall && yarn run watch",
|
||||
"watch:modules": "run-p watch:modules:*",
|
||||
|
||||
"ddev:setup": "ddev start && ddev orchestrate",
|
||||
"ddev:start": "ddev start",
|
||||
"ddev:stop": "ddev stop",
|
||||
|
@ -44,7 +40,10 @@
|
|||
"ddev:composer-update": "ddev composer update && ddev composer update --lock",
|
||||
"ddev:unit-tests": "ddev exec phpunit",
|
||||
"ddev:e2e-tests": "cp -n .env.e2e.example .env.e2e && ddev php tests/e2e/PHPUnit/setup.php && ddev exec phpunit -c tests/e2e/phpunit.xml.dist",
|
||||
"ddev:test": "yarn run ddev:unit-tests && yarn run ddev:e2e-tests",
|
||||
"ddev:pw-install": "ddev exec npx playwright install --with-deps",
|
||||
"ddev:pw-tests-ci": "ddev exec npx playwright test --grep @ci",
|
||||
"ddev:pw-tests-headed": "ddev exec npx playwright test --headed",
|
||||
"ddev:test": "yarn run ddev:unit-tests && yarn run ddev:e2e-tests && yarn run ddev:pw-tests-ci",
|
||||
"ddev:lint": "yarn ddev:phpcs && yarn ddev:psalm",
|
||||
"ddev:phpcs": "ddev exec phpcs --parallel=8 -s",
|
||||
"ddev:psalm": "ddev exec psalm --show-info=false --threads=8 --diff",
|
||||
|
@ -52,19 +51,21 @@
|
|||
"ddev:xdebug-on": "ddev xdebug",
|
||||
"ddev:xdebug-off": "ddev xdebug",
|
||||
"ddev:build-package": "ddev yarn build",
|
||||
|
||||
"prebuild": "rm -rf ./vendor && find . -name 'node_modules' -type d -maxdepth 3 -exec rm -rf {} +",
|
||||
"build": "composer install --no-dev && yarn install && yarn run archive",
|
||||
"prearchive": "rm -rf $npm_package_name.zip",
|
||||
"archive": "zip -r $npm_package_name.zip . -x **.git/\\* **node_modules/\\*",
|
||||
"postarchive": "yarn run archive:cleanup && rm -rf $npm_package_name && unzip $npm_package_name.zip -d $npm_package_name && rm $npm_package_name.zip && zip -r $npm_package_name.zip $npm_package_name && rm -rf $npm_package_name",
|
||||
"archive:cleanup": "zip -d $npm_package_name.zip .env* .ddev/\\* \\*.idea/\\* .editorconfig tests/\\* .github/\\* .psalm/\\* wordpress_org_assets/\\* \\*.DS_Store \\*README.md \\*.gitattributes \\*.gitignore \\*composer.json \\*composer.lock patchwork.json phpunit.xml.dist .phpunit.result.cache phpcs.xml* psalm*.xml* \\*.babelrc \\*package.json \\*webpack.config.js \\*yarn.lock \\*.travis.yml"
|
||||
"archive:cleanup": "zip -d $npm_package_name.zip .env* .ddev/\\* \\*.idea/\\* .editorconfig tests/\\* .github/\\* .psalm/\\* wordpress_org_assets/\\* \\*.DS_Store \\*README.md \\*.gitattributes \\*.gitignore \\*composer.json \\*composer.lock patchwork.json phpunit.xml.dist .phpunit.result.cache phpcs.xml* psalm*.xml* playwright.config.js \\*.babelrc \\*package.json \\*webpack.config.js \\*yarn.lock \\*.travis.yml\\"
|
||||
},
|
||||
"config": {
|
||||
"wp_org_slug": "woocommerce-paypal-payments"
|
||||
},
|
||||
"dependencies": {
|
||||
"dotenv": "^16.0.3",
|
||||
"npm-run-all": "^4.1.5"
|
||||
},
|
||||
"devDependencies": {}
|
||||
"devDependencies": {
|
||||
"@playwright/test": "^1.31.1"
|
||||
}
|
||||
}
|
||||
|
|
11
playwright.config.js
Normal file
11
playwright.config.js
Normal file
|
@ -0,0 +1,11 @@
|
|||
require('dotenv').config({ path: '.env.e2e' });
|
||||
|
||||
const config = {
|
||||
testDir: './tests/playwright',
|
||||
timeout: 30000,
|
||||
use: {
|
||||
baseURL: process.env.BASEURL,
|
||||
},
|
||||
};
|
||||
|
||||
module.exports = config;
|
117
readme.txt
117
readme.txt
|
@ -4,7 +4,7 @@ Tags: woocommerce, paypal, payments, ecommerce, e-commerce, store, sales, sell,
|
|||
Requires at least: 5.3
|
||||
Tested up to: 6.1
|
||||
Requires PHP: 7.2
|
||||
Stable tag: 2.0.2
|
||||
Stable tag: 2.0.3
|
||||
License: GPLv2
|
||||
License URI: http://www.gnu.org/licenses/gpl-2.0.html
|
||||
|
||||
|
@ -81,9 +81,32 @@ Follow the steps below to connect the plugin to your PayPal account:
|
|||
|
||||
== Changelog ==
|
||||
|
||||
= 2.0.2 =
|
||||
= 2.0.3 =
|
||||
* Fix - `DEVICE_DATA_NOT_AVAILABLE` error message when FraudNet is enabled #1177
|
||||
* Fix - Redirect to connection tab after manual credentials input #1201
|
||||
* Fix - Asking for address fields in checkout when not using them #1089
|
||||
* Fix - Validate before free trial #1170
|
||||
* Fix - Validate new user creation #1131
|
||||
* Fix - After Updating to 2.0.2, Site Health reports REST API error #1195
|
||||
* Fix - Do not send buyer-country for previews in live mode to avoid error #1186
|
||||
* Fix - PPEC compatibility layer does not take over subscriptions #1193
|
||||
* Enhancement - Save checkout form before free trial redirect #1135
|
||||
* Enhancement - Add filter for controlling the ditching of items/breakdown #1146
|
||||
* Enhancement - Add patch order data filter #1147
|
||||
* Enhancement - Add filter for disabling fees on wc order admin pages #1153
|
||||
* Enhancement - Use wp_loaded for fraudnet loading to avoid warnings #1172
|
||||
* Enhancement - reCaptcha for WooCommerce support #1093
|
||||
* Enhancement - Make it possible to hide missing funding resource Trustly #1155
|
||||
* Enhancement - Add white color option #1167
|
||||
* Enhancement - Checkout validation for other fields #861
|
||||
* Enhancement - Mention PUI only for German shops and add line breaks #1169
|
||||
* Enhancement - Add filter to fallback tracking_data['carrier'] #1188
|
||||
* Enhancement - Error notices in checkout do not update / or are shown twice #1168
|
||||
* Enhancement - capture authorized payment by changing order status (or programmatically) #587
|
||||
|
||||
= 2.0.2 - 2023-01-31 =
|
||||
* Fix - Do not call PayPal get order by ID if it does not exist #1029
|
||||
* Fix - Type check error conflict with German Market #1056
|
||||
* Fix - Type check error conflict with German Market #1056
|
||||
* Fix - Backend Storage for the PayPalRequestIdRepository does not scale #983
|
||||
* Fix - Ensure WC()->payment_gateways is not null #1128
|
||||
* Enhancement - Remove plugin data after uninstalling #1075
|
||||
|
@ -93,7 +116,7 @@ Follow the steps below to connect the plugin to your PayPal account:
|
|||
* Enhancement - When PUI is enabled FraudNet should be also enabled #1129
|
||||
* Enhancement - Add PayPal-Request-Id if payment source exist #1132
|
||||
|
||||
= 2.0.1 =
|
||||
= 2.0.1 - 2022-12-13 =
|
||||
* Fix - Error while syncing tracking data to PayPal -> Sync GZD Tracking #1020
|
||||
* Fix - Fix product price retrieval for variable product buttons #1000
|
||||
* Fix - All tabs hidden on OXXO tab visit #1048
|
||||
|
@ -106,12 +129,12 @@ Follow the steps below to connect the plugin to your PayPal account:
|
|||
* Fix - Execute WC validation only for smart buttons in checkout #1074
|
||||
* Enhancement - Param types removed in closure to avoid third-party issues #1046
|
||||
|
||||
= 2.0.0 =
|
||||
* Add - Option to separate JSSDK APM payment buttons into individual WooCommerce gateways #671
|
||||
* Add - OXXO APM (Alternative Payment Method) #684
|
||||
= 2.0.0 - 2022-11-21 =
|
||||
* Add - Option to separate JSSDK APM payment buttons into individual WooCommerce gateways #671
|
||||
* Add - OXXO APM (Alternative Payment Method) #684
|
||||
* Add - Pay Later tab #961
|
||||
* Add - Button preview in settings #929
|
||||
* Fix - Prevent Enter key submit for our non-standard button gateways #981
|
||||
* Fix - Prevent Enter key submit for our non-standard button gateways #981
|
||||
* Fix - Pay Upon Invoice - Stock correction on failed orders #964
|
||||
* Fix - Check that WC session exists before using it #846
|
||||
* Fix - Compatibility with One Page Checkout Extension #356
|
||||
|
@ -120,11 +143,11 @@ Follow the steps below to connect the plugin to your PayPal account:
|
|||
* Enhancement - PHP 8.1 warning: Constant FILTER_SANITIZE_STRING is deprecated #867
|
||||
* Enhancement - Execute server-side WC validation when clicking button #942
|
||||
* Enhancement - Update order with order note if payment failed after billing agreement canceled at PayPal #886
|
||||
* Enhancement - Missing PUI refund functionality from WC order #937
|
||||
* Enhancement - Missing PUI refund functionality from WC order #937
|
||||
* Enhancement - Hide Pay upon Invoice tab if not available for merchant #978
|
||||
* Enhancement - Handle synced sub without upfront payment like free trial #936
|
||||
* Enhancement - Isolate container and modularity deps #972
|
||||
**NOTE**: if you were extending/modifying the plugin using the modularity system,
|
||||
**NOTE**: if you were extending/modifying the plugin using the modularity system,
|
||||
you will need to add the `WooCommerce\PayPalCommerce\Vendor\` prefix for the container/modularity namespaces in your code,
|
||||
that is `Psr\Container\ContainerInterface` becomes `WooCommerce\PayPalCommerce\Vendor\Psr\Container\ContainerInterface`,
|
||||
and `Dhii\Modular\Module\ModuleInterface` becomes `WooCommerce\PayPalCommerce\Vendor\Dhii\Modular\Module\ModuleInterface`.
|
||||
|
@ -132,7 +155,7 @@ Follow the steps below to connect the plugin to your PayPal account:
|
|||
* Enhancement - When Brand Name field is left empty, PUI purchase fails #916
|
||||
* Enhancement - Improve styling when using separate buttons #996
|
||||
|
||||
= 1.9.5 =
|
||||
= 1.9.5 - 2022-11-01 =
|
||||
* Fix - Invalid tracking number in logs when adding tracking #903
|
||||
* Fix - Tracking on Connection tab always enabled #900
|
||||
* Fix - PUI payment instructions printed in the refund email #873
|
||||
|
@ -148,7 +171,7 @@ Follow the steps below to connect the plugin to your PayPal account:
|
|||
* Enhancement - Onboard with PUI Checkbox automatically set when shop is set to Germany #876
|
||||
* Enhancement - Update all plugin strings #946
|
||||
|
||||
= 1.9.4 =
|
||||
= 1.9.4 - 2022-10-11 =
|
||||
* Add - Create new connection tab #801
|
||||
* Add - Functionality to choose subscription failure behavior #728
|
||||
* Fix - Virtual-only orders always move order status to completed #868
|
||||
|
@ -160,7 +183,7 @@ Follow the steps below to connect the plugin to your PayPal account:
|
|||
* Enhancement - PUI-relevant webhook not subscribed to #842
|
||||
* Enhancement - Remove WC logo during onboarding #881
|
||||
|
||||
= 1.9.3 =
|
||||
= 1.9.3 - 2022-08-31 =
|
||||
* Add - Tracking API #792
|
||||
* Fix - Improve compatibility with Siteground Optimizer plugin #797
|
||||
* Fix - Transaction ID in order not updated when manually capturing authorized payment from WC #766
|
||||
|
@ -175,7 +198,7 @@ Follow the steps below to connect the plugin to your PayPal account:
|
|||
* Enhancement - PUI add option for a phone number field next to the Birth Date field #742
|
||||
* Enhancement - PUI gateway availability on pay for order page with unsupported currency #744
|
||||
|
||||
= 1.9.2 =
|
||||
= 1.9.2 - 2022-08-09 =
|
||||
* Fix - Do not allow birth date older than 100 years for PUI. #743
|
||||
* Fix - Store the customer id for vaulted payment method in usermeta to not lose vaulted methods after the invoice prefix change. #698
|
||||
* Fix - Capture Virtual-Only Orders setting did not auto-capture subscription renewal payments. #626
|
||||
|
@ -188,28 +211,28 @@ Follow the steps below to connect the plugin to your PayPal account:
|
|||
* Enhancement - Improve Checkout Field Validation Message. #739
|
||||
* Enhancement - Handle PAYER_ACTION_REQUIRED error. #759
|
||||
|
||||
= 1.9.1 =
|
||||
= 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
|
||||
* Fix - Pay Later messaging displayed for out of stock variable products or with no variation selected #667
|
||||
* Fix - Placeholders and card type detection not working for PayPal Card Processing (260) #685
|
||||
* Fix - PUI gateway is displayed with unsupported store currency #711
|
||||
* Fix - Wrong PUI locale sent causing error PAYMENT_SOURCE_CANNOT_BE_USED #741
|
||||
* Fix - Wrong PUI locale sent causing error PAYMENT_SOURCE_CANNOT_BE_USED #741
|
||||
* Enhancement - Missing PayPal fee in WC order details for PUI purchase #714
|
||||
* Enhancement - Skip loading of PUI js file on all pages where PUI gateway is not displayed #723
|
||||
* Enhancement - PUI feature capitalization not consistent #724
|
||||
* Enhancement - PUI feature capitalization not consistent #724
|
||||
|
||||
= 1.9.0 =
|
||||
= 1.9.0 - 2022-07-04 =
|
||||
* Add - New Feature - Pay Upon Invoice (Germany only) #608
|
||||
* Fix - Order not approved: payment via vaulted PayPal account fails #677
|
||||
* Fix - Cant' refund : "ERROR Refund failed: No country given for address." #639
|
||||
* Fix - Something went wrong error in Virtual products when using vaulted payment #673
|
||||
* Fix - Something went wrong error in Virtual products when using vaulted payment #673
|
||||
* Fix - PayPal smart buttons are not displayed for product variations when parent product is set to out of stock #669
|
||||
* Fix - Pay Later messaging displayed for out of stock variable products or with no variation selected #667
|
||||
* Fix - "Capture Virtual-Only Orders" intent sets virtual+downloadable product orders to "Processing" instead of "Completed" #665
|
||||
* Fix - Free trial period causing incorrerct disable-funding parameters with DCC disabled #661
|
||||
* Fix - Smart button not visible on single product page when product price is below 1 and decimal is "," #654
|
||||
* Fix - Pay Later messaging displayed for out of stock variable products or with no variation selected #667
|
||||
* Fix - "Capture Virtual-Only Orders" intent sets virtual+downloadable product orders to "Processing" instead of "Completed" #665
|
||||
* Fix - Free trial period causing incorrerct disable-funding parameters with DCC disabled #661
|
||||
* Fix - Smart button not visible on single product page when product price is below 1 and decimal is "," #654
|
||||
* Fix - Checkout using an email address containing a + symbol results in a "[INVALID_REQUEST]" error #523
|
||||
* Fix - Order details are sometimes empty in PayPal dashboard #689
|
||||
* Fix - Incorrect TAX details on PayPal order overview #541
|
||||
|
@ -217,7 +240,7 @@ Follow the steps below to connect the plugin to your PayPal account:
|
|||
* Fix - DCC causes checkout continuation state after checkout validation error #695
|
||||
* Enhancement - Improve checkout validation & order creation #513
|
||||
|
||||
= 1.8.1 =
|
||||
= 1.8.1 - 2022-05-31 =
|
||||
* Fix - Manual orders return an error for guest users when paying with PayPal Card Processing #530
|
||||
* Fix - "No PayPal order found in the current WooCommerce session" error for guests on Pay for Order page #605
|
||||
* Fix - Error on order discount by third-party plugins #548
|
||||
|
@ -233,7 +256,7 @@ Follow the steps below to connect the plugin to your PayPal account:
|
|||
* Enhancement - Add Fraud Processor Response as an order note #616
|
||||
* Enhancement - Add the Paypal Fee to the Meta Custom Field for export purposes #591
|
||||
|
||||
= 1.8.0 =
|
||||
= 1.8.0 - 2022-05-03 =
|
||||
* Add - Allow free trial subscriptions #580
|
||||
* Fix - The Card Processing does not appear as an available payment method when manually creating an order #562
|
||||
* Fix - Express buttons & Pay Later visible on variable Subscription products /w disabled vaulting #281
|
||||
|
@ -244,7 +267,7 @@ Follow the steps below to connect the plugin to your PayPal account:
|
|||
* Enhancement - Onboarding errors improvements #558
|
||||
* Enhancement - "Place order" button visible during gateway load time when DCC gateway is selected as the default #560
|
||||
|
||||
= 1.7.1 =
|
||||
= 1.7.1 - 2022-04-06 =
|
||||
* Fix - Hide smart buttons for free products and zero-sum carts #499
|
||||
* Fix - Unprocessable Entity when paying with AMEX card #516
|
||||
* Fix - Multisite path doubled in ajax URLs #528
|
||||
|
@ -257,7 +280,7 @@ Follow the steps below to connect the plugin to your PayPal account:
|
|||
* Enhancement - Improve payment token checking for subscriptions #525
|
||||
* Enhancement - Add Spain and Italy to messaging #497
|
||||
|
||||
= 1.7.0 =
|
||||
= 1.7.0 - 2022-02-28 =
|
||||
* Fix - DCC orders randomly failing #503
|
||||
* Fix - Multi-currency broke #481
|
||||
* Fix - Address information from PayPal shortcut flow not loaded #451
|
||||
|
@ -277,7 +300,7 @@ Follow the steps below to connect the plugin to your PayPal account:
|
|||
* Enhancement - PayPal Payments doesn't set transaction fee metadata #467
|
||||
* Enhancement - Show PayPal fee information in order #489
|
||||
|
||||
= 1.6.5 =
|
||||
= 1.6.5 - 2022-01-31 =
|
||||
* Fix - Allow guest users to purchase subscription products from checkout page #422
|
||||
* Fix - Transaction ID missing for renewal order #424
|
||||
* Fix - Save your credit card checkbox should be removed in pay for order for subscriptions #420
|
||||
|
@ -291,7 +314,7 @@ Follow the steps below to connect the plugin to your PayPal account:
|
|||
* Fix - Improve DCC error notice when not available #435
|
||||
* Enhancement - Add View Logs link #416
|
||||
|
||||
= 1.6.4 =
|
||||
= 1.6.4 - 2021-12-27 =
|
||||
* Fix - Non admin user cannot save changes to the plugin settings #278
|
||||
* Fix - Empty space in invoice prefix causes smart buttons to not load #390
|
||||
* Fix - woocommerce_payment_complete action not triggered for payments completed via webhook #399
|
||||
|
@ -300,7 +323,7 @@ Follow the steps below to connect the plugin to your PayPal account:
|
|||
* Enhancement - Allow formatted text for the Description field #407
|
||||
* Enhancement - Remove filter to prevent On-Hold emails #411
|
||||
|
||||
= 1.6.3 =
|
||||
= 1.6.3 - 2021-12-14 =
|
||||
* Fix - Payments fail when using custom order numbers #354
|
||||
* Fix - Do not display saved payments on PayPal buttons if vault option is disabled #358
|
||||
* Fix - Double "Place Order" button #362
|
||||
|
@ -311,7 +334,7 @@ Follow the steps below to connect the plugin to your PayPal account:
|
|||
* Fix - Error messages are not cleared even when checkout is re-attempted (DCC) #366
|
||||
* Add - New additions for system report status #377
|
||||
|
||||
= 1.6.2 =
|
||||
= 1.6.2 - 2021-11-22 =
|
||||
* Fix - Order of WooCommerce checkout actions causing incompatibility with AvaTax address validation #335
|
||||
* Fix - Can't checkout to certain countries with optional postcode #330
|
||||
* Fix - Prevent subscription from being purchased when saving payment fails #308
|
||||
|
@ -328,14 +351,14 @@ Follow the steps below to connect the plugin to your PayPal account:
|
|||
* Fix - When paying for a subscription and vaulting fails, cart is cleared #367
|
||||
* Fix - Fatal error when activating PayPal Checkout plugin #363
|
||||
|
||||
= 1.6.1 =
|
||||
= 1.6.1 - 2021-10-12 =
|
||||
* Fix - Handle authorization capture failures #312
|
||||
* Fix - Handle denied payment authorization #302
|
||||
* Fix - Handle failed authorizations when capturing order #303
|
||||
* Fix - Transactions cannot be voided #293
|
||||
* Fix - Fatal error: get_3ds_contingency() #310
|
||||
|
||||
= 1.6.0 =
|
||||
= 1.6.0 - 2021-09-29 =
|
||||
* Add - Webhook status. #246 #273
|
||||
* Add - Show CC gateway in admin payments list. #236
|
||||
* Add - Add 3d secure contingency settings. #230
|
||||
|
@ -349,14 +372,14 @@ Follow the steps below to connect the plugin to your PayPal account:
|
|||
* Fix - REFUND_CAPTURE_CURRENCY_MISMATCH on multicurrency sites. #225
|
||||
* Fix - Can't checkout to certain countries with optional postcode. #224
|
||||
|
||||
= 1.5.1 =
|
||||
= 1.5.1 - 2021-08-19 =
|
||||
* Fix - Set 3DS contingencies to "SCA_WHEN_REQUIRED". #178
|
||||
* Fix - Plugin conflict blocking line item details. #221
|
||||
* Fix - WooCommerce orders left in "Pending Payment" after a decline. #222
|
||||
* Fix - Do not send decimals when currency does not support them. #202
|
||||
* Fix - Gateway can be activated without a connected PayPal account. #205
|
||||
|
||||
= 1.5.0 =
|
||||
= 1.5.0 - 2021-08-09 =
|
||||
* Add - Filter to modify plugin modules list. #203
|
||||
* Add - Filters to move PayPal buttons and Pay Later messages. #203
|
||||
* Fix - Remove redirection when enabling payment gateway with setup already done. #206
|
||||
|
@ -365,7 +388,7 @@ Follow the steps below to connect the plugin to your PayPal account:
|
|||
* Fix - Hide mini cart height field when mini cart is disabled. #213
|
||||
* Fix - Address possible error on frontend pages due to an empty gateway description. #214
|
||||
|
||||
= 1.4.0 =
|
||||
= 1.4.0 - 2021-07-27 =
|
||||
* Add - Venmo update #169
|
||||
* Add - Pay Later Button –Global Expansion #182
|
||||
* Add - Add Canada to advanced credit and debit card #180
|
||||
|
@ -381,7 +404,7 @@ Follow the steps below to connect the plugin to your PayPal account:
|
|||
* Fix - Remove merchant-id query parameter in JSSDK #179
|
||||
* Fix - Error on Plugin activation with Zettle POS Integration for WooCommerce #195
|
||||
|
||||
= 1.3.2 =
|
||||
= 1.3.2 - 2021-06-08 =
|
||||
* Fix - Improve Subscription plugin support. #161
|
||||
* Fix - Disable vault setting if vaulting feature is not available. #150
|
||||
* Fix - Cast item get_quantity into int. #168
|
||||
|
@ -392,10 +415,10 @@ Follow the steps below to connect the plugin to your PayPal account:
|
|||
* Fix - Fix pay later messaging options. #141
|
||||
* Fix - UI/UX for vaulting settings. #166
|
||||
|
||||
= 1.3.1 =
|
||||
= 1.3.1 - 2021-04-30 =
|
||||
* Fix - Fix Credit Card fields for non logged-in users. #152
|
||||
|
||||
= 1.3.0 =
|
||||
= 1.3.0 - 2021-04-28 =
|
||||
* Add - Client-side vaulting and allow WooCommerce Subscriptions product renewals through payment tokens. #134
|
||||
* Add - Send transaction ids to woocommerce. #125
|
||||
* Fix - Validate checkout form before sending request to PayPal #137
|
||||
|
@ -405,31 +428,31 @@ Follow the steps below to connect the plugin to your PayPal account:
|
|||
* Fix - Remove disabling credit for UK. #127
|
||||
* Fix - Show WC message on account creating error. #136
|
||||
|
||||
= 1.2.1 =
|
||||
= 1.2.1 - 2021-03-08 =
|
||||
* Fix - Address compatibility issue with Jetpack.
|
||||
|
||||
= 1.2.0 =
|
||||
= 1.2.0 - 2021-03-08 =
|
||||
* Add - Rework onboarding code and add REST controller for integration with the OBW. #121
|
||||
* Fix - Remove spinner on click, on cancel and on error. #124
|
||||
|
||||
= 1.1.0 =
|
||||
= 1.1.0 - 2021-02-01 =
|
||||
* Add - Buy Now Pay Later for UK. #104
|
||||
* Add - DE now has 12 month installments. #106
|
||||
* Fix - Check phone for empty string. #102
|
||||
|
||||
= 1.0.4 =
|
||||
= 1.0.4 - 2021-01-18 =
|
||||
* Fix - Check if WooCommerce is active before initialize. #99
|
||||
* Fix - Payment buttons only visible on order-pay site when Mini Cart is enabled; payment fails. #96
|
||||
* Fix - High volume of failed calls to /v1/notifications/webhooks #93
|
||||
* Fix - GB country has ACDC blocked. #91
|
||||
|
||||
= 1.0.3 =
|
||||
= 1.0.3 - 2020-11-30 =
|
||||
* Fix - Order with Payment received when Hosted Fields transaction is declined. #88
|
||||
|
||||
= 1.0.2 =
|
||||
= 1.0.2 - 2020-11-09 =
|
||||
* Fix - Purchases over 1.000 USD fail. #84
|
||||
|
||||
= 1.0.1 =
|
||||
= 1.0.1 - 2020-11-05 =
|
||||
* Fix - PayPal Smart buttons don't load when using a production/live account and `WP_Debug` is turned on/true. #66
|
||||
* Fix - [Card Processing] SCA/Visa Verification form loads underneath the Checkout blockUI element. #63
|
||||
* Fix - Attempting to checkout without country selected results in unexpected error message. #67
|
||||
|
@ -438,5 +461,5 @@ Follow the steps below to connect the plugin to your PayPal account:
|
|||
* Fix - "The value of a field does not conform to the expected format" error when using certain e-mail addresses. #56
|
||||
* Fix - HTML tags in Product description. #79
|
||||
|
||||
= 1.0.0 =
|
||||
= 1.0.0 - 2020-10-15 =
|
||||
* Initial release.
|
||||
|
|
|
@ -0,0 +1,72 @@
|
|||
<?php
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace WooCommerce\PayPalCommerce\Button\Endpoint;
|
||||
|
||||
use Exception;
|
||||
use Mockery;
|
||||
use Psr\Log\LoggerInterface;
|
||||
use WooCommerce\PayPalCommerce\Button\Exception\ValidationException;
|
||||
use WooCommerce\PayPalCommerce\Button\Validation\CheckoutFormValidator;
|
||||
use WooCommerce\PayPalCommerce\TestCase;
|
||||
use function Brain\Monkey\Functions\expect;
|
||||
|
||||
class ValidateCheckoutEndpointTest extends TestCase
|
||||
{
|
||||
private $requestData;
|
||||
private $formValidator;
|
||||
private $logger;
|
||||
private $sut;
|
||||
|
||||
public function setUp(): void
|
||||
{
|
||||
parent::setUp();
|
||||
|
||||
$this->requestData = Mockery::mock(RequestData::class);
|
||||
$this->formValidator = Mockery::mock(CheckoutFormValidator::class);
|
||||
$this->logger = Mockery::mock(LoggerInterface::class);
|
||||
|
||||
$this->sut = new ValidateCheckoutEndpoint(
|
||||
$this->requestData,
|
||||
$this->formValidator,
|
||||
$this->logger
|
||||
);
|
||||
|
||||
$this->requestData->expects('read_request')->andReturn(['form' => ['field1' => 'value']]);
|
||||
}
|
||||
|
||||
public function testValid()
|
||||
{
|
||||
$this->formValidator->expects('validate')->once();
|
||||
|
||||
expect('wp_send_json_success')->once();
|
||||
|
||||
$this->sut->handle_request();
|
||||
}
|
||||
|
||||
public function testInvalid()
|
||||
{
|
||||
$exception = new ValidationException(['Invalid value']);
|
||||
$this->formValidator->expects('validate')->once()
|
||||
->andThrow($exception);
|
||||
|
||||
expect('wp_send_json_error')->once()
|
||||
->with(['message' => $exception->getMessage(), 'errors' => ['Invalid value']]);
|
||||
|
||||
$this->sut->handle_request();
|
||||
}
|
||||
|
||||
public function testFailure()
|
||||
{
|
||||
$exception = new Exception('BOOM');
|
||||
$this->formValidator->expects('validate')->once()
|
||||
->andThrow($exception);
|
||||
|
||||
expect('wp_send_json_error')->once()
|
||||
->with(['message' => $exception->getMessage()]);
|
||||
|
||||
$this->logger->expects('error')->once();
|
||||
|
||||
$this->sut->handle_request();
|
||||
}
|
||||
}
|
|
@ -3,6 +3,7 @@
|
|||
namespace WooCommerce\PayPalCommerce\WcGateway\Assets;
|
||||
|
||||
use WooCommerce\PayPalCommerce\ApiClient\Authentication\Bearer;
|
||||
use WooCommerce\PayPalCommerce\Onboarding\Environment;
|
||||
use WooCommerce\PayPalCommerce\Subscription\Helper\SubscriptionHelper;
|
||||
use WooCommerce\PayPalCommerce\TestCase;
|
||||
use function Brain\Monkey\Functions\when;
|
||||
|
@ -23,6 +24,7 @@ class SettingsPagesAssetsTest extends TestCase
|
|||
'123',
|
||||
'EUR',
|
||||
'DE',
|
||||
Mockery::mock(Environment::class),
|
||||
true,
|
||||
array(),
|
||||
array()
|
||||
|
|
|
@ -8,5 +8,6 @@ require_once ROOT_DIR . '/vendor/autoload.php';
|
|||
require_once TESTS_ROOT_DIR . '/stubs/WC_Payment_Gateway.php';
|
||||
require_once TESTS_ROOT_DIR . '/stubs/WC_Payment_Gateway_CC.php';
|
||||
require_once TESTS_ROOT_DIR . '/stubs/WC_Ajax.php';
|
||||
require_once TESTS_ROOT_DIR . '/stubs/WC_Checkout.php';
|
||||
|
||||
Hamcrest\Util::registerGlobalFunctions();
|
||||
|
|
70
tests/e2e/PHPUnit/Validation/ValidationTest.php
Normal file
70
tests/e2e/PHPUnit/Validation/ValidationTest.php
Normal file
|
@ -0,0 +1,70 @@
|
|||
<?php
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace WooCommerce\PayPalCommerce\Tests\E2e\Validation;
|
||||
|
||||
use WooCommerce\PayPalCommerce\Button\Exception\ValidationException;
|
||||
use WooCommerce\PayPalCommerce\Button\Validation\CheckoutFormValidator;
|
||||
use WooCommerce\PayPalCommerce\Tests\E2e\TestCase;
|
||||
|
||||
class ValidationTest extends TestCase
|
||||
{
|
||||
protected $container;
|
||||
|
||||
/**
|
||||
* @var CheckoutFormValidator
|
||||
*/
|
||||
protected $sut;
|
||||
|
||||
public function setUp(): void
|
||||
{
|
||||
parent::setUp();
|
||||
|
||||
$this->container = $this->getContainer();
|
||||
|
||||
$this->sut = $this->container->get( 'button.validation.wc-checkout-validator' );
|
||||
assert($this->sut instanceof CheckoutFormValidator);
|
||||
}
|
||||
|
||||
public function testValid()
|
||||
{
|
||||
$this->sut->validate([
|
||||
'billing_first_name'=>'John',
|
||||
'billing_last_name'=>'Doe',
|
||||
'billing_company'=>'',
|
||||
'billing_country'=>'DE',
|
||||
'billing_address_1'=>'1 Main St',
|
||||
'billing_address_2'=>'city1',
|
||||
'billing_postcode'=>'11111',
|
||||
'billing_city'=>'city1',
|
||||
'billing_state'=>'DE-BW',
|
||||
'billing_phone'=>'12345678',
|
||||
'billing_email'=>'a@gmail.com',
|
||||
'terms-field'=>'1',
|
||||
'terms'=>'on',
|
||||
]);
|
||||
}
|
||||
|
||||
public function testInvalid()
|
||||
{
|
||||
$this->expectException(ValidationException::class);
|
||||
$this->expectExceptionMessageMatches('/.+First name.+Postcode/i');
|
||||
|
||||
$this->sut->validate([
|
||||
'billing_first_name'=>'',
|
||||
'billing_postcode'=>'ABCDE',
|
||||
|
||||
'billing_last_name'=>'Doe',
|
||||
'billing_company'=>'',
|
||||
'billing_country'=>'DE',
|
||||
'billing_address_1'=>'1 Main St',
|
||||
'billing_address_2'=>'city1',
|
||||
'billing_city'=>'city1',
|
||||
'billing_state'=>'DE-BW',
|
||||
'billing_phone'=>'12345678',
|
||||
'billing_email'=>'a@gmail.com',
|
||||
'terms-field'=>'1',
|
||||
'terms'=>'on',
|
||||
]);
|
||||
}
|
||||
}
|
3
tests/playwright/.gitignore
vendored
Normal file
3
tests/playwright/.gitignore
vendored
Normal file
|
@ -0,0 +1,3 @@
|
|||
test-results/
|
||||
playwright-report/
|
||||
.cache/
|
15
tests/playwright/README.md
Normal file
15
tests/playwright/README.md
Normal file
|
@ -0,0 +1,15 @@
|
|||
# Playwright Testing
|
||||
|
||||
## Local Environment Variables
|
||||
Allows using environment variables inside the tests.
|
||||
|
||||
- Duplicate `.env.e2e.example` and rename it as `.env.e2e`, set values and add new variables if needed.
|
||||
|
||||
## Run Tests
|
||||
```
|
||||
$ npx playwright test
|
||||
$ npx playwright test --grep @ci
|
||||
$ npx playwright test example.spec.js --headed
|
||||
$ npx playwright test example.spec.js --debug
|
||||
$ npx playwright test -g "Test name here"
|
||||
```
|
75
tests/playwright/place-order.spec.js
Normal file
75
tests/playwright/place-order.spec.js
Normal file
|
@ -0,0 +1,75 @@
|
|||
const {test, expect} = require('@playwright/test');
|
||||
const {
|
||||
CUSTOMER_EMAIL,
|
||||
CUSTOMER_PASSWORD,
|
||||
CREDIT_CARD_NUMBER,
|
||||
CREDIT_CARD_EXPIRATION,
|
||||
CREDIT_CARD_CVV
|
||||
} = process.env;
|
||||
|
||||
async function fillCheckoutForm(page) {
|
||||
await page.fill('#billing_first_name', 'John');
|
||||
await page.fill('#billing_last_name', 'Doe');
|
||||
await page.selectOption('select#billing_country', 'DE');
|
||||
await page.fill('#billing_address_1', 'Badensche Str. 24');
|
||||
await page.fill('#billing_postcode', '10715');
|
||||
await page.fill('#billing_city', '10715');
|
||||
await page.fill('#billing_phone', '1234567890');
|
||||
await page.fill('#billing_email', CUSTOMER_EMAIL);
|
||||
}
|
||||
|
||||
test('PayPal button place order from Product page', async ({page}) => {
|
||||
|
||||
await page.goto('/product/product/');
|
||||
|
||||
const [popup] = await Promise.all([
|
||||
page.waitForEvent('popup'),
|
||||
page.frameLocator('.component-frame').locator('[data-funding-source="paypal"]').click(),
|
||||
]);
|
||||
await popup.waitForLoadState();
|
||||
|
||||
await popup.click("text=Log in");
|
||||
await popup.fill('#email', CUSTOMER_EMAIL);
|
||||
await popup.locator('#btnNext').click();
|
||||
await popup.fill('#password', CUSTOMER_PASSWORD);
|
||||
await popup.locator('#btnLogin').click();
|
||||
|
||||
await popup.locator('#payment-submit-btn').click();
|
||||
await fillCheckoutForm(page);
|
||||
|
||||
await Promise.all([
|
||||
page.waitForNavigation(),
|
||||
page.locator('#place_order').click(),
|
||||
]);
|
||||
|
||||
const title = await page.locator('.entry-title');
|
||||
await expect(title).toHaveText('Order received');
|
||||
});
|
||||
|
||||
test('Advanced Credit and Debit Card (ACDC) place order from Checkout page @ci', async ({page}) => {
|
||||
|
||||
await page.goto('/product/product/');
|
||||
await page.locator('.single_add_to_cart_button').click();
|
||||
|
||||
await page.goto('/checkout/');
|
||||
await fillCheckoutForm(page);
|
||||
|
||||
await page.click("text=Credit Cards");
|
||||
|
||||
const creditCardNumber = page.frameLocator('#braintree-hosted-field-number').locator('#credit-card-number');
|
||||
await creditCardNumber.fill(CREDIT_CARD_NUMBER);
|
||||
|
||||
const expirationDate = page.frameLocator('#braintree-hosted-field-expirationDate').locator('#expiration');
|
||||
await expirationDate.fill(CREDIT_CARD_EXPIRATION);
|
||||
|
||||
const cvv = page.frameLocator('#braintree-hosted-field-cvv').locator('#cvv');
|
||||
await cvv.fill(CREDIT_CARD_CVV);
|
||||
|
||||
await Promise.all([
|
||||
page.waitForNavigation(),
|
||||
page.locator('.ppcp-dcc-order-button').click(),
|
||||
]);
|
||||
|
||||
const title = await page.locator('.entry-title');
|
||||
await expect(title).toHaveText('Order received');
|
||||
});
|
11
tests/stubs/WC_Checkout.php
Normal file
11
tests/stubs/WC_Checkout.php
Normal file
|
@ -0,0 +1,11 @@
|
|||
<?php
|
||||
declare( strict_types=1 );
|
||||
|
||||
class WC_Checkout {
|
||||
public function get_posted_data() {
|
||||
return [];
|
||||
}
|
||||
|
||||
protected function validate_checkout( &$data, &$errors ) {
|
||||
}
|
||||
}
|
|
@ -3,13 +3,13 @@
|
|||
* Plugin Name: WooCommerce PayPal Payments
|
||||
* Plugin URI: https://woocommerce.com/products/woocommerce-paypal-payments/
|
||||
* Description: PayPal's latest complete payments processing solution. Accept PayPal, Pay Later, credit/debit cards, alternative digital wallets local payment types and bank accounts. Turn on only PayPal options or process a full suite of payment methods. Enable global transaction with extensive currency and country coverage.
|
||||
* Version: 2.0.2
|
||||
* Version: 2.0.3
|
||||
* Author: WooCommerce
|
||||
* Author URI: https://woocommerce.com/
|
||||
* License: GPL-2.0
|
||||
* Requires PHP: 7.2
|
||||
* WC requires at least: 3.9
|
||||
* WC tested up to: 7.2
|
||||
* WC tested up to: 7.4
|
||||
* Text Domain: woocommerce-paypal-payments
|
||||
*
|
||||
* @package WooCommerce\PayPalCommerce
|
||||
|
@ -23,7 +23,7 @@ use WooCommerce\PayPalCommerce\WcGateway\Settings\Settings;
|
|||
|
||||
define( 'PAYPAL_API_URL', 'https://api.paypal.com' );
|
||||
define( 'PAYPAL_SANDBOX_API_URL', 'https://api.sandbox.paypal.com' );
|
||||
define( 'PAYPAL_INTEGRATION_DATE', '2023-01-11' );
|
||||
define( 'PAYPAL_INTEGRATION_DATE', '2023-02-21' );
|
||||
|
||||
define( 'PPCP_FLAG_SUBSCRIPTION', true );
|
||||
|
||||
|
|
30
yarn.lock
30
yarn.lock
|
@ -2,6 +2,21 @@
|
|||
# yarn lockfile v1
|
||||
|
||||
|
||||
"@playwright/test@^1.31.1":
|
||||
version "1.31.1"
|
||||
resolved "https://registry.yarnpkg.com/@playwright/test/-/test-1.31.1.tgz#39d6873dc46af135f12451d79707db7d1357455d"
|
||||
integrity sha512-IsytVZ+0QLDh1Hj83XatGp/GsI1CDJWbyDaBGbainsh0p2zC7F4toUocqowmjS6sQff2NGT3D9WbDj/3K2CJiA==
|
||||
dependencies:
|
||||
"@types/node" "*"
|
||||
playwright-core "1.31.1"
|
||||
optionalDependencies:
|
||||
fsevents "2.3.2"
|
||||
|
||||
"@types/node@*":
|
||||
version "18.14.1"
|
||||
resolved "https://registry.yarnpkg.com/@types/node/-/node-18.14.1.tgz#90dad8476f1e42797c49d6f8b69aaf9f876fc69f"
|
||||
integrity sha512-QH+37Qds3E0eDlReeboBxfHbX9omAcBCXEzswCu6jySP642jiM3cYSIkU/REqwhCUqXdonHFuBfJDiAJxMNhaQ==
|
||||
|
||||
ansi-styles@^3.2.1:
|
||||
version "3.2.1"
|
||||
resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-3.2.1.tgz#41fbb20243e50b12be0f04b8dedbf07520ce841d"
|
||||
|
@ -75,6 +90,11 @@ define-properties@^1.1.3, define-properties@^1.1.4:
|
|||
has-property-descriptors "^1.0.0"
|
||||
object-keys "^1.1.1"
|
||||
|
||||
dotenv@^16.0.3:
|
||||
version "16.0.3"
|
||||
resolved "https://registry.yarnpkg.com/dotenv/-/dotenv-16.0.3.tgz#115aec42bac5053db3c456db30cc243a5a836a07"
|
||||
integrity sha512-7GO6HghkA5fYG9TYnNxi14/7K9f5occMlp3zXAuSxn7CKCxt9xbNWG7yF8hTCSUchlfWSe3uLmlPfigevRItzQ==
|
||||
|
||||
error-ex@^1.3.1:
|
||||
version "1.3.2"
|
||||
resolved "https://registry.yarnpkg.com/error-ex/-/error-ex-1.3.2.tgz#b4ac40648107fdcdcfae242f428bea8a14d4f1bf"
|
||||
|
@ -126,6 +146,11 @@ escape-string-regexp@^1.0.5:
|
|||
resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz#1b61c0562190a8dff6ae3bb2cf0200ca130b86d4"
|
||||
integrity sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==
|
||||
|
||||
fsevents@2.3.2:
|
||||
version "2.3.2"
|
||||
resolved "https://registry.yarnpkg.com/fsevents/-/fsevents-2.3.2.tgz#8a526f78b8fdf4623b709e0b975c52c24c02fd1a"
|
||||
integrity sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==
|
||||
|
||||
function-bind@^1.1.1:
|
||||
version "1.1.1"
|
||||
resolved "https://registry.yarnpkg.com/function-bind/-/function-bind-1.1.1.tgz#a56899d3ea3c9bab874bb9773b7c5ede92f4895d"
|
||||
|
@ -422,6 +447,11 @@ pify@^3.0.0:
|
|||
resolved "https://registry.yarnpkg.com/pify/-/pify-3.0.0.tgz#e5a4acd2c101fdf3d9a4d07f0dbc4db49dd28176"
|
||||
integrity sha512-C3FsVNH1udSEX48gGX1xfvwTWfsYWj5U+8/uK15BGzIGrKoUpghX8hWZwa/OFnakBiiVNmBvemTJR5mcy7iPcg==
|
||||
|
||||
playwright-core@1.31.1:
|
||||
version "1.31.1"
|
||||
resolved "https://registry.yarnpkg.com/playwright-core/-/playwright-core-1.31.1.tgz#4deeebbb8fb73b512593fe24bea206d8fd85ff7f"
|
||||
integrity sha512-JTyX4kV3/LXsvpHkLzL2I36aCdml4zeE35x+G5aPc4bkLsiRiQshU5lWeVpHFAuC8xAcbI6FDcw/8z3q2xtJSQ==
|
||||
|
||||
read-pkg@^3.0.0:
|
||||
version "3.0.0"
|
||||
resolved "https://registry.yarnpkg.com/read-pkg/-/read-pkg-3.0.0.tgz#9cbc686978fee65d16c00e2b19c237fcf6e38389"
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue