Files
2026-05-22 12:52:44 +00:00

192 lines
5.8 KiB
PHP

<?php
/**
* Tom's Java Jive - POS Order API
* Creates orders from the POS system
*/
header('Content-Type: application/json');
require_once __DIR__ . '/../includes/functions.php';
require_once __DIR__ . '/../includes/auth.php';
// Only accept POST
if ($_SERVER['REQUEST_METHOD'] !== 'POST') {
jsonResponse(['error' => 'Method not allowed'], 405);
}
$input = json_decode(file_get_contents('php://input'), true);
if (empty($input['items']) || !is_array($input['items'])) {
jsonResponse(['error' => 'No items provided'], 400);
}
$items = $input['items'];
$paymentMethod = $input['payment_method'] ?? 'cash';
$notes = $input['notes'] ?? '';
$customerId = $input['customer_id'] ?? null;
$customerEmail = $input['customer_email'] ?? null;
$discountAmount = floatval($input['discount'] ?? 0);
$couponCode = $input['coupon_code'] ?? null;
// Calculate totals
$subtotal = 0;
$orderItems = [];
foreach ($items as $item) {
// Verify product exists and has stock
$product = db()->fetch(
"SELECT product_id, name, price, sale_price, stock FROM products WHERE product_id = :id AND is_active = 1",
['id' => $item['product_id']]
);
if (!$product) {
jsonResponse(['error' => 'Product not found: ' . $item['name']], 400);
}
if ($product['stock'] < $item['quantity']) {
jsonResponse(['error' => 'Insufficient stock for: ' . $product['name']], 400);
}
$price = $product['sale_price'] ?? $product['price'];
$lineTotal = $price * $item['quantity'];
$subtotal += $lineTotal;
$orderItems[] = [
'product_id' => $product['product_id'],
'name' => $product['name'],
'price' => $price,
'quantity' => $item['quantity'],
'total' => $lineTotal
];
}
// Apply coupon if provided
$couponDiscount = 0;
if ($couponCode) {
$coupon = db()->fetch(
"SELECT * FROM coupons WHERE code = :code AND is_active = 1
AND (starts_at IS NULL OR starts_at <= NOW())
AND (expires_at IS NULL OR expires_at > NOW())
AND (max_uses IS NULL OR times_used < max_uses)",
['code' => strtoupper($couponCode)]
);
if ($coupon) {
if ($coupon['min_order_amount'] && $subtotal < $coupon['min_order_amount']) {
// Coupon minimum not met, ignore
} else {
if ($coupon['discount_type'] === 'percentage') {
$couponDiscount = $subtotal * ($coupon['discount_value'] / 100);
} else {
$couponDiscount = min($coupon['discount_value'], $subtotal);
}
// Update coupon usage
db()->query("UPDATE coupons SET times_used = times_used + 1 WHERE coupon_id = :id",
['id' => $coupon['coupon_id']]);
}
}
}
// Calculate final total
$discount = $discountAmount + $couponDiscount;
$taxRate = 0; // Adjust based on settings
$tax = ($subtotal - $discount) * $taxRate;
$total = $subtotal - $discount + $tax;
// Handle wallet payment
$walletUsed = 0;
if ($paymentMethod === 'wallet' && $customerId) {
$customer = db()->fetch(
"SELECT wallet_balance FROM customers WHERE customer_id = :id",
['id' => $customerId]
);
if (!$customer || $customer['wallet_balance'] < $total) {
jsonResponse(['error' => 'Insufficient wallet balance'], 400);
}
$walletUsed = $total;
// Deduct from wallet
db()->query(
"UPDATE customers SET wallet_balance = wallet_balance - :amount WHERE customer_id = :id",
['amount' => $walletUsed, 'id' => $customerId]
);
// Log wallet transaction
$newBalance = $customer['wallet_balance'] - $walletUsed;
db()->insert('wallet_transactions', [
'transaction_id' => generateId('wt_'),
'customer_id' => $customerId,
'amount' => -$walletUsed,
'balance_after' => $newBalance,
'type' => 'purchase',
'description' => 'POS Purchase'
]);
}
// Generate order
$orderId = generateId('ord_');
$orderNumber = generateOrderNumber();
try {
// Create order
db()->insert('orders', [
'order_id' => $orderId,
'order_number' => $orderNumber,
'customer_id' => $customerId,
'customer_email' => $customerEmail ?? 'pos@store.local',
'customer_name' => $input['customer_name'] ?? 'POS Customer',
'items' => json_encode($orderItems),
'subtotal' => $subtotal,
'tax' => $tax,
'discount' => $discount,
'wallet_amount_used' => $walletUsed,
'total' => $total,
'payment_method' => $paymentMethod,
'payment_status' => 'paid',
'order_status' => 'confirmed',
'notes' => $notes,
'is_pos_order' => 1
]);
// Insert order items
foreach ($orderItems as $item) {
db()->insert('order_items', [
'order_id' => $orderId,
'product_id' => $item['product_id'],
'name' => $item['name'],
'price' => $item['price'],
'quantity' => $item['quantity'],
'total' => $item['total']
]);
// Update stock
db()->query(
"UPDATE products SET stock = stock - :qty WHERE product_id = :id",
['qty' => $item['quantity'], 'id' => $item['product_id']]
);
}
// Award reward points if customer
if ($customerId) {
$pointsEarned = floor($total); // 1 point per dollar
db()->query(
"UPDATE customers SET reward_points = reward_points + :points WHERE customer_id = :id",
['points' => $pointsEarned, 'id' => $customerId]
);
}
jsonResponse([
'success' => true,
'order_id' => $orderId,
'order_number' => $orderNumber,
'total' => $total,
'items' => $orderItems
]);
} catch (Exception $e) {
jsonResponse(['error' => 'Failed to create order: ' . $e->getMessage()], 500);
}