false, 'error' => 'Invalid method']); exit; } $input = json_decode(file_get_contents('php://input'), true); if (!$input || empty($input['items'])) { echo json_encode(['success' => false, 'error' => 'Cart is empty']); exit; } $name = trim($input['name'] ?? ''); $phoneInput = trim($input['phone'] ?? ''); $phone = normalize_oman_phone($phoneInput); $address = trim($input['address'] ?? ''); $acceptPolicies = !empty($input['accept_policies']); $paymentMethod = trim((string) ($input['payment_method'] ?? 'pay_later')); if (!in_array($paymentMethod, ['pay_later', 'pay_online'], true)) { echo json_encode(['success' => false, 'error' => 'Invalid payment method']); exit; } if (!$acceptPolicies) { echo json_encode(['success' => false, 'error' => 'You must accept the Privacy Policy and Terms & Conditions']); exit; } if ($paymentMethod === 'pay_online' && !thawani_is_configured()) { echo json_encode(['success' => false, 'error' => 'Thawani payment is not configured']); exit; } if ($name === '' || $phoneInput === '' || $address === '') { echo json_encode(['success' => false, 'error' => 'Missing customer details']); exit; } if ($phone === '') { echo json_encode(['success' => false, 'error' => 'Phone must be an 8-digit Oman number']); exit; } $items = $input['items']; $subtotal = 0; $totalVat = 0; // Recalculate total for security $db = db(); $processedItems = []; foreach ($items as $id => $item) { $qty = (int)$item['qty']; if ($qty <= 0) continue; // get price and vat from DB $stmt = $db->prepare("SELECT sku, name, price, vat FROM items WHERE id = ?"); $stmt->execute([$id]); $dbItem = $stmt->fetch(); if ($dbItem) { $price = (float)$dbItem['price']; $vatPercent = (float)($dbItem['vat'] ?? 0); $lineTotal = $price * $qty; $itemVat = $lineTotal * ($vatPercent / 100); $subtotal += $lineTotal; $totalVat += $itemVat; $processedItems[] = [ 'id' => $id, 'sku' => $dbItem['sku'], 'name' => $dbItem['name'], 'price' => $price, 'vat' => $vatPercent, 'vat_amount' => $itemVat, 'qty' => $qty, 'line_total' => $lineTotal ]; } } if (empty($processedItems)) { echo json_encode(['success' => false, 'error' => 'Invalid items']); exit; } $totalAmount = $subtotal + $totalVat; try { $db->beginTransaction(); $paymentGateway = $paymentMethod === 'pay_online' ? 'thawani' : null; $paymentStatus = $paymentMethod === 'pay_online' ? 'pending' : 'unpaid'; $stmt = $db->prepare("INSERT INTO online_orders (customer_name, customer_phone, customer_address, items_json, subtotal, vat_amount, total_amount, payment_method, payment_gateway, payment_status) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)"); $stmt->execute([ $name, $phone, $address, json_encode($processedItems, JSON_UNESCAPED_UNICODE), $subtotal, $totalVat, $totalAmount, $paymentMethod, $paymentGateway, $paymentStatus ]); $orderId = (int) $db->lastInsertId(); sync_online_order_stock_reservation([], 'rejected', $processedItems, 'pending'); $checkoutUrl = null; if ($paymentMethod === 'pay_online') { $thawaniResult = thawani_create_checkout_session($orderId, [ 'customer_name' => $name, 'customer_phone' => $phone, 'customer_address' => $address, 'items' => $processedItems, ]); if (empty($thawaniResult['success'])) { throw new RuntimeException((string) ($thawaniResult['error'] ?? 'Unable to create Thawani session')); } $checkoutUrl = (string) ($thawaniResult['checkout_url'] ?? ''); $sessionId = (string) ($thawaniResult['session_id'] ?? ''); $updateStmt = $db->prepare("UPDATE online_orders SET gateway_session_id = ? WHERE id = ?"); $updateStmt->execute([$sessionId, $orderId]); } $db->commit(); // Optional: send Telegram admin notice and customer WhatsApp notification. try { $msg = "๐Ÿ›’ *New Online Order #{$orderId}* "; $msg .= "๐Ÿ‘ค {$name} ๐Ÿ“ž " . phone_display($phone) . " ๐Ÿ“ {$address} "; $msg .= "๐Ÿ’ฐ Subtotal: " . currency($subtotal) . " "; $msg .= "๐Ÿงพ VAT: " . currency($totalVat) . " "; $msg .= "๐Ÿ’ต Total: " . currency($totalAmount) . " "; $botToken = getenv('TELEGRAM_BOT_TOKEN') ?: get_setting('telegram_bot_token'); $chatId = getenv('TELEGRAM_CHAT_ID') ?: get_setting('telegram_chat_id'); if ($botToken && $chatId) { $url = "https://api.telegram.org/bot{$botToken}/sendMessage"; $data = ['chat_id' => $chatId, 'text' => $msg, 'parse_mode' => 'Markdown']; $options = [ 'http' => [ 'header' => "Content-type: application/x-www-form-urlencoded ", 'method' => 'POST', 'content' => http_build_query($data) ] ]; $context = stream_context_create($options); @file_get_contents($url, false, $context); } } catch (Throwable $e) { error_log('Telegram notify failed for online order #' . $orderId . ': ' . $e->getMessage()); } if ($paymentMethod === 'pay_later' && wablas_is_configured()) { try { wablas_notify_online_order_by_id($orderId, 'created'); } catch (Throwable $e) { error_log('Customer WhatsApp notify failed for online order #' . $orderId . ': ' . $e->getMessage()); } } echo json_encode(['success' => true, 'redirect_url' => $checkoutUrl]); } catch (Throwable $e) { if ($db->inTransaction()) { $db->rollBack(); } echo json_encode(['success' => false, 'error' => 'Database error: ' . $e->getMessage()]); }