mirror of
https://github.com/woocommerce/woocommerce-paypal-payments.git
synced 2025-09-06 18:16:38 +08:00
Add support for WooCommerce Bookings on single product page
This commit is contained in:
parent
315ef2c2cd
commit
7b04290eac
3 changed files with 111 additions and 35 deletions
|
@ -1,4 +1,5 @@
|
||||||
import Product from '../Entity/Product';
|
import Product from '../Entity/Product';
|
||||||
|
import BookingProduct from "../Entity/BookingProduct";
|
||||||
import onApprove from '../OnApproveHandler/onApproveForContinue';
|
import onApprove from '../OnApproveHandler/onApproveForContinue';
|
||||||
import {payerData} from "../Helper/PayerData";
|
import {payerData} from "../Helper/PayerData";
|
||||||
import {PaymentMethods} from "../Helper/CheckoutMethodState";
|
import {PaymentMethods} from "../Helper/CheckoutMethodState";
|
||||||
|
@ -80,16 +81,25 @@ class SingleProductActionHandler {
|
||||||
|
|
||||||
createOrder()
|
createOrder()
|
||||||
{
|
{
|
||||||
var getProducts = null;
|
let getProducts = (() => {
|
||||||
if (! this.isGroupedProduct() ) {
|
if ( this.isBookingProduct() ) {
|
||||||
getProducts = () => {
|
return () => {
|
||||||
const id = document.querySelector('[name="add-to-cart"]').value;
|
|
||||||
const qty = document.querySelector('[name="quantity"]').value;
|
const getPrefixedFields = (formElement, prefix) => {
|
||||||
const variations = this.variations();
|
let fields = {};
|
||||||
return [new Product(id, qty, variations)];
|
for(const element of formElement.elements) {
|
||||||
|
if( element.name.startsWith(prefix) ) {
|
||||||
|
fields[element.name] = element.value;
|
||||||
}
|
}
|
||||||
} else {
|
}
|
||||||
getProducts = () => {
|
return fields;
|
||||||
|
}
|
||||||
|
|
||||||
|
const id = document.querySelector('[name="add-to-cart"]').value;
|
||||||
|
return [new BookingProduct(id, 1, getPrefixedFields(this.formElement, "wc_bookings_field"))];
|
||||||
|
}
|
||||||
|
} else if ( this.isGroupedProduct() ) {
|
||||||
|
return () => {
|
||||||
const products = [];
|
const products = [];
|
||||||
this.formElement.querySelectorAll('input[type="number"]').forEach((element) => {
|
this.formElement.querySelectorAll('input[type="number"]').forEach((element) => {
|
||||||
if (! element.value) {
|
if (! element.value) {
|
||||||
|
@ -105,8 +115,17 @@ class SingleProductActionHandler {
|
||||||
})
|
})
|
||||||
return products;
|
return products;
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
return () => {
|
||||||
|
const id = document.querySelector('[name="add-to-cart"]').value;
|
||||||
|
const qty = document.querySelector('[name="quantity"]').value;
|
||||||
|
const variations = this.variations();
|
||||||
|
return [new Product(id, qty, variations)];
|
||||||
}
|
}
|
||||||
const createOrder = (data, actions) => {
|
}
|
||||||
|
})();
|
||||||
|
|
||||||
|
return (data, actions) => {
|
||||||
this.errorHandler.clear();
|
this.errorHandler.clear();
|
||||||
|
|
||||||
const onResolve = (purchase_units) => {
|
const onResolve = (purchase_units) => {
|
||||||
|
@ -139,19 +158,16 @@ class SingleProductActionHandler {
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
const promise = this.updateCart.update(onResolve, getProducts());
|
return this.updateCart.update(onResolve, getProducts());
|
||||||
return promise;
|
|
||||||
};
|
};
|
||||||
return createOrder;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
variations()
|
variations()
|
||||||
{
|
{
|
||||||
|
|
||||||
if (! this.hasVariations()) {
|
if (! this.hasVariations()) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
const attributes = [...this.formElement.querySelectorAll("[name^='attribute_']")].map(
|
return [...this.formElement.querySelectorAll("[name^='attribute_']")].map(
|
||||||
(element) => {
|
(element) => {
|
||||||
return {
|
return {
|
||||||
value:element.value,
|
value:element.value,
|
||||||
|
@ -159,7 +175,6 @@ class SingleProductActionHandler {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
return attributes;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
hasVariations()
|
hasVariations()
|
||||||
|
@ -171,5 +186,12 @@ class SingleProductActionHandler {
|
||||||
{
|
{
|
||||||
return this.formElement.classList.contains('grouped_form');
|
return this.formElement.classList.contains('grouped_form');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
isBookingProduct()
|
||||||
|
{
|
||||||
|
// detection for "woocommerce-bookings" plugin
|
||||||
|
return !!this.formElement.querySelector('.wc-booking-product-id');
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
export default SingleProductActionHandler;
|
export default SingleProductActionHandler;
|
||||||
|
|
|
@ -0,0 +1,18 @@
|
||||||
|
import Product from "./Product";
|
||||||
|
|
||||||
|
class BookingProduct extends Product {
|
||||||
|
|
||||||
|
constructor(id, quantity, booking) {
|
||||||
|
super(id, quantity, null);
|
||||||
|
this.booking = booking;
|
||||||
|
}
|
||||||
|
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
...super.data(),
|
||||||
|
booking: this.booking
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default BookingProduct;
|
|
@ -153,13 +153,23 @@ class ChangeCartEndpoint implements EndpointInterface {
|
||||||
$this->cart->empty_cart( false );
|
$this->cart->empty_cart( false );
|
||||||
$success = true;
|
$success = true;
|
||||||
foreach ( $products as $product ) {
|
foreach ( $products as $product ) {
|
||||||
$success = $success && ( ! $product['product']->is_type( 'variable' ) ) ?
|
if ( $product['product']->is_type( 'booking' ) ) {
|
||||||
$this->add_product( $product['product'], $product['quantity'] )
|
$success = $success && $this->add_booking_product(
|
||||||
: $this->add_variable_product(
|
$product['product'],
|
||||||
|
$product['booking']
|
||||||
|
);
|
||||||
|
} elseif ( $product['product']->is_type( 'variable' ) ) {
|
||||||
|
$success = $success && $this->add_variable_product(
|
||||||
$product['product'],
|
$product['product'],
|
||||||
$product['quantity'],
|
$product['quantity'],
|
||||||
$product['variations']
|
$product['variations']
|
||||||
);
|
);
|
||||||
|
} else {
|
||||||
|
$success = $success && $this->add_product(
|
||||||
|
$product['product'],
|
||||||
|
$product['quantity']
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if ( ! $success ) {
|
if ( ! $success ) {
|
||||||
$this->handle_error();
|
$this->handle_error();
|
||||||
|
@ -234,7 +244,8 @@ class ChangeCartEndpoint implements EndpointInterface {
|
||||||
$products[] = array(
|
$products[] = array(
|
||||||
'product' => $wc_product,
|
'product' => $wc_product,
|
||||||
'quantity' => (int) $product['quantity'],
|
'quantity' => (int) $product['quantity'],
|
||||||
'variations' => isset( $product['variations'] ) ? $product['variations'] : null,
|
'variations' => $product['variations'] ?? null,
|
||||||
|
'booking' => $product['booking'] ?? null,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
return $products;
|
return $products;
|
||||||
|
@ -286,6 +297,31 @@ class ChangeCartEndpoint implements EndpointInterface {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adds variations to the cart.
|
||||||
|
*
|
||||||
|
* @param \WC_Product $product The Product.
|
||||||
|
* @param array $data Data used by the booking plugin.
|
||||||
|
*
|
||||||
|
* @return bool
|
||||||
|
* @throws Exception When product could not be added.
|
||||||
|
*/
|
||||||
|
private function add_booking_product(
|
||||||
|
\WC_Product $product,
|
||||||
|
array $data
|
||||||
|
): bool {
|
||||||
|
|
||||||
|
if ( ! is_callable( 'wc_bookings_get_posted_data' ) ) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
$cart_item_data = array(
|
||||||
|
'booking' => wc_bookings_get_posted_data( $data, $product ),
|
||||||
|
);
|
||||||
|
|
||||||
|
return false !== $this->cart->add_to_cart( $product->get_id(), 1, 0, array(), $cart_item_data );
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Based on the cart contents, the purchase units are created.
|
* Based on the cart contents, the purchase units are created.
|
||||||
*
|
*
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue