Compare commits

...

3 Commits

Author SHA1 Message Date
ca0dfcd905 feat: food item and category impl" 2025-04-12 13:19:30 +05:30
f774a5ac28 feat: add food item 2025-04-11 17:07:39 +05:30
315e2d2748 feat: add food item 2025-04-11 14:51:59 +05:30
14 changed files with 199 additions and 32 deletions

View File

@@ -20,6 +20,7 @@ import { MongooseModule } from '@nestjs/mongoose';
import { OrderModule } from './order/order.module';
import { IngredientUsageModule } from './ingredient-usage/ingredient-usage.module';
import { CategoryModule } from './category/category.module';
import { FoodItemModule } from './food-item/food-item.module';
@Module({
imports: [
ConfigModule.forRoot({ isGlobal: true }),
@@ -39,6 +40,7 @@ import { CategoryModule } from './category/category.module';
OrderModule,
IngredientUsageModule,
CategoryModule,
FoodItemModule,
],
controllers: [AppController],
providers: [AppService],

View File

@@ -6,6 +6,7 @@ import {
Patch,
Param,
Delete,
Query,
} from '@nestjs/common';
import { CategoryService } from './category.service';
import { CreateCategoryDto } from './dto/create-category.dto';
@@ -21,8 +22,8 @@ export class CategoryController {
}
@Get()
findAll() {
return this.categoryService.findAll();
findAll(@Query('relations') relations: boolean = false) {
return this.categoryService.findAll(relations);
}
@Get(':id')

View File

@@ -15,27 +15,30 @@ export class CategoryService {
return await this.categoryRepository.save(createCategoryDto);
}
async findAll() {
async findAll(withRelations = false) {
return await this.categoryRepository.find({
order: {
created_at: 'DESC',
},
relations: withRelations ? ['food_items'] : [],
});
}
async findOne(id: string) {
return await this.categoryRepository.findOne({
const category = await this.categoryRepository.findOne({
where: {
id,
},
});
if (!category) {
throw new BadRequestException('Category not found');
}
return category;
}
async update(id: string, updateCategoryDto: UpdateCategoryDto) {
const entity = await this.findOne(id);
if (!entity) {
throw new BadRequestException('Category not found.');
}
const updated = this.categoryRepository.merge(entity, updateCategoryDto);
await this.categoryRepository.save(updated);
@@ -43,9 +46,7 @@ export class CategoryService {
async remove(id: string) {
const entity = await this.findOne(id);
if (!entity) {
throw new BadRequestException('Category not found.');
}
await this.categoryRepository.remove(entity);
}
}

View File

@@ -1,8 +1,12 @@
import { BaseEntity } from 'src/common/base_entity';
import { Column, Entity } from 'typeorm';
import { FoodItem } from 'src/food-item/entities/food-item.entity';
import { Column, Entity, OneToMany } from 'typeorm';
@Entity({ name: 'categories' })
export class Category extends BaseEntity {
@Column({ unique: true })
name: string;
@OneToMany(() => FoodItem, (foodItem) => foodItem.category)
food_items: FoodItem[];
}

View File

@@ -0,0 +1,12 @@
import { IsString, IsUUID } from 'class-validator';
export class CreateFoodItemDto {
@IsString()
name: string;
@IsUUID()
category: string;
@IsString()
unit: string;
}

View File

@@ -0,0 +1,5 @@
import { PartialType } from '@nestjs/mapped-types';
import { CreateFoodItemDto } from './create-food-item.dto';
import { FoodItem } from '../entities/food-item.entity';
export class UpdateFoodItemDto extends PartialType(FoodItem) {}

View File

@@ -0,0 +1,19 @@
import { Category } from 'src/category/entities/category.entity';
import { BaseEntity } from 'src/common/base_entity';
import { InwardEntry } from 'src/inventory/inward_entry.entity';
import { Column, Entity, ManyToOne, OneToMany } from 'typeorm';
@Entity()
export class FoodItem extends BaseEntity {
@Column()
name: string;
@Column({})
unit: string;
@ManyToOne(() => Category, (category) => category.food_items)
category: Category;
@OneToMany(() => InwardEntry, (inwardEntry) => inwardEntry.foodItem)
inward_entries: InwardEntry[];
}

View File

@@ -0,0 +1,46 @@
import {
Controller,
Get,
Post,
Body,
Patch,
Param,
Delete,
Query,
} from '@nestjs/common';
import { FoodItemService } from './food-item.service';
import { CreateFoodItemDto } from './dto/create-food-item.dto';
import { UpdateFoodItemDto } from './dto/update-food-item.dto';
@Controller('food-item')
export class FoodItemController {
constructor(private readonly foodItemService: FoodItemService) {}
@Post()
create(@Body() createFoodItemDto: CreateFoodItemDto) {
return this.foodItemService.create(createFoodItemDto);
}
@Get()
findAll(@Query('relations') relations: boolean = false) {
return this.foodItemService.findAll(relations);
}
@Get(':id')
findOne(@Param('id') id: string) {
return this.foodItemService.findOne(id);
}
@Patch(':id')
update(
@Param('id') id: string,
@Body() updateFoodItemDto: UpdateFoodItemDto,
) {
return this.foodItemService.update(id, updateFoodItemDto);
}
@Delete(':id')
remove(@Param('id') id: string) {
return this.foodItemService.remove(id);
}
}

View File

@@ -0,0 +1,14 @@
import { Module } from '@nestjs/common';
import { FoodItemService } from './food-item.service';
import { FoodItemController } from './food-item.controller';
import { CategoryModule } from 'src/category/category.module';
import { TypeOrmModule } from '@nestjs/typeorm';
import { FoodItem } from './entities/food-item.entity';
@Module({
imports: [TypeOrmModule.forFeature([FoodItem]), CategoryModule],
controllers: [FoodItemController],
providers: [FoodItemService],
exports: [FoodItemService],
})
export class FoodItemModule {}

View File

@@ -0,0 +1,61 @@
import { BadRequestException, Injectable } from '@nestjs/common';
import { CreateFoodItemDto } from './dto/create-food-item.dto';
import { UpdateFoodItemDto } from './dto/update-food-item.dto';
import { InjectRepository } from '@nestjs/typeorm';
import { FoodItem } from './entities/food-item.entity';
import { Repository } from 'typeorm';
import { CategoryService } from 'src/category/category.service';
@Injectable()
export class FoodItemService {
constructor(
@InjectRepository(FoodItem)
private readonly foodItemRepository: Repository<FoodItem>,
private readonly categoryService: CategoryService,
) {}
async create(createFoodItemDto: CreateFoodItemDto) {
const category = await this.categoryService.findOne(
createFoodItemDto.category,
);
return await this.foodItemRepository.save({
name: createFoodItemDto.name,
category,
unit: createFoodItemDto.unit,
});
}
async findAll(withRelations: boolean) {
return await this.foodItemRepository.find({
order: {
created_at: 'DESC',
},
relations: withRelations ? ['category'] : [],
});
}
async findOne(id: string) {
const food = await this.foodItemRepository.findOne({
where: {
id,
},
});
if (!food) {
throw new BadRequestException('Food item not found');
}
return food;
}
async update(id: string, updateFoodItemDto: UpdateFoodItemDto) {
const foodItem = await this.findOne(id);
const updated = this.foodItemRepository.merge(foodItem, updateFoodItemDto);
await this.foodItemRepository.save(updated);
}
async remove(id: string) {
const foodItem = await this.findOne(id);
await this.foodItemRepository.remove(foodItem);
}
}

View File

@@ -9,12 +9,13 @@ import {
IsPositive,
isString,
IsString,
IsUUID,
} from 'class-validator';
export class CreateInwardEntryDto {
@IsUUID()
@IsNotEmpty()
@IsString()
description: string;
food_item_id: string;
@IsOptional()
@IsString()
@@ -32,10 +33,6 @@ export class CreateInwardEntryDto {
@IsNumber()
rate: number;
@IsNotEmpty()
@IsString()
unit: string;
@IsNumber()
@IsPositive()
amount: number;

View File

@@ -6,11 +6,13 @@ import { Inventory } from './inventory.entity';
import { Inward } from './inward.entity';
import { InwardEntry } from './inward_entry.entity';
import { VendorModule } from 'src/vendor/vendor.module';
import { FoodItemModule } from 'src/food-item/food-item.module';
@Module({
imports: [
TypeOrmModule.forFeature([Inventory, Inward, InwardEntry]),
VendorModule,
FoodItemModule,
],
controllers: [InventoryController],
providers: [InventoryService],

View File

@@ -16,6 +16,7 @@ import UpdateInwardDto from './dto/update-inward';
import { updateInventoryItemDto } from './dto/update-inventory';
import { LogService } from 'src/log/log.service';
import { UserService } from 'src/user/user.service';
import { FoodItemService } from 'src/food-item/food-item.service';
@Injectable()
export class InventoryService {
@@ -32,6 +33,7 @@ export class InventoryService {
private readonly vendorService: VendorService,
private readonly logService: LogService,
private readonly userService: UserService,
private readonly foodItemService: FoodItemService,
) {}
async findAllInwards() {
@@ -88,19 +90,20 @@ export class InventoryService {
const savedInward = await this.inwardRepository.save(inward);
for (const entry of dto.entries) {
const { manufacturing_date, ...data } = entry;
console.log('manu date', manufacturing_date);
const { manufacturing_date, food_item_id, ...data } = entry;
const foodItem = await this.foodItemService.findOne(food_item_id);
const inwardEntry = this.inwardEntryRepository.create({
...data,
foodItem,
manufacuting_date: new Date(entry.manufacturing_date),
inward: savedInward,
});
await this.inwardEntryRepository.save(inwardEntry);
await this.modifyStock(
entry.description,
foodItem.name,
entry.quantity,
'add',
inwardEntry.unit,
foodItem.unit,
userId,
);
}
@@ -156,17 +159,17 @@ export class InventoryService {
async deleteInward(id: string, userId: string) {
const inward = await this.inwardRepository.findOne({
where: { id },
relations: ['entries'],
relations: ['entries', 'foodItem'],
});
if (!inward)
throw new NotFoundException(`Inward entry with ID ${id} not found.`);
for (const entry of inward.entries) {
await this.modifyStock(
entry.description,
entry.foodItem.name,
entry.quantity,
'subtract',
entry.unit,
entry.foodItem.unit,
userId,
);
}
@@ -197,10 +200,10 @@ export class InventoryService {
throw new NotFoundException(`Inward entry with ID ${entryId} not found.`);
await this.modifyStock(
entry.description,
entry.foodItem.name,
entry.quantity,
'subtract',
entry.unit,
entry.foodItem.unit,
userId,
);
await this.inwardEntryRepository.remove(entry);

View File

@@ -1,6 +1,7 @@
import { Column, Entity, JoinColumn, ManyToOne } from 'typeorm';
import { Column, Entity, JoinColumn, ManyToOne, OneToMany } from 'typeorm';
import { BaseEntity } from '../common/base_entity';
import { Inward } from './inward.entity';
import { FoodItem } from 'src/food-item/entities/food-item.entity';
@Entity()
export class InwardEntry extends BaseEntity {
@@ -11,8 +12,10 @@ export class InwardEntry extends BaseEntity {
@JoinColumn()
inward: Inward;
@Column()
description: string;
@ManyToOne(() => FoodItem, (foodItem) => foodItem.inward_entries, {
eager: true,
})
foodItem: FoodItem;
@Column({ nullable: true })
hsn_sac: string;
@@ -26,9 +29,6 @@ export class InwardEntry extends BaseEntity {
@Column({ type: 'decimal', precision: 10, scale: 2 })
rate: number;
@Column()
unit: string;
@Column({ type: 'decimal', precision: 12, scale: 2 })
amount: number;