Add Support for product variants on ApplePay

This commit is contained in:
Pedro Silva 2023-10-25 17:52:00 +01:00
parent cb598ccbca
commit 3d293058fb
No known key found for this signature in database
GPG key ID: E2EE20C0669D24B3
11 changed files with 519 additions and 246 deletions

View file

@ -23,9 +23,6 @@ class ApplepayButton {
this.ppcpConfig
);
//PRODUCT DETAIL PAGE
this.refreshContextData();
this.updated_contact_info = []
this.selectedShippingMethod = []
this.nonce = document.getElementById('woocommerce-process-checkout-nonce').value
@ -35,6 +32,21 @@ class ApplepayButton {
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) {
@ -260,6 +272,8 @@ class ApplepayButton {
case 'product':
// Refresh product data that makes the price change.
this.productQuantity = document.querySelector('input.qty').value;
this.products = this.contextHandler.products();
this.log('Products updated', this.products);
break;
}
}
@ -389,6 +403,7 @@ class ApplepayButton {
return {
action: 'ppcp_update_shipping_contact',
product_id: product_id,
products: JSON.stringify(this.products),
caller_page: 'productDetail',
product_quantity: this.productQuantity,
simplified_contact: event.shippingContact,
@ -419,6 +434,7 @@ class ApplepayButton {
action: 'ppcp_update_shipping_method',
shipping_method: event.shippingMethod,
product_id: product_id,
products: JSON.stringify(this.products),
caller_page: 'productDetail',
product_quantity: this.productQuantity,
simplified_contact: this.updated_contact_info,
@ -456,6 +472,7 @@ class ApplepayButton {
action: 'ppcp_create_order',
'caller_page': this.context,
'product_id': this.buttonConfig.product.id ?? null,
'products': JSON.stringify(this.products),
'product_quantity': this.productQuantity ?? null,
'shipping_contact': shippingContact,
'billing_contact': billingContact,

View file

@ -49,12 +49,20 @@ class SingleProductHandler extends BaseHandler {
}
createOrder() {
return this.actionHandler().configuration().createOrder();
}
products() {
return this.actionHandler().getProducts();
}
actionHandler() {
const errorHandler = new ErrorHandler(
this.ppcpConfig.labels.error.generic,
document.querySelector('.woocommerce-notices-wrapper')
);
const actionHandler = new SingleProductActionHandler(
return new SingleProductActionHandler(
this.ppcpConfig,
new UpdateCart(
this.ppcpConfig.ajax.change_cart.endpoint,
@ -63,8 +71,6 @@ class SingleProductHandler extends BaseHandler {
document.querySelector('form.cart'),
errorHandler,
);
return actionHandler.configuration().createOrder();
}
}

View file

@ -100,7 +100,6 @@ return array(
return new DataToAppleButtonScripts( $container->get( 'applepay.sdk_script_url' ), $container->get( 'wcgateway.settings' ) );
},
'applepay.button' => static function ( ContainerInterface $container ): ApplePayButton {
return new ApplePayButton(
$container->get( 'wcgateway.settings' ),
$container->get( 'woocommerce.logger.woocommerce' ),
@ -108,8 +107,9 @@ return array(
$container->get( 'applepay.url' ),
$container->get( 'ppcp.asset-version' ),
$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 {
return new BlocksPaymentMethod(

View file

@ -14,6 +14,7 @@ use Psr\Log\LoggerInterface;
use WC_Cart;
use WC_Order;
use WooCommerce\PayPalCommerce\Button\Assets\ButtonInterface;
use WooCommerce\PayPalCommerce\Button\Helper\CartProductsHelper;
use WooCommerce\PayPalCommerce\WcGateway\Exception\NotFoundException;
use WooCommerce\PayPalCommerce\WcGateway\Helper\SettingsStatus;
use WooCommerce\PayPalCommerce\WcGateway\Processor\OrderProcessor;
@ -25,18 +26,21 @@ use WooCommerce\PayPalCommerce\Webhooks\Handler\RequestHandlerTrait;
*/
class ApplePayButton implements ButtonInterface {
use RequestHandlerTrait;
/**
* The settings.
*
* @var Settings
*/
private $settings;
/**
* The logger.
*
* @var LoggerInterface
*/
private $logger;
/**
* The response templates.
*
@ -58,12 +62,14 @@ class ApplePayButton implements ButtonInterface {
* @var string
*/
protected $id;
/**
* The method title.
*
* @var string
*/
protected $method_title;
/**
* The processor for orders.
*
@ -84,18 +90,21 @@ class ApplePayButton implements ButtonInterface {
* @var string
*/
private $version;
/**
* The module URL.
*
* @var string
*/
private $module_url;
/**
* The data to send to the ApplePay button script.
*
* @var DataToAppleButtonScripts
*/
private $script_data;
/**
* The Settings status helper.
*
@ -103,6 +112,13 @@ class ApplePayButton implements ButtonInterface {
*/
private $settings_status;
/**
* The cart products helper.
*
* @var CartProductsHelper
*/
protected $cart_products;
/**
* PayPalPaymentMethod constructor.
*
@ -113,6 +129,7 @@ class ApplePayButton implements ButtonInterface {
* @param string $version The module version.
* @param DataToAppleButtonScripts $data The data to send to the ApplePay button script.
* @param SettingsStatus $settings_status The settings status helper.
* @param CartProductsHelper $cart_products The cart products helper.
*/
public function __construct(
Settings $settings,
@ -121,7 +138,8 @@ class ApplePayButton implements ButtonInterface {
string $module_url,
string $version,
DataToAppleButtonScripts $data,
SettingsStatus $settings_status
SettingsStatus $settings_status,
CartProductsHelper $cart_products
) {
$this->settings = $settings;
$this->response_templates = new ResponsesToApple();
@ -133,6 +151,7 @@ class ApplePayButton implements ButtonInterface {
$this->version = $version;
$this->script_data = $data;
$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.
* @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 {
$this->save_old_cart();
$cart = WC()->cart;
return $cart->add_to_cart(
(int) $applepay_request_data_object->product_id(),
(int) $applepay_request_data_object->product_quantity()
$this->cart_products->set_cart( WC()->cart );
$product = $this->cart_products->product_from_data(
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];
}
/**

View file

@ -38,13 +38,6 @@ class ApplePayDataObjectHttp {
*/
protected $need_shipping;
/**
* The product id.
*
* @var mixed
*/
protected $product_id = '';
/**
* The caller page.
*
@ -52,6 +45,13 @@ class ApplePayDataObjectHttp {
*/
protected $caller_page;
/**
* The product id.
*
* @var mixed
*/
protected $product_id = '';
/**
* The product quantity.
*
@ -59,6 +59,27 @@ class ApplePayDataObjectHttp {
*/
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.
*
@ -166,6 +187,9 @@ class ApplePayDataObjectHttp {
if ( ! $data ) {
return;
}
$data = $this->preprocess_request_data( $data );
$result = $this->update_required_data(
$data,
PropertiesDictionary::UPDATE_CONTACT_SINGLE_PROD_REQUIRED_FIELDS,
@ -198,6 +222,9 @@ class ApplePayDataObjectHttp {
if ( ! $data ) {
return;
}
$data = $this->preprocess_request_data( $data );
$result = $this->update_required_data(
$data,
PropertiesDictionary::UPDATE_METHOD_SINGLE_PROD_REQUIRED_FIELDS,
@ -226,6 +253,9 @@ class ApplePayDataObjectHttp {
if ( ! $data ) {
return;
}
$data = $this->preprocess_request_data( $data );
$data[ PropertiesDictionary::CALLER_PAGE ] = $caller_page;
$result = $this->update_required_data(
$data,
@ -261,6 +291,27 @@ class ApplePayDataObjectHttp {
$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
* are not empty.
@ -300,7 +351,7 @@ class ApplePayDataObjectHttp {
*/
protected function assign_data_object_values( array $data ): void {
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 ) {
continue;
}
@ -547,6 +598,33 @@ class ApplePayDataObjectHttp {
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.
*
@ -580,7 +658,7 @@ class ApplePayDataObjectHttp {
* @return array|false|null
*/
public function get_filtered_request_data() {
return filter_input_array(
$data = filter_input_array(
INPUT_POST,
array(
PropertiesDictionary::CALLER_PAGE => FILTER_SANITIZE_SPECIAL_CHARS,
@ -604,8 +682,28 @@ class ApplePayDataObjectHttp {
),
PropertiesDictionary::PRODUCT_ID => 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;
}
/**

View file

@ -14,7 +14,6 @@ namespace WooCommerce\PayPalCommerce\Applepay\Assets;
*/
class PropertiesDictionary {
public const BILLING_CONTACT_INVALID = 'billing Contact Invalid';
public const CREATE_ORDER_SINGLE_PROD_REQUIRED_FIELDS =
@ -62,18 +61,20 @@ class PropertiesDictionary {
self::SIMPLIFIED_CONTACT,
);
public const PRODUCT_ID = 'product_id';
public const SIMPLIFIED_CONTACT = 'simplified_contact';
public const SHIPPING_METHOD = 'shipping_method';
public const SHIPPING_CONTACT = 'shipping_contact';
public const PRODUCTS = 'products';
public const PRODUCT_ID = 'product_id';
public const PRODUCT_QUANTITY = 'product_quantity';
public const PRODUCT_VARIATIONS = 'product_variations';
public const PRODUCT_EXTRA = 'product_extra';
public const PRODUCT_BOOKING = 'product_booking';
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 BILLING_CONTACT = 'billing_contact';
public const NONCE = 'nonce';
public const NONCE = 'nonce';
public const WCNONCE = 'woocommerce-process-checkout-nonce';
public const CREATE_ORDER_CART_REQUIRED_FIELDS =
@ -83,25 +84,16 @@ class PropertiesDictionary {
self::SHIPPING_CONTACT,
);
public const PRODUCT_QUANTITY = 'product_quantity';
public const CALLER_PAGE = 'caller_page';
public const BILLING_CONTACT = 'billing_contact';
public const NEED_SHIPPING = 'need_shipping';
public const UPDATE_SHIPPING_CONTACT = 'ppcp_update_shipping_contact';
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 REDIRECT = 'ppcp_redirect';
public const VALIDATE = 'ppcp_validate';
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 REDIRECT = 'ppcp_redirect';
public const VALIDATE = 'ppcp_validate';
/**
* Returns the possible list of button colors.