251204:1700 Prepare to version 1.5.1

This commit is contained in:
admin
2025-12-04 16:50:09 +07:00
parent 05f8f4403a
commit dc8b80c5f9
34 changed files with 8518 additions and 3107 deletions
@@ -1,98 +1,143 @@
// File: src/modules/transmittal/transmittal.service.ts
import {
Injectable,
Logger,
NotFoundException,
InternalServerErrorException,
BadRequestException,
} from '@nestjs/common';
import { InjectRepository } from '@nestjs/typeorm';
import { Repository, DataSource, In } from 'typeorm';
import { Transmittal } from './entities/transmittal.entity.js';
import { TransmittalItem } from './entities/transmittal-item.entity.js';
import { Correspondence } from '../correspondence/entities/correspondence.entity.js';
import { CreateTransmittalDto } from './dto/create-transmittal.dto.js';
import { User } from '../user/entities/user.entity.js';
import { DocumentNumberingService } from '../document-numbering/document-numbering.service.js';
import { SearchService } from '../search/search.service.js';
import { Repository, DataSource } from 'typeorm';
import { Transmittal } from './entities/transmittal.entity';
import { TransmittalItem } from './entities/transmittal-item.entity';
import { CreateTransmittalDto } from './dto/create-transmittal.dto';
import { User } from '../user/entities/user.entity';
import { DocumentNumberingService } from '../document-numbering/document-numbering.service';
import { Correspondence } from '../correspondence/entities/correspondence.entity';
import { CorrespondenceRevision } from '../correspondence/entities/correspondence-revision.entity';
import { CorrespondenceType } from '../correspondence/entities/correspondence-type.entity';
import { CorrespondenceStatus } from '../correspondence/entities/correspondence-status.entity';
@Injectable()
export class TransmittalService {
private readonly logger = new Logger(TransmittalService.name);
constructor(
@InjectRepository(Transmittal)
private transmittalRepo: Repository<Transmittal>,
@InjectRepository(TransmittalItem)
private transmittalItemRepo: Repository<TransmittalItem>,
@InjectRepository(Correspondence)
private correspondenceRepo: Repository<Correspondence>,
private itemRepo: Repository<TransmittalItem>,
@InjectRepository(CorrespondenceType)
private typeRepo: Repository<CorrespondenceType>,
@InjectRepository(CorrespondenceStatus)
private statusRepo: Repository<CorrespondenceStatus>,
private numberingService: DocumentNumberingService,
private dataSource: DataSource,
private searchService: SearchService,
private dataSource: DataSource
) {}
async create(createDto: CreateTransmittalDto, user: User) {
if (!user.primaryOrganizationId) {
throw new BadRequestException(
'User must belong to an organization to create documents',
);
}
const userOrgId = user.primaryOrganizationId;
// 1. Get Transmittal Type (Assuming Code '901' or 'TRN')
const type = await this.typeRepo.findOne({
where: { typeCode: 'TRN' }, // Adjust code as per Master Data
});
if (!type) throw new NotFoundException('Transmittal Type (TRN) not found');
const statusDraft = await this.statusRepo.findOne({
where: { statusCode: 'DRAFT' },
});
if (!statusDraft)
throw new InternalServerErrorException('Status DRAFT not found');
const queryRunner = this.dataSource.createQueryRunner();
await queryRunner.connect();
await queryRunner.startTransaction();
try {
const transmittalTypeId = 3; // TODO: ดึง ID จริงจาก DB หรือ Config
const orgCode = 'ORG'; // TODO: Fetch real ORG Code
if (!user.primaryOrganizationId) {
throw new BadRequestException(
'User must belong to an organization to create a transmittal'
);
}
// [FIXED] เรียกใช้แบบ Object Context
try {
// 2. Generate Number
const docNumber = await this.numberingService.generateNextNumber({
projectId: createDto.projectId,
originatorId: userOrgId,
typeId: transmittalTypeId,
originatorId: user.primaryOrganizationId,
typeId: type.id,
year: new Date().getFullYear(),
customTokens: {
TYPE_CODE: 'TR',
ORG_CODE: orgCode,
TYPE_CODE: type.typeCode,
ORG_CODE: 'ORG', // TODO: Fetch real ORG Code
},
});
// 3. Create Correspondence (Parent)
const correspondence = queryRunner.manager.create(Correspondence, {
correspondenceNumber: docNumber,
correspondenceTypeId: transmittalTypeId,
correspondenceTypeId: type.id,
projectId: createDto.projectId,
originatorId: userOrgId,
originatorId: user.primaryOrganizationId,
isInternal: false,
createdBy: user.user_id,
});
const savedCorr = await queryRunner.manager.save(correspondence);
// 4. Create Revision (Draft)
const revision = queryRunner.manager.create(CorrespondenceRevision, {
correspondenceId: savedCorr.id,
revisionNumber: 0,
revisionLabel: '0',
isCurrent: true,
statusId: statusDraft.id,
title: createDto.subject,
createdBy: user.user_id,
});
await queryRunner.manager.save(revision);
// 5. Create Transmittal
const transmittal = queryRunner.manager.create(Transmittal, {
correspondenceId: savedCorr.id,
purpose: createDto.purpose,
remarks: createDto.remarks,
transmittalNo: docNumber,
subject: createDto.subject,
});
await queryRunner.manager.save(transmittal);
const savedTransmittal = await queryRunner.manager.save(transmittal);
if (createDto.itemIds && createDto.itemIds.length > 0) {
const items = createDto.itemIds.map((itemId) =>
// 6. Create Items
if (createDto.items && createDto.items.length > 0) {
const items = createDto.items.map((item) =>
queryRunner.manager.create(TransmittalItem, {
transmittalId: savedCorr.id,
itemCorrespondenceId: itemId,
quantity: 1,
}),
transmittalId: savedTransmittal.id,
itemType: item.itemType,
itemId: item.itemId,
description: item.description,
})
);
await queryRunner.manager.save(items);
}
await queryRunner.commitTransaction();
return { ...savedCorr, transmittal };
return {
...savedTransmittal,
correspondence: savedCorr,
};
} catch (err) {
await queryRunner.rollbackTransaction();
this.logger.error(
`Failed to create transmittal: ${(err as Error).message}`
);
throw err;
} finally {
await queryRunner.release();
}
}
}
async findOne(id: number) {
const transmittal = await this.transmittalRepo.findOne({
where: { id },
relations: ['correspondence', 'items'],
});
if (!transmittal)
throw new NotFoundException(`Transmittal ID ${id} not found`);
return transmittal;
}
}