init
This commit is contained in:
@@ -0,0 +1,113 @@
|
||||
import { Injectable, NotFoundException } from '@nestjs/common';
|
||||
import { Food } from '../../foods/entities/food.entity';
|
||||
import { Cart, CartItem } from '../interfaces/cart.interface';
|
||||
import { CartValidationService } from './cart-validation.service';
|
||||
import { CartCalculationService } from './cart-calculation.service';
|
||||
import { CartMessage } from 'src/common/enums/message.enum';
|
||||
|
||||
@Injectable()
|
||||
export class CartItemService {
|
||||
constructor(
|
||||
private readonly validationService: CartValidationService,
|
||||
private readonly calculationService: CartCalculationService,
|
||||
) {}
|
||||
|
||||
/**
|
||||
* Create a new cart item from food
|
||||
*/
|
||||
createCartItem(food: Food, quantity: number): CartItem {
|
||||
const itemPrice = food.price || 0;
|
||||
const itemDiscount = food.discount || 0;
|
||||
|
||||
return {
|
||||
foodId: food.id,
|
||||
foodTitle: food.title,
|
||||
quantity,
|
||||
price: itemPrice,
|
||||
discount: itemDiscount,
|
||||
totalPrice: this.calculationService.calculateItemTotalPrice(itemPrice, itemDiscount, quantity),
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Build cart item from food (updating existing item if provided)
|
||||
*/
|
||||
buildCartItemFromFood(food: Food, quantity: number, previous?: CartItem): CartItem {
|
||||
const itemPrice = food.price || 0;
|
||||
const itemDiscount = food.discount || 0;
|
||||
return {
|
||||
...(previous ?? ({} as CartItem)),
|
||||
foodId: food.id,
|
||||
foodTitle: food.title,
|
||||
quantity,
|
||||
price: itemPrice,
|
||||
discount: itemDiscount,
|
||||
totalPrice: this.calculationService.calculateItemTotalPrice(itemPrice, itemDiscount, quantity),
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Get item index in cart
|
||||
*/
|
||||
getItemIndex(cart: Cart, foodId: string): number {
|
||||
return cart.items.findIndex(item => item.foodId === foodId);
|
||||
}
|
||||
|
||||
/**
|
||||
* Add or increment item in cart
|
||||
*/
|
||||
async addOrIncrementItem(cart: Cart, foodId: string, restaurantId: string, quantityToAdd: number): Promise<void> {
|
||||
const food = await this.validationService.validateAndGetFood(foodId, restaurantId, quantityToAdd);
|
||||
|
||||
// Validate meal type compatibility
|
||||
this.validationService.assertMealTypeCompatibility(food);
|
||||
|
||||
// Validate weekday compatibility
|
||||
this.validationService.assertWeekdayCompatibility(food);
|
||||
|
||||
const index = this.getItemIndex(cart, food.id);
|
||||
|
||||
if (index < 0) {
|
||||
cart.items.push(this.createCartItem(food, quantityToAdd));
|
||||
return;
|
||||
}
|
||||
|
||||
const existingItem = cart.items[index];
|
||||
const newQuantity = existingItem.quantity + quantityToAdd;
|
||||
this.validationService.validateStock(food, newQuantity);
|
||||
cart.items[index] = this.buildCartItemFromFood(food, newQuantity, existingItem);
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove item from cart
|
||||
*/
|
||||
removeItemOrFail(cart: Cart, foodId: string): void {
|
||||
const itemIndex = this.getItemIndex(cart, foodId);
|
||||
if (itemIndex < 0) {
|
||||
throw new NotFoundException(CartMessage.ITEM_NOT_FOUND);
|
||||
}
|
||||
cart.items.splice(itemIndex, 1);
|
||||
}
|
||||
|
||||
/**
|
||||
* Decrement item quantity or remove if quantity reaches 0
|
||||
*/
|
||||
async decrementOrRemoveItem(cart: Cart, foodId: string): Promise<void> {
|
||||
const itemIndex = this.getItemIndex(cart, foodId);
|
||||
if (itemIndex < 0) {
|
||||
throw new NotFoundException(CartMessage.ITEM_NOT_FOUND);
|
||||
}
|
||||
|
||||
const existingItem = cart.items[itemIndex];
|
||||
const newQuantity = existingItem.quantity - 1;
|
||||
|
||||
if (newQuantity <= 0) {
|
||||
cart.items.splice(itemIndex, 1);
|
||||
return;
|
||||
}
|
||||
|
||||
const food = await this.validationService.getFoodOrFail(foodId);
|
||||
cart.items[itemIndex] = this.buildCartItemFromFood(food, newQuantity, existingItem);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user