mirror of
https://github.com/woocommerce/woocommerce-paypal-payments.git
synced 2025-08-31 06:52:50 +08:00
Merge branch 'trunk' into PCP-991-v2-detach-vaulting-from-wc-subscriptions-support
This commit is contained in:
commit
d6c12ce29d
34 changed files with 669 additions and 379 deletions
|
@ -1,6 +1,6 @@
|
|||
*** Changelog ***
|
||||
|
||||
= 2.2.0 - TBD =
|
||||
= 2.2.0 - 2023-07-17 =
|
||||
* Fix - Improve handling of APM payments when buyer did not return to Checkout #1233
|
||||
* Fix - Use order currency instead of shop currency on order-pay page #1363
|
||||
* Fix - Do not show broken card button gateway when no checkout location #1358
|
||||
|
@ -11,6 +11,7 @@
|
|||
* Fix - Incompatibility with WooCommerce One Page Checkout (or similar use cases) in Version 2.1.0 #1473
|
||||
* Fix - Prevent Repetitive Token Migration and Database Overload After 2.1.0 Update #1461
|
||||
* Fix - Onboarding from connection page with CSRF parameter manipulates email and merchant id fields #1502
|
||||
* Fix - Do not complete non-checkout button orders via webhooks #1513
|
||||
* Enhancement - Remove feature flag requirement for express cart/checkout block integration #1483
|
||||
* Enhancement - Add notice when shop currency is unsupported #1433
|
||||
* Enhancement - Improve ACDC error message when empty fields #1360
|
||||
|
|
|
@ -298,6 +298,7 @@ return array(
|
|||
$shipping_factory = $container->get( 'api.factory.shipping' );
|
||||
$payments_factory = $container->get( 'api.factory.payments' );
|
||||
$prefix = $container->get( 'api.prefix' );
|
||||
$soft_descriptor = $container->get( 'wcgateway.soft-descriptor' );
|
||||
|
||||
return new PurchaseUnitFactory(
|
||||
$amount_factory,
|
||||
|
@ -306,7 +307,8 @@ return array(
|
|||
$item_factory,
|
||||
$shipping_factory,
|
||||
$payments_factory,
|
||||
$prefix
|
||||
$prefix,
|
||||
$soft_descriptor
|
||||
);
|
||||
},
|
||||
'api.factory.patch-collection-factory' => static function ( ContainerInterface $container ): PatchCollectionFactory {
|
||||
|
|
|
@ -18,7 +18,6 @@ use WooCommerce\PayPalCommerce\ApiClient\Entity\Order;
|
|||
use WooCommerce\PayPalCommerce\ApiClient\Entity\OrderStatus;
|
||||
use WooCommerce\PayPalCommerce\ApiClient\Entity\PatchCollection;
|
||||
use WooCommerce\PayPalCommerce\ApiClient\Entity\Payer;
|
||||
use WooCommerce\PayPalCommerce\ApiClient\Entity\PaymentMethod;
|
||||
use WooCommerce\PayPalCommerce\ApiClient\Entity\PaymentToken;
|
||||
use WooCommerce\PayPalCommerce\ApiClient\Entity\PurchaseUnit;
|
||||
use WooCommerce\PayPalCommerce\ApiClient\Exception\PayPalApiException;
|
||||
|
@ -27,7 +26,6 @@ use WooCommerce\PayPalCommerce\ApiClient\Factory\OrderFactory;
|
|||
use WooCommerce\PayPalCommerce\ApiClient\Factory\PatchCollectionFactory;
|
||||
use WooCommerce\PayPalCommerce\ApiClient\Helper\ErrorResponse;
|
||||
use WooCommerce\PayPalCommerce\ApiClient\Repository\ApplicationContextRepository;
|
||||
use WooCommerce\PayPalCommerce\ApiClient\Repository\PayPalRequestIdRepository;
|
||||
use Psr\Log\LoggerInterface;
|
||||
use WooCommerce\PayPalCommerce\Subscription\Helper\SubscriptionHelper;
|
||||
use WooCommerce\PayPalCommerce\WcGateway\FraudNet\FraudNet;
|
||||
|
@ -176,13 +174,12 @@ class OrderEndpoint {
|
|||
/**
|
||||
* Creates an order.
|
||||
*
|
||||
* @param PurchaseUnit[] $items The purchase unit items for the order.
|
||||
* @param string $shipping_preference One of ApplicationContext::SHIPPING_PREFERENCE_ values.
|
||||
* @param Payer|null $payer The payer off the order.
|
||||
* @param PaymentToken|null $payment_token The payment token.
|
||||
* @param PaymentMethod|null $payment_method The payment method.
|
||||
* @param string $paypal_request_id The paypal request id.
|
||||
* @param string $user_action The user action.
|
||||
* @param PurchaseUnit[] $items The purchase unit items for the order.
|
||||
* @param string $shipping_preference One of ApplicationContext::SHIPPING_PREFERENCE_ values.
|
||||
* @param Payer|null $payer The payer off the order.
|
||||
* @param PaymentToken|null $payment_token The payment token.
|
||||
* @param string $paypal_request_id The paypal request id.
|
||||
* @param string $user_action The user action.
|
||||
*
|
||||
* @return Order
|
||||
* @throws RuntimeException If the request fails.
|
||||
|
@ -192,7 +189,6 @@ class OrderEndpoint {
|
|||
string $shipping_preference,
|
||||
Payer $payer = null,
|
||||
PaymentToken $payment_token = null,
|
||||
PaymentMethod $payment_method = null,
|
||||
string $paypal_request_id = '',
|
||||
string $user_action = ApplicationContext::USER_ACTION_CONTINUE
|
||||
): Order {
|
||||
|
@ -221,9 +217,6 @@ class OrderEndpoint {
|
|||
if ( $payment_token ) {
|
||||
$data['payment_source']['token'] = $payment_token->to_array();
|
||||
}
|
||||
if ( $payment_method ) {
|
||||
$data['payment_method'] = $payment_method->to_array();
|
||||
}
|
||||
|
||||
/**
|
||||
* The filter can be used to modify the order creation request body data.
|
||||
|
|
|
@ -41,6 +41,9 @@ class ApplicationContext {
|
|||
self::USER_ACTION_PAY_NOW,
|
||||
);
|
||||
|
||||
const PAYMENT_METHOD_UNRESTRICTED = 'UNRESTRICTED';
|
||||
const PAYMENT_METHOD_IMMEDIATE_PAYMENT_REQUIRED = 'IMMEDIATE_PAYMENT_REQUIRED';
|
||||
|
||||
/**
|
||||
* The brand name.
|
||||
*
|
||||
|
@ -91,11 +94,11 @@ class ApplicationContext {
|
|||
private $cancel_url;
|
||||
|
||||
/**
|
||||
* The payment method.
|
||||
* The payment method preference.
|
||||
*
|
||||
* @var null
|
||||
* @var string
|
||||
*/
|
||||
private $payment_method;
|
||||
private $payment_method_preference;
|
||||
|
||||
/**
|
||||
* ApplicationContext constructor.
|
||||
|
@ -107,6 +110,7 @@ class ApplicationContext {
|
|||
* @param string $landing_page The landing page.
|
||||
* @param string $shipping_preference The shipping preference.
|
||||
* @param string $user_action The user action.
|
||||
* @param string $payment_method_preference The payment method preference.
|
||||
*
|
||||
* @throws RuntimeException When values are not valid.
|
||||
*/
|
||||
|
@ -117,7 +121,8 @@ class ApplicationContext {
|
|||
string $locale = '',
|
||||
string $landing_page = self::LANDING_PAGE_NO_PREFERENCE,
|
||||
string $shipping_preference = self::SHIPPING_PREFERENCE_NO_SHIPPING,
|
||||
string $user_action = self::USER_ACTION_CONTINUE
|
||||
string $user_action = self::USER_ACTION_CONTINUE,
|
||||
string $payment_method_preference = self::PAYMENT_METHOD_IMMEDIATE_PAYMENT_REQUIRED
|
||||
) {
|
||||
|
||||
if ( ! in_array( $landing_page, self::VALID_LANDING_PAGE_VALUES, true ) ) {
|
||||
|
@ -129,16 +134,14 @@ class ApplicationContext {
|
|||
if ( ! in_array( $user_action, self::VALID_USER_ACTION_VALUES, true ) ) {
|
||||
throw new RuntimeException( 'User action preference not correct' );
|
||||
}
|
||||
$this->return_url = $return_url;
|
||||
$this->cancel_url = $cancel_url;
|
||||
$this->brand_name = $brand_name;
|
||||
$this->locale = $locale;
|
||||
$this->landing_page = $landing_page;
|
||||
$this->shipping_preference = $shipping_preference;
|
||||
$this->user_action = $user_action;
|
||||
|
||||
// Currently we have not implemented the payment method.
|
||||
$this->payment_method = null;
|
||||
$this->return_url = $return_url;
|
||||
$this->cancel_url = $cancel_url;
|
||||
$this->brand_name = $brand_name;
|
||||
$this->locale = $locale;
|
||||
$this->landing_page = $landing_page;
|
||||
$this->shipping_preference = $shipping_preference;
|
||||
$this->user_action = $user_action;
|
||||
$this->payment_method_preference = $payment_method_preference;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -205,12 +208,10 @@ class ApplicationContext {
|
|||
}
|
||||
|
||||
/**
|
||||
* Returns the payment method.
|
||||
*
|
||||
* @return PaymentMethod|null
|
||||
* Returns the payment method preference.
|
||||
*/
|
||||
public function payment_method() {
|
||||
return $this->payment_method;
|
||||
public function payment_method_preference(): string {
|
||||
return $this->payment_method_preference;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -223,9 +224,6 @@ class ApplicationContext {
|
|||
if ( $this->user_action() ) {
|
||||
$data['user_action'] = $this->user_action();
|
||||
}
|
||||
if ( $this->payment_method() ) {
|
||||
$data['payment_method'] = $this->payment_method();
|
||||
}
|
||||
if ( $this->shipping_preference() ) {
|
||||
$data['shipping_preference'] = $this->shipping_preference();
|
||||
}
|
||||
|
@ -244,6 +242,11 @@ class ApplicationContext {
|
|||
if ( $this->cancel_url() ) {
|
||||
$data['cancel_url'] = $this->cancel_url();
|
||||
}
|
||||
if ( $this->payment_method_preference ) {
|
||||
$data['payment_method'] = array(
|
||||
'payee_preferred' => $this->payment_method_preference,
|
||||
);
|
||||
}
|
||||
return $data;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -73,6 +73,13 @@ class Item {
|
|||
*/
|
||||
protected $tax_rate;
|
||||
|
||||
/**
|
||||
* The cart item key.
|
||||
*
|
||||
* @var string|null
|
||||
*/
|
||||
protected $cart_item_key;
|
||||
|
||||
/**
|
||||
* Item constructor.
|
||||
*
|
||||
|
@ -84,6 +91,7 @@ class Item {
|
|||
* @param string $sku The SKU.
|
||||
* @param string $category The category.
|
||||
* @param float $tax_rate The tax rate.
|
||||
* @param ?string $cart_item_key The cart key for this item.
|
||||
*/
|
||||
public function __construct(
|
||||
string $name,
|
||||
|
@ -93,18 +101,20 @@ class Item {
|
|||
Money $tax = null,
|
||||
string $sku = '',
|
||||
string $category = 'PHYSICAL_GOODS',
|
||||
float $tax_rate = 0
|
||||
float $tax_rate = 0,
|
||||
string $cart_item_key = null
|
||||
) {
|
||||
|
||||
$this->name = $name;
|
||||
$this->unit_amount = $unit_amount;
|
||||
$this->quantity = $quantity;
|
||||
$this->description = $description;
|
||||
$this->tax = $tax;
|
||||
$this->sku = $sku;
|
||||
$this->category = ( self::DIGITAL_GOODS === $category ) ? self::DIGITAL_GOODS : self::PHYSICAL_GOODS;
|
||||
$this->category = $category;
|
||||
$this->tax_rate = $tax_rate;
|
||||
$this->name = $name;
|
||||
$this->unit_amount = $unit_amount;
|
||||
$this->quantity = $quantity;
|
||||
$this->description = $description;
|
||||
$this->tax = $tax;
|
||||
$this->sku = $sku;
|
||||
$this->category = ( self::DIGITAL_GOODS === $category ) ? self::DIGITAL_GOODS : self::PHYSICAL_GOODS;
|
||||
$this->category = $category;
|
||||
$this->tax_rate = $tax_rate;
|
||||
$this->cart_item_key = $cart_item_key;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -179,6 +189,15 @@ class Item {
|
|||
return round( (float) $this->tax_rate, 2 );
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the cart key for this item.
|
||||
*
|
||||
* @return string|null
|
||||
*/
|
||||
public function cart_item_key():?string {
|
||||
return $this->cart_item_key;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the object as array.
|
||||
*
|
||||
|
@ -202,6 +221,10 @@ class Item {
|
|||
$item['tax_rate'] = (string) $this->tax_rate();
|
||||
}
|
||||
|
||||
if ( $this->cart_item_key() ) {
|
||||
$item['cart_item_key'] = (string) $this->cart_item_key();
|
||||
}
|
||||
|
||||
return $item;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,81 +0,0 @@
|
|||
<?php
|
||||
/**
|
||||
* The PaymentMethod object
|
||||
*
|
||||
* @package WooCommerce\PayPalCommerce\ApiClient\Entity
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace WooCommerce\PayPalCommerce\ApiClient\Entity;
|
||||
|
||||
/**
|
||||
* Class PaymentMethod
|
||||
*/
|
||||
class PaymentMethod {
|
||||
|
||||
|
||||
const PAYER_SELECTED_DEFAULT = 'PAYPAL';
|
||||
|
||||
const PAYEE_PREFERRED_UNRESTRICTED = 'UNRESTRICTED';
|
||||
const PAYEE_PREFERRED_IMMEDIATE_PAYMENT_REQUIRED = 'IMMEDIATE_PAYMENT_REQUIRED';
|
||||
|
||||
/**
|
||||
* The preferred value.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
private $preferred;
|
||||
|
||||
/**
|
||||
* The selected value.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
private $selected;
|
||||
|
||||
/**
|
||||
* PaymentMethod constructor.
|
||||
*
|
||||
* @param string $preferred The preferred value.
|
||||
* @param string $selected The selected value.
|
||||
*/
|
||||
public function __construct(
|
||||
string $preferred = self::PAYEE_PREFERRED_UNRESTRICTED,
|
||||
string $selected = self::PAYER_SELECTED_DEFAULT
|
||||
) {
|
||||
|
||||
$this->preferred = $preferred;
|
||||
$this->selected = $selected;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the payer preferred value.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function payee_preferred(): string {
|
||||
return $this->preferred;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the payer selected value.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function payer_selected(): string {
|
||||
return $this->selected;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the object as array.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function to_array(): array {
|
||||
return array(
|
||||
'payee_preferred' => $this->payee_preferred(),
|
||||
'payer_selected' => $this->payer_selected(),
|
||||
);
|
||||
}
|
||||
}
|
|
@ -211,6 +211,15 @@ class PurchaseUnit {
|
|||
return $this->custom_id;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the custom ID.
|
||||
*
|
||||
* @param string $custom_id The value to set.
|
||||
*/
|
||||
public function set_custom_id( string $custom_id ): void {
|
||||
$this->custom_id = $custom_id;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the invoice id.
|
||||
*
|
||||
|
|
|
@ -44,7 +44,8 @@ class ItemFactory {
|
|||
public function from_wc_cart( \WC_Cart $cart ): array {
|
||||
$items = array_map(
|
||||
function ( array $item ): Item {
|
||||
$product = $item['data'];
|
||||
$product = $item['data'];
|
||||
$cart_item_key = $item['key'] ?? null;
|
||||
|
||||
/**
|
||||
* The WooCommerce product.
|
||||
|
@ -61,7 +62,9 @@ class ItemFactory {
|
|||
$this->prepare_description( $product->get_description() ),
|
||||
null,
|
||||
$product->get_sku(),
|
||||
( $product->is_virtual() ) ? Item::DIGITAL_GOODS : Item::PHYSICAL_GOODS
|
||||
( $product->is_virtual() ) ? Item::DIGITAL_GOODS : Item::PHYSICAL_GOODS,
|
||||
0,
|
||||
$cart_item_key
|
||||
);
|
||||
},
|
||||
$cart->get_cart_contents()
|
||||
|
|
|
@ -70,6 +70,13 @@ class PurchaseUnitFactory {
|
|||
*/
|
||||
private $prefix;
|
||||
|
||||
/**
|
||||
* The Soft Descriptor.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
private $soft_descriptor;
|
||||
|
||||
/**
|
||||
* PurchaseUnitFactory constructor.
|
||||
*
|
||||
|
@ -80,6 +87,7 @@ class PurchaseUnitFactory {
|
|||
* @param ShippingFactory $shipping_factory The shipping factory.
|
||||
* @param PaymentsFactory $payments_factory The payments factory.
|
||||
* @param string $prefix The prefix.
|
||||
* @param string $soft_descriptor The soft descriptor.
|
||||
*/
|
||||
public function __construct(
|
||||
AmountFactory $amount_factory,
|
||||
|
@ -88,7 +96,8 @@ class PurchaseUnitFactory {
|
|||
ItemFactory $item_factory,
|
||||
ShippingFactory $shipping_factory,
|
||||
PaymentsFactory $payments_factory,
|
||||
string $prefix = 'WC-'
|
||||
string $prefix = 'WC-',
|
||||
string $soft_descriptor = ''
|
||||
) {
|
||||
|
||||
$this->amount_factory = $amount_factory;
|
||||
|
@ -98,6 +107,7 @@ class PurchaseUnitFactory {
|
|||
$this->shipping_factory = $shipping_factory;
|
||||
$this->payments_factory = $payments_factory;
|
||||
$this->prefix = $prefix;
|
||||
$this->soft_descriptor = $soft_descriptor;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -128,7 +138,7 @@ class PurchaseUnitFactory {
|
|||
$payee = $this->payee_repository->payee();
|
||||
$custom_id = (string) $order->get_id();
|
||||
$invoice_id = $this->prefix . $order->get_order_number();
|
||||
$soft_descriptor = '';
|
||||
$soft_descriptor = $this->soft_descriptor;
|
||||
|
||||
$purchase_unit = new PurchaseUnit(
|
||||
$amount,
|
||||
|
@ -198,7 +208,7 @@ class PurchaseUnitFactory {
|
|||
}
|
||||
}
|
||||
$invoice_id = '';
|
||||
$soft_descriptor = '';
|
||||
$soft_descriptor = $this->soft_descriptor;
|
||||
$purchase_unit = new PurchaseUnit(
|
||||
$amount,
|
||||
$items,
|
||||
|
@ -233,7 +243,7 @@ class PurchaseUnitFactory {
|
|||
$description = ( isset( $data->description ) ) ? $data->description : '';
|
||||
$custom_id = ( isset( $data->custom_id ) ) ? $data->custom_id : '';
|
||||
$invoice_id = ( isset( $data->invoice_id ) ) ? $data->invoice_id : '';
|
||||
$soft_descriptor = ( isset( $data->soft_descriptor ) ) ? $data->soft_descriptor : '';
|
||||
$soft_descriptor = ( isset( $data->soft_descriptor ) ) ? $data->soft_descriptor : $this->soft_descriptor;
|
||||
$items = array();
|
||||
if ( isset( $data->items ) && is_array( $data->items ) ) {
|
||||
$items = array_map(
|
||||
|
|
|
@ -47,18 +47,21 @@ class ApplicationContextRepository {
|
|||
string $user_action = ApplicationContext::USER_ACTION_CONTINUE
|
||||
): ApplicationContext {
|
||||
|
||||
$brand_name = $this->settings->has( 'brand_name' ) ? $this->settings->get( 'brand_name' ) : '';
|
||||
$locale = $this->valid_bcp47_code();
|
||||
$landingpage = $this->settings->has( 'landing_page' ) ?
|
||||
$brand_name = $this->settings->has( 'brand_name' ) ? $this->settings->get( 'brand_name' ) : '';
|
||||
$locale = $this->valid_bcp47_code();
|
||||
$landingpage = $this->settings->has( 'landing_page' ) ?
|
||||
$this->settings->get( 'landing_page' ) : ApplicationContext::LANDING_PAGE_NO_PREFERENCE;
|
||||
$context = new ApplicationContext(
|
||||
$payment_preference = $this->settings->has( 'payee_preferred' ) && $this->settings->get( 'payee_preferred' ) ?
|
||||
ApplicationContext::PAYMENT_METHOD_IMMEDIATE_PAYMENT_REQUIRED : ApplicationContext::PAYMENT_METHOD_UNRESTRICTED;
|
||||
$context = new ApplicationContext(
|
||||
network_home_url( \WC_AJAX::get_endpoint( ReturnUrlEndpoint::ENDPOINT ) ),
|
||||
(string) wc_get_checkout_url(),
|
||||
(string) $brand_name,
|
||||
$locale,
|
||||
(string) $landingpage,
|
||||
$shipping_preferences,
|
||||
$user_action
|
||||
$user_action,
|
||||
$payment_preference
|
||||
);
|
||||
return $context;
|
||||
}
|
||||
|
|
|
@ -164,6 +164,7 @@ const bootstrap = () => {
|
|||
const cartBootstrap = new CartBootstrap(
|
||||
PayPalCommerceGateway,
|
||||
renderer,
|
||||
messageRenderer,
|
||||
errorHandler,
|
||||
);
|
||||
|
||||
|
|
|
@ -50,8 +50,6 @@ class CheckoutActionHandler {
|
|||
|
||||
const formSelector = this.config.context === 'checkout' ? 'form.checkout' : 'form#order_review';
|
||||
const formData = new FormData(document.querySelector(formSelector));
|
||||
// will not handle fields with multiple values (checkboxes, <select multiple>), but we do not care about this here
|
||||
const formJsonObj = Object.fromEntries(formData.entries());
|
||||
|
||||
const createaccount = jQuery('#createaccount').is(":checked") ? true : false;
|
||||
|
||||
|
@ -72,7 +70,8 @@ class CheckoutActionHandler {
|
|||
order_id:this.config.order_id,
|
||||
payment_method: paymentMethod,
|
||||
funding_source: fundingSource,
|
||||
form: formJsonObj,
|
||||
// send as urlencoded string to handle complex fields via PHP functions the same as normal form submit
|
||||
form_encoded: new URLSearchParams(formData).toString(),
|
||||
createaccount: createaccount
|
||||
})
|
||||
}).then(function (res) {
|
||||
|
|
|
@ -1,7 +1,10 @@
|
|||
import Product from '../Entity/Product';
|
||||
import BookingProduct from "../Entity/BookingProduct";
|
||||
import onApprove from '../OnApproveHandler/onApproveForContinue';
|
||||
import {payerData} from "../Helper/PayerData";
|
||||
import {PaymentMethods} from "../Helper/CheckoutMethodState";
|
||||
import CartHelper from "../Helper/CartHelper";
|
||||
import FormHelper from "../Helper/FormHelper";
|
||||
|
||||
class SingleProductActionHandler {
|
||||
|
||||
|
@ -15,6 +18,7 @@ class SingleProductActionHandler {
|
|||
this.updateCart = updateCart;
|
||||
this.formElement = formElement;
|
||||
this.errorHandler = errorHandler;
|
||||
this.cartHelper = null;
|
||||
}
|
||||
|
||||
getPlanIdFromVariation = (variation) => {
|
||||
|
@ -91,43 +95,70 @@ class SingleProductActionHandler {
|
|||
createOrder: this.createOrder(),
|
||||
onApprove: onApprove(this, this.errorHandler),
|
||||
onError: (error) => {
|
||||
this.refreshMiniCart();
|
||||
|
||||
if (this.isBookingProduct() && error.message) {
|
||||
this.errorHandler.clear();
|
||||
this.errorHandler.message(error.message);
|
||||
return;
|
||||
}
|
||||
this.errorHandler.genericError();
|
||||
},
|
||||
onCancel: () => {
|
||||
// Could be used for every product type,
|
||||
// but only clean the cart for Booking products for now.
|
||||
if (this.isBookingProduct()) {
|
||||
this.cleanCart();
|
||||
} else {
|
||||
this.refreshMiniCart();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
createOrder()
|
||||
{
|
||||
var getProducts = null;
|
||||
if (! this.isGroupedProduct() ) {
|
||||
getProducts = () => {
|
||||
const id = document.querySelector('[name="add-to-cart"]').value;
|
||||
const qty = document.querySelector('[name="quantity"]').value;
|
||||
const variations = this.variations();
|
||||
return [new Product(id, qty, variations)];
|
||||
this.cartHelper = null;
|
||||
|
||||
let getProducts = (() => {
|
||||
if ( this.isBookingProduct() ) {
|
||||
return () => {
|
||||
const id = document.querySelector('[name="add-to-cart"]').value;
|
||||
return [new BookingProduct(id, 1, FormHelper.getPrefixedFields(this.formElement, "wc_bookings_field"))];
|
||||
}
|
||||
} else if ( this.isGroupedProduct() ) {
|
||||
return () => {
|
||||
const products = [];
|
||||
this.formElement.querySelectorAll('input[type="number"]').forEach((element) => {
|
||||
if (! element.value) {
|
||||
return;
|
||||
}
|
||||
const elementName = element.getAttribute('name').match(/quantity\[([\d]*)\]/);
|
||||
if (elementName.length !== 2) {
|
||||
return;
|
||||
}
|
||||
const id = parseInt(elementName[1]);
|
||||
const quantity = parseInt(element.value);
|
||||
products.push(new Product(id, quantity, null));
|
||||
})
|
||||
return products;
|
||||
}
|
||||
} else {
|
||||
return () => {
|
||||
const id = document.querySelector('[name="add-to-cart"]').value;
|
||||
const qty = document.querySelector('[name="quantity"]').value;
|
||||
const variations = this.variations();
|
||||
return [new Product(id, qty, variations)];
|
||||
}
|
||||
}
|
||||
} else {
|
||||
getProducts = () => {
|
||||
const products = [];
|
||||
this.formElement.querySelectorAll('input[type="number"]').forEach((element) => {
|
||||
if (! element.value) {
|
||||
return;
|
||||
}
|
||||
const elementName = element.getAttribute('name').match(/quantity\[([\d]*)\]/);
|
||||
if (elementName.length !== 2) {
|
||||
return;
|
||||
}
|
||||
const id = parseInt(elementName[1]);
|
||||
const quantity = parseInt(element.value);
|
||||
products.push(new Product(id, quantity, null));
|
||||
})
|
||||
return products;
|
||||
}
|
||||
}
|
||||
const createOrder = (data, actions) => {
|
||||
})();
|
||||
|
||||
return (data, actions) => {
|
||||
this.errorHandler.clear();
|
||||
|
||||
const onResolve = (purchase_units) => {
|
||||
this.cartHelper = (new CartHelper()).addFromPurchaseUnits(purchase_units);
|
||||
|
||||
const payer = payerData();
|
||||
const bnCode = typeof this.config.bn_codes[this.config.context] !== 'undefined' ?
|
||||
this.config.bn_codes[this.config.context] : '';
|
||||
|
@ -157,19 +188,16 @@ class SingleProductActionHandler {
|
|||
});
|
||||
};
|
||||
|
||||
const promise = this.updateCart.update(onResolve, getProducts());
|
||||
return promise;
|
||||
return this.updateCart.update(onResolve, getProducts());
|
||||
};
|
||||
return createOrder;
|
||||
}
|
||||
|
||||
variations()
|
||||
{
|
||||
|
||||
if (! this.hasVariations()) {
|
||||
return null;
|
||||
}
|
||||
const attributes = [...this.formElement.querySelectorAll("[name^='attribute_']")].map(
|
||||
return [...this.formElement.querySelectorAll("[name^='attribute_']")].map(
|
||||
(element) => {
|
||||
return {
|
||||
value:element.value,
|
||||
|
@ -177,7 +205,6 @@ class SingleProductActionHandler {
|
|||
}
|
||||
}
|
||||
);
|
||||
return attributes;
|
||||
}
|
||||
|
||||
hasVariations()
|
||||
|
@ -189,5 +216,24 @@ class SingleProductActionHandler {
|
|||
{
|
||||
return this.formElement.classList.contains('grouped_form');
|
||||
}
|
||||
|
||||
isBookingProduct()
|
||||
{
|
||||
// detection for "woocommerce-bookings" plugin
|
||||
return !!this.formElement.querySelector('.wc-booking-product-id');
|
||||
}
|
||||
|
||||
cleanCart() {
|
||||
this.cartHelper.removeFromCart().then(() => {
|
||||
this.refreshMiniCart();
|
||||
}).catch(error => {
|
||||
this.refreshMiniCart();
|
||||
});
|
||||
}
|
||||
|
||||
refreshMiniCart() {
|
||||
jQuery(document.body).trigger('wc_fragment_refresh');
|
||||
}
|
||||
|
||||
}
|
||||
export default SingleProductActionHandler;
|
||||
|
|
|
@ -3,10 +3,12 @@ import BootstrapHelper from "../Helper/BootstrapHelper";
|
|||
import {setVisible} from "../Helper/Hiding";
|
||||
|
||||
class CartBootstrap {
|
||||
constructor(gateway, renderer, errorHandler) {
|
||||
constructor(gateway, renderer, messages, errorHandler) {
|
||||
this.gateway = gateway;
|
||||
this.renderer = renderer;
|
||||
this.messages = messages;
|
||||
this.errorHandler = errorHandler;
|
||||
this.lastAmount = this.gateway.messages.amount;
|
||||
|
||||
this.renderer.onButtonsInit(this.gateway.button.wrapper, () => {
|
||||
this.handleButtonStatus();
|
||||
|
@ -38,11 +40,16 @@ class CartBootstrap {
|
|||
return;
|
||||
}
|
||||
|
||||
const newParams = result.data;
|
||||
const newParams = result.data.url_params;
|
||||
const reloadRequired = this.gateway.url_params.intent !== newParams.intent;
|
||||
|
||||
// TODO: should reload the script instead
|
||||
setVisible(this.gateway.button.wrapper, !reloadRequired)
|
||||
|
||||
if (this.lastAmount !== result.data.amount) {
|
||||
this.lastAmount = result.data.amount;
|
||||
this.messages.renderWithAmount(this.lastAmount);
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
@ -76,6 +83,8 @@ class CartBootstrap {
|
|||
this.renderer.render(
|
||||
actionHandler.configuration()
|
||||
);
|
||||
|
||||
this.messages.renderWithAmount(this.lastAmount);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -15,6 +15,7 @@ class CheckoutBootstap {
|
|||
this.messages = messages;
|
||||
this.spinner = spinner;
|
||||
this.errorHandler = errorHandler;
|
||||
this.lastAmount = this.gateway.messages.amount;
|
||||
|
||||
this.standardOrderButtonSelector = ORDER_BUTTON_SELECTOR;
|
||||
|
||||
|
@ -36,6 +37,27 @@ class CheckoutBootstap {
|
|||
jQuery(document.body).on('updated_checkout', () => {
|
||||
this.render()
|
||||
this.handleButtonStatus();
|
||||
|
||||
if (this.shouldRenderMessages()) { // currently we need amount only for Pay Later
|
||||
fetch(
|
||||
this.gateway.ajax.cart_script_params.endpoint,
|
||||
{
|
||||
method: 'GET',
|
||||
credentials: 'same-origin',
|
||||
}
|
||||
)
|
||||
.then(result => result.json())
|
||||
.then(result => {
|
||||
if (! result.success) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (this.lastAmount !== result.data.amount) {
|
||||
this.lastAmount = result.data.amount;
|
||||
this.updateUi();
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
jQuery(document.body).on('updated_checkout payment_method_selected', () => {
|
||||
|
@ -117,8 +139,8 @@ class CheckoutBootstap {
|
|||
setVisible(wrapper, gatewayId === currentPaymentMethod);
|
||||
}
|
||||
|
||||
if (isPaypal && !isFreeTrial) {
|
||||
this.messages.render();
|
||||
if (this.shouldRenderMessages()) {
|
||||
this.messages.renderWithAmount(this.lastAmount);
|
||||
}
|
||||
|
||||
if (isCard) {
|
||||
|
@ -130,6 +152,12 @@ class CheckoutBootstap {
|
|||
}
|
||||
}
|
||||
|
||||
shouldRenderMessages() {
|
||||
return getCurrentPaymentMethod() === PaymentMethods.PAYPAL
|
||||
&& !PayPalCommerceGateway.is_free_trial_cart
|
||||
&& this.messages.shouldRender();
|
||||
}
|
||||
|
||||
disableCreditCardFields() {
|
||||
jQuery('label[for="ppcp-credit-card-gateway-card-number"]').addClass('ppcp-credit-card-gateway-form-field-disabled')
|
||||
jQuery('#ppcp-credit-card-gateway-card-number').addClass('ppcp-credit-card-gateway-form-field-disabled')
|
||||
|
|
|
@ -0,0 +1,18 @@
|
|||
import Product from "./Product";
|
||||
|
||||
class BookingProduct extends Product {
|
||||
|
||||
constructor(id, quantity, booking) {
|
||||
super(id, quantity, null);
|
||||
this.booking = booking;
|
||||
}
|
||||
|
||||
data() {
|
||||
return {
|
||||
...super.data(),
|
||||
booking: this.booking
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export default BookingProduct;
|
|
@ -0,0 +1,65 @@
|
|||
class CartHelper {
|
||||
|
||||
constructor(cartItemKeys = [])
|
||||
{
|
||||
this.endpoint = wc_cart_fragments_params.wc_ajax_url.toString().replace('%%endpoint%%', 'remove_from_cart');
|
||||
this.cartItemKeys = cartItemKeys;
|
||||
}
|
||||
|
||||
addFromPurchaseUnits(purchaseUnits) {
|
||||
for (const purchaseUnit of purchaseUnits || []) {
|
||||
for (const item of purchaseUnit.items || []) {
|
||||
if (!item.cart_item_key) {
|
||||
continue;
|
||||
}
|
||||
this.cartItemKeys.push(item.cart_item_key);
|
||||
}
|
||||
}
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
removeFromCart()
|
||||
{
|
||||
return new Promise((resolve, reject) => {
|
||||
if (!this.cartItemKeys || !this.cartItemKeys.length) {
|
||||
resolve();
|
||||
return;
|
||||
}
|
||||
|
||||
const numRequests = this.cartItemKeys.length;
|
||||
let numResponses = 0;
|
||||
|
||||
const tryToResolve = () => {
|
||||
numResponses++;
|
||||
if (numResponses >= numRequests) {
|
||||
resolve();
|
||||
}
|
||||
}
|
||||
|
||||
for (const cartItemKey of this.cartItemKeys) {
|
||||
const params = new URLSearchParams();
|
||||
params.append('cart_item_key', cartItemKey);
|
||||
|
||||
if (!cartItemKey) {
|
||||
tryToResolve();
|
||||
continue;
|
||||
}
|
||||
|
||||
fetch(this.endpoint, {
|
||||
method: 'POST',
|
||||
credentials: 'same-origin',
|
||||
body: params
|
||||
}).then(function (res) {
|
||||
return res.json();
|
||||
}).then(() => {
|
||||
tryToResolve();
|
||||
}).catch(() => {
|
||||
tryToResolve();
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
export default CartHelper;
|
|
@ -0,0 +1,17 @@
|
|||
|
||||
/**
|
||||
* Common Form utility methods
|
||||
*/
|
||||
export default class FormHelper {
|
||||
|
||||
static getPrefixedFields(formElement, prefix) {
|
||||
let fields = {};
|
||||
for(const element of formElement.elements) {
|
||||
if( element.name.startsWith(prefix) ) {
|
||||
fields[element.name] = element.value;
|
||||
}
|
||||
}
|
||||
return fields;
|
||||
}
|
||||
|
||||
}
|
|
@ -6,7 +6,6 @@ export default class FormValidator {
|
|||
|
||||
async validate(form) {
|
||||
const formData = new FormData(form);
|
||||
const formJsonObj = Object.fromEntries(formData.entries());
|
||||
|
||||
const res = await fetch(this.url, {
|
||||
method: 'POST',
|
||||
|
@ -16,7 +15,7 @@ export default class FormValidator {
|
|||
credentials: 'same-origin',
|
||||
body: JSON.stringify({
|
||||
nonce: this.nonce,
|
||||
form: formJsonObj,
|
||||
form_encoded: new URLSearchParams(formData).toString(),
|
||||
}),
|
||||
});
|
||||
|
||||
|
|
|
@ -5,28 +5,6 @@ class MessageRenderer {
|
|||
this.optionsFingerprint = null;
|
||||
}
|
||||
|
||||
render() {
|
||||
if (! this.shouldRender()) {
|
||||
return;
|
||||
}
|
||||
|
||||
const options = {
|
||||
amount: this.config.amount,
|
||||
placement: this.config.placement,
|
||||
style: this.config.style
|
||||
};
|
||||
|
||||
if (this.optionsEqual(options)) {
|
||||
return;
|
||||
}
|
||||
|
||||
paypal.Messages(options).render(this.config.wrapper);
|
||||
|
||||
jQuery(document.body).on('updated_cart_totals', () => {
|
||||
paypal.Messages(options).render(this.config.wrapper);
|
||||
});
|
||||
}
|
||||
|
||||
renderWithAmount(amount) {
|
||||
if (! this.shouldRender()) {
|
||||
return;
|
||||
|
|
|
@ -67,7 +67,12 @@ class CartScriptParamsEndpoint implements EndpointInterface {
|
|||
try {
|
||||
$script_data = $this->smart_button->script_data();
|
||||
|
||||
wp_send_json_success( $script_data['url_params'] );
|
||||
wp_send_json_success(
|
||||
array(
|
||||
'url_params' => $script_data['url_params'],
|
||||
'amount' => WC()->cart->get_total( 'raw' ),
|
||||
)
|
||||
);
|
||||
|
||||
return true;
|
||||
} catch ( Throwable $error ) {
|
||||
|
|
|
@ -153,13 +153,23 @@ class ChangeCartEndpoint implements EndpointInterface {
|
|||
$this->cart->empty_cart( false );
|
||||
$success = true;
|
||||
foreach ( $products as $product ) {
|
||||
$success = $success && ( ! $product['product']->is_type( 'variable' ) ) ?
|
||||
$this->add_product( $product['product'], $product['quantity'] )
|
||||
: $this->add_variable_product(
|
||||
if ( $product['product']->is_type( 'booking' ) ) {
|
||||
$success = $success && $this->add_booking_product(
|
||||
$product['product'],
|
||||
$product['booking']
|
||||
);
|
||||
} elseif ( $product['product']->is_type( 'variable' ) ) {
|
||||
$success = $success && $this->add_variable_product(
|
||||
$product['product'],
|
||||
$product['quantity'],
|
||||
$product['variations']
|
||||
);
|
||||
} else {
|
||||
$success = $success && $this->add_product(
|
||||
$product['product'],
|
||||
$product['quantity']
|
||||
);
|
||||
}
|
||||
}
|
||||
if ( ! $success ) {
|
||||
$this->handle_error();
|
||||
|
@ -234,7 +244,8 @@ class ChangeCartEndpoint implements EndpointInterface {
|
|||
$products[] = array(
|
||||
'product' => $wc_product,
|
||||
'quantity' => (int) $product['quantity'],
|
||||
'variations' => isset( $product['variations'] ) ? $product['variations'] : null,
|
||||
'variations' => $product['variations'] ?? null,
|
||||
'booking' => $product['booking'] ?? null,
|
||||
);
|
||||
}
|
||||
return $products;
|
||||
|
@ -286,6 +297,31 @@ class ChangeCartEndpoint implements EndpointInterface {
|
|||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds variations to the cart.
|
||||
*
|
||||
* @param \WC_Product $product The Product.
|
||||
* @param array $data Data used by the booking plugin.
|
||||
*
|
||||
* @return bool
|
||||
* @throws Exception When product could not be added.
|
||||
*/
|
||||
private function add_booking_product(
|
||||
\WC_Product $product,
|
||||
array $data
|
||||
): bool {
|
||||
|
||||
if ( ! is_callable( 'wc_bookings_get_posted_data' ) ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$cart_item_data = array(
|
||||
'booking' => wc_bookings_get_posted_data( $data, $product ),
|
||||
);
|
||||
|
||||
return false !== $this->cart->add_to_cart( $product->get_id(), 1, 0, array(), $cart_item_data );
|
||||
}
|
||||
|
||||
/**
|
||||
* Based on the cart contents, the purchase units are created.
|
||||
*
|
||||
|
|
|
@ -19,7 +19,6 @@ use WooCommerce\PayPalCommerce\ApiClient\Entity\ApplicationContext;
|
|||
use WooCommerce\PayPalCommerce\ApiClient\Entity\Money;
|
||||
use WooCommerce\PayPalCommerce\ApiClient\Entity\Order;
|
||||
use WooCommerce\PayPalCommerce\ApiClient\Entity\Payer;
|
||||
use WooCommerce\PayPalCommerce\ApiClient\Entity\PaymentMethod;
|
||||
use WooCommerce\PayPalCommerce\ApiClient\Entity\PurchaseUnit;
|
||||
use WooCommerce\PayPalCommerce\ApiClient\Exception\PayPalApiException;
|
||||
use WooCommerce\PayPalCommerce\ApiClient\Exception\RuntimeException;
|
||||
|
@ -32,7 +31,6 @@ use WooCommerce\PayPalCommerce\Button\Helper\EarlyOrderHandler;
|
|||
use WooCommerce\PayPalCommerce\Session\SessionHandler;
|
||||
use WooCommerce\PayPalCommerce\Subscription\FreeTrialHandlerTrait;
|
||||
use WooCommerce\PayPalCommerce\WcGateway\CardBillingMode;
|
||||
use WooCommerce\PayPalCommerce\WcGateway\Exception\NotFoundException;
|
||||
use WooCommerce\PayPalCommerce\WcGateway\Gateway\CardButtonGateway;
|
||||
use WooCommerce\PayPalCommerce\WcGateway\Gateway\CreditCardGateway;
|
||||
use WooCommerce\PayPalCommerce\WcGateway\Gateway\PayPalGateway;
|
||||
|
@ -166,6 +164,13 @@ class CreateOrderEndpoint implements EndpointInterface {
|
|||
*/
|
||||
protected $logger;
|
||||
|
||||
/**
|
||||
* The form data, or empty if not available.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
private $form = array();
|
||||
|
||||
/**
|
||||
* CreateOrderEndpoint constructor.
|
||||
*
|
||||
|
@ -258,6 +263,12 @@ class CreateOrderEndpoint implements EndpointInterface {
|
|||
} else {
|
||||
$this->purchase_unit = $this->purchase_unit_factory->from_wc_cart( null, $this->handle_shipping_in_paypal );
|
||||
|
||||
// Do not allow completion by webhooks when started via non-checkout buttons,
|
||||
// it is needed only for some APMs in checkout.
|
||||
if ( in_array( $data['context'], array( 'product', 'cart', 'cart-block' ), true ) ) {
|
||||
$this->purchase_unit->set_custom_id( '' );
|
||||
}
|
||||
|
||||
// The cart does not have any info about payment method, so we must handle free trial here.
|
||||
if ( (
|
||||
in_array( $payment_method, array( CreditCardGateway::ID, CardButtonGateway::ID ), true )
|
||||
|
@ -276,18 +287,20 @@ class CreateOrderEndpoint implements EndpointInterface {
|
|||
|
||||
$this->set_bn_code( $data );
|
||||
|
||||
$form_fields = $data['form'] ?? null;
|
||||
if ( isset( $data['form'] ) ) {
|
||||
$this->form = $data['form'];
|
||||
}
|
||||
|
||||
if ( $this->early_validation_enabled
|
||||
&& is_array( $form_fields )
|
||||
&& $this->form
|
||||
&& 'checkout' === $data['context']
|
||||
&& in_array( $payment_method, array( PayPalGateway::ID, CardButtonGateway::ID ), true )
|
||||
) {
|
||||
$this->validate_form( $form_fields );
|
||||
$this->validate_form( $this->form );
|
||||
}
|
||||
|
||||
if ( 'pay-now' === $data['context'] && is_array( $form_fields ) && get_option( 'woocommerce_terms_page_id', '' ) !== '' ) {
|
||||
$this->validate_paynow_form( $form_fields );
|
||||
if ( 'pay-now' === $data['context'] && $this->form && get_option( 'woocommerce_terms_page_id', '' ) !== '' ) {
|
||||
$this->validate_paynow_form( $this->form );
|
||||
}
|
||||
|
||||
try {
|
||||
|
@ -448,7 +461,6 @@ class CreateOrderEndpoint implements EndpointInterface {
|
|||
$shipping_preference,
|
||||
$payer,
|
||||
null,
|
||||
$this->payment_method(),
|
||||
'',
|
||||
$action
|
||||
);
|
||||
|
@ -471,8 +483,7 @@ class CreateOrderEndpoint implements EndpointInterface {
|
|||
array( $this->purchase_unit ),
|
||||
$shipping_preference,
|
||||
$payer,
|
||||
null,
|
||||
$this->payment_method()
|
||||
null
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -510,11 +521,9 @@ class CreateOrderEndpoint implements EndpointInterface {
|
|||
$payer = $this->payer_factory->from_paypal_response( json_decode( wp_json_encode( $data['payer'] ) ) );
|
||||
}
|
||||
|
||||
if ( ! $payer && isset( $data['form'] ) ) {
|
||||
$form_fields = $data['form'];
|
||||
|
||||
if ( is_array( $form_fields ) && isset( $form_fields['billing_email'] ) && '' !== $form_fields['billing_email'] ) {
|
||||
return $this->payer_factory->from_checkout_form( $form_fields );
|
||||
if ( ! $payer && $this->form ) {
|
||||
if ( isset( $this->form['billing_email'] ) && '' !== $this->form['billing_email'] ) {
|
||||
return $this->payer_factory->from_checkout_form( $this->form );
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -536,24 +545,6 @@ class CreateOrderEndpoint implements EndpointInterface {
|
|||
$this->api_endpoint->with_bn_code( $bn_code );
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the PaymentMethod object for the order.
|
||||
*
|
||||
* @return PaymentMethod
|
||||
*/
|
||||
private function payment_method() : PaymentMethod {
|
||||
try {
|
||||
$payee_preferred = $this->settings->has( 'payee_preferred' ) && $this->settings->get( 'payee_preferred' ) ?
|
||||
PaymentMethod::PAYEE_PREFERRED_IMMEDIATE_PAYMENT_REQUIRED
|
||||
: PaymentMethod::PAYEE_PREFERRED_UNRESTRICTED;
|
||||
} catch ( NotFoundException $exception ) {
|
||||
$payee_preferred = PaymentMethod::PAYEE_PREFERRED_UNRESTRICTED;
|
||||
}
|
||||
|
||||
$payment_method = new PaymentMethod( $payee_preferred );
|
||||
return $payment_method;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks whether the form fields are valid.
|
||||
*
|
||||
|
|
|
@ -53,6 +53,11 @@ class RequestData {
|
|||
}
|
||||
$this->dequeue_nonce_fix();
|
||||
|
||||
if ( isset( $json['form_encoded'] ) ) {
|
||||
$json['form'] = array();
|
||||
parse_str( $json['form_encoded'], $json['form'] );
|
||||
}
|
||||
|
||||
$sanitized = $this->sanitize( $json );
|
||||
return $sanitized;
|
||||
}
|
||||
|
@ -80,6 +85,10 @@ class RequestData {
|
|||
private function sanitize( array $assoc_array ): array {
|
||||
$data = array();
|
||||
foreach ( (array) $assoc_array as $raw_key => $raw_value ) {
|
||||
if ( $raw_key === 'form_encoded' ) {
|
||||
$data[ $raw_key ] = $raw_value;
|
||||
continue;
|
||||
}
|
||||
if ( ! is_array( $raw_value ) ) {
|
||||
// Not sure if it is a good idea to sanitize everything at this level,
|
||||
// but should be fine for now since we do not send any HTML or multi-line texts via ajax.
|
||||
|
|
|
@ -9,6 +9,7 @@ declare(strict_types=1);
|
|||
|
||||
namespace WooCommerce\PayPalCommerce\StatusReport;
|
||||
|
||||
use WooCommerce\PayPalCommerce\Subscription\Helper\SubscriptionHelper;
|
||||
use WooCommerce\PayPalCommerce\Vendor\Dhii\Container\ServiceProvider;
|
||||
use WooCommerce\PayPalCommerce\Vendor\Dhii\Modular\Module\ModuleInterface;
|
||||
use WooCommerce\PayPalCommerce\Vendor\Interop\Container\ServiceProviderInterface;
|
||||
|
@ -49,6 +50,8 @@ class StatusReportModule implements ModuleInterface {
|
|||
$settings = $c->get( 'wcgateway.settings' );
|
||||
assert( $settings instanceof ContainerInterface );
|
||||
|
||||
$subscriptions_mode_settings = $c->get( 'wcgateway.settings.fields.subscriptions_mode' ) ?: array();
|
||||
|
||||
/* @var State $state The state. */
|
||||
$state = $c->get( 'onboarding.state' );
|
||||
|
||||
|
@ -61,6 +64,9 @@ class StatusReportModule implements ModuleInterface {
|
|||
/* @var MessagesApply $messages_apply The messages apply. */
|
||||
$messages_apply = $c->get( 'button.helper.messages-apply' );
|
||||
|
||||
/* @var SubscriptionHelper $subscription_helper The subscription helper class. */
|
||||
$subscription_helper = $c->get( 'subscription.helper' );
|
||||
|
||||
$last_webhook_storage = $c->get( 'webhook.last-webhook-storage' );
|
||||
assert( $last_webhook_storage instanceof WebhookEventStorage );
|
||||
|
||||
|
@ -167,6 +173,20 @@ class StatusReportModule implements ModuleInterface {
|
|||
),
|
||||
);
|
||||
|
||||
// For now only show this status if PPCP_FLAG_SUBSCRIPTIONS_API is true.
|
||||
if ( defined( 'PPCP_FLAG_SUBSCRIPTIONS_API' ) && PPCP_FLAG_SUBSCRIPTIONS_API ) {
|
||||
$items[] = array(
|
||||
'label' => esc_html__( 'Subscriptions Mode', 'woocommerce-paypal-payments' ),
|
||||
'exported_label' => 'Subscriptions Mode',
|
||||
'description' => esc_html__( 'Whether subscriptions are active and their mode.', 'woocommerce-paypal-payments' ),
|
||||
'value' => $this->subscriptions_mode_text(
|
||||
$subscription_helper->plugin_is_active(),
|
||||
$settings->has( 'subscriptions_mode' ) ? (string) $settings->get( 'subscriptions_mode' ) : '',
|
||||
$subscriptions_mode_settings
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
echo wp_kses_post(
|
||||
$renderer->render(
|
||||
esc_html__( 'WooCommerce PayPal Payments', 'woocommerce-paypal-payments' ),
|
||||
|
@ -200,6 +220,27 @@ class StatusReportModule implements ModuleInterface {
|
|||
return $token->is_valid() && $current_state === $state::STATE_ONBOARDED;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the text associated with the subscriptions mode status.
|
||||
*
|
||||
* @param bool $is_plugin_active Indicates if the WooCommerce Subscriptions plugin is active.
|
||||
* @param string $subscriptions_mode The subscriptions mode stored in settings.
|
||||
* @param array $field_settings The subscriptions mode field settings.
|
||||
* @return string
|
||||
*/
|
||||
private function subscriptions_mode_text( bool $is_plugin_active, string $subscriptions_mode, array $field_settings ): string {
|
||||
if ( ! $is_plugin_active || ! $field_settings || $subscriptions_mode === 'disable_paypal_subscriptions' ) {
|
||||
return 'Disabled';
|
||||
}
|
||||
|
||||
if ( ! $subscriptions_mode ) {
|
||||
$subscriptions_mode = $field_settings['default'] ?? '';
|
||||
}
|
||||
|
||||
// Return the options value or if it's missing from options the settings value.
|
||||
return $field_settings['options'][ $subscriptions_mode ] ?? $subscriptions_mode;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if reference transactions are enabled in account.
|
||||
*
|
||||
|
|
|
@ -386,6 +386,28 @@ return array(
|
|||
return array_key_exists( $current_page_id, $sections );
|
||||
},
|
||||
|
||||
'wcgateway.settings.fields.subscriptions_mode' => static function ( ContainerInterface $container ): array {
|
||||
return array(
|
||||
'title' => __( 'Subscriptions Mode', 'woocommerce-paypal-payments' ),
|
||||
'type' => 'select',
|
||||
'class' => array(),
|
||||
'input_class' => array( 'wc-enhanced-select' ),
|
||||
'desc_tip' => true,
|
||||
'description' => __( 'Utilize PayPal Vaulting for flexible subscription processing with saved payment methods, create “PayPal Subscriptions” to bill customers at regular intervals, or disable PayPal for subscription-type products.', 'woocommerce-paypal-payments' ),
|
||||
'default' => 'vaulting_api',
|
||||
'options' => array(
|
||||
'vaulting_api' => __( 'PayPal Vaulting', 'woocommerce-paypal-payments' ),
|
||||
'subscriptions_api' => __( 'PayPal Subscriptions', 'woocommerce-paypal-payments' ),
|
||||
'disable_paypal_subscriptions' => __( 'Disable PayPal for subscriptions', 'woocommerce-paypal-payments' ),
|
||||
),
|
||||
'screens' => array(
|
||||
State::STATE_ONBOARDED,
|
||||
),
|
||||
'requirements' => array(),
|
||||
'gateway' => 'paypal',
|
||||
);
|
||||
},
|
||||
|
||||
'wcgateway.settings.fields' => static function ( ContainerInterface $container ): array {
|
||||
|
||||
$should_render_settings = $container->get( 'wcgateway.settings.should-render-settings' );
|
||||
|
@ -805,25 +827,7 @@ return array(
|
|||
'requirements' => array(),
|
||||
'gateway' => 'paypal',
|
||||
),
|
||||
'subscriptions_mode' => array(
|
||||
'title' => __( 'Subscriptions Mode', 'woocommerce-paypal-payments' ),
|
||||
'type' => 'select',
|
||||
'class' => array(),
|
||||
'input_class' => array( 'wc-enhanced-select' ),
|
||||
'desc_tip' => true,
|
||||
'description' => __( 'Utilize PayPal Vaulting for flexible subscription processing with saved payment methods, create “PayPal Subscriptions” to bill customers at regular intervals, or disable PayPal for subscription-type products.', 'woocommerce-paypal-payments' ),
|
||||
'default' => 'vaulting_api',
|
||||
'options' => array(
|
||||
'vaulting_api' => __( 'PayPal Vaulting', 'woocommerce-paypal-payments' ),
|
||||
'subscriptions_api' => __( 'PayPal Subscriptions', 'woocommerce-paypal-payments' ),
|
||||
'disable_paypal_subscriptions' => __( 'Disable PayPal for subscriptions', 'woocommerce-paypal-payments' ),
|
||||
),
|
||||
'screens' => array(
|
||||
State::STATE_ONBOARDED,
|
||||
),
|
||||
'requirements' => array(),
|
||||
'gateway' => 'paypal',
|
||||
),
|
||||
'subscriptions_mode' => $container->get( 'wcgateway.settings.fields.subscriptions_mode' ),
|
||||
'vault_enabled' => array(
|
||||
'title' => __( 'Vaulting', 'woocommerce-paypal-payments' ),
|
||||
'type' => 'checkbox',
|
||||
|
@ -872,7 +876,6 @@ return array(
|
|||
$billing_agreements_endpoint = $container->get( 'api.endpoint.billing-agreements' );
|
||||
if ( ! $billing_agreements_endpoint->reference_transaction_enabled() ) {
|
||||
unset( $fields['vault_enabled'] );
|
||||
unset( $fields['vault_enabled_dcc'] );
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -976,6 +979,15 @@ return array(
|
|||
return 'https://www.paypal.com/cgi-bin/webscr?cmd=_view-a-trans&id=%s';
|
||||
},
|
||||
|
||||
'wcgateway.soft-descriptor' => static function ( ContainerInterface $container ): string {
|
||||
$settings = $container->get( 'wcgateway.settings' );
|
||||
assert( $settings instanceof Settings );
|
||||
if ( $settings->has( 'soft_descriptor' ) ) {
|
||||
return $settings->get( 'soft_descriptor' );
|
||||
}
|
||||
return '';
|
||||
},
|
||||
|
||||
'wcgateway.transaction-url-provider' => static function ( ContainerInterface $container ): TransactionUrlProvider {
|
||||
$sandbox_url_base = $container->get( 'wcgateway.transaction-url-sandbox' );
|
||||
$live_url_base = $container->get( 'wcgateway.transaction-url-live' );
|
||||
|
|
|
@ -226,6 +226,7 @@ class PayPalGateway extends \WC_Payment_Gateway {
|
|||
|
||||
if (
|
||||
( $this->config->has( 'vault_enabled' ) && $this->config->get( 'vault_enabled' ) )
|
||||
|| ( $this->config->has( 'vault_enabled_dcc' ) && $this->config->get( 'vault_enabled_dcc' ) )
|
||||
|| ( $this->config->has( 'subscriptions_mode' ) && $this->config->get( 'subscriptions_mode' ) === 'subscriptions_api' )
|
||||
) {
|
||||
array_push(
|
||||
|
|
|
@ -245,32 +245,40 @@ return function ( ContainerInterface $container, array $fields ): array {
|
|||
'gateway' => Settings::CONNECTION_TAB_ID,
|
||||
),
|
||||
'merchant_id_production' => array(
|
||||
'title' => __( 'Live Merchant Id', 'woocommerce-paypal-payments' ),
|
||||
'classes' => array( State::STATE_ONBOARDED === $state->production_state() ? 'onboarded' : '', 'ppcp-always-shown-element' ),
|
||||
'type' => 'ppcp-text-input',
|
||||
'desc_tip' => true,
|
||||
'description' => __( 'The merchant id of your account ', 'woocommerce-paypal-payments' ),
|
||||
'default' => false,
|
||||
'screens' => array(
|
||||
'title' => __( 'Live Merchant Id', 'woocommerce-paypal-payments' ),
|
||||
'classes' => array( State::STATE_ONBOARDED === $state->production_state() ? 'onboarded' : '', 'ppcp-always-shown-element' ),
|
||||
'type' => 'text',
|
||||
'desc_tip' => true,
|
||||
'description' => __( 'The merchant id of your account. Should be exactly 13 alphanumeric uppercase letters.', 'woocommerce-paypal-payments' ),
|
||||
'maxlength' => 13,
|
||||
'custom_attributes' => array(
|
||||
'pattern' => '[A-Z0-9]{13}',
|
||||
'autocomplete' => 'off',
|
||||
),
|
||||
'default' => false,
|
||||
'screens' => array(
|
||||
State::STATE_START,
|
||||
State::STATE_ONBOARDED,
|
||||
),
|
||||
'requirements' => array(),
|
||||
'gateway' => Settings::CONNECTION_TAB_ID,
|
||||
'requirements' => array(),
|
||||
'gateway' => Settings::CONNECTION_TAB_ID,
|
||||
),
|
||||
'client_id_production' => array(
|
||||
'title' => __( 'Live Client Id', 'woocommerce-paypal-payments' ),
|
||||
'classes' => array( State::STATE_ONBOARDED === $state->production_state() ? 'onboarded' : '', 'ppcp-always-shown-element' ),
|
||||
'type' => 'ppcp-text-input',
|
||||
'desc_tip' => true,
|
||||
'description' => __( 'The client id of your api ', 'woocommerce-paypal-payments' ),
|
||||
'default' => false,
|
||||
'screens' => array(
|
||||
'title' => __( 'Live Client Id', 'woocommerce-paypal-payments' ),
|
||||
'classes' => array( State::STATE_ONBOARDED === $state->production_state() ? 'onboarded' : '', 'ppcp-always-shown-element' ),
|
||||
'type' => 'text',
|
||||
'desc_tip' => true,
|
||||
'description' => __( 'The client id of your api ', 'woocommerce-paypal-payments' ),
|
||||
'custom_attributes' => array(
|
||||
'autocomplete' => 'off',
|
||||
),
|
||||
'default' => false,
|
||||
'screens' => array(
|
||||
State::STATE_START,
|
||||
State::STATE_ONBOARDED,
|
||||
),
|
||||
'requirements' => array(),
|
||||
'gateway' => Settings::CONNECTION_TAB_ID,
|
||||
'requirements' => array(),
|
||||
'gateway' => Settings::CONNECTION_TAB_ID,
|
||||
),
|
||||
'client_secret_production' => array(
|
||||
'title' => __( 'Live Secret Key', 'woocommerce-paypal-payments' ),
|
||||
|
@ -303,32 +311,40 @@ return function ( ContainerInterface $container, array $fields ): array {
|
|||
'gateway' => Settings::CONNECTION_TAB_ID,
|
||||
),
|
||||
'merchant_id_sandbox' => array(
|
||||
'title' => __( 'Sandbox Merchant Id', 'woocommerce-paypal-payments' ),
|
||||
'classes' => array( State::STATE_ONBOARDED === $state->sandbox_state() ? 'onboarded' : '', 'ppcp-always-shown-element' ),
|
||||
'type' => 'ppcp-text-input',
|
||||
'desc_tip' => true,
|
||||
'description' => __( 'The merchant id of your account ', 'woocommerce-paypal-payments' ),
|
||||
'default' => false,
|
||||
'screens' => array(
|
||||
'title' => __( 'Sandbox Merchant Id', 'woocommerce-paypal-payments' ),
|
||||
'classes' => array( State::STATE_ONBOARDED === $state->sandbox_state() ? 'onboarded' : '', 'ppcp-always-shown-element' ),
|
||||
'type' => 'text',
|
||||
'desc_tip' => true,
|
||||
'description' => __( 'The merchant id of your account. Should be exactly 13 alphanumeric uppercase letters.', 'woocommerce-paypal-payments' ),
|
||||
'maxlength' => 13,
|
||||
'custom_attributes' => array(
|
||||
'pattern' => '[A-Z0-9]{13}',
|
||||
'autocomplete' => 'off',
|
||||
),
|
||||
'default' => false,
|
||||
'screens' => array(
|
||||
State::STATE_START,
|
||||
State::STATE_ONBOARDED,
|
||||
),
|
||||
'requirements' => array(),
|
||||
'gateway' => Settings::CONNECTION_TAB_ID,
|
||||
'requirements' => array(),
|
||||
'gateway' => Settings::CONNECTION_TAB_ID,
|
||||
),
|
||||
'client_id_sandbox' => array(
|
||||
'title' => __( 'Sandbox Client Id', 'woocommerce-paypal-payments' ),
|
||||
'classes' => array( State::STATE_ONBOARDED === $state->sandbox_state() ? 'onboarded' : '', 'ppcp-always-shown-element' ),
|
||||
'type' => 'ppcp-text-input',
|
||||
'desc_tip' => true,
|
||||
'description' => __( 'The client id of your api ', 'woocommerce-paypal-payments' ),
|
||||
'default' => false,
|
||||
'screens' => array(
|
||||
'title' => __( 'Sandbox Client Id', 'woocommerce-paypal-payments' ),
|
||||
'classes' => array( State::STATE_ONBOARDED === $state->sandbox_state() ? 'onboarded' : '', 'ppcp-always-shown-element' ),
|
||||
'type' => 'text',
|
||||
'desc_tip' => true,
|
||||
'description' => __( 'The client id of your api ', 'woocommerce-paypal-payments' ),
|
||||
'custom_attributes' => array(
|
||||
'autocomplete' => 'off',
|
||||
),
|
||||
'default' => false,
|
||||
'screens' => array(
|
||||
State::STATE_START,
|
||||
State::STATE_ONBOARDED,
|
||||
),
|
||||
'requirements' => array(),
|
||||
'gateway' => Settings::CONNECTION_TAB_ID,
|
||||
'requirements' => array(),
|
||||
'gateway' => Settings::CONNECTION_TAB_ID,
|
||||
),
|
||||
'client_secret_sandbox' => array(
|
||||
'title' => __( 'Sandbox Secret Key', 'woocommerce-paypal-payments' ),
|
||||
|
@ -423,6 +439,20 @@ return function ( ContainerInterface $container, array $fields ): array {
|
|||
'</a>'
|
||||
),
|
||||
),
|
||||
'soft_descriptor' => array(
|
||||
'title' => __( 'Soft Descriptor', 'woocommerce-paypal-payments' ),
|
||||
'type' => 'text',
|
||||
'desc_tip' => true,
|
||||
'description' => __( 'The soft descriptor is the dynamic text used to construct the statement descriptor that appears on a payer\'s card statement. Text field, max value of 22 characters.', 'woocommerce-paypal-payments' ),
|
||||
'maxlength' => 22,
|
||||
'default' => '',
|
||||
'screens' => array(
|
||||
State::STATE_START,
|
||||
State::STATE_ONBOARDED,
|
||||
),
|
||||
'requirements' => array(),
|
||||
'gateway' => Settings::CONNECTION_TAB_ID,
|
||||
),
|
||||
'prefix' => array(
|
||||
'title' => __( 'Invoice prefix', 'woocommerce-paypal-payments' ),
|
||||
'type' => 'text',
|
||||
|
|
|
@ -478,7 +478,6 @@ class SettingsListener {
|
|||
break;
|
||||
case 'text':
|
||||
case 'number':
|
||||
case 'ppcp-text-input':
|
||||
$settings[ $key ] = isset( $raw_data[ $key ] ) ? wp_kses_post( $raw_data[ $key ] ) : '';
|
||||
break;
|
||||
case 'ppcp-password':
|
||||
|
|
|
@ -243,39 +243,6 @@ class SettingsRenderer {
|
|||
return $html;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Renders the text input field.
|
||||
*
|
||||
* @param string $field The current field HTML.
|
||||
* @param string $key The current key.
|
||||
* @param array $config The configuration array.
|
||||
* @param string $value The current value.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function render_text_input( $field, $key, $config, $value ): string {
|
||||
|
||||
if ( 'ppcp-text-input' !== $config['type'] ) {
|
||||
return $field;
|
||||
}
|
||||
|
||||
$html = sprintf(
|
||||
'<input
|
||||
type="text"
|
||||
autocomplete="off"
|
||||
class="%s"
|
||||
name="%s"
|
||||
value="%s"
|
||||
>',
|
||||
esc_attr( implode( ' ', $config['class'] ) ),
|
||||
esc_attr( $key ),
|
||||
esc_attr( $value )
|
||||
);
|
||||
|
||||
return $html;
|
||||
}
|
||||
|
||||
/**
|
||||
* Renders the heading field.
|
||||
*
|
||||
|
|
|
@ -528,7 +528,6 @@ class WCGatewayModule implements ModuleInterface {
|
|||
*/
|
||||
$field = $renderer->render_multiselect( $field, $key, $args, $value );
|
||||
$field = $renderer->render_password( $field, $key, $args, $value );
|
||||
$field = $renderer->render_text_input( $field, $key, $args, $value );
|
||||
$field = $renderer->render_heading( $field, $key, $args, $value );
|
||||
$field = $renderer->render_table( $field, $key, $args, $value );
|
||||
return $field;
|
||||
|
|
|
@ -81,7 +81,7 @@ Follow the steps below to connect the plugin to your PayPal account:
|
|||
|
||||
== Changelog ==
|
||||
|
||||
= 2.2.0 - TBD =
|
||||
= 2.2.0 - 2023-07-17 =
|
||||
* Fix - Improve handling of APM payments when buyer did not return to Checkout #1233
|
||||
* Fix - Use order currency instead of shop currency on order-pay page #1363
|
||||
* Fix - Do not show broken card button gateway when no checkout location #1358
|
||||
|
@ -92,6 +92,7 @@ Follow the steps below to connect the plugin to your PayPal account:
|
|||
* Fix - Incompatibility with WooCommerce One Page Checkout (or similar use cases) in Version 2.1.0 #1473
|
||||
* Fix - Prevent Repetitive Token Migration and Database Overload After 2.1.0 Update #1461
|
||||
* Fix - Onboarding from connection page with CSRF parameter manipulates email and merchant id fields #1502
|
||||
* Fix - Do not complete non-checkout button orders via webhooks #1513
|
||||
* Enhancement - Remove feature flag requirement for express cart/checkout block integration #1483
|
||||
* Enhancement - Add notice when shop currency is unsupported #1433
|
||||
* Enhancement - Improve ACDC error message when empty fields #1360
|
||||
|
|
|
@ -26,13 +26,8 @@ class ChangeCartEndpointTest extends TestCase
|
|||
->once()
|
||||
->with($singleProductArray['id'])
|
||||
->andReturn($products[$productKey]);
|
||||
if (! $singleProductArray['__test_data_is_variation']) {
|
||||
$cart
|
||||
->expects('add_to_cart')
|
||||
->with($singleProductArray['id'], $singleProductArray['quantity'])
|
||||
->andReturnTrue();
|
||||
}
|
||||
if ($singleProductArray['__test_data_is_variation']) {
|
||||
|
||||
if ($singleProductArray['__test_data_is_variation'] ?? false) {
|
||||
$dataStore
|
||||
->expects('find_matching_product_variation')
|
||||
->with($products[$productKey], $singleProductArray['__test_data_variation_map'])
|
||||
|
@ -47,7 +42,34 @@ class ChangeCartEndpointTest extends TestCase
|
|||
)
|
||||
->andReturnTrue();
|
||||
}
|
||||
}
|
||||
elseif ($singleProductArray['__test_data_is_booking'] ?? false) {
|
||||
|
||||
$processedBooking = array();
|
||||
foreach ($singleProductArray['booking'] as $key => $value) {
|
||||
$processedBooking['_processed_' . $key] = $value;
|
||||
}
|
||||
|
||||
expect('wc_bookings_get_posted_data')
|
||||
->with($singleProductArray['booking'])
|
||||
->andReturn($processedBooking);
|
||||
$cart
|
||||
->expects('add_to_cart')
|
||||
->with(
|
||||
$singleProductArray['id'],
|
||||
$singleProductArray['quantity'],
|
||||
0,
|
||||
array(),
|
||||
array('booking' => $processedBooking)
|
||||
)
|
||||
->andReturnTrue();
|
||||
}
|
||||
else {
|
||||
$cart
|
||||
->expects('add_to_cart')
|
||||
->with($singleProductArray['id'], $singleProductArray['quantity'])
|
||||
->andReturnTrue();
|
||||
}
|
||||
}
|
||||
$cart
|
||||
->expects('empty_cart')
|
||||
->with(false);
|
||||
|
@ -88,6 +110,10 @@ class ChangeCartEndpointTest extends TestCase
|
|||
$defaultProduct
|
||||
->shouldReceive('get_id')
|
||||
->andReturn(1);
|
||||
$defaultProduct
|
||||
->shouldReceive('is_type')
|
||||
->with('booking')
|
||||
->andReturn(false);
|
||||
$defaultProduct
|
||||
->shouldReceive('is_type')
|
||||
->with('variable')
|
||||
|
@ -97,19 +123,42 @@ class ChangeCartEndpointTest extends TestCase
|
|||
$variationProduct
|
||||
->shouldReceive('get_id')
|
||||
->andReturn(2);
|
||||
$variationProduct
|
||||
->shouldReceive('is_type')
|
||||
->with('booking')
|
||||
->andReturn(false);
|
||||
$variationProduct
|
||||
->shouldReceive('is_type')
|
||||
->with('variable')
|
||||
->andReturn(true);
|
||||
|
||||
$testData = [
|
||||
$bookingData = [
|
||||
'_duration' => 2,
|
||||
'_start_day' => 12,
|
||||
'_start_month' => 6,
|
||||
'_start_year' => 2023,
|
||||
];
|
||||
|
||||
$bookingProduct = Mockery::mock(\WC_Product::class);
|
||||
$bookingProduct
|
||||
->shouldReceive('get_id')
|
||||
->andReturn(3);
|
||||
$bookingProduct
|
||||
->shouldReceive('is_type')
|
||||
->with('booking')
|
||||
->andReturn(true);
|
||||
$bookingProduct
|
||||
->shouldReceive('is_type')
|
||||
->with('variable')
|
||||
->andReturn(false);
|
||||
|
||||
$testData = [
|
||||
'default' => [
|
||||
[
|
||||
'products' => [
|
||||
[
|
||||
'quantity' => 2,
|
||||
'id' => 1,
|
||||
'__test_data_is_variation' => false,
|
||||
],
|
||||
]
|
||||
],
|
||||
|
@ -121,43 +170,65 @@ class ChangeCartEndpointTest extends TestCase
|
|||
]
|
||||
],
|
||||
'variation' => [
|
||||
[
|
||||
'products' => [
|
||||
[
|
||||
'quantity' => 2,
|
||||
'id' => 1,
|
||||
'__test_data_is_variation' => false,
|
||||
],
|
||||
[
|
||||
'quantity' => 2,
|
||||
'id' => 2,
|
||||
'variations' => [
|
||||
[
|
||||
'name' => 'variation-1',
|
||||
'value' => 'abc',
|
||||
],
|
||||
[
|
||||
'name' => 'variation-2',
|
||||
'value' => 'def',
|
||||
],
|
||||
],
|
||||
'__test_data_is_variation' => true,
|
||||
'__test_data_variation_id' => 123,
|
||||
'__test_data_variation_map' => [
|
||||
'variation-1' => 'abc',
|
||||
'variation-2' => 'def',
|
||||
]
|
||||
],
|
||||
]
|
||||
],
|
||||
[
|
||||
$defaultProduct,
|
||||
$variationProduct,
|
||||
],
|
||||
[
|
||||
[1, 2]
|
||||
]
|
||||
]
|
||||
[
|
||||
'products' => [
|
||||
[
|
||||
'quantity' => 2,
|
||||
'id' => 1,
|
||||
],
|
||||
[
|
||||
'quantity' => 2,
|
||||
'id' => 2,
|
||||
'variations' => [
|
||||
[
|
||||
'name' => 'variation-1',
|
||||
'value' => 'abc',
|
||||
],
|
||||
[
|
||||
'name' => 'variation-2',
|
||||
'value' => 'def',
|
||||
],
|
||||
],
|
||||
'__test_data_is_variation' => true,
|
||||
'__test_data_variation_id' => 123,
|
||||
'__test_data_variation_map' => [
|
||||
'variation-1' => 'abc',
|
||||
'variation-2' => 'def',
|
||||
]
|
||||
],
|
||||
]
|
||||
],
|
||||
[
|
||||
$defaultProduct,
|
||||
$variationProduct,
|
||||
],
|
||||
[
|
||||
[1, 2]
|
||||
]
|
||||
],
|
||||
'booking' => [
|
||||
[
|
||||
'products' => [
|
||||
[
|
||||
'quantity' => 2,
|
||||
'id' => 1,
|
||||
],
|
||||
[
|
||||
'quantity' => 1,
|
||||
'id' => 3,
|
||||
'booking' => $bookingData,
|
||||
'__test_data_is_booking' => true,
|
||||
],
|
||||
]
|
||||
],
|
||||
[
|
||||
$defaultProduct,
|
||||
$bookingProduct,
|
||||
],
|
||||
[
|
||||
[1, 3]
|
||||
]
|
||||
],
|
||||
];
|
||||
|
||||
return $testData;
|
||||
|
|
|
@ -73,6 +73,7 @@ class ApplicationContextRepositoryTest extends TestCase
|
|||
'container' => [
|
||||
'brand_name' => 'Acme corp.',
|
||||
'landing_page' => ApplicationContext::LANDING_PAGE_BILLING,
|
||||
'payee_preferred' => '',
|
||||
],
|
||||
'user_locale' => 'de_DE',
|
||||
'shippingPreference' => ApplicationContext::SHIPPING_PREFERENCE_NO_SHIPPING,
|
||||
|
@ -81,6 +82,7 @@ class ApplicationContextRepositoryTest extends TestCase
|
|||
'brand_name' => 'Acme corp.',
|
||||
'landing_page' => ApplicationContext::LANDING_PAGE_BILLING,
|
||||
'shipping_preference' => ApplicationContext::SHIPPING_PREFERENCE_NO_SHIPPING,
|
||||
'payment_method_preference' => ApplicationContext::PAYMENT_METHOD_UNRESTRICTED,
|
||||
],
|
||||
],
|
||||
];
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue