Add support for WooCommerce Bookings on single product page

This commit is contained in:
Pedro Silva 2023-06-30 10:00:44 +01:00
parent 315ef2c2cd
commit 7b04290eac
No known key found for this signature in database
GPG key ID: E2EE20C0669D24B3
3 changed files with 111 additions and 35 deletions

View file

@ -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,33 +81,51 @@ 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) ) {
} else { fields[element.name] = element.value;
getProducts = () => { }
const products = []; }
this.formElement.querySelectorAll('input[type="number"]').forEach((element) => { return fields;
if (! element.value) {
return;
} }
const elementName = element.getAttribute('name').match(/quantity\[([\d]*)\]/);
if (elementName.length !== 2) { const id = document.querySelector('[name="add-to-cart"]').value;
return; return [new BookingProduct(id, 1, getPrefixedFields(this.formElement, "wc_bookings_field"))];
} }
const id = parseInt(elementName[1]); } else if ( this.isGroupedProduct() ) {
const quantity = parseInt(element.value); return () => {
products.push(new Product(id, quantity, null)); const products = [];
}) this.formElement.querySelectorAll('input[type="number"]').forEach((element) => {
return products; if (! element.value) {
return;
}
const elementName = element.getAttribute('name').match(/quantity\[([\d]*)\]/);
if (elementName.length !== 2) {
return;
}
const id = parseInt(elementName[1]);
const quantity = parseInt(element.value);
products.push(new Product(id, quantity, null));
})
return products;
}
} else {
return () => {
const id = document.querySelector('[name="add-to-cart"]').value;
const qty = document.querySelector('[name="quantity"]').value;
const variations = this.variations();
return [new Product(id, qty, variations)];
}
} }
} })();
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;

View file

@ -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;

View file

@ -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.
* *