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

601 lines
27 KiB
PHP

<?php
namespace App\Controllers\Frontend;
use App\Models\CartItemOptions;
use App\Models\CartItems;
use App\Models\Carts;
use App\Models\MenuItemOptionsGroups;
use App\Models\MenuItems;
use App\Models\MenuItemVariations;
use App\Models\Options;
use App\Models\OptionsGroups;
use App\Models\Outlet;
use App\Models\OutletMenus;
use App\Models\VariationOptionsGroups;
use CodeIgniter\Database\Config;
use CodeIgniter\HTTP\ResponseInterface;
use CodeIgniter\RESTful\ResourceController;
use App\Services\CartService;
class CartController extends ResourceController
{
private $carts;
private $cart_items;
private $cart_item_options;
private $menu_items;
private $menu_item_options_groups;
private $option_groups;
private $options;
private $menu_item_variations;
private $variation_options_groups;
private $outlet_menus;
private $outlet;
private $db;
private $cart_service;
private $calculate_service;
private $promo_service;
private $voucher_service;
public function __construct()
{
$this->carts = new Carts();
$this->cart_items = new CartItems();
$this->cart_item_options = new CartItemOptions();
$this->menu_items = new MenuItems();
$this->menu_item_options_groups = new MenuItemOptionsGroups();
$this->option_groups = new OptionsGroups();
$this->options = new Options();
$this->menu_item_variations = new MenuItemVariations();
$this->variation_options_groups = new VariationOptionsGroups();
$this->outlet_menus = new OutletMenus();
$this->outlet = new Outlet();
$this->db = Config::connect();
$this->cart_service = service('cartService');
$this->calculate_service = service('calculateService');
$this->promo_service = service('promoService');
$this->voucher_service = service('voucherService');
}
public function checkPwp($cart_id)
{
$cart = $this->carts->find($cart_id);
if (!$cart) {
return ['status' => 400, 'result' => 'Cart not found.'];
}
$cart_items = $this->cart_items
->where('cart_id', $cart_id)
->findAll();
if (empty($cart_items)) {
return ['status' => 200, 'result' => []];
}
$cart_item_ids = array_column($cart_items, 'menu_item_id');
$pwp_promos = $this->db->table('pwp')
->where('deleted_at', null)
->get()
->getResultArray();
$eligible_pwps = [];
foreach ($pwp_promos as $promo) {
$requiredIds = explode(',', $promo['selected_item']);
$pwpIds = explode(',', $promo['pwp_item_id']);
$hasQualifier = count(array_intersect($cart_item_ids, $requiredIds)) > 0;
if ($hasQualifier) {
foreach ($pwpIds as $pid) {
$menu_item = $this->menu_items->find($pid);
if (!$menu_item) continue;
$eligible_pwps[] = [
'pwp_id' => $promo['id'],
'pwp_item' => [
'id' => $menu_item['id'],
'title' => $menu_item['title'],
'original_price' => $menu_item['price'],
'pwp_price' => $promo['amount'],
],
'requires' => $requiredIds,
'requirement' => [
'type' => $promo['amount_type'],
'value' => $promo['order_index']
]
];
}
}
}
return ['status' => 200, 'result' => $eligible_pwps];
}
public function getCartDetail()
{
// echo(123);exit;
$validation = $this->validate([
'customer_id' => 'required|numeric',
'outlet_id' => 'required|numeric',
'selected_date' => 'permit_empty|string',
'selected_time' => 'permit_empty|string',
'latitude' => 'permit_empty|string',
'longitude' => 'permit_empty|string',
'order_type' => 'permit_empty|string',
'address' => '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');
$selected_date = $this->request->getVar('selected_date') ?? date('Y-m-d');
$selected_time = $this->request->getVar('selected_time') ?? date('H:i');
$latitude = $this->request->getVar('latitude');
$longitude = $this->request->getVar('longitude');
$order_type = strtolower(str_replace('-', '', $this->request->getVar('order_type')));
$address = $this->request->getVar('address');
$outlet = $this->outlet->where('id', $outlet_id)->first();
if (!$outlet) {
return $this->respond(['status' => 405, 'message' => 'Outlet not found'], 400);
}
$outlet['serve_method'] = strtolower(str_replace('-', '', $outlet['serve_method']));
//check order type
$serve_method = explode(',', $outlet['serve_method']);
if ($outlet['status'] == 'inactive' || $outlet['deleted_at'] != null || !in_array($order_type, $serve_method)) {
return $this->respond(['status' => 405, 'message' => 'Outlet not available for this order type'], 400);
}
$cart = $this->carts->where('customer_id', $customer_id)
->where('outlet_id', $outlet_id)
->where('status', 'active')
->where('deleted_at', null)
->orderBy('id', 'DESC')
->first();
if (!$cart) {
return $this->respond("No active cart found for this customer.", 200);
}
$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_detail = $this->calculate_service->calculateCartTotals($cart['id'], $cart['outlet_id'], $selected_date, $selected_time, $latitude, $longitude, $order_type, $address, $promo_or_voucher);
// print_r($cart_total_detail);
// exit;
if (isset($cart_total_detail['status']) && $cart_total_detail['status'] == 400) {
$response = [
'status' => 400,
'message' => $cart_total_detail['result']
];
return $this->respond($response, 400);
}
$cart_total_detail = $cart_total_detail['data'];
// $pwp_check = $this->checkPwp($cart['id']);
// $eligible_pwps = ($pwp_check['status'] === 200) ? $pwp_check['result'] : [];
unset($cart_total_detail['invalid_items']);
return $this->respond([
'status' => 200,
'message' => 'Cart retrieved successfully.',
'data' => $cart_total_detail,
// 'eligible_pwps' => $eligible_pwps
]);
}
public function addCart()
{
$validation = $this->validate([
'customer_id' => 'required|numeric',
'outlet_id' => 'required|numeric',
'menu_item_id' => 'required|numeric',
'quantity' => 'required|numeric',
'variation_id' => 'permit_empty|numeric',
'option' => 'permit_empty',
'is_free_item' => 'permit_empty',
'is_pwp' => 'permit_empty',
]);
if (!$validation) {
return $this->failValidationErrors($this->validator->getErrors());
}
$customer_id = $this->request->getVar('customer_id');
$outlet_id = $this->request->getVar('outlet_id');
$menu_item_id = $this->request->getVar('menu_item_id');
$variation_id = $this->request->getVar('variation_id') ?? 0;
$option_group = $this->request->getVar('option');
$quantity = $this->request->getVar('quantity');
$is_free_item_type = $this->request->getVar('is_free_item') == true ? 'free_item' : null;
$is_pwp_type = $this->request->getVar('is_pwp') == true ? 'pwp' : null;
$type = $is_free_item_type ?? $is_pwp_type;
// print_r($this->request->getVar('is_free_item') == true ? 'free_item' : null);exit;
// Check if existing cart
$existing_cart = $this->carts
->where('customer_id', $customer_id)
->where('outlet_id', $outlet_id)
->where('status', 'active')
->first();
$addCart = $this->cart_service->addCartItem($customer_id, $outlet_id, $existing_cart, $menu_item_id, $variation_id, $option_group, $quantity, $type);
return $this->respond($addCart);
}
public function updateCart()
{
$validation = $this->validate([
'customer_id' => 'required|numeric',
'outlet_id' => 'required|numeric',
'action' => 'required|numeric',
]);
if (!$validation) {
return $this->failValidationErrors($this->validator->getErrors());
}
$customer_id = $this->request->getVar('customer_id');
$outlet_id = $this->request->getVar('outlet_id');
$action = $this->request->getVar('action');
$cart_item_id = $this->request->getVar('cart_item_id');
$quantity = $this->request->getVar('quantity');
$variation_id = $this->request->getVar('variation_id');
$option_group = $this->request->getVar('option');
$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);
}
$this->db->transStart();
try {
switch ($action) {
case 1: // Update quantity
$cart_item = $this->cart_items->find($cart_item_id);
if (!$cart_item || $cart_item['cart_id'] != $cart['id']) {
return $this->fail('Cart item not found', 400);
}
$data = [
'unit_price' => $cart_item['unit_price'],
'quantity' => $quantity,
'line_subtotal' => $cart_item['unit_price'] * $quantity
];
$this->cart_items->update($cart_item['id'], $data);
break;
case 2: // Update Option
$cart_item = $this->cart_items->find($cart_item_id);
if (!$cart_item || $cart_item['cart_id'] != $cart['id']) {
return $this->fail('Cart item not found', 400);
}
$menu_item_id = $cart_item['menu_item_id'];
if (!isset($variation_id)) {
return $this->fail('No variation found', 400);
}
$required_groups = $this->cart_service->getRequiredOptionGroups($menu_item_id, $variation_id);
// Validate that required options are provided
if (!empty($required_groups)) {
if (empty($option_group)) {
return $this->fail('Required options are missing', 400);
}
$provided_group_ids = array_map(function ($opt) {
return $opt->group_id;
}, $option_group);
foreach ($required_groups as $group) {
if (!in_array($group['id'], $provided_group_ids)) {
return $this->fail('Required option group ' . $group['title'] . ' is missing', 400);
}
}
}
if ($variation_id == 0) {
$menu_item = $this->menu_items->where('status', 'active')->find($menu_item_id);
if (empty($menu_item)) {
return $this->fail("Menu Item not found!", 400);
}
$basePrice = $menu_item['price'];
$line_subtotal = $basePrice * $quantity;
$update_cart_detail = [
'variation_id' => 0,
'title' => $menu_item['title'],
'unit_price' => $basePrice,
'quantity' => $quantity,
'line_subtotal' => $line_subtotal,
];
$this->cart_items->update($cart_item['id'], $update_cart_detail);
if (!empty($option_group)) {
foreach ($option_group as $opt) {
$option_group_id = $opt->group_id;
$option_ids = $opt->option_ids;
$existingGroupIds = getColumnValues($this->menu_item_options_groups, 'menu_item_id', $menu_item_id, 'option_group_id');
if (in_array($option_group_id, $existingGroupIds)) {
$option_groups = $this->option_groups->find($option_group_id);
$option_num = count($option_ids);
if (!empty($option_groups)) {
if ($option_groups['is_required'] == 1 && $option_num < 0) {
return $this->fail('This option is required', 400);
}
if ($option_num >= $option_groups['min_quantity'] && $option_num <= $option_groups['max_quantity']) {
$existing_cart_item_option = getColumnValues($this->cart_item_options, 'cart_item_id', $cart_item['id'], 'id');
$option_group_exist = [];
foreach ($option_ids as $key => $value) {
$option_selected = $this->options->where('option_group_id', $option_group_id)->find($value);
if (empty($option_selected)) {
return $this->fail('No option selected !', 400);
}
$option_data = [
'cart_item_id' => $cart_item['id'],
'option_id' => $value,
'option_group_id' => $option_group_id,
'option_title' => $option_selected['title'],
'price_adjustment' => $option_selected['price_adjustment']
];
$current_option_existing = $this->cart_item_options->where('cart_item_id', $cart_item['id'])
->where('option_id', $value)
->where('option_group_id', $option_group_id)
->first();
if ($current_option_existing) {
$option_group_exist[] = $current_option_existing['id'];
} else {
$this->cart_item_options->insert($option_data);
}
}
foreach ($existing_cart_item_option as $exist_option_id) {
if (!in_array($exist_option_id, $option_group_exist)) {
$this->cart_item_options->delete($exist_option_id);
}
}
} else {
return $this->fail('Please select correct quantity for option!', 400);
}
}
}
}
} else {
$existing_cart_item_option = getColumnValues($this->cart_item_options, 'cart_item_id', $cart_item['id'], 'id');
$this->cart_item_options->whereIn('id', $existing_cart_item_option)->delete();
}
} else {
$menu_item = $this->menu_items->where('status', 'active')->find($menu_item_id);
if (empty($menu_item)) {
return $this->fail("Menu Item not found!", 400);
}
$menu_variation = $this->menu_item_variations->where('menu_item_id', $menu_item_id)->first();
$basePrice = $menu_variation['price'];
$line_subtotal = $basePrice * $quantity;
$update_cart_detail = [
'variation_id' => $variation_id,
'title' => $menu_item['title'],
'unit_price' => $basePrice,
'quantity' => $quantity,
'line_subtotal' => $line_subtotal,
];
$this->cart_items->update($cart_item['id'], $update_cart_detail);
if (!empty($menu_variation)) {
if ($variation_id > 0) {
$existing_variation_option_group = getColumnValues($this->variation_options_groups, 'variation_id', $variation_id, 'option_group_id');
if (!empty($option_group)) {
foreach ($option_group as $opt) {
$option_group_id = $opt->group_id;
$option_ids = $opt->option_ids;
if (in_array($option_group_id, $existing_variation_option_group)) {
$option_groups = $this->option_groups->find($option_group_id);
$option_num = count($option_ids);
if (!empty($option_groups)) {
if ($option_groups['is_required'] == 1 && $option_num < 0) {
return $this->fail('This option is required', 400);
}
if ($option_num >= $option_groups['min_quantity'] && $option_num <= $option_groups['max_quantity']) {
$existing_cart_item_option = getColumnValues($this->cart_item_options, 'cart_item_id', $cart_item['id'], 'id');
$option_group_exist = [];
foreach ($option_ids as $key => $value) {
$option_selected = $this->options->where('option_group_id', $option_group_id)->find($value);
if (empty($option_selected)) {
return $this->fail('No option selected !', 400);
}
$option_data = [
'cart_item_id' => $cart_item['id'],
'option_id' => $value,
'option_group_id' => $option_group_id,
'option_title' => $option_selected['title'],
'price_adjustment' => $option_selected['price_adjustment']
];
$current_option_existing = $this->cart_item_options->where('cart_item_id', $cart_item['id'])
->where('option_id', $value)
->where('option_group_id', $option_group_id)
->first();
if ($current_option_existing) {
$option_group_exist[] = $current_option_existing['id'];
} else {
$this->cart_item_options->insert($option_data);
}
}
foreach ($existing_cart_item_option as $exist_option_id) {
if (!in_array($exist_option_id, $option_group_exist)) {
$this->cart_item_options->delete($exist_option_id);
}
}
} else {
return $this->fail('Please select correct quantity for option!', 400);
}
}
}
}
} else {
$existing_cart_item_options = $this->cart_item_options
->where('cart_item_id', $cart_item['id'])
->findAll();
if (!empty($existing_cart_item_options)) {
$option_ids = array_column($existing_cart_item_options, 'id');
$this->cart_item_options->whereIn('id', $option_ids)->delete();
}
}
} else {
return $this->fail('No variation found!', 400);
}
}
}
break;
case 3: // Remove one item
$cart_item = $this->cart_items->find($cart_item_id);
// print_r(123123);exit;
if (!$cart_item || $cart_item['cart_id'] != $cart['id']) {
return $this->fail('Cart item not found', 400);
}
$this->cart_items->delete($cart_item['id']);
$this->cart_item_options->where('cart_item_id', $cart_item['id'])->delete();
break;
case 4: // Remove all items
$all_cart_item = $this->cart_items->where('cart_id', $cart['id'])->findAll();
foreach ($all_cart_item as $item) {
$this->cart_item_options->where('cart_item_id', $item['id'])->delete();
$this->cart_items->delete($item['id']);
}
break;
default:
return $this->fail('Invalid action', 400);
break;
}
// $this->calculate_service->calculateCartTotals($cart['id'], $outlet_id);
$this->db->transComplete();
return $this->respond([
'status' => 200,
'message' => 'Cart updated successfully'
]);
} catch (\Exception $e) {
$this->db->transRollback();
return $this->fail($e->getMessage(), 400);
}
}
public function deleteCart()
{
$validation = $this->validate([
'customer_id' => 'required|numeric',
'outlet_id' => 'required|numeric',
]);
if (!$validation) {
return $this->failValidationErrors($this->validator->getErrors());
}
$customer_id = $this->request->getVar('customer_id');
$outlet_id = $this->request->getVar('outlet_id');
$cart = $this->carts->where('customer_id', $customer_id)
->where('outlet_id', $outlet_id)
->where('status', 'active')
->first();
if ($cart) {
$this->carts->update($cart['id'], ['status' => 'trash']);
$this->carts->delete($cart['id']);
$exist_cart_item = getColumnValues($this->cart_items, 'cart_id', $cart['id'], 'id');
$this->cart_items->where('cart_id', $cart['id'])->delete();
$this->cart_item_options->whereIn('cart_item_id', $exist_cart_item)->delete();
return $this->respond([
'status' => 200,
'message' => 'Cart delete successfully'
]);
} else {
return $this->fail('Cart not found', 400);
}
}
public function getCartItemsDetails($cart_item_id = null)
{
$cart_item = $this->cart_items->find($cart_item_id);
if (!$cart_item) {
return $this->fail('Cart item not found', 400);
}
$cart_item['variation'] = $this->menu_item_variations->find($cart_item['variation_id']);
$cart_item['options'] = $this->cart_item_options
->select('cart_item_options.*, options_groups.title as option_group_title')
->join('options_groups', 'options_groups.id = cart_item_options.option_group_id', 'left')
->where('cart_item_id', $cart_item_id)
->findAll();
return $this->respond([
'status' => 200,
'message' => 'Cart item details retrieved successfully',
'data' => $cart_item
]);
}
}