mirror of
https://github.com/woocommerce/woocommerce-paypal-payments.git
synced 2025-09-07 19:54:15 +08:00
* Add paypal script reloading
* Add button reloading in cart and product page * Add checking filters asynchronously
This commit is contained in:
parent
e207a11b7e
commit
4e50d1d6ba
16 changed files with 626 additions and 529 deletions
|
@ -1384,10 +1384,10 @@ class SmartButton implements SmartButtonInterface {
|
|||
* Checks if PayPal buttons/messages should be rendered for the current page.
|
||||
*
|
||||
* @param string|null $context The context that should be checked, use default otherwise.
|
||||
*
|
||||
* @param float|null $price_total The price total to be considered.
|
||||
* @return bool
|
||||
*/
|
||||
protected function is_button_disabled( string $context = null ): bool {
|
||||
public function is_button_disabled( string $context = null, float $price_total = null ): bool {
|
||||
if ( null === $context ) {
|
||||
$context = $this->context();
|
||||
}
|
||||
|
@ -1415,7 +1415,8 @@ class SmartButton implements SmartButtonInterface {
|
|||
$is_disabled = apply_filters(
|
||||
'woocommerce_paypal_payments_buttons_disabled',
|
||||
null,
|
||||
$context
|
||||
$context,
|
||||
null === $price_total ? $this->get_cart_price_total() : $price_total
|
||||
);
|
||||
|
||||
if ( $is_disabled !== null ) {
|
||||
|
@ -1429,9 +1430,10 @@ class SmartButton implements SmartButtonInterface {
|
|||
* Checks a filter if pay_later/messages should be rendered on a given location / context.
|
||||
*
|
||||
* @param string $location The location.
|
||||
* @param float|null $price_total The price total to be considered.
|
||||
* @return bool
|
||||
*/
|
||||
protected function is_pay_later_filter_enabled_for_location( string $location ): bool {
|
||||
private function is_pay_later_filter_enabled_for_location( string $location, float $price_total = null ): bool {
|
||||
|
||||
if ( 'product' === $location ) {
|
||||
$product = wc_get_product();
|
||||
|
@ -1446,8 +1448,7 @@ class SmartButton implements SmartButtonInterface {
|
|||
$is_disabled = apply_filters(
|
||||
'woocommerce_paypal_payments_product_buttons_paylater_disabled',
|
||||
null,
|
||||
$product,
|
||||
$product->get_price( 'numeric' )
|
||||
$product
|
||||
);
|
||||
|
||||
if ( $is_disabled !== null ) {
|
||||
|
@ -1462,7 +1463,7 @@ class SmartButton implements SmartButtonInterface {
|
|||
'woocommerce_paypal_payments_buttons_paylater_disabled',
|
||||
null,
|
||||
$location,
|
||||
$this->get_cart_price_total()
|
||||
null === $price_total ? $this->get_cart_price_total() : $price_total
|
||||
);
|
||||
|
||||
if ( $is_disabled !== null ) {
|
||||
|
@ -1476,10 +1477,11 @@ class SmartButton implements SmartButtonInterface {
|
|||
* Check whether Pay Later button is enabled for a given location.
|
||||
*
|
||||
* @param string $location The location.
|
||||
* @param float|null $price_total The price total to be considered.
|
||||
* @return bool true if is enabled, otherwise false.
|
||||
*/
|
||||
private function is_pay_later_button_enabled_for_location( string $location ): bool {
|
||||
return $this->is_pay_later_filter_enabled_for_location( $location )
|
||||
public function is_pay_later_button_enabled_for_location( string $location, float $price_total = null ): bool {
|
||||
return $this->is_pay_later_filter_enabled_for_location( $location, $price_total )
|
||||
&& $this->settings_status->is_pay_later_button_enabled_for_location( $location );
|
||||
|
||||
}
|
||||
|
@ -1488,10 +1490,11 @@ class SmartButton implements SmartButtonInterface {
|
|||
* Check whether Pay Later message is enabled for a given location.
|
||||
*
|
||||
* @param string $location The location setting name.
|
||||
* @param float|null $price_total The price total to be considered.
|
||||
* @return bool true if is enabled, otherwise false.
|
||||
*/
|
||||
private function is_pay_later_messaging_enabled_for_location( string $location ): bool {
|
||||
return $this->is_pay_later_filter_enabled_for_location( $location )
|
||||
public function is_pay_later_messaging_enabled_for_location( string $location, float $price_total = null ): bool {
|
||||
return $this->is_pay_later_filter_enabled_for_location( $location, $price_total )
|
||||
&& $this->settings_status->is_pay_later_messaging_enabled_for_location( $location );
|
||||
}
|
||||
|
||||
|
|
315
modules/ppcp-button/src/Endpoint/AbstractCartEndpoint.php
Normal file
315
modules/ppcp-button/src/Endpoint/AbstractCartEndpoint.php
Normal file
|
@ -0,0 +1,315 @@
|
|||
<?php
|
||||
|
||||
namespace WooCommerce\PayPalCommerce\Button\Endpoint;
|
||||
|
||||
use Exception;
|
||||
use Psr\Log\LoggerInterface;
|
||||
use WooCommerce\PayPalCommerce\ApiClient\Exception\PayPalApiException;
|
||||
|
||||
abstract class AbstractCartEndpoint implements EndpointInterface {
|
||||
|
||||
const ENDPOINT = '';
|
||||
|
||||
/**
|
||||
* The current cart object.
|
||||
*
|
||||
* @var \WC_Cart
|
||||
*/
|
||||
protected $cart;
|
||||
|
||||
/**
|
||||
* The product data store.
|
||||
*
|
||||
* @var \WC_Data_Store
|
||||
*/
|
||||
protected $product_data_store;
|
||||
|
||||
/**
|
||||
* The request data helper.
|
||||
*
|
||||
* @var RequestData
|
||||
*/
|
||||
protected $request_data;
|
||||
|
||||
/**
|
||||
* The logger.
|
||||
*
|
||||
* @var LoggerInterface
|
||||
*/
|
||||
protected $logger;
|
||||
|
||||
/**
|
||||
* The tag to be added to logs.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $logger_tag = '';
|
||||
|
||||
/**
|
||||
* The added cart item IDs
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
private $cart_item_keys = [];
|
||||
|
||||
/**
|
||||
* The nonce.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public static function nonce(): string {
|
||||
return static::ENDPOINT;
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles the request.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function handle_request(): bool {
|
||||
try {
|
||||
return $this->handle_data();
|
||||
} catch ( Exception $error ) {
|
||||
$this->logger->error( 'Cart ' . $this->logger_tag . ' failed: ' . $error->getMessage() );
|
||||
|
||||
wp_send_json_error(
|
||||
array(
|
||||
'name' => is_a( $error, PayPalApiException::class ) ? $error->name() : '',
|
||||
'message' => $error->getMessage(),
|
||||
'code' => $error->getCode(),
|
||||
'details' => is_a( $error, PayPalApiException::class ) ? $error->details() : array(),
|
||||
)
|
||||
);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles the request data.
|
||||
*
|
||||
* @return bool
|
||||
* @throws Exception On error.
|
||||
*/
|
||||
abstract protected function handle_data(): bool;
|
||||
|
||||
/**
|
||||
* Adds products to cart.
|
||||
*
|
||||
* @param array $products Array of products to be added to cart.
|
||||
* @return bool
|
||||
* @throws Exception
|
||||
*/
|
||||
protected function add_products( array $products ): bool {
|
||||
$this->cart->empty_cart( false );
|
||||
|
||||
$success = true;
|
||||
foreach ( $products as $product ) {
|
||||
if ( $product['product']->is_type( 'booking' ) ) {
|
||||
$success = $success && $this->add_booking_product(
|
||||
$product['product'],
|
||||
$product['booking']
|
||||
);
|
||||
} elseif ( $product['product']->is_type( 'variable' ) ) {
|
||||
$success = $success && $this->add_variable_product(
|
||||
$product['product'],
|
||||
$product['quantity'],
|
||||
$product['variations']
|
||||
);
|
||||
} else {
|
||||
$success = $success && $this->add_product(
|
||||
$product['product'],
|
||||
$product['quantity']
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
if ( ! $success ) {
|
||||
$this->handle_error();
|
||||
}
|
||||
|
||||
return $success;
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles errors.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
private function handle_error(): void {
|
||||
|
||||
$message = __(
|
||||
'Something went wrong. Action aborted',
|
||||
'woocommerce-paypal-payments'
|
||||
);
|
||||
$errors = wc_get_notices( 'error' );
|
||||
if ( count( $errors ) ) {
|
||||
$message = array_reduce(
|
||||
$errors,
|
||||
static function ( string $add, array $error ): string {
|
||||
return $add . $error['notice'] . ' ';
|
||||
},
|
||||
''
|
||||
);
|
||||
wc_clear_notices();
|
||||
}
|
||||
|
||||
wp_send_json_error(
|
||||
array(
|
||||
'name' => '',
|
||||
'message' => $message,
|
||||
'code' => 0,
|
||||
'details' => array(),
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array|false
|
||||
*/
|
||||
protected function products_from_request() {
|
||||
$data = $this->request_data->read_request( $this->nonce() );
|
||||
$products = $this->products_from_data( $data );
|
||||
if ( ! $products ) {
|
||||
wp_send_json_error(
|
||||
array(
|
||||
'name' => '',
|
||||
'message' => __(
|
||||
'Necessary fields not defined. Action aborted.',
|
||||
'woocommerce-paypal-payments'
|
||||
),
|
||||
'code' => 0,
|
||||
'details' => array(),
|
||||
)
|
||||
);
|
||||
return false;
|
||||
}
|
||||
|
||||
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,
|
||||
);
|
||||
}
|
||||
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 );
|
||||
|
||||
$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
|
||||
);
|
||||
|
||||
$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 );
|
||||
|
||||
$this->cart_item_keys[] = $cart_item_key;
|
||||
return false !== $cart_item_key;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return void
|
||||
*/
|
||||
protected function remove_cart_items(): void {
|
||||
foreach ( $this->cart_item_keys as $cart_item_key ) {
|
||||
$this->cart->remove_cart_item( $cart_item_key );
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -65,11 +65,16 @@ class CartScriptParamsEndpoint implements EndpointInterface {
|
|||
*/
|
||||
public function handle_request(): bool {
|
||||
try {
|
||||
if ( is_callable('wc_maybe_define_constant') ) {
|
||||
wc_maybe_define_constant( 'WOOCOMMERCE_CART', true );
|
||||
}
|
||||
|
||||
$script_data = $this->smart_button->script_data();
|
||||
|
||||
wp_send_json_success(
|
||||
array(
|
||||
'url_params' => $script_data['url_params'],
|
||||
'button' => $script_data['button'],
|
||||
'amount' => WC()->cart->get_total( 'raw' ),
|
||||
)
|
||||
);
|
||||
|
|
|
@ -11,26 +11,15 @@ namespace WooCommerce\PayPalCommerce\Button\Endpoint;
|
|||
|
||||
use Exception;
|
||||
use Psr\Log\LoggerInterface;
|
||||
use WooCommerce\PayPalCommerce\ApiClient\Entity\PurchaseUnit;
|
||||
use WooCommerce\PayPalCommerce\ApiClient\Exception\PayPalApiException;
|
||||
use WooCommerce\PayPalCommerce\ApiClient\Factory\PurchaseUnitFactory;
|
||||
use WooCommerce\PayPalCommerce\Button\Exception\RuntimeException;
|
||||
|
||||
/**
|
||||
* Class ChangeCartEndpoint
|
||||
*/
|
||||
class ChangeCartEndpoint implements EndpointInterface {
|
||||
|
||||
class ChangeCartEndpoint extends AbstractCartEndpoint {
|
||||
|
||||
const ENDPOINT = 'ppc-change-cart';
|
||||
|
||||
/**
|
||||
* The current cart object.
|
||||
*
|
||||
* @var \WC_Cart
|
||||
*/
|
||||
private $cart;
|
||||
|
||||
/**
|
||||
* The current shipping object.
|
||||
*
|
||||
|
@ -38,13 +27,6 @@ class ChangeCartEndpoint implements EndpointInterface {
|
|||
*/
|
||||
private $shipping;
|
||||
|
||||
/**
|
||||
* The request data helper.
|
||||
*
|
||||
* @var RequestData
|
||||
*/
|
||||
private $request_data;
|
||||
|
||||
/**
|
||||
* The PurchaseUnit factory.
|
||||
*
|
||||
|
@ -52,20 +34,6 @@ class ChangeCartEndpoint implements EndpointInterface {
|
|||
*/
|
||||
private $purchase_unit_factory;
|
||||
|
||||
/**
|
||||
* The product data store.
|
||||
*
|
||||
* @var \WC_Data_Store
|
||||
*/
|
||||
private $product_data_store;
|
||||
|
||||
/**
|
||||
* The logger.
|
||||
*
|
||||
* @var LoggerInterface
|
||||
*/
|
||||
protected $logger;
|
||||
|
||||
/**
|
||||
* ChangeCartEndpoint constructor.
|
||||
*
|
||||
|
@ -91,38 +59,8 @@ class ChangeCartEndpoint implements EndpointInterface {
|
|||
$this->purchase_unit_factory = $purchase_unit_factory;
|
||||
$this->product_data_store = $product_data_store;
|
||||
$this->logger = $logger;
|
||||
}
|
||||
|
||||
/**
|
||||
* The nonce.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public static function nonce(): string {
|
||||
return self::ENDPOINT;
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles the request.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function handle_request(): bool {
|
||||
try {
|
||||
return $this->handle_data();
|
||||
} catch ( Exception $error ) {
|
||||
$this->logger->error( 'Cart updating failed: ' . $error->getMessage() );
|
||||
|
||||
wp_send_json_error(
|
||||
array(
|
||||
'name' => is_a( $error, PayPalApiException::class ) ? $error->name() : '',
|
||||
'message' => $error->getMessage(),
|
||||
'code' => $error->getCode(),
|
||||
'details' => is_a( $error, PayPalApiException::class ) ? $error->details() : array(),
|
||||
)
|
||||
);
|
||||
return false;
|
||||
}
|
||||
$this->logger_tag = 'updating';
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -131,195 +69,19 @@ class ChangeCartEndpoint implements EndpointInterface {
|
|||
* @return bool
|
||||
* @throws Exception On error.
|
||||
*/
|
||||
private function handle_data(): bool {
|
||||
$data = $this->request_data->read_request( $this->nonce() );
|
||||
$products = $this->products_from_data( $data );
|
||||
if ( ! $products ) {
|
||||
wp_send_json_error(
|
||||
array(
|
||||
'name' => '',
|
||||
'message' => __(
|
||||
'Necessary fields not defined. Action aborted.',
|
||||
'woocommerce-paypal-payments'
|
||||
),
|
||||
'code' => 0,
|
||||
'details' => array(),
|
||||
)
|
||||
);
|
||||
protected function handle_data(): bool {
|
||||
if ( ! $products = $this->products_from_request() ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$this->shipping->reset_shipping();
|
||||
$this->cart->empty_cart( false );
|
||||
$success = true;
|
||||
foreach ( $products as $product ) {
|
||||
if ( $product['product']->is_type( 'booking' ) ) {
|
||||
$success = $success && $this->add_booking_product(
|
||||
$product['product'],
|
||||
$product['booking']
|
||||
);
|
||||
} elseif ( $product['product']->is_type( 'variable' ) ) {
|
||||
$success = $success && $this->add_variable_product(
|
||||
$product['product'],
|
||||
$product['quantity'],
|
||||
$product['variations']
|
||||
);
|
||||
} else {
|
||||
$success = $success && $this->add_product(
|
||||
$product['product'],
|
||||
$product['quantity']
|
||||
);
|
||||
}
|
||||
}
|
||||
if ( ! $success ) {
|
||||
$this->handle_error();
|
||||
return $success;
|
||||
}
|
||||
|
||||
wp_send_json_success( $this->generate_purchase_units() );
|
||||
return $success;
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles errors.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
private function handle_error(): bool {
|
||||
|
||||
$message = __(
|
||||
'Something went wrong. Action aborted',
|
||||
'woocommerce-paypal-payments'
|
||||
);
|
||||
$errors = wc_get_notices( 'error' );
|
||||
if ( count( $errors ) ) {
|
||||
$message = array_reduce(
|
||||
$errors,
|
||||
static function ( string $add, array $error ): string {
|
||||
return $add . $error['notice'] . ' ';
|
||||
},
|
||||
''
|
||||
);
|
||||
wc_clear_notices();
|
||||
}
|
||||
|
||||
wp_send_json_error(
|
||||
array(
|
||||
'name' => '',
|
||||
'message' => $message,
|
||||
'code' => 0,
|
||||
'details' => array(),
|
||||
)
|
||||
);
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns product information from an data array.
|
||||
*
|
||||
* @param array $data The data array.
|
||||
*
|
||||
* @return array|null
|
||||
*/
|
||||
private function products_from_data( array $data ) {
|
||||
|
||||
$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,
|
||||
);
|
||||
}
|
||||
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 {
|
||||
return false !== $this->cart->add_to_cart( $product->get_id(), $quantity );
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 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.
|
||||
return false !== $this->cart->add_to_cart(
|
||||
$product->get_id(),
|
||||
$quantity,
|
||||
$variation_id,
|
||||
$variations
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* 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' ) ) {
|
||||
if ( ! $this->add_products($products) ) {
|
||||
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 );
|
||||
wp_send_json_success( $this->generate_purchase_units() );
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -11,95 +11,45 @@ namespace WooCommerce\PayPalCommerce\Button\Endpoint;
|
|||
|
||||
use Exception;
|
||||
use Psr\Log\LoggerInterface;
|
||||
use WooCommerce\PayPalCommerce\ApiClient\Exception\PayPalApiException;
|
||||
use WooCommerce\PayPalCommerce\ApiClient\Factory\PurchaseUnitFactory;
|
||||
use WooCommerce\PayPalCommerce\Button\Assets\SmartButton;
|
||||
|
||||
/**
|
||||
* Class SimulateCartEndpoint
|
||||
*/
|
||||
class SimulateCartEndpoint implements EndpointInterface {
|
||||
class SimulateCartEndpoint extends AbstractCartEndpoint {
|
||||
|
||||
const ENDPOINT = 'ppc-simulate-cart';
|
||||
|
||||
/**
|
||||
* The cart object.
|
||||
* The SmartButton.
|
||||
*
|
||||
* @var \WC_Cart
|
||||
* @var SmartButton
|
||||
*/
|
||||
private $cart;
|
||||
|
||||
/**
|
||||
* The request data helper.
|
||||
*
|
||||
* @var RequestData
|
||||
*/
|
||||
private $request_data;
|
||||
|
||||
/**
|
||||
* The product data store.
|
||||
*
|
||||
* @var \WC_Data_Store
|
||||
*/
|
||||
private $product_data_store;
|
||||
|
||||
/**
|
||||
* The logger.
|
||||
*
|
||||
* @var LoggerInterface
|
||||
*/
|
||||
protected $logger;
|
||||
private $smart_button;
|
||||
|
||||
/**
|
||||
* ChangeCartEndpoint constructor.
|
||||
*
|
||||
* @param SmartButton $smart_button The SmartButton.
|
||||
* @param \WC_Cart $cart The current WC cart object.
|
||||
* @param RequestData $request_data The request data helper.
|
||||
* @param \WC_Data_Store $product_data_store The data store for products.
|
||||
* @param LoggerInterface $logger The logger.
|
||||
*/
|
||||
public function __construct(
|
||||
SmartButton $smart_button,
|
||||
\WC_Cart $cart,
|
||||
RequestData $request_data,
|
||||
\WC_Data_Store $product_data_store,
|
||||
LoggerInterface $logger
|
||||
) {
|
||||
|
||||
$this->smart_button = $smart_button;
|
||||
$this->cart = clone $cart;
|
||||
$this->request_data = $request_data;
|
||||
$this->product_data_store = $product_data_store;
|
||||
$this->logger = $logger;
|
||||
}
|
||||
|
||||
/**
|
||||
* The nonce.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public static function nonce(): string {
|
||||
return self::ENDPOINT;
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles the request.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function handle_request(): bool {
|
||||
try {
|
||||
return $this->handle_data();
|
||||
} catch ( Exception $error ) {
|
||||
$this->logger->error( 'Cart simulation failed: ' . $error->getMessage() );
|
||||
|
||||
wp_send_json_error(
|
||||
array(
|
||||
'name' => is_a( $error, PayPalApiException::class ) ? $error->name() : '',
|
||||
'message' => $error->getMessage(),
|
||||
'code' => $error->getCode(),
|
||||
'details' => is_a( $error, PayPalApiException::class ) ? $error->details() : array(),
|
||||
)
|
||||
);
|
||||
return false;
|
||||
}
|
||||
$this->logger_tag = 'simulation';
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -108,167 +58,44 @@ class SimulateCartEndpoint implements EndpointInterface {
|
|||
* @return bool
|
||||
* @throws Exception On error.
|
||||
*/
|
||||
private function handle_data(): bool {
|
||||
$data = $this->request_data->read_request( $this->nonce() );
|
||||
$products = $this->products_from_data( $data );
|
||||
if ( ! $products ) {
|
||||
wp_send_json_error(
|
||||
array(
|
||||
'name' => '',
|
||||
'message' => __(
|
||||
'Necessary fields not defined. Action aborted.',
|
||||
'woocommerce-paypal-payments'
|
||||
),
|
||||
'code' => 0,
|
||||
'details' => array(),
|
||||
)
|
||||
);
|
||||
protected function handle_data(): bool {
|
||||
if ( ! $products = $this->products_from_request() ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$this->cart->empty_cart( false );
|
||||
$success = true;
|
||||
foreach ( $products as $product ) {
|
||||
$success = $success && ( ! $product['product']->is_type( 'variable' ) ) ?
|
||||
$this->add_product( $product['product'], $product['quantity'] )
|
||||
: $this->add_variable_product(
|
||||
$product['product'],
|
||||
$product['quantity'],
|
||||
$product['variations']
|
||||
);
|
||||
}
|
||||
if ( ! $success ) {
|
||||
$this->handle_error();
|
||||
return $success;
|
||||
// Set WC default cart as the clone.
|
||||
// Store a reference to the real cart.
|
||||
$activeCart = WC()->cart;
|
||||
WC()->cart = $this->cart;
|
||||
|
||||
if ( ! $this->add_products($products) ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$this->cart->calculate_totals();
|
||||
$total = (float) $this->cart->get_total( 'numeric' );
|
||||
|
||||
$total = $this->cart->get_total( 'numeric' );
|
||||
$this->remove_cart_items();
|
||||
|
||||
// Restore cart and unset cart clone
|
||||
WC()->cart = $activeCart;
|
||||
unset( $this->cart );
|
||||
|
||||
wp_send_json_success(
|
||||
array(
|
||||
'total' => $total,
|
||||
)
|
||||
);
|
||||
return $success;
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles errors.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
private function handle_error(): bool {
|
||||
|
||||
$message = __(
|
||||
'Something went wrong. Action aborted',
|
||||
'woocommerce-paypal-payments'
|
||||
);
|
||||
$errors = wc_get_notices( 'error' );
|
||||
if ( count( $errors ) ) {
|
||||
$message = array_reduce(
|
||||
$errors,
|
||||
static function ( string $add, array $error ): string {
|
||||
return $add . $error['notice'] . ' ';
|
||||
},
|
||||
''
|
||||
);
|
||||
wc_clear_notices();
|
||||
}
|
||||
|
||||
wp_send_json_error(
|
||||
array(
|
||||
'name' => '',
|
||||
'message' => $message,
|
||||
'code' => 0,
|
||||
'details' => array(),
|
||||
'funding' => [
|
||||
'paylater' => [
|
||||
'enabled' => $this->smart_button->is_pay_later_button_enabled_for_location( 'cart', $total ),
|
||||
'messaging_enabled' => $this->smart_button->is_pay_later_messaging_enabled_for_location( 'cart', $total ),
|
||||
]
|
||||
],
|
||||
'button' => [
|
||||
'is_disabled' => $this->smart_button->is_button_disabled( 'cart', $total ),
|
||||
]
|
||||
)
|
||||
);
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns product information from an data array.
|
||||
*
|
||||
* @param array $data The data array.
|
||||
*
|
||||
* @return array|null
|
||||
*/
|
||||
private function products_from_data( array $data ) {
|
||||
|
||||
$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' => isset( $product['variations'] ) ? $product['variations'] : 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 {
|
||||
return false !== $this->cart->add_to_cart( $product->get_id(), $quantity );
|
||||
}
|
||||
|
||||
/**
|
||||
* 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.
|
||||
return false !== $this->cart->add_to_cart(
|
||||
$product->get_id(),
|
||||
$quantity,
|
||||
$variation_id,
|
||||
$variations
|
||||
);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue