carts = new Carts(); $this->cart_items = new CartItems(); $this->cart_item_options = new CartItemOptions(); $this->orders = new Orders(); $this->order_items = new OrderItems(); $this->order_item_options = new OrderItemOptions(); $this->customer = new Customer(); $this->order_payments = new OrderPayments(); $this->order_taxes = new OrderTaxes(); $this->customer_wallet = new CustomerWallet(); $this->db = Config::connect(); $this->cart_service = service('cartService'); $this->calculate_service = service('calculateService'); $this->promo_service = service('promoService'); $this->voucher_service = service('voucherService'); $this->outlet = new Outlet(); $this->fiuu = new Fiuu(); $this->variations = new MenuItemVariations(); $this->order_deliveries = new OrderDeliveries(); $this->promo_redemptions_record = new PromoRedemptionRecord(); $this->voucher_redemptions = new VoucherRedemptions(); } public function createOrder() { $validation = $this->validate([ 'customer_id' => 'required|numeric', 'outlet_id' => 'required|numeric', 'order_type' => 'required', 'customer_address_id' => 'permit_empty|numeric', 'payment_method' => 'required', 'selected_date' => 'permit_empty|string', 'selected_time' => 'permit_empty|string', 'latitude' => 'permit_empty|string', 'longitude' => 'permit_empty|string', 'notes' => 'permit_empty|string', ]); if (!$validation) { return $this->failValidationErrors($this->validator->getErrors()); } $customer_id = $this->request->getVar('customer_id'); $outlet_id = $this->request->getVar('outlet_id'); $customer_address_id = $this->request->getVar('customer_address_id'); $order_type = strtolower(str_replace('-', '', $this->request->getVar('order_type'))); $payment_method = $this->request->getVar('payment_method'); $selected_date = $this->request->getVar('selected_date') ?? date('Y-m-d'); $selected_time = $this->request->getVar('selected_time') ?? date('H:i'); $real_selected_date = $this->request->getVar('selected_date'); $real_selected_time = $this->request->getVar('selected_time'); $latitude = $this->request->getVar('latitude'); $longitude = $this->request->getVar('longitude'); $notes = $this->request->getVar('notes'); $address = $this->request->getVar('address'); $cart = $this->carts->where('customer_id', $customer_id) ->where('outlet_id', $outlet_id) ->where('status', 'active') ->first(); if (!$cart) { return $this->fail('Cart not found', 400); } $customer = $this->customer->find($customer_id); if (!$customer) { return $this->fail('Customer not found', 400); } $promo_or_voucher = null; if ($cart['promo_code_id'] > 0) { $check_promo = $this->promo_service->checkPromoAvailability($cart['promo_code_id'], $order_type, $customer_id); if (isset($check_promo['status']) && $check_promo['status'] == 400) { $this->calculate_service->resetVoucher($cart['id']); return $this->respond($check_promo); } $promo_or_voucher = 'promo'; } if ($cart['customer_voucher_list_id'] > 0) { $check_voucher = $this->voucher_service->checkVoucherAvailability($cart['customer_voucher_list_id'], $order_type, $customer_id); if (isset($check_voucher['status']) && $check_voucher['status'] == 400) { $this->calculate_service->resetVoucher($cart['id']); return $this->respond($check_voucher); } $promo_or_voucher = 'voucher'; } $cart_total = $this->calculate_service->calculateCartTotals($cart['id'], $cart['outlet_id'], $real_selected_date, $real_selected_time, $latitude, $longitude, $order_type, $address, $promo_or_voucher); // print_r($cart_total); // exit; if (isset($cart_total['status']) && $cart_total['status'] == 400) { $response = [ 'status' => 400, 'message' => $cart_total['message'] ]; return $this->respond($response, 400); } $cart_total = $cart_total['data']; if (count($cart_total['invalid_items']) > 0) { return $this->fail('Menu got updated, try again', 400); } if ($payment_method == 'wallet') { if ($customer['customer_wallet'] < $cart_total['order_summary']['grand_total']) { return $this->fail('Insufficient Wallet Balance', 400); } } if ($cart_total['order_summary']['grand_total'] < 0) { return $this->fail('Invalid Grand Total', 400); } //check operation date and time $check_operation_date_and_time = checkOperationDateAndTime($outlet_id, $selected_date, $selected_time); if (!$check_operation_date_and_time) { return $this->fail('Outlet is not operated on the selected date and time', 400); } $this->db->transStart(); try { $orderData = [ 'customer_id' => $customer_id, 'outlet_id' => $outlet_id, 'customer_address_id' => $customer_address_id, 'order_type' => $order_type, 'status' => 'pending', 'payment_status' => 'unpaid', 'packaging_charge' => $cart_total['order_summary']['packaging_charge'] ?? 0, 'payment_method' => $payment_method, 'subtotal_amount' => $cart_total['order_summary']['subtotal_amount'], 'discount_amount' => $cart_total['order_summary']['discount_amount'], 'tax_amount' => $cart_total['order_summary']['tax_amount'], 'delivery_fee' => $cart_total['order_summary']['delivery_fee'] ?? 0, 'rounding_amount' => $cart_total['order_summary']['rounding_amount'], 'grand_total' => $cart_total['order_summary']['grand_total'], 'promo_code_id' => $cart_total['order_summary']['promo_code_id'], 'promo_discount_amount' => $cart_total['order_summary']['promo_discount_amount'], 'customer_voucher_list_id' => $cart_total['order_summary']['customer_voucher_list_id'], 'voucher_discount_amount' => $cart_total['order_summary']['voucher_discount_amount'], 'placed_at' => '', 'selected_date' => $real_selected_date, 'selected_time' => $real_selected_time, 'expected_ready_time' => '', 'notes' => $notes, 'lalamove_quot_id' => $cart['lalamove_quot_id'] ?? null, 'grab_quot_id' => $cart['grab_quot_id'] ?? null ]; //insert order $order_id = $this->orders->insert($orderData); if ($promo_or_voucher != null) { if ($promo_or_voucher == 'promo') { $this->promo_redemptions_record->insert([ 'order_id' => $order_id, 'promo_codes_id' => $orderData['promo_code_id'], 'customer_id' => $orderData['customer_id'], ]); } else if ($promo_or_voucher == 'voucher') { $this->voucher_redemptions->insert([ 'order_id' => $order_id, 'customer_voucher_list_id' => $orderData['customer_voucher_list_id'], 'customer_id' => $orderData['customer_id'], 'order_type' => $orderData['order_type'], ]); } } if ($order_id > 0) { $today_order_count = $this->orders->where('created_at >=', date('Y-m-d 00:00:00'))->where('created_at <=', date('Y-m-d 23:59:59'))->countAllResults(); $order_so = date('ymd') . str_pad($today_order_count, 5, '0', STR_PAD_LEFT); $this->orders->update($order_id, ['order_so' => $order_so]); } //insert order items $cartItems = $this->cart_items->where('cart_id', $cart['id'])->findAll(); foreach ($cartItems as $cartItem) { $orderItemData = [ 'order_id' => $order_id, 'menu_item_id' => $cartItem['menu_item_id'], 'variation_id' => $cartItem['variation_id'], 'title' => $cartItem['title'], 'unit_price' => $cartItem['unit_price'], 'quantity' => $cartItem['quantity'], 'line_subtotal' => $cartItem['line_subtotal'], 'order_index' => $cartItem['order_index'], ]; $orderItemId = $this->order_items->insert($orderItemData); $cartItemOptions = $this->cart_item_options->where('cart_item_id', $cartItem['id'])->findAll(); foreach ($cartItemOptions as $option) { $orderItemOptionData = [ 'order_item_id' => $orderItemId, 'option_id' => $option['option_id'], 'option_title' => $option['option_title'], 'price_adjustment' => $option['price_adjustment'], ]; $this->order_item_options->insert($orderItemOptionData); } } //insert order taxes foreach ($cart_total['tax_detail'] as $tax_order) { $tax_data = [ 'order_id' => $order_id, 'tax_type' => $tax_order['tax_type'], 'tax_rate' => $tax_order['tax_rate'], 'tax_amount' => $tax_order['tax_amount'], ]; $this->order_taxes->insert($tax_data); } $respond_data = []; //insert order payments if ($payment_method == 'wallet') { $payment = [ 'order_id' => $order_id, 'payment_method' => $payment_method, 'amount' => $cart_total['order_summary']['grand_total'], 'transaction_id' => 0, 'status' => 'pending', 'paid_at' => '', ]; // echo(123);exit; $this->order_payments->insert($payment); completeOrder($order_id); } else { //generate payment details & url $payment = [ 'order_id' => $order_id, 'payment_method' => $payment_method, 'amount' => $cart_total['order_summary']['grand_total'], 'transaction_id' => 0, 'status' => 'pending', 'paid_at' => '', ]; $this->order_payments->insert($payment); $payment_details = [ 'bill_name' => $customer['name'], 'bill_email' => $customer['email'], 'bill_mobile' => $customer['phone'], 'bill_desc' => 'US Pizza - Payment for ' . ucfirst($order_type) . ' - ' . $order_id, ]; $result = $this->fiuu->createPayment($order_so, $cart_total['order_summary']['grand_total'], $payment_details); $respond_data['redirect_url'] = $result['redirect_url']; } $this->carts->update($cart['id'], ['status' => 'completed']); $this->db->transComplete(); $order = $this->orders->find($order_id); $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(); } $respond_data['status'] = 200; $respond_data['message'] = 'Order created successfully'; $respond_data['order'] = $order; return $this->respond($respond_data); } catch (\Exception $e) { $this->db->transRollback(); print_r($e->getMessage()); return $this->fail('Cannot checkout order. Please try again.', 400); } } public function createOrderAgain($order_id = null) { $order = $this->orders->select('orders.*, customer_addresses.address, customer_addresses.latitude, customer_addresses.longitude') ->join('customer_addresses', 'customer_addresses.id = orders.customer_address_id', 'left') ->find($order_id); if (!$order) { return $this->fail('Order not found', 400); } $outlet = $this->outlet->find($order['outlet_id']); $outlet_title = $outlet['title'] ?? ''; //check outlet cart exist $existing_cart = $this->carts ->where('customer_id', $order['customer_id']) ->where('outlet_id', $order['outlet_id']) ->where('status', 'active') ->first(); if ($existing_cart) { //clear all cart items $this->cart_items->where('cart_id', $existing_cart['id'])->delete(); } //select order items $order_items = $this->order_items->where('order_id', $order_id)->findAll(); // print_r($order_items);exit; foreach ($order_items as $order_item) { if ($order_item['unit_price'] > 0) { $options = $this->order_item_options ->select('options.option_group_id, order_item_options.option_id') ->join('options', 'options.id = order_item_options.option_id') ->where('order_item_id', $order_item['id']) ->findAll(); $option_group = []; if (!empty($options)) { // Group options by option_group_id $grouped_options = []; foreach ($options as $option) { $grouped_options[$option['option_group_id']][] = $option['option_id']; } // Convert to the expected format for cart service foreach ($grouped_options as $group_id => $option_ids) { $option_group[] = [ 'group_id' => $group_id, 'option_ids' => $option_ids ]; } } // print_r($option_group);exit; $addCart = $this->cart_service->addCartItem($order['customer_id'], $order['outlet_id'], $existing_cart, $order_item['menu_item_id'], $order_item['variation_id'], $option_group, $order_item['quantity'], false); if (isset($addCart['status']) && $addCart['status'] == 400) { return $this->fail($addCart['message'], 400); } } } $data = [ 'order_id' => $order['id'], 'customer_id' => $order['customer_id'], 'outlet_id' => $order['outlet_id'], 'outlet_title' => $outlet_title, 'customer_address_id' => $order['customer_address_id'], 'order_type' => $order['order_type'], 'address' => $order['address'], 'latitude' => $order['latitude'], 'longitude' => $order['longitude'] ]; return $this->respond(['status' => 200, 'message' => 'Order created successfully', 'data' => $data]); } public function createOrderVip() { $customer_id = $this->request->getVar('customer_id'); $outlet_id = HQ_OUTLET_ID; $outlet = $this->outlet->find($outlet_id); $order_type = 'dinein'; $outlet_title = $outlet['title'] ?? ''; //check outlet cart exist $existing_cart = $this->carts ->where('customer_id', $customer_id) ->where('outlet_id', $outlet_id) ->where('status', 'active') ->first(); if ($existing_cart) { //clear all cart items $this->cart_items->where('cart_id', $existing_cart['id'])->delete(); } //select VIP Cart Item $addCart = $this->cart_service->addCartItem($customer_id, $outlet_id, $existing_cart, VIP_MENU_ITEM_ID, 0, [], 1, false); if (isset($addCart['status']) && $addCart['status'] == 400) { return $this->fail($addCart['message'], 400); } $data = [ 'customer_id' => $customer_id, 'outlet_id' => $outlet_id, 'outlet_title' => $outlet_title, 'order_type' => $order_type, ]; return $this->respond(['status' => 200, 'message' => 'Order created successfully', 'data' => $data]); } public function showOrder($order_id = null) { // echo(123);exit; $order = $this->orders->find($order_id); if (!$order) { return $this->fail('Order not found', 400); } //calculate grad_total before rounding $grand_total_before_rounding = $order['grand_total'] - $order['rounding_amount']; $order['grand_total_before_rounding'] = number_format($grand_total_before_rounding, 2); $order['items'] = $this->order_items->where('order_id', $order_id)->findAll(); foreach ($order['items'] as &$item) { $item['variation'] = $this->variations->find($item['variation_id']); $item['options'] = $this->order_item_options->where('order_item_id', $item['id'])->findAll(); } $order['taxes'] = $this->order_taxes->where('order_id', $order_id)->findAll(); $order['payments'] = $this->order_payments ->where('order_id', $order_id) ->orderBy('created_at', 'DESC') ->findAll(); $order['deliveries'] = $this->order_deliveries ->where('order_id', $order_id) ->orderBy('created_at', 'DESC') ->findAll(); $order['packaging_charge'] = $order['packaging_charge'] ?? 0; $order['points'] = floor($order['grand_total']); // print_r($order);exit; return $this->respond([ 'status' => 200, 'message' => 'Order retrieved successfully', 'data' => $order ]); } public function orderList($customer_id) { $start_date = $this->request->getVar('start_date'); $end_date = $this->request->getVar('end_date'); $status = $this->request->getVar('status'); $order_type = $this->request->getVar('order_type'); $orderQuery = $this->orders ->where('customer_id', $customer_id) ->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($order_type)) { $orderQuery->where('order_type', $order_type); } $orders = $orderQuery->findAll(); if (empty($orders)) { return $this->respond([ 'status' => 200, 'message' => 'No orders found for this customer', 'data' => [] ]); } foreach ($orders as &$order) { $order_id = $order['id']; $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(); } $order['taxes'] = $this->order_taxes ->where('order_id', $order_id) ->findAll(); $order['payments'] = $this->order_payments ->where('order_id', $order_id) ->orderBy('created_at', 'DESC') ->findAll(); $order['packaging_charge'] = $order['packaging_charge'] ?? 0; } return $this->respond([ 'status' => 200, 'message' => 'Orders retrieved successfully', 'data' => $orders ]); } // public function applyPromoCode(){ // $validation = $this->validate([ // 'promo_code' => 'required', // 'cart_id' => 'required|numeric', // 'outlet_id' => 'required|numeric', // ]); // if (!$validation) { // return $this->failValidationErrors($this->validator->getErrors()); // } // $promo_code = $this->request->getVar('promo_code'); // $cart_id = $this->request->getVar('cart_id'); // $outlet_id = $this->request->getVar('outlet_id'); // $free_item = $this->request->getVar('free_item') ?? []; // if(empty($promo_code)){ // return $this->respond(['status' => 400, 'result' => 'Promo code is empty.']); // } // $promo_code_id = $this->promo_service->checkPromoCode($promo_code); // if(isset($promo_code_id['status']) && $promo_code_id['status'] == 400){ // //error message respond // return $this->respond($promo_code_id); // } // //update promo id // $this->carts->update($cart_id, ['promo_code_id' => $promo_code_id]); // $applyPromoCode = $this->calculate_service->calculateCartTotals($cart_id, $outlet_id, null, null, null, null, null, null, $free_item); // return $this->respond($applyPromoCode); // } //get all active outlets // public function outletList() // { // $outlets = $this->outlet->getActiveOperatingHoursWithDaysList(); // if(empty($outlets)){ // return $this->respond(['status' => 400, 'result' => 'No outlet data found.']); // } // return $this->respond(['status' => 200, 'result' => $outlets]); // } public function index() { $outlets = $this->outlet->getOperatingHoursWithDaysList(); if (empty($outlets)) { return $this->respond(['status' => 400, 'result' => 'No outlet data found.']); } return $this->respond(['status' => 200, 'result' => $outlets]); } public function nearestOutletList($mode = null, $latitude = null, $longitude = null) { $outlets = $this->outlet->getActiveOperatingHoursWithDaysListAndDistance($mode, $latitude, $longitude); if (empty($outlets)) { return $this->respond(['status' => 400, 'result' => 'No outlet data found.']); } return $this->respond(['status' => 200, 'result' => $outlets]); } public function showOutlet($outlet_id = null) { $result = $this->outlet->getOperatingHoursWithDays($outlet_id); if (empty($result)) { return $this->respond(['status' => 400, 'result' => 'No outlet data found.']); } return $this->respond(['status' => 200, 'result' => $result]); } public function checkPayment($order_id = null) { $order = $this->orders->find($order_id); if (!$order) { return $this->fail('Order not found', 400); } $payment_status = $order['payment_status']; if ($payment_status == 'paid') { return $this->respond(['status' => 200, 'result' => 'Success', 'order_id' => $order_id]); } else if ($payment_status == 'pending') { return $this->respond(['status' => 200, 'result' => 'Pending', 'order_id' => $order_id]); } else { return $this->respond(['status' => 400, 'result' => 'Failed', 'order_id' => $order_id]); } } /** * Get driver location coordinates for real-time tracking * Called every 5 seconds from mobile app */ public function getDriverLocation() { // Get order ID from request $order_id = $this->request->getPost('order_id') ?? $this->request->getGet('order_id'); if (!$order_id) { return $this->respond([ 'status' => 'error', 'message' => 'Order ID is required', 'data' => null ], 400); } // Get order details $orders = new Orders(); $order = $orders->select('orders.*, order_deliveries.provider_name, order_deliveries.provider_order_id, order_deliveries.status') ->join('order_deliveries', 'order_deliveries.order_id = orders.id', 'left') ->where('orders.id', $order_id) ->where('orders.deleted_at', null) ->first(); if (!$order) { return $this->respond([ 'status' => 'error', 'message' => 'Order not found', 'data' => null ], 404); } // Check if order has delivery if (!$order['provider_name'] || !$order['provider_order_id']) { return $this->respond([ 'status' => 'error', 'message' => 'Order has no active delivery', 'data' => null ], 400); } $driver_location = null; $error_message = null; try { // Check delivery provider and call respective API if ($order['provider_name'] === 'Lalamove') { $lalamove = new \App\Libraries\Lalamove(); $driver_location = $lalamove->getDriverLocation($order['provider_order_id']); if (!$driver_location || isset($driver_location['error'])) { $error_message = 'Unable to fetch Lalamove driver location'; } } elseif ($order['provider_name'] === 'Grab') { $grab = new \App\Libraries\Grab(); $driver_location = $grab->getDriverLocation($order['provider_order_id']); if (!$driver_location || isset($driver_location['error'])) { $error_message = 'Unable to fetch Grab driver location'; } } else { return $this->respond([ 'status' => 'error', 'message' => 'Unsupported delivery provider: ' . $order['provider_name'], 'data' => null ], 400); } } catch (Exception $e) { log_message('error', 'Driver location API error: ' . $e->getMessage()); $error_message = 'Failed to fetch driver location'; } // If there's an error, return error response if ($error_message) { return $this->respond([ 'status' => 'error', 'message' => $error_message, 'data' => null ], 500); } // Return driver location data return $this->respond([ 'status' => 'success', 'message' => 'Driver location retrieved successfully', 'data' => [ 'order_id' => $order_id, 'provider' => $order['provider_name'], 'delivery_status' => $order['status'], 'driver_location' => $driver_location, 'timestamp' => date('Y-m-d H:i:s'), 'last_updated' => time() ] ], 200); } }