feat: 出入库记录模块完善

This commit is contained in:
louis 2024-03-06 17:13:14 +08:00
parent cf7c91eab2
commit 466c3ca384
5 changed files with 126 additions and 31 deletions

View File

@ -18,3 +18,8 @@ export enum MaterialsInOrOutEnum {
In,
Out
}
// 系统参数key
export enum ParamConfigEnum {
MaterialsInOutPrefix = 'materials_in_out_prefix'
}

View File

@ -2,6 +2,7 @@ import { ApiProperty, IntersectionType, PartialType } from '@nestjs/swagger';
import { Transform } from 'class-transformer';
import {
IsArray,
IsBoolean,
IsDate,
IsDateString,
IsEnum,
@ -11,7 +12,8 @@ import {
IsOptional,
IsString,
Matches,
MinLength
MinLength,
ValidateIf
} from 'class-validator';
import dayjs from 'dayjs';
import { PagerDto } from '~/common/dto/pager.dto';
@ -21,9 +23,15 @@ import { formatToDate } from '~/utils';
export class MaterialsInOutDto {
@ApiProperty({ description: '产品' })
@ValidateIf(o => !o.inventoryNumber)
@IsNumber()
productId: number;
@ApiProperty({ description: '原材料库存编号' })
@IsOptional()
@IsString()
inventoryNumber: string;
@ApiProperty({ description: '单位(字典)' })
@IsNumber()
@IsOptional()
@ -68,10 +76,6 @@ export class MaterialsInOutDto {
@IsString()
@ApiProperty({ description: '项目' })
project: string;
// @ApiProperty({ description: '附件' })
// @IsOptional()
// files: Storage[];
}
export class MaterialsInOutUpdateDto extends PartialType(MaterialsInOutDto) {
@ -80,7 +84,7 @@ export class MaterialsInOutUpdateDto extends PartialType(MaterialsInOutDto) {
@IsArray()
fileIds: number[];
}
export class MaterialsInOutQueryDto extends PagerDto<MaterialsInOutDto> {
export class MaterialsInOutQueryDto extends PagerDto<MaterialsInOutQueryDto> {
@ApiProperty({ description: '出入库时间YYYY-MM-DD' })
@IsOptional()
// @IsString()
@ -97,10 +101,41 @@ export class MaterialsInOutQueryDto extends PagerDto<MaterialsInOutDto> {
@ApiProperty({ description: '入库或出库 0:入库 1:出库' })
@IsOptional()
@IsEnum(MaterialsInOrOutEnum)
inOrOut: MaterialsInOrOutEnum;
inOrOut?: MaterialsInOrOutEnum;
@ApiProperty({ description: '产品名称' })
@IsOptional()
@IsString()
product: string;
product?: string;
@ApiProperty({ description: '经办人' })
@IsOptional()
@IsString()
agent?: string;
@ApiProperty({ description: '领料单号' })
@IsOptional()
@IsString()
issuanceNumber?: string;
@ApiProperty({ description: '原材料库存编号' })
@IsOptional()
@IsString()
inventoryNumber?: string;
@IsOptional()
@IsString()
@ApiProperty({ description: '备注' })
remark?: string;
@IsOptional()
@IsString()
@ApiProperty({ description: '项目' })
project?: string;
@IsOptional()
@IsBoolean()
@ApiProperty({ description: '是否是用于创建出库记录' })
isCreateOut?: boolean;
}

View File

@ -1,23 +1,34 @@
import { ApiHideProperty, ApiProperty } from '@nestjs/swagger';
import { InjectRepository } from '@nestjs/typeorm';
import { Expose } from 'class-transformer';
import pinyin from 'pinyin';
import {
BeforeInsert,
Column,
Entity,
JoinColumn,
JoinTable,
ManyToMany,
ManyToOne,
OneToMany,
Relation,
VirtualColumn
Repository
} from 'typeorm';
import { CommonEntity } from '~/common/entity/common.entity';
import { MaterialsInOrOutEnum } from '~/constants/enum';
import { MaterialsInOrOutEnum, ParamConfigEnum } from '~/constants/enum';
import { ProductEntity } from '~/modules/product/product.entity';
import { DictItemEntity } from '~/modules/system/dict-item/dict-item.entity';
import { ParamConfigEntity } from '~/modules/system/param-config/param-config.entity';
import { Storage } from '~/modules/tools/storage/storage.entity';
@Entity({ name: 'materials_in_out' })
export class MaterialsInOutEntity extends CommonEntity {
@Column({
name: 'inventory_number',
type: 'varchar',
length: 50,
comment: '原材料库存编号'
})
@ApiProperty({ description: '原材料库存编号' })
inventoryNumber: string;
@Column({
name: 'product_id',
type: 'int',
@ -55,9 +66,9 @@ export class MaterialsInOutEntity extends CommonEntity {
@Column({
name: 'unit_price',
type: 'decimal',
precision: 10,
precision: 15,
default: 0,
scale: 2,
scale: 10,
comment: '单价'
})
@ApiProperty({ description: '单价' })
@ -66,9 +77,9 @@ export class MaterialsInOutEntity extends CommonEntity {
@Column({
name: 'amount',
type: 'decimal',
precision: 10,
precision: 15,
default: 0,
scale: 2,
scale: 10,
comment: '金额'
})
@ApiProperty({ description: '金额' })
@ -104,9 +115,6 @@ export class MaterialsInOutEntity extends CommonEntity {
@JoinColumn({ name: 'product_id' })
product: ProductEntity;
@ApiHideProperty()
unit: DictItemEntity;
@ManyToMany(() => Storage, storage => storage.materialsInOut)
@JoinTable({
name: 'materials_in_out_storage',

View File

@ -14,6 +14,8 @@ import {
} from './materials_in_out.dto';
import { MaterialsInOutEntity } from './materials_in_out.entity';
import { fieldSearch } from '~/shared/database/field-search';
import { ParamConfigEntity } from '~/modules/system/param-config/param-config.entity';
import { MaterialsInOrOutEnum, ParamConfigEnum } from '~/constants/enum';
@Injectable()
export class MaterialsInOutService {
@ -22,7 +24,9 @@ export class MaterialsInOutService {
@InjectRepository(MaterialsInOutEntity)
private materialsInOutRepository: Repository<MaterialsInOutEntity>,
@InjectRepository(Storage)
private storageRepository: Repository<Storage>
private storageRepository: Repository<Storage>,
@InjectRepository(ParamConfigEntity)
private paramConfigRepository: Repository<ParamConfigEntity>
) {}
/**
*
@ -31,6 +35,7 @@ export class MaterialsInOutService {
page,
pageSize,
product: productName,
isCreateOut,
...ext
}: MaterialsInOutQueryDto): Promise<Pagination<MaterialsInOutEntity>> {
const sqb = this.materialsInOutRepository
@ -38,23 +43,21 @@ export class MaterialsInOutService {
.leftJoin('materialsInOut.files', 'files')
.leftJoin('materialsInOut.product', 'product')
.leftJoin('product.unit', 'unit')
.addSelect(['files.id', 'files.path', 'product.id', 'product.name', 'unit.id', 'unit.label'])
.leftJoin('product.company', 'company')
.addSelect(['files.path', 'product.name', 'unit.label', 'company.name'])
.where(fieldSearch(ext))
.andWhere('materialsInOut.isDelete = 0')
.addOrderBy('materialsInOut.time', 'DESC');
.addOrderBy('materialsInOut.createdAt', 'DESC');
if (productName) {
sqb.andWhere('product.name like :productName', { productName: `%${productName}%` });
}
let pageData = await paginate<MaterialsInOutEntity>(sqb, {
if (isCreateOut) {
sqb.andWhere('materialsInOut.inOrOut = 0');
}
const pageData = await paginate<MaterialsInOutEntity>(sqb, {
page,
pageSize
});
// 产品表中的单位字段需要单独处理
pageData.items = pageData.items.map(materialsInOut => {
materialsInOut.unit = materialsInOut.product.unit;
delete materialsInOut.product.unit;
return materialsInOut;
});
return pageData;
}
@ -62,7 +65,22 @@ export class MaterialsInOutService {
*
*/
async create(dto: MaterialsInOutDto): Promise<void> {
await this.materialsInOutRepository.insert(dto);
let { inOrOut, inventoryNumber } = dto;
if (inOrOut === MaterialsInOrOutEnum.In) {
inventoryNumber = await this.generateInventoryNumber();
} else {
const inRecord = await this.materialsInOutRepository.findOne({
where: {
inventoryNumber
}
});
const { productId } = inRecord;
dto.productId = productId;
}
await this.materialsInOutRepository.insert({
...this.materialsInOutRepository.create(dto),
inventoryNumber
});
}
/**
@ -141,4 +159,31 @@ export class MaterialsInOutService {
.addAndRemove(linkedFiles, materialsInOut.files);
});
}
/**
*
* @returns
*/
async generateInventoryNumber() {
const prefix =
(
await this.paramConfigRepository.findOne({
where: {
key: ParamConfigEnum.MaterialsInOutPrefix
}
})
)?.value || '';
const lastMaterial = await this.materialsInOutRepository
.createQueryBuilder('materialsInOut')
.select(
`MAX(CAST(REPLACE(materialsInOut.inventoryNumber, '${prefix}', '') AS UNSIGNED))`,
'maxInventoryNumber'
)
.getRawOne();
const lastNumber = lastMaterial.maxInventoryNumber
? parseInt(lastMaterial.maxInventoryNumber.replace(prefix, ''))
: 0;
const newNumber = lastNumber + 1 < 1000 ? 1000 : lastNumber + 1;
return `${prefix}${newNumber}`;
}
}

View File

@ -7,10 +7,12 @@ 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';
import { ParamConfigModule } from '../system/param-config/param-config.module';
@Module({
imports: [
TypeOrmModule.forFeature([MaterialsInventoryEntity, MaterialsInOutEntity]),
ParamConfigModule,
StorageModule
],
controllers: [MaterialsInventoryController, MaterialsInOutController],