AMS_Backend/app/Services/CartService.php
2025-11-06 13:41:06 +08:00

427 lines
19 KiB
PHP

<?
namespace App\Services;
use App\Models\CartItems;
use App\Models\MenuItemVariations;
use App\Models\CartItemOptions;
use App\Models\Carts;
use App\Models\MenuItems;
use App\Models\OutletMenus;
use App\Models\OutletTax;
use App\Models\SettingTax;
use CodeIgniter\Database\Config;
use App\Models\MenuItemOptionsGroups;
use App\Models\OptionsGroups;
use App\Models\VariationOptionsGroups;
use App\Services\PromoService;
use App\Models\Options;
class CartService
{
private $db;
private $cart_items;
private $variations;
private $options;
private $carts;
private $menu_items;
private $outlet_menus;
private $outlet_tax;
private $setting_tax;
private $cart_item_options;
private $menu_item_options_groups;
private $option_groups;
private $menu_item_variations;
private $variation_options_groups;
private $promo_service;
public function __construct()
{
$this->cart_items = new CartItems();
$this->variations = new MenuItemVariations();
$this->options = new Options();
$this->carts = new Carts();
$this->menu_items = new MenuItems();
$this->outlet_menus = new OutletMenus();
$this->outlet_tax = new OutletTax();
$this->setting_tax = new SettingTax();
$this->cart_item_options = new CartItemOptions();
$this->menu_item_options_groups = new MenuItemOptionsGroups();
$this->option_groups = new OptionsGroups();
$this->menu_item_variations = new MenuItemVariations();
$this->variation_options_groups = new VariationOptionsGroups();
$this->db = Config::connect();
}
public function addCartItem($customer_id, $outlet_id, $existing_cart, $menu_item_id, $variation_id, $option_group, $quantity, $type = null) {
// If no cart, create one
if (!$existing_cart) {
$cartData = [
'customer_id' => $customer_id,
'outlet_id' => $outlet_id,
'status' => 'active',
'item_count' => 0,
'subtotal_amount' => 0,
'discount_amount' => 0,
'tax_amount' => 0,
'grand_total' => 0,
'promo_code_id' => 0,
'promo_discount_amount' => 0,
'customer_voucher_list_id' => 0,
'voucher_discount_amount' => 0,
'created_at' => date('Y-m-d H:i:s'),
];
$cartId = $this->carts->insert($cartData);
if (!$cartId) {
return ['status' => 400, 'message' => "Failed to create cart."];
}
$existing_cart = $this->carts->find($cartId);
}
$cart = $existing_cart;
$this->db->transStart();
try {
//check outlet menu
$menuAvailable = $this->outlet_menus->where([
'menu_item_id' => $menu_item_id,
'outlet_id' => $outlet_id
])->first();
if (!$menuAvailable) {
return ['status' => 400, 'message' => 'This menu is not available for this outlet!'];
}
$menu_variation = $this->menu_item_variations->where('menu_item_id', $menu_item_id)->findAll();
if(($variation_id == 0 || $variation_id == null) && !empty($menu_variation)){ //make variation required
return ['status' => 400, 'message' => 'Please select a variation!'];
}
$required_groups = $this->getRequiredOptionGroups($menu_item_id, $variation_id);
// Validate that required options are provided
if (!empty($required_groups)) {
if (empty($option_group)) {
return ['status' => 400, 'message' => 'Required options are missing'];
}
$provided_group_ids = array_map(function ($opt) {
if (!is_object($opt)) {
$opt = (object) $opt;
}
return $opt->group_id;
}, $option_group);
foreach ($required_groups as $group) {
if (!in_array($group['id'], $provided_group_ids)) {
return ['status' => 400, 'message' => 'Required option group ' . $group['title'] . ' is missing'];
}
}
}
//Check if the new item is same with old item then update quantity
$options_match = false;
$existing_cart_item = $this->cart_items
->where('cart_id', $cart['id'])
->where('menu_item_id', $menu_item_id)
->where('variation_id', $variation_id)
->first();
if($type != 'free_item'){
if ($existing_cart_item) {
if(($type == 'pwp' && $existing_cart_item['is_pwp'] == true) || $type != 'pwp'){
// Check if options match
$options_match = true;
if (!empty($option_group)) {
// Get existing options for this cart item
$existing_options = $this->cart_item_options
->where('cart_item_id', $existing_cart_item['id'])
->findAll();
// Convert existing options to comparable format
$existing_option_ids = [];
foreach ($existing_options as $opt) {
if (!isset($existing_option_ids[$opt['option_group_id']])) {
$existing_option_ids[$opt['option_group_id']] = [];
}
$existing_option_ids[$opt['option_group_id']][] = $opt['option_id'];
}
// Convert new options to comparable format
$new_option_ids = [];
foreach ($option_group as $opt) {
if (!is_object($opt)) {
$opt = (object) $opt;
}
$new_option_ids[$opt->group_id] = $opt->option_ids;
}
// Compare options
if ($existing_option_ids != $new_option_ids) {
$options_match = false;
}
} else {
// If no options in request but existing item has options
$has_existing_options = $this->cart_item_options
->where('cart_item_id', $existing_cart_item['id'])
->countAllResults() > 0;
if ($has_existing_options) {
$options_match = false;
}
}
if ($options_match) {
// Update quantity of existing item
$new_quantity = $existing_cart_item['quantity'] + $quantity;
$new_line_subtotal = $existing_cart_item['unit_price'] * $new_quantity;
$this->cart_items->update($existing_cart_item['id'], [
'quantity' => $new_quantity,
'line_subtotal' => $new_line_subtotal
]);
}
}
}
}
// echo($variation_id);exit;
if (!$options_match) {
if ($variation_id == 0) {
$menu_item = $this->menu_items->where('status', 'active')->find($menu_item_id);
if (empty($menu_item)) {
return ['status' => 400, 'message' => "Menu Item not found!"];
}
$basePrice = $menu_item['price'];
$order_index = $this->cart_items->withDeleted()->where('cart_id', $cart['id'])->countAllResults();
// Insert cart item
$line_subtotal = $basePrice * $quantity;
$add_cart_detail = [
'cart_id' => $cart['id'],
'menu_item_id' => $menu_item_id,
'variation_id' => 0,
'title' => $menu_item['title'],
'unit_price' => $basePrice,
'quantity' => $quantity,
'line_subtotal' => $line_subtotal,
'order_index' => $order_index,
];
if($type == 'free_item'){
$add_cart_detail = [
'cart_id' => $cart['id'],
'menu_item_id' => $menu_item_id,
'variation_id' => 0,
'title' => $menu_item['title'],
'unit_price' => 0,
'quantity' => $quantity,
'line_subtotal' => 0,
'order_index' => $order_index,
'is_free_item' => 1
];
}
if($type == 'pwp'){
$add_cart_detail = [
'cart_id' => $cart['id'],
'menu_item_id' => $menu_item_id,
'variation_id' => 0,
'title' => $menu_item['title'],
'unit_price' => $menu_item['pwp_price'],
'quantity' => $quantity,
'line_subtotal' => $menu_item['pwp_price'] * $quantity,
'order_index' => $order_index,
'is_pwp' => true
];
}
// print_r($add_cart_detail);exit;
$cart_item_id = $this->cart_items->insert($add_cart_detail);
$existingGroupIds = getColumnValues($this->menu_item_options_groups, 'menu_item_id', $menu_item_id, 'option_group_id');
if (!empty($option_group)) {
foreach ($option_group as $opt) {
if (!is_object($opt)) {
$opt = (object) $opt;
}
$option_group_id = $opt->group_id;
$option_ids = $opt->option_ids;
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_num >= $option_groups['min_quantity'] && $option_num <= $option_groups['max_quantity']) {
foreach ($option_ids as $key => $value) {
$option_selected = $this->options->where('option_group_id', $option_group_id)->find($value);
if (empty($option_selected)) {
return ['status' => 400, 'message' => 'No option selected !'];
}
$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']
];
$this->cart_item_options->insert($option_data);
}
} else {
return ['status' => 400, 'message' => 'Please select correct quantity for option!'];
}
}
}
}
}
} else {
$menu_item = $this->menu_items->where('status', 'active')->find($menu_item_id);
if (empty($menu_item)) {
return ['status' => 400, 'message' => "Menu Item not found!"];
}
$menu_variation = $this->menu_item_variations->withDeleted()->find($variation_id);
if (empty($menu_variation)) {
return ['status' => 400, 'message' => "Menu Variation not found!"];
}
$item_price = $menu_variation['price'];
$order_index = $this->cart_items->withDeleted()->where('cart_id', $cart['id'])->countAllResults();
$line_subtotal = $item_price * $quantity;
$add_cart_detail = [
'cart_id' => $cart['id'],
'menu_item_id' => $menu_item_id,
'variation_id' => $variation_id,
'title' => $menu_item['title'],
'unit_price' => $item_price,
'quantity' => $quantity,
'line_subtotal' => $line_subtotal,
'order_index' => $order_index,
];
if($type == 'free_item'){
$add_cart_detail = [
'cart_id' => $cart['id'],
'menu_item_id' => $menu_item_id,
'variation_id' => $variation_id,
'title' => $menu_item['title'],
'unit_price' => 0,
'quantity' => $quantity,
'line_subtotal' => 0,
'order_index' => $order_index,
'is_free_item' => 1
];
}
if($type == 'pwp'){
$add_cart_detail = [
'cart_id' => $cart['id'],
'menu_item_id' => $menu_item_id,
'variation_id' => $variation_id,
'title' => $menu_item['title'],
'unit_price' => $menu_item['pwp_price'],
'quantity' => $quantity,
'line_subtotal' => $menu_item['pwp_price'] * $quantity,
'order_index' => $order_index,
'is_pwp' => true
];
}
$cart_item_id = $this->cart_items->insert($add_cart_detail);
if ($menu_variation) {
$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) {
if (!is_object($opt)) {
$opt = (object) $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_num >= $option_groups['min_quantity'] && $option_num <= $option_groups['max_quantity']) {
foreach ($option_ids as $key => $value) {
$option_selected = $this->options->where('option_group_id', $option_group_id)->where('id', $value)->first();
if (empty($option_selected)) {
return ['status' => 400, 'message' => 'No option selected !'];
}
$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']
];
$this->cart_item_options->insert($option_data);
}
} else {
return ['status' => 400, 'message' => 'Please select correct quantity for option!'];
}
}
}
}
}
} else {
return ['status' => 400, 'message' => 'No variation found!'];
}
}
}
// $total = $this->calculateCartTotals($cart['id'], $cart['outlet_id']);
$this->db->transComplete();
return [
'status' => 200,
'message' => 'Item added to cart successfully.',
'data' => ['cart_id' => $cart['id']]
];
} catch (\Exception $e) {
$this->db->transRollback();
return ['status' => 400, 'message' => "Something went wrong: " . $e];
}
}
public function getRequiredOptionGroups($menu_item_id, $variation_id)
{
if ($variation_id == 0) {
$existingGroupIds = getColumnValues($this->menu_item_options_groups, 'menu_item_id', $menu_item_id, 'option_group_id');
} else {
$existingGroupIds = getColumnValues($this->variation_options_groups, 'variation_id', $variation_id, 'option_group_id');
}
if(!empty($existingGroupIds)){
$data = $this->option_groups
->whereIn('id', $existingGroupIds)
->where('is_required', 1)
->findAll();
} else {
$data = [];
}
return $data;
}
}