452 lines
19 KiB
PHP
452 lines
19 KiB
PHP
<?php
|
|
|
|
namespace App\Services;
|
|
|
|
use App\Models\PromoSetting;
|
|
use App\Models\PromoCode;
|
|
use App\Models\PromoRedemptionRecord;
|
|
use App\Models\MenuItems;
|
|
use App\Models\MenuItemCategories;
|
|
use App\Models\Carts;
|
|
|
|
helper('promo');
|
|
class PromoService
|
|
{
|
|
private $promoSetting;
|
|
private $promoCode;
|
|
private $promoRedemptionRecord;
|
|
private $menuItem;
|
|
private $menuItemCategories;
|
|
private $carts;
|
|
private $cart_service;
|
|
public function __construct()
|
|
{
|
|
|
|
$this->promoSetting = new PromoSetting();
|
|
$this->promoCode = new PromoCode();
|
|
$this->promoRedemptionRecord = new PromoRedemptionRecord();
|
|
$this->menuItem = new MenuItems();
|
|
$this->carts = new Carts();
|
|
$this->menuItemCategories = new MenuItemCategories();
|
|
$this->cart_service = service('cartService');
|
|
}
|
|
|
|
public function checkPromoAvailability($promo_code_id, $order_type, $customer_id){
|
|
$promo_code = $this->promoCode->where('deleted_at', null)->find($promo_code_id);
|
|
|
|
if (empty($promo_code)) {
|
|
return ['status' => 400, 'result' => 'Promotion does not exist.'];
|
|
}
|
|
|
|
//Filter by date and time
|
|
$current_date = date('Y-m-d');
|
|
$current_time = date('H:i');
|
|
|
|
if ($current_date < $promo_code['start_date'] || $current_date > $promo_code['end_date']) {
|
|
return ['status' => 400, 'result' => 'Promotion already expired.'];
|
|
}
|
|
|
|
// Check day/time validity
|
|
$validity = json_decode($promo_code['customize_validity'], true);
|
|
$dayMap = [
|
|
'mon' => 'mon',
|
|
'tue' => 'tue',
|
|
'wed' => 'wed',
|
|
'thu' => 'thurs',
|
|
'fri' => 'fri',
|
|
'sat' => 'sat',
|
|
'sun' => 'sun'
|
|
];
|
|
|
|
$current_day_key = $dayMap[strtolower(date('D'))];
|
|
|
|
if (isset($validity[$current_day_key]) && $validity[$current_day_key]['enabled']) {
|
|
$startTime = $validity[$current_day_key]['startTime'];
|
|
$endTime = $validity[$current_day_key]['endTime'];
|
|
|
|
if ($current_time < $startTime || $current_time > $endTime) {
|
|
return ['status' => 400, 'result' => 'Promo code not valid at this time.'];
|
|
}
|
|
} else {
|
|
return ['status' => 400, 'result' => 'Promo Code not valid on this day.'];
|
|
}
|
|
|
|
//Check how many left for the promotion
|
|
$promotionAlreadyRedeem = $this->promoRedemptionRecord->where('promo_codes_id', $promo_code['id'])->countAllResults();
|
|
|
|
if($promotionAlreadyRedeem >= $promo_code['total_redemption_limit'] && $promo_code['total_redemption_limit'] != 0){
|
|
return ['status' => 400, 'result' => 'Promo Code already fully redeemed.'];
|
|
}
|
|
|
|
//Check how many left for the customer / customer can redeem multiple or one times
|
|
$customerAlreadyRedeem = $this->promoRedemptionRecord ->where('promo_codes_id', $promo_code['id'])->where('customer_id', $customer_id)->countAllResults();
|
|
|
|
if($promo_code['usage_limit_type'] == 'one' && $customerAlreadyRedeem > 0){
|
|
return ['status' => 400, 'result' => 'Promo Code only can be redeemed once.'];
|
|
}
|
|
|
|
if($promo_code['usage_limit_type'] == 'multiple' && $customerAlreadyRedeem >= $promo_code['usage_limit'] && $promo_code['usage_limit'] != 0){
|
|
return ['status' => 400, 'result' => 'Promo Code only can be redeemed '. $promo_code['usage_limit'] .' times.'];
|
|
}
|
|
|
|
//Check if the promotion is valid for the order type
|
|
//order type = delivery, pick-up, dine-in, reservation
|
|
$allowed_order_types = ['delivery', 'pickup', 'dinein', 'reservation'];
|
|
if (!in_array($order_type, $allowed_order_types)) {
|
|
return ['status' => 400, 'result' => 'Invalid order type.'];
|
|
}
|
|
|
|
$promo_code['promo_order_type'] = explode(',', $promo_code['promo_order_type']);
|
|
// print_r($order_type);exit;
|
|
|
|
if (!in_array($order_type, $promo_code['promo_order_type']) && !in_array("all", $promo_code['promo_order_type'])) {
|
|
return ['status' => 400, 'result' => 'Promo Code only valid for ' . $order_type . ' order.'];
|
|
}
|
|
|
|
}
|
|
|
|
// public function checkPromoLogic($promo_setting_id, $cart_items, $subtotal, $customer_id, $outlet_id, $order_type = 'pickup', $delivery_fee = 0){
|
|
public function checkPromoLogic($promo_setting_id, $cart_items, $subtotal, $customer_id, $outlet_id, $order_type, $delivery_fee) {
|
|
|
|
//Check if it has minimum spend requirement
|
|
$promoSetting = $this->promoSetting->where('status', 'active')->find($promo_setting_id);
|
|
if(empty($promoSetting)){
|
|
return ['status' => 400, 'result' => 'Promo Code does not exist.'];
|
|
}
|
|
|
|
$promoSettingData = json_decode($promoSetting['promo_setting'], true);
|
|
$minimumSpend = $promoSettingData['MinimumSpend'];
|
|
$promo = $promoSettingData['Promo'];
|
|
|
|
|
|
if ($minimumSpend['type'] !== 'none') {
|
|
|
|
//minimum spend of subtotal amount (excluded options price)
|
|
if($minimumSpend['type'] == 'total' && $minimumSpend['amount_type'] == 'amount'){
|
|
if ($subtotal < $minimumSpend['amount']) {
|
|
return ['status' => 400, 'result' => 'Minimum spend requirement not met.'];
|
|
}
|
|
}
|
|
|
|
//minimum quantity in item / category
|
|
if(($minimumSpend['type'] == 'item' || $minimumSpend['type'] == 'category') && $minimumSpend['amount_type'] == 'quantity'){
|
|
|
|
$minimumQuantity = 0;
|
|
if($minimumSpend['type'] == 'item'){
|
|
foreach($cart_items as $item){
|
|
if(in_array($item['menu_item_id'], $minimumSpend['filter'])){
|
|
$minimumQuantity += $item['quantity'];
|
|
}
|
|
}
|
|
|
|
} else if ($minimumSpend['type'] == 'category') {
|
|
foreach($cart_items as $item){
|
|
$category_ids = getMenuCategory($item['menu_item_id']);
|
|
foreach($category_ids as $category_id){
|
|
if(in_array($category_id['id'], $minimumSpend['filter'])){
|
|
$minimumQuantity += $item['quantity'];
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
if($minimumQuantity < $minimumSpend['amount']){
|
|
return ['status' => 400, 'result' => 'Minimum quantity requirement for this promo code is not met.'];
|
|
}
|
|
}
|
|
|
|
//minmum every item / category have certain quantity
|
|
if (($minimumSpend['type'] == 'item' || $minimumSpend['type'] == 'category') &&$minimumSpend['amount_type'] == 'every_quantity') {
|
|
$everyQuantity = (int)$minimumSpend['amount'];
|
|
$validItems = [];
|
|
|
|
if ($minimumSpend['type'] == 'item') {
|
|
// Build a map of menu_item_id to quantity
|
|
foreach ($cart_items as $item) {
|
|
if (in_array($item['menu_item_id'], $minimumSpend['filter'])) {
|
|
$validItems[$item['menu_item_id']] = ($validItems[$item['menu_item_id']] ?? 0) + $item['quantity'];
|
|
}
|
|
}
|
|
|
|
// Check all required filters are present
|
|
foreach ($minimumSpend['filter'] as $requiredId) {
|
|
if (!isset($validItems[$requiredId])) {
|
|
return ['status' => 400, 'result' => 'Required item(s) is not found in cart.'];
|
|
}
|
|
if ((int)$validItems[$requiredId] < $everyQuantity) {
|
|
return ['status' => 400, 'result' => 'Every quantity requirement for this promo code is not met.'];
|
|
}
|
|
}
|
|
}
|
|
|
|
if ($minimumSpend['type'] == 'category') {
|
|
foreach ($cart_items as $item) {
|
|
$category_ids = getMenuCategory($item['menu_item_id']);
|
|
foreach ($category_ids as $cat) {
|
|
$cat_id = $cat['id'];
|
|
if (in_array($cat_id, $minimumSpend['filter'])) {
|
|
if (!isset($validItems[$cat_id])) {
|
|
$validItems[$cat_id] = $item['quantity'];
|
|
}else{
|
|
$validItems[$cat_id] += $item['quantity'];
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
foreach ($minimumSpend['filter'] as $requiredCatId) {
|
|
if (!isset($validItems[$requiredCatId])) {
|
|
return ['status' => 400, 'result' => 'Required category item(s) is not found in cart.'];
|
|
}
|
|
if ((int)$validItems[$requiredCatId] < $everyQuantity) {
|
|
return ['status' => 400, 'result' => 'Every quantity requirement for this promo code is not met.'];
|
|
}
|
|
}
|
|
}
|
|
}
|
|
if (($minimumSpend['type'] == 'item' || $minimumSpend['type'] == 'category') && $minimumSpend['amount_type'] == 'amount') {
|
|
$eligibleSubtotal = 0.0;
|
|
// print_r($minimumSpend);
|
|
// print_r($cart_items);
|
|
// exit;
|
|
foreach ($cart_items as $item) {
|
|
if ($minimumSpend['type'] === 'item') {
|
|
if (in_array($item['menu_item_id'], $minimumSpend['filter'])) {
|
|
$eligibleSubtotal += (float)$item['line_subtotal'];
|
|
}
|
|
} else {
|
|
$category_ids = getMenuCategory($item['menu_item_id']);
|
|
foreach ($category_ids as $cat) {
|
|
if (in_array($cat['id'], haystack: $minimumSpend['filter'])) {
|
|
$eligibleSubtotal += (float)$item['line_subtotal'];
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
// print_r($eligibleSubtotal);exit;
|
|
if ($eligibleSubtotal < (float)$minimumSpend['amount']) {
|
|
return ['status' => 400, 'result' => 'Minimum spend on eligible items not met.'];
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
$afterPromo = [];
|
|
$promo_discount_total = 0;
|
|
$afterPromo['promo_discount_total'] = 0;
|
|
$afterPromo['delivery_fee'] = 0;
|
|
$afterPromo['free_item_list'] = [];
|
|
|
|
//Discount
|
|
if ($promo['promo_type'] == 'discount') {
|
|
$promoPrice = 0;
|
|
$total = 0;
|
|
// $capped_at = $promo['capped_at'] ?? 0;
|
|
|
|
// All
|
|
if ($promo['filter_type'] == 'total') {
|
|
$promoPrice = calculatePromoPrice($subtotal, $promo['amount'], $promo['discount_type']);
|
|
$total = $subtotal;
|
|
}
|
|
|
|
// Item
|
|
if ($promo['filter_type'] == 'item') {
|
|
// $total = 0;
|
|
foreach ($cart_items as $item) {
|
|
if (in_array($item['menu_item_id'], $promo['filter'])) {
|
|
$total += $item['line_subtotal'];
|
|
}
|
|
}
|
|
|
|
switch($promo['discount_type']){
|
|
case 'amount':
|
|
$promoPrice = $promo['amount'];
|
|
break;
|
|
case 'percentage':
|
|
$promoPrice = calculatePromoPrice($total, $promo['amount'], $promo['discount_type']);
|
|
break;
|
|
}
|
|
}
|
|
|
|
// Category
|
|
if ($promo['filter_type'] == 'category') {
|
|
foreach ($cart_items as $item) {
|
|
$category_ids = getMenuCategory($item['menu_item_id']);
|
|
foreach ($category_ids as $category_id) {
|
|
if (in_array($category_id['id'], $promo['filter'])) {
|
|
$total += $item['line_subtotal'];
|
|
}
|
|
}
|
|
}
|
|
switch($promo['discount_type']){
|
|
case 'amount':
|
|
$promoPrice = $promo['amount'];
|
|
break;
|
|
case 'percentage':
|
|
$promoPrice = calculatePromoPrice($total, $promo['amount'], $promo['discount_type']);
|
|
break;
|
|
}
|
|
}
|
|
|
|
// if($promo['discount_type'] == 'percentage'){
|
|
// if($promoPrice > $capped_at){
|
|
// $promoPrice = $capped_at;
|
|
// }
|
|
// }
|
|
|
|
if($promoPrice > $total){
|
|
$promoPrice = $total;
|
|
}
|
|
|
|
$afterPromo['promo_discount_total'] = $promoPrice;
|
|
}
|
|
|
|
//Next Item
|
|
if ($promo['promo_type'] == 'next_item') {
|
|
if (count($cart_items) < 2) {
|
|
return ['status' => 400, 'result' => 'At least two items are required for this promo code.'];
|
|
}
|
|
|
|
$eligibleItems = [];
|
|
|
|
if ($promo['filter_type'] == 'item') {
|
|
foreach ($cart_items as $item) {
|
|
if (in_array($item['menu_item_id'], $promo['filter'])) {
|
|
$eligibleItems[] = $item;
|
|
}
|
|
}
|
|
|
|
if (count($eligibleItems) < 2) {
|
|
return ['status' => 400, 'result' => 'Two eligible items required for this promo code.'];
|
|
}
|
|
|
|
$lowestItem = $eligibleItems[0];
|
|
foreach ($eligibleItems as $item) {
|
|
if ((float)$item['unit_price'] < (float)$lowestItem['unit_price']) {
|
|
$lowestItem = $item;
|
|
}
|
|
}
|
|
|
|
$afterPromo['promo_discount_total'] = calculatePromoPrice($lowestItem['unit_price'], $promo['amount'], $promo['discount_type']);
|
|
}
|
|
|
|
if ($promo['filter_type'] == 'category') {
|
|
foreach ($cart_items as $item) {
|
|
$category_ids = getMenuCategory($item['menu_item_id']);
|
|
$category_ids_flat = array_column($category_ids, 'id');
|
|
$intersect = array_intersect($category_ids_flat, $promo['filter']);
|
|
if (!empty($intersect)) {
|
|
$eligibleItems[] = $item;
|
|
}
|
|
}
|
|
|
|
if (count($eligibleItems) < 2) {
|
|
return ['status' => 400, 'result' => 'Two eligible category items required for this promo code.'];
|
|
}
|
|
|
|
$lowestItem = $eligibleItems[0];
|
|
foreach ($eligibleItems as $item) {
|
|
if ((float)$item['unit_price'] < (float)$lowestItem['unit_price']) {
|
|
$lowestItem = $item;
|
|
}
|
|
}
|
|
|
|
$afterPromo['promo_discount_total'] = calculatePromoPrice($lowestItem['unit_price'], $promo['amount'], $promo['discount_type']);
|
|
}
|
|
}
|
|
|
|
// print_r($order_type);
|
|
// print_r($delivery_fee);
|
|
// print_r($promo);
|
|
// exit;
|
|
//Delivery Fee
|
|
if($delivery_fee > 0 && $order_type == 'delivery') {
|
|
if($promo['promo_type'] == 'delivery'){
|
|
if($promo['filter_type'] == 'total'){
|
|
$afterPromo['delivery_fee'] = calculatePromoPrice($delivery_fee, $promo['amount'], $promo['discount_type']);
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
//Free Item
|
|
if($promo['promo_type'] == 'free_item'){
|
|
$free_items = [];
|
|
$isIncluded = true;
|
|
|
|
if($promo['filter_type'] == 'item'){
|
|
foreach($promo['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['filter_type'] == 'category'){
|
|
foreach($promo['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;
|
|
}
|
|
|
|
$afterPromo['status'] = 200;
|
|
|
|
return $afterPromo;
|
|
}
|
|
|
|
public function checkPromoCode($promo_code){
|
|
if(empty($promo_code)){
|
|
return ['status' => 400, 'result' => 'Promo code is empty.'];
|
|
}
|
|
|
|
$promo_code_id = $this->promoCode->where('code', $promo_code)->orderBy('id', 'desc')->limit(1)->first();
|
|
|
|
if(empty($promo_code_id)){
|
|
return ['status' => 400, 'result' => 'Promo code not found.'];
|
|
}
|
|
|
|
return $promo_code_id['id'];
|
|
}
|
|
}
|
|
?>
|