mirror of
https://github.com/woocommerce/woocommerce-paypal-payments.git
synced 2025-09-01 07:02:48 +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 ***
|
*** 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 - 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 - 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
|
* 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 - 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 - 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 - 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 - Remove feature flag requirement for express cart/checkout block integration #1483
|
||||||
* Enhancement - Add notice when shop currency is unsupported #1433
|
* Enhancement - Add notice when shop currency is unsupported #1433
|
||||||
* Enhancement - Improve ACDC error message when empty fields #1360
|
* Enhancement - Improve ACDC error message when empty fields #1360
|
||||||
|
|
|
@ -298,6 +298,7 @@ return array(
|
||||||
$shipping_factory = $container->get( 'api.factory.shipping' );
|
$shipping_factory = $container->get( 'api.factory.shipping' );
|
||||||
$payments_factory = $container->get( 'api.factory.payments' );
|
$payments_factory = $container->get( 'api.factory.payments' );
|
||||||
$prefix = $container->get( 'api.prefix' );
|
$prefix = $container->get( 'api.prefix' );
|
||||||
|
$soft_descriptor = $container->get( 'wcgateway.soft-descriptor' );
|
||||||
|
|
||||||
return new PurchaseUnitFactory(
|
return new PurchaseUnitFactory(
|
||||||
$amount_factory,
|
$amount_factory,
|
||||||
|
@ -306,7 +307,8 @@ return array(
|
||||||
$item_factory,
|
$item_factory,
|
||||||
$shipping_factory,
|
$shipping_factory,
|
||||||
$payments_factory,
|
$payments_factory,
|
||||||
$prefix
|
$prefix,
|
||||||
|
$soft_descriptor
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
'api.factory.patch-collection-factory' => static function ( ContainerInterface $container ): PatchCollectionFactory {
|
'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\OrderStatus;
|
||||||
use WooCommerce\PayPalCommerce\ApiClient\Entity\PatchCollection;
|
use WooCommerce\PayPalCommerce\ApiClient\Entity\PatchCollection;
|
||||||
use WooCommerce\PayPalCommerce\ApiClient\Entity\Payer;
|
use WooCommerce\PayPalCommerce\ApiClient\Entity\Payer;
|
||||||
use WooCommerce\PayPalCommerce\ApiClient\Entity\PaymentMethod;
|
|
||||||
use WooCommerce\PayPalCommerce\ApiClient\Entity\PaymentToken;
|
use WooCommerce\PayPalCommerce\ApiClient\Entity\PaymentToken;
|
||||||
use WooCommerce\PayPalCommerce\ApiClient\Entity\PurchaseUnit;
|
use WooCommerce\PayPalCommerce\ApiClient\Entity\PurchaseUnit;
|
||||||
use WooCommerce\PayPalCommerce\ApiClient\Exception\PayPalApiException;
|
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\Factory\PatchCollectionFactory;
|
||||||
use WooCommerce\PayPalCommerce\ApiClient\Helper\ErrorResponse;
|
use WooCommerce\PayPalCommerce\ApiClient\Helper\ErrorResponse;
|
||||||
use WooCommerce\PayPalCommerce\ApiClient\Repository\ApplicationContextRepository;
|
use WooCommerce\PayPalCommerce\ApiClient\Repository\ApplicationContextRepository;
|
||||||
use WooCommerce\PayPalCommerce\ApiClient\Repository\PayPalRequestIdRepository;
|
|
||||||
use Psr\Log\LoggerInterface;
|
use Psr\Log\LoggerInterface;
|
||||||
use WooCommerce\PayPalCommerce\Subscription\Helper\SubscriptionHelper;
|
use WooCommerce\PayPalCommerce\Subscription\Helper\SubscriptionHelper;
|
||||||
use WooCommerce\PayPalCommerce\WcGateway\FraudNet\FraudNet;
|
use WooCommerce\PayPalCommerce\WcGateway\FraudNet\FraudNet;
|
||||||
|
@ -176,13 +174,12 @@ class OrderEndpoint {
|
||||||
/**
|
/**
|
||||||
* Creates an order.
|
* Creates an order.
|
||||||
*
|
*
|
||||||
* @param PurchaseUnit[] $items The purchase unit items for the order.
|
* @param PurchaseUnit[] $items The purchase unit items for the order.
|
||||||
* @param string $shipping_preference One of ApplicationContext::SHIPPING_PREFERENCE_ values.
|
* @param string $shipping_preference One of ApplicationContext::SHIPPING_PREFERENCE_ values.
|
||||||
* @param Payer|null $payer The payer off the order.
|
* @param Payer|null $payer The payer off the order.
|
||||||
* @param PaymentToken|null $payment_token The payment token.
|
* @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 $paypal_request_id The paypal request id.
|
* @param string $user_action The user action.
|
||||||
* @param string $user_action The user action.
|
|
||||||
*
|
*
|
||||||
* @return Order
|
* @return Order
|
||||||
* @throws RuntimeException If the request fails.
|
* @throws RuntimeException If the request fails.
|
||||||
|
@ -192,7 +189,6 @@ class OrderEndpoint {
|
||||||
string $shipping_preference,
|
string $shipping_preference,
|
||||||
Payer $payer = null,
|
Payer $payer = null,
|
||||||
PaymentToken $payment_token = null,
|
PaymentToken $payment_token = null,
|
||||||
PaymentMethod $payment_method = null,
|
|
||||||
string $paypal_request_id = '',
|
string $paypal_request_id = '',
|
||||||
string $user_action = ApplicationContext::USER_ACTION_CONTINUE
|
string $user_action = ApplicationContext::USER_ACTION_CONTINUE
|
||||||
): Order {
|
): Order {
|
||||||
|
@ -221,9 +217,6 @@ class OrderEndpoint {
|
||||||
if ( $payment_token ) {
|
if ( $payment_token ) {
|
||||||
$data['payment_source']['token'] = $payment_token->to_array();
|
$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.
|
* The filter can be used to modify the order creation request body data.
|
||||||
|
|
|
@ -41,6 +41,9 @@ class ApplicationContext {
|
||||||
self::USER_ACTION_PAY_NOW,
|
self::USER_ACTION_PAY_NOW,
|
||||||
);
|
);
|
||||||
|
|
||||||
|
const PAYMENT_METHOD_UNRESTRICTED = 'UNRESTRICTED';
|
||||||
|
const PAYMENT_METHOD_IMMEDIATE_PAYMENT_REQUIRED = 'IMMEDIATE_PAYMENT_REQUIRED';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The brand name.
|
* The brand name.
|
||||||
*
|
*
|
||||||
|
@ -91,11 +94,11 @@ class ApplicationContext {
|
||||||
private $cancel_url;
|
private $cancel_url;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The payment method.
|
* The payment method preference.
|
||||||
*
|
*
|
||||||
* @var null
|
* @var string
|
||||||
*/
|
*/
|
||||||
private $payment_method;
|
private $payment_method_preference;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* ApplicationContext constructor.
|
* ApplicationContext constructor.
|
||||||
|
@ -107,6 +110,7 @@ class ApplicationContext {
|
||||||
* @param string $landing_page The landing page.
|
* @param string $landing_page The landing page.
|
||||||
* @param string $shipping_preference The shipping preference.
|
* @param string $shipping_preference The shipping preference.
|
||||||
* @param string $user_action The user action.
|
* @param string $user_action The user action.
|
||||||
|
* @param string $payment_method_preference The payment method preference.
|
||||||
*
|
*
|
||||||
* @throws RuntimeException When values are not valid.
|
* @throws RuntimeException When values are not valid.
|
||||||
*/
|
*/
|
||||||
|
@ -117,7 +121,8 @@ class ApplicationContext {
|
||||||
string $locale = '',
|
string $locale = '',
|
||||||
string $landing_page = self::LANDING_PAGE_NO_PREFERENCE,
|
string $landing_page = self::LANDING_PAGE_NO_PREFERENCE,
|
||||||
string $shipping_preference = self::SHIPPING_PREFERENCE_NO_SHIPPING,
|
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 ) ) {
|
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 ) ) {
|
if ( ! in_array( $user_action, self::VALID_USER_ACTION_VALUES, true ) ) {
|
||||||
throw new RuntimeException( 'User action preference not correct' );
|
throw new RuntimeException( 'User action preference not correct' );
|
||||||
}
|
}
|
||||||
$this->return_url = $return_url;
|
$this->return_url = $return_url;
|
||||||
$this->cancel_url = $cancel_url;
|
$this->cancel_url = $cancel_url;
|
||||||
$this->brand_name = $brand_name;
|
$this->brand_name = $brand_name;
|
||||||
$this->locale = $locale;
|
$this->locale = $locale;
|
||||||
$this->landing_page = $landing_page;
|
$this->landing_page = $landing_page;
|
||||||
$this->shipping_preference = $shipping_preference;
|
$this->shipping_preference = $shipping_preference;
|
||||||
$this->user_action = $user_action;
|
$this->user_action = $user_action;
|
||||||
|
$this->payment_method_preference = $payment_method_preference;
|
||||||
// Currently we have not implemented the payment method.
|
|
||||||
$this->payment_method = null;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -205,12 +208,10 @@ class ApplicationContext {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the payment method.
|
* Returns the payment method preference.
|
||||||
*
|
|
||||||
* @return PaymentMethod|null
|
|
||||||
*/
|
*/
|
||||||
public function payment_method() {
|
public function payment_method_preference(): string {
|
||||||
return $this->payment_method;
|
return $this->payment_method_preference;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -223,9 +224,6 @@ class ApplicationContext {
|
||||||
if ( $this->user_action() ) {
|
if ( $this->user_action() ) {
|
||||||
$data['user_action'] = $this->user_action();
|
$data['user_action'] = $this->user_action();
|
||||||
}
|
}
|
||||||
if ( $this->payment_method() ) {
|
|
||||||
$data['payment_method'] = $this->payment_method();
|
|
||||||
}
|
|
||||||
if ( $this->shipping_preference() ) {
|
if ( $this->shipping_preference() ) {
|
||||||
$data['shipping_preference'] = $this->shipping_preference();
|
$data['shipping_preference'] = $this->shipping_preference();
|
||||||
}
|
}
|
||||||
|
@ -244,6 +242,11 @@ class ApplicationContext {
|
||||||
if ( $this->cancel_url() ) {
|
if ( $this->cancel_url() ) {
|
||||||
$data['cancel_url'] = $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;
|
return $data;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -73,6 +73,13 @@ class Item {
|
||||||
*/
|
*/
|
||||||
protected $tax_rate;
|
protected $tax_rate;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The cart item key.
|
||||||
|
*
|
||||||
|
* @var string|null
|
||||||
|
*/
|
||||||
|
protected $cart_item_key;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Item constructor.
|
* Item constructor.
|
||||||
*
|
*
|
||||||
|
@ -84,6 +91,7 @@ class Item {
|
||||||
* @param string $sku The SKU.
|
* @param string $sku The SKU.
|
||||||
* @param string $category The category.
|
* @param string $category The category.
|
||||||
* @param float $tax_rate The tax rate.
|
* @param float $tax_rate The tax rate.
|
||||||
|
* @param ?string $cart_item_key The cart key for this item.
|
||||||
*/
|
*/
|
||||||
public function __construct(
|
public function __construct(
|
||||||
string $name,
|
string $name,
|
||||||
|
@ -93,18 +101,20 @@ class Item {
|
||||||
Money $tax = null,
|
Money $tax = null,
|
||||||
string $sku = '',
|
string $sku = '',
|
||||||
string $category = 'PHYSICAL_GOODS',
|
string $category = 'PHYSICAL_GOODS',
|
||||||
float $tax_rate = 0
|
float $tax_rate = 0,
|
||||||
|
string $cart_item_key = null
|
||||||
) {
|
) {
|
||||||
|
|
||||||
$this->name = $name;
|
$this->name = $name;
|
||||||
$this->unit_amount = $unit_amount;
|
$this->unit_amount = $unit_amount;
|
||||||
$this->quantity = $quantity;
|
$this->quantity = $quantity;
|
||||||
$this->description = $description;
|
$this->description = $description;
|
||||||
$this->tax = $tax;
|
$this->tax = $tax;
|
||||||
$this->sku = $sku;
|
$this->sku = $sku;
|
||||||
$this->category = ( self::DIGITAL_GOODS === $category ) ? self::DIGITAL_GOODS : self::PHYSICAL_GOODS;
|
$this->category = ( self::DIGITAL_GOODS === $category ) ? self::DIGITAL_GOODS : self::PHYSICAL_GOODS;
|
||||||
$this->category = $category;
|
$this->category = $category;
|
||||||
$this->tax_rate = $tax_rate;
|
$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 );
|
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.
|
* Returns the object as array.
|
||||||
*
|
*
|
||||||
|
@ -202,6 +221,10 @@ class Item {
|
||||||
$item['tax_rate'] = (string) $this->tax_rate();
|
$item['tax_rate'] = (string) $this->tax_rate();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if ( $this->cart_item_key() ) {
|
||||||
|
$item['cart_item_key'] = (string) $this->cart_item_key();
|
||||||
|
}
|
||||||
|
|
||||||
return $item;
|
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;
|
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.
|
* Returns the invoice id.
|
||||||
*
|
*
|
||||||
|
|
|
@ -44,7 +44,8 @@ class ItemFactory {
|
||||||
public function from_wc_cart( \WC_Cart $cart ): array {
|
public function from_wc_cart( \WC_Cart $cart ): array {
|
||||||
$items = array_map(
|
$items = array_map(
|
||||||
function ( array $item ): Item {
|
function ( array $item ): Item {
|
||||||
$product = $item['data'];
|
$product = $item['data'];
|
||||||
|
$cart_item_key = $item['key'] ?? null;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The WooCommerce product.
|
* The WooCommerce product.
|
||||||
|
@ -61,7 +62,9 @@ class ItemFactory {
|
||||||
$this->prepare_description( $product->get_description() ),
|
$this->prepare_description( $product->get_description() ),
|
||||||
null,
|
null,
|
||||||
$product->get_sku(),
|
$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()
|
$cart->get_cart_contents()
|
||||||
|
|
|
@ -70,6 +70,13 @@ class PurchaseUnitFactory {
|
||||||
*/
|
*/
|
||||||
private $prefix;
|
private $prefix;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The Soft Descriptor.
|
||||||
|
*
|
||||||
|
* @var string
|
||||||
|
*/
|
||||||
|
private $soft_descriptor;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* PurchaseUnitFactory constructor.
|
* PurchaseUnitFactory constructor.
|
||||||
*
|
*
|
||||||
|
@ -80,6 +87,7 @@ class PurchaseUnitFactory {
|
||||||
* @param ShippingFactory $shipping_factory The shipping factory.
|
* @param ShippingFactory $shipping_factory The shipping factory.
|
||||||
* @param PaymentsFactory $payments_factory The payments factory.
|
* @param PaymentsFactory $payments_factory The payments factory.
|
||||||
* @param string $prefix The prefix.
|
* @param string $prefix The prefix.
|
||||||
|
* @param string $soft_descriptor The soft descriptor.
|
||||||
*/
|
*/
|
||||||
public function __construct(
|
public function __construct(
|
||||||
AmountFactory $amount_factory,
|
AmountFactory $amount_factory,
|
||||||
|
@ -88,7 +96,8 @@ class PurchaseUnitFactory {
|
||||||
ItemFactory $item_factory,
|
ItemFactory $item_factory,
|
||||||
ShippingFactory $shipping_factory,
|
ShippingFactory $shipping_factory,
|
||||||
PaymentsFactory $payments_factory,
|
PaymentsFactory $payments_factory,
|
||||||
string $prefix = 'WC-'
|
string $prefix = 'WC-',
|
||||||
|
string $soft_descriptor = ''
|
||||||
) {
|
) {
|
||||||
|
|
||||||
$this->amount_factory = $amount_factory;
|
$this->amount_factory = $amount_factory;
|
||||||
|
@ -98,6 +107,7 @@ class PurchaseUnitFactory {
|
||||||
$this->shipping_factory = $shipping_factory;
|
$this->shipping_factory = $shipping_factory;
|
||||||
$this->payments_factory = $payments_factory;
|
$this->payments_factory = $payments_factory;
|
||||||
$this->prefix = $prefix;
|
$this->prefix = $prefix;
|
||||||
|
$this->soft_descriptor = $soft_descriptor;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -128,7 +138,7 @@ class PurchaseUnitFactory {
|
||||||
$payee = $this->payee_repository->payee();
|
$payee = $this->payee_repository->payee();
|
||||||
$custom_id = (string) $order->get_id();
|
$custom_id = (string) $order->get_id();
|
||||||
$invoice_id = $this->prefix . $order->get_order_number();
|
$invoice_id = $this->prefix . $order->get_order_number();
|
||||||
$soft_descriptor = '';
|
$soft_descriptor = $this->soft_descriptor;
|
||||||
|
|
||||||
$purchase_unit = new PurchaseUnit(
|
$purchase_unit = new PurchaseUnit(
|
||||||
$amount,
|
$amount,
|
||||||
|
@ -198,7 +208,7 @@ class PurchaseUnitFactory {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
$invoice_id = '';
|
$invoice_id = '';
|
||||||
$soft_descriptor = '';
|
$soft_descriptor = $this->soft_descriptor;
|
||||||
$purchase_unit = new PurchaseUnit(
|
$purchase_unit = new PurchaseUnit(
|
||||||
$amount,
|
$amount,
|
||||||
$items,
|
$items,
|
||||||
|
@ -233,7 +243,7 @@ class PurchaseUnitFactory {
|
||||||
$description = ( isset( $data->description ) ) ? $data->description : '';
|
$description = ( isset( $data->description ) ) ? $data->description : '';
|
||||||
$custom_id = ( isset( $data->custom_id ) ) ? $data->custom_id : '';
|
$custom_id = ( isset( $data->custom_id ) ) ? $data->custom_id : '';
|
||||||
$invoice_id = ( isset( $data->invoice_id ) ) ? $data->invoice_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();
|
$items = array();
|
||||||
if ( isset( $data->items ) && is_array( $data->items ) ) {
|
if ( isset( $data->items ) && is_array( $data->items ) ) {
|
||||||
$items = array_map(
|
$items = array_map(
|
||||||
|
|
|
@ -47,18 +47,21 @@ class ApplicationContextRepository {
|
||||||
string $user_action = ApplicationContext::USER_ACTION_CONTINUE
|
string $user_action = ApplicationContext::USER_ACTION_CONTINUE
|
||||||
): ApplicationContext {
|
): ApplicationContext {
|
||||||
|
|
||||||
$brand_name = $this->settings->has( 'brand_name' ) ? $this->settings->get( 'brand_name' ) : '';
|
$brand_name = $this->settings->has( 'brand_name' ) ? $this->settings->get( 'brand_name' ) : '';
|
||||||
$locale = $this->valid_bcp47_code();
|
$locale = $this->valid_bcp47_code();
|
||||||
$landingpage = $this->settings->has( 'landing_page' ) ?
|
$landingpage = $this->settings->has( 'landing_page' ) ?
|
||||||
$this->settings->get( 'landing_page' ) : ApplicationContext::LANDING_PAGE_NO_PREFERENCE;
|
$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 ) ),
|
network_home_url( \WC_AJAX::get_endpoint( ReturnUrlEndpoint::ENDPOINT ) ),
|
||||||
(string) wc_get_checkout_url(),
|
(string) wc_get_checkout_url(),
|
||||||
(string) $brand_name,
|
(string) $brand_name,
|
||||||
$locale,
|
$locale,
|
||||||
(string) $landingpage,
|
(string) $landingpage,
|
||||||
$shipping_preferences,
|
$shipping_preferences,
|
||||||
$user_action
|
$user_action,
|
||||||
|
$payment_preference
|
||||||
);
|
);
|
||||||
return $context;
|
return $context;
|
||||||
}
|
}
|
||||||
|
|
|
@ -164,6 +164,7 @@ const bootstrap = () => {
|
||||||
const cartBootstrap = new CartBootstrap(
|
const cartBootstrap = new CartBootstrap(
|
||||||
PayPalCommerceGateway,
|
PayPalCommerceGateway,
|
||||||
renderer,
|
renderer,
|
||||||
|
messageRenderer,
|
||||||
errorHandler,
|
errorHandler,
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
|
@ -50,8 +50,6 @@ class CheckoutActionHandler {
|
||||||
|
|
||||||
const formSelector = this.config.context === 'checkout' ? 'form.checkout' : 'form#order_review';
|
const formSelector = this.config.context === 'checkout' ? 'form.checkout' : 'form#order_review';
|
||||||
const formData = new FormData(document.querySelector(formSelector));
|
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;
|
const createaccount = jQuery('#createaccount').is(":checked") ? true : false;
|
||||||
|
|
||||||
|
@ -72,7 +70,8 @@ class CheckoutActionHandler {
|
||||||
order_id:this.config.order_id,
|
order_id:this.config.order_id,
|
||||||
payment_method: paymentMethod,
|
payment_method: paymentMethod,
|
||||||
funding_source: fundingSource,
|
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
|
createaccount: createaccount
|
||||||
})
|
})
|
||||||
}).then(function (res) {
|
}).then(function (res) {
|
||||||
|
|
|
@ -1,7 +1,10 @@
|
||||||
import Product from '../Entity/Product';
|
import Product from '../Entity/Product';
|
||||||
|
import BookingProduct from "../Entity/BookingProduct";
|
||||||
import onApprove from '../OnApproveHandler/onApproveForContinue';
|
import onApprove from '../OnApproveHandler/onApproveForContinue';
|
||||||
import {payerData} from "../Helper/PayerData";
|
import {payerData} from "../Helper/PayerData";
|
||||||
import {PaymentMethods} from "../Helper/CheckoutMethodState";
|
import {PaymentMethods} from "../Helper/CheckoutMethodState";
|
||||||
|
import CartHelper from "../Helper/CartHelper";
|
||||||
|
import FormHelper from "../Helper/FormHelper";
|
||||||
|
|
||||||
class SingleProductActionHandler {
|
class SingleProductActionHandler {
|
||||||
|
|
||||||
|
@ -15,6 +18,7 @@ class SingleProductActionHandler {
|
||||||
this.updateCart = updateCart;
|
this.updateCart = updateCart;
|
||||||
this.formElement = formElement;
|
this.formElement = formElement;
|
||||||
this.errorHandler = errorHandler;
|
this.errorHandler = errorHandler;
|
||||||
|
this.cartHelper = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
getPlanIdFromVariation = (variation) => {
|
getPlanIdFromVariation = (variation) => {
|
||||||
|
@ -91,43 +95,70 @@ class SingleProductActionHandler {
|
||||||
createOrder: this.createOrder(),
|
createOrder: this.createOrder(),
|
||||||
onApprove: onApprove(this, this.errorHandler),
|
onApprove: onApprove(this, this.errorHandler),
|
||||||
onError: (error) => {
|
onError: (error) => {
|
||||||
|
this.refreshMiniCart();
|
||||||
|
|
||||||
|
if (this.isBookingProduct() && error.message) {
|
||||||
|
this.errorHandler.clear();
|
||||||
|
this.errorHandler.message(error.message);
|
||||||
|
return;
|
||||||
|
}
|
||||||
this.errorHandler.genericError();
|
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()
|
createOrder()
|
||||||
{
|
{
|
||||||
var getProducts = null;
|
this.cartHelper = null;
|
||||||
if (! this.isGroupedProduct() ) {
|
|
||||||
getProducts = () => {
|
let getProducts = (() => {
|
||||||
const id = document.querySelector('[name="add-to-cart"]').value;
|
if ( this.isBookingProduct() ) {
|
||||||
const qty = document.querySelector('[name="quantity"]').value;
|
return () => {
|
||||||
const variations = this.variations();
|
const id = document.querySelector('[name="add-to-cart"]').value;
|
||||||
return [new Product(id, qty, variations)];
|
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 = [];
|
return (data, actions) => {
|
||||||
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) => {
|
|
||||||
this.errorHandler.clear();
|
this.errorHandler.clear();
|
||||||
|
|
||||||
const onResolve = (purchase_units) => {
|
const onResolve = (purchase_units) => {
|
||||||
|
this.cartHelper = (new CartHelper()).addFromPurchaseUnits(purchase_units);
|
||||||
|
|
||||||
const payer = payerData();
|
const payer = payerData();
|
||||||
const bnCode = typeof this.config.bn_codes[this.config.context] !== 'undefined' ?
|
const bnCode = typeof this.config.bn_codes[this.config.context] !== 'undefined' ?
|
||||||
this.config.bn_codes[this.config.context] : '';
|
this.config.bn_codes[this.config.context] : '';
|
||||||
|
@ -157,19 +188,16 @@ class SingleProductActionHandler {
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
const promise = this.updateCart.update(onResolve, getProducts());
|
return this.updateCart.update(onResolve, getProducts());
|
||||||
return promise;
|
|
||||||
};
|
};
|
||||||
return createOrder;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
variations()
|
variations()
|
||||||
{
|
{
|
||||||
|
|
||||||
if (! this.hasVariations()) {
|
if (! this.hasVariations()) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
const attributes = [...this.formElement.querySelectorAll("[name^='attribute_']")].map(
|
return [...this.formElement.querySelectorAll("[name^='attribute_']")].map(
|
||||||
(element) => {
|
(element) => {
|
||||||
return {
|
return {
|
||||||
value:element.value,
|
value:element.value,
|
||||||
|
@ -177,7 +205,6 @@ class SingleProductActionHandler {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
return attributes;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
hasVariations()
|
hasVariations()
|
||||||
|
@ -189,5 +216,24 @@ class SingleProductActionHandler {
|
||||||
{
|
{
|
||||||
return this.formElement.classList.contains('grouped_form');
|
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;
|
export default SingleProductActionHandler;
|
||||||
|
|
|
@ -3,10 +3,12 @@ import BootstrapHelper from "../Helper/BootstrapHelper";
|
||||||
import {setVisible} from "../Helper/Hiding";
|
import {setVisible} from "../Helper/Hiding";
|
||||||
|
|
||||||
class CartBootstrap {
|
class CartBootstrap {
|
||||||
constructor(gateway, renderer, errorHandler) {
|
constructor(gateway, renderer, messages, errorHandler) {
|
||||||
this.gateway = gateway;
|
this.gateway = gateway;
|
||||||
this.renderer = renderer;
|
this.renderer = renderer;
|
||||||
|
this.messages = messages;
|
||||||
this.errorHandler = errorHandler;
|
this.errorHandler = errorHandler;
|
||||||
|
this.lastAmount = this.gateway.messages.amount;
|
||||||
|
|
||||||
this.renderer.onButtonsInit(this.gateway.button.wrapper, () => {
|
this.renderer.onButtonsInit(this.gateway.button.wrapper, () => {
|
||||||
this.handleButtonStatus();
|
this.handleButtonStatus();
|
||||||
|
@ -38,11 +40,16 @@ class CartBootstrap {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const newParams = result.data;
|
const newParams = result.data.url_params;
|
||||||
const reloadRequired = this.gateway.url_params.intent !== newParams.intent;
|
const reloadRequired = this.gateway.url_params.intent !== newParams.intent;
|
||||||
|
|
||||||
// TODO: should reload the script instead
|
// TODO: should reload the script instead
|
||||||
setVisible(this.gateway.button.wrapper, !reloadRequired)
|
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(
|
this.renderer.render(
|
||||||
actionHandler.configuration()
|
actionHandler.configuration()
|
||||||
);
|
);
|
||||||
|
|
||||||
|
this.messages.renderWithAmount(this.lastAmount);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -15,6 +15,7 @@ class CheckoutBootstap {
|
||||||
this.messages = messages;
|
this.messages = messages;
|
||||||
this.spinner = spinner;
|
this.spinner = spinner;
|
||||||
this.errorHandler = errorHandler;
|
this.errorHandler = errorHandler;
|
||||||
|
this.lastAmount = this.gateway.messages.amount;
|
||||||
|
|
||||||
this.standardOrderButtonSelector = ORDER_BUTTON_SELECTOR;
|
this.standardOrderButtonSelector = ORDER_BUTTON_SELECTOR;
|
||||||
|
|
||||||
|
@ -36,6 +37,27 @@ class CheckoutBootstap {
|
||||||
jQuery(document.body).on('updated_checkout', () => {
|
jQuery(document.body).on('updated_checkout', () => {
|
||||||
this.render()
|
this.render()
|
||||||
this.handleButtonStatus();
|
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', () => {
|
jQuery(document.body).on('updated_checkout payment_method_selected', () => {
|
||||||
|
@ -117,8 +139,8 @@ class CheckoutBootstap {
|
||||||
setVisible(wrapper, gatewayId === currentPaymentMethod);
|
setVisible(wrapper, gatewayId === currentPaymentMethod);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (isPaypal && !isFreeTrial) {
|
if (this.shouldRenderMessages()) {
|
||||||
this.messages.render();
|
this.messages.renderWithAmount(this.lastAmount);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (isCard) {
|
if (isCard) {
|
||||||
|
@ -130,6 +152,12 @@ class CheckoutBootstap {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
shouldRenderMessages() {
|
||||||
|
return getCurrentPaymentMethod() === PaymentMethods.PAYPAL
|
||||||
|
&& !PayPalCommerceGateway.is_free_trial_cart
|
||||||
|
&& this.messages.shouldRender();
|
||||||
|
}
|
||||||
|
|
||||||
disableCreditCardFields() {
|
disableCreditCardFields() {
|
||||||
jQuery('label[for="ppcp-credit-card-gateway-card-number"]').addClass('ppcp-credit-card-gateway-form-field-disabled')
|
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')
|
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) {
|
async validate(form) {
|
||||||
const formData = new FormData(form);
|
const formData = new FormData(form);
|
||||||
const formJsonObj = Object.fromEntries(formData.entries());
|
|
||||||
|
|
||||||
const res = await fetch(this.url, {
|
const res = await fetch(this.url, {
|
||||||
method: 'POST',
|
method: 'POST',
|
||||||
|
@ -16,7 +15,7 @@ export default class FormValidator {
|
||||||
credentials: 'same-origin',
|
credentials: 'same-origin',
|
||||||
body: JSON.stringify({
|
body: JSON.stringify({
|
||||||
nonce: this.nonce,
|
nonce: this.nonce,
|
||||||
form: formJsonObj,
|
form_encoded: new URLSearchParams(formData).toString(),
|
||||||
}),
|
}),
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
@ -5,28 +5,6 @@ class MessageRenderer {
|
||||||
this.optionsFingerprint = null;
|
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) {
|
renderWithAmount(amount) {
|
||||||
if (! this.shouldRender()) {
|
if (! this.shouldRender()) {
|
||||||
return;
|
return;
|
||||||
|
|
|
@ -67,7 +67,12 @@ class CartScriptParamsEndpoint implements EndpointInterface {
|
||||||
try {
|
try {
|
||||||
$script_data = $this->smart_button->script_data();
|
$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;
|
return true;
|
||||||
} catch ( Throwable $error ) {
|
} catch ( Throwable $error ) {
|
||||||
|
|
|
@ -153,13 +153,23 @@ class ChangeCartEndpoint implements EndpointInterface {
|
||||||
$this->cart->empty_cart( false );
|
$this->cart->empty_cart( false );
|
||||||
$success = true;
|
$success = true;
|
||||||
foreach ( $products as $product ) {
|
foreach ( $products as $product ) {
|
||||||
$success = $success && ( ! $product['product']->is_type( 'variable' ) ) ?
|
if ( $product['product']->is_type( 'booking' ) ) {
|
||||||
$this->add_product( $product['product'], $product['quantity'] )
|
$success = $success && $this->add_booking_product(
|
||||||
: $this->add_variable_product(
|
$product['product'],
|
||||||
|
$product['booking']
|
||||||
|
);
|
||||||
|
} elseif ( $product['product']->is_type( 'variable' ) ) {
|
||||||
|
$success = $success && $this->add_variable_product(
|
||||||
$product['product'],
|
$product['product'],
|
||||||
$product['quantity'],
|
$product['quantity'],
|
||||||
$product['variations']
|
$product['variations']
|
||||||
);
|
);
|
||||||
|
} else {
|
||||||
|
$success = $success && $this->add_product(
|
||||||
|
$product['product'],
|
||||||
|
$product['quantity']
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if ( ! $success ) {
|
if ( ! $success ) {
|
||||||
$this->handle_error();
|
$this->handle_error();
|
||||||
|
@ -234,7 +244,8 @@ class ChangeCartEndpoint implements EndpointInterface {
|
||||||
$products[] = array(
|
$products[] = array(
|
||||||
'product' => $wc_product,
|
'product' => $wc_product,
|
||||||
'quantity' => (int) $product['quantity'],
|
'quantity' => (int) $product['quantity'],
|
||||||
'variations' => isset( $product['variations'] ) ? $product['variations'] : null,
|
'variations' => $product['variations'] ?? null,
|
||||||
|
'booking' => $product['booking'] ?? null,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
return $products;
|
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.
|
* 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\Money;
|
||||||
use WooCommerce\PayPalCommerce\ApiClient\Entity\Order;
|
use WooCommerce\PayPalCommerce\ApiClient\Entity\Order;
|
||||||
use WooCommerce\PayPalCommerce\ApiClient\Entity\Payer;
|
use WooCommerce\PayPalCommerce\ApiClient\Entity\Payer;
|
||||||
use WooCommerce\PayPalCommerce\ApiClient\Entity\PaymentMethod;
|
|
||||||
use WooCommerce\PayPalCommerce\ApiClient\Entity\PurchaseUnit;
|
use WooCommerce\PayPalCommerce\ApiClient\Entity\PurchaseUnit;
|
||||||
use WooCommerce\PayPalCommerce\ApiClient\Exception\PayPalApiException;
|
use WooCommerce\PayPalCommerce\ApiClient\Exception\PayPalApiException;
|
||||||
use WooCommerce\PayPalCommerce\ApiClient\Exception\RuntimeException;
|
use WooCommerce\PayPalCommerce\ApiClient\Exception\RuntimeException;
|
||||||
|
@ -32,7 +31,6 @@ use WooCommerce\PayPalCommerce\Button\Helper\EarlyOrderHandler;
|
||||||
use WooCommerce\PayPalCommerce\Session\SessionHandler;
|
use WooCommerce\PayPalCommerce\Session\SessionHandler;
|
||||||
use WooCommerce\PayPalCommerce\Subscription\FreeTrialHandlerTrait;
|
use WooCommerce\PayPalCommerce\Subscription\FreeTrialHandlerTrait;
|
||||||
use WooCommerce\PayPalCommerce\WcGateway\CardBillingMode;
|
use WooCommerce\PayPalCommerce\WcGateway\CardBillingMode;
|
||||||
use WooCommerce\PayPalCommerce\WcGateway\Exception\NotFoundException;
|
|
||||||
use WooCommerce\PayPalCommerce\WcGateway\Gateway\CardButtonGateway;
|
use WooCommerce\PayPalCommerce\WcGateway\Gateway\CardButtonGateway;
|
||||||
use WooCommerce\PayPalCommerce\WcGateway\Gateway\CreditCardGateway;
|
use WooCommerce\PayPalCommerce\WcGateway\Gateway\CreditCardGateway;
|
||||||
use WooCommerce\PayPalCommerce\WcGateway\Gateway\PayPalGateway;
|
use WooCommerce\PayPalCommerce\WcGateway\Gateway\PayPalGateway;
|
||||||
|
@ -166,6 +164,13 @@ class CreateOrderEndpoint implements EndpointInterface {
|
||||||
*/
|
*/
|
||||||
protected $logger;
|
protected $logger;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The form data, or empty if not available.
|
||||||
|
*
|
||||||
|
* @var array
|
||||||
|
*/
|
||||||
|
private $form = array();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* CreateOrderEndpoint constructor.
|
* CreateOrderEndpoint constructor.
|
||||||
*
|
*
|
||||||
|
@ -258,6 +263,12 @@ class CreateOrderEndpoint implements EndpointInterface {
|
||||||
} else {
|
} else {
|
||||||
$this->purchase_unit = $this->purchase_unit_factory->from_wc_cart( null, $this->handle_shipping_in_paypal );
|
$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.
|
// The cart does not have any info about payment method, so we must handle free trial here.
|
||||||
if ( (
|
if ( (
|
||||||
in_array( $payment_method, array( CreditCardGateway::ID, CardButtonGateway::ID ), true )
|
in_array( $payment_method, array( CreditCardGateway::ID, CardButtonGateway::ID ), true )
|
||||||
|
@ -276,18 +287,20 @@ class CreateOrderEndpoint implements EndpointInterface {
|
||||||
|
|
||||||
$this->set_bn_code( $data );
|
$this->set_bn_code( $data );
|
||||||
|
|
||||||
$form_fields = $data['form'] ?? null;
|
if ( isset( $data['form'] ) ) {
|
||||||
|
$this->form = $data['form'];
|
||||||
|
}
|
||||||
|
|
||||||
if ( $this->early_validation_enabled
|
if ( $this->early_validation_enabled
|
||||||
&& is_array( $form_fields )
|
&& $this->form
|
||||||
&& 'checkout' === $data['context']
|
&& 'checkout' === $data['context']
|
||||||
&& in_array( $payment_method, array( PayPalGateway::ID, CardButtonGateway::ID ), true )
|
&& 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', '' ) !== '' ) {
|
if ( 'pay-now' === $data['context'] && $this->form && get_option( 'woocommerce_terms_page_id', '' ) !== '' ) {
|
||||||
$this->validate_paynow_form( $form_fields );
|
$this->validate_paynow_form( $this->form );
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
@ -448,7 +461,6 @@ class CreateOrderEndpoint implements EndpointInterface {
|
||||||
$shipping_preference,
|
$shipping_preference,
|
||||||
$payer,
|
$payer,
|
||||||
null,
|
null,
|
||||||
$this->payment_method(),
|
|
||||||
'',
|
'',
|
||||||
$action
|
$action
|
||||||
);
|
);
|
||||||
|
@ -471,8 +483,7 @@ class CreateOrderEndpoint implements EndpointInterface {
|
||||||
array( $this->purchase_unit ),
|
array( $this->purchase_unit ),
|
||||||
$shipping_preference,
|
$shipping_preference,
|
||||||
$payer,
|
$payer,
|
||||||
null,
|
null
|
||||||
$this->payment_method()
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -510,11 +521,9 @@ class CreateOrderEndpoint implements EndpointInterface {
|
||||||
$payer = $this->payer_factory->from_paypal_response( json_decode( wp_json_encode( $data['payer'] ) ) );
|
$payer = $this->payer_factory->from_paypal_response( json_decode( wp_json_encode( $data['payer'] ) ) );
|
||||||
}
|
}
|
||||||
|
|
||||||
if ( ! $payer && isset( $data['form'] ) ) {
|
if ( ! $payer && $this->form ) {
|
||||||
$form_fields = $data['form'];
|
if ( isset( $this->form['billing_email'] ) && '' !== $this->form['billing_email'] ) {
|
||||||
|
return $this->payer_factory->from_checkout_form( $this->form );
|
||||||
if ( is_array( $form_fields ) && isset( $form_fields['billing_email'] ) && '' !== $form_fields['billing_email'] ) {
|
|
||||||
return $this->payer_factory->from_checkout_form( $form_fields );
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -536,24 +545,6 @@ class CreateOrderEndpoint implements EndpointInterface {
|
||||||
$this->api_endpoint->with_bn_code( $bn_code );
|
$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.
|
* Checks whether the form fields are valid.
|
||||||
*
|
*
|
||||||
|
|
|
@ -53,6 +53,11 @@ class RequestData {
|
||||||
}
|
}
|
||||||
$this->dequeue_nonce_fix();
|
$this->dequeue_nonce_fix();
|
||||||
|
|
||||||
|
if ( isset( $json['form_encoded'] ) ) {
|
||||||
|
$json['form'] = array();
|
||||||
|
parse_str( $json['form_encoded'], $json['form'] );
|
||||||
|
}
|
||||||
|
|
||||||
$sanitized = $this->sanitize( $json );
|
$sanitized = $this->sanitize( $json );
|
||||||
return $sanitized;
|
return $sanitized;
|
||||||
}
|
}
|
||||||
|
@ -80,6 +85,10 @@ class RequestData {
|
||||||
private function sanitize( array $assoc_array ): array {
|
private function sanitize( array $assoc_array ): array {
|
||||||
$data = array();
|
$data = array();
|
||||||
foreach ( (array) $assoc_array as $raw_key => $raw_value ) {
|
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 ) ) {
|
if ( ! is_array( $raw_value ) ) {
|
||||||
// Not sure if it is a good idea to sanitize everything at this level,
|
// 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.
|
// 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;
|
namespace WooCommerce\PayPalCommerce\StatusReport;
|
||||||
|
|
||||||
|
use WooCommerce\PayPalCommerce\Subscription\Helper\SubscriptionHelper;
|
||||||
use WooCommerce\PayPalCommerce\Vendor\Dhii\Container\ServiceProvider;
|
use WooCommerce\PayPalCommerce\Vendor\Dhii\Container\ServiceProvider;
|
||||||
use WooCommerce\PayPalCommerce\Vendor\Dhii\Modular\Module\ModuleInterface;
|
use WooCommerce\PayPalCommerce\Vendor\Dhii\Modular\Module\ModuleInterface;
|
||||||
use WooCommerce\PayPalCommerce\Vendor\Interop\Container\ServiceProviderInterface;
|
use WooCommerce\PayPalCommerce\Vendor\Interop\Container\ServiceProviderInterface;
|
||||||
|
@ -49,6 +50,8 @@ class StatusReportModule implements ModuleInterface {
|
||||||
$settings = $c->get( 'wcgateway.settings' );
|
$settings = $c->get( 'wcgateway.settings' );
|
||||||
assert( $settings instanceof ContainerInterface );
|
assert( $settings instanceof ContainerInterface );
|
||||||
|
|
||||||
|
$subscriptions_mode_settings = $c->get( 'wcgateway.settings.fields.subscriptions_mode' ) ?: array();
|
||||||
|
|
||||||
/* @var State $state The state. */
|
/* @var State $state The state. */
|
||||||
$state = $c->get( 'onboarding.state' );
|
$state = $c->get( 'onboarding.state' );
|
||||||
|
|
||||||
|
@ -61,6 +64,9 @@ class StatusReportModule implements ModuleInterface {
|
||||||
/* @var MessagesApply $messages_apply The messages apply. */
|
/* @var MessagesApply $messages_apply The messages apply. */
|
||||||
$messages_apply = $c->get( 'button.helper.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' );
|
$last_webhook_storage = $c->get( 'webhook.last-webhook-storage' );
|
||||||
assert( $last_webhook_storage instanceof WebhookEventStorage );
|
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(
|
echo wp_kses_post(
|
||||||
$renderer->render(
|
$renderer->render(
|
||||||
esc_html__( 'WooCommerce PayPal Payments', 'woocommerce-paypal-payments' ),
|
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;
|
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.
|
* Checks if reference transactions are enabled in account.
|
||||||
*
|
*
|
||||||
|
|
|
@ -386,6 +386,28 @@ return array(
|
||||||
return array_key_exists( $current_page_id, $sections );
|
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 {
|
'wcgateway.settings.fields' => static function ( ContainerInterface $container ): array {
|
||||||
|
|
||||||
$should_render_settings = $container->get( 'wcgateway.settings.should-render-settings' );
|
$should_render_settings = $container->get( 'wcgateway.settings.should-render-settings' );
|
||||||
|
@ -805,25 +827,7 @@ return array(
|
||||||
'requirements' => array(),
|
'requirements' => array(),
|
||||||
'gateway' => 'paypal',
|
'gateway' => 'paypal',
|
||||||
),
|
),
|
||||||
'subscriptions_mode' => array(
|
'subscriptions_mode' => $container->get( 'wcgateway.settings.fields.subscriptions_mode' ),
|
||||||
'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',
|
|
||||||
),
|
|
||||||
'vault_enabled' => array(
|
'vault_enabled' => array(
|
||||||
'title' => __( 'Vaulting', 'woocommerce-paypal-payments' ),
|
'title' => __( 'Vaulting', 'woocommerce-paypal-payments' ),
|
||||||
'type' => 'checkbox',
|
'type' => 'checkbox',
|
||||||
|
@ -872,7 +876,6 @@ return array(
|
||||||
$billing_agreements_endpoint = $container->get( 'api.endpoint.billing-agreements' );
|
$billing_agreements_endpoint = $container->get( 'api.endpoint.billing-agreements' );
|
||||||
if ( ! $billing_agreements_endpoint->reference_transaction_enabled() ) {
|
if ( ! $billing_agreements_endpoint->reference_transaction_enabled() ) {
|
||||||
unset( $fields['vault_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';
|
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 {
|
'wcgateway.transaction-url-provider' => static function ( ContainerInterface $container ): TransactionUrlProvider {
|
||||||
$sandbox_url_base = $container->get( 'wcgateway.transaction-url-sandbox' );
|
$sandbox_url_base = $container->get( 'wcgateway.transaction-url-sandbox' );
|
||||||
$live_url_base = $container->get( 'wcgateway.transaction-url-live' );
|
$live_url_base = $container->get( 'wcgateway.transaction-url-live' );
|
||||||
|
|
|
@ -226,6 +226,7 @@ class PayPalGateway extends \WC_Payment_Gateway {
|
||||||
|
|
||||||
if (
|
if (
|
||||||
( $this->config->has( 'vault_enabled' ) && $this->config->get( 'vault_enabled' ) )
|
( $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' )
|
|| ( $this->config->has( 'subscriptions_mode' ) && $this->config->get( 'subscriptions_mode' ) === 'subscriptions_api' )
|
||||||
) {
|
) {
|
||||||
array_push(
|
array_push(
|
||||||
|
|
|
@ -245,32 +245,40 @@ return function ( ContainerInterface $container, array $fields ): array {
|
||||||
'gateway' => Settings::CONNECTION_TAB_ID,
|
'gateway' => Settings::CONNECTION_TAB_ID,
|
||||||
),
|
),
|
||||||
'merchant_id_production' => array(
|
'merchant_id_production' => array(
|
||||||
'title' => __( 'Live Merchant Id', 'woocommerce-paypal-payments' ),
|
'title' => __( 'Live Merchant Id', 'woocommerce-paypal-payments' ),
|
||||||
'classes' => array( State::STATE_ONBOARDED === $state->production_state() ? 'onboarded' : '', 'ppcp-always-shown-element' ),
|
'classes' => array( State::STATE_ONBOARDED === $state->production_state() ? 'onboarded' : '', 'ppcp-always-shown-element' ),
|
||||||
'type' => 'ppcp-text-input',
|
'type' => 'text',
|
||||||
'desc_tip' => true,
|
'desc_tip' => true,
|
||||||
'description' => __( 'The merchant id of your account ', 'woocommerce-paypal-payments' ),
|
'description' => __( 'The merchant id of your account. Should be exactly 13 alphanumeric uppercase letters.', 'woocommerce-paypal-payments' ),
|
||||||
'default' => false,
|
'maxlength' => 13,
|
||||||
'screens' => array(
|
'custom_attributes' => array(
|
||||||
|
'pattern' => '[A-Z0-9]{13}',
|
||||||
|
'autocomplete' => 'off',
|
||||||
|
),
|
||||||
|
'default' => false,
|
||||||
|
'screens' => array(
|
||||||
State::STATE_START,
|
State::STATE_START,
|
||||||
State::STATE_ONBOARDED,
|
State::STATE_ONBOARDED,
|
||||||
),
|
),
|
||||||
'requirements' => array(),
|
'requirements' => array(),
|
||||||
'gateway' => Settings::CONNECTION_TAB_ID,
|
'gateway' => Settings::CONNECTION_TAB_ID,
|
||||||
),
|
),
|
||||||
'client_id_production' => array(
|
'client_id_production' => array(
|
||||||
'title' => __( 'Live Client Id', 'woocommerce-paypal-payments' ),
|
'title' => __( 'Live Client Id', 'woocommerce-paypal-payments' ),
|
||||||
'classes' => array( State::STATE_ONBOARDED === $state->production_state() ? 'onboarded' : '', 'ppcp-always-shown-element' ),
|
'classes' => array( State::STATE_ONBOARDED === $state->production_state() ? 'onboarded' : '', 'ppcp-always-shown-element' ),
|
||||||
'type' => 'ppcp-text-input',
|
'type' => 'text',
|
||||||
'desc_tip' => true,
|
'desc_tip' => true,
|
||||||
'description' => __( 'The client id of your api ', 'woocommerce-paypal-payments' ),
|
'description' => __( 'The client id of your api ', 'woocommerce-paypal-payments' ),
|
||||||
'default' => false,
|
'custom_attributes' => array(
|
||||||
'screens' => array(
|
'autocomplete' => 'off',
|
||||||
|
),
|
||||||
|
'default' => false,
|
||||||
|
'screens' => array(
|
||||||
State::STATE_START,
|
State::STATE_START,
|
||||||
State::STATE_ONBOARDED,
|
State::STATE_ONBOARDED,
|
||||||
),
|
),
|
||||||
'requirements' => array(),
|
'requirements' => array(),
|
||||||
'gateway' => Settings::CONNECTION_TAB_ID,
|
'gateway' => Settings::CONNECTION_TAB_ID,
|
||||||
),
|
),
|
||||||
'client_secret_production' => array(
|
'client_secret_production' => array(
|
||||||
'title' => __( 'Live Secret Key', 'woocommerce-paypal-payments' ),
|
'title' => __( 'Live Secret Key', 'woocommerce-paypal-payments' ),
|
||||||
|
@ -303,32 +311,40 @@ return function ( ContainerInterface $container, array $fields ): array {
|
||||||
'gateway' => Settings::CONNECTION_TAB_ID,
|
'gateway' => Settings::CONNECTION_TAB_ID,
|
||||||
),
|
),
|
||||||
'merchant_id_sandbox' => array(
|
'merchant_id_sandbox' => array(
|
||||||
'title' => __( 'Sandbox Merchant Id', 'woocommerce-paypal-payments' ),
|
'title' => __( 'Sandbox Merchant Id', 'woocommerce-paypal-payments' ),
|
||||||
'classes' => array( State::STATE_ONBOARDED === $state->sandbox_state() ? 'onboarded' : '', 'ppcp-always-shown-element' ),
|
'classes' => array( State::STATE_ONBOARDED === $state->sandbox_state() ? 'onboarded' : '', 'ppcp-always-shown-element' ),
|
||||||
'type' => 'ppcp-text-input',
|
'type' => 'text',
|
||||||
'desc_tip' => true,
|
'desc_tip' => true,
|
||||||
'description' => __( 'The merchant id of your account ', 'woocommerce-paypal-payments' ),
|
'description' => __( 'The merchant id of your account. Should be exactly 13 alphanumeric uppercase letters.', 'woocommerce-paypal-payments' ),
|
||||||
'default' => false,
|
'maxlength' => 13,
|
||||||
'screens' => array(
|
'custom_attributes' => array(
|
||||||
|
'pattern' => '[A-Z0-9]{13}',
|
||||||
|
'autocomplete' => 'off',
|
||||||
|
),
|
||||||
|
'default' => false,
|
||||||
|
'screens' => array(
|
||||||
State::STATE_START,
|
State::STATE_START,
|
||||||
State::STATE_ONBOARDED,
|
State::STATE_ONBOARDED,
|
||||||
),
|
),
|
||||||
'requirements' => array(),
|
'requirements' => array(),
|
||||||
'gateway' => Settings::CONNECTION_TAB_ID,
|
'gateway' => Settings::CONNECTION_TAB_ID,
|
||||||
),
|
),
|
||||||
'client_id_sandbox' => array(
|
'client_id_sandbox' => array(
|
||||||
'title' => __( 'Sandbox Client Id', 'woocommerce-paypal-payments' ),
|
'title' => __( 'Sandbox Client Id', 'woocommerce-paypal-payments' ),
|
||||||
'classes' => array( State::STATE_ONBOARDED === $state->sandbox_state() ? 'onboarded' : '', 'ppcp-always-shown-element' ),
|
'classes' => array( State::STATE_ONBOARDED === $state->sandbox_state() ? 'onboarded' : '', 'ppcp-always-shown-element' ),
|
||||||
'type' => 'ppcp-text-input',
|
'type' => 'text',
|
||||||
'desc_tip' => true,
|
'desc_tip' => true,
|
||||||
'description' => __( 'The client id of your api ', 'woocommerce-paypal-payments' ),
|
'description' => __( 'The client id of your api ', 'woocommerce-paypal-payments' ),
|
||||||
'default' => false,
|
'custom_attributes' => array(
|
||||||
'screens' => array(
|
'autocomplete' => 'off',
|
||||||
|
),
|
||||||
|
'default' => false,
|
||||||
|
'screens' => array(
|
||||||
State::STATE_START,
|
State::STATE_START,
|
||||||
State::STATE_ONBOARDED,
|
State::STATE_ONBOARDED,
|
||||||
),
|
),
|
||||||
'requirements' => array(),
|
'requirements' => array(),
|
||||||
'gateway' => Settings::CONNECTION_TAB_ID,
|
'gateway' => Settings::CONNECTION_TAB_ID,
|
||||||
),
|
),
|
||||||
'client_secret_sandbox' => array(
|
'client_secret_sandbox' => array(
|
||||||
'title' => __( 'Sandbox Secret Key', 'woocommerce-paypal-payments' ),
|
'title' => __( 'Sandbox Secret Key', 'woocommerce-paypal-payments' ),
|
||||||
|
@ -423,6 +439,20 @@ return function ( ContainerInterface $container, array $fields ): array {
|
||||||
'</a>'
|
'</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(
|
'prefix' => array(
|
||||||
'title' => __( 'Invoice prefix', 'woocommerce-paypal-payments' ),
|
'title' => __( 'Invoice prefix', 'woocommerce-paypal-payments' ),
|
||||||
'type' => 'text',
|
'type' => 'text',
|
||||||
|
|
|
@ -478,7 +478,6 @@ class SettingsListener {
|
||||||
break;
|
break;
|
||||||
case 'text':
|
case 'text':
|
||||||
case 'number':
|
case 'number':
|
||||||
case 'ppcp-text-input':
|
|
||||||
$settings[ $key ] = isset( $raw_data[ $key ] ) ? wp_kses_post( $raw_data[ $key ] ) : '';
|
$settings[ $key ] = isset( $raw_data[ $key ] ) ? wp_kses_post( $raw_data[ $key ] ) : '';
|
||||||
break;
|
break;
|
||||||
case 'ppcp-password':
|
case 'ppcp-password':
|
||||||
|
|
|
@ -243,39 +243,6 @@ class SettingsRenderer {
|
||||||
return $html;
|
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.
|
* Renders the heading field.
|
||||||
*
|
*
|
||||||
|
|
|
@ -528,7 +528,6 @@ class WCGatewayModule implements ModuleInterface {
|
||||||
*/
|
*/
|
||||||
$field = $renderer->render_multiselect( $field, $key, $args, $value );
|
$field = $renderer->render_multiselect( $field, $key, $args, $value );
|
||||||
$field = $renderer->render_password( $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_heading( $field, $key, $args, $value );
|
||||||
$field = $renderer->render_table( $field, $key, $args, $value );
|
$field = $renderer->render_table( $field, $key, $args, $value );
|
||||||
return $field;
|
return $field;
|
||||||
|
|
|
@ -81,7 +81,7 @@ Follow the steps below to connect the plugin to your PayPal account:
|
||||||
|
|
||||||
== Changelog ==
|
== 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 - 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 - 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
|
* 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 - 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 - 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 - 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 - Remove feature flag requirement for express cart/checkout block integration #1483
|
||||||
* Enhancement - Add notice when shop currency is unsupported #1433
|
* Enhancement - Add notice when shop currency is unsupported #1433
|
||||||
* Enhancement - Improve ACDC error message when empty fields #1360
|
* Enhancement - Improve ACDC error message when empty fields #1360
|
||||||
|
|
|
@ -26,13 +26,8 @@ class ChangeCartEndpointTest extends TestCase
|
||||||
->once()
|
->once()
|
||||||
->with($singleProductArray['id'])
|
->with($singleProductArray['id'])
|
||||||
->andReturn($products[$productKey]);
|
->andReturn($products[$productKey]);
|
||||||
if (! $singleProductArray['__test_data_is_variation']) {
|
|
||||||
$cart
|
if ($singleProductArray['__test_data_is_variation'] ?? false) {
|
||||||
->expects('add_to_cart')
|
|
||||||
->with($singleProductArray['id'], $singleProductArray['quantity'])
|
|
||||||
->andReturnTrue();
|
|
||||||
}
|
|
||||||
if ($singleProductArray['__test_data_is_variation']) {
|
|
||||||
$dataStore
|
$dataStore
|
||||||
->expects('find_matching_product_variation')
|
->expects('find_matching_product_variation')
|
||||||
->with($products[$productKey], $singleProductArray['__test_data_variation_map'])
|
->with($products[$productKey], $singleProductArray['__test_data_variation_map'])
|
||||||
|
@ -47,7 +42,34 @@ class ChangeCartEndpointTest extends TestCase
|
||||||
)
|
)
|
||||||
->andReturnTrue();
|
->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
|
$cart
|
||||||
->expects('empty_cart')
|
->expects('empty_cart')
|
||||||
->with(false);
|
->with(false);
|
||||||
|
@ -88,6 +110,10 @@ class ChangeCartEndpointTest extends TestCase
|
||||||
$defaultProduct
|
$defaultProduct
|
||||||
->shouldReceive('get_id')
|
->shouldReceive('get_id')
|
||||||
->andReturn(1);
|
->andReturn(1);
|
||||||
|
$defaultProduct
|
||||||
|
->shouldReceive('is_type')
|
||||||
|
->with('booking')
|
||||||
|
->andReturn(false);
|
||||||
$defaultProduct
|
$defaultProduct
|
||||||
->shouldReceive('is_type')
|
->shouldReceive('is_type')
|
||||||
->with('variable')
|
->with('variable')
|
||||||
|
@ -97,19 +123,42 @@ class ChangeCartEndpointTest extends TestCase
|
||||||
$variationProduct
|
$variationProduct
|
||||||
->shouldReceive('get_id')
|
->shouldReceive('get_id')
|
||||||
->andReturn(2);
|
->andReturn(2);
|
||||||
|
$variationProduct
|
||||||
|
->shouldReceive('is_type')
|
||||||
|
->with('booking')
|
||||||
|
->andReturn(false);
|
||||||
$variationProduct
|
$variationProduct
|
||||||
->shouldReceive('is_type')
|
->shouldReceive('is_type')
|
||||||
->with('variable')
|
->with('variable')
|
||||||
->andReturn(true);
|
->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' => [
|
'default' => [
|
||||||
[
|
[
|
||||||
'products' => [
|
'products' => [
|
||||||
[
|
[
|
||||||
'quantity' => 2,
|
'quantity' => 2,
|
||||||
'id' => 1,
|
'id' => 1,
|
||||||
'__test_data_is_variation' => false,
|
|
||||||
],
|
],
|
||||||
]
|
]
|
||||||
],
|
],
|
||||||
|
@ -121,43 +170,65 @@ class ChangeCartEndpointTest extends TestCase
|
||||||
]
|
]
|
||||||
],
|
],
|
||||||
'variation' => [
|
'variation' => [
|
||||||
[
|
[
|
||||||
'products' => [
|
'products' => [
|
||||||
[
|
[
|
||||||
'quantity' => 2,
|
'quantity' => 2,
|
||||||
'id' => 1,
|
'id' => 1,
|
||||||
'__test_data_is_variation' => false,
|
],
|
||||||
],
|
[
|
||||||
[
|
'quantity' => 2,
|
||||||
'quantity' => 2,
|
'id' => 2,
|
||||||
'id' => 2,
|
'variations' => [
|
||||||
'variations' => [
|
[
|
||||||
[
|
'name' => 'variation-1',
|
||||||
'name' => 'variation-1',
|
'value' => 'abc',
|
||||||
'value' => 'abc',
|
],
|
||||||
],
|
[
|
||||||
[
|
'name' => 'variation-2',
|
||||||
'name' => 'variation-2',
|
'value' => 'def',
|
||||||
'value' => 'def',
|
],
|
||||||
],
|
],
|
||||||
],
|
'__test_data_is_variation' => true,
|
||||||
'__test_data_is_variation' => true,
|
'__test_data_variation_id' => 123,
|
||||||
'__test_data_variation_id' => 123,
|
'__test_data_variation_map' => [
|
||||||
'__test_data_variation_map' => [
|
'variation-1' => 'abc',
|
||||||
'variation-1' => 'abc',
|
'variation-2' => 'def',
|
||||||
'variation-2' => 'def',
|
]
|
||||||
]
|
],
|
||||||
],
|
]
|
||||||
]
|
],
|
||||||
],
|
[
|
||||||
[
|
$defaultProduct,
|
||||||
$defaultProduct,
|
$variationProduct,
|
||||||
$variationProduct,
|
],
|
||||||
],
|
[
|
||||||
[
|
[1, 2]
|
||||||
[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;
|
return $testData;
|
||||||
|
|
|
@ -73,6 +73,7 @@ class ApplicationContextRepositoryTest extends TestCase
|
||||||
'container' => [
|
'container' => [
|
||||||
'brand_name' => 'Acme corp.',
|
'brand_name' => 'Acme corp.',
|
||||||
'landing_page' => ApplicationContext::LANDING_PAGE_BILLING,
|
'landing_page' => ApplicationContext::LANDING_PAGE_BILLING,
|
||||||
|
'payee_preferred' => '',
|
||||||
],
|
],
|
||||||
'user_locale' => 'de_DE',
|
'user_locale' => 'de_DE',
|
||||||
'shippingPreference' => ApplicationContext::SHIPPING_PREFERENCE_NO_SHIPPING,
|
'shippingPreference' => ApplicationContext::SHIPPING_PREFERENCE_NO_SHIPPING,
|
||||||
|
@ -81,6 +82,7 @@ class ApplicationContextRepositoryTest extends TestCase
|
||||||
'brand_name' => 'Acme corp.',
|
'brand_name' => 'Acme corp.',
|
||||||
'landing_page' => ApplicationContext::LANDING_PAGE_BILLING,
|
'landing_page' => ApplicationContext::LANDING_PAGE_BILLING,
|
||||||
'shipping_preference' => ApplicationContext::SHIPPING_PREFERENCE_NO_SHIPPING,
|
'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