39728-vm/api/place_order.php
2026-04-22 04:55:52 +00:00

183 lines
6.0 KiB
PHP

<?php
require_once __DIR__ . '/../includes/app.php';
header('Content-Type: application/json; charset=utf-8');
if ($_SERVER['REQUEST_METHOD'] !== 'POST') {
echo json_encode(['success' => 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()]);
}