Files
dkala-api/src/modules/cart/providers/cart-item.service.ts
T
2026-02-08 16:51:35 +03:30

108 lines
3.3 KiB
TypeScript

import { Injectable, NotFoundException } from '@nestjs/common';
import { Product } from '../../products/entities/product.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 product
*/
createCartItem(product: Product, quantity: number): CartItem {
const itemPrice = product.price || 0;
const itemDiscount = product.discount || 0;
return {
foodId: product.id,
foodTitle: product.title,
quantity,
price: itemPrice,
discount: itemDiscount,
totalPrice: this.calculationService.calculateItemTotalPrice(itemPrice, itemDiscount, quantity),
};
}
/**
* Build cart item from product (updating existing item if provided)
*/
buildCartItemFromFood(product: Product, quantity: number, previous?: CartItem): CartItem {
const itemPrice = product.price || 0;
const itemDiscount = product.discount || 0;
return {
...(previous ?? ({} as CartItem)),
foodId: product.id,
foodTitle: product.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 product = await this.validationService.validateAndGetFood(foodId, restaurantId, quantityToAdd);
const index = this.getItemIndex(cart, product.id);
if (index < 0) {
cart.items.push(this.createCartItem(product, quantityToAdd));
return;
}
const existingItem = cart.items[index];
const newQuantity = existingItem.quantity + quantityToAdd;
this.validationService.validateStock(product, newQuantity);
cart.items[index] = this.buildCartItemFromFood(product, 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 product = await this.validationService.getFoodOrFail(foodId);
cart.items[itemIndex] = this.buildCartItemFromFood(product, newQuantity, existingItem);
}
}