From 2eaf83c3fe2cf4c4fd01b33e8599b1296d1474be Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E2=80=9CVeLiTi=E2=80=9D?= <“info@veliti.nl”> Date: Wed, 12 Feb 2025 11:16:41 +0100 Subject: [PATCH] CMXX - API based checkout --- cart.php | 180 +++--- checkout.php | 575 ++++++++----------- custom/email/order-details-template.php | 6 +- custom/email/order-notification-template.php | 6 +- functions.php | 31 +- product.php | 539 ++++++++--------- products.php | 8 +- script.js | 13 +- 8 files changed, 611 insertions(+), 747 deletions(-) diff --git a/cart.php b/cart.php index 3648d51..916a7b1 100644 --- a/cart.php +++ b/cart.php @@ -1,5 +1,5 @@ prepare('SELECT p.id, pc.category_id, p.* FROM products p LEFT JOIN products_categories pc ON p.id = pc.product_id LEFT JOIN categories c ON c.id = pc.category_id WHERE p.id IN (' . $array_to_question_marks . ') GROUP BY p.id'); - $stmt = $pdo->prepare('SELECT p.*, (SELECT m.full_path FROM products_media pm JOIN media m ON m.id = pm.media_id WHERE pm.product_id = p.id ORDER BY pm.position ASC LIMIT 1) AS img FROM products p WHERE p.id IN (' . $array_to_question_marks . ')'); - // Leverage the array_column function to retrieve only the id's of the products - $stmt->execute(array_column($products_in_cart, 'id')); - // Fetch the products from the database and return the result as an Array - $products = $stmt->fetchAll(PDO::FETCH_ASSOC); - // Iterate the products in cart and add the meta data (product name, desc, etc) - foreach ($products_in_cart as &$cart_product) { - foreach ($products as $product) { - if ($cart_product['id'] == $product['id']) { - $cart_product['meta'] = $product; - // Calculate the subtotal - $subtotal += (float)$cart_product['options_price'] * (int)$cart_product['quantity']; - } - } - } +foreach ($products_in_cart as $num => $product) { + // Calculate the subtotal + $subtotal += (float)$product['options_price'] * (int)$product['quantity']; } -?> - +template_header('Shopping Cart'); + +$view = '
-

+

'.$h1_cart_name.'

- - + + '.$navigation_back_to_store.'

@@ -133,88 +114,105 @@ if ($products_in_cart) { - + - - - + + + - - + '; + if (empty($products_in_cart)){ + $view .= ' - - - - $product): ?> + + '; + } else { + foreach ($products_in_cart as $num => $product){ + + // Ensure product price is a numeric value + $product['options_price'] = isset($product['options_price']) && $product['options_price'] > 0 ? floatval($product['options_price']) : 0.00; + + if (isset($product['options']) && $product['options'] !=''){ + $prod_options = ''; + foreach ($product['options'] as $prod_opt){ + $prod_options .= (${$prod_opt} ?? $prod_opt).', '; + } + } + + $view .= ' - + - - - - - - - - - - - + '; + + if ($product['options'] == $h2_cart_sample_product && !empty(category_id_checkout_samples)){ + + $view .= ' + '; + } else { + $view .= ' + '; + } + $view .= ' + '; + } + } +$view .= '
'.$tr_product.' '.$tr_price.''.$tr_quantity.''.$tr_total.'
'.$cart_message_empty.'
- - - <?=$product['meta']['name']?> - - - '; + if (!empty($product['meta']['img'])){ + $view .= ' + '.$product['meta']['name'].' + '; + } + $view .= ' - + '.(${$product['meta']['name']} ?? $product['meta']['name']).'
- Remove + Remove
- - + '.htmlspecialchars(substr($prod_options, 0,-2), ENT_QUOTES).' + - - - max="" placeholder="Quantity" required> -
'.currency_code.''.number_format($product['options_price'],2).' + + + + '.currency_code.''.number_format($product['options_price'] * $product['quantity'],2).'
- - - - - - - + '; + + //SUGGESTIONS + if (!empty($products_in_cart) && !empty(category_id_checkout_suggestions)){ + $view .= getAccessoiries($pdo,category_id_checkout_suggestions); + } + // SAMPLES + if (!empty($products_in_cart) && !empty(category_id_checkout_samples)){ + $view .= getSamples($pdo,category_id_checkout_samples); + } +$view .= '
- - - + '.$total_subtotal.' + '.currency_code.''.number_format($subtotal,2).' + '.$total_note.'
- - - + + +

- - + + '.$navigation_back_to_store.'

- - +//OUTPUT +echo $view; + +template_footer(); + +?> \ No newline at end of file diff --git a/checkout.php b/checkout.php index 8756867..0817d21 100644 --- a/checkout.php +++ b/checkout.php @@ -1,26 +1,54 @@ '', - 'last_name' => '', - 'address_street' => '', - 'address_city' => '', - 'address_state' => '', - 'address_zip' => '', - 'address_country' => '', - 'role' => 'Member', - 'address_phone' => '' + 'account_id' => $_POST['account_id'] ?? '', + 'email' => $_POST['email'] ?? '', + 'first_name' => $_POST['first_name'] ?? '', + 'last_name' => $_POST['last_name'] ?? '', + 'address_street' => $_POST['address_street'] ?? '', + 'address_city' => $_POST['address_city'] ?? '', + 'address_state' => $_POST['address_state'] ?? '', + 'address_zip' => $_POST['address_zip'] ?? '', + 'address_country' => $_POST['address_country'] ?? '', + 'address_phone' => $_POST['address_phone'] ?? '' ]; +$products_in_cart = isset($_SESSION['cart']) ? $_SESSION['cart'] : []; +$subtotal = 0.00; +$total = 0.00; +$shippingtotal = 0.00; +$discounttotal = 0.00; +$taxtotal = 0.00; +$tax_rate = ''; +$weighttotal = 0; + +$checkout_input = [ + "selected_country" => isset($_POST['address_country']) ? $_POST['address_country'] : $account['address_country'], + "selected_shipment_method" => isset($_POST['shipping_method']) ? $_POST['shipping_method'] : null, + "business_type" => 'b2c', + "discount_code" => isset($_SESSION['discount']) ? $_SESSION['discount'] : null +]; + +$selected_shipping_method_name = ''; +$shipping_methods_available = []; // Error array, output errors on the form $errors = []; + +// --------------------------------------- +// --------------------------------------- +// --------------------------------------- + // Redirect the user if the shopping cart is empty if (empty($_SESSION['cart'])) { header('Location: ' . url('index.php?page=cart')); exit; } + // Check if user is logged in if (isset($_SESSION['account_loggedin'])) { $stmt = $pdo->prepare('SELECT * FROM accounts WHERE id = ?'); @@ -34,173 +62,48 @@ if (isset($_POST['discount_code']) && !empty($_POST['discount_code'])) { } else if (isset($_POST['discount_code']) && empty($_POST['discount_code']) && isset($_SESSION['discount'])) { unset($_SESSION['discount']); } - -// Variables -$products_in_cart = isset($_SESSION['cart']) ? $_SESSION['cart'] : []; -$subtotal = 0.00; -$shippingtotal = 0.00; -$discounttotal = 0.00; -$taxtotal = 0.00; -$weighttotal = 0; -$selected_country = isset($_POST['address_country']) ? $_POST['address_country'] : $account['address_country']; -$selected_shipping_method = isset($_POST['shipping_method']) ? $_POST['shipping_method'] : null; -$selected_shipping_method_name = ''; -$shipping_methods_available = []; -// If there are products in cart +//------------------------------- +// If there are products in cart handle the checkout +//------------------------------- if ($products_in_cart) { - // There are products in the cart so we need to select those products from the database - // Products in cart array to question mark string array, we need the SQL statement to include: IN (?,?,?,...etc) - $array_to_question_marks = implode(',', array_fill(0, count($products_in_cart), '?')); - $stmt = $pdo->prepare('SELECT p.*, (SELECT m.full_path FROM products_media pm JOIN media m ON m.id = pm.media_id WHERE pm.product_id = p.id ORDER BY pm.position ASC LIMIT 1) AS img, (SELECT GROUP_CONCAT(pc.category_id) FROM products_categories pc WHERE pc.product_id = p.id) AS categories FROM products p WHERE p.id IN (' . $array_to_question_marks . ')'); - // We use the array_column to retrieve only the id's of the products - $stmt->execute(array_column($products_in_cart, 'id')); - // Fetch the products from the database and return the result as an Array - $products = $stmt->fetchAll(PDO::FETCH_ASSOC); - // Retrieve the discount code - if (isset($_SESSION['discount'])) { - $stmt = $pdo->prepare('SELECT * FROM discounts WHERE discount_code = ?'); - $stmt->execute([ $_SESSION['discount'] ]); - $discount = $stmt->fetch(PDO::FETCH_ASSOC); - } - - // Get tax - $stmt = $pdo->prepare('SELECT * FROM taxes WHERE country = ?'); - $stmt->execute([ isset($_POST['address_country']) ? $_POST['address_country'] : $account['address_country'] ]); - $tax = $stmt->fetch(PDO::FETCH_ASSOC); - $tax_rate = $tax ? $tax['rate'] : 0.00; - // Get the current date - $current_date = strtotime((new DateTime())->format('Y-m-d H:i:s')); + + //Calculate shopping_cart + $payload = json_encode(array("cart" => $products_in_cart, "checkout_input" => $checkout_input), JSON_UNESCAPED_UNICODE); + $products_in_cart = ioAPIv2('/v2/checkout/',$payload,$clientsecret); + $products_in_cart = json_decode($products_in_cart,true); + + //GET SPECIFIC TOTALS FROM API RESULTS + $subtotal = $products_in_cart['totals']['subtotal']; + $shippingtotal = $products_in_cart['totals']['shippingtotal']; + $discounttotal = $products_in_cart['totals']['discounttotal']; + $taxtotal = $products_in_cart['totals']['taxtotal']; + $tax_rate = $products_in_cart['totals']['tax_rate']; + $weighttotal = $products_in_cart['totals']['weighttotal']; + $total = $products_in_cart['totals']['total']; + + $selected_country = isset($_POST['address_country']) ? $_POST['address_country'] : $account['address_country']; + $selected_shipping_method = isset($_POST['shipping_method']) ? $_POST['shipping_method'] : null; + $selected_shipping_method_name = ''; + // Retrieve shipping methods $stmt = $pdo->query('SELECT * FROM shipping'); $shipping_methods = $stmt->fetchAll(PDO::FETCH_ASSOC); - // Iterate the products in cart and add the meta data (product name, desc, etc) - - foreach ($products_in_cart as &$cart_product) { - foreach ($products as $product) { - if ($cart_product['id'] == $product['id']) { - // If product no longer in stock, prepare for removal - if ((int)$product['quantity'] === 0) { - $cart_product['remove'] = 1; - - } else { - $cart_product['meta'] = $product; - // Prevent the cart quantity exceeding the product quantity - $cart_product['quantity'] = ($cart_product['quantity'] > $product['quantity'] && $product['quantity'] !== -1) ? $product['quantity'] : $cart_product['quantity']; - $product_weight = $cart_product['options_weight']; - $weighttotal += $product_weight; - // Calculate the subtotal - $product_price = (float)$cart_product['options_price']; - $subtotal += $product_price * (int)$cart_product['quantity']; - - // Calculate the final price, which includes tax - $cart_product['final_price'] = $product_price; //+ (($tax_rate / 100) * $product_price); - - //------------------------------- - //TAX ON TOP OFF OF PRICE - //------------------------------- - //$taxtotal += (($tax_rate / 100) * $product_price) * (int)$cart_product['quantity']; - //------------------------------- - //TAX INCLUDED IN PRICE - //------------------------------- - $taxtotal += ($product_price - ($product_price/ (1 + ($tax_rate / 100))))* (int)$cart_product['quantity']; - - //------------------------------- - //------------------------------- - // Check which products are eligible for a discount - if (isset($discount) && $discount && $current_date >= strtotime($discount['start_date']) && $current_date <= strtotime($discount['end_date'])) { - // Check whether product list is empty or if product id is whitelisted - if (empty($discount['product_ids']) || in_array($product['id'], explode(',', $discount['product_ids']))) { - // Check whether category list is empty or if category id is whitelisted - if (empty($discount['category_ids']) || array_intersect(explode(',', $product['categories']), explode(',', $discount['category_ids']))) { - $cart_product['discounted'] = true; - } - } - } - } - } - } - } - - // Remove products that are out of stock - for ($i = 0; $i < count($products_in_cart); $i++) { - if (isset($products_in_cart[$i]['remove'])) { - unset($_SESSION['cart'][$i]); - unset($products_in_cart[$i]); - } - } - $_SESSION['cart'] = array_values($_SESSION['cart']); - $products_in_cart = array_values($products_in_cart); + // Redirect the user if the shopping cart is empty if (empty($products_in_cart)) { header('Location: ' . url('index.php?page=cart')); exit; } - // Calculate the shipping - foreach ($products_in_cart as &$cart_product) { - foreach ($shipping_methods as $shipping_method) { - // Product weight - $product_weight = $cart_product['options_weight'] ? $cart_product['options_weight'] : $weighttotal; - // Determine the price - $product_price = $shipping_method['type'] == 'Single Product' ? (float)$cart_product['options_price'] : $subtotal; - // Check if no country required or if shipping method only available in specified countries - if (empty($shipping_method['countries']) || in_array($selected_country, explode(',', $shipping_method['countries']))) { - // Compare the price and weight to meet shipping method requirements - if ($shipping_method['id'] == $selected_shipping_method && $product_price >= $shipping_method['price_from'] && $product_price <= $shipping_method['price_to'] && $product_weight >= $shipping_method['weight_from'] && $product_weight <= $shipping_method['weight_to']) { - if ($shipping_method['type'] == 'Single Product') { - // Calculate single product price - $cart_product['shipping_price'] += (float)$shipping_method['price'] * (int)$cart_product['quantity']; - $shippingtotal += $cart_product['shipping_price']; - } else { - // Calculate entire order price - $cart_product['shipping_price'] = (float)$shipping_method['price'] / count($products_in_cart); - $shippingtotal = (float)$shipping_method['price']; - } - $shipping_methods_available[] = $shipping_method['id']; - } else if ($product_price >= $shipping_method['price_from'] && $product_price <= $shipping_method['price_to'] && $product_weight >= $shipping_method['weight_from'] && $product_weight <= $shipping_method['weight_to']) { - // No method selected, so store all methods available - $shipping_methods_available[] = $shipping_method['id']; - } - } - // Update selected shipping method name - if ($shipping_method['id'] == $selected_shipping_method) { - $selected_shipping_method_name = $shipping_method['name']; - } - } - } - // Number of discounted products - $num_discounted_products = count(array_column($products_in_cart, 'discounted')); - // Iterate the products and update the price for the discounted products - foreach ($products_in_cart as &$cart_product) { - if (isset($cart_product['discounted']) && $cart_product['discounted']) { - $price = &$cart_product['final_price']; - if ($discount['discount_type'] == 'Percentage') { - $d = (float)$price * ((float)$discount['discount_value'] / 100); - //$price -= $d; - $discounttotal += $d * (int)$cart_product['quantity']; - } - if ($discount['discount_type'] == 'Fixed') { - $d = (float)$discount['discount_value'] / $num_discounted_products; - //$price -= $d / (int)$cart_product['quantity']; - $discounttotal += $d; - } - } - } - -//Override TAXTOTAAL IN CASE OF DISCOUNTS -//------------------------------- -//TAX ON TOP OFF OF PRICE -//------------------------------- -//$taxtotal = ($tax_rate / 100) * (($subtotal) - $discounttotal); -//------------------------------- -//TAX INCLUDED IN PRICE -//------------------------------- - -$taxable_total = $subtotal - $discounttotal; -$taxtotal = $taxable_total - ($taxable_total / (1 + ($tax_rate / 100))); //------------------------------- +// END Checkout handler //------------------------------- } + +//------------------------------- +//Place order +//------------------------------- + // Make sure when the user submits the form all data was submitted and shopping cart is not empty if (isset($_POST['method'], $_POST['first_name'], $_POST['last_name'], $_POST['address_street'], $_POST['address_city'], $_POST['address_state'], $_POST['address_zip'], $_POST['address_country'], $_POST['address_phone'], $_SESSION['cart']) && !isset($_POST['update'])) { $account_id = null; @@ -243,56 +146,42 @@ if (isset($_POST['method'], $_POST['first_name'], $_POST['last_name'], $_POST['a } if (!$errors && $products_in_cart) { - $payment_amount = (($subtotal)-$discounttotal)+$shippingtotal; - // No errors, process the order - if (pay_on_delivery_enabled && $_POST['method'] == 'payondelivery') { - // Process Normal Checkout - // Generate unique transaction ID - $transaction_id = strtoupper(uniqid('SC') . substr(md5(mt_rand()), 0, 5)); - // Insert transaction into database - $stmt = $pdo->prepare('INSERT INTO transactions (txn_id, payment_amount, payment_status, created, payer_email, first_name, last_name, address_street, address_city, address_state, address_zip, address_country, account_id, payment_method, shipping_method, shipping_amount, discount_code, address_phone,tax_amount) VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)'); - $stmt->execute([ - $transaction_id, - $payment_amount, - default_payment_status, - date('Y-m-d H:i:s'), - isset($account['email']) && !empty($account['email']) ? $account['email'] : $_POST['email'], - $_POST['first_name'], - $_POST['last_name'], - $_POST['address_street'], - $_POST['address_city'], - $_POST['address_state'], - $_POST['address_zip'], - $_POST['address_country'], - $account_id, - 'PayOnDelivery', - $selected_shipping_method_name, - $shippingtotal, - isset($_SESSION['discount']) ? $_SESSION['discount'] : '', - $_POST['address_phone'], - $taxtotal - ]); - // Get order ID - $order_id = $pdo->lastInsertId(); - // Iterate products and deduct quantities - foreach ($products_in_cart as $product) { - // For every product in the shopping cart insert a new transaction into our database - $stmt = $pdo->prepare('INSERT INTO transactions_items (txn_id, item_id, item_price, item_quantity, item_options) VALUES (?,?,?,?,?)'); - $stmt->execute([ $transaction_id, $product['id'], $product['final_price'], $product['quantity'], $product['options'] ]); - // Update product quantity in the products table - $stmt = $pdo->prepare('UPDATE products SET quantity = quantity - ? WHERE quantity > 0 AND id = ?'); - $stmt->execute([ $product['quantity'], $product['id'] ]); - // Deduct option quantities - if ($product['options']) { - $options = explode(',', $product['options']); - foreach ($options as $opt) { - $option_name = explode('-', $opt)[0]; - $option_value = explode('-', $opt)[1]; - $stmt = $pdo->prepare('UPDATE products_options SET quantity = quantity - ? WHERE quantity > 0 AND title = ? AND (name = ? OR name = "")'); - $stmt->execute([ $product['quantity'], $option_name, $option_value ]); - } - } - } + //Process checkout + //Calculate shopping_cart + $payload = json_encode(array("cart" => $products_in_cart, "checkout_input" => $checkout_input, "customer_details" => $account), JSON_UNESCAPED_UNICODE); + $place_order = ioAPIv2('/v2/placeorder/',$payload,$clientsecret); + $place_order = json_decode($products_in_cart,true); + + //Check if transaction is succesfull and send order confirmation to customer + if ($place_order['error'] == '' && $place_order['id'] != ''){ + + //SEND CONFIRMATION TO CUSTOMER + send_order_details_email( + $account['email'], + $products_in_cart, + $account['first_name'], + $account['last_name'], + $account['address_street'], + $account['address_city'], + $account['address_state'], + $account['address_zip'], + $account['address_country'], + $place_order['subtotal'], + $place_order['discounttotal'], + $place_order['shippingtotal'], + $place_order['taxtotal'], + $place_order['payment_amount'], + $place_order['transaction_id'] + ); + } + + //Pay on delivery = 2 + if (pay_on_delivery_enabled && $place_order['payment_method'] == 2){ + + //header('Location: ' . url('index.php?page=placeorder')); + //exit; + } + /* //Disable giftcard if (isset($_SESSION['discount'])){ if (preg_match("/[#][0-9]/", $_SESSION['discount']) == 1){ @@ -328,8 +217,7 @@ if (isset($_POST['method'], $_POST['first_name'], $_POST['last_name'], $_POST['a ); header('Location: ' . url('index.php?page=placeorder')); exit; - - } + */ // +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ // Mollie ++++++++++++++++++++++++++++++++++++++++++++++++++++ // +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ @@ -415,7 +303,7 @@ if (isset($_POST['method'], $_POST['first_name'], $_POST['last_name'], $_POST['a /* * Payment parameters: - * amount Amount in EUROs. This example creates a € 10,- payment. + * amount Amount in EUROs. * description Description of the payment. * redirectUrl Redirect location. The customer will be redirected there after the payment. * webhookUrl Webhook location, used to report when the payment changes state. @@ -560,207 +448,197 @@ if (isset($_POST['method'], $_POST['first_name'], $_POST['last_name'], $_POST['a } } - // Preserve form details if the user encounters an error - $account = [ - 'first_name' => $_POST['first_name'], - 'last_name' => $_POST['last_name'], - 'address_street' => $_POST['address_street'], - 'address_city' => $_POST['address_city'], - 'address_state' => $_POST['address_state'], - 'address_zip' => $_POST['address_zip'], - 'address_country' => $_POST['address_country'], - 'address_phone' => $_POST['address_phone'] - ]; } +//------------------------------- +// END PLACE ORDER +//------------------------------- + $terms_link = url('index.php?page=termsandconditions'); -?> - - +template_header('Checkout'); +$view = '
-

+

'.$h1_checkout.'

-

', $errors)?>

+

'.implode('
', $errors).'

'; - -

- + if (!isset($_SESSION['account_loggedin'])){ +$view .= '

'.$account_available.' '.$account_log_in.'

'; + } + $view .= '
-

+

'.$payment_method.'

-
- - > +
'; + if (mollie_enabled){ + $view .= ' - + '.$payment_method_1.' + '.$payment_method_1.' + '; + } - - > - - + if (paypal_enabled){ +$view .= ' + '; + } - - > - - + if (pay_on_delivery_enabled){ +$view .= ' + '; + } -
+$view .= '
'; - + if (!isset($_SESSION['account_loggedin'])){ -

+$view .= ' +

'.$account_create_email.'

- + -

- - +

'.$account_create.((!account_required) ? $account_create_optional : '').'

+ + - - - - -

+ + '; + } +$view .= ' +

'.$h2_Shipping_details.'

- - + +
- - + +
- - + + - - + +
- - + +
- - + +
- - + + - - + +
-

+

'.$h2_shoppingcart.'

- - - - - - - - -
<?=$product['meta']['name']?> x
+ '; + foreach($products_in_cart['cart_details']['products'] as $product){ + + $view .= ' + + + + '; + } +$view .= '
'.$product['meta']['name'].''.$product['quantity'].' x '.$product['meta']['name'].''.currency_code.''.number_format($product['options_price'] * $product['quantity'],2).'
- - - - - - - strtotime($discount['end_date'])): ?> - - - - - + + '; + if (isset($_SESSION['discount'], $products_in_cart['totals']['discounttotal'])){ + $view .= $products_in_cart['totals']['discount_message']; + } +$view .= '
+
'; + + if ($shipping_methods_available){ + $view .= '
+

'.$h3_shipping_method.'

'; -
- -
-

- $method): ?> - -
- > - -
- -
- -
- + foreach($shipping_methods as $k => $method){ + + if (!in_array($method['id'], $shipping_methods_available)){ + $view .= '
+ + +
'; + } + $view .= '
'; + } + } +$view .= '
- - + '.$total_subtotal.' + '.currency_code.''.number_format($subtotal,2).'
- - -
+ '.$total_shipping.' + '.currency_code.''.number_format($shippingtotal,2).' +
'; - 0): ?> -
- - - -
- + if ($discounttotal > 0){ + $view .= '
+ '.$total_discount.' + -'.currency_code.''.number_format(round($discounttotal, 1),2).' +
'; + } - -
- VAT (%) - -
- -
- + if ($taxtotal > 0){ + $view .= '
+ VAT ('.$tax_rate.') + '.currency_code.''.number_format($taxtotal,2).' +
'; + } + $view .= '
- + '.$total_total.' '.$total_total_note.''.currency_code.''.number_format($total,2).'
- + '.$order_consent_1.'
- + '.$order_consent_2.' '.$order_consent_3.'
- +
@@ -769,6 +647,11 @@ $terms_link = url('index.php?page=termsandconditions'); - +'; - \ No newline at end of file +//OUTPUT +echo $view; + +template_footer(); + +?> \ No newline at end of file diff --git a/custom/email/order-details-template.php b/custom/email/order-details-template.php index 6f8ce93..f7453e2 100644 --- a/custom/email/order-details-template.php +++ b/custom/email/order-details-template.php @@ -38,13 +38,13 @@ - + - - + + diff --git a/custom/email/order-notification-template.php b/custom/email/order-notification-template.php index c75e1c0..e4209e7 100644 --- a/custom/email/order-notification-template.php +++ b/custom/email/order-notification-template.php @@ -39,13 +39,13 @@ - + - - + + diff --git a/functions.php b/functions.php index b06dd0c..c8afca7 100644 --- a/functions.php +++ b/functions.php @@ -142,7 +142,7 @@ function send_order_details_email($email, $products, $first_name, $last_name, $a $subject = $subject_order_notification; $headers = 'From: ' . mail_from . "\r\n" . 'Reply-To: ' . $email . "\r\n" . 'Return-Path: ' . mail_from . "\r\n" . 'X-Mailer: PHP/' . phpversion() . "\r\n" . 'MIME-Version: 1.0' . "\r\n" . 'Content-Type: text/html; charset=UTF-8' . "\r\n"; ob_start(); - include './custom/order-notification-template.php'; + include './custom/email/order-notification-template.php'; $order_notification_template = ob_get_clean(); send_mail_by_PHPMailer(email, $subject, $order_notification_template, '', ''); } @@ -152,7 +152,7 @@ function send_order_details_email($email, $products, $first_name, $last_name, $a $subject = $subject_new_order; $headers = 'From: ' . mail_from . "\r\n" . 'Reply-To: ' . mail_from . "\r\n" . 'Return-Path: ' . mail_from . "\r\n" . 'X-Mailer: PHP/' . phpversion() . "\r\n" . 'MIME-Version: 1.0' . "\r\n" . 'Content-Type: text/html; charset=UTF-8' . "\r\n"; ob_start(); - include './custom/order-details-template.php'; + include './custom/email/order-details-template.php'; $order_details_template = ob_get_clean(); send_mail_by_PHPMailer($email, $subject, $order_details_template, '', ''); } @@ -322,7 +322,7 @@ function getAccessoiries($pdo, $categoryID){ $stmt->execute(); $additional_products = $stmt->fetchAll(PDO::FETCH_ASSOC); - echo '
+ $output ='

'.$h2_cart_suggestions.'

'; @@ -333,7 +333,7 @@ function getAccessoiries($pdo, $categoryID){ $url_contents = 'index.php?page=product&id='; $url_contents .= $additional_product['url_slug'] ? $additional_product['url_slug'] : $additional_product['id']; $additional_product_url = url($url_contents); - echo' + $output .=' '; } } - echo '
'; + $output .='
'; + + return $output; } function getSamples($pdo, $categoryID){ @@ -371,7 +373,7 @@ function getSamples($pdo, $categoryID){ $stmt->execute(); $additional_products = $stmt->fetchAll(PDO::FETCH_ASSOC); - echo '
+ $output ='

'.$h2_cart_samples.'

@@ -389,7 +391,7 @@ function getSamples($pdo, $categoryID){ $url_contents = 'index.php?page=product&id='; $url_contents .= $additional_product['url_slug'] ? $additional_product['url_slug'] : $additional_product['id']; $additional_product_url = url($url_contents); - echo' + $output .=' '; } } - echo ' + $output .='
'; + return $output; } function createGiftCart($pdo, $orderID){ @@ -542,7 +545,7 @@ function generateInvoice($pdo, $orderID){ //Generate invoice ob_start(); - include dirname(__FILE__).'/custom/order-invoice-template.php'; + include dirname(__FILE__).'/custom/email/order-invoice-template.php'; $order_invoice_template = ob_get_clean(); return array($order_invoice_template,$customer_email,$order_id); diff --git a/product.php b/product.php index 0644006..1a00956 100644 --- a/product.php +++ b/product.php @@ -1,115 +1,75 @@ prepare('SELECT * FROM products WHERE status = 1 AND (id = ? OR url_slug = ?)'); - $stmt->execute([ $_GET['id'], $_GET['id'] ]); - // Fetch the product from the database and return the result as an Array - $product = $stmt->fetch(PDO::FETCH_ASSOC); + + //GET CATALOG DATA + $product = ioAPIv2('/v2/catalog/product_id='.$_GET['id'],'',$clientsecret); + $product = json_decode($product,true); + $product = $product[0] ?? ''; + // Check if the product exists (array is not empty) if (!$product) { // Output simple error if the id for the product doesn't exists (array is empty) http_response_code(404); exit('Product does not exist!'); } - // Select the product images (if any) from the products_images table - $stmt = $pdo->prepare('SELECT m.*, pm.position FROM products_media pm JOIN media m ON m.id = pm.media_id WHERE pm.product_id = ? ORDER BY pm.position ASC'); - $stmt->execute([ $product['id'] ]); - // Fetch the product images from the database and return the result as an Array - $product_media = $stmt->fetchAll(PDO::FETCH_ASSOC); - // Select the product options (if any) from the products_options table - $stmt = $pdo->prepare('SELECT CONCAT(title, "::", type, "::", required) AS k, name, quantity, price, price_modifier, weight, weight_modifier, type, id, required FROM products_options WHERE product_id = ? ORDER BY position ASC'); - $stmt->execute([ $product['id'] ]); - // Fetch the product options from the database and return the result as an Array - $product_options = $stmt->fetchAll(PDO::FETCH_GROUP); + // Add the HTML meta data (for SEO purposes) $meta = ' - - + + '; - if (isset($product_media[0]) && file_exists($product_media[0]['full_path'])) { - $meta .= ''; + if (isset($product['full_path'])) { + $meta .= ''; } + + //GET RELATED MEDIA + $product_media = ioAPIv2('/v2/products_media/product_id='.$product['rowID'],'',$clientsecret); + $product_media = json_decode($product_media,true); + // If the user clicked the add to cart button - if (isset($_POST['quantity']) && is_numeric($_POST['quantity'])) { - // abs() function will prevent minus quantity and (int) will ensure the value is an integer (number) - $quantity = abs((int)$_POST['quantity']); - // Get product options - $options = ''; - $options_price = (float)$product['price']; - $options_weight = (float)$product['weight']; - // Iterate post data - foreach ($_POST as $k => $v) { - if (strpos($k, 'option-') !== false) { - if (is_array($v)) { - // Option is checkbox or radio element - foreach ($v as $vv) { - if (empty($vv)) continue; - $options .= str_replace(['_', 'option-'], [' ', ''], $k) . '-' . $vv . ','; - $stmt = $pdo->prepare('SELECT * FROM products_options WHERE title = ? AND name = ? AND product_id = ?'); - $stmt->execute([ str_replace(['_', 'option-'], [' ', ''], $k), $vv, $product['id'] ]); - $option = $stmt->fetch(PDO::FETCH_ASSOC); - $options_price = $option['price_modifier'] == 'add' ? $options_price + $option['price'] : $options_price - $option['price']; - $options_weight = $option['weight_modifier'] == 'add' ? $options_weight + $option['weight'] : $options_weight - $option['weight']; - } - } else { - if (empty($v)) continue; - $options .= str_replace(['_', 'option-'], [' ', ''], $k) . '-' . $v . ','; - //------------------ - //Update name otherwise option is not found - //------------------ - $name_update = '%|^|'.$v; - $stmt = $pdo->prepare('SELECT * FROM products_options WHERE title = ? AND name like ? AND product_id = ?'); - $stmt->execute([ str_replace(['_', 'option-'], [' ', ''], $k), $name_update, $product['id'] ]); - //------------------ - // OLD CODE - //------------------ - //$stmt = $pdo->prepare('SELECT * FROM products_options WHERE title = ? AND name = ? AND product_id = ?'); - //$stmt->execute([ str_replace(['_', 'option-'], [' ', ''], $k), $v, $product['id'] ]); - //------------------ - $option = $stmt->fetch(PDO::FETCH_ASSOC); - if (!$option) { - // Option is text or datetime element - $stmt = $pdo->prepare('SELECT * FROM products_options WHERE title = ? AND product_id = ?'); - $stmt->execute([ str_replace(['_', 'option-'], [' ', ''], $k), $product['id'] ]); - $option = $stmt->fetch(PDO::FETCH_ASSOC); - } - $options_price = $option['price_modifier'] == 'add' ? $options_price + $option['price'] : $options_price - $option['price']; - $options_weight = $option['weight_modifier'] == 'add' ? $options_weight + $option['weight'] : $options_weight - $option['weight']; - } - } - } - $options_price = $options_price < 0 ? 0 : $options_price; - $options = rtrim($options, ','); + if (isset($_POST['product'])) { + + //VALIDATE THE INPUT FOR THE SHOPPING CART + $payload = json_encode($_POST['product'], JSON_UNESCAPED_UNICODE); + $product_to_cart = ioAPIv2('/v2/shopping_cart/',$payload,$clientsecret); + $product_to_cart = json_decode($product_to_cart,true); + // Check if the product exists (array is not empty) - if ($quantity > 0) { + if ($product_to_cart['quantity'] > 0) { // Product exists in database, now we can create/update the session variable for the cart if (!isset($_SESSION['cart'])) { // Shopping cart session variable doesnt exist, create it $_SESSION['cart'] = []; } - $cart_product = &get_cart_product($product['id'], $options); + $cart_product = &get_cart_product($product_to_cart['id'], $product_to_cart['options']); if ($cart_product) { // Product exists in cart, update the quanity $cart_product['quantity'] += $quantity; } else { // Product is not in cart, add it - $_SESSION['cart'][] = [ - 'id' => $product['id'], - 'quantity' => $quantity, - 'options' => $options, - 'options_price' => $options_price, - 'options_weight' => $options_weight, - 'shipping_price' => 0.00 - ]; + $_SESSION['cart'][] = $product_to_cart; } } // Prevent form resubmission... - header('Location: ' . url('index.php?page=cart')); - - exit; + header('Location: ' . url('index.php?page=cart')); + exit; } @@ -120,16 +80,11 @@ if (isset($_GET['id'])) { exit('Product does not exist!'); } -//get all media -$stmt = $pdo->query('SELECT id, full_path, caption FROM media'); -$stmt->execute(); -$media2 = $stmt->fetchAll(PDO::FETCH_ASSOC); - //LINK to products page: $products_link = url(link_to_collection); -$product_link = url('index.php?page=product&id='.($product['url_slug'] ? $product['url_slug'] : $product['id'])); +$product_link = url('index.php?page=product&id='.($product['url_slug'] ? $product['url_slug'] : $product['rowID'])); -//Notifier - when 1 user ask for product notification +/*Notifier - when 1 user ask for product notification $notifier = 0; if (isset($_POST["notifier"])){ @@ -140,226 +95,242 @@ if (isset($_POST["notifier"])){ send_product_notification_email($email, $_POST["product_details"]); $notifier = 1; } -//CREATE OPTION_PICTURE ARRAY FOR USE IN OPTION OVERVIEW -$option_profile = json_decode($product['product_config']) ?? ''; -if (!empty($option_profile) && $option_profile !=''){ - //CREATE OPTION PICTURE ARRAY - $option_picture[] = ''; - foreach ($option_profile as $option){ - //CHECK FOR RELATED MEDIA - foreach ($media2 as $media_item2){ - if ($media_item2['id'] == $option->IMG_large_id){ - $option_picture[$option->option_id] = $media_item2['full_path']; - } - } - } +*/ +$view = ''; +template_header((${$product['productname']} ?? $product['productname']), $meta); + +if ($error){ + +$view .='

'.$error.'

'; + } -?> - - - - -

- - - +else { +$view .='
-
- - option_id == $_GET['option_id']){ - $IMG_large_id = $option->IMG_large_id; - foreach ($media2 as $media_item2){ - if ($media_item2['id'] == $IMG_large_id){ - - $IMG_large_path = $media_item2['full_path']; - echo ' -
- '.$media_item2['caption'].' -
'; +
'; + if (isset($_GET['option_id']) && !empty($_GET['option_id']) && $_GET['option_id'] !=''){ + + $fullPath = null; + foreach ($product['configurations'] as $configuration) { + if (isset($configuration['attributes'])) { + foreach ($configuration['attributes'] as $attribute) { + if ($attribute['attribute_id'] == $_GET['option_id']) { + $fullPath = $attribute['alternative_media_full_path'] ?? $attribute['full_path']; + $altTitle = $attribute['alternative_media_title'] ?? $attribute['title']; + $view .=' +
+ '.$altTitle.' +
'; + break 2; // Exit all loops once found } } } - } - ?> - -
- <?=$product_media[0]['caption']?> -
- - -
- + '.(${$product['productname']} ?? $product['productname']).' +
'; + } + $view .=' +
'; //Show small images foreach ($product_media as $media){ - if (isset($_GET['option_id']) && !empty($_GET['option_id']) && $_GET['option_id'] !='' && show_option_images != true){ - $option_profile = json_decode($product['product_config']); - //create array with all option imagesIDs - $option_images = []; - foreach($option_profile as $option){ - $option_images[] = $option->IMG_large_id; - } - if (in_array($media['id'], $option_images)){ - //Do nothing - } else { - echo '
- '.$media['caption'].' -
'; - } + + $view .='
+ +
'; } - else { - //No Option profile - show all images - echo '
- '.$media['caption'].' -
'; - } - } - ?> +$view .='
-
-

/

+ '.$breadcrum_products.'

/ '.(${$product['productname']} ?? $product['productname']).'

-

+ +

'.(${$product['productname']} ?? $product['productname']).'

- - 0): ?> - - -
- -
- -

'.$stock_status.'

- '; - ?> -
- - '.currency_code.''.number_format($product['price'],2).''; + if ($product['rrp'] > 0){ + $view .= ''.currency_code.''.number_format($product['rrp'],2).''; + } +$view .='
+
'; + //Stock status + $stock_status = ($product['quantity'] != 0) ? $product_on_stock : $out_of_stock; + $style = ($stock_status == $product_on_stock) ? 'style="color:green;font-weight: bold;"' : 'style="color:gray;font-weight: lighter;"'; + $view .= ' +

'.$stock_status.'

+
'; +$view .='
'; + //FREE SHIPMENT INDICATOR if (free_shipment_indicator){ freeShipment($product['price'],'div'); + } + +$view .=''; + + //CHECK FOR OPTIONS ASSIGNED + if(isset($product['configurations'])){ + foreach ($product['configurations'] as $configuration) { + //CHECK FOR GROUPS + if (isset($configuration['type']) && $configuration['type'] == 'product'){ + + $view .= ''; + } + + //CHECK FOR GROUPS + if (isset($configuration['type']) && $configuration['type'] == 'group'){ + + $view .= ''; + + //BASED ON GROUP TYPE CREATE INPUT FORM + switch($configuration['group_type']) { + case 0: //Radiobutton + + $output =''; + + foreach ($configuration['attributes'] as $attribute){ + + if(isset($attribute['full_path']) && $attribute['full_path'] !=''){ + + $onclick =''; + //ADD updateOption to change pictures when GROUP is IN configuration + if(isset($product['config_setting']) && $product['config_setting'] == $configuration['assignment']){ + + $IMG_large_id = $img_url.$attribute['alternative_media_full_path']; //URL TO LARGE IMAGE + $onclick = 'onclick="updateOption(\''.$product['rowID'].'\',\''.$IMG_large_id.'\')"'; + } + + $IMG_small_id = $img_url.$attribute['full_path']; //URL TO SMALL IMAGE + + $output .= ' + '; + + } else { + $output .= ' + '; + } + + + } + $view .= '
'.$output.'
'; + + break; + case 1: //Checkbox + $output =''; + + foreach ($configuration['attributes'] as $attribute){ + + if(isset($attribute['full_path']) && $attribute['full_path'] !=''){ + + $onclick =''; + //ADD updateOption to change pictures when GROUP is IN configuration + if(isset($product['config_setting']) && $product['config_setting'] == $configuration['assignment']){ + + $IMG_large_id = $img_url.$attribute['alternative_media_full_path']; //URL TO LARGE IMAGE + $onclick = 'onclick="updateOption(\''.$product['rowID'].'\',\''.$IMG_large_id.'\')"'; + } + + $IMG_small_id = $img_url.$attribute['full_path']; //URL TO SMALL IMAGE + + $output .= ' + '; + + } else { + $output .= ' + '; + } + + + } + $view .= '
'.$output.'
'; + + break; + + case 2: //Dropdown + $output =' +
'; + + break; + } + } } - ?> - - $option): ?> - - - - - - -
- $option_value): ?> - - - - - - - - - - - -
- - -
- $option_value): ?> - - - - - - - - - - - - -
- - - - > - - - - - data-price="" data-modifier=""> - - - - - - - - - - - - - max="" placeholder="Quantity" required> - - - - - max="" placeholder="Quantity" required> - - + } + +$view .=' + + + + + + -
- + '.(${$product['productdescription']} ?? $product['productdescription']).'
+
+
'; - - +$view .= ' + '; } +//OUTPUT +echo $view; - +template_footer(); - \ No newline at end of file +?> \ No newline at end of file diff --git a/products.php b/products.php index 9681e47..afdb3df 100644 --- a/products.php +++ b/products.php @@ -140,7 +140,7 @@ $view .= '
'; $view .= '
- '.$product['productname'].' + '.(${$product['productname']} ?? $product['productname']).' '; //CHECK IF CONFIGURATION SETTING IS FOUND AND NOT EMPTY => USE GROUP TO DISPLAY IMAGES @@ -157,15 +157,13 @@ $view .= '
'; //GET ALL RELATED ATTRIBUTES foreach ($config['attributes'] as $attribute){ - $option_id = $attribute['alternative_media']; // ID of the LARGE IMAGE + $option_id = $attribute['attribute_id']; // ID of the LARGE IMAGE $IMG_small_id = $img_url.$attribute['full_path']; //URL TO SMALL IMAGE $IMG_large_id = $img_url.$attribute['alternative_media_full_path']; //URL TO LARGE IMAGE // Ensure attribute price is a numeric value $attribute_price = isset($attribute['price']) ? floatval($attribute['price']) : 0.00; - //$option_price = (isset($attribute['price'])) ? (currency_code.((isset($attribute['price_modifier']) && $attribute['price_modifier'] == 1) ? number_format(floatval($product_price+$attribute_price),2) : number_format(($product_price-$attribute_price),2))) : (($product_price != 0.00) ? currency_code.number_format($product_price,2) : ''); - $option_price = isset($attribute['price']) // If price modifier is 1, add prices; otherwise, subtract ? ((isset($attribute['price_modifier']) && $attribute['price_modifier'] == 1) ? currency_code . number_format(floatval($product_price + $attribute_price), 2) : currency_code . number_format(floatval($product_price - $attribute_price), 2)) @@ -207,7 +205,7 @@ $view .= '
'; } $option_id =''; $view .=' - '.$product['productname'].''; + '.(${$product['productname']} ?? $product['productname']).''; if (isset($product_price)){ diff --git a/script.js b/script.js index 1f5c53b..ba38dce 100644 --- a/script.js +++ b/script.js @@ -45,15 +45,25 @@ if (document.querySelector('.product-img-small')) { if (document.querySelector('.product #product-form')) { let updatePrice = () => { let price = parseFloat(document.querySelector('.product .price').dataset.price); + let rrp = parseFloat(document.querySelector('.product .rrp').dataset.rrp); + document.querySelectorAll('.product #product-form .option').forEach(e => { if (e.value) { let optionPrice = e.classList.contains('text') || e.classList.contains('datetime') ? e.dataset.price : 0.00; optionPrice = e.classList.contains('select') ? e.options[e.selectedIndex].dataset.price : optionPrice; optionPrice = (e.classList.contains('radio') || e.classList.contains('checkbox')) && e.checked ? e.dataset.price : optionPrice; - price = (e.classList.contains('select') ? e.options[e.selectedIndex].dataset.modifier : e.dataset.modifier) == 'add' ? price+parseFloat(optionPrice) : price-parseFloat(optionPrice); + price = (e.classList.contains('select') ? e.options[e.selectedIndex].dataset.modifier : e.dataset.modifier) == 1 ? price+parseFloat(optionPrice) : price-parseFloat(optionPrice); + + let optionRRP = e.classList.contains('text') || e.classList.contains('datetime') ? e.dataset.rrp : 0.00; + optionRRP = e.classList.contains('select') ? e.options[e.selectedIndex].dataset.rrp : optionRRP; + optionRRP = (e.classList.contains('radio') || e.classList.contains('checkbox')) && e.checked ? e.dataset.rrp : optionRRP; + rrp = (e.classList.contains('select') ? e.options[e.selectedIndex].dataset.modifier : e.dataset.modifier) == 1 ? rrp+parseFloat(optionRRP) : rrp-parseFloat(optionRRP); + } }); document.querySelector('.product .price').innerHTML = currency_code + (price > 0.00 ? price.toFixed(2) : 0.00); + document.querySelector('.product .rrp').innerHTML = currency_code + (rrp > 0.00 ? rrp.toFixed(2) : 0.00); + }; document.querySelectorAll('.product #product-form .option').forEach(ele => ele.onchange = () => updatePrice()); updatePrice(); @@ -76,6 +86,7 @@ if (document.querySelector('.cart .ajax-update')) { let formEle = document.querySelector('.cart form'); let formData = new FormData(formEle); formData.append('update', 'Update'); + console.log(formData); fetch(formEle.action, { method: 'POST', body: formData