38682-vm/api/order.php
2026-02-23 03:43:41 +00:00

292 lines
11 KiB
PHP

<?php
header('Content-Type: application/json');
require_once __DIR__ . '/../db/config.php';
require_once __DIR__ . '/../includes/WablasService.php';
$input = file_get_contents('php://input');
$data = json_decode($input, true);
if (!$data) {
echo json_encode(['success' => false, 'error' => 'No data provided']);
exit;
}
try {
$pdo = db();
$pdo->beginTransaction();
// Validate order_type against allowed ENUM values
$allowed_types = ['dine-in', 'takeaway', 'delivery', 'drive-thru'];
$order_type = isset($data['order_type']) && in_array($data['order_type'], $allowed_types)
? $data['order_type']
: 'dine-in';
// Get outlet_id from input, default to 1 if missing
$outlet_id = isset($data['outlet_id']) ? intval($data['outlet_id']) : 1;
$table_id = null;
$table_number = null;
if ($order_type === 'dine-in') {
$tid = $data['table_number'] ?? null; // Front-end sends ID as table_number
if ($tid) {
// Validate table exists AND belongs to the correct outlet
$stmt = $pdo->prepare(
"SELECT t.id, t.name
FROM tables t
JOIN areas a ON t.area_id = a.id
WHERE t.id = ? AND a.outlet_id = ?"
);
$stmt->execute([$tid, $outlet_id]);
$table = $stmt->fetch(PDO::FETCH_ASSOC);
if ($table) {
$table_id = $table['id'];
$table_number = $table['name'];
}
}
// If not found or not provided, leave null (Walk-in/Counter) or try to find a default table for this outlet
if (!$table_id) {
// Optional: try to find the first available table for this outlet
$stmt = $pdo->prepare(
"SELECT t.id, t.name
FROM tables t
JOIN areas a ON t.area_id = a.id
WHERE a.outlet_id = ?
LIMIT 1"
);
$stmt->execute([$outlet_id]);
$table = $stmt->fetch(PDO::FETCH_ASSOC);
if ($table) {
$table_id = $table['id'];
$table_number = $table['name'];
}
}
}
// Customer Handling
$customer_id = $data['customer_id'] ?? null;
$customer_name = $data['customer_name'] ?? null;
$customer_phone = $data['customer_phone'] ?? null;
// Fetch Loyalty Settings
$settingsStmt = $pdo->query("SELECT points_per_order, points_for_free_meal FROM loyalty_settings WHERE id = 1");
$settings = $settingsStmt->fetch(PDO::FETCH_ASSOC);
$points_per_order = $settings ? intval($settings['points_per_order']) : 10;
$points_threshold = $settings ? intval($settings['points_for_free_meal']) : 70;
$current_points = 0;
$points_deducted = 0;
$points_awarded = 0;
if ($customer_id) {
$stmt = $pdo->prepare("SELECT name, phone, points FROM customers WHERE id = ?");
$stmt->execute([$customer_id]);
$cust = $stmt->fetch(PDO::FETCH_ASSOC);
if ($cust) {
$customer_name = $cust['name'];
$customer_phone = $cust['phone'];
$current_points = intval($cust['points']);
} else {
$customer_id = null;
}
}
// Loyalty Redemption Logic
$redeem_loyalty = !empty($data['redeem_loyalty']);
if ($redeem_loyalty && $customer_id) {
if ($current_points < $points_threshold) {
throw new Exception("Insufficient loyalty points for redemption.");
}
// Deduct points
$deductStmt = $pdo->prepare("UPDATE customers SET points = points - ? WHERE id = ?");
$deductStmt->execute([$points_threshold, $customer_id]);
$points_deducted = $points_threshold;
// --- OVERRIDE PAYMENT TYPE ---
$ptStmt = $pdo->prepare("SELECT id FROM payment_types WHERE name = 'Loyalty Redeem' LIMIT 1");
$ptStmt->execute();
$loyaltyPt = $ptStmt->fetchColumn();
if ($loyaltyPt) {
$data['payment_type_id'] = $loyaltyPt;
}
}
// Award Points
if ($customer_id) {
$awardStmt = $pdo->prepare("UPDATE customers SET points = points + ? WHERE id = ?");
$awardStmt->execute([$points_per_order, $customer_id]);
$points_awarded = $points_per_order;
}
// Payment Type
$payment_type_id = isset($data['payment_type_id']) ? intval($data['payment_type_id']) : null;
$discount = isset($data['discount']) ? floatval($data['discount']) : 0.00;
$total_amount = isset($data['total_amount']) ? floatval($data['total_amount']) : 0.00;
// Check for Existing Order ID (Update Mode)
$order_id = isset($data['order_id']) ? intval($data['order_id']) : null;
$is_update = false;
if ($order_id) {
// Verify existence and status (optional: only update pending orders?)
$checkStmt = $pdo->prepare("SELECT id FROM orders WHERE id = ?");
$checkStmt->execute([$order_id]);
if ($checkStmt->fetch()) {
$is_update = true;
} else {
// If ID sent but not found, create new? Or error?
// Let's treat as new if not found to avoid errors, or maybe user meant to update.
// Safe bet: error if explicit update requested but failed.
// But for now, let's just create new if ID is invalid, or better, stick to the plan: Update if ID present.
$order_id = null; // Reset to create new
}
}
if ($is_update) {
// UPDATE Existing Order
$stmt = $pdo->prepare("UPDATE orders SET
outlet_id = ?, table_id = ?, table_number = ?, order_type = ?,
customer_id = ?, customer_name = ?, customer_phone = ?,
payment_type_id = ?, total_amount = ?, discount = ?, status = 'pending'
WHERE id = ?");
$stmt->execute([
$outlet_id, $table_id, $table_number, $order_type,
$customer_id, $customer_name, $customer_phone,
$payment_type_id, $total_amount, $discount,
$order_id
]);
// Clear existing items to replace them
$delStmt = $pdo->prepare("DELETE FROM order_items WHERE order_id = ?");
$delStmt->execute([$order_id]);
} else {
// INSERT New Order
$stmt = $pdo->prepare("INSERT INTO orders (outlet_id, table_id, table_number, order_type, customer_id, customer_name, customer_phone, payment_type_id, total_amount, discount, status) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, 'pending')");
$stmt->execute([$outlet_id, $table_id, $table_number, $order_type, $customer_id, $customer_name, $customer_phone, $payment_type_id, $total_amount, $discount]);
$order_id = $pdo->lastInsertId();
}
// Insert Items (Common for both Insert and Update)
$item_stmt = $pdo->prepare("INSERT INTO order_items (order_id, product_id, variant_id, quantity, unit_price) VALUES (?, ?, ?, ?, ?)");
// Pre-prepare statements for name fetching
$prodNameStmt = $pdo->prepare("SELECT name FROM products WHERE id = ?");
$varNameStmt = $pdo->prepare("SELECT name FROM product_variants WHERE id = ?");
$order_items_list = []; // To store item details for notification
if (!empty($data['items']) && is_array($data['items'])) {
foreach ($data['items'] as $item) {
$pid = $item['product_id'] ?? ($item['id'] ?? null);
$qty = $item['quantity'] ?? 1;
$price = $item['unit_price'] ?? ($item['price'] ?? 0);
$vid = $item['variant_id'] ?? null;
if ($pid) {
$item_stmt->execute([$order_id, $pid, $vid, $qty, $price]);
// Fetch names for notification
$prodNameStmt->execute([$pid]);
$pRow = $prodNameStmt->fetch(PDO::FETCH_ASSOC);
$pName = $pRow ? $pRow['name'] : 'Item';
if ($vid) {
$varNameStmt->execute([$vid]);
$vRow = $varNameStmt->fetch(PDO::FETCH_ASSOC);
if ($vRow) {
$pName .= " (" . $vRow['name'] . ")";
}
}
$order_items_list[] = "$qty x $pName";
}
}
}
$pdo->commit();
// --- Post-Transaction Actions ---
// Send WhatsApp Notification if Customer exists
if ($customer_id && $customer_phone) {
try {
// Calculate final points
$final_points = $current_points - $points_deducted + $points_awarded;
// Determine message content
$wablas = new WablasService($pdo);
// Fetch Company Name
require_once __DIR__ . '/../includes/functions.php';
$companySettings = get_company_settings();
$company_name = $companySettings['company_name'] ?? 'Flatlogic POS';
// Fetch Template
$stmt = $pdo->prepare("SELECT setting_value FROM integration_settings WHERE provider = 'wablas' AND setting_key = 'order_template'");
$stmt->execute();
$template = $stmt->fetchColumn();
// Default Template if not set
if (!$template) {
$template = "Dear *{customer_name}*,
Thank you for dining with *{company_name}*! 🍽️
*Order Details:*
{order_details}
Total: *{total_amount}* OMR
You've earned *{points_earned} points* with this order.
💰 *Current Balance: {new_balance} points*
{loyalty_status}";
}
// Calculate Loyalty Status String
$loyalty_status = "";
if ($final_points >= $points_threshold) {
$loyalty_status = "🎉 Congratulations! You have enough points for a *FREE MEAL* on your next visit!";
} else {
$needed = $points_threshold - $final_points;
$loyalty_status = "You need *$needed more points* to unlock a free meal.";
}
// Prepare replacements
$replacements = [
'{customer_name}' => $customer_name,
'{company_name}' => $company_name,
'{order_id}' => $order_id,
'{order_details}' => !empty($order_items_list) ? implode("\n", $order_items_list) : 'N/A',
'{total_amount}' => number_format($total_amount, 3),
'{points_earned}' => $points_awarded,
'{points_redeemed}' => $points_deducted,
'{new_balance}' => $final_points,
'{loyalty_status}' => $loyalty_status
];
$msg = str_replace(array_keys($replacements), array_values($replacements), $template);
// Send (fire and forget, don't block response on failure, just log)
$res = $wablas->sendMessage($customer_phone, $msg);
if (!$res['success']) {
error_log("Wablas Notification Failed: " . $res['message']);
}
} catch (Exception $w) {
error_log("Wablas Exception: " . $w->getMessage());
}
}
echo json_encode(['success' => true, 'order_id' => $order_id]);
} catch (Exception $e) {
if ($pdo->inTransaction()) {
$pdo->rollBack();
}
error_log("Order Error: " . $e->getMessage());
echo json_encode(['success' => false, 'error' => $e->getMessage()]);
}