diff --git a/backend/package-lock.json b/backend/package-lock.json index 141159c..03e49c7 100644 --- a/backend/package-lock.json +++ b/backend/package-lock.json @@ -12,15 +12,16 @@ "@nestjs/common": "^10.0.0", "@nestjs/config": "^3.0.0", "@nestjs/core": "^10.0.0", + "@nestjs/mapped-types": "*", "@nestjs/platform-express": "^10.0.0", - "@nestjs/typeorm": "^10.0.0", + "@nestjs/typeorm": "^10.0.2", "class-transformer": "^0.5.1", "class-validator": "^0.14.0", "nestjs-i18n": "^10.5.1", "pg": "^8.11.3", "reflect-metadata": "^0.2.0", "rxjs": "^7.8.1", - "typeorm": "^0.3.17" + "typeorm": "^0.3.27" }, "devDependencies": { "@nestjs/cli": "^10.0.0", @@ -1686,6 +1687,26 @@ } } }, + "node_modules/@nestjs/mapped-types": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/@nestjs/mapped-types/-/mapped-types-2.1.0.tgz", + "integrity": "sha512-W+n+rM69XsFdwORF11UqJahn4J3xi4g/ZEOlJNL6KoW5ygWSmBB2p0S2BZ4FQeS/NDH72e6xIcu35SfJnE8bXw==", + "license": "MIT", + "peerDependencies": { + "@nestjs/common": "^10.0.0 || ^11.0.0", + "class-transformer": "^0.4.0 || ^0.5.0", + "class-validator": "^0.13.0 || ^0.14.0", + "reflect-metadata": "^0.1.12 || ^0.2.0" + }, + "peerDependenciesMeta": { + "class-transformer": { + "optional": true + }, + "class-validator": { + "optional": true + } + } + }, "node_modules/@nestjs/platform-express": { "version": "10.4.20", "resolved": "https://registry.npmjs.org/@nestjs/platform-express/-/platform-express-10.4.20.tgz", diff --git a/backend/package.json b/backend/package.json index 4459e27..f585664 100644 --- a/backend/package.json +++ b/backend/package.json @@ -23,15 +23,16 @@ "@nestjs/common": "^10.0.0", "@nestjs/config": "^3.0.0", "@nestjs/core": "^10.0.0", + "@nestjs/mapped-types": "*", "@nestjs/platform-express": "^10.0.0", - "@nestjs/typeorm": "^10.0.0", + "@nestjs/typeorm": "^10.0.2", "class-transformer": "^0.5.1", "class-validator": "^0.14.0", "nestjs-i18n": "^10.5.1", "pg": "^8.11.3", "reflect-metadata": "^0.2.0", "rxjs": "^7.8.1", - "typeorm": "^0.3.17" + "typeorm": "^0.3.27" }, "devDependencies": { "@nestjs/cli": "^10.0.0", diff --git a/backend/src/app.module.ts b/backend/src/app.module.ts index 2b211ed..e65fa6e 100644 --- a/backend/src/app.module.ts +++ b/backend/src/app.module.ts @@ -1,5 +1,4 @@ import { Module } from '@nestjs/common'; -import { TypeOrmModule } from '@nestjs/typeorm'; import { ConfigModule, ConfigService } from '@nestjs/config'; import { AppController } from './app.controller'; import { AppService } from './app.service'; @@ -16,7 +15,6 @@ import { User } from './users/entities/user.entity'; ConfigModule.forRoot({ isGlobal: true, }), - TypeOrmModule.forRootAsync({ imports: [ConfigModule], useFactory: (configService: ConfigService) => ({ @@ -31,6 +29,7 @@ import { User } from './users/entities/user.entity'; }), inject: [ConfigService], }), + AssetCategoriesModule, DepartmentsModule, AssetTransfersModule, diff --git a/backend/src/suppliers/dto/create-supplier.dto.ts b/backend/src/suppliers/dto/create-supplier.dto.ts new file mode 100644 index 0000000..3f262e0 --- /dev/null +++ b/backend/src/suppliers/dto/create-supplier.dto.ts @@ -0,0 +1,21 @@ +import { IsEmail, IsNotEmpty, IsOptional, IsString } from 'class-validator'; + +export class CreateSupplierDto { + @IsString() + @IsNotEmpty() + name: string; + + @IsOptional() + @IsString() + contactInfo?: string; + + @IsOptional() + @IsString() + address?: string; + + @IsEmail() + email: string; + + @IsString() + phone: string; +} diff --git a/backend/src/suppliers/dto/update-supplier.dto.ts b/backend/src/suppliers/dto/update-supplier.dto.ts new file mode 100644 index 0000000..40a7218 --- /dev/null +++ b/backend/src/suppliers/dto/update-supplier.dto.ts @@ -0,0 +1,4 @@ +import { PartialType } from '@nestjs/mapped-types'; +import { CreateSupplierDto } from './create-supplier.dto'; + +export class UpdateSupplierDto extends PartialType(CreateSupplierDto) {} diff --git a/backend/src/suppliers/entities/supplier.entity.ts b/backend/src/suppliers/entities/supplier.entity.ts new file mode 100644 index 0000000..f2c2e30 --- /dev/null +++ b/backend/src/suppliers/entities/supplier.entity.ts @@ -0,0 +1,26 @@ +import { Entity, PrimaryGeneratedColumn, Column, OneToMany } from 'typeorm'; + +@Entity('suppliers') +export class Supplier { + @PrimaryGeneratedColumn('uuid') + id: string; + + @Column() + name: string; + + @Column({ nullable: true }) + contactInfo: string; + + @Column({ nullable: true }) + address: string; + + @Column({ unique: true }) + email: string; + + @Column() + phone: string; + + // This should be uncommented when the Asset entity is created + // @OneToMany(() => Asset, (asset) => asset.supplier) + // assets: Asset[]; +} diff --git a/backend/src/suppliers/suppliers.controller.ts b/backend/src/suppliers/suppliers.controller.ts new file mode 100644 index 0000000..1e81422 --- /dev/null +++ b/backend/src/suppliers/suppliers.controller.ts @@ -0,0 +1,42 @@ +import { + Controller, + Get, + Post, + Body, + Param, + Put, + Delete, +} from '@nestjs/common'; +import { SuppliersService } from './suppliers.service'; +import { CreateSupplierDto } from './dto/create-supplier.dto'; +import { UpdateSupplierDto } from './dto/update-supplier.dto'; + +@Controller('suppliers') +export class SuppliersController { + constructor(private readonly suppliersService: SuppliersService) {} + + @Post() + create(@Body() dto: CreateSupplierDto) { + return this.suppliersService.create(dto); + } + + @Get() + findAll() { + return this.suppliersService.findAll(); + } + + @Get(':id') + findOne(@Param('id') id: string) { + return this.suppliersService.findOne(id); + } + + @Put(':id') + update(@Param('id') id: string, @Body() dto: UpdateSupplierDto) { + return this.suppliersService.update(id, dto); + } + + @Delete(':id') + remove(@Param('id') id: string) { + return this.suppliersService.remove(id); + } +} diff --git a/backend/src/suppliers/suppliers.module.ts b/backend/src/suppliers/suppliers.module.ts new file mode 100644 index 0000000..7edd4d5 --- /dev/null +++ b/backend/src/suppliers/suppliers.module.ts @@ -0,0 +1,12 @@ +import { Module } from '@nestjs/common'; +import { SuppliersService } from './suppliers.service'; +import { SuppliersController } from './suppliers.controller'; +import { TypeOrmModule } from '@nestjs/typeorm'; +import { Supplier } from './entities/supplier.entity'; + +@Module({ + imports: [TypeOrmModule.forFeature([Supplier])], + controllers: [SuppliersController], + providers: [SuppliersService], +}) +export class SuppliersModule {} diff --git a/backend/src/suppliers/suppliers.service.ts b/backend/src/suppliers/suppliers.service.ts new file mode 100644 index 0000000..0c72ee5 --- /dev/null +++ b/backend/src/suppliers/suppliers.service.ts @@ -0,0 +1,42 @@ +import { Injectable, NotFoundException } from '@nestjs/common'; +import { InjectRepository } from '@nestjs/typeorm'; +import { Repository } from 'typeorm'; +import { CreateSupplierDto } from './dto/create-supplier.dto'; +import { UpdateSupplierDto } from './dto/update-supplier.dto'; +import { Supplier } from './entities/supplier.entity'; + +@Injectable() +export class SuppliersService { + constructor( + @InjectRepository(Supplier) + private suppliersRepo: Repository, + ) {} + + create(dto: CreateSupplierDto): Promise { + const supplier = this.suppliersRepo.create(dto); + return this.suppliersRepo.save(supplier); + } + + findAll(): Promise { + return this.suppliersRepo.find({ relations: ['assets'] }); + } + + public async findOne(id: string): Promise { + const supplier = await this.suppliersRepo.findOne({ + where: { id }, + relations: ['assets'], + }); + if (!supplier) throw new NotFoundException(`Supplier ${id} not found`); + return supplier; + } + + public async update(id: string, dto: UpdateSupplierDto): Promise { + const supplier = await this.findOne(id); + Object.assign(supplier, dto); + return this.suppliersRepo.save(supplier); + } + + public async remove(id: string): Promise { + await this.suppliersRepo.delete(id); + } +}