feat: 产品模块

This commit is contained in:
louis 2024-03-05 13:57:03 +08:00
parent 47b7015c16
commit df8806a5fb
9 changed files with 92 additions and 33 deletions

View File

@ -49,5 +49,8 @@ export enum ErrorEnum {
// Storage相关 // Storage相关
STORAGE_NOT_FOUND = '1404:文件不存在,请重试', STORAGE_NOT_FOUND = '1404:文件不存在,请重试',
STORAGE_REFRENCE_EXISTS = '1405:文件存在关联,无法删除,请先找到该文件关联的业务解除关联。' STORAGE_REFRENCE_EXISTS = '1405:文件存在关联,无法删除,请先找到该文件关联的业务解除关联。',
// Product
PRODUCT_EXIST = '1406:产品已存在'
} }

View File

@ -33,7 +33,19 @@ export class CompanyUpdateDto extends PartialType(CompanyDto) {
fileIds: number[]; fileIds: number[];
} }
export class ComapnyCreateDto extends PartialType(CompanyDto) {
@ApiProperty({ description: '附件' })
@IsOptional()
@IsArray()
fileIds: number[];
}
export class CompanyQueryDto extends IntersectionType( export class CompanyQueryDto extends IntersectionType(
PagerDto<CompanyDto>, PagerDto<CompanyDto>,
PartialType(CompanyDto) PartialType(CompanyDto)
) {} ) {
@ApiProperty({ description: '公司名称' })
@IsOptional()
@IsString()
name: string;
}

View File

@ -1,7 +1,8 @@
import { ApiHideProperty, ApiProperty } from '@nestjs/swagger'; import { ApiHideProperty, ApiProperty } from '@nestjs/swagger';
import { Column, Entity, JoinTable, ManyToMany, Relation } from 'typeorm'; import { Column, Entity, JoinTable, ManyToMany, OneToMany, Relation } from 'typeorm';
import { CommonEntity } from '~/common/entity/common.entity'; import { CommonEntity } from '~/common/entity/common.entity';
import { Storage } from '../tools/storage/storage.entity'; import { Storage } from '../tools/storage/storage.entity';
import { ProductEntity } from '../product/product.entity';
@Entity({ name: 'company' }) @Entity({ name: 'company' })
export class CompanyEntity extends CommonEntity { export class CompanyEntity extends CommonEntity {
@ -19,6 +20,10 @@ export class CompanyEntity extends CommonEntity {
@ApiProperty({ description: '删除状态0未删除1已删除' }) @ApiProperty({ description: '删除状态0未删除1已删除' })
isDelete: number; isDelete: number;
@ApiHideProperty()
@OneToMany(() => ProductEntity, product => product.company)
products: Relation<ProductEntity[]>;
@ManyToMany(() => Storage, storage => storage.companys) @ManyToMany(() => Storage, storage => storage.companys)
@JoinTable({ @JoinTable({
name: 'company_storage', name: 'company_storage',

View File

@ -16,46 +16,46 @@ export const permissions = definePermission('materials_inventory:history_in_out'
DELETE: 'delete' DELETE: 'delete'
} as const); } as const);
@ApiTags('Materials In Out History - 原材料出入库管理') @ApiTags('Materials In Out History - 原材料出入库记录')
@ApiSecurityAuth() @ApiSecurityAuth()
@Controller('materials-in-out') @Controller('materials-in-out')
export class MaterialsInOutController { export class MaterialsInOutController {
constructor(private miService: MaterialsInOutService) {} constructor(private materialsInOutService: MaterialsInOutService) {}
@Get() @Get()
@ApiOperation({ summary: '获取原材料盘点列表' }) @ApiOperation({ summary: '获取原材料出入库记录列表' })
@ApiResult({ type: [MaterialsInOutEntity], isPage: true }) @ApiResult({ type: [MaterialsInOutEntity], isPage: true })
@Perm(permissions.LIST) @Perm(permissions.LIST)
async list(@Query() dto: MaterialsInOutQueryDto) { async list(@Query() dto: MaterialsInOutQueryDto) {
return this.miService.findAll(dto); return this.materialsInOutService.findAll(dto);
} }
@Get(':id') @Get(':id')
@ApiOperation({ summary: '获取原材料盘点信息' }) @ApiOperation({ summary: '获取原材料出入库记录信息' })
@ApiResult({ type: MaterialsInOutDto }) @ApiResult({ type: MaterialsInOutDto })
@Perm(permissions.READ) @Perm(permissions.READ)
async info(@IdParam() id: number) { async info(@IdParam() id: number) {
return this.miService.info(id); return this.materialsInOutService.info(id);
} }
@Post() @Post()
@ApiOperation({ summary: '新增原材料盘点' }) @ApiOperation({ summary: '新增原材料出入库记录' })
@Perm(permissions.CREATE) @Perm(permissions.CREATE)
async create(@Body() dto: MaterialsInOutDto): Promise<void> { async create(@Body() dto: MaterialsInOutDto): Promise<void> {
await this.miService.create(dto); await this.materialsInOutService.create(dto);
} }
@Put(':id') @Put(':id')
@ApiOperation({ summary: '更新原材料盘点' }) @ApiOperation({ summary: '更新原材料出入库记录' })
@Perm(permissions.UPDATE) @Perm(permissions.UPDATE)
async update(@IdParam() id: number, @Body() dto: MaterialsInOutUpdateDto): Promise<void> { async update(@IdParam() id: number, @Body() dto: MaterialsInOutUpdateDto): Promise<void> {
await this.miService.update(id, dto); await this.materialsInOutService.update(id, dto);
} }
@Delete(':id') @Delete(':id')
@ApiOperation({ summary: '删除原材料盘点' }) @ApiOperation({ summary: '删除原材料出入库记录' })
@Perm(permissions.DELETE) @Perm(permissions.DELETE)
async delete(@IdParam() id: number): Promise<void> { async delete(@IdParam() id: number): Promise<void> {
await this.miService.delete(id); await this.materialsInOutService.delete(id);
} }
@Put('unlink-attachments/:id') @Put('unlink-attachments/:id')
@ -65,6 +65,6 @@ export class MaterialsInOutController {
@IdParam() id: number, @IdParam() id: number,
@Body() { fileIds }: MaterialsInOutUpdateDto @Body() { fileIds }: MaterialsInOutUpdateDto
): Promise<void> { ): Promise<void> {
await this.miService.unlinkAttachments(id, fileIds); await this.materialsInOutService.unlinkAttachments(id, fileIds);
} }
} }

View File

@ -4,10 +4,16 @@ import { MaterialsInventoryService } from './materials_inventory.service';
import { TypeOrmModule } from '@nestjs/typeorm'; import { TypeOrmModule } from '@nestjs/typeorm';
import { MaterialsInventoryEntity } from './materials_inventory.entity'; import { MaterialsInventoryEntity } from './materials_inventory.entity';
import { StorageModule } from '../tools/storage/storage.module'; import { StorageModule } from '../tools/storage/storage.module';
import { MaterialsInOutController } from './in_out/materials_in_out.controller';
import { MaterialsInOutService } from './in_out/materials_in_out.service';
import { MaterialsInOutEntity } from './in_out/materials_in_out.entity';
@Module({ @Module({
imports: [TypeOrmModule.forFeature([MaterialsInventoryEntity]), StorageModule], imports: [
controllers: [MaterialsInventoryController], TypeOrmModule.forFeature([MaterialsInventoryEntity, MaterialsInOutEntity]),
providers: [MaterialsInventoryService] StorageModule
],
controllers: [MaterialsInventoryController, MaterialsInOutController],
providers: [MaterialsInventoryService, MaterialsInOutService]
}) })
export class MaterialsInventoryModule {} export class MaterialsInventoryModule {}

View File

@ -18,10 +18,14 @@ import { ProductEntity } from './product.entity';
export class ProductDto { export class ProductDto {
@ApiProperty({ description: '产品名称' }) @ApiProperty({ description: '产品名称' })
@IsUnique(ProductEntity, { message: '已存在同名产品' })
@IsString() @IsString()
name: string; name: string;
@ApiProperty({ description: '所属公司' })
@IsOptional()
@IsNumber()
companyId: number;
@ApiProperty({ description: '附件' }) @ApiProperty({ description: '附件' })
files: Storage[]; files: Storage[];
} }
@ -36,4 +40,9 @@ export class ProductUpdateDto extends PartialType(ProductDto) {
export class ProductQueryDto extends IntersectionType( export class ProductQueryDto extends IntersectionType(
PagerDto<ProductDto>, PagerDto<ProductDto>,
PartialType(ProductDto) PartialType(ProductDto)
) {} ) {
@ApiProperty({ description: '所属公司名称' })
@IsOptional()
@IsString()
company: string;
}

View File

@ -1,14 +1,14 @@
import { ApiHideProperty, ApiProperty } from '@nestjs/swagger'; import { ApiHideProperty, ApiProperty } from '@nestjs/swagger';
import { Column, Entity, JoinTable, ManyToMany, Relation } from 'typeorm'; import { Column, Entity, JoinColumn, JoinTable, ManyToMany, ManyToOne, Relation } from 'typeorm';
import { CommonEntity } from '~/common/entity/common.entity'; import { CommonEntity } from '~/common/entity/common.entity';
import { Storage } from '../tools/storage/storage.entity'; import { Storage } from '../tools/storage/storage.entity';
import { CompanyEntity } from '../company/company.entity';
@Entity({ name: 'product' }) @Entity({ name: 'product' })
export class ProductEntity extends CommonEntity { export class ProductEntity extends CommonEntity {
@Column({ @Column({
name: 'name', name: 'name',
type: 'varchar', type: 'varchar',
unique: true,
length: 255, length: 255,
comment: '产品名称' comment: '产品名称'
}) })
@ -19,6 +19,14 @@ export class ProductEntity extends CommonEntity {
@ApiProperty({ description: '删除状态0未删除1已删除' }) @ApiProperty({ description: '删除状态0未删除1已删除' })
isDelete: number; isDelete: number;
@Column({ name: 'company_id', type: 'int', comment: '所属公司', nullable: true })
@ApiProperty({ description: '所属公司' })
companyId: number;
@ManyToOne(() => CompanyEntity /* , { onDelete: 'CASCADE' } */)
@JoinColumn({ name: 'company_id' })
company: CompanyEntity;
@ManyToMany(() => Storage, storage => storage.products) @ManyToMany(() => Storage, storage => storage.products)
@JoinTable({ @JoinTable({
name: 'product_storage', name: 'product_storage',

View File

@ -28,14 +28,22 @@ export class ProductService {
pageSize, pageSize,
...fields ...fields
}: ProductQueryDto): Promise<Pagination<ProductEntity>> { }: ProductQueryDto): Promise<Pagination<ProductEntity>> {
const queryBuilder = this.productRepository const { company: companyName,...ext } = fields;
const sqb = this.productRepository
.createQueryBuilder('product') .createQueryBuilder('product')
.leftJoin('product.files', 'files') .leftJoin('product.files', 'files')
.addSelect(['files.id', 'files.path']) .leftJoin('product.company', 'company')
.where(fieldSearch(fields)) .addSelect(['files.id', 'files.path', 'company.name', 'company.id'])
.andWhere('product.isDelete = 0'); .where(fieldSearch(ext))
.where('product.isDelete = 0');
return paginate<ProductEntity>(queryBuilder, { if (companyName) {
sqb.andWhere({
company: {
name: Like(`%${companyName}%`)
}
});
}
return paginate<ProductEntity>(sqb, {
page, page,
pageSize pageSize
}); });
@ -45,6 +53,13 @@ export class ProductService {
* *
*/ */
async create(dto: ProductDto): Promise<void> { async create(dto: ProductDto): Promise<void> {
const { name, companyId } = dto;
const isExsit = await this.productRepository.findOne({
where: { name, company: { id: companyId } }
});
if (isExsit) {
throw new BusinessException(ErrorEnum.PRODUCT_EXIST);
}
await this.productRepository.insert(dto); await this.productRepository.insert(dto);
} }
@ -83,16 +98,17 @@ export class ProductService {
* *
*/ */
async delete(id: number): Promise<void> { async delete(id: number): Promise<void> {
// 合同比较重要,做逻辑删除
await this.productRepository.update(id, { isDelete: 1 }); await this.productRepository.update(id, { isDelete: 1 });
} }
/** /**
* *
*/ */
async info(id: number) { async info(id: number) {
const info = await this.productRepository const info = await this.productRepository
.createQueryBuilder('product') .createQueryBuilder('product')
.leftJoin('product.company', 'company')
.addSelect(['company.name', 'company.id'])
.where({ .where({
id id
}) })
@ -103,7 +119,7 @@ export class ProductService {
/** /**
* *
* @param id ID * @param id ID
* @param fileIds ID * @param fileIds ID
*/ */
async unlinkAttachments(id: number, fileIds: number[]) { async unlinkAttachments(id: number, fileIds: number[]) {