import { Injectable } from '@nestjs/common'; import { InjectEntityManager, InjectRepository } from '@nestjs/typeorm'; import { ContractEntity } from './contract.entity'; import { EntityManager, Like, Not, Repository } from 'typeorm'; import { ContractDto, ContractQueryDto, ContractUpdateDto } from './contract.dto'; import { Pagination } from '~/helper/paginate/pagination'; import { isNumber } from 'lodash'; import { paginate } from '~/helper/paginate'; import { Storage } from '../tools/storage/storage.entity'; import { BusinessException } from '~/common/exceptions/biz.exception'; import { ErrorEnum } from '~/constants/error-code.constant'; import { fieldSearch } from '~/shared/database/field-search'; @Injectable() export class ContractService { constructor( @InjectEntityManager() private entityManager: EntityManager, @InjectRepository(ContractEntity) private contractRepository: Repository, @InjectRepository(Storage) private storageRepository: Repository ) {} /** * 查找所有合同 */ async findAll({ page, pageSize, ...fields }: ContractQueryDto): Promise> { const queryBuilder = this.contractRepository .createQueryBuilder('contract') .leftJoin('contract.files', 'files') .addSelect(['files.id', 'files.path']) .where(fieldSearch(fields)) .andWhere('contract.isDelete = 0'); return paginate(queryBuilder, { page, pageSize }); } /** * 新增 */ async create({ contractNumber, ...ext }: ContractDto): Promise { if (await this.checkIsContractNumberExsit(contractNumber)) { throw new BusinessException(ErrorEnum.CONTRACT_NUMBER_EXIST); } await this.contractRepository.insert( this.contractRepository.create({ contractNumber, ...ext }) ); } /** * 更新 */ async update( id: number, { fileIds, contractNumber, ...ext }: Partial ): Promise { await this.entityManager.transaction(async manager => { if (contractNumber && (await this.checkIsContractNumberExsit(contractNumber, id))) { throw new BusinessException(ErrorEnum.CONTRACT_NUMBER_EXIST); } await manager.update(ContractEntity, id, { ...ext, contractNumber }); if (fileIds?.length) { const count = await this.storageRepository .createQueryBuilder('storage') .where('storage.id in(:fileIds)', { fileIds }) .getCount(); if (count !== fileIds?.length) { throw new BusinessException(ErrorEnum.STORAGE_NOT_FOUND); } // 附件要批量插入 await manager.createQueryBuilder().relation(ContractEntity, 'files').of(id).add(fileIds); } }); } /** * 是否存在相同编号的合同 * @param contractNumber 合同编号 */ async checkIsContractNumberExsit(contractNumber: string, id?: number): Promise { return !!(await this.contractRepository.findOne({ where: { contractNumber: contractNumber, id: Not(id) } })); } /** * 删除 */ async delete(id: number): Promise { // 合同比较重要,做逻辑删除 await this.contractRepository.update(id, { isDelete: 1 }); } /** * 获取单个合同信息 */ async info(id: number) { const info = await this.contractRepository .createQueryBuilder('contract') .where({ id }) .andWhere('contract.isDelete = 0') .getOne(); return info; } /** * 解除附件关联 * @param id 合同ID * @param fileIds 附件ID */ async unlinkAttachments(id: number, fileIds: number[]) { await this.entityManager.transaction(async manager => { const contract = await this.contractRepository .createQueryBuilder('contract') .leftJoinAndSelect('contract.files', 'files') .where('contract.id = :id', { id }) .getOne(); const linkedFiles = contract.files .map(item => item.id) .filter(item => !fileIds.includes(item)); // 附件要批量更新 await manager .createQueryBuilder() .relation(ContractEntity, 'files') .of(id) .addAndRemove(linkedFiles, contract.files); }); } }