File manager - Edit - /home/webapp69.cm.in.th/u69319090017/shop17/checkout.php
Back
<?php // checkout.php require_once 'config.php'; // บังคับให้ผู้ซื้อต้องเข้าสู่ระบบก่อนทำการชำระเงินพรีออเดอร์ if (!isset($_SESSION['is_logged_in']) || $_SESSION['is_logged_in'] !== true) { header('Location: login.php'); exit; } // หากตะกร้าสินค้าว่างเปล่า ให้ส่งกลับไปยังหน้าแรกทันที if (empty($_SESSION['cart'])) { header('Location: index.php'); exit; } // คำนวณราคารวมทั้งหมดเพื่อใช้สร้างพร้อมเพย์คิวอาร์โค้ดแบบไดนามิก $total_price = 0; foreach ($_SESSION['cart'] as $item) { $total_price += $item['price'] * $item['qty']; } // ข้อความคำแปลภาษาที่เกี่ยวข้องสำหรับหน้าชำระเงิน $checkout_txt = [ 'th' => [ 'title' => '💳 ชำระเงินและแจ้งที่อยู่จัดส่ง', 'desc' => 'กรุณากรอกข้อมูลปลายทางจัดส่งพรีออเดอร์ให้ละเอียด เพื่อความสะดวกรวดเร็วในการได้รับสินค้า', 'shipping_info' => 'ข้อมูลที่อยู่ผู้รับปลายทาง', 'lbl_fullname' => 'ชื่อ-นามสกุล ผู้รับสายตรง', 'lbl_phone' => 'หมายเลขโทรศัพท์ติดต่อ', 'lbl_address' => 'ที่อยู่พิกัดในการจัดส่งโดยละเอียด', 'ph_fullname' => 'สมชาย พลดี', 'ph_phone' => '089-XXXXXXX', 'ph_address' => 'บ้านเลขที่ 123/4 หมู่บ้านสุขใจ ซอย 5 ถนนสาธร แขวงยานนาวา เขตสาทร กรุงเทพฯ 10120', 'summary_title' => 'รายการพรีออเดอร์ในตะกร้า', 'btn_confirm' => 'ยืนยันสั่งซื้อและชำระเงินพรีออเดอร์', 'back_to_shop' => '← ย้อนกลับไปยังหน้าร้านหลัก', 'validate_fields' => 'กรุณากรอกข้อมูลสำหรับจัดส่งให้ครบถ้วนก่อนทำรายการ' ], 'en' => [ 'title' => '💳 Pre-order Checkout & Shipping', 'desc' => 'Please fill in your delivery credentials carefully to complete your pre-order.', 'shipping_info' => 'Shipping Information', 'lbl_fullname' => 'Recipient Full Name', 'lbl_phone' => 'Mobile Phone Number', 'lbl_address' => 'Full Shipping Address', 'ph_fullname' => 'John Doe', 'ph_phone' => '089-XXXXXXX', 'ph_address' => '123/4 Sukjai Village, Sathorn Road, Yannywa, Sathorn, Bangkok 10120', 'summary_title' => 'Pre-order Items Summary', 'btn_confirm' => 'Confirm Order & Checkout', 'back_to_shop' => '← Return to shopping page', 'validate_fields' => 'Please complete all required fields before placing order.' ] ]; $ct = $checkout_txt[$lang]; $error_message = ""; // ประมวลผลเมื่อคลิกปุ่มชำระเงินและยืนยันคำสั่งซื้อ if (isset($_POST['process_payment'])) { $fullname = trim($_POST['fullname'] ?? ''); $phone = trim($_POST['phone'] ?? ''); $address = trim($_POST['address'] ?? ''); $payment_method = trim($_POST['payment_method'] ?? 'PromptPay'); // ตรวจสอบความถูกต้องของชื่อและคำแปลสำหรับการบันทึก DB $payment_labels = [ 'PromptPay' => ($lang === 'th') ? 'คิวอาร์พร้อมเพย์' : 'QR PromptPay', 'CreditCard' => ($lang === 'th') ? 'บัตรเครดิต/เดบิต' : 'Credit/Debit Card', 'COD' => ($lang === 'th') ? 'ชำระเงินปลายทาง' : 'Cash on Delivery' ]; $payment_db_value = $payment_labels[$payment_method] ?? 'PromptPay'; if (empty($fullname) || empty($phone) || empty($address)) { $error_message = $ct['validate_fields']; } else { $userId = $_SESSION['user_id']; try { // [1] บันทึกออเดอร์ลงฐานข้อมูล SQLite ในตาราง orders และหักลบสต็อกสินค้าจริง foreach ($_SESSION['cart'] as $key => $cart_item) { $productId = $cart_item['id']; $qty = $cart_item['qty']; $size = $cart_item['size']; $color = $cart_item['color']; // ดึงข้อมูลสินค้าล่าสุดจากฐานข้อมูล $stmtProd = $pdo->prepare("SELECT shop_id, price, stock FROM products WHERE id = ?"); $stmtProd->execute([$productId]); $prodDb = $stmtProd->fetch(); if ($prodDb) { $shopId = $prodDb['shop_id']; $price = $prodDb['price']; $currentStock = $prodDb['stock']; // คำนวณสต็อกและหักลบสต็อกคงเหลือ $newStock = max(0, $currentStock - $qty); $stmtUpdateStock = $pdo->prepare("UPDATE products SET stock = ? WHERE id = ?"); $stmtUpdateStock->execute([$newStock, $productId]); // บันทึกคำสั่งซื้อลงใน SQLite $productNameWithDetails = $cart_item['name_th'] . " (Size: " . $size . ", Color: " . $color . ")"; $totalPrice = $price * $qty; $stmtInsertOrder = $pdo->prepare(" INSERT INTO orders (user_id, shop_id, product_id, product_name, quantity, total_price, payment_method, status) VALUES (?, ?, ?, ?, ?, ?, ?, 'Pending') "); $stmtInsertOrder->execute([ $userId, $shopId, $productId, $productNameWithDetails, $qty, $totalPrice, $payment_db_value ]); } } // [2] ล้างค่าสินค้าทั้งหมดในตะกร้าหลังจากชำระเงินและบันทึกเสร็จสิ้น $_SESSION['cart'] = []; // ย้ายหน้ากลับไปยังหน้า index.php พร้อมตัวแจ้งเตือนสำเร็จ header('Location: index.php?checkout_success=1'); exit; } catch (PDOException $e) { $error_message = "เกิดข้อผิดพลาดในการบันทึกออเดอร์: " . $e->getMessage(); } } } ?> <!DOCTYPE html> <html lang="<?= $lang ?>"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title><?= ($lang == 'th') ? 'หน้าชำระเงินพรีออเดอร์' : 'Pre-order Checkout' ?> - Noa Shop</title> <script src="https://cdn.tailwindcss.com"></script> <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/animate.css/4.1.1/animate.min.css"/> <link href="https://fonts.googleapis.com/css2?family=Outfit:wght@300;400;600;800&family=Sarabun:wght@300;400;600;800&display=swap" rel="stylesheet"> <style> body { font-family: 'Outfit', 'Sarabun', sans-serif; } .gradient-brand { background: linear-gradient(135deg, #f59e0b 0%, #ee4d2d 100%); } .text-gradient { background: linear-gradient(135deg, #f59e0b 0%, #ee4d2d 100%); -webkit-background-clip: text; -webkit-text-fill-color: transparent; } </style> </head> <body class="<?= $tc['bg'] ?> min-h-screen p-6 transition-colors duration-300"> <div class="max-w-5xl mx-auto"> <!-- ส่วนหัวหน้าชำระเงิน --> <div class="flex flex-col md:flex-row justify-between items-start md:items-center mb-8 pb-4 border-b border-slate-200/50 gap-4"> <div> <h1 class="text-3xl font-black text-gradient uppercase tracking-tight"><?= $ct['title'] ?></h1> <p class="text-xs opacity-60 mt-1"><?= $ct['desc'] ?></p> </div> <a href="index.php" class="bg-neutral-600 hover:bg-neutral-700 text-white font-bold text-xs px-5 py-2.5 rounded-xl shadow transition duration-200"> <?= $ct['back_to_shop'] ?> </a> </div> <?php if (!empty($error_message)): ?> <div class="mb-6 p-4 bg-red-500 text-white font-bold rounded-2xl text-center shadow animate__animated animate__shakeX text-xs"> ⚠️ <?= $error_message ?> </div> <?php endif; ?> <!-- GRID LAYOUT --> <div class="grid grid-cols-1 lg:grid-cols-3 gap-8 items-start"> <!-- คอลัมน์ซ้าย: ฟอร์มที่อยู่จัดส่งสินค้า (2 ใน 3 ส่วน) --> <div class="lg:col-span-2 rounded-3xl p-6 <?= $tc['card'] ?> animate__animated animate__fadeInLeft"> <h2 class="text-lg font-bold text-amber-500 mb-5 flex items-center gap-2"> <span>📍</span> <?= $ct['shipping_info'] ?> </h2> <form action="checkout.php" method="POST" class="space-y-5 text-xs"> <div> <label class="block font-bold mb-1.5 opacity-70"><?= $ct['lbl_fullname'] ?></label> <input type="text" name="fullname" required value="<?= htmlspecialchars($_SESSION['username'] ?? '') ?>" class="w-full p-3.5 rounded-xl outline-none font-medium <?= $tc['input'] ?>" placeholder="<?= $ct['ph_fullname'] ?>"> </div> <div> <label class="block font-bold mb-1.5 opacity-70"><?= $ct['lbl_phone'] ?></label> <input type="text" name="phone" required class="w-full p-3.5 rounded-xl outline-none font-medium <?= $tc['input'] ?>" placeholder="<?= $ct['ph_phone'] ?>"> </div> <div> <label class="block font-bold mb-1.5 opacity-70"><?= $ct['lbl_address'] ?></label> <textarea name="address" rows="4" required class="w-full p-3.5 rounded-xl outline-none font-medium <?= $tc['input'] ?>" placeholder="<?= $ct['ph_address'] ?>"></textarea> </div> <!-- หัวข้อ: เลือกวิธีการชำระเงิน (Select Payment Method) --> <div class="pt-4 border-t border-slate-500/10"> <label class="block font-black text-sm text-slate-800 dark:text-slate-200 mb-3"> 💳 <?= ($lang === 'th') ? 'เลือกวิธีการชำระเงิน' : 'Select Payment Method' ?> </label> <div class="grid grid-cols-1 sm:grid-cols-3 gap-3"> <!-- QR PromptPay --> <label class="flex items-center justify-between border border-slate-700/60 rounded-xl p-3.5 cursor-pointer bg-slate-950/20 hover:bg-slate-950/50 transition"> <span class="flex items-center gap-2"> <input type="radio" name="payment_method" value="PromptPay" checked onclick="togglePaymentSection('PromptPay')" class="accent-amber-500"> <span class="text-xs font-bold text-slate-300"><?= ($lang === 'th') ? 'คิวอาร์พร้อมเพย์' : 'QR PromptPay' ?></span> </span> <span class="text-lg">📱</span> </label> <!-- Credit Card --> <label class="flex items-center justify-between border border-slate-700/60 rounded-xl p-3.5 cursor-pointer bg-slate-950/20 hover:bg-slate-950/50 transition"> <span class="flex items-center gap-2"> <input type="radio" name="payment_method" value="CreditCard" onclick="togglePaymentSection('CreditCard')" class="accent-amber-500"> <span class="text-xs font-bold text-slate-300"><?= ($lang === 'th') ? 'บัตรเครดิต/เดบิต' : 'Credit/Debit Card' ?></span> </span> <span class="text-lg">💳</span> </label> <!-- Cash on Delivery --> <label class="flex items-center justify-between border border-slate-700/60 rounded-xl p-3.5 cursor-pointer bg-slate-950/20 hover:bg-slate-950/50 transition"> <span class="flex items-center gap-2"> <input type="radio" name="payment_method" value="COD" onclick="togglePaymentSection('COD')" class="accent-amber-500"> <span class="text-xs font-bold text-slate-300"><?= ($lang === 'th') ? 'ชำระเงินปลายทาง' : 'Cash on Delivery' ?></span> </span> <span class="text-lg">🚚</span> </label> </div> </div> <!-- ส่วนแสดงรายละเอียดแผงชำระเงินตามที่เลือก (Dynamic Payment Panels) --> <div class="mt-4"> <!-- Panel 1: QR PromptPay (แสดง QR Code คิวอาร์สร้างสดแบบพร้อมสแกน) --> <div id="panel-PromptPay" class="payment-panel p-5 bg-white dark:bg-slate-900 border border-slate-200 dark:border-slate-800 rounded-2xl text-center space-y-4"> <div class="flex items-center justify-center gap-2"> <span class="text-xs font-black text-blue-600 dark:text-blue-400 tracking-wider">PROMPTPAY DYNAMIC QR</span> </div> <!-- ส่วนแสดงเวลานับถอยหลัง (Timer Section) --> <div id="qr-timer-container" class="bg-amber-50 dark:bg-amber-950/20 border border-amber-200 dark:border-amber-900 p-2.5 rounded-xl text-xs text-amber-700 dark:text-amber-400 font-bold inline-flex items-center gap-2"> <span>⏳</span> <span><?= ($lang === 'th') ? 'กรุณาชำระเงินภายใน' : 'Please pay within' ?> <span id="qr-countdown" class="font-mono text-sm">20:00</span></span> </div> <!-- Wrapper สำหรับรูป QR Code --> <div id="qr-code-wrapper" class="space-y-4"> <div class="inline-block p-4 bg-white rounded-2xl border border-slate-200/80 shadow-md"> <img src="https://promptpay.io/0806202522/<?= $total_price ?>.png" alt="PromptPay QR Code" class="w-48 h-48 mx-auto object-contain"> </div> <div class="text-xs text-slate-600 dark:text-slate-400 font-medium space-y-1"> <div class="text-sm font-bold text-slate-900 dark:text-white"> <?= ($lang === 'th') ? 'หมายเลขพร้อมเพย์' : 'PromptPay Number' ?>: <span class="text-amber-500 font-mono font-extrabold text-base">080-620-2522</span> </div> <p> <?= ($lang === 'th') ? 'สแกนคิวอาร์โค้ดด้านบนด้วยแอปธนาคารใดก็ได้เพื่อชำระเงินยอดรวม' : 'Scan the QR code above with any mobile banking app to pay' ?>: <strong class="text-amber-500 font-bold block text-sm mt-1">฿<?= number_format($total_price, 2) ?></strong> </p> </div> </div> <!-- Wrapper เมื่อ QR Code หมดเวลาชำระเงิน --> <div id="qr-expired-wrapper" class="hidden p-6 bg-red-50 dark:bg-red-950/10 border border-red-200 dark:border-red-900/50 rounded-2xl space-y-3"> <span class="text-3xl block">❌</span> <h3 class="text-xs font-bold text-red-650"><?= ($lang === 'th') ? 'คิวอาร์โค้ดหมดอายุการชำระเงินแล้ว' : 'QR Code has expired' ?></h3> <p class="text-[11px] text-slate-500"><?= ($lang === 'th') ? 'เนื่องจากพ้นกำหนดระยะเวลาชำระเงิน 20 นาที' : 'Because the 20-minute payment window has passed.' ?></p> <button type="button" onclick="regenerateQrCode()" class="bg-amber-500 hover:bg-amber-600 text-white font-bold px-4 py-2 rounded-xl transition text-xs transform active:scale-95 cursor-pointer"> 🔄 <?= ($lang === 'th') ? 'สร้างคิวอาร์โค้ดใหม่' : 'Generate New QR Code' ?> </button> </div> </div> <!-- Panel 2: Credit Card Form (ฟอร์มกรอกเลขบัตรเครดิต) --> <div id="panel-CreditCard" class="payment-panel hidden p-5 bg-slate-950/20 border border-slate-700/60 rounded-2xl space-y-3"> <div> <label class="block font-semibold mb-1 opacity-75"><?= ($lang === 'th') ? 'ชื่อบนบัตร' : 'Cardholder Name' ?></label> <input type="text" placeholder="John Doe" class="w-full p-2.5 rounded-lg outline-none <?= $tc['input'] ?>"> </div> <div> <label class="block font-semibold mb-1 opacity-75"><?= ($lang === 'th') ? 'หมายเลขบัตร' : 'Card Number' ?></label> <input type="text" placeholder="xxxx-xxxx-xxxx-xxxx" class="w-full p-2.5 rounded-lg outline-none <?= $tc['input'] ?>"> </div> <div class="grid grid-cols-2 gap-3"> <div> <label class="block font-semibold mb-1 opacity-75"><?= ($lang === 'th') ? 'วันหมดอายุ (MM/YY)' : 'Expiry Date' ?></label> <input type="text" placeholder="12/28" class="w-full p-2.5 rounded-lg outline-none <?= $tc['input'] ?>"> </div> <div> <label class="block font-semibold mb-1 opacity-75">CVV</label> <input type="text" placeholder="123" class="w-full p-2.5 rounded-lg outline-none <?= $tc['input'] ?>"> </div> </div> </div> <!-- Panel 3: Cash on Delivery (ชำระเงินปลายทาง) --> <div id="panel-COD" class="payment-panel hidden p-5 bg-slate-950/20 border border-slate-700/60 rounded-2xl text-center"> <span class="text-4xl block mb-2">💵</span> <p class="text-xs font-semibold text-slate-300"> <?= ($lang === 'th') ? 'ชำระเงินสดด้วยการสแกนหรือเงินสดเมื่อเจ้าหน้าที่นำส่งสินค้าถึงปลายทางของคุณ' : 'Pay in cash or bank transfer once the courier delivers the package to your address.' ?> </p> </div> </div> <button type="submit" name="process_payment" class="w-full py-4 rounded-xl font-bold bg-gradient-to-r from-amber-500 to-orange-500 hover:from-amber-600 hover:to-orange-600 text-white shadow-lg transition transform active:scale-95 text-xs tracking-wider uppercase"> 🚀 <?= $ct['btn_confirm'] ?> </button> </form> </div> <!-- คอลัมน์ขวา: สรุปรายการสินค้าในตะกร้า (1 ใน 3 ส่วน) --> <div class="lg:col-span-1 rounded-3xl p-6 <?= $tc['card'] ?> animate__animated animate__fadeInRight"> <h2 class="text-lg font-bold pb-4 border-b border-slate-200/50 mb-4 flex items-center gap-2"> <span>📦</span> <?= $ct['summary_title'] ?> </h2> <div class="space-y-4 max-h-[300px] overflow-y-auto pr-1"> <?php $total_price_check = 0; foreach ($_SESSION['cart'] as $item): $item_total = $item['price'] * $item['qty']; $total_price_check += $item_total; ?> <div class="flex gap-3 items-center justify-between p-2.5 rounded-xl bg-slate-500/5 border border-slate-500/5 text-xs"> <img src="<?= htmlspecialchars($item['image']) ?>" alt="img" class="w-10 h-10 object-cover rounded-lg border border-slate-200/20"> <div class="flex-grow min-w-0"> <h4 class="font-bold truncate"> <?= ($lang == 'th') ? htmlspecialchars($item['name_th']) : htmlspecialchars($item['name_en']) ?> </h4> <p class="text-[9px] opacity-60 mt-0.5"> Size: <?= htmlspecialchars($item['size']) ?> | Color: <?= htmlspecialchars($item['color']) ?> | Qty: <?= $item['qty'] ?> </p> </div> <span class="font-black text-amber-500">฿<?= number_format($item_total) ?></span> </div> <?php endforeach; ?> </div> <div class="pt-4 border-t border-slate-200/50 mt-4 flex justify-between items-center text-xs"> <span class="font-bold opacity-60"><?= $txt['cart_total'] ?></span> <span class="text-xl font-black text-amber-500">฿<?= number_format($total_price_check) ?></span> </div> </div> </div> </div> <!-- Script สำหรับการสลับประเภทการจ่ายเงินและนับเวลานับถอยหลัง 20 นาทีแบบ Interactive --> <script> let timerInterval; function startCountdown() { // เคลียร์ interval เดิมหากมีอยู่ if (timerInterval) clearInterval(timerInterval); // ดึงเวลาหมดอายุการจ่ายเงินจาก sessionStorage เพื่อรองรับการกดรีเฟรชหน้าแล้วเวลานับต่อ let expiryTime = sessionStorage.getItem('checkout_qr_expiry'); if (!expiryTime) { expiryTime = Date.now() + 20 * 60 * 1000; // ตั้งเวลาหมดอายุที่ 20 นาทีถัดไป sessionStorage.setItem('checkout_qr_expiry', expiryTime); } else { expiryTime = parseInt(expiryTime); } const countdownEl = document.getElementById('qr-countdown'); const codeWrapper = document.getElementById('qr-code-wrapper'); const expiredWrapper = document.getElementById('qr-expired-wrapper'); const submitButton = document.querySelector('button[name="process_payment"]'); const timerContainer = document.getElementById('qr-timer-container'); function updateTimer() { const now = Date.now(); const remaining = Math.max(0, Math.floor((expiryTime - now) / 1000)); const minutes = Math.floor(remaining / 60); const seconds = remaining % 60; countdownEl.innerText = `${minutes.toString().padStart(2, '0')}:${seconds.toString().padStart(2, '0')}`; if (remaining <= 0) { clearInterval(timerInterval); // ซ่อนหน้า QR codeWrapper.classList.add('hidden'); timerContainer.classList.add('hidden'); // แสดงแจ้งเตือนหมดเวลาชำระเงิน expiredWrapper.classList.remove('hidden'); // ล็อคปุ่มยืนยันการจ่ายเงิน submitButton.disabled = true; submitButton.classList.add('opacity-50', 'cursor-not-allowed'); } else { // แสดงหน้า QR ปกติ codeWrapper.classList.remove('hidden'); timerContainer.classList.remove('hidden'); expiredWrapper.classList.add('hidden'); // เปิดปุ่มยืนยันให้กดได้ปกติ submitButton.disabled = false; submitButton.classList.remove('opacity-50', 'cursor-not-allowed'); } } updateTimer(); timerInterval = setInterval(updateTimer, 1000); } function regenerateQrCode() { // สร้างเวลาหมดอายุใหม่ 20 นาทีและเริ่มเวลานับถอยหลังอีกครั้ง const newExpiry = Date.now() + 20 * 60 * 1000; sessionStorage.setItem('checkout_qr_expiry', newExpiry); startCountdown(); } function togglePaymentSection(selectedMethod) { // ซ่อนทุก Panel ก่อนหน้า const panels = document.querySelectorAll('.payment-panel'); panels.forEach(p => p.classList.add('hidden')); // แสดงเฉพาะ Panel ที่ผู้ใช้เลือก const targetPanel = document.getElementById('panel-' + selectedMethod); if (targetPanel) { targetPanel.classList.remove('hidden'); } const submitButton = document.querySelector('button[name="process_payment"]'); if (selectedMethod === 'PromptPay') { startCountdown(); } else { if (timerInterval) clearInterval(timerInterval); // วิธีจ่ายเงินอื่น ให้เปิดใช้งานปุ่มกดเสมอ submitButton.disabled = false; submitButton.classList.remove('opacity-50', 'cursor-not-allowed'); } } // เช็คการติ๊กเลือกเมื่อหน้าเว็บเริ่มโหลดเสร็จ window.addEventListener('DOMContentLoaded', () => { const checkedOption = document.querySelector('input[name="payment_method"]:checked'); if (checkedOption) { togglePaymentSection(checkedOption.value); } }); // ลบค่า sessionStorage เมื่อทำการกดยืนยันการสั่งซื้อชำระเงินสำเร็จ document.querySelector('form').addEventListener('submit', () => { sessionStorage.removeItem('checkout_qr_expiry'); }); </script> </body> </html>
| ver. 1.4 |
Github
|
.
| PHP 7.4.33 | Generation time: 0.24 |
proxy
|
phpinfo
|
Settings