mirror of
https://github.com/woocommerce/woocommerce-paypal-payments.git
synced 2025-09-05 08:59:14 +08:00
Add Support for product variants on ApplePay
This commit is contained in:
parent
cb598ccbca
commit
3d293058fb
11 changed files with 519 additions and 246 deletions
|
@ -23,9 +23,6 @@ class ApplepayButton {
|
||||||
this.ppcpConfig
|
this.ppcpConfig
|
||||||
);
|
);
|
||||||
|
|
||||||
//PRODUCT DETAIL PAGE
|
|
||||||
this.refreshContextData();
|
|
||||||
|
|
||||||
this.updated_contact_info = []
|
this.updated_contact_info = []
|
||||||
this.selectedShippingMethod = []
|
this.selectedShippingMethod = []
|
||||||
this.nonce = document.getElementById('woocommerce-process-checkout-nonce').value
|
this.nonce = document.getElementById('woocommerce-process-checkout-nonce').value
|
||||||
|
@ -35,6 +32,21 @@ class ApplepayButton {
|
||||||
console.log('[ApplePayButton]', ...arguments);
|
console.log('[ApplePayButton]', ...arguments);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//PRODUCT DETAIL PAGE
|
||||||
|
this.refreshContextData();
|
||||||
|
|
||||||
|
if (this.context === 'product') {
|
||||||
|
jQuery(document).on('appleclick', () => {
|
||||||
|
(this.onshippingcontactselected())({
|
||||||
|
shippingContact: {
|
||||||
|
locality: 'New York',
|
||||||
|
postalCode: '10001',
|
||||||
|
countryCode: 'US'
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
init(config) {
|
init(config) {
|
||||||
|
@ -260,6 +272,8 @@ class ApplepayButton {
|
||||||
case 'product':
|
case 'product':
|
||||||
// Refresh product data that makes the price change.
|
// Refresh product data that makes the price change.
|
||||||
this.productQuantity = document.querySelector('input.qty').value;
|
this.productQuantity = document.querySelector('input.qty').value;
|
||||||
|
this.products = this.contextHandler.products();
|
||||||
|
this.log('Products updated', this.products);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -389,6 +403,7 @@ class ApplepayButton {
|
||||||
return {
|
return {
|
||||||
action: 'ppcp_update_shipping_contact',
|
action: 'ppcp_update_shipping_contact',
|
||||||
product_id: product_id,
|
product_id: product_id,
|
||||||
|
products: JSON.stringify(this.products),
|
||||||
caller_page: 'productDetail',
|
caller_page: 'productDetail',
|
||||||
product_quantity: this.productQuantity,
|
product_quantity: this.productQuantity,
|
||||||
simplified_contact: event.shippingContact,
|
simplified_contact: event.shippingContact,
|
||||||
|
@ -419,6 +434,7 @@ class ApplepayButton {
|
||||||
action: 'ppcp_update_shipping_method',
|
action: 'ppcp_update_shipping_method',
|
||||||
shipping_method: event.shippingMethod,
|
shipping_method: event.shippingMethod,
|
||||||
product_id: product_id,
|
product_id: product_id,
|
||||||
|
products: JSON.stringify(this.products),
|
||||||
caller_page: 'productDetail',
|
caller_page: 'productDetail',
|
||||||
product_quantity: this.productQuantity,
|
product_quantity: this.productQuantity,
|
||||||
simplified_contact: this.updated_contact_info,
|
simplified_contact: this.updated_contact_info,
|
||||||
|
@ -456,6 +472,7 @@ class ApplepayButton {
|
||||||
action: 'ppcp_create_order',
|
action: 'ppcp_create_order',
|
||||||
'caller_page': this.context,
|
'caller_page': this.context,
|
||||||
'product_id': this.buttonConfig.product.id ?? null,
|
'product_id': this.buttonConfig.product.id ?? null,
|
||||||
|
'products': JSON.stringify(this.products),
|
||||||
'product_quantity': this.productQuantity ?? null,
|
'product_quantity': this.productQuantity ?? null,
|
||||||
'shipping_contact': shippingContact,
|
'shipping_contact': shippingContact,
|
||||||
'billing_contact': billingContact,
|
'billing_contact': billingContact,
|
||||||
|
|
|
@ -49,12 +49,20 @@ class SingleProductHandler extends BaseHandler {
|
||||||
}
|
}
|
||||||
|
|
||||||
createOrder() {
|
createOrder() {
|
||||||
|
return this.actionHandler().configuration().createOrder();
|
||||||
|
}
|
||||||
|
|
||||||
|
products() {
|
||||||
|
return this.actionHandler().getProducts();
|
||||||
|
}
|
||||||
|
|
||||||
|
actionHandler() {
|
||||||
const errorHandler = new ErrorHandler(
|
const errorHandler = new ErrorHandler(
|
||||||
this.ppcpConfig.labels.error.generic,
|
this.ppcpConfig.labels.error.generic,
|
||||||
document.querySelector('.woocommerce-notices-wrapper')
|
document.querySelector('.woocommerce-notices-wrapper')
|
||||||
);
|
);
|
||||||
|
|
||||||
const actionHandler = new SingleProductActionHandler(
|
return new SingleProductActionHandler(
|
||||||
this.ppcpConfig,
|
this.ppcpConfig,
|
||||||
new UpdateCart(
|
new UpdateCart(
|
||||||
this.ppcpConfig.ajax.change_cart.endpoint,
|
this.ppcpConfig.ajax.change_cart.endpoint,
|
||||||
|
@ -63,8 +71,6 @@ class SingleProductHandler extends BaseHandler {
|
||||||
document.querySelector('form.cart'),
|
document.querySelector('form.cart'),
|
||||||
errorHandler,
|
errorHandler,
|
||||||
);
|
);
|
||||||
|
|
||||||
return actionHandler.configuration().createOrder();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -100,7 +100,6 @@ return array(
|
||||||
return new DataToAppleButtonScripts( $container->get( 'applepay.sdk_script_url' ), $container->get( 'wcgateway.settings' ) );
|
return new DataToAppleButtonScripts( $container->get( 'applepay.sdk_script_url' ), $container->get( 'wcgateway.settings' ) );
|
||||||
},
|
},
|
||||||
'applepay.button' => static function ( ContainerInterface $container ): ApplePayButton {
|
'applepay.button' => static function ( ContainerInterface $container ): ApplePayButton {
|
||||||
|
|
||||||
return new ApplePayButton(
|
return new ApplePayButton(
|
||||||
$container->get( 'wcgateway.settings' ),
|
$container->get( 'wcgateway.settings' ),
|
||||||
$container->get( 'woocommerce.logger.woocommerce' ),
|
$container->get( 'woocommerce.logger.woocommerce' ),
|
||||||
|
@ -108,8 +107,9 @@ return array(
|
||||||
$container->get( 'applepay.url' ),
|
$container->get( 'applepay.url' ),
|
||||||
$container->get( 'ppcp.asset-version' ),
|
$container->get( 'ppcp.asset-version' ),
|
||||||
$container->get( 'applepay.data_to_scripts' ),
|
$container->get( 'applepay.data_to_scripts' ),
|
||||||
$container->get( 'wcgateway.settings.status' )
|
$container->get( 'wcgateway.settings.status' ),
|
||||||
);
|
$container->get( 'button.helper.cart-products' )
|
||||||
|
);
|
||||||
},
|
},
|
||||||
'applepay.blocks-payment-method' => static function ( ContainerInterface $container ): PaymentMethodTypeInterface {
|
'applepay.blocks-payment-method' => static function ( ContainerInterface $container ): PaymentMethodTypeInterface {
|
||||||
return new BlocksPaymentMethod(
|
return new BlocksPaymentMethod(
|
||||||
|
|
|
@ -14,6 +14,7 @@ use Psr\Log\LoggerInterface;
|
||||||
use WC_Cart;
|
use WC_Cart;
|
||||||
use WC_Order;
|
use WC_Order;
|
||||||
use WooCommerce\PayPalCommerce\Button\Assets\ButtonInterface;
|
use WooCommerce\PayPalCommerce\Button\Assets\ButtonInterface;
|
||||||
|
use WooCommerce\PayPalCommerce\Button\Helper\CartProductsHelper;
|
||||||
use WooCommerce\PayPalCommerce\WcGateway\Exception\NotFoundException;
|
use WooCommerce\PayPalCommerce\WcGateway\Exception\NotFoundException;
|
||||||
use WooCommerce\PayPalCommerce\WcGateway\Helper\SettingsStatus;
|
use WooCommerce\PayPalCommerce\WcGateway\Helper\SettingsStatus;
|
||||||
use WooCommerce\PayPalCommerce\WcGateway\Processor\OrderProcessor;
|
use WooCommerce\PayPalCommerce\WcGateway\Processor\OrderProcessor;
|
||||||
|
@ -25,18 +26,21 @@ use WooCommerce\PayPalCommerce\Webhooks\Handler\RequestHandlerTrait;
|
||||||
*/
|
*/
|
||||||
class ApplePayButton implements ButtonInterface {
|
class ApplePayButton implements ButtonInterface {
|
||||||
use RequestHandlerTrait;
|
use RequestHandlerTrait;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The settings.
|
* The settings.
|
||||||
*
|
*
|
||||||
* @var Settings
|
* @var Settings
|
||||||
*/
|
*/
|
||||||
private $settings;
|
private $settings;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The logger.
|
* The logger.
|
||||||
*
|
*
|
||||||
* @var LoggerInterface
|
* @var LoggerInterface
|
||||||
*/
|
*/
|
||||||
private $logger;
|
private $logger;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The response templates.
|
* The response templates.
|
||||||
*
|
*
|
||||||
|
@ -58,12 +62,14 @@ class ApplePayButton implements ButtonInterface {
|
||||||
* @var string
|
* @var string
|
||||||
*/
|
*/
|
||||||
protected $id;
|
protected $id;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The method title.
|
* The method title.
|
||||||
*
|
*
|
||||||
* @var string
|
* @var string
|
||||||
*/
|
*/
|
||||||
protected $method_title;
|
protected $method_title;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The processor for orders.
|
* The processor for orders.
|
||||||
*
|
*
|
||||||
|
@ -84,18 +90,21 @@ class ApplePayButton implements ButtonInterface {
|
||||||
* @var string
|
* @var string
|
||||||
*/
|
*/
|
||||||
private $version;
|
private $version;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The module URL.
|
* The module URL.
|
||||||
*
|
*
|
||||||
* @var string
|
* @var string
|
||||||
*/
|
*/
|
||||||
private $module_url;
|
private $module_url;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The data to send to the ApplePay button script.
|
* The data to send to the ApplePay button script.
|
||||||
*
|
*
|
||||||
* @var DataToAppleButtonScripts
|
* @var DataToAppleButtonScripts
|
||||||
*/
|
*/
|
||||||
private $script_data;
|
private $script_data;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The Settings status helper.
|
* The Settings status helper.
|
||||||
*
|
*
|
||||||
|
@ -103,6 +112,13 @@ class ApplePayButton implements ButtonInterface {
|
||||||
*/
|
*/
|
||||||
private $settings_status;
|
private $settings_status;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The cart products helper.
|
||||||
|
*
|
||||||
|
* @var CartProductsHelper
|
||||||
|
*/
|
||||||
|
protected $cart_products;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* PayPalPaymentMethod constructor.
|
* PayPalPaymentMethod constructor.
|
||||||
*
|
*
|
||||||
|
@ -113,6 +129,7 @@ class ApplePayButton implements ButtonInterface {
|
||||||
* @param string $version The module version.
|
* @param string $version The module version.
|
||||||
* @param DataToAppleButtonScripts $data The data to send to the ApplePay button script.
|
* @param DataToAppleButtonScripts $data The data to send to the ApplePay button script.
|
||||||
* @param SettingsStatus $settings_status The settings status helper.
|
* @param SettingsStatus $settings_status The settings status helper.
|
||||||
|
* @param CartProductsHelper $cart_products The cart products helper.
|
||||||
*/
|
*/
|
||||||
public function __construct(
|
public function __construct(
|
||||||
Settings $settings,
|
Settings $settings,
|
||||||
|
@ -121,7 +138,8 @@ class ApplePayButton implements ButtonInterface {
|
||||||
string $module_url,
|
string $module_url,
|
||||||
string $version,
|
string $version,
|
||||||
DataToAppleButtonScripts $data,
|
DataToAppleButtonScripts $data,
|
||||||
SettingsStatus $settings_status
|
SettingsStatus $settings_status,
|
||||||
|
CartProductsHelper $cart_products
|
||||||
) {
|
) {
|
||||||
$this->settings = $settings;
|
$this->settings = $settings;
|
||||||
$this->response_templates = new ResponsesToApple();
|
$this->response_templates = new ResponsesToApple();
|
||||||
|
@ -133,6 +151,7 @@ class ApplePayButton implements ButtonInterface {
|
||||||
$this->version = $version;
|
$this->version = $version;
|
||||||
$this->script_data = $data;
|
$this->script_data = $data;
|
||||||
$this->settings_status = $settings_status;
|
$this->settings_status = $settings_status;
|
||||||
|
$this->cart_products = $cart_products;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -822,15 +841,24 @@ class ApplePayButton implements ButtonInterface {
|
||||||
*
|
*
|
||||||
* @param ApplePayDataObjectHttp $applepay_request_data_object The request data object.
|
* @param ApplePayDataObjectHttp $applepay_request_data_object The request data object.
|
||||||
* @return bool | string The cart item key after adding to the new cart.
|
* @return bool | string The cart item key after adding to the new cart.
|
||||||
* @throws \Exception If cannot be added to cart.
|
* @throws \Exception If it cannot be added to cart.
|
||||||
*/
|
*/
|
||||||
public function prepare_cart( ApplePayDataObjectHttp $applepay_request_data_object ): string {
|
public function prepare_cart( ApplePayDataObjectHttp $applepay_request_data_object ): string {
|
||||||
$this->save_old_cart();
|
$this->save_old_cart();
|
||||||
$cart = WC()->cart;
|
$this->cart_products->set_cart( WC()->cart );
|
||||||
return $cart->add_to_cart(
|
|
||||||
(int) $applepay_request_data_object->product_id(),
|
$product = $this->cart_products->product_from_data(
|
||||||
(int) $applepay_request_data_object->product_quantity()
|
array(
|
||||||
|
'id' => (int) $applepay_request_data_object->product_id(),
|
||||||
|
'quantity' => (int) $applepay_request_data_object->product_quantity(),
|
||||||
|
'variations' => $applepay_request_data_object->product_variations(),
|
||||||
|
'extra' => $applepay_request_data_object->product_extra(),
|
||||||
|
'booking' => $applepay_request_data_object->product_booking(),
|
||||||
|
)
|
||||||
);
|
);
|
||||||
|
|
||||||
|
$this->cart_products->add_products( array( $product ) );
|
||||||
|
return $this->cart_products->cart_item_keys()[0];
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -38,13 +38,6 @@ class ApplePayDataObjectHttp {
|
||||||
*/
|
*/
|
||||||
protected $need_shipping;
|
protected $need_shipping;
|
||||||
|
|
||||||
/**
|
|
||||||
* The product id.
|
|
||||||
*
|
|
||||||
* @var mixed
|
|
||||||
*/
|
|
||||||
protected $product_id = '';
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The caller page.
|
* The caller page.
|
||||||
*
|
*
|
||||||
|
@ -52,6 +45,13 @@ class ApplePayDataObjectHttp {
|
||||||
*/
|
*/
|
||||||
protected $caller_page;
|
protected $caller_page;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The product id.
|
||||||
|
*
|
||||||
|
* @var mixed
|
||||||
|
*/
|
||||||
|
protected $product_id = '';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The product quantity.
|
* The product quantity.
|
||||||
*
|
*
|
||||||
|
@ -59,6 +59,27 @@ class ApplePayDataObjectHttp {
|
||||||
*/
|
*/
|
||||||
protected $product_quantity = '';
|
protected $product_quantity = '';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The product variations.
|
||||||
|
*
|
||||||
|
* @var string
|
||||||
|
*/
|
||||||
|
protected $product_variations = array();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The product extra.
|
||||||
|
*
|
||||||
|
* @var string
|
||||||
|
*/
|
||||||
|
protected $product_extra = array();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The product booking.
|
||||||
|
*
|
||||||
|
* @var string
|
||||||
|
*/
|
||||||
|
protected $product_booking = array();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The shipping methods.
|
* The shipping methods.
|
||||||
*
|
*
|
||||||
|
@ -166,6 +187,9 @@ class ApplePayDataObjectHttp {
|
||||||
if ( ! $data ) {
|
if ( ! $data ) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$data = $this->preprocess_request_data( $data );
|
||||||
|
|
||||||
$result = $this->update_required_data(
|
$result = $this->update_required_data(
|
||||||
$data,
|
$data,
|
||||||
PropertiesDictionary::UPDATE_CONTACT_SINGLE_PROD_REQUIRED_FIELDS,
|
PropertiesDictionary::UPDATE_CONTACT_SINGLE_PROD_REQUIRED_FIELDS,
|
||||||
|
@ -198,6 +222,9 @@ class ApplePayDataObjectHttp {
|
||||||
if ( ! $data ) {
|
if ( ! $data ) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$data = $this->preprocess_request_data( $data );
|
||||||
|
|
||||||
$result = $this->update_required_data(
|
$result = $this->update_required_data(
|
||||||
$data,
|
$data,
|
||||||
PropertiesDictionary::UPDATE_METHOD_SINGLE_PROD_REQUIRED_FIELDS,
|
PropertiesDictionary::UPDATE_METHOD_SINGLE_PROD_REQUIRED_FIELDS,
|
||||||
|
@ -226,6 +253,9 @@ class ApplePayDataObjectHttp {
|
||||||
if ( ! $data ) {
|
if ( ! $data ) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$data = $this->preprocess_request_data( $data );
|
||||||
|
|
||||||
$data[ PropertiesDictionary::CALLER_PAGE ] = $caller_page;
|
$data[ PropertiesDictionary::CALLER_PAGE ] = $caller_page;
|
||||||
$result = $this->update_required_data(
|
$result = $this->update_required_data(
|
||||||
$data,
|
$data,
|
||||||
|
@ -261,6 +291,27 @@ class ApplePayDataObjectHttp {
|
||||||
$this->update_shipping_method( $data );
|
$this->update_shipping_method( $data );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Pre-processes request data to transform it to a standard format.
|
||||||
|
*
|
||||||
|
* @param array $data
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
protected function preprocess_request_data( array $data ): array {
|
||||||
|
// Fill product variables if a products object is received.
|
||||||
|
if ( is_array( $data[ PropertiesDictionary::PRODUCTS ] ?? null ) ) {
|
||||||
|
$product = $data[ PropertiesDictionary::PRODUCTS ][0];
|
||||||
|
|
||||||
|
$data[ PropertiesDictionary::PRODUCT_ID ] = $product['id'] ?? 0;
|
||||||
|
$data[ PropertiesDictionary::PRODUCT_QUANTITY ] = $product['quantity'] ?? array();
|
||||||
|
$data[ PropertiesDictionary::PRODUCT_VARIATIONS ] = $product['variations'] ?? array();
|
||||||
|
$data[ PropertiesDictionary::PRODUCT_EXTRA ] = $product['extra'] ?? array();
|
||||||
|
$data[ PropertiesDictionary::PRODUCT_BOOKING ] = $product['booking'] ?? array();
|
||||||
|
}
|
||||||
|
unset( $data[ PropertiesDictionary::PRODUCTS ] );
|
||||||
|
return $data;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Checks if the array contains all required fields and if those
|
* Checks if the array contains all required fields and if those
|
||||||
* are not empty.
|
* are not empty.
|
||||||
|
@ -300,7 +351,7 @@ class ApplePayDataObjectHttp {
|
||||||
*/
|
*/
|
||||||
protected function assign_data_object_values( array $data ): void {
|
protected function assign_data_object_values( array $data ): void {
|
||||||
foreach ( $data as $key => $value ) {
|
foreach ( $data as $key => $value ) {
|
||||||
// Null values may give origin to type errors. If necessary replace condition this with a specialized field filter.
|
// Null values may give origin to type errors. If necessary replace this condition with a specialized field filter.
|
||||||
if ( null === $value ) {
|
if ( null === $value ) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
@ -547,6 +598,33 @@ class ApplePayDataObjectHttp {
|
||||||
return $this->product_quantity;
|
return $this->product_quantity;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the product variations.
|
||||||
|
*
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
public function product_variations(): array {
|
||||||
|
return $this->product_variations;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the product extra.
|
||||||
|
*
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
public function product_extra(): array {
|
||||||
|
return $this->product_extra;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the product booking.
|
||||||
|
*
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
public function product_booking(): array {
|
||||||
|
return $this->product_booking;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the nonce.
|
* Returns the nonce.
|
||||||
*
|
*
|
||||||
|
@ -580,7 +658,7 @@ class ApplePayDataObjectHttp {
|
||||||
* @return array|false|null
|
* @return array|false|null
|
||||||
*/
|
*/
|
||||||
public function get_filtered_request_data() {
|
public function get_filtered_request_data() {
|
||||||
return filter_input_array(
|
$data = filter_input_array(
|
||||||
INPUT_POST,
|
INPUT_POST,
|
||||||
array(
|
array(
|
||||||
PropertiesDictionary::CALLER_PAGE => FILTER_SANITIZE_SPECIAL_CHARS,
|
PropertiesDictionary::CALLER_PAGE => FILTER_SANITIZE_SPECIAL_CHARS,
|
||||||
|
@ -604,8 +682,28 @@ class ApplePayDataObjectHttp {
|
||||||
),
|
),
|
||||||
PropertiesDictionary::PRODUCT_ID => FILTER_SANITIZE_NUMBER_INT,
|
PropertiesDictionary::PRODUCT_ID => FILTER_SANITIZE_NUMBER_INT,
|
||||||
PropertiesDictionary::PRODUCT_QUANTITY => FILTER_SANITIZE_NUMBER_INT,
|
PropertiesDictionary::PRODUCT_QUANTITY => FILTER_SANITIZE_NUMBER_INT,
|
||||||
|
PropertiesDictionary::PRODUCT_VARIATIONS => array(
|
||||||
|
'filter' => FILTER_SANITIZE_SPECIAL_CHARS,
|
||||||
|
'flags' => FILTER_REQUIRE_ARRAY,
|
||||||
|
),
|
||||||
|
PropertiesDictionary::PRODUCT_EXTRA => array(
|
||||||
|
'filter' => FILTER_SANITIZE_SPECIAL_CHARS,
|
||||||
|
'flags' => FILTER_REQUIRE_ARRAY,
|
||||||
|
),
|
||||||
|
PropertiesDictionary::PRODUCT_BOOKING => array(
|
||||||
|
'filter' => FILTER_SANITIZE_SPECIAL_CHARS,
|
||||||
|
'flags' => FILTER_REQUIRE_ARRAY,
|
||||||
|
),
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
|
|
||||||
|
$products = json_decode( wp_unslash( $_POST[ PropertiesDictionary::PRODUCTS ] ?? '' ), true );
|
||||||
|
|
||||||
|
if ( $products ) {
|
||||||
|
$data[ PropertiesDictionary::PRODUCTS ] = $products;
|
||||||
|
}
|
||||||
|
|
||||||
|
return $data;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -14,7 +14,6 @@ namespace WooCommerce\PayPalCommerce\Applepay\Assets;
|
||||||
*/
|
*/
|
||||||
class PropertiesDictionary {
|
class PropertiesDictionary {
|
||||||
|
|
||||||
|
|
||||||
public const BILLING_CONTACT_INVALID = 'billing Contact Invalid';
|
public const BILLING_CONTACT_INVALID = 'billing Contact Invalid';
|
||||||
|
|
||||||
public const CREATE_ORDER_SINGLE_PROD_REQUIRED_FIELDS =
|
public const CREATE_ORDER_SINGLE_PROD_REQUIRED_FIELDS =
|
||||||
|
@ -62,18 +61,20 @@ class PropertiesDictionary {
|
||||||
self::SIMPLIFIED_CONTACT,
|
self::SIMPLIFIED_CONTACT,
|
||||||
);
|
);
|
||||||
|
|
||||||
public const PRODUCT_ID = 'product_id';
|
public const PRODUCTS = 'products';
|
||||||
|
public const PRODUCT_ID = 'product_id';
|
||||||
public const SIMPLIFIED_CONTACT = 'simplified_contact';
|
public const PRODUCT_QUANTITY = 'product_quantity';
|
||||||
|
public const PRODUCT_VARIATIONS = 'product_variations';
|
||||||
public const SHIPPING_METHOD = 'shipping_method';
|
public const PRODUCT_EXTRA = 'product_extra';
|
||||||
|
public const PRODUCT_BOOKING = 'product_booking';
|
||||||
public const SHIPPING_CONTACT = 'shipping_contact';
|
|
||||||
|
|
||||||
|
public const SIMPLIFIED_CONTACT = 'simplified_contact';
|
||||||
|
public const SHIPPING_METHOD = 'shipping_method';
|
||||||
|
public const SHIPPING_CONTACT = 'shipping_contact';
|
||||||
public const SHIPPING_CONTACT_INVALID = 'shipping Contact Invalid';
|
public const SHIPPING_CONTACT_INVALID = 'shipping Contact Invalid';
|
||||||
|
public const BILLING_CONTACT = 'billing_contact';
|
||||||
|
|
||||||
public const NONCE = 'nonce';
|
public const NONCE = 'nonce';
|
||||||
|
|
||||||
public const WCNONCE = 'woocommerce-process-checkout-nonce';
|
public const WCNONCE = 'woocommerce-process-checkout-nonce';
|
||||||
|
|
||||||
public const CREATE_ORDER_CART_REQUIRED_FIELDS =
|
public const CREATE_ORDER_CART_REQUIRED_FIELDS =
|
||||||
|
@ -83,25 +84,16 @@ class PropertiesDictionary {
|
||||||
self::SHIPPING_CONTACT,
|
self::SHIPPING_CONTACT,
|
||||||
);
|
);
|
||||||
|
|
||||||
public const PRODUCT_QUANTITY = 'product_quantity';
|
|
||||||
|
|
||||||
public const CALLER_PAGE = 'caller_page';
|
public const CALLER_PAGE = 'caller_page';
|
||||||
|
|
||||||
public const BILLING_CONTACT = 'billing_contact';
|
|
||||||
|
|
||||||
public const NEED_SHIPPING = 'need_shipping';
|
public const NEED_SHIPPING = 'need_shipping';
|
||||||
|
|
||||||
public const UPDATE_SHIPPING_CONTACT = 'ppcp_update_shipping_contact';
|
public const UPDATE_SHIPPING_CONTACT = 'ppcp_update_shipping_contact';
|
||||||
|
public const UPDATE_SHIPPING_METHOD = 'ppcp_update_shipping_method';
|
||||||
public const UPDATE_SHIPPING_METHOD = 'ppcp_update_shipping_method';
|
public const CREATE_ORDER = 'ppcp_create_order';
|
||||||
|
public const CREATE_ORDER_CART = 'ppcp_create_order_cart';
|
||||||
public const CREATE_ORDER = 'ppcp_create_order';
|
public const REDIRECT = 'ppcp_redirect';
|
||||||
|
public const VALIDATE = 'ppcp_validate';
|
||||||
public const CREATE_ORDER_CART = 'ppcp_create_order_cart';
|
|
||||||
|
|
||||||
public const REDIRECT = 'ppcp_redirect';
|
|
||||||
|
|
||||||
public const VALIDATE = 'ppcp_validate';
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the possible list of button colors.
|
* Returns the possible list of button colors.
|
||||||
|
|
|
@ -12,6 +12,7 @@ namespace WooCommerce\PayPalCommerce\Button;
|
||||||
use WooCommerce\PayPalCommerce\Button\Endpoint\ApproveSubscriptionEndpoint;
|
use WooCommerce\PayPalCommerce\Button\Endpoint\ApproveSubscriptionEndpoint;
|
||||||
use WooCommerce\PayPalCommerce\Button\Endpoint\CartScriptParamsEndpoint;
|
use WooCommerce\PayPalCommerce\Button\Endpoint\CartScriptParamsEndpoint;
|
||||||
use WooCommerce\PayPalCommerce\Button\Endpoint\SimulateCartEndpoint;
|
use WooCommerce\PayPalCommerce\Button\Endpoint\SimulateCartEndpoint;
|
||||||
|
use WooCommerce\PayPalCommerce\Button\Helper\CartProductsHelper;
|
||||||
use WooCommerce\PayPalCommerce\Button\Helper\CheckoutFormSaver;
|
use WooCommerce\PayPalCommerce\Button\Helper\CheckoutFormSaver;
|
||||||
use WooCommerce\PayPalCommerce\Button\Endpoint\SaveCheckoutFormEndpoint;
|
use WooCommerce\PayPalCommerce\Button\Endpoint\SaveCheckoutFormEndpoint;
|
||||||
use WooCommerce\PayPalCommerce\Button\Validation\CheckoutFormValidator;
|
use WooCommerce\PayPalCommerce\Button\Validation\CheckoutFormValidator;
|
||||||
|
@ -128,24 +129,24 @@ return array(
|
||||||
if ( ! \WC()->cart ) {
|
if ( ! \WC()->cart ) {
|
||||||
throw new RuntimeException( 'cant initialize endpoint at this moment' );
|
throw new RuntimeException( 'cant initialize endpoint at this moment' );
|
||||||
}
|
}
|
||||||
$smart_button = $container->get( 'button.smart-button' );
|
$smart_button = $container->get( 'button.smart-button' );
|
||||||
$cart = WC()->cart;
|
$cart = WC()->cart;
|
||||||
$request_data = $container->get( 'button.request-data' );
|
$request_data = $container->get( 'button.request-data' );
|
||||||
$data_store = \WC_Data_Store::load( 'product' );
|
$cart_products = $container->get( 'button.helper.cart-products' );
|
||||||
$logger = $container->get( 'woocommerce.logger.woocommerce' );
|
$logger = $container->get( 'woocommerce.logger.woocommerce' );
|
||||||
return new SimulateCartEndpoint( $smart_button, $cart, $request_data, $data_store, $logger );
|
return new SimulateCartEndpoint( $smart_button, $cart, $request_data, $cart_products, $logger );
|
||||||
},
|
},
|
||||||
'button.endpoint.change-cart' => static function ( ContainerInterface $container ): ChangeCartEndpoint {
|
'button.endpoint.change-cart' => static function ( ContainerInterface $container ): ChangeCartEndpoint {
|
||||||
if ( ! \WC()->cart ) {
|
if ( ! \WC()->cart ) {
|
||||||
throw new RuntimeException( 'cant initialize endpoint at this moment' );
|
throw new RuntimeException( 'cant initialize endpoint at this moment' );
|
||||||
}
|
}
|
||||||
$cart = WC()->cart;
|
$cart = WC()->cart;
|
||||||
$shipping = WC()->shipping();
|
$shipping = WC()->shipping();
|
||||||
$request_data = $container->get( 'button.request-data' );
|
$request_data = $container->get( 'button.request-data' );
|
||||||
$purchase_unit_factory = $container->get( 'api.factory.purchase-unit' );
|
$purchase_unit_factory = $container->get( 'api.factory.purchase-unit' );
|
||||||
$data_store = \WC_Data_Store::load( 'product' );
|
$cart_products = $container->get( 'button.helper.cart-products' );
|
||||||
$logger = $container->get( 'woocommerce.logger.woocommerce' );
|
$logger = $container->get( 'woocommerce.logger.woocommerce' );
|
||||||
return new ChangeCartEndpoint( $cart, $shipping, $request_data, $purchase_unit_factory, $data_store, $logger );
|
return new ChangeCartEndpoint( $cart, $shipping, $request_data, $purchase_unit_factory, $cart_products, $logger );
|
||||||
},
|
},
|
||||||
'button.endpoint.create-order' => static function ( ContainerInterface $container ): CreateOrderEndpoint {
|
'button.endpoint.create-order' => static function ( ContainerInterface $container ): CreateOrderEndpoint {
|
||||||
$request_data = $container->get( 'button.request-data' );
|
$request_data = $container->get( 'button.request-data' );
|
||||||
|
@ -251,6 +252,12 @@ return array(
|
||||||
$container->get( 'woocommerce.logger.woocommerce' )
|
$container->get( 'woocommerce.logger.woocommerce' )
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
|
|
||||||
|
'button.helper.cart-products' => static function ( ContainerInterface $container ): CartProductsHelper {
|
||||||
|
$data_store = \WC_Data_Store::load( 'product' );
|
||||||
|
return new CartProductsHelper( $data_store );
|
||||||
|
},
|
||||||
|
|
||||||
'button.helper.three-d-secure' => static function ( ContainerInterface $container ): ThreeDSecure {
|
'button.helper.three-d-secure' => static function ( ContainerInterface $container ): ThreeDSecure {
|
||||||
$logger = $container->get( 'woocommerce.logger.woocommerce' );
|
$logger = $container->get( 'woocommerce.logger.woocommerce' );
|
||||||
return new ThreeDSecure( $logger );
|
return new ThreeDSecure( $logger );
|
||||||
|
|
|
@ -10,6 +10,7 @@ namespace WooCommerce\PayPalCommerce\Button\Endpoint;
|
||||||
use Exception;
|
use Exception;
|
||||||
use Psr\Log\LoggerInterface;
|
use Psr\Log\LoggerInterface;
|
||||||
use WooCommerce\PayPalCommerce\ApiClient\Exception\PayPalApiException;
|
use WooCommerce\PayPalCommerce\ApiClient\Exception\PayPalApiException;
|
||||||
|
use WooCommerce\PayPalCommerce\Button\Helper\CartProductsHelper;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Abstract Class AbstractCartEndpoint
|
* Abstract Class AbstractCartEndpoint
|
||||||
|
@ -26,11 +27,11 @@ abstract class AbstractCartEndpoint implements EndpointInterface {
|
||||||
protected $cart;
|
protected $cart;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The product data store.
|
* The cart products helper.
|
||||||
*
|
*
|
||||||
* @var \WC_Data_Store
|
* @var CartProductsHelper
|
||||||
*/
|
*/
|
||||||
protected $product_data_store;
|
protected $cart_products;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The request data helper.
|
* The request data helper.
|
||||||
|
@ -53,13 +54,6 @@ abstract class AbstractCartEndpoint implements EndpointInterface {
|
||||||
*/
|
*/
|
||||||
protected $logger_tag = '';
|
protected $logger_tag = '';
|
||||||
|
|
||||||
/**
|
|
||||||
* The added cart item IDs
|
|
||||||
*
|
|
||||||
* @var array
|
|
||||||
*/
|
|
||||||
private $cart_item_keys = array();
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The nonce.
|
* The nonce.
|
||||||
*
|
*
|
||||||
|
@ -110,44 +104,13 @@ abstract class AbstractCartEndpoint implements EndpointInterface {
|
||||||
protected function add_products( array $products ): bool {
|
protected function add_products( array $products ): bool {
|
||||||
$this->cart->empty_cart( false );
|
$this->cart->empty_cart( false );
|
||||||
|
|
||||||
$success = true;
|
try {
|
||||||
foreach ( $products as $product ) {
|
$this->cart_products->add_products( $products );
|
||||||
|
} catch ( Exception $e ) {
|
||||||
// Add extras to POST, they are usually added by custom plugins.
|
|
||||||
if ( $product['extra'] && is_array( $product['extra'] ) ) {
|
|
||||||
// Handle cases like field[].
|
|
||||||
$query = http_build_query( $product['extra'] );
|
|
||||||
parse_str( $query, $extra );
|
|
||||||
|
|
||||||
foreach ( $extra as $key => $value ) {
|
|
||||||
$_POST[ $key ] = $value;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
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();
|
$this->handle_error();
|
||||||
}
|
}
|
||||||
|
|
||||||
return $success;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -193,7 +156,7 @@ abstract class AbstractCartEndpoint implements EndpointInterface {
|
||||||
*/
|
*/
|
||||||
protected function products_from_request() {
|
protected function products_from_request() {
|
||||||
$data = $this->request_data->read_request( $this->nonce() );
|
$data = $this->request_data->read_request( $this->nonce() );
|
||||||
$products = $this->products_from_data( $data );
|
$products = $this->cart_products->products_from_data( $data );
|
||||||
if ( ! $products ) {
|
if ( ! $products ) {
|
||||||
wp_send_json_error(
|
wp_send_json_error(
|
||||||
array(
|
array(
|
||||||
|
@ -212,141 +175,12 @@ abstract class AbstractCartEndpoint implements EndpointInterface {
|
||||||
return $products;
|
return $products;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns product information from a data array.
|
|
||||||
*
|
|
||||||
* @param array $data The data array.
|
|
||||||
*
|
|
||||||
* @return array|null
|
|
||||||
*/
|
|
||||||
protected function products_from_data( array $data ): ?array {
|
|
||||||
|
|
||||||
$products = array();
|
|
||||||
|
|
||||||
if (
|
|
||||||
! isset( $data['products'] )
|
|
||||||
|| ! is_array( $data['products'] )
|
|
||||||
) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
foreach ( $data['products'] as $product ) {
|
|
||||||
if ( ! isset( $product['quantity'] ) || ! isset( $product['id'] ) ) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
$wc_product = wc_get_product( (int) $product['id'] );
|
|
||||||
|
|
||||||
if ( ! $wc_product ) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
$products[] = array(
|
|
||||||
'product' => $wc_product,
|
|
||||||
'quantity' => (int) $product['quantity'],
|
|
||||||
'variations' => $product['variations'] ?? null,
|
|
||||||
'booking' => $product['booking'] ?? null,
|
|
||||||
'extra' => $product['extra'] ?? null,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
return $products;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Adds a product to the cart.
|
|
||||||
*
|
|
||||||
* @param \WC_Product $product The Product.
|
|
||||||
* @param int $quantity The Quantity.
|
|
||||||
*
|
|
||||||
* @return bool
|
|
||||||
* @throws Exception When product could not be added.
|
|
||||||
*/
|
|
||||||
private function add_product( \WC_Product $product, int $quantity ): bool {
|
|
||||||
$cart_item_key = $this->cart->add_to_cart( $product->get_id(), $quantity );
|
|
||||||
|
|
||||||
if ( $cart_item_key ) {
|
|
||||||
$this->cart_item_keys[] = $cart_item_key;
|
|
||||||
}
|
|
||||||
return false !== $cart_item_key;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Adds variations to the cart.
|
|
||||||
*
|
|
||||||
* @param \WC_Product $product The Product.
|
|
||||||
* @param int $quantity The Quantity.
|
|
||||||
* @param array $post_variations The variations.
|
|
||||||
*
|
|
||||||
* @return bool
|
|
||||||
* @throws Exception When product could not be added.
|
|
||||||
*/
|
|
||||||
private function add_variable_product(
|
|
||||||
\WC_Product $product,
|
|
||||||
int $quantity,
|
|
||||||
array $post_variations
|
|
||||||
): bool {
|
|
||||||
|
|
||||||
$variations = array();
|
|
||||||
foreach ( $post_variations as $key => $value ) {
|
|
||||||
$variations[ $value['name'] ] = $value['value'];
|
|
||||||
}
|
|
||||||
|
|
||||||
$variation_id = $this->product_data_store->find_matching_product_variation( $product, $variations );
|
|
||||||
|
|
||||||
// ToDo: Check stock status for variation.
|
|
||||||
$cart_item_key = $this->cart->add_to_cart(
|
|
||||||
$product->get_id(),
|
|
||||||
$quantity,
|
|
||||||
$variation_id,
|
|
||||||
$variations
|
|
||||||
);
|
|
||||||
|
|
||||||
if ( $cart_item_key ) {
|
|
||||||
$this->cart_item_keys[] = $cart_item_key;
|
|
||||||
}
|
|
||||||
return false !== $cart_item_key;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Adds booking 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 ),
|
|
||||||
);
|
|
||||||
|
|
||||||
$cart_item_key = $this->cart->add_to_cart( $product->get_id(), 1, 0, array(), $cart_item_data );
|
|
||||||
|
|
||||||
if ( $cart_item_key ) {
|
|
||||||
$this->cart_item_keys[] = $cart_item_key;
|
|
||||||
}
|
|
||||||
return false !== $cart_item_key;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Removes stored cart items from WooCommerce cart.
|
* Removes stored cart items from WooCommerce cart.
|
||||||
*
|
*
|
||||||
* @return void
|
* @return void
|
||||||
*/
|
*/
|
||||||
protected function remove_cart_items(): void {
|
protected function remove_cart_items(): void {
|
||||||
foreach ( $this->cart_item_keys as $cart_item_key ) {
|
$this->cart_products->remove_cart_items();
|
||||||
if ( ! $cart_item_key ) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
$this->cart->remove_cart_item( $cart_item_key );
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -12,6 +12,7 @@ namespace WooCommerce\PayPalCommerce\Button\Endpoint;
|
||||||
use Exception;
|
use Exception;
|
||||||
use Psr\Log\LoggerInterface;
|
use Psr\Log\LoggerInterface;
|
||||||
use WooCommerce\PayPalCommerce\ApiClient\Factory\PurchaseUnitFactory;
|
use WooCommerce\PayPalCommerce\ApiClient\Factory\PurchaseUnitFactory;
|
||||||
|
use WooCommerce\PayPalCommerce\Button\Helper\CartProductsHelper;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Class ChangeCartEndpoint
|
* Class ChangeCartEndpoint
|
||||||
|
@ -41,7 +42,7 @@ class ChangeCartEndpoint extends AbstractCartEndpoint {
|
||||||
* @param \WC_Shipping $shipping The current WC shipping object.
|
* @param \WC_Shipping $shipping The current WC shipping object.
|
||||||
* @param RequestData $request_data The request data helper.
|
* @param RequestData $request_data The request data helper.
|
||||||
* @param PurchaseUnitFactory $purchase_unit_factory The PurchaseUnit factory.
|
* @param PurchaseUnitFactory $purchase_unit_factory The PurchaseUnit factory.
|
||||||
* @param \WC_Data_Store $product_data_store The data store for products.
|
* @param CartProductsHelper $cart_products The cart products helper.
|
||||||
* @param LoggerInterface $logger The logger.
|
* @param LoggerInterface $logger The logger.
|
||||||
*/
|
*/
|
||||||
public function __construct(
|
public function __construct(
|
||||||
|
@ -49,7 +50,7 @@ class ChangeCartEndpoint extends AbstractCartEndpoint {
|
||||||
\WC_Shipping $shipping,
|
\WC_Shipping $shipping,
|
||||||
RequestData $request_data,
|
RequestData $request_data,
|
||||||
PurchaseUnitFactory $purchase_unit_factory,
|
PurchaseUnitFactory $purchase_unit_factory,
|
||||||
\WC_Data_Store $product_data_store,
|
CartProductsHelper $cart_products,
|
||||||
LoggerInterface $logger
|
LoggerInterface $logger
|
||||||
) {
|
) {
|
||||||
|
|
||||||
|
@ -57,7 +58,7 @@ class ChangeCartEndpoint extends AbstractCartEndpoint {
|
||||||
$this->shipping = $shipping;
|
$this->shipping = $shipping;
|
||||||
$this->request_data = $request_data;
|
$this->request_data = $request_data;
|
||||||
$this->purchase_unit_factory = $purchase_unit_factory;
|
$this->purchase_unit_factory = $purchase_unit_factory;
|
||||||
$this->product_data_store = $product_data_store;
|
$this->cart_products = $cart_products;
|
||||||
$this->logger = $logger;
|
$this->logger = $logger;
|
||||||
|
|
||||||
$this->logger_tag = 'updating';
|
$this->logger_tag = 'updating';
|
||||||
|
@ -70,6 +71,8 @@ class ChangeCartEndpoint extends AbstractCartEndpoint {
|
||||||
* @throws Exception On error.
|
* @throws Exception On error.
|
||||||
*/
|
*/
|
||||||
protected function handle_data(): bool {
|
protected function handle_data(): bool {
|
||||||
|
$this->cart_products->set_cart( $this->cart );
|
||||||
|
|
||||||
$products = $this->products_from_request();
|
$products = $this->products_from_request();
|
||||||
|
|
||||||
if ( ! $products ) {
|
if ( ! $products ) {
|
||||||
|
|
|
@ -13,6 +13,7 @@ use Exception;
|
||||||
use Psr\Log\LoggerInterface;
|
use Psr\Log\LoggerInterface;
|
||||||
use WooCommerce\PayPalCommerce\ApiClient\Entity\Money;
|
use WooCommerce\PayPalCommerce\ApiClient\Entity\Money;
|
||||||
use WooCommerce\PayPalCommerce\Button\Assets\SmartButton;
|
use WooCommerce\PayPalCommerce\Button\Assets\SmartButton;
|
||||||
|
use WooCommerce\PayPalCommerce\Button\Helper\CartProductsHelper;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Class SimulateCartEndpoint
|
* Class SimulateCartEndpoint
|
||||||
|
@ -38,23 +39,23 @@ class SimulateCartEndpoint extends AbstractCartEndpoint {
|
||||||
/**
|
/**
|
||||||
* ChangeCartEndpoint constructor.
|
* ChangeCartEndpoint constructor.
|
||||||
*
|
*
|
||||||
* @param SmartButton $smart_button The SmartButton.
|
* @param SmartButton $smart_button The SmartButton.
|
||||||
* @param \WC_Cart $cart The current WC cart object.
|
* @param \WC_Cart $cart The current WC cart object.
|
||||||
* @param RequestData $request_data The request data helper.
|
* @param RequestData $request_data The request data helper.
|
||||||
* @param \WC_Data_Store $product_data_store The data store for products.
|
* @param CartProductsHelper $cart_products The cart products helper.
|
||||||
* @param LoggerInterface $logger The logger.
|
* @param LoggerInterface $logger The logger.
|
||||||
*/
|
*/
|
||||||
public function __construct(
|
public function __construct(
|
||||||
SmartButton $smart_button,
|
SmartButton $smart_button,
|
||||||
\WC_Cart $cart,
|
\WC_Cart $cart,
|
||||||
RequestData $request_data,
|
RequestData $request_data,
|
||||||
\WC_Data_Store $product_data_store,
|
CartProductsHelper $cart_products,
|
||||||
LoggerInterface $logger
|
LoggerInterface $logger
|
||||||
) {
|
) {
|
||||||
$this->smart_button = $smart_button;
|
$this->smart_button = $smart_button;
|
||||||
$this->cart = clone $cart;
|
$this->cart = clone $cart;
|
||||||
$this->request_data = $request_data;
|
$this->request_data = $request_data;
|
||||||
$this->product_data_store = $product_data_store;
|
$this->cart_products = $cart_products;
|
||||||
$this->logger = $logger;
|
$this->logger = $logger;
|
||||||
|
|
||||||
$this->logger_tag = 'simulation';
|
$this->logger_tag = 'simulation';
|
||||||
|
@ -147,6 +148,7 @@ class SimulateCartEndpoint extends AbstractCartEndpoint {
|
||||||
// Store a reference to the real cart.
|
// Store a reference to the real cart.
|
||||||
$this->real_cart = WC()->cart;
|
$this->real_cart = WC()->cart;
|
||||||
WC()->cart = $this->cart;
|
WC()->cart = $this->cart;
|
||||||
|
$this->cart_products->set_cart( $this->cart );
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
286
modules/ppcp-button/src/Helper/CartProductsHelper.php
Normal file
286
modules/ppcp-button/src/Helper/CartProductsHelper.php
Normal file
|
@ -0,0 +1,286 @@
|
||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* Handles the adding of products to WooCommerce cart.
|
||||||
|
*
|
||||||
|
* @package WooCommerce\PayPalCommerce\Button\Helper
|
||||||
|
*/
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace WooCommerce\PayPalCommerce\Button\Helper;
|
||||||
|
|
||||||
|
use Exception;
|
||||||
|
use WC_Cart;
|
||||||
|
use WC_Data_Store;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Class CartProductsHelper
|
||||||
|
*/
|
||||||
|
class CartProductsHelper {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The cart
|
||||||
|
*
|
||||||
|
* @var ?WC_Cart
|
||||||
|
*/
|
||||||
|
private $cart;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The product data store.
|
||||||
|
*
|
||||||
|
* @var WC_Data_Store
|
||||||
|
*/
|
||||||
|
protected $product_data_store;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The added cart item IDs
|
||||||
|
*
|
||||||
|
* @var array
|
||||||
|
*/
|
||||||
|
private $cart_item_keys = array();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* CheckoutFormSaver constructor.
|
||||||
|
*
|
||||||
|
* @param WC_Data_Store $product_data_store The data store for products.
|
||||||
|
*/
|
||||||
|
public function __construct(
|
||||||
|
WC_Data_Store $product_data_store
|
||||||
|
) {
|
||||||
|
$this->product_data_store = $product_data_store;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets a new cart instance.
|
||||||
|
*
|
||||||
|
* @param WC_Cart $cart
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function set_cart( WC_Cart $cart ): void {
|
||||||
|
$this->cart = $cart;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns products information from a data array.
|
||||||
|
*
|
||||||
|
* @param array $data The data array.
|
||||||
|
*
|
||||||
|
* @return array|null
|
||||||
|
*/
|
||||||
|
public function products_from_data( array $data ): ?array {
|
||||||
|
|
||||||
|
$products = array();
|
||||||
|
|
||||||
|
if (
|
||||||
|
! isset( $data['products'] )
|
||||||
|
|| ! is_array( $data['products'] )
|
||||||
|
) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
foreach ( $data['products'] as $product ) {
|
||||||
|
$product = $this->products_from_data( $product );
|
||||||
|
if ( $product ) {
|
||||||
|
$products[] = $product;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return $products;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns product information from a data array.
|
||||||
|
*
|
||||||
|
* @param array $product
|
||||||
|
* @return array|null
|
||||||
|
*/
|
||||||
|
public function product_from_data( array $product ): ?array {
|
||||||
|
if ( ! isset( $product['quantity'] ) || ! isset( $product['id'] ) ) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
$wc_product = wc_get_product( (int) $product['id'] );
|
||||||
|
|
||||||
|
if ( ! $wc_product ) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
return array(
|
||||||
|
'product' => $wc_product,
|
||||||
|
'quantity' => (int) $product['quantity'],
|
||||||
|
'variations' => $product['variations'] ?? null,
|
||||||
|
'booking' => $product['booking'] ?? null,
|
||||||
|
'extra' => $product['extra'] ?? null,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adds products to cart.
|
||||||
|
*
|
||||||
|
* @param array $products Array of products to be added to cart.
|
||||||
|
* @return bool
|
||||||
|
* @throws Exception Add to cart methods throw an exception on fail.
|
||||||
|
*/
|
||||||
|
public function add_products( array $products ): bool {
|
||||||
|
$success = true;
|
||||||
|
foreach ( $products as $product ) {
|
||||||
|
|
||||||
|
// Add extras to POST, they are usually added by custom plugins.
|
||||||
|
if ( $product['extra'] && is_array( $product['extra'] ) ) {
|
||||||
|
// Handle cases like field[].
|
||||||
|
$query = http_build_query( $product['extra'] );
|
||||||
|
parse_str( $query, $extra );
|
||||||
|
|
||||||
|
foreach ( $extra as $key => $value ) {
|
||||||
|
$_POST[ $key ] = $value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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 ) {
|
||||||
|
throw new Exception( 'Error adding products to cart.' );
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adds a product to the cart.
|
||||||
|
*
|
||||||
|
* @param \WC_Product $product The Product.
|
||||||
|
* @param int $quantity The Quantity.
|
||||||
|
*
|
||||||
|
* @return bool
|
||||||
|
* @throws Exception When product could not be added.
|
||||||
|
*/
|
||||||
|
public function add_product( \WC_Product $product, int $quantity ): bool {
|
||||||
|
$this->validate_cart();
|
||||||
|
|
||||||
|
$cart_item_key = $this->cart->add_to_cart( $product->get_id(), $quantity );
|
||||||
|
|
||||||
|
if ( $cart_item_key ) {
|
||||||
|
$this->cart_item_keys[] = $cart_item_key;
|
||||||
|
}
|
||||||
|
return false !== $cart_item_key;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adds variations to the cart.
|
||||||
|
*
|
||||||
|
* @param \WC_Product $product The Product.
|
||||||
|
* @param int $quantity The Quantity.
|
||||||
|
* @param array $post_variations The variations.
|
||||||
|
*
|
||||||
|
* @return bool
|
||||||
|
* @throws Exception When product could not be added.
|
||||||
|
*/
|
||||||
|
public function add_variable_product(
|
||||||
|
\WC_Product $product,
|
||||||
|
int $quantity,
|
||||||
|
array $post_variations
|
||||||
|
): bool {
|
||||||
|
$this->validate_cart();
|
||||||
|
|
||||||
|
$variations = array();
|
||||||
|
foreach ( $post_variations as $key => $value ) {
|
||||||
|
$variations[ $value['name'] ] = $value['value'];
|
||||||
|
}
|
||||||
|
|
||||||
|
$variation_id = $this->product_data_store->find_matching_product_variation( $product, $variations );
|
||||||
|
|
||||||
|
// ToDo: Check stock status for variation.
|
||||||
|
$cart_item_key = $this->cart->add_to_cart(
|
||||||
|
$product->get_id(),
|
||||||
|
$quantity,
|
||||||
|
$variation_id,
|
||||||
|
$variations
|
||||||
|
);
|
||||||
|
|
||||||
|
if ( $cart_item_key ) {
|
||||||
|
$this->cart_item_keys[] = $cart_item_key;
|
||||||
|
}
|
||||||
|
return false !== $cart_item_key;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adds booking 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.
|
||||||
|
*/
|
||||||
|
public function add_booking_product(
|
||||||
|
\WC_Product $product,
|
||||||
|
array $data
|
||||||
|
): bool {
|
||||||
|
$this->validate_cart();
|
||||||
|
|
||||||
|
if ( ! is_callable( 'wc_bookings_get_posted_data' ) ) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
$cart_item_data = array(
|
||||||
|
'booking' => wc_bookings_get_posted_data( $data, $product ),
|
||||||
|
);
|
||||||
|
|
||||||
|
$cart_item_key = $this->cart->add_to_cart( $product->get_id(), 1, 0, array(), $cart_item_data );
|
||||||
|
|
||||||
|
if ( $cart_item_key ) {
|
||||||
|
$this->cart_item_keys[] = $cart_item_key;
|
||||||
|
}
|
||||||
|
return false !== $cart_item_key;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Removes stored cart items from WooCommerce cart.
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
* @throws Exception
|
||||||
|
*/
|
||||||
|
public function remove_cart_items(): void {
|
||||||
|
$this->validate_cart();
|
||||||
|
|
||||||
|
foreach ( $this->cart_item_keys as $cart_item_key ) {
|
||||||
|
if ( ! $cart_item_key ) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
$this->cart->remove_cart_item( $cart_item_key );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
public function cart_item_keys(): array {
|
||||||
|
return $this->cart_item_keys;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Throws the cart not set exception.
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
* @throws Exception
|
||||||
|
*/
|
||||||
|
private function validate_cart(): void {
|
||||||
|
if ( ! $this->cart ) {
|
||||||
|
throw new Exception( 'Cart not set.' );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
Loading…
Add table
Add a link
Reference in a new issue