'', 'last_name' => '', 'address_street' => '', 'address_city' => '', 'address_state' => '', 'address_zip' => '', 'address_country' => '', 'role' => 'Member', 'address_phone' => '' ]; // 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 = ?'); $stmt->execute([ $_SESSION['account_id'] ]); // Fetch the account from the database and return the result as an Array $account = $stmt->fetch(PDO::FETCH_ASSOC); } // Update discount code if (isset($_POST['discount_code']) && !empty($_POST['discount_code'])) { $_SESSION['discount'] = $_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 ($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')); // 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))); //------------------------------- //------------------------------- } // 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; // If the user is already logged in if (isset($_SESSION['account_loggedin'])) { // Account logged-in, update the user's details $stmt = $pdo->prepare('UPDATE accounts SET first_name = ?, last_name = ?, address_street = ?, address_city = ?, address_state = ?, address_zip = ?, address_country = ?, address_phone = ? WHERE id = ?'); $stmt->execute([ $_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['account_id'] ]); $account_id = $_SESSION['account_id']; } else if (isset($_POST['email'], $_POST['password'], $_POST['cpassword']) && filter_var($_POST['email'], FILTER_VALIDATE_EMAIL) && !empty($_POST['password']) && !empty($_POST['cpassword'])) { // User is not logged in, check if the account already exists with the email they submitted $stmt = $pdo->prepare('SELECT id FROM accounts WHERE email = ?'); $stmt->execute([ $_POST['email'] ]); if ($stmt->fetch(PDO::FETCH_ASSOC)) { // Email exists, user should login instead... $errors[] = $error_account_name; } if (strlen($_POST['password']) > 20 || strlen($_POST['password']) < 5) { // Password must be between 5 and 20 characters long. $errors[] = $error_account_password_rules; } if ($_POST['password'] != $_POST['cpassword']) { // Password and confirm password fields do not match... $errors[] = $error_account_password_match; } if (!$errors) { // Hash the password $password = password_hash($_POST['password'], PASSWORD_DEFAULT); // Email doesnt exist, create new account $stmt = $pdo->prepare('INSERT INTO accounts (email, password, first_name, last_name, address_street, address_city, address_state, address_zip, address_country, address_phone) VALUES (?,?,?,?,?,?,?,?,?,?)'); $stmt->execute([ $_POST['email'], $password, $_POST['first_name'], $_POST['last_name'], $_POST['address_street'], $_POST['address_city'], $_POST['address_state'], $_POST['address_zip'], $_POST['address_country'], $_POST['address_phone'] ]); $account_id = $pdo->lastInsertId(); $stmt = $pdo->prepare('SELECT * FROM accounts WHERE id = ?'); $stmt->execute([ $account_id ]); // Fetch the account from the database and return the result as an Array $account = $stmt->fetch(PDO::FETCH_ASSOC); } } else if (account_required) { $errors[] = $error_account; } 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 ]); } } } //Disable giftcard if (isset($_SESSION['discount'])){ if (preg_match("/[#][0-9]/", $_SESSION['discount']) == 1){ useGiftCart($pdo, $_SESSION['discount']); } } // Authenticate the user if ($account_id != null) { // Log the user in with the details provided session_regenerate_id(); $_SESSION['account_loggedin'] = TRUE; $_SESSION['account_id'] = $account_id; $_SESSION['account_role'] = $account ? $account['role'] : 'Member'; } // Send order details to the specified email address send_order_details_email( isset($account['email']) && !empty($account['email']) ? $account['email'] : $_POST['email'], $products_in_cart, $_POST['first_name'], $_POST['last_name'], $_POST['address_street'], $_POST['address_city'], $_POST['address_state'], $_POST['address_zip'], $_POST['address_country'], $subtotal, $discounttotal, $shippingtotal, $taxtotal, $payment_amount, $order_id ); header('Location: ' . url('index.php?page=placeorder')); exit; } // +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ // Mollie ++++++++++++++++++++++++++++++++++++++++++++++++++++ // +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ if (mollie_enabled && $_POST['method'] == 'mollie') { // 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, 'Debit/Credit', $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 ]); } } } // Authenticate the user if ($account_id != null) { // Log the user in with the details provided session_regenerate_id(); $_SESSION['account_loggedin'] = TRUE; $_SESSION['account_id'] = $account_id; $_SESSION['account_role'] = $account ? $account['role'] : 'Member'; } try { /* * Initialize the Mollie API library with your API key. * * See: https://www.mollie.com/dashboard/developers/api-keys */ require "initialize.php"; /* * Generate a unique order id for this example. It is important to include this unique attribute * in the redirectUrl (below) so a proper return page can be shown to the customer. */ $orderId = $transaction_id; $value = number_format(($subtotal-$discounttotal)+$shippingtotal,2,'.',''); /* * Determine the url parts to these example files. */ $protocol = isset($_SERVER['HTTPS']) && strcasecmp('off', $_SERVER['HTTPS']) !== 0 ? "https" : "http"; $hostname = $_SERVER['HTTP_HOST']; $path = dirname($_SERVER['REQUEST_URI'] ?? $_SERVER['PHP_SELF']); /* * Payment parameters: * amount Amount in EUROs. This example creates a € 10,- payment. * 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. * metadata Custom metadata that is stored with the payment. */ if (rewrite_url){ $redirectURL = $protocol.'://'.$hostname.$path.'placeorder/'.$orderId; }else{ $redirectURL = $protocol.'://'.$hostname.$path.'index.php?page=placeorder&order_id='.$orderId; } $payment = $mollie->payments->create([ "amount" => [ "currency" => "EUR", "value" => "{$value}", // You must send the correct number of decimals, thus we enforce the use of strings ], "description" => "Order #{$orderId}", "redirectUrl" => "$redirectURL", "webhookUrl" => "{$protocol}://{$hostname}{$path}webhook.php", "metadata" => [ "order_id" => $orderId, ], ]); /* * Send the customer off to complete the payment. * This request should always be a GET, thus we enforce 303 http response code */ // Send order details to the specified email address send_order_details_email( isset($account['email']) && !empty($account['email']) ? $account['email'] : $_POST['email'], $products_in_cart, $_POST['first_name'], $_POST['last_name'], $_POST['address_street'], $_POST['address_city'], $_POST['address_state'], $_POST['address_zip'], $_POST['address_country'], $subtotal, $discounttotal, $shippingtotal, $taxtotal, $payment_amount, $order_id ); // Send customer to checkout header("Location: " . $payment->getCheckoutUrl(), true, 303); } catch (\Mollie\Api\Exceptions\ApiException $e) { echo "API call failed: " . htmlspecialchars($e->getMessage()); } exit; } // +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ // PayPal Payment + +++++++++++++++++++++++++++++++++++++++++ // +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ if (paypal_enabled && $_POST['method'] == 'paypal') { // Process Normal Checkout first then do PayPal related // 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, 'paypal', $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 ]); } } } if ($account_id != null) { // Log the user in with the details provided session_regenerate_id(); $_SESSION['account_loggedin'] = TRUE; $_SESSION['account_id'] = $account_id; $_SESSION['account_role'] = $account ? $account['role'] : 'Member'; } //Process Payment require_once __DIR__."/lib/paypal/paypal.php"; $base = PAYPAL_URL; $id = PAYPAL_CLIENT_ID; $secret = PAYPAL_CLIENT_SECRET; //init input $order = $transaction_id; $price = $payment_amount; $currency = "EUR"; //make payment $paypal = new paypalCurl(); $paypal->init($id,$secret,$base); $result = $paypal->makePaymentURL($order,$price,$currency); if ($result->status === true) { header("location:". $result->url); die; } else { //raise error echo $result->msg; die; } } } // 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'] ]; } $terms_link = url('index.php?page=termsandconditions'); ?> =template_header('Checkout')?>
=template_footer()?>