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

509 lines
22 KiB
PHP

<?php
namespace App\Controllers\Frontend;
use App\Controllers\BaseController;
use CodeIgniter\API\ResponseTrait;
use CodeIgniter\HTTP\ResponseInterface;
use App\Models\Customer;
use App\Models\CustomerVoucherList;
use App\Models\PromoCode;
use App\Models\PromoSetting;
use App\Models\Carts;
use App\Models\VoucherPoints;
use App\Models\MenuItems;
use App\Models\MenuItemCategories;
use App\Models\CustomerPoint;
class VoucherController extends BaseController
{
use ResponseTrait;
private $customers;
private $customer_voucher_list;
private $customer_points;
private $promo_codes;
private $promo_settings;
private $carts;
private $calculate_service;
private $promo_service;
private $voucher_service;
private $menuItem;
private $menuItemCategories;
private $voucher_points;
public function __construct()
{
$this->customers = new Customer();
$this->voucher_points = new VoucherPoints();
$this->customer_voucher_list = new CustomerVoucherList();
$this->promo_codes = new PromoCode();
$this->promo_settings = new PromoSetting();
$this->carts = new Carts();
$this->calculate_service = service('calculateService');
$this->promo_service = service('promoService');
$this->voucher_service = service('voucherService');
$this->menuItem = new MenuItems();
$this->menuItemCategories = new MenuItemCategories();
}
public function claim()
{
// echo(123);exit;
$body = $this->request->getJSON(true) ?? $this->request->getPost();
$customerId = (int) ($body['customer_id'] ?? 0);
$voucherId = (int) ($body['voucher_id'] ?? 0);
if ($customerId <= 0 || $voucherId <= 0) {
return $this->respond(['status' => 400, 'message' => 'Missing customer_id or voucher_id'], 400);
}
$voucherModel = $this->voucher_points;
$custPtsModel = new CustomerPoint();
$custVoucherMod = new CustomerVoucherList();
$voucher = $voucherModel
->where('id', $voucherId)
->where('voucher_status', 'active')
->first();
if (!$voucher) {
return $this->respond(['status' => 404, 'message' => 'Voucher not found or inactive'], 404);
}
if (!empty($voucher['voucher_total_count']) && !empty($voucher['voucher_redeem_count'])) {
if ((int)$voucher['voucher_redeem_count'] >= (int)$voucher['voucher_total_count']) {
return $this->respond(['status' => 400, 'message' => 'Voucher is out of stock'], 400);
}
}
if (!empty($voucher['voucher_count_customer'])) {
$taken = $custVoucherMod->where([
'customer_id' => $customerId,
'promo_setting_id' => $voucher['promo_setting_id'] ?? null,
])->where('voucher_status !=', 'trash')->countAllResults();
if ($taken >= (int)$voucher['voucher_count_customer']) {
return $this->respond(['status' => 400, 'message' => 'You have reached the redeem limit for this voucher'], 400);
}
}
$today = date('Y-m-d');
if (!empty($voucher['voucher_expired_date']) && $today > $voucher['voucher_expired_date']) {
return $this->respond(['status' => 400, 'message' => 'Voucher already expired'], 400);
}
$lastLedger = $custPtsModel->where('customer_id', $customerId)
->orderBy('id', 'DESC')->first();
$currentBalance = $lastLedger ? (float)$lastLedger['balance'] : 0.0;
$costPoints = (float) ($voucher['voucher_point_redeem'] ?? 0);
if ($costPoints <= 0) {
return $this->respond(['status' => 400, 'message' => 'Voucher point cost is invalid'], 400);
}
if ($currentBalance < $costPoints) {
return $this->respond(['status' => 400, 'message' => 'Insufficient points'], 400);
}
$custVoucherExpiry = null;
$type = strtolower(trim($voucher['voucher_expiry_type'] ?? ''));
$value = trim($voucher['voucher_expiry_value'] ?? '');
if ($type === 'date' && !empty($voucher['voucher_expired_date'])) {
$custVoucherExpiry = $voucher['voucher_expired_date'];
} elseif ($type === 'fixed' || $type === 'days') {
$days = (int)$value;
$custVoucherExpiry = date('Y-m-d', strtotime("+{$days} days"));
} else {
$custVoucherExpiry = !empty($voucher['voucher_expired_date']) ? $voucher['voucher_expired_date'] : null;
}
$already = $custVoucherMod->where([
'customer_id' => $customerId,
'promo_setting_id' => $voucher['promo_setting_id'] ?? null,
'voucher_status' => 'active',
])->first();
if ($already) {
return $this->respond(['status' => 200, 'message' => 'Voucher already redeemed for this customer', 'data' => $already]);
}
$db = \Config\Database::connect();
$db->transStart();
$voucherCode = strtoupper('V' . $voucherId . '-' . bin2hex(random_bytes(3)));
$custVoucherId = $custVoucherMod->insert([
'promo_setting_id' => $voucher['promo_setting_id'] ?? null,
'customer_id' => $customerId,
'voucher_order_id' => 0,
'voucher_topup_id' => 0,
'voucher_code' => $voucherCode,
'voucher_expiry_date'=> $custVoucherExpiry,
'voucher_status' => 'active',
], true);
$newBalance = $currentBalance - $costPoints;
$ledgerId = $custPtsModel->insert([
'customer_id' => $customerId,
'related_id' => $voucherId,
'related_type'=> 'voucher',
'action' => 'redeem_voucher',
'current' => $currentBalance,
'in' => 0,
'out' => $costPoints,
'balance' => $newBalance,
'remark' => sprintf('Redeemed voucher "%s" (ID %d, code %s)', $voucher['voucher_name'] ?? '', $voucherId, $voucherCode),
], true);
$this->customers->update($customerId, [
'customer_point' => $newBalance
]);
$voucherModel->where('id', $voucherId)->set('voucher_redeem_count', 'voucher_redeem_count + 1', false)->update();
$db->transComplete();
if ($db->transStatus() === false) {
return $this->respond(['status' => 500, 'message' => 'Failed to redeem voucher'], 500);
}
return $this->respond([
'status' => 200,
'message' => 'Voucher redeemed successfully',
'data' => [
'customer_voucher_id' => $custVoucherId,
'ledger_id' => $ledgerId,
'voucher_code' => $voucherCode,
'new_balance' => $newBalance,
'voucher_expiry_date' => $custVoucherExpiry,
],
]);
}
public function index()
{
// echo(123123);exit;
log_message('info', 'Voucher index accessed');
$voucherName = $this->request->getGet('voucher_name');
$dateFrom = $this->request->getGet('date_from');
$dateTo = $this->request->getGet('date_to');
$builder = $this->voucher_points->builder();
$builder->where('voucher_status !=', 'trash');
if ($voucherName) {
$builder->like('voucher_name', $voucherName);
}
if ($dateFrom && $dateTo) {
$builder->where('voucher_expired_date >=', $dateFrom);
$builder->where('voucher_expired_date <=', $dateTo);
}
// ✅ Print the generated SQL
// echo $builder->getCompiledSelect();
// exit;
// All transactions
$voucherSettings = $builder->get()->getResult();
if (empty($voucherSettings)) {
return $this->respond(["status" => 400, "message" => "No Voucher Found", "data" => []]);
}
return $this->respond(["status" => 200, "message" => "Successfully retrive data!", "data" => $voucherSettings]);
}
public function show($id = null)
{
$voucherSettings = $this->voucher_points->find($id);
if (empty($voucherSettings)) {
return $this->fail("No voucher settings found.", 400);
}
$voucherSettingData = [];
if ($voucherSettings) {
$voucherSettingData[] = [
'id' => $voucherSettings['id'],
'voucher_name' => $voucherSettings['voucher_name'],
'voucher_total_count' => $voucherSettings['voucher_total_count'],
'voucher_redeem_count' => $voucherSettings['voucher_redeem_count'],
'voucher_count_customer' => $voucherSettings['voucher_count_customer'],
'voucher_expiry_type' => $voucherSettings['voucher_expiry_type'],
'voucher_expiry_value' => $voucherSettings['voucher_expiry_value'],
'voucher_expired_date' => $voucherSettings['voucher_expired_date'],
'voucher_point_redeem' => $voucherSettings['voucher_point_redeem'],
'promo_setting_id'=> $voucherSettings['promo_setting_id'],
'voucher_details'=> $voucherSettings['voucher_details'],
'voucher_tnc'=> $voucherSettings['voucher_tnc'],
'voucher_status'=> $voucherSettings['voucher_status'],
'voucher_image_url'=> getImagePath('vouchers', $voucherSettings['voucher_image']),
];
}
return $this->respond(["status" => 200, "message" => "Successfully retrive data!", "data" => $voucherSettingData]);
}
public function voucherList($customer_id)
{
if(empty($customer_id)) {
return $this->respond(['status' => 400, 'result' => 'Customer ID is empty.']);
}
$customer = $this->customers->find($customer_id);
if(empty($customer)) {
return $this->respond(['status' => 400, 'result' => 'Customer data not found.']);
}
$customer_voucher_list = $this->customer_voucher_list
->select('customer_voucher_list.*, promo_settings.description')
->join('promo_settings', 'promo_settings.id = customer_voucher_list.promo_setting_id')
->where('customer_voucher_list.customer_id', $customer_id)
->findAll();
return $this->respond(['status' => 200, 'message' =>'Customer voucher list retrieved sucessfully!', 'data' => $customer_voucher_list]);
}
public function redeemVoucher($customer_id)
{
if(empty($customer_id)) {
return $this->respond(['status' => 400, 'result' => 'Customer ID is empty.']);
}
$customer = $this->customers->find($customer_id);
if(empty($customer)) {
return $this->respond(['status' => 400, 'result' => 'Customer data not found.']);
}
$validation = $this->validate([
'order_type' => 'required',
'promo_code' => 'permit_empty',
'voucher_id' => 'permit_empty',
'cart_id' => 'required',
'outlet_id' => 'required',
]);
if (!$validation) {
return $this->failValidationErrors($this->validator->getErrors());
}
$promo_code = $this->request->getVar('promo_code');
$voucher_id = $this->request->getVar('voucher_id');
$cart_id = $this->request->getVar('cart_id');
$outlet_id = $this->request->getVar('outlet_id');
$order_type = $this->request->getVar('order_type');
if(empty($promo_code) && empty($voucher_id)) {
return $this->respond(['status' => 400, 'result' => 'Voucher code or voucher id is empty.']);
}
$getCart = $this->carts->where('customer_id', $customer_id)->where('outlet_id', $outlet_id)->where('status', 'active')->find($cart_id);
if(empty($getCart)) {
return $this->respond(['status' => 400, 'result' => 'Unable to find your cart.']);
}
if($getCart['promo_code_id'] > 0 || $getCart['customer_voucher_list_id'] > 0) {
$getCart['promo_code_id'] = 0;
$getCart['customer_voucher_list_id'] = 0;
$this->carts->update($cart_id, $getCart);
}
$free_items = [];
if(!empty($promo_code)) {
// promo code
$promo = $this->promo_codes->select('promo_codes.*, promo_settings.promo_setting')
->where('promo_codes.code', $promo_code)
->join('promo_settings', 'promo_settings.id = promo_codes.promo_setting_id')
->orderBy('promo_codes.id', 'DESC')->first();
if(empty($promo)) {
return $this->respond(['status' => 400, 'result' => 'Code not found.']);
}
$promoSettingData = json_decode($promo['promo_setting'], true);
$promo_setting = $promoSettingData['Promo'];
// print_r($promo);exit;
//check promo availability
$check_promo = $this->promo_service->checkPromoAvailability($promo['id'], $order_type, $customer_id);
//promo unavailable
if(isset($check_promo['status']) && $check_promo['status'] == 400) {
return $this->respond($check_promo);
}
if($promo_setting['promo_type'] == 'free_item'){
$free_items = [];
$isIncluded = true;
if($promo_setting['filter_type'] == 'item'){
foreach($promo_setting['free_item'] as $free_item_id){
$menu_item = $this->menuItem
->select('menu_items.id, menu_items.title, menu_images.image_url, menu_images.image_url_compressed')
->join('menu_images', 'menu_images.menu_item_id = menu_items.id', 'left')
->where('menu_items.status', 'active')
->find($free_item_id);
if($menu_item){
$free_items[] = [
'id' => $menu_item['id'],
'title' => $menu_item['title'],
'image_url' => getMenuImage($menu_item['id']),
// 'image_url_compressed' => getMenuImage($menu_item['id'])
];
}
}
}
if($promo_setting['filter_type'] == 'category'){
foreach($promo_setting['free_item'] as $free_item_id){
$menu_items = $this->menuItemCategories
->select('menu_items.id, menu_items.title, menu_item_categories.category_id')
->join('menu_items', 'menu_items.id = menu_item_categories.menu_item_id')
->where('menu_item_categories.category_id', $free_item_id)
->where('menu_items.status', 'active')
->findAll();
if($menu_items){
foreach($menu_items as $item){
$menu_item = $this->menuItem
->select('menu_items.id, menu_items.title, menu_images.image_url, menu_images.image_url_compressed')
->join('menu_images', 'menu_images.menu_item_id = menu_items.id', 'left')
->where('menu_items.status', 'active')
->find($item['id']);
if($menu_item){
$free_items[$item['category_id']][] = [
'id' => $menu_item['id'],
'category_id' => $item['category_id'],
'title' => $menu_item['title'],
'image_url' => getMenuImage($menu_item['id']),
// 'image_url_compressed' => getMenuImage($menu_item['id'])
];
}
}
}
}
}
$afterPromo['free_item_list'] = $free_items;
}
//promo available
$this->carts->update($cart_id, ['promo_code_id' => $promo['id'], 'customer_voucher_list_id' => 0]);
// $applyPromoCode = $this->calculate_service->calculateCartTotals($cart_id, $outlet_id, null, null, null, null, null, null, 'promo');
} else if(!empty($voucher_id)){
// use voucher
// please add in voucher_expiry_date
$customer_voucher = $this->customer_voucher_list
->select('customer_voucher_list.*, promo_settings.promo_setting')
->join('promo_settings', 'promo_settings.id = customer_voucher_list.promo_setting_id')
->where('customer_voucher_list.id', $voucher_id)
->first();
if(empty($customer_voucher)){
return $this->respond(['status' => 400, 'result' => 'Voucher not found.']);
}
$promoSettingData = json_decode($customer_voucher['promo_setting'], true);
$promo_setting = $promoSettingData['Promo'];
// print_r($promo);exit;
//check voucher availability
$check_voucher = $this->voucher_service->checkVoucherAvailability($customer_voucher['id'], $order_type, $customer_id);
//voucher unavailable
if(isset($check_voucher['status']) && $check_voucher['status'] == 400) {
return $this->respond($check_voucher);
}
$free_items = [];
if($promo_setting['promo_type'] == 'free_item'){
$isIncluded = true;
if($promo_setting['filter_type'] == 'item'){
foreach($promo_setting['free_item'] as $free_item_id){
$menu_item = $this->menuItem
->select('menu_items.id, menu_items.title, menu_images.image_url, menu_images.image_url_compressed')
->join('menu_images', 'menu_images.menu_item_id = menu_items.id', 'left')
->where('menu_items.status', 'active')
->find($free_item_id);
if($menu_item){
$free_items[] = [
'id' => $menu_item['id'],
'title' => $menu_item['title'],
'image_url' => getMenuImage($menu_item['id']),
// 'image_url_compressed' => getMenuImage($menu_item['id'])
];
}
}
}
if($promo_setting['filter_type'] == 'category'){
foreach($promo_setting['free_item'] as $free_item_id){
$menu_items = $this->menuItemCategories
->select('menu_items.id, menu_items.title, menu_item_categories.category_id')
->join('menu_items', 'menu_items.id = menu_item_categories.menu_item_id')
->where('menu_item_categories.category_id', $free_item_id)
->where('menu_items.status', 'active')
->findAll();
if($menu_items){
foreach($menu_items as $item){
$menu_item = $this->menuItem
->select('menu_items.id, menu_items.title, menu_images.image_url, menu_images.image_url_compressed')
->join('menu_images', 'menu_images.menu_item_id = menu_items.id', 'left')
->where('menu_items.status', 'active')
->find($item['id']);
if($menu_item){
$free_items[$item['category_id']][] = [
'id' => $menu_item['id'],
'category_id' => $item['category_id'],
'title' => $menu_item['title'],
'image_url' => getMenuImage($menu_item['id']),
// 'image_url_compressed' => getMenuImage($menu_item['id'])
];
}
}
}
}
}
}
//voucher available
$this->carts->update($cart_id, ['customer_voucher_list_id' => $customer_voucher['id'], 'promo_code_id' => 0]);
// $applyPromoCode = $this->calculate_service->calculateCartTotals($cart_id, $outlet_id, null, null, null, null, null, null, 'voucher');
}
return $this->respond(['status' => 200, 'result' => 'Voucher applied successfully.', 'data' => $free_items]);
}
public function removeVoucher($customer_id)
{
$cart_id = $this->request->getVar('cart_id');
if(empty($cart_id)){
return $this->respond(['status' => 400, 'result' => 'Cart id is empty.']);
}
$getCart = $this->carts->where('customer_id', $customer_id)->where('status', 'active')->find($cart_id);
if(empty($getCart)) {
return $this->respond(['status' => 400, 'result' => 'Unable to find your cart.']);
}
$this->calculate_service->resetVoucher($cart_id);
return $this->respond(['status' => 200, 'result' => 'Voucher removed successfully.']);
}
}