feat: 出入库记录模块完善
This commit is contained in:
parent
cf7c91eab2
commit
466c3ca384
|
@ -18,3 +18,8 @@ export enum MaterialsInOrOutEnum {
|
||||||
In,
|
In,
|
||||||
Out
|
Out
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 系统参数key
|
||||||
|
export enum ParamConfigEnum {
|
||||||
|
MaterialsInOutPrefix = 'materials_in_out_prefix'
|
||||||
|
}
|
||||||
|
|
|
@ -2,6 +2,7 @@ import { ApiProperty, IntersectionType, PartialType } from '@nestjs/swagger';
|
||||||
import { Transform } from 'class-transformer';
|
import { Transform } from 'class-transformer';
|
||||||
import {
|
import {
|
||||||
IsArray,
|
IsArray,
|
||||||
|
IsBoolean,
|
||||||
IsDate,
|
IsDate,
|
||||||
IsDateString,
|
IsDateString,
|
||||||
IsEnum,
|
IsEnum,
|
||||||
|
@ -11,7 +12,8 @@ import {
|
||||||
IsOptional,
|
IsOptional,
|
||||||
IsString,
|
IsString,
|
||||||
Matches,
|
Matches,
|
||||||
MinLength
|
MinLength,
|
||||||
|
ValidateIf
|
||||||
} from 'class-validator';
|
} from 'class-validator';
|
||||||
import dayjs from 'dayjs';
|
import dayjs from 'dayjs';
|
||||||
import { PagerDto } from '~/common/dto/pager.dto';
|
import { PagerDto } from '~/common/dto/pager.dto';
|
||||||
|
@ -21,9 +23,15 @@ import { formatToDate } from '~/utils';
|
||||||
|
|
||||||
export class MaterialsInOutDto {
|
export class MaterialsInOutDto {
|
||||||
@ApiProperty({ description: '产品' })
|
@ApiProperty({ description: '产品' })
|
||||||
|
@ValidateIf(o => !o.inventoryNumber)
|
||||||
@IsNumber()
|
@IsNumber()
|
||||||
productId: number;
|
productId: number;
|
||||||
|
|
||||||
|
@ApiProperty({ description: '原材料库存编号' })
|
||||||
|
@IsOptional()
|
||||||
|
@IsString()
|
||||||
|
inventoryNumber: string;
|
||||||
|
|
||||||
@ApiProperty({ description: '单位(字典)' })
|
@ApiProperty({ description: '单位(字典)' })
|
||||||
@IsNumber()
|
@IsNumber()
|
||||||
@IsOptional()
|
@IsOptional()
|
||||||
|
@ -68,10 +76,6 @@ export class MaterialsInOutDto {
|
||||||
@IsString()
|
@IsString()
|
||||||
@ApiProperty({ description: '项目' })
|
@ApiProperty({ description: '项目' })
|
||||||
project: string;
|
project: string;
|
||||||
|
|
||||||
// @ApiProperty({ description: '附件' })
|
|
||||||
// @IsOptional()
|
|
||||||
// files: Storage[];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export class MaterialsInOutUpdateDto extends PartialType(MaterialsInOutDto) {
|
export class MaterialsInOutUpdateDto extends PartialType(MaterialsInOutDto) {
|
||||||
|
@ -80,7 +84,7 @@ export class MaterialsInOutUpdateDto extends PartialType(MaterialsInOutDto) {
|
||||||
@IsArray()
|
@IsArray()
|
||||||
fileIds: number[];
|
fileIds: number[];
|
||||||
}
|
}
|
||||||
export class MaterialsInOutQueryDto extends PagerDto<MaterialsInOutDto> {
|
export class MaterialsInOutQueryDto extends PagerDto<MaterialsInOutQueryDto> {
|
||||||
@ApiProperty({ description: '出入库时间YYYY-MM-DD' })
|
@ApiProperty({ description: '出入库时间YYYY-MM-DD' })
|
||||||
@IsOptional()
|
@IsOptional()
|
||||||
// @IsString()
|
// @IsString()
|
||||||
|
@ -97,10 +101,41 @@ export class MaterialsInOutQueryDto extends PagerDto<MaterialsInOutDto> {
|
||||||
@ApiProperty({ description: '入库或出库 0:入库 1:出库' })
|
@ApiProperty({ description: '入库或出库 0:入库 1:出库' })
|
||||||
@IsOptional()
|
@IsOptional()
|
||||||
@IsEnum(MaterialsInOrOutEnum)
|
@IsEnum(MaterialsInOrOutEnum)
|
||||||
inOrOut: MaterialsInOrOutEnum;
|
inOrOut?: MaterialsInOrOutEnum;
|
||||||
|
|
||||||
@ApiProperty({ description: '产品名称' })
|
@ApiProperty({ description: '产品名称' })
|
||||||
@IsOptional()
|
@IsOptional()
|
||||||
@IsString()
|
@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;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,23 +1,34 @@
|
||||||
import { ApiHideProperty, ApiProperty } from '@nestjs/swagger';
|
import { ApiHideProperty, ApiProperty } from '@nestjs/swagger';
|
||||||
|
import { InjectRepository } from '@nestjs/typeorm';
|
||||||
|
import { Expose } from 'class-transformer';
|
||||||
|
import pinyin from 'pinyin';
|
||||||
import {
|
import {
|
||||||
|
BeforeInsert,
|
||||||
Column,
|
Column,
|
||||||
Entity,
|
Entity,
|
||||||
JoinColumn,
|
JoinColumn,
|
||||||
JoinTable,
|
JoinTable,
|
||||||
ManyToMany,
|
ManyToMany,
|
||||||
ManyToOne,
|
ManyToOne,
|
||||||
OneToMany,
|
|
||||||
Relation,
|
Relation,
|
||||||
VirtualColumn
|
Repository
|
||||||
} from 'typeorm';
|
} from 'typeorm';
|
||||||
import { CommonEntity } from '~/common/entity/common.entity';
|
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 { 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';
|
import { Storage } from '~/modules/tools/storage/storage.entity';
|
||||||
|
|
||||||
@Entity({ name: 'materials_in_out' })
|
@Entity({ name: 'materials_in_out' })
|
||||||
export class MaterialsInOutEntity extends CommonEntity {
|
export class MaterialsInOutEntity extends CommonEntity {
|
||||||
|
@Column({
|
||||||
|
name: 'inventory_number',
|
||||||
|
type: 'varchar',
|
||||||
|
length: 50,
|
||||||
|
comment: '原材料库存编号'
|
||||||
|
})
|
||||||
|
@ApiProperty({ description: '原材料库存编号' })
|
||||||
|
inventoryNumber: string;
|
||||||
|
|
||||||
@Column({
|
@Column({
|
||||||
name: 'product_id',
|
name: 'product_id',
|
||||||
type: 'int',
|
type: 'int',
|
||||||
|
@ -55,9 +66,9 @@ export class MaterialsInOutEntity extends CommonEntity {
|
||||||
@Column({
|
@Column({
|
||||||
name: 'unit_price',
|
name: 'unit_price',
|
||||||
type: 'decimal',
|
type: 'decimal',
|
||||||
precision: 10,
|
precision: 15,
|
||||||
default: 0,
|
default: 0,
|
||||||
scale: 2,
|
scale: 10,
|
||||||
comment: '单价'
|
comment: '单价'
|
||||||
})
|
})
|
||||||
@ApiProperty({ description: '单价' })
|
@ApiProperty({ description: '单价' })
|
||||||
|
@ -66,9 +77,9 @@ export class MaterialsInOutEntity extends CommonEntity {
|
||||||
@Column({
|
@Column({
|
||||||
name: 'amount',
|
name: 'amount',
|
||||||
type: 'decimal',
|
type: 'decimal',
|
||||||
precision: 10,
|
precision: 15,
|
||||||
default: 0,
|
default: 0,
|
||||||
scale: 2,
|
scale: 10,
|
||||||
comment: '金额'
|
comment: '金额'
|
||||||
})
|
})
|
||||||
@ApiProperty({ description: '金额' })
|
@ApiProperty({ description: '金额' })
|
||||||
|
@ -104,9 +115,6 @@ export class MaterialsInOutEntity extends CommonEntity {
|
||||||
@JoinColumn({ name: 'product_id' })
|
@JoinColumn({ name: 'product_id' })
|
||||||
product: ProductEntity;
|
product: ProductEntity;
|
||||||
|
|
||||||
@ApiHideProperty()
|
|
||||||
unit: DictItemEntity;
|
|
||||||
|
|
||||||
@ManyToMany(() => Storage, storage => storage.materialsInOut)
|
@ManyToMany(() => Storage, storage => storage.materialsInOut)
|
||||||
@JoinTable({
|
@JoinTable({
|
||||||
name: 'materials_in_out_storage',
|
name: 'materials_in_out_storage',
|
||||||
|
|
|
@ -14,6 +14,8 @@ import {
|
||||||
} from './materials_in_out.dto';
|
} from './materials_in_out.dto';
|
||||||
import { MaterialsInOutEntity } from './materials_in_out.entity';
|
import { MaterialsInOutEntity } from './materials_in_out.entity';
|
||||||
import { fieldSearch } from '~/shared/database/field-search';
|
import { fieldSearch } from '~/shared/database/field-search';
|
||||||
|
import { ParamConfigEntity } from '~/modules/system/param-config/param-config.entity';
|
||||||
|
import { MaterialsInOrOutEnum, ParamConfigEnum } from '~/constants/enum';
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export class MaterialsInOutService {
|
export class MaterialsInOutService {
|
||||||
|
@ -22,7 +24,9 @@ export class MaterialsInOutService {
|
||||||
@InjectRepository(MaterialsInOutEntity)
|
@InjectRepository(MaterialsInOutEntity)
|
||||||
private materialsInOutRepository: Repository<MaterialsInOutEntity>,
|
private materialsInOutRepository: Repository<MaterialsInOutEntity>,
|
||||||
@InjectRepository(Storage)
|
@InjectRepository(Storage)
|
||||||
private storageRepository: Repository<Storage>
|
private storageRepository: Repository<Storage>,
|
||||||
|
@InjectRepository(ParamConfigEntity)
|
||||||
|
private paramConfigRepository: Repository<ParamConfigEntity>
|
||||||
) {}
|
) {}
|
||||||
/**
|
/**
|
||||||
* 查询所有出入库记录
|
* 查询所有出入库记录
|
||||||
|
@ -31,6 +35,7 @@ export class MaterialsInOutService {
|
||||||
page,
|
page,
|
||||||
pageSize,
|
pageSize,
|
||||||
product: productName,
|
product: productName,
|
||||||
|
isCreateOut,
|
||||||
...ext
|
...ext
|
||||||
}: MaterialsInOutQueryDto): Promise<Pagination<MaterialsInOutEntity>> {
|
}: MaterialsInOutQueryDto): Promise<Pagination<MaterialsInOutEntity>> {
|
||||||
const sqb = this.materialsInOutRepository
|
const sqb = this.materialsInOutRepository
|
||||||
|
@ -38,23 +43,21 @@ export class MaterialsInOutService {
|
||||||
.leftJoin('materialsInOut.files', 'files')
|
.leftJoin('materialsInOut.files', 'files')
|
||||||
.leftJoin('materialsInOut.product', 'product')
|
.leftJoin('materialsInOut.product', 'product')
|
||||||
.leftJoin('product.unit', 'unit')
|
.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))
|
.where(fieldSearch(ext))
|
||||||
.andWhere('materialsInOut.isDelete = 0')
|
.andWhere('materialsInOut.isDelete = 0')
|
||||||
.addOrderBy('materialsInOut.time', 'DESC');
|
.addOrderBy('materialsInOut.createdAt', 'DESC');
|
||||||
if (productName) {
|
if (productName) {
|
||||||
sqb.andWhere('product.name like :productName', { productName: `%${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,
|
page,
|
||||||
pageSize
|
pageSize
|
||||||
});
|
});
|
||||||
// 产品表中的单位字段需要单独处理
|
|
||||||
pageData.items = pageData.items.map(materialsInOut => {
|
|
||||||
materialsInOut.unit = materialsInOut.product.unit;
|
|
||||||
delete materialsInOut.product.unit;
|
|
||||||
return materialsInOut;
|
|
||||||
});
|
|
||||||
return pageData;
|
return pageData;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -62,7 +65,22 @@ export class MaterialsInOutService {
|
||||||
* 新增
|
* 新增
|
||||||
*/
|
*/
|
||||||
async create(dto: MaterialsInOutDto): Promise<void> {
|
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);
|
.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}`;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,10 +7,12 @@ import { StorageModule } from '../tools/storage/storage.module';
|
||||||
import { MaterialsInOutController } from './in_out/materials_in_out.controller';
|
import { MaterialsInOutController } from './in_out/materials_in_out.controller';
|
||||||
import { MaterialsInOutService } from './in_out/materials_in_out.service';
|
import { MaterialsInOutService } from './in_out/materials_in_out.service';
|
||||||
import { MaterialsInOutEntity } from './in_out/materials_in_out.entity';
|
import { MaterialsInOutEntity } from './in_out/materials_in_out.entity';
|
||||||
|
import { ParamConfigModule } from '../system/param-config/param-config.module';
|
||||||
|
|
||||||
@Module({
|
@Module({
|
||||||
imports: [
|
imports: [
|
||||||
TypeOrmModule.forFeature([MaterialsInventoryEntity, MaterialsInOutEntity]),
|
TypeOrmModule.forFeature([MaterialsInventoryEntity, MaterialsInOutEntity]),
|
||||||
|
ParamConfigModule,
|
||||||
StorageModule
|
StorageModule
|
||||||
],
|
],
|
||||||
controllers: [MaterialsInventoryController, MaterialsInOutController],
|
controllers: [MaterialsInventoryController, MaterialsInOutController],
|
||||||
|
|
Loading…
Reference in New Issue