AMS_Backend/app/Controllers/Backend/OrderController.php
2025-11-06 13:41:06 +08:00

582 lines
20 KiB
PHP

<?php
namespace App\Controllers\Backend;
use CodeIgniter\HTTP\ResponseInterface;
use CodeIgniter\RESTful\ResourceController;
use App\Models\OrderItemOptions;
use App\Models\OrderItems;
use App\Models\OrderPayments;
use App\Models\Orders;
use App\Models\OrderTaxes;
use CodeIgniter\Database\Config;
use CodeIgniter\HTTP\Message;
use App\Models\OrderDeliveries;
use App\Libraries\Wato;
use App\Models\User;
use App\Models\MenuItemVariations;
class OrderController extends ResourceController
{
private $orders;
private $order_items;
private $order_item_options;
private $order_payments;
private $order_taxes;
private $order_deliveries;
private $db;
private $wato;
private $user;
private $menu_item_variations;
public function __construct()
{
$this->orders = new Orders();
$this->order_items = new OrderItems();
$this->order_item_options = new OrderItemOptions();
$this->order_taxes = new OrderTaxes();
$this->order_payments = new OrderPayments();
$this->order_deliveries = new OrderDeliveries();
$this->db = Config::connect();
$this->wato = new Wato();
$this->user = new User();
$this->menu_item_variations = new MenuItemVariations();
}
public function orderList()
{
$user_id = $this->request->getVar('user_id');
$start_date = $this->request->getVar('start_date');
$end_date = $this->request->getVar('end_date');
$status = $this->request->getVar('status');
$outlet_id = $this->request->getVar('outlet_id');
$order_type = $this->request->getVar('order_type');
// Get the user information to check role and outlet
$user = $this->user->find($user_id);
if (!$user) {
return $this->respond([
'status' => 404,
'message' => 'User not found',
'data' => []
]);
}
$orderQuery = $this->orders
->orderBy('created_at', 'DESC');
// If user is not admin, filter by their outlet_id
if ($user['role'] !== 'admin') {
$orderQuery->where('outlet_id', $user['outlet_id']);
} else {
// If admin and specific outlet_id is provided, use it
if (!empty($outlet_id)) {
$orderQuery->where('outlet_id', $outlet_id);
}
// Otherwise admin sees all orders (no outlet filter)
}
if (!empty($start_date)) {
$orderQuery->where('created_at >=', $start_date . ' 00:00:00');
}
if (!empty($end_date)) {
$orderQuery->where('created_at <=', $end_date . ' 23:59:59');
}
if (!empty($status)) {
$orderQuery->where('status', $status);
}
if (!empty($outlet_id)) {
$orderQuery->where('outlet_id', $outlet_id);
}
if (!empty($order_type)) {
$orderQuery->where('order_type', $order_type);
}
$orders = $orderQuery->findAll();
if (empty($orders)) {
return $this->respond([
'status' => 200,
'message' => 'No orders found!',
'data' => []
]);
}
foreach ($orders as &$order) {
$order_id = $order['id'];
// Fetch items + options
$order['items'] = $this->order_items->where('order_id', $order_id)->findAll();
foreach ($order['items'] as &$item) {
$item['options'] = $this->order_item_options
->where('order_item_id', $item['id'])
->findAll();
}
// Fetch taxes
$order['taxes'] = $this->order_taxes
->where('order_id', $order_id)
->findAll();
// Fetch payments
$order['payments'] = $this->order_payments
->where('order_id', $order_id)
->orderBy('created_at', 'DESC')
->findAll();
// Fetch deliveries
$order['deliveries'] = $this->order_deliveries
->where('order_id', $order_id)
->findAll();
}
return $this->respond([
'status' => 200,
'message' => 'Orders retrieved successfully',
'data' => $orders
]);
}
public function showOrder($order_id = null)
{
// Get order with customer + outlet info
$order = $this->orders
->select('
orders.*,
customers.id as customer_id,
customers.name as customer_name,
customers.email as customer_email,
customers.phone as customer_phone,
customers.profile_picture as customer_profile_pic,
outlets.id as outlet_id,
outlets.title as outlet_title,
outlets.email as outlet_email,
outlets.phone as outlet_phone,
outlets.address as outlet_address,
')
->join('customers', 'customers.id = orders.customer_id', 'left')
->join('outlets', 'outlets.id = orders.outlet_id', 'left') // join outlets
->where('orders.id', $order_id)
->first();
if (!$order) {
return $this->fail('Order not found', 400);
}
// Items + options + menu images
$order['items'] = $this->order_items
->select('order_items.*, menu_images.image_url as menu_item_image')
->join('menu_images', 'menu_images.menu_item_id = order_items.menu_item_id', 'left')
->where('order_items.order_id', $order_id)
->groupBy('order_items.id')
->findAll();
foreach ($order['items'] as &$item) {
$item['options'] = $this->order_item_options->where('order_item_id', $item['id'])->findAll();
$item['menu_item_image'] = getMenuImage($item['menu_item_id']);
$item['variation_name'] = $this->menu_item_variations
->where('menu_item_id', $item['menu_item_id'])
->where('id', $item['variation_id'])
->first()['title'] ?? '';
}
// Taxes
$order['taxes'] = $this->order_taxes->where('order_id', $order_id)->findAll();
// Payments
$order['payments'] = $this->order_payments
->where('order_id', $order_id)
->orderBy('created_at', 'DESC')
->findAll();
// Deliveries
$order['deliveries'] = $this->order_deliveries->where('order_id', $order_id)->findAll();
return $this->respond([
'status' => 200,
'message' => 'Order retrieved successfully',
'data' => $order
]);
}
public function updateOrderSchedule($order_id = null)
{
// Validate order_id
if (empty($order_id)) {
return $this->fail('Order ID is required', 400);
}
// Get the order
$order = $this->orders->find($order_id);
if (!$order) {
return $this->fail('Order not found', 404);
}
// Check if order status is 'complete'
if (isset($order['status']) && $order['status'] === 'complete') {
return $this->fail('Cannot modify schedule for completed orders', 400);
}
// Get request data
$selected_date = $this->request->getVar('selected_date');
$selected_time = $this->request->getVar('selected_time');
// Validate input
if (empty($selected_date) || empty($selected_time)) {
return $this->fail('Both selected_date and selected_time are required', 400);
}
// Prepare data to update
$data = [
'selected_date' => $selected_date,
'selected_time' => $selected_time,
'updated_at' => date('Y-m-d H:i:s') // Update timestamp
];
try {
// Update the order
$updated = $this->orders->update($order_id, $data);
if (!$updated) {
return $this->fail('Failed to update order schedule', 500);
}
// Get the updated order
$updatedOrder = $this->orders->find($order_id);
return $this->respond([
'status' => 200,
'message' => 'Order schedule updated successfully',
'data' => $updatedOrder
]);
} catch (\Exception $e) {
return $this->fail('An error occurred while updating order schedule: ' . $e->getMessage(), 500);
}
}
public function updateOrderStatus($order_id = null)
{
// Validate order_id
if (empty($order_id)) {
return $this->fail('Order ID is required', 400);
}
// Get the order
$order = $this->orders->select('orders.*, customer_addresses.phone as recipient_phone')
->join('customer_addresses', 'customer_addresses.id = orders.customer_address_id AND customer_addresses.deleted_at IS NULL', 'left')->find($order_id);
if (!$order) {
return $this->fail('Order not found', 404);
}
// Get request data
$status = $this->request->getVar('status');
// Validate input
if (empty($status)) {
return $this->fail('Status is required', 400);
}
// Define allowed status values
$allowedStatuses = ['pending', 'picked_up', 'on_the_way', 'completed', 'ready_to_pickup'];
if (!in_array($status, $allowedStatuses)) {
return $this->fail('Invalid status value. Allowed values: ' . implode(', ', $allowedStatuses), 400);
}
// Prepare data to update
$data = [
'status' => $status,
'updated_at' => date('Y-m-d H:i:s') // Update timestamp
];
try {
// Update the order
$updated = $this->orders->update($order_id, $data);
if ($order['status'] != $status) { //send notification to customer if status is changed
$message = '';
switch ($status) {
case 'ready_to_pickup':
$message = "🍴 Your food is ready for pickup!\nPlease show your order number at the counter: \n**{{" . $order['order_so'] . "}}**";
break;
case 'on_the_way':
$message = "🚚 Your order [**" . $order['order_so'] . "**] is on the way!\nThe driver is delivering your food now.\nPlease get ready to receive it.";
break;
case 'completed':
$message = "🎉 Your order [**" . $order['order_so'] . "**] has been completed.\nWe hope you enjoy your meal!\nThank you for ordering with us.";
break;
}
if ($message) {
$this->wato->pushNotification($order['recipient_phone'], $message);
}
}
if (!$updated) {
return $this->fail('Failed to update order status', 500);
}
// Get the updated order
$updatedOrder = $this->orders->find($order_id);
return $this->respond([
'status' => 200,
'message' => 'Order status updated successfully',
'data' => $updatedOrder
]);
} catch (\Exception $e) {
return $this->fail('An error occurred while updating order status: ' . $e->getMessage(), 500);
}
}
public function createOrderDelivery()
{
// Get request data
$order_id = $this->request->getVar('order_id');
$fee_amount = $this->request->getVar('actual_fee_amount');
$tracking_link = $this->request->getVar('tracking_link');
// Optional fields that will be set to empty string if not provided
$provider_name = $this->request->getVar('provider_name') ?? '';
$provider_order_id = $this->request->getVar('provider_order_id') ?? '';
$actual_fee_amount = $this->request->getVar('fee_amount') ?? '';
$transaction_id = $this->request->getVar('transaction_id') ?? '';
// Validate required fields
if (empty($order_id) || empty($actual_fee_amount) || empty($tracking_link)) {
return $this->fail('order_id, actual_fee_amount, and tracking_link are required', 400);
}
// Check if the order exists
$order = $this->orders->find($order_id);
if (!$order) {
return $this->fail('Order not found', 404);
}
// Prepare data for insertion with empty strings for optional fields
$data = [
'order_id' => $order_id,
'provider_name' => $provider_name,
'status' => 'pending', // Default status
'provider_order_id' => $provider_order_id,
'fee_amount' => $fee_amount,
'actual_fee_amount' => $actual_fee_amount,
'transaction_id' => $transaction_id,
'tracking_link' => $tracking_link,
'created_at' => date('Y-m-d H:i:s'),
'updated_at' => date('Y-m-d H:i:s')
];
try {
// Insert the data
$inserted = $this->order_deliveries->insert($data);
if (!$inserted) {
return $this->fail('Failed to create order delivery record', 500);
}
// Get the inserted ID
$insertId = $this->db->insertID();
// Return success response with the created record
return $this->respond([
'status' => 201,
'message' => 'Order delivery record created successfully',
'data' => array_merge(['id' => $insertId], $data)
], 201);
} catch (\Exception $e) {
return $this->fail('An error occurred while creating order delivery: ' . $e->getMessage(), 500);
}
}
public function updateOrderDelivery($id = null)
{
if (empty($id)) {
return $this->fail('Delivery record ID is required', 400);
}
// Get request data - all fields optional except id
$data = [
'actual_fee_amount' => $this->request->getVar('actual_fee_amount') ?? '',
'tracking_link' => $this->request->getVar('tracking_link'),
'updated_at' => date('Y-m-d H:i:s')
];
// Remove fields that weren't provided in the request (except status which has a default)
$data = array_filter($data, function ($value, $key) {
return $value !== null || $key === 'status';
}, ARRAY_FILTER_USE_BOTH);
if (empty($data)) {
return $this->respond([
'status' => 200,
'message' => 'No fields to update',
'data' => null
]);
}
try {
$updated = $this->order_deliveries->update($id, $data);
if (!$updated) {
return $this->fail('Failed to update order delivery record', 500);
}
// Get the updated record
$updatedData = $this->order_deliveries->find($id);
// Convert NULL values to empty strings in the response
$responseData = [
'id' => $id,
'order_id' => $updatedData['order_id'],
'provider_name' => $updatedData['provider_name'] ?? '',
'status' => $updatedData['status'] ?? '',
'provider_order_id' => $updatedData['provider_order_id'] ?? '',
'fee_amount' => $updatedData['fee_amount'] ?? '',
'actual_fee_amount' => $updatedData['actual_fee_amount'],
'transaction_id' => $updatedData['transaction_id'] ?? '',
'tracking_link' => $updatedData['tracking_link'],
'created_at' => $updatedData['created_at'],
'updated_at' => $updatedData['updated_at']
];
return $this->respond([
'status' => 200,
'message' => 'Order delivery updated successfully',
'data' => $responseData
]);
} catch (\Exception $e) {
return $this->fail('An error occurred while updating order delivery: ' . $e->getMessage(), 500);
}
}
public function getOrderDelivery($order_id = null)
{
// Validate order_id
if (empty($order_id)) {
return $this->fail('Order ID is required', 400);
}
try {
// Get delivery record by order_id
$delivery = $this->order_deliveries->where('order_id', $order_id)->get()->getRowArray();
if (!$delivery) {
return $this->respond([
'status' => 404,
'message' => 'No delivery record found for this order',
'data' => null
], 404);
}
// Format the response data with empty strings instead of NULL
$responseData = [
'id' => $delivery['id'],
'order_id' => $delivery['order_id'],
'provider_name' => $delivery['provider_name'] ?? '',
'status' => $delivery['status'] ?? '',
'provider_order_id' => $delivery['provider_order_id'] ?? '',
'fee_amount' => $delivery['fee_amount'] ?? '',
'actual_fee_amount' => $delivery['actual_fee_amount'],
'transaction_id' => $delivery['transaction_id'] ?? '',
'tracking_link' => $delivery['tracking_link'],
'created_at' => $delivery['created_at'],
'updated_at' => $delivery['updated_at']
];
return $this->respond([
'status' => 200,
'message' => 'Order delivery retrieved successfully',
'data' => $responseData
]);
} catch (\Exception $e) {
return $this->fail('An error occurred while fetching order delivery: ' . $e->getMessage(), 500);
}
}
public function customerOrderList()
{
$start_date = $this->request->getVar('start_date');
$end_date = $this->request->getVar('end_date');
$status = $this->request->getVar('status');
$outlet_id = $this->request->getVar('outlet_id');
$order_type = $this->request->getVar('order_type');
$orderQuery = $this->orders
->orderBy('created_at', 'DESC');
if (!empty($start_date)) {
$orderQuery->where('created_at >=', $start_date . ' 00:00:00');
}
if (!empty($end_date)) {
$orderQuery->where('created_at <=', $end_date . ' 23:59:59');
}
if (!empty($status)) {
$orderQuery->where('status', $status);
}
if (!empty($outlet_id)) {
$orderQuery->where('outlet_id', $outlet_id);
}
if (!empty($order_type)) {
$orderQuery->where('order_type', $order_type);
}
$orders = $orderQuery->findAll();
if (empty($orders)) {
return $this->respond([
'status' => 200,
'message' => 'No orders found!',
'data' => []
]);
}
foreach ($orders as &$order) {
$order_id = $order['id'];
// Fetch items + options
$order['items'] = $this->order_items->where('order_id', $order_id)->findAll();
foreach ($order['items'] as &$item) {
$item['options'] = $this->order_item_options
->where('order_item_id', $item['id'])
->findAll();
}
// Fetch taxes
$order['taxes'] = $this->order_taxes
->where('order_id', $order_id)
->findAll();
// Fetch payments
$order['payments'] = $this->order_payments
->where('order_id', $order_id)
->orderBy('created_at', 'DESC')
->findAll();
// Fetch deliveries
$order['deliveries'] = $this->order_deliveries
->where('order_id', $order_id)
->findAll();
}
return $this->respond([
'status' => 200,
'message' => 'Orders retrieved successfully',
'data' => $orders
]);
}
}