Recipe-app main
This commit is contained in:
@@ -0,0 +1,248 @@
|
||||
import { ConsumeInventoryDto } from './dto/consume-inventory.dto';
|
||||
import { Injectable, NotFoundException } from '@nestjs/common';
|
||||
import { Prisma } from '@prisma/client';
|
||||
import { PrismaService } from '../prisma/prisma.service';
|
||||
import { CreateInventoryDto } from './dto/create-inventory.dto';
|
||||
import { UpdateInventoryDto } from './dto/update-inventory.dto';
|
||||
|
||||
type InventoryQuery = {
|
||||
location?: string;
|
||||
sort?: string;
|
||||
};
|
||||
|
||||
@Injectable()
|
||||
export class InventoryService {
|
||||
constructor(private prisma: PrismaService) {}
|
||||
|
||||
async findAll(query?: InventoryQuery) {
|
||||
const where: Prisma.InventoryItemWhereInput = {};
|
||||
const orderBy: Prisma.InventoryItemOrderByWithRelationInput[] = [];
|
||||
|
||||
if (query?.location) {
|
||||
where.location = query.location;
|
||||
}
|
||||
|
||||
if (query?.sort === 'bestBeforeAsc') {
|
||||
orderBy.push({ bestBeforeDate: 'asc' });
|
||||
} else if (query?.sort === 'bestBeforeDesc') {
|
||||
orderBy.push({ bestBeforeDate: 'desc' });
|
||||
} else if (query?.sort === 'purchaseDateAsc') {
|
||||
orderBy.push({ purchaseDate: 'asc' });
|
||||
} else if (query?.sort === 'purchaseDateDesc') {
|
||||
orderBy.push({ purchaseDate: 'desc' });
|
||||
} else {
|
||||
orderBy.push({ createdAt: 'desc' });
|
||||
}
|
||||
|
||||
return this.prisma.inventoryItem.findMany({
|
||||
where,
|
||||
include: {
|
||||
product: true,
|
||||
},
|
||||
orderBy,
|
||||
});
|
||||
}
|
||||
|
||||
async consume(id: number, data: ConsumeInventoryDto) {
|
||||
const existing = await this.prisma.inventoryItem.findUnique({
|
||||
where: { id },
|
||||
include: {
|
||||
product: true,
|
||||
},
|
||||
});
|
||||
|
||||
if (!existing) {
|
||||
throw new NotFoundException(`Inventory item with id ${id} not found`);
|
||||
}
|
||||
|
||||
const currentQuantity = Number(existing.quantity);
|
||||
const newQuantity = Math.max(0, currentQuantity - data.amountUsed);
|
||||
|
||||
return this.prisma.$transaction(async (tx) => {
|
||||
const updatedItem = await tx.inventoryItem.update({
|
||||
where: { id },
|
||||
data: {
|
||||
quantity: new Prisma.Decimal(newQuantity),
|
||||
},
|
||||
include: {
|
||||
product: true,
|
||||
},
|
||||
});
|
||||
|
||||
await tx.inventoryConsumption.create({
|
||||
data: {
|
||||
inventoryItemId: id,
|
||||
amountUsed: new Prisma.Decimal(data.amountUsed),
|
||||
comment: data.comment?.trim() || null,
|
||||
},
|
||||
});
|
||||
|
||||
return updatedItem;
|
||||
});
|
||||
}
|
||||
|
||||
async findConsumptionHistory(id: number) {
|
||||
const existing = await this.prisma.inventoryItem.findUnique({
|
||||
where: { id },
|
||||
});
|
||||
|
||||
if (!existing) {
|
||||
throw new NotFoundException(`Inventory item with id ${id} not found`);
|
||||
}
|
||||
|
||||
return this.prisma.inventoryConsumption.findMany({
|
||||
where: {
|
||||
inventoryItemId: id,
|
||||
},
|
||||
orderBy: {
|
||||
createdAt: 'desc',
|
||||
},
|
||||
});
|
||||
}
|
||||
async findExpiring() {
|
||||
const now = new Date();
|
||||
|
||||
return this.prisma.inventoryItem.findMany({
|
||||
where: {
|
||||
bestBeforeDate: {
|
||||
not: null,
|
||||
gte: now,
|
||||
},
|
||||
},
|
||||
include: {
|
||||
product: true,
|
||||
},
|
||||
orderBy: [{ bestBeforeDate: 'asc' }, { createdAt: 'desc' }],
|
||||
});
|
||||
}
|
||||
|
||||
async create(data: CreateInventoryDto) {
|
||||
const product = await this.prisma.product.findUnique({
|
||||
where: { id: data.productId },
|
||||
});
|
||||
|
||||
if (!product) {
|
||||
throw new NotFoundException('Product not found');
|
||||
}
|
||||
|
||||
return this.prisma.inventoryItem.create({
|
||||
data: {
|
||||
...data,
|
||||
quantity: new Prisma.Decimal(data.quantity),
|
||||
location: data.location?.trim() || undefined,
|
||||
brand: data.brand?.trim() || undefined,
|
||||
suitableFor: data.suitableFor?.trim() || undefined,
|
||||
comment: data.comment?.trim() || undefined,
|
||||
purchaseDate: data.purchaseDate
|
||||
? new Date(data.purchaseDate)
|
||||
: undefined,
|
||||
bestBeforeDate: data.bestBeforeDate
|
||||
? new Date(data.bestBeforeDate)
|
||||
: undefined,
|
||||
},
|
||||
include: {
|
||||
product: true,
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
async update(id: number, data: UpdateInventoryDto) {
|
||||
const existing = await this.prisma.inventoryItem.findUnique({
|
||||
where: { id },
|
||||
});
|
||||
|
||||
if (!existing) {
|
||||
throw new NotFoundException(`Inventory item with id ${id} not found`);
|
||||
}
|
||||
|
||||
if (typeof data.productId === 'number') {
|
||||
const product = await this.prisma.product.findUnique({
|
||||
where: { id: data.productId },
|
||||
});
|
||||
|
||||
if (!product) {
|
||||
throw new NotFoundException('Product not found');
|
||||
}
|
||||
}
|
||||
|
||||
const updateData: Prisma.InventoryItemUpdateInput = {};
|
||||
|
||||
if (typeof data.productId === 'number') {
|
||||
updateData.product = {
|
||||
connect: { id: data.productId },
|
||||
};
|
||||
}
|
||||
|
||||
if (typeof data.quantity === 'number') {
|
||||
updateData.quantity = new Prisma.Decimal(data.quantity);
|
||||
}
|
||||
|
||||
if (typeof data.unit === 'string') {
|
||||
updateData.unit = data.unit.trim();
|
||||
}
|
||||
|
||||
if (typeof data.location === 'string') {
|
||||
updateData.location = data.location.trim();
|
||||
}
|
||||
|
||||
if (typeof data.brand === 'string') {
|
||||
updateData.brand = data.brand.trim();
|
||||
}
|
||||
|
||||
if (typeof data.priority === 'number') {
|
||||
updateData.priority = data.priority;
|
||||
}
|
||||
|
||||
if (typeof data.purchaseDate === 'string') {
|
||||
updateData.purchaseDate = data.purchaseDate
|
||||
? new Date(data.purchaseDate)
|
||||
: null;
|
||||
}
|
||||
|
||||
if (typeof data.bestBeforeDate === 'string') {
|
||||
updateData.bestBeforeDate = data.bestBeforeDate
|
||||
? new Date(data.bestBeforeDate)
|
||||
: null;
|
||||
}
|
||||
|
||||
if (typeof data.opened === 'boolean') {
|
||||
updateData.opened = data.opened;
|
||||
}
|
||||
|
||||
if (typeof data.shelfNote === 'string') {
|
||||
updateData.shelfNote = data.shelfNote.trim();
|
||||
}
|
||||
|
||||
if (typeof data.suitableFor === 'string') {
|
||||
updateData.suitableFor = data.suitableFor.trim();
|
||||
}
|
||||
|
||||
if (typeof data.isOnSale === 'boolean') {
|
||||
updateData.isOnSale = data.isOnSale;
|
||||
}
|
||||
|
||||
if (typeof data.priceLevel === 'number') {
|
||||
updateData.priceLevel = data.priceLevel;
|
||||
}
|
||||
|
||||
if (typeof data.proteinType === 'string') {
|
||||
updateData.proteinType = data.proteinType.trim();
|
||||
}
|
||||
|
||||
if (typeof data.isLeftover === 'boolean') {
|
||||
updateData.isLeftover = data.isLeftover;
|
||||
}
|
||||
|
||||
if (typeof data.comment === 'string') {
|
||||
updateData.comment = data.comment.trim();
|
||||
}
|
||||
|
||||
return this.prisma.inventoryItem.update({
|
||||
where: { id },
|
||||
data: updateData,
|
||||
include: {
|
||||
product: true,
|
||||
},
|
||||
});
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user