This commit is contained in:
@@ -19,6 +19,7 @@ import { JsonSchemaModule } from '../json-schema/json-schema.module';
|
||||
import { UserModule } from '../user/user.module';
|
||||
import { WorkflowEngineModule } from '../workflow-engine/workflow-engine.module';
|
||||
import { SearchModule } from '../search/search.module';
|
||||
import { FileStorageModule } from '../../common/file-storage/file-storage.module';
|
||||
|
||||
/**
|
||||
* CorrespondenceModule
|
||||
@@ -42,6 +43,7 @@ import { SearchModule } from '../search/search.module';
|
||||
UserModule,
|
||||
WorkflowEngineModule,
|
||||
SearchModule,
|
||||
FileStorageModule,
|
||||
],
|
||||
controllers: [CorrespondenceController],
|
||||
providers: [CorrespondenceService, CorrespondenceWorkflowService],
|
||||
|
||||
@@ -14,6 +14,7 @@ import { JsonSchemaService } from '../json-schema/json-schema.service';
|
||||
import { WorkflowEngineService } from '../workflow-engine/workflow-engine.service';
|
||||
import { UserService } from '../user/user.service';
|
||||
import { SearchService } from '../search/search.service';
|
||||
import { FileStorageService } from '../../common/file-storage/file-storage.service';
|
||||
|
||||
describe('CorrespondenceService', () => {
|
||||
let service: CorrespondenceService;
|
||||
@@ -118,6 +119,10 @@ describe('CorrespondenceService', () => {
|
||||
provide: SearchService,
|
||||
useValue: { indexDocument: jest.fn() },
|
||||
},
|
||||
{
|
||||
provide: FileStorageService,
|
||||
useValue: { commit: jest.fn().mockResolvedValue([]) },
|
||||
},
|
||||
],
|
||||
}).compile();
|
||||
|
||||
|
||||
@@ -34,6 +34,7 @@ import { JsonSchemaService } from '../json-schema/json-schema.service';
|
||||
import { WorkflowEngineService } from '../workflow-engine/workflow-engine.service';
|
||||
import { UserService } from '../user/user.service';
|
||||
import { SearchService } from '../search/search.service';
|
||||
import { FileStorageService } from '../../common/file-storage/file-storage.service';
|
||||
|
||||
/**
|
||||
* CorrespondenceService - Document management (CRUD)
|
||||
@@ -64,7 +65,8 @@ export class CorrespondenceService {
|
||||
private workflowEngine: WorkflowEngineService,
|
||||
private userService: UserService,
|
||||
private dataSource: DataSource,
|
||||
private searchService: SearchService
|
||||
private searchService: SearchService,
|
||||
private fileStorageService: FileStorageService
|
||||
) {}
|
||||
|
||||
async create(createDto: CreateCorrespondenceDto, user: User) {
|
||||
@@ -180,6 +182,12 @@ export class CorrespondenceService {
|
||||
body: createDto.body,
|
||||
remarks: createDto.remarks,
|
||||
dueDate: createDto.dueDate ? new Date(createDto.dueDate) : undefined,
|
||||
documentDate: createDto.documentDate
|
||||
? new Date(createDto.documentDate)
|
||||
: undefined,
|
||||
issuedDate: createDto.issuedDate
|
||||
? new Date(createDto.issuedDate)
|
||||
: undefined,
|
||||
description: createDto.description,
|
||||
details: createDto.details,
|
||||
createdBy: user.user_id,
|
||||
@@ -199,6 +207,20 @@ export class CorrespondenceService {
|
||||
await queryRunner.manager.save(recipients);
|
||||
}
|
||||
|
||||
// Commit attachments from Temp → Permanent (Two-Phase Storage)
|
||||
if (createDto.attachmentTempIds?.length) {
|
||||
const issueDate = createDto.issuedDate
|
||||
? new Date(createDto.issuedDate)
|
||||
: createDto.documentDate
|
||||
? new Date(createDto.documentDate)
|
||||
: undefined;
|
||||
|
||||
await this.fileStorageService.commit(createDto.attachmentTempIds, {
|
||||
issueDate,
|
||||
documentType: 'Correspondence',
|
||||
});
|
||||
}
|
||||
|
||||
await queryRunner.commitTransaction();
|
||||
|
||||
// Start Workflow Instance (non-blocking)
|
||||
@@ -457,6 +479,10 @@ export class CorrespondenceService {
|
||||
if (updateDto.remarks) revisionUpdate.remarks = updateDto.remarks;
|
||||
// Format Date correctly if string
|
||||
if (updateDto.dueDate) revisionUpdate.dueDate = new Date(updateDto.dueDate);
|
||||
if (updateDto.documentDate)
|
||||
revisionUpdate.documentDate = new Date(updateDto.documentDate);
|
||||
if (updateDto.issuedDate)
|
||||
revisionUpdate.issuedDate = new Date(updateDto.issuedDate);
|
||||
if (updateDto.description)
|
||||
revisionUpdate.description = updateDto.description;
|
||||
if (updateDto.details) revisionUpdate.details = updateDto.details;
|
||||
@@ -465,6 +491,20 @@ export class CorrespondenceService {
|
||||
await this.revisionRepo.update(revision.id, revisionUpdate);
|
||||
}
|
||||
|
||||
// 4.5 Commit new attachments from Temp → Permanent (Two-Phase Storage)
|
||||
if (updateDto.attachmentTempIds?.length) {
|
||||
const issueDate = updateDto.issuedDate
|
||||
? new Date(updateDto.issuedDate)
|
||||
: updateDto.documentDate
|
||||
? new Date(updateDto.documentDate)
|
||||
: revision.issuedDate || revision.documentDate || undefined;
|
||||
|
||||
await this.fileStorageService.commit(updateDto.attachmentTempIds, {
|
||||
issueDate: issueDate ? new Date(issueDate) : undefined,
|
||||
documentType: 'Correspondence',
|
||||
});
|
||||
}
|
||||
|
||||
// 5. Update Recipients if provided
|
||||
if (updateDto.recipients) {
|
||||
const recipientRepo = this.dataSource.getRepository(
|
||||
|
||||
@@ -84,6 +84,30 @@ export class CreateCorrespondenceDto {
|
||||
@IsOptional()
|
||||
isInternal?: boolean;
|
||||
|
||||
@ApiPropertyOptional({
|
||||
description: 'Document Date (วันที่เอกสาร)',
|
||||
example: '2025-12-06',
|
||||
})
|
||||
@IsDateString()
|
||||
@IsOptional()
|
||||
documentDate?: string;
|
||||
|
||||
@ApiPropertyOptional({
|
||||
description: 'Issued Date (วันที่ออกเอกสาร) — ใช้จัดเก็บไฟล์ตาม YYYY/MM',
|
||||
example: '2025-12-06T00:00:00Z',
|
||||
})
|
||||
@IsDateString()
|
||||
@IsOptional()
|
||||
issuedDate?: string;
|
||||
|
||||
@ApiPropertyOptional({
|
||||
description: 'Attachment temp IDs from upload phase (Two-Phase Storage)',
|
||||
example: ['uuid-temp-1', 'uuid-temp-2'],
|
||||
})
|
||||
@IsArray()
|
||||
@IsOptional()
|
||||
attachmentTempIds?: string[];
|
||||
|
||||
// ✅ เพิ่ม Field สำหรับ Impersonation (เลือกองค์กรผู้ส่ง)
|
||||
@ApiPropertyOptional({
|
||||
description: 'Originator Organization ID (for impersonation)',
|
||||
|
||||
@@ -11,6 +11,7 @@ import { Repository, DataSource, In, Brackets } from 'typeorm';
|
||||
import { ContractDrawing } from './entities/contract-drawing.entity';
|
||||
import { Attachment } from '../../common/file-storage/entities/attachment.entity';
|
||||
import { User } from '../user/entities/user.entity';
|
||||
import { Contract } from '../contract/entities/contract.entity';
|
||||
|
||||
// DTOs
|
||||
import { CreateContractDrawingDto } from './dto/create-contract-drawing.dto';
|
||||
@@ -29,10 +30,23 @@ export class ContractDrawingService {
|
||||
private drawingRepo: Repository<ContractDrawing>,
|
||||
@InjectRepository(Attachment)
|
||||
private attachmentRepo: Repository<Attachment>,
|
||||
@InjectRepository(Contract)
|
||||
private contractRepo: Repository<Contract>,
|
||||
private fileStorageService: FileStorageService,
|
||||
private dataSource: DataSource
|
||||
) {}
|
||||
|
||||
/**
|
||||
* Resolve issueDate from contract.startDate for file storage path
|
||||
* Fallback: contract.startDate → current date
|
||||
*/
|
||||
private async resolveIssueDateByProject(projectId: number): Promise<Date> {
|
||||
const contract = await this.contractRepo.findOne({
|
||||
where: { projectId },
|
||||
});
|
||||
return contract?.startDate ?? new Date();
|
||||
}
|
||||
|
||||
/**
|
||||
* สร้างแบบสัญญาใหม่ (Create Contract Drawing)
|
||||
* - ตรวจสอบเลขที่ซ้ำในโปรเจกต์
|
||||
@@ -84,9 +98,12 @@ export class ContractDrawingService {
|
||||
// 4. Commit Files (ย้ายไฟล์จริง)
|
||||
if (createDto.attachmentIds?.length) {
|
||||
// ✅ FIX TS2345: แปลง number[] เป็น string[] ก่อนส่ง
|
||||
const issueDate = await this.resolveIssueDateByProject(
|
||||
createDto.projectId
|
||||
);
|
||||
await this.fileStorageService.commit(
|
||||
createDto.attachmentIds.map(String),
|
||||
{ documentType: 'ContractDrawing' }
|
||||
{ issueDate, documentType: 'ContractDrawing' }
|
||||
);
|
||||
}
|
||||
|
||||
@@ -225,10 +242,14 @@ export class ContractDrawingService {
|
||||
drawing.attachments = newAttachments;
|
||||
|
||||
// Commit new files
|
||||
|
||||
// ✅ FIX TS2345: แปลง number[] เป็น string[] ก่อนส่ง
|
||||
const issueDate = await this.resolveIssueDateByProject(
|
||||
drawing.projectId
|
||||
);
|
||||
await this.fileStorageService.commit(
|
||||
updateDto.attachmentIds.map(String),
|
||||
{ documentType: 'ContractDrawing' }
|
||||
{ issueDate, documentType: 'ContractDrawing' }
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@@ -20,6 +20,7 @@ import { ShopDrawingSubCategory } from './entities/shop-drawing-sub-category.ent
|
||||
|
||||
// Common Entities
|
||||
import { Attachment } from '../../common/file-storage/entities/attachment.entity';
|
||||
import { Contract } from '../contract/entities/contract.entity';
|
||||
|
||||
// Services
|
||||
import { ShopDrawingService } from './shop-drawing.service';
|
||||
@@ -57,6 +58,7 @@ import { UserModule } from '../user/user.module';
|
||||
|
||||
// Common
|
||||
Attachment,
|
||||
Contract,
|
||||
]),
|
||||
FileStorageModule,
|
||||
UserModule,
|
||||
|
||||
Reference in New Issue
Block a user