fix(workflow): ADR-021 code review fixes (8 bugs)
- fix(transmittal): guard duplicate workflow instance on submit() - fix(workflow-guard): add organizationId to context so Level-2 RBAC works - fix(circulation): organizationId context passed relation object not INT FK - fix(transmittal): require Idempotency-Key header on POST submit endpoint - fix(workflow): userId non-optional in processTransition controller - fix(circulation): auto-close counts PENDING and IN_PROGRESS tasks - fix(transmittal): status badge uses workflowState/DRAFT not purpose field - fix(workflow): log cache invalidation failures instead of swallowing - fix(workflow): implement getAvailableActions endpoint stub - fix(i18n): add removeFile key to EN/TH locales
This commit is contained in:
@@ -1,6 +1,8 @@
|
||||
import {
|
||||
BadRequestException,
|
||||
Controller,
|
||||
Get,
|
||||
Headers,
|
||||
Post,
|
||||
Body,
|
||||
Param,
|
||||
@@ -85,8 +87,12 @@ export class TransmittalController {
|
||||
@Audit('transmittal.submit', 'transmittal')
|
||||
submit(
|
||||
@Param('uuid', ParseUuidPipe) uuid: string,
|
||||
@CurrentUser() user: User
|
||||
@CurrentUser() user: User,
|
||||
@Headers('Idempotency-Key') idempotencyKey: string
|
||||
) {
|
||||
if (!idempotencyKey) {
|
||||
throw new BadRequestException('Idempotency-Key header is required');
|
||||
}
|
||||
return this.transmittalService.submit(uuid, user);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -252,7 +252,7 @@ export class TransmittalService {
|
||||
Correspondence,
|
||||
{
|
||||
where: { publicId: uuid },
|
||||
select: ['id', 'correspondenceNumber', 'disciplineId'],
|
||||
select: ['id', 'correspondenceNumber', 'disciplineId', 'originatorId'],
|
||||
}
|
||||
);
|
||||
if (!correspondence)
|
||||
@@ -285,10 +285,17 @@ export class TransmittalService {
|
||||
}
|
||||
}
|
||||
|
||||
// เริ่ม Workflow Instance สำหรับ Transmittal
|
||||
const statusDraft = await this.statusRepo.findOne({
|
||||
where: { statusCode: 'DRAFT' },
|
||||
});
|
||||
// Bug 1 fix: ป้องกัน duplicate instance — ถ้ามี Active Instance อยู่แล้ว ให้หยุด
|
||||
const existingInstance = await this.workflowEngine.getInstanceByEntity(
|
||||
'transmittal',
|
||||
correspondence.id.toString()
|
||||
);
|
||||
if (existingInstance) {
|
||||
throw new ValidationException(
|
||||
`Transmittal นี้ถูก Submit ไปแล้ว (Workflow Instance: ${existingInstance.id})`
|
||||
);
|
||||
}
|
||||
|
||||
// [C3] Resolve contractId from discipline for contract-scoped workflow
|
||||
let contractId: number | null = null;
|
||||
if (correspondence.disciplineId) {
|
||||
@@ -298,11 +305,17 @@ export class TransmittalService {
|
||||
);
|
||||
contractId = rows[0]?.contract_id ?? null;
|
||||
}
|
||||
|
||||
// Bug 2 fix: ใส่ organizationId ใน context เพื่อให้ WorkflowTransitionGuard Level 2 (Org Admin) ทำงานได้
|
||||
const instance = await this.workflowEngine.createInstance(
|
||||
'TRANSMITTAL_FLOW_V1',
|
||||
'transmittal',
|
||||
correspondence.id.toString(),
|
||||
{ ownerId: user.user_id, contractId }
|
||||
{
|
||||
ownerId: user.user_id,
|
||||
contractId,
|
||||
organizationId: correspondence.originatorId ?? null,
|
||||
}
|
||||
);
|
||||
|
||||
const result = await this.workflowEngine.processTransition(
|
||||
@@ -313,18 +326,16 @@ export class TransmittalService {
|
||||
);
|
||||
|
||||
// Sync สถานะกลับที่ Correspondence Revision
|
||||
if (statusDraft) {
|
||||
const revision = await this.revisionRepo.findOne({
|
||||
where: { correspondenceId: correspondence.id, isCurrent: true },
|
||||
const revision = await this.revisionRepo.findOne({
|
||||
where: { correspondenceId: correspondence.id, isCurrent: true },
|
||||
});
|
||||
if (revision) {
|
||||
const submittedStatus = await this.statusRepo.findOne({
|
||||
where: { statusCode: 'SUBMITTED' },
|
||||
});
|
||||
if (revision) {
|
||||
const submittedStatus = await this.statusRepo.findOne({
|
||||
where: { statusCode: 'SUBMITTED' },
|
||||
});
|
||||
if (submittedStatus) {
|
||||
revision.statusId = submittedStatus.id;
|
||||
await this.revisionRepo.save(revision);
|
||||
}
|
||||
if (submittedStatus) {
|
||||
revision.statusId = submittedStatus.id;
|
||||
await this.revisionRepo.save(revision);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user