feat: develop domain

This commit is contained in:
louis 2024-04-17 09:59:18 +08:00
parent cd32cc1ac0
commit f958ab7af9
13 changed files with 286 additions and 83 deletions

View File

@ -17,7 +17,6 @@ import { DomainEntity } from './domain.entity';
import { DomainDto, DomainQueryDto, DomainUpdateDto } from './domain.dto'; import { DomainDto, DomainQueryDto, DomainUpdateDto } from './domain.dto';
import { IdParam } from '~/common/decorators/id-param.decorator'; import { IdParam } from '~/common/decorators/id-param.decorator';
export const permissions = definePermission('app:domain', { export const permissions = definePermission('app:domain', {
LIST: 'list',
CREATE: 'create', CREATE: 'create',
READ: 'read', READ: 'read',
UPDATE: 'update', UPDATE: 'update',
@ -33,7 +32,6 @@ export class DomainController {
@Get() @Get()
@ApiOperation({ summary: '获取域列表' }) @ApiOperation({ summary: '获取域列表' })
@ApiResult({ type: [DomainEntity], isPage: true }) @ApiResult({ type: [DomainEntity], isPage: true })
@Perm(permissions.LIST)
async list(@Query() dto: DomainQueryDto) { async list(@Query() dto: DomainQueryDto) {
return this.domainService.findAll(dto); return this.domainService.findAll(dto);
} }

View File

@ -1,4 +1,4 @@
import { Body, Controller, Delete, Get, Post, Put, Query } from '@nestjs/common'; import { Body, Controller, Delete, Get, Post, Put, Query, Res } from '@nestjs/common';
import { ApiOperation, ApiTags } from '@nestjs/swagger'; import { ApiOperation, ApiTags } from '@nestjs/swagger';
import { ApiResult } from '~/common/decorators/api-result.decorator'; import { ApiResult } from '~/common/decorators/api-result.decorator';
import { IdParam } from '~/common/decorators/id-param.decorator'; import { IdParam } from '~/common/decorators/id-param.decorator';
@ -9,23 +9,38 @@ import { definePermission, Perm } from '~/modules/auth/decorators/permission.dec
import { import {
MaterialsInOutQueryDto, MaterialsInOutQueryDto,
MaterialsInOutDto, MaterialsInOutDto,
MaterialsInOutUpdateDto MaterialsInOutUpdateDto,
MaterialsInOutExportDto
} from './materials_in_out.dto'; } from './materials_in_out.dto';
import { Domain, DomainType, SkDomain } from '~/common/decorators/domain.decorator'; import { Domain, DomainType, SkDomain } from '~/common/decorators/domain.decorator';
import { FastifyReply } from 'fastify';
export const permissions = definePermission('materials_inventory:history_in_out', { export const permissions = definePermission('materials_inventory:history_in_out', {
LIST: 'list', LIST: 'list',
CREATE: 'create', CREATE: 'create',
READ: 'read', READ: 'read',
UPDATE: 'update', UPDATE: 'update',
DELETE: 'delete' DELETE: 'delete',
EXPORT: 'export'
} 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 materialsInOutService: MaterialsInOutService) {} constructor(private materialsInOutService: MaterialsInOutService) { }
@Get('export')
@ApiOperation({ summary: '导出原材料盘点表' })
@Perm(permissions.EXPORT)
async exportMaterialsInventoryCheck(
@Domain() domain: SkDomain,
@Query() dto: MaterialsInOutExportDto,
@Res() res: FastifyReply
): Promise<void> {
await this.materialsInOutService.exportMaterialsInventoryCheck({ ...dto, domain }, res);
}
@Get() @Get()
@ApiOperation({ summary: '获取原材料出入库记录列表' }) @ApiOperation({ summary: '获取原材料出入库记录列表' })
@ApiResult({ type: [MaterialsInOutEntity], isPage: true }) @ApiResult({ type: [MaterialsInOutEntity], isPage: true })

View File

@ -112,9 +112,9 @@ export class MaterialsInOutQueryDto extends IntersectionType(
// 开始和结束时间用的是一天的开始和一天的结束的时分秒 // 开始和结束时间用的是一天的开始和一天的结束的时分秒
return params.value return params.value
? [ ? [
params.value[0] ? `${formatToDate(params.value[0], 'YYYY-MM-DD')} 00:00:00` : null, params.value[0] ? `${formatToDate(params.value[0], 'YYYY-MM-DD')} 00:00:00` : null,
params.value[1] ? `${formatToDate(params.value[1], 'YYYY-MM-DD')} 23:59:59` : null params.value[1] ? `${formatToDate(params.value[1], 'YYYY-MM-DD')} 23:59:59` : null
] ]
: []; : [];
}) })
time?: string[]; time?: string[];
@ -159,3 +159,41 @@ export class MaterialsInOutQueryDto extends IntersectionType(
@ApiProperty({ description: '是否是用于创建出库记录' }) @ApiProperty({ description: '是否是用于创建出库记录' })
isCreateOut?: boolean; isCreateOut?: boolean;
} }
export class MaterialsInOutExportDto extends IntersectionType(
DomainType
) {
@ApiProperty({ description: '导出时间YYYY-MM-DD' })
@IsOptional()
@IsArray()
@Transform(params => {
// 开始和结束时间用的是一月的开始和一月的结束的时分秒
const date = params.value;
return [
date ? `${date[0]} 00:00:00` : null,
date ? `${date[1]} 23:59:59` : null
];
})
time?: string[];
@ApiProperty({ description: '导出文件名' })
@IsOptional()
@IsString()
filename?: string
@ApiProperty({ description: '入库或出库 0:入库 1:出库' })
@IsOptional()
@IsEnum(MaterialsInOrOutEnum)
inOrOut?: MaterialsInOrOutEnum;
@ApiProperty({ description: '产品名称' })
@IsOptional()
@IsString()
product?: string;
@ApiProperty({ description: '经办人' })
@IsOptional()
@IsString()
agent?: string;
}

View File

@ -1,7 +1,7 @@
import { Injectable } from '@nestjs/common'; import { Injectable } from '@nestjs/common';
import { InjectEntityManager, InjectRepository } from '@nestjs/typeorm'; import { InjectEntityManager, InjectRepository } from '@nestjs/typeorm';
import { EntityManager, In, Repository } from 'typeorm'; import { Between, EntityManager, In, Repository } from 'typeorm';
import { Pagination } from '~/helper/paginate/pagination'; import { Pagination } from '~/helper/paginate/pagination';
import { BusinessException } from '~/common/exceptions/biz.exception'; import { BusinessException } from '~/common/exceptions/biz.exception';
import { ErrorEnum } from '~/constants/error-code.constant'; import { ErrorEnum } from '~/constants/error-code.constant';
@ -10,7 +10,8 @@ import { Storage } from '~/modules/tools/storage/storage.entity';
import { import {
MaterialsInOutQueryDto, MaterialsInOutQueryDto,
MaterialsInOutDto, MaterialsInOutDto,
MaterialsInOutUpdateDto MaterialsInOutUpdateDto,
MaterialsInOutExportDto
} 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';
@ -19,7 +20,9 @@ import { MaterialsInOrOutEnum, ParamConfigEnum } from '~/constants/enum';
import { MaterialsInventoryEntity } from '../materials_inventory.entity'; import { MaterialsInventoryEntity } from '../materials_inventory.entity';
import { MaterialsInventoryService } from '../materials_inventory.service'; import { MaterialsInventoryService } from '../materials_inventory.service';
import { isDefined } from 'class-validator'; import { isDefined } from 'class-validator';
import { FastifyReply } from 'fastify';
import * as ExcelJS from 'exceljs';
import dayjs from 'dayjs';
@Injectable() @Injectable()
export class MaterialsInOutService { export class MaterialsInOutService {
constructor( constructor(
@ -31,7 +34,119 @@ export class MaterialsInOutService {
@InjectRepository(ParamConfigEntity) @InjectRepository(ParamConfigEntity)
private paramConfigRepository: Repository<ParamConfigEntity>, private paramConfigRepository: Repository<ParamConfigEntity>,
private materialsInventoryService: MaterialsInventoryService private materialsInventoryService: MaterialsInventoryService
) {} ) { }
/**
*
*/
async exportMaterialsInventoryCheck(
{ time, domain, filename, ...ext }: MaterialsInOutExportDto,
res: FastifyReply
): Promise<void> {
const ROW_HEIGHT = 20;
const HEADER_FONT_SIZE = 18;
// 生成数据
const sqb = this.buildSearchQuery()
.where(fieldSearch(ext))
.andWhere({
time: Between(time[0], time[1])
})
.andWhere('materialsInOut.isDelete = 0');
const data = await sqb.addOrderBy('materialsInOut.time', 'DESC').getMany();
const workbook = new ExcelJS.Workbook();
const sheet = workbook.addWorksheet('出入库记录');
sheet.mergeCells('A1:T1');
// 设置标题
sheet.getCell('A1').value = '山东矿机华信智能科技有限公司出入库记录表';
// 设置日期
sheet.mergeCells('A2:C2');
sheet.getCell('A2').value = `日期:${dayjs(time[0]).format('YYYY年M月D日')}-${dayjs(time[1]).format('YYYY年M月D日')}`;
// 设置表头
const headers = [
'出入库单号',
'出入库',
'项目',
'公司名称',
'产品名称',
'规格型号',
'时间',
'单位',
'数量',
'单价',
'金额',
'经办人',
'领料单号',
'备注'
];
sheet.addRow(headers);
for (let index = 0; index < data.length; index++) {
const record = data[index];
sheet.addRow([
`${record.inventoryInOutNumber}`,
record.project?.name || '',
record.inOrOut === MaterialsInOrOutEnum.In ? '入库' : "出库",
record.product?.company?.name || '',
record.product?.name || '',
record.product?.productSpecification || '',
`${dayjs(record.time).format('YYYY-MM-DD HH:mm')}`,
record.product.unit.label || '',
record.quantity,
parseFloat(`${record.unitPrice || 0}`),
parseFloat(`${record.amount || 0}`),
`${record?.agent || ''}`,
record?.issuanceNumber || '',
record?.remark || ''
]);
}
// 固定信息样式设定
sheet.eachRow((row, index) => {
if (index >= 3) {
row.alignment = { vertical: 'middle', horizontal: 'center' };
row.height = ROW_HEIGHT;
row.eachCell(cell => {
cell.border = {
top: { style: 'thin' },
left: { style: 'thin' },
bottom: { style: 'thin' },
right: { style: 'thin' }
};
});
}
});
sheet.columns.forEach((column, index: number) => {
let maxColumnLength = 0;
const autoWidth = ['B', 'C', 'S', 'U'];
if (String.fromCharCode(65 + index) === 'B') maxColumnLength = 20;
if (autoWidth.includes(String.fromCharCode(65 + index))) {
column.eachCell({ includeEmpty: true }, (cell, rowIndex) => {
if (rowIndex >= 5) {
const columnLength = `${cell.value || ''}`.length;
if (columnLength > maxColumnLength) {
maxColumnLength = columnLength;
}
}
});
column.width = maxColumnLength < 12 ? 12 : maxColumnLength; // Minimum width of 10
} else {
column.width = 12;
}
});
//读取buffer进行传输
const buffer = await workbook.xlsx.writeBuffer();
res
.header('Content-Type', 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet')
.header(
'Content-Disposition',
`attachment; filename="${filename}.xls"`
)
.send(buffer);
}
/** /**
* *
*/ */
@ -104,7 +219,8 @@ export class MaterialsInOutService {
position, position,
unitPrice, unitPrice,
quantity, quantity,
productId productId,
domain
} = dto; } = dto;
inventoryInOutNumber = await this.generateInventoryInOutNumber(inOrOut); inventoryInOutNumber = await this.generateInventoryInOutNumber(inOrOut);
let newRecordId; let newRecordId;
@ -115,7 +231,7 @@ export class MaterialsInOutService {
Object.is(inOrOut, MaterialsInOrOutEnum.In) Object.is(inOrOut, MaterialsInOrOutEnum.In)
? this.materialsInventoryService.inInventory.bind(this.materialsInventoryService) ? this.materialsInventoryService.inInventory.bind(this.materialsInventoryService)
: this.materialsInventoryService.outInventory.bind(this.materialsInventoryService) : this.materialsInventoryService.outInventory.bind(this.materialsInventoryService)
)({ productId, quantity, unitPrice, projectId, inventoryId, position }, manager); )({ productId, quantity, unitPrice, projectId, inventoryId, position }, manager, domain);
// 2.生成出入库记录 // 2.生成出入库记录
const { id } = await manager.save(MaterialsInOutEntity, { const { id } = await manager.save(MaterialsInOutEntity, {
...this.materialsInOutRepository.create({ ...dto, inventoryId: inventoryEntity?.id }), ...this.materialsInOutRepository.create({ ...dto, inventoryId: inventoryEntity?.id }),

View File

@ -45,8 +45,8 @@ export class MaterialsInventoryController {
@ApiOperation({ summary: '获取原材料库存列表' }) @ApiOperation({ summary: '获取原材料库存列表' })
@ApiResult({ type: [MaterialsInventoryEntity], isPage: true }) @ApiResult({ type: [MaterialsInventoryEntity], isPage: true })
@Perm(permissions.LIST) @Perm(permissions.LIST)
async list(@Query() dto: MaterialsInventoryQueryDto) { async list(@Domain() domain: SkDomain, @Query() dto: MaterialsInventoryQueryDto) {
return this.miService.findAll(dto); return this.miService.findAll({ ...dto, domain });
} }
@Get(':id') @Get(':id')

View File

@ -61,9 +61,14 @@ export class MaterialsInventoryExportDto extends DomainType {
// 开始和结束时间用的是一月的开始和一月的结束的时分秒 // 开始和结束时间用的是一月的开始和一月的结束的时分秒
const date = params.value; const date = params.value;
return [ return [
date ? `${formatToDate(dayjs(date).startOf('month'))} 00:00:00` : null, date ? `${date[0]} 00:00:00` : null,
date ? `${formatToDate(dayjs(date).endOf('month'))} 23:59:59` : null date ? `${date[1]} 23:59:59` : null
]; ];
}) })
time?: string[]; time?: string[];
@ApiProperty({ description: '文件名' })
@IsOptional()
@IsString()
filename: string;
} }

View File

@ -23,6 +23,7 @@ import { BusinessException } from '~/common/exceptions/biz.exception';
import { ErrorEnum } from '~/constants/error-code.constant'; import { ErrorEnum } from '~/constants/error-code.constant';
import { ParamConfigEntity } from '../system/param-config/param-config.entity'; import { ParamConfigEntity } from '../system/param-config/param-config.entity';
import { isDefined } from 'class-validator'; import { isDefined } from 'class-validator';
import { DomainType } from '~/common/decorators/domain.decorator';
@Injectable() @Injectable()
export class MaterialsInventoryService { export class MaterialsInventoryService {
constructor( constructor(
@ -35,7 +36,7 @@ export class MaterialsInventoryService {
private projectRepository: Repository<ProjectEntity>, private projectRepository: Repository<ProjectEntity>,
@InjectRepository(ParamConfigEntity) @InjectRepository(ParamConfigEntity)
private paramConfigRepository: Repository<ParamConfigEntity> private paramConfigRepository: Repository<ParamConfigEntity>
) {} ) { }
/** /**
* *
@ -55,7 +56,8 @@ export class MaterialsInventoryService {
const inventoriesInProjects = await this.materialsInventoryRepository.find({ const inventoriesInProjects = await this.materialsInventoryRepository.find({
where: { where: {
...(projects?.length ? { projectId: In(projects.map(item => item.id)) } : null) ...(projects?.length ? { projectId: In(projects.map(item => item.id)) } : null)
} },
relations: ['product', 'product.company', 'product.unit']
}); });
// 生成数据 // 生成数据
@ -86,7 +88,7 @@ export class MaterialsInventoryService {
const data = await sqb.addOrderBy('mio.time', 'DESC').getMany(); const data = await sqb.addOrderBy('mio.time', 'DESC').getMany();
if (!projectId) { if (!projectId) {
projects = uniqBy( projects = uniqBy(
data.map(item => item.project), data.filter(item => item.inOrOut === MaterialsInOrOutEnum.Out).map(item => item.project),
'id' 'id'
); );
} }
@ -95,7 +97,9 @@ export class MaterialsInventoryService {
const currentProjectInventories = inventoriesInProjects.filter(({ projectId }) => const currentProjectInventories = inventoriesInProjects.filter(({ projectId }) =>
Object.is(projectId, project.id) Object.is(projectId, project.id)
); );
const currentProjectData = data.filter(item => item.projectId === project.id); const currentProjectData = data.filter(
item => item.projectId === project.id || item.inOrOut === MaterialsInOrOutEnum.Out
);
const currentMonthProjectData = currentProjectData.filter(item => { const currentMonthProjectData = currentProjectData.filter(item => {
return ( return (
dayjs(item.time).isAfter(dayjs(time[0])) && dayjs(item.time).isBefore(dayjs(time[1])) dayjs(item.time).isAfter(dayjs(time[0])) && dayjs(item.time).isBefore(dayjs(time[1]))
@ -110,7 +114,7 @@ export class MaterialsInventoryService {
sheet.getCell('A2').value = `日期:${dayjs(time[0]).format('YYYY年M月')}`; sheet.getCell('A2').value = `日期:${dayjs(time[0]).format('YYYY年M月')}`;
// 设置表头 // 设置表头
const headers = [ const headers = [
'出入库单号', '号',
'公司名称', '公司名称',
'产品名称', '产品名称',
'单位', '单位',
@ -128,8 +132,6 @@ export class MaterialsInventoryService {
'结存数量', '结存数量',
'单价', '单价',
'金额', '金额',
'经办人',
'领料单号',
'备注' '备注'
]; ];
sheet.addRow(headers); sheet.addRow(headers);
@ -152,8 +154,6 @@ export class MaterialsInventoryService {
'', '',
'', '',
'', '',
'',
'',
'' ''
]); ]);
for (let i = 1; i <= 7; i++) { for (let i = 1; i <= 7; i++) {
@ -175,7 +175,7 @@ export class MaterialsInventoryService {
}; };
} }
for (let i = 16; i <= 21; i++) { for (let i = 16; i <= 19; i++) {
sheet.mergeCells(`${String.fromCharCode(64 + i)}3:${String.fromCharCode(64 + i)}4`); sheet.mergeCells(`${String.fromCharCode(64 + i)}3:${String.fromCharCode(64 + i)}4`);
} }
@ -196,24 +196,40 @@ export class MaterialsInventoryService {
} }
}); });
// 根据库存Id分组
const groupedData = groupBy<MaterialsInOutEntity>( const groupedData = groupBy<MaterialsInOutEntity>(
currentMonthProjectData, currentMonthProjectData,
record => `${record.productId}-${record.unitPrice}` record => record.inventoryId
); );
let number = 0; let number = 0;
const groupedInventories = groupBy( const groupedInventories = groupBy(currentProjectInventories, item => item.id);
currentProjectInventories, let orderNo = 0;
item => `${item.projectId}_${item.productId}`
); for (const key in groupedInventories) {
for (const key in groupedData) { orderNo++;
// 目前暂定逻辑出库只有一次或者没有出库。不会对一个入库的记录多次出库,故而用find。 // 目前暂定逻辑出库只有一次或者没有出库。不会对一个入库的记录多次出库,故而用find。---废弃
const inRecord = groupedData[key].find(item => item.inOrOut === MaterialsInOrOutEnum.In); // 2024.04.16 改成
const outRecord = groupedData[key].find(item => item.inOrOut === MaterialsInOrOutEnum.Out); const inventory = groupedInventories[key][0];
const currInventories = const outRecords = groupedData[key].filter(
groupedInventories[`${inRecord.projectId}_${inRecord.productId}`]?.shift(); item => item.inOrOut === MaterialsInOrOutEnum.Out
const allDataFromMonth = data.filter(
res => res.projectId === inRecord.projectId && res.productId === inRecord.productId
); );
const inRecords = groupedData[key].filter(item => item.inOrOut === MaterialsInOrOutEnum.In);
const outRecordQuantity = outRecords
.map(item => item.quantity)
.reduce((acc, cur) => {
return calcNumber(acc, cur, 'add');
}, 0);
const inRecordQuantity = inRecords
.map(item => item.quantity)
.reduce((acc, cur) => {
return calcNumber(acc, cur, 'add');
}, 0);
// 这里的单价默认入库价格和出库价格一致,所以直接用总数量*入库单价
const outRecordAmount = calcNumber(outRecordQuantity, inventory.unitPrice || 0, 'multiply');
const inRecordAmount = calcNumber(inRecordQuantity, inventory.unitPrice || 0, 'multiply');
const currInventories = groupedInventories[key]?.shift();
const allDataFromMonth = data.filter(res => res.inventoryId == Number(key));
let currentQuantity = 0; let currentQuantity = 0;
let balanceQuantity = 0; let balanceQuantity = 0;
// 月初库存数量 // 月初库存数量
@ -234,32 +250,33 @@ export class MaterialsInventoryService {
// 结存库存数量 // 结存库存数量
balanceQuantity = calcNumber( balanceQuantity = calcNumber(
currentQuantity, currentQuantity,
calcNumber(inRecord.quantity, outRecord?.quantity || 0, 'subtract'), calcNumber(inRecordQuantity, outRecordQuantity, 'subtract'),
'add' 'add'
); );
number++; number++;
sheet.addRow([ sheet.addRow([
`${inRecord.inventoryInOutNumber || ''}`, `${orderNo}`,
inRecord.product.company.name || '', inventory.product?.company?.name || '',
inRecord.product.name || '', inventory.product?.name || '',
inRecord.product.unit.label || '', inventory.product.unit.label || '',
currentQuantity, currentQuantity,
parseFloat(`${inRecord.unitPrice || 0}`), parseFloat(`${inventory.unitPrice || 0}`),
calcNumber(currentQuantity, inRecord.unitPrice || 0, 'multiply'), calcNumber(currentQuantity, inventory.unitPrice || 0, 'multiply'),
inRecord.time, // inRecord.time,
inRecord.quantity || 0, '',
parseFloat(`${inRecord.unitPrice || 0}`), inRecordQuantity,
parseFloat(`${inRecord.amount || 0}`), parseFloat(`${inventory.unitPrice || 0}`),
outRecord?.time || '', parseFloat(`${inRecordAmount}`),
outRecord?.quantity || 0, // outRecord?.time || '',
parseFloat(`${outRecord?.unitPrice || 0}`), '',
parseFloat(`${outRecord?.amount || 0}`), outRecordQuantity,
parseFloat(`${inventory?.unitPrice || 0}`),
parseFloat(`${outRecordAmount}`),
balanceQuantity, balanceQuantity,
parseFloat(`${inRecord?.unitPrice || 0}`), parseFloat(`${inventory?.unitPrice || 0}`),
calcNumber(balanceQuantity, inRecord?.unitPrice || 0, 'multiply'), calcNumber(balanceQuantity, inventory?.unitPrice || 0, 'multiply'),
`${inRecord?.agent || ''}/${outRecord?.agent || ''}`, // `${inRecord?.agent || ''}/${outRecord?.agent || ''}`,
outRecord?.issuanceNumber || '', ''
`${inRecord?.remark || ''}/${outRecord?.remark || ''}`
]); ]);
} }
sheet.getCell('A1').font = { size: HEADER_FONT_SIZE }; sheet.getCell('A1').font = { size: HEADER_FONT_SIZE };
@ -319,7 +336,8 @@ export class MaterialsInventoryService {
product, product,
keyword, keyword,
projectId, projectId,
isHasInventory isHasInventory,
domain
}: MaterialsInventoryQueryDto): Promise<Pagination<MaterialsInventoryEntity>> { }: MaterialsInventoryQueryDto): Promise<Pagination<MaterialsInventoryEntity>> {
const queryBuilder = this.materialsInventoryRepository const queryBuilder = this.materialsInventoryRepository
.createQueryBuilder('materialsInventory') .createQueryBuilder('materialsInventory')
@ -339,7 +357,8 @@ export class MaterialsInventoryService {
'product.productSpecification', 'product.productSpecification',
'product.productNumber' 'product.productNumber'
]) ])
.where('materialsInventory.isDelete = 0'); .where(fieldSearch({ domain }))
.andWhere('materialsInventory.isDelete = 0');
if (product) { if (product) {
queryBuilder.andWhere('product.name like :product', { product: `%${product}%` }); queryBuilder.andWhere('product.name like :product', { product: `%${product}%` });
} }
@ -402,7 +421,8 @@ export class MaterialsInventoryService {
unitPrice?: number; unitPrice?: number;
changedUnitPrice?: number; changedUnitPrice?: number;
}, },
manager: EntityManager manager: EntityManager,
domain?: DomainType
): Promise<MaterialsInventoryEntity> { ): Promise<MaterialsInventoryEntity> {
const { const {
projectId, projectId,
@ -415,9 +435,9 @@ export class MaterialsInventoryService {
} = data; } = data;
let searchPayload: any = {}; let searchPayload: any = {};
if (isDefined(inventoryId)) { if (isDefined(inventoryId)) {
searchPayload = { id: inventoryId }; searchPayload = { id: inventoryId, domain };
} else { } else {
searchPayload = { projectId, productId, unitPrice }; searchPayload = { projectId, productId, unitPrice, domain };
} }
const exsitedInventory = await manager.findOne(MaterialsInventoryEntity, { const exsitedInventory = await manager.findOne(MaterialsInventoryEntity, {
where: searchPayload, // 根据项目,产品,价格查出之前的实时库存情况 where: searchPayload, // 根据项目,产品,价格查出之前的实时库存情况
@ -461,7 +481,7 @@ export class MaterialsInventoryService {
quantity: number; quantity: number;
inventoryId?: number; inventoryId?: number;
}, },
manager: EntityManager manager: EntityManager,
): Promise<MaterialsInventoryEntity> { ): Promise<MaterialsInventoryEntity> {
const { quantity: outQuantity, inventoryId } = data; const { quantity: outQuantity, inventoryId } = data;
// 开启悲观行锁,防止脏读和修改 // 开启悲观行锁,防止脏读和修改

View File

@ -16,6 +16,7 @@ import { ApiResult } from '~/common/decorators/api-result.decorator';
import { ProjectEntity } from './project.entity'; import { ProjectEntity } from './project.entity';
import { ProjectDto, ProjectQueryDto, ProjectUpdateDto } from './project.dto'; import { ProjectDto, ProjectQueryDto, ProjectUpdateDto } from './project.dto';
import { IdParam } from '~/common/decorators/id-param.decorator'; import { IdParam } from '~/common/decorators/id-param.decorator';
import { Domain, SkDomain } from '~/common/decorators/domain.decorator';
export const permissions = definePermission('app:project', { export const permissions = definePermission('app:project', {
LIST: 'list', LIST: 'list',
CREATE: 'create', CREATE: 'create',
@ -34,8 +35,8 @@ export class ProjectController {
@ApiOperation({ summary: '分页获取项目列表' }) @ApiOperation({ summary: '分页获取项目列表' })
@ApiResult({ type: [ProjectEntity], isPage: true }) @ApiResult({ type: [ProjectEntity], isPage: true })
@Perm(permissions.LIST) @Perm(permissions.LIST)
async list(@Query() dto: ProjectQueryDto) { async list(@Domain() domain: SkDomain, @Query() dto: ProjectQueryDto) {
return this.projectService.findAll(dto); return this.projectService.findAll({ ...dto, domain });
} }
@Get(':id') @Get(':id')
@ -49,8 +50,8 @@ export class ProjectController {
@Post() @Post()
@ApiOperation({ summary: '新增项目' }) @ApiOperation({ summary: '新增项目' })
@Perm(permissions.CREATE) @Perm(permissions.CREATE)
async create(@Body() dto: ProjectDto): Promise<void> { async create(@Domain() domain: SkDomain, @Body() dto: ProjectDto): Promise<void> {
await this.projectService.create(dto); await this.projectService.create({ ...dto, domain });
} }
@Put(':id') @Put(':id')

View File

@ -4,8 +4,9 @@ import { PagerDto } from '~/common/dto/pager.dto';
import { Storage } from '../tools/storage/storage.entity'; import { Storage } from '../tools/storage/storage.entity';
import { IsUnique } from '~/shared/database/constraints/unique.constraint'; import { IsUnique } from '~/shared/database/constraints/unique.constraint';
import { ProjectEntity } from './project.entity'; import { ProjectEntity } from './project.entity';
import { DomainType } from '~/common/decorators/domain.decorator';
export class ProjectDto { export class ProjectDto extends DomainType {
@ApiProperty({ description: '项目名称' }) @ApiProperty({ description: '项目名称' })
@IsUnique(ProjectEntity, { message: '已存在同名项目' }) @IsUnique(ProjectEntity, { message: '已存在同名项目' })
@IsString() @IsString()
@ -31,7 +32,8 @@ export class ComapnyCreateDto extends PartialType(ProjectDto) {
export class ProjectQueryDto extends IntersectionType( export class ProjectQueryDto extends IntersectionType(
PagerDto<ProjectDto>, PagerDto<ProjectDto>,
PartialType(ProjectDto) PartialType(ProjectDto),
DomainType
) { ) {
@ApiProperty({ description: '项目名称' }) @ApiProperty({ description: '项目名称' })
@IsOptional() @IsOptional()

View File

@ -4,6 +4,7 @@ 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'; import { ProductEntity } from '../product/product.entity';
import { MaterialsInOutEntity } from '../materials_inventory/in_out/materials_in_out.entity'; import { MaterialsInOutEntity } from '../materials_inventory/in_out/materials_in_out.entity';
import { SkDomain } from '~/common/decorators/domain.decorator';
/** /**
* *
@ -24,6 +25,10 @@ export class ProjectEntity extends CommonEntity {
@ApiProperty({ description: '删除状态0未删除1已删除' }) @ApiProperty({ description: '删除状态0未删除1已删除' })
isDelete: number; isDelete: number;
@Column({ type: 'int', default: 1, comment: '所属域' })
@ApiProperty({ description: '所属域' })
domain: SkDomain;
@ApiHideProperty() @ApiHideProperty()
@OneToMany(() => MaterialsInOutEntity, product => product.project) @OneToMany(() => MaterialsInOutEntity, product => product.project)
materialsInOuts: Relation<MaterialsInOutEntity[]>; materialsInOuts: Relation<MaterialsInOutEntity[]>;

View File

@ -15,10 +15,11 @@ import {
ValidateIf ValidateIf
} from 'class-validator'; } from 'class-validator';
import { isEmpty } from 'lodash'; import { isEmpty } from 'lodash';
import { DomainType } from '~/common/decorators/domain.decorator';
import { PagerDto } from '~/common/dto/pager.dto'; import { PagerDto } from '~/common/dto/pager.dto';
export class UserDto { export class UserDto extends DomainType {
@ApiProperty({ description: '头像' }) @ApiProperty({ description: '头像' })
@IsOptional() @IsOptional()
@IsString() @IsString()
@ -83,9 +84,9 @@ export class UserDto {
status: number; status: number;
} }
export class UserUpdateDto extends PartialType(UserDto) {} export class UserUpdateDto extends PartialType(UserDto) { }
export class UserQueryDto extends IntersectionType(PagerDto<UserDto>, PartialType(UserDto)) { export class UserQueryDto extends IntersectionType(PagerDto<UserDto>, PartialType(UserDto), DomainType) {
@ApiProperty({ description: '归属大区', example: 1, required: false }) @ApiProperty({ description: '归属大区', example: 1, required: false })
@IsInt() @IsInt()
@IsOptional() @IsOptional()

View File

@ -22,7 +22,7 @@ import { UserPasswordDto } from './dto/password.dto';
import { UserDto, UserQueryDto, UserUpdateDto } from './dto/user.dto'; import { UserDto, UserQueryDto, UserUpdateDto } from './dto/user.dto';
import { UserEntity } from './user.entity'; import { UserEntity } from './user.entity';
import { UserService } from './user.service'; import { UserService } from './user.service';
import { Domain, SkDomain } from '~/common/decorators/domain.decorator'; import { Domain, DomainType, SkDomain } from '~/common/decorators/domain.decorator';
export const permissions = definePermission('system:user', { export const permissions = definePermission('system:user', {
LIST: 'list', LIST: 'list',
@ -42,7 +42,7 @@ export class UserController {
constructor( constructor(
private userService: UserService, private userService: UserService,
private menuService: MenuService private menuService: MenuService
) {} ) { }
@Get() @Get()
@ApiOperation({ summary: '获取用户列表' }) @ApiOperation({ summary: '获取用户列表' })
@ -62,8 +62,8 @@ export class UserController {
@Post() @Post()
@ApiOperation({ summary: '新增用户' }) @ApiOperation({ summary: '新增用户' })
@Perm(permissions.CREATE) @Perm(permissions.CREATE)
async create(@Body() dto: UserDto): Promise<void> { async create(@Domain() domain: SkDomain, @Body() dto: UserDto): Promise<void> {
await this.userService.create(dto); await this.userService.create({ ...dto, domain });
} }
@Put(':id') @Put(':id')

View File

@ -4,7 +4,9 @@ import { SkDomain } from '~/common/decorators/domain.decorator';
export const fieldSearch = <T>(entity: Partial<T>): ObjectLiteral => { export const fieldSearch = <T>(entity: Partial<T>): ObjectLiteral => {
let result = {}; let result = {};
for (let key in entity) { for (let key in entity) {
if (entity.hasOwnProperty(key)) { if (key == 'domain') {
result = { ...result, domain: entity['domain'] || -1 };
} else if (entity.hasOwnProperty(key)) {
switch (typeof entity[key]) { switch (typeof entity[key]) {
case 'number': case 'number':
result = { ...result, ...(isNumber(entity[key]) ? { [key]: entity[key] } : null) }; result = { ...result, ...(isNumber(entity[key]) ? { [key]: entity[key] } : null) };