690403:1632 fix dashboard cir and trans
This commit is contained in:
@@ -184,11 +184,22 @@ describe('CorrespondenceService', () => {
|
|||||||
user_id: 1,
|
user_id: 1,
|
||||||
primaryOrganizationId: 10,
|
primaryOrganizationId: 10,
|
||||||
} as unknown as User;
|
} as unknown as User;
|
||||||
|
|
||||||
|
const mockCorr = {
|
||||||
|
id: 1,
|
||||||
|
publicId: 'corr-uuid-1',
|
||||||
|
correspondenceNumber: 'CORR-001',
|
||||||
|
projectId: 1,
|
||||||
|
createdAt: new Date(),
|
||||||
|
recipients: [],
|
||||||
|
};
|
||||||
|
|
||||||
const mockRevision = {
|
const mockRevision = {
|
||||||
id: 100,
|
id: 100,
|
||||||
correspondenceId: 1,
|
correspondenceId: 1,
|
||||||
isCurrent: true,
|
isCurrent: true,
|
||||||
statusId: 23,
|
statusId: 23,
|
||||||
|
correspondence: mockCorr,
|
||||||
};
|
};
|
||||||
|
|
||||||
jest
|
jest
|
||||||
@@ -209,11 +220,7 @@ describe('CorrespondenceService', () => {
|
|||||||
]);
|
]);
|
||||||
|
|
||||||
jest.spyOn(correspondenceRepo, 'findOne').mockResolvedValue({
|
jest.spyOn(correspondenceRepo, 'findOne').mockResolvedValue({
|
||||||
id: 1,
|
...mockCorr,
|
||||||
publicId: 'corr-uuid-1',
|
|
||||||
correspondenceNumber: 'CORR-001',
|
|
||||||
projectId: 1,
|
|
||||||
createdAt: new Date(),
|
|
||||||
revisions: [],
|
revisions: [],
|
||||||
} as unknown as Correspondence);
|
} as unknown as Correspondence);
|
||||||
|
|
||||||
@@ -258,16 +265,6 @@ describe('CorrespondenceService', () => {
|
|||||||
|
|
||||||
it('should NOT regenerate number if critical fields unchanged', async () => {
|
it('should NOT regenerate number if critical fields unchanged', async () => {
|
||||||
const mockUser = { id: 1, primaryOrganizationId: 10 } as unknown as User;
|
const mockUser = { id: 1, primaryOrganizationId: 10 } as unknown as User;
|
||||||
const mockRevision = {
|
|
||||||
id: 100,
|
|
||||||
correspondenceId: 1,
|
|
||||||
isCurrent: true,
|
|
||||||
statusId: 5,
|
|
||||||
};
|
|
||||||
|
|
||||||
jest
|
|
||||||
.spyOn(revisionRepo, 'findOne')
|
|
||||||
.mockResolvedValue(mockRevision as unknown as CorrespondenceRevision);
|
|
||||||
|
|
||||||
const mockCorr = {
|
const mockCorr = {
|
||||||
id: 1,
|
id: 1,
|
||||||
@@ -278,6 +275,18 @@ describe('CorrespondenceService', () => {
|
|||||||
correspondenceNumber: 'OLD-NUM',
|
correspondenceNumber: 'OLD-NUM',
|
||||||
recipients: [{ recipientType: 'TO', recipientOrganizationId: 99 }],
|
recipients: [{ recipientType: 'TO', recipientOrganizationId: 99 }],
|
||||||
};
|
};
|
||||||
|
const mockRevision = {
|
||||||
|
id: 100,
|
||||||
|
correspondenceId: 1,
|
||||||
|
isCurrent: true,
|
||||||
|
statusId: 5,
|
||||||
|
correspondence: mockCorr,
|
||||||
|
};
|
||||||
|
|
||||||
|
jest
|
||||||
|
.spyOn(revisionRepo, 'findOne')
|
||||||
|
.mockResolvedValue(mockRevision as unknown as CorrespondenceRevision);
|
||||||
|
|
||||||
jest
|
jest
|
||||||
.spyOn(correspondenceRepo, 'findOne')
|
.spyOn(correspondenceRepo, 'findOne')
|
||||||
.mockResolvedValue(mockCorr as unknown as Correspondence);
|
.mockResolvedValue(mockCorr as unknown as Correspondence);
|
||||||
@@ -296,16 +305,6 @@ describe('CorrespondenceService', () => {
|
|||||||
|
|
||||||
it('should regenerate number if Project ID changes', async () => {
|
it('should regenerate number if Project ID changes', async () => {
|
||||||
const mockUser = { id: 1, primaryOrganizationId: 10 } as unknown as User;
|
const mockUser = { id: 1, primaryOrganizationId: 10 } as unknown as User;
|
||||||
const mockRevision = {
|
|
||||||
id: 100,
|
|
||||||
correspondenceId: 1,
|
|
||||||
isCurrent: true,
|
|
||||||
statusId: 5,
|
|
||||||
};
|
|
||||||
jest
|
|
||||||
.spyOn(revisionRepo, 'findOne')
|
|
||||||
.mockResolvedValue(mockRevision as unknown as CorrespondenceRevision);
|
|
||||||
|
|
||||||
const mockCorr = {
|
const mockCorr = {
|
||||||
id: 1,
|
id: 1,
|
||||||
projectId: 1,
|
projectId: 1,
|
||||||
@@ -315,9 +314,32 @@ describe('CorrespondenceService', () => {
|
|||||||
correspondenceNumber: 'OLD-NUM',
|
correspondenceNumber: 'OLD-NUM',
|
||||||
recipients: [{ recipientType: 'TO', recipientOrganizationId: 99 }],
|
recipients: [{ recipientType: 'TO', recipientOrganizationId: 99 }],
|
||||||
};
|
};
|
||||||
|
const mockRevision = {
|
||||||
|
id: 100,
|
||||||
|
correspondenceId: 1,
|
||||||
|
isCurrent: true,
|
||||||
|
statusId: 5,
|
||||||
|
correspondence: mockCorr,
|
||||||
|
};
|
||||||
jest
|
jest
|
||||||
.spyOn(correspondenceRepo, 'findOne')
|
.spyOn(revisionRepo, 'findOne')
|
||||||
.mockResolvedValue(mockCorr as unknown as Correspondence);
|
.mockResolvedValue(mockRevision as unknown as CorrespondenceRevision);
|
||||||
|
|
||||||
|
const statusRepo = testingModule.get<Repository<CorrespondenceStatus>>(
|
||||||
|
getRepositoryToken(CorrespondenceStatus)
|
||||||
|
);
|
||||||
|
(statusRepo.findOne as jest.Mock).mockResolvedValue({
|
||||||
|
id: 5,
|
||||||
|
statusCode: 'DRAFT',
|
||||||
|
});
|
||||||
|
|
||||||
|
const typeRepo = testingModule.get<Repository<CorrespondenceType>>(
|
||||||
|
getRepositoryToken(CorrespondenceType)
|
||||||
|
);
|
||||||
|
(typeRepo.findOne as jest.Mock).mockResolvedValue({
|
||||||
|
id: 2,
|
||||||
|
typeCode: 'OLD-TYPE',
|
||||||
|
});
|
||||||
|
|
||||||
const updateDto: UpdateCorrespondenceDto = {
|
const updateDto: UpdateCorrespondenceDto = {
|
||||||
projectId: 2,
|
projectId: 2,
|
||||||
@@ -327,6 +349,11 @@ describe('CorrespondenceService', () => {
|
|||||||
testingModule.get<UuidResolverService>(UuidResolverService);
|
testingModule.get<UuidResolverService>(UuidResolverService);
|
||||||
(uuidResolver.resolveProjectId as jest.Mock).mockResolvedValue(2);
|
(uuidResolver.resolveProjectId as jest.Mock).mockResolvedValue(2);
|
||||||
|
|
||||||
|
jest.spyOn(correspondenceRepo, 'findOne').mockResolvedValue({
|
||||||
|
...mockCorr,
|
||||||
|
projectId: 2,
|
||||||
|
} as unknown as Correspondence);
|
||||||
|
|
||||||
await service.update(1, updateDto, mockUser);
|
await service.update(1, updateDto, mockUser);
|
||||||
|
|
||||||
expect(
|
expect(
|
||||||
@@ -336,16 +363,6 @@ describe('CorrespondenceService', () => {
|
|||||||
|
|
||||||
it('should regenerate number if Document Type changes', async () => {
|
it('should regenerate number if Document Type changes', async () => {
|
||||||
const mockUser = { id: 1, primaryOrganizationId: 10 } as unknown as User;
|
const mockUser = { id: 1, primaryOrganizationId: 10 } as unknown as User;
|
||||||
const mockRevision = {
|
|
||||||
id: 100,
|
|
||||||
correspondenceId: 1,
|
|
||||||
isCurrent: true,
|
|
||||||
statusId: 5,
|
|
||||||
};
|
|
||||||
jest
|
|
||||||
.spyOn(revisionRepo, 'findOne')
|
|
||||||
.mockResolvedValue(mockRevision as unknown as CorrespondenceRevision);
|
|
||||||
|
|
||||||
const mockCorr = {
|
const mockCorr = {
|
||||||
id: 1,
|
id: 1,
|
||||||
projectId: 1,
|
projectId: 1,
|
||||||
@@ -355,13 +372,24 @@ describe('CorrespondenceService', () => {
|
|||||||
correspondenceNumber: 'OLD-NUM',
|
correspondenceNumber: 'OLD-NUM',
|
||||||
recipients: [{ recipientType: 'TO', recipientOrganizationId: 99 }],
|
recipients: [{ recipientType: 'TO', recipientOrganizationId: 99 }],
|
||||||
};
|
};
|
||||||
jest
|
const mockRevision = {
|
||||||
.spyOn(correspondenceRepo, 'findOne')
|
id: 100,
|
||||||
.mockResolvedValue(mockCorr as unknown as Correspondence);
|
correspondenceId: 1,
|
||||||
|
isCurrent: true,
|
||||||
const updateDto: UpdateCorrespondenceDto = {
|
statusId: 5,
|
||||||
typeId: 999,
|
correspondence: mockCorr,
|
||||||
};
|
};
|
||||||
|
jest
|
||||||
|
.spyOn(revisionRepo, 'findOne')
|
||||||
|
.mockResolvedValue(mockRevision as unknown as CorrespondenceRevision);
|
||||||
|
|
||||||
|
const statusRepo = testingModule.get<Repository<CorrespondenceStatus>>(
|
||||||
|
getRepositoryToken(CorrespondenceStatus)
|
||||||
|
);
|
||||||
|
(statusRepo.findOne as jest.Mock).mockResolvedValue({
|
||||||
|
id: 5,
|
||||||
|
statusCode: 'DRAFT',
|
||||||
|
});
|
||||||
|
|
||||||
const typeRepo = testingModule.get<Repository<CorrespondenceType>>(
|
const typeRepo = testingModule.get<Repository<CorrespondenceType>>(
|
||||||
getRepositoryToken(CorrespondenceType)
|
getRepositoryToken(CorrespondenceType)
|
||||||
@@ -371,6 +399,15 @@ describe('CorrespondenceService', () => {
|
|||||||
typeCode: 'NEW-TYPE',
|
typeCode: 'NEW-TYPE',
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const updateDto: UpdateCorrespondenceDto = {
|
||||||
|
typeId: 999,
|
||||||
|
};
|
||||||
|
|
||||||
|
jest.spyOn(correspondenceRepo, 'findOne').mockResolvedValue({
|
||||||
|
...mockCorr,
|
||||||
|
correspondenceTypeId: 999,
|
||||||
|
} as unknown as Correspondence);
|
||||||
|
|
||||||
await service.update(1, updateDto, mockUser);
|
await service.update(1, updateDto, mockUser);
|
||||||
|
|
||||||
expect(
|
expect(
|
||||||
@@ -380,16 +417,6 @@ describe('CorrespondenceService', () => {
|
|||||||
|
|
||||||
it('should regenerate number if Recipient Organization changes', async () => {
|
it('should regenerate number if Recipient Organization changes', async () => {
|
||||||
const mockUser = { id: 1, primaryOrganizationId: 10 } as unknown as User;
|
const mockUser = { id: 1, primaryOrganizationId: 10 } as unknown as User;
|
||||||
const mockRevision = {
|
|
||||||
id: 100,
|
|
||||||
correspondenceId: 1,
|
|
||||||
isCurrent: true,
|
|
||||||
statusId: 5,
|
|
||||||
};
|
|
||||||
jest
|
|
||||||
.spyOn(revisionRepo, 'findOne')
|
|
||||||
.mockResolvedValue(mockRevision as unknown as CorrespondenceRevision);
|
|
||||||
|
|
||||||
const mockCorr = {
|
const mockCorr = {
|
||||||
id: 1,
|
id: 1,
|
||||||
projectId: 1,
|
projectId: 1,
|
||||||
@@ -399,9 +426,32 @@ describe('CorrespondenceService', () => {
|
|||||||
correspondenceNumber: 'OLD-NUM',
|
correspondenceNumber: 'OLD-NUM',
|
||||||
recipients: [{ recipientType: 'TO', recipientOrganizationId: 99 }],
|
recipients: [{ recipientType: 'TO', recipientOrganizationId: 99 }],
|
||||||
};
|
};
|
||||||
|
const mockRevision = {
|
||||||
|
id: 100,
|
||||||
|
correspondenceId: 1,
|
||||||
|
isCurrent: true,
|
||||||
|
statusId: 5,
|
||||||
|
correspondence: mockCorr,
|
||||||
|
};
|
||||||
jest
|
jest
|
||||||
.spyOn(correspondenceRepo, 'findOne')
|
.spyOn(revisionRepo, 'findOne')
|
||||||
.mockResolvedValue(mockCorr as unknown as Correspondence);
|
.mockResolvedValue(mockRevision as unknown as CorrespondenceRevision);
|
||||||
|
|
||||||
|
const typeRepo = testingModule.get<Repository<CorrespondenceType>>(
|
||||||
|
getRepositoryToken(CorrespondenceType)
|
||||||
|
);
|
||||||
|
(typeRepo.findOne as jest.Mock).mockResolvedValue({
|
||||||
|
id: 2,
|
||||||
|
typeCode: 'OLD-TYPE',
|
||||||
|
});
|
||||||
|
|
||||||
|
const statusRepo = testingModule.get<Repository<CorrespondenceStatus>>(
|
||||||
|
getRepositoryToken(CorrespondenceStatus)
|
||||||
|
);
|
||||||
|
(statusRepo.findOne as jest.Mock).mockResolvedValue({
|
||||||
|
id: 5,
|
||||||
|
statusCode: 'DRAFT',
|
||||||
|
});
|
||||||
|
|
||||||
// Access DataSource manager for mocking
|
// Access DataSource manager for mocking
|
||||||
mockDataSource.manager.findOne.mockResolvedValue({
|
mockDataSource.manager.findOne.mockResolvedValue({
|
||||||
@@ -413,6 +463,11 @@ describe('CorrespondenceService', () => {
|
|||||||
recipients: [{ type: 'TO', organizationId: 88 }],
|
recipients: [{ type: 'TO', organizationId: 88 }],
|
||||||
};
|
};
|
||||||
|
|
||||||
|
jest.spyOn(correspondenceRepo, 'findOne').mockResolvedValue({
|
||||||
|
...mockCorr,
|
||||||
|
recipients: [{ recipientType: 'TO', recipientOrganizationId: 88 }],
|
||||||
|
} as unknown as Correspondence);
|
||||||
|
|
||||||
await service.update(1, updateDto, mockUser);
|
await service.update(1, updateDto, mockUser);
|
||||||
|
|
||||||
expect(
|
expect(
|
||||||
|
|||||||
@@ -696,14 +696,94 @@ export class CorrespondenceService {
|
|||||||
)
|
)
|
||||||
: undefined;
|
: undefined;
|
||||||
|
|
||||||
// 3. Update Correspondence Entity if needed
|
// 3. Check if number regeneration is needed (only for DRAFT status)
|
||||||
|
const oldCorr = revision.correspondence;
|
||||||
|
if (!oldCorr) {
|
||||||
|
throw new InternalServerErrorException(
|
||||||
|
'Correspondence relation not loaded for revision'
|
||||||
|
);
|
||||||
|
}
|
||||||
|
const oldRecipientOrgId = oldCorr.recipients?.find(
|
||||||
|
(r) => r.recipientType === 'TO'
|
||||||
|
)?.recipientOrganizationId;
|
||||||
|
const newRecipientOrgId = updResolvedRecipients?.find(
|
||||||
|
(r) => r.type === 'TO'
|
||||||
|
)?.organizationId;
|
||||||
|
|
||||||
|
const needsNumberRegen =
|
||||||
|
(updResolvedProjectId && updResolvedProjectId !== oldCorr.projectId) ||
|
||||||
|
(updateDto.typeId && updateDto.typeId !== oldCorr.correspondenceTypeId) ||
|
||||||
|
(newRecipientOrgId && newRecipientOrgId !== oldRecipientOrgId);
|
||||||
|
|
||||||
|
let newNumber: string | undefined;
|
||||||
|
if (needsNumberRegen) {
|
||||||
|
// Check if current status is DRAFT - only regenerate for drafts
|
||||||
|
const currentStatus = await this.statusRepo.findOne({
|
||||||
|
where: { id: revision.statusId },
|
||||||
|
});
|
||||||
|
|
||||||
|
if (currentStatus?.statusCode === 'DRAFT') {
|
||||||
|
// Resolve originator for number generation
|
||||||
|
const originatorId =
|
||||||
|
updResolvedOriginatorId ||
|
||||||
|
oldCorr.originatorId ||
|
||||||
|
user.primaryOrganizationId;
|
||||||
|
|
||||||
|
// Get type info for number generation
|
||||||
|
const typeId = updateDto.typeId || oldCorr.correspondenceTypeId;
|
||||||
|
const type = await this.typeRepo.findOne({ where: { id: typeId } });
|
||||||
|
|
||||||
|
if (!type) {
|
||||||
|
throw new NotFoundException('Document Type not found');
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get recipient org code for number generation
|
||||||
|
const recipientOrgId = newRecipientOrgId || oldRecipientOrgId;
|
||||||
|
let _recipientCode = '';
|
||||||
|
if (recipientOrgId) {
|
||||||
|
const recOrg = await this.dataSource.manager.findOne(Organization, {
|
||||||
|
where: { id: recipientOrgId },
|
||||||
|
});
|
||||||
|
if (recOrg) _recipientCode = recOrg.organizationCode;
|
||||||
|
}
|
||||||
|
|
||||||
|
const projectId = updResolvedProjectId || oldCorr.projectId;
|
||||||
|
|
||||||
|
newNumber = await this.numberingService.updateNumberForDraft(
|
||||||
|
oldCorr.correspondenceNumber,
|
||||||
|
{
|
||||||
|
projectId: oldCorr.projectId,
|
||||||
|
originatorOrganizationId:
|
||||||
|
oldCorr.originatorId || user.primaryOrganizationId || 0,
|
||||||
|
typeId: oldCorr.correspondenceTypeId,
|
||||||
|
disciplineId: oldCorr.disciplineId,
|
||||||
|
recipientOrganizationId: oldRecipientOrgId || 0,
|
||||||
|
userId: user.user_id,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
projectId,
|
||||||
|
originatorOrganizationId:
|
||||||
|
originatorId || user.primaryOrganizationId || 0,
|
||||||
|
typeId,
|
||||||
|
disciplineId: updateDto.disciplineId || oldCorr.disciplineId,
|
||||||
|
recipientOrganizationId: recipientOrgId || 0,
|
||||||
|
userId: user.user_id,
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 4. Update Correspondence Entity if needed
|
||||||
const correspondenceUpdate: Record<string, unknown> = {};
|
const correspondenceUpdate: Record<string, unknown> = {};
|
||||||
|
if (newNumber) correspondenceUpdate.correspondenceNumber = newNumber;
|
||||||
if (updateDto.disciplineId)
|
if (updateDto.disciplineId)
|
||||||
correspondenceUpdate.disciplineId = updateDto.disciplineId;
|
correspondenceUpdate.disciplineId = updateDto.disciplineId;
|
||||||
if (updResolvedProjectId)
|
if (updResolvedProjectId)
|
||||||
correspondenceUpdate.projectId = updResolvedProjectId;
|
correspondenceUpdate.projectId = updResolvedProjectId;
|
||||||
if (updResolvedOriginatorId)
|
if (updResolvedOriginatorId)
|
||||||
correspondenceUpdate.originatorId = updResolvedOriginatorId;
|
correspondenceUpdate.originatorId = updResolvedOriginatorId;
|
||||||
|
if (updateDto.typeId)
|
||||||
|
correspondenceUpdate.correspondenceTypeId = updateDto.typeId;
|
||||||
|
|
||||||
if (Object.keys(correspondenceUpdate).length > 0) {
|
if (Object.keys(correspondenceUpdate).length > 0) {
|
||||||
await this.correspondenceRepo.update(id, correspondenceUpdate);
|
await this.correspondenceRepo.update(id, correspondenceUpdate);
|
||||||
|
|||||||
@@ -56,8 +56,8 @@ export default function TransmittalPage() {
|
|||||||
</SelectTrigger>
|
</SelectTrigger>
|
||||||
<SelectContent>
|
<SelectContent>
|
||||||
{(Array.isArray(projects) ? projects : []).map(
|
{(Array.isArray(projects) ? projects : []).map(
|
||||||
(p: { uuid: string; projectName?: string; projectCode?: string }) => (
|
(p: { publicId: string; projectName?: string; projectCode?: string }) => (
|
||||||
<SelectItem key={p.uuid} value={p.uuid}>
|
<SelectItem key={p.publicId} value={p.publicId}>
|
||||||
{p.projectName || p.projectCode}
|
{p.projectName || p.projectCode}
|
||||||
</SelectItem>
|
</SelectItem>
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -790,6 +790,31 @@ CREATE TABLE circulations (
|
|||||||
UNIQUE INDEX idx_circulations_uuid (uuid)
|
UNIQUE INDEX idx_circulations_uuid (uuid)
|
||||||
) ENGINE = InnoDB DEFAULT CHARSET = utf8mb4 COLLATE = utf8mb4_general_ci COMMENT = 'ตาราง "แม่" ของใบเวียนเอกสารภายใน';
|
) ENGINE = InnoDB DEFAULT CHARSET = utf8mb4 COLLATE = utf8mb4_general_ci COMMENT = 'ตาราง "แม่" ของใบเวียนเอกสารภายใน';
|
||||||
|
|
||||||
|
-- ตารางเก็บ Routing/Workflow ของใบเวียน (ขั้นตอนการดำเนินงาน)
|
||||||
|
CREATE TABLE circulation_routings (
|
||||||
|
id INT PRIMARY KEY AUTO_INCREMENT COMMENT 'ID ของรายการ routing',
|
||||||
|
circulation_id INT NOT NULL COMMENT 'ID ของใบเวียน',
|
||||||
|
step_number INT NOT NULL COMMENT 'ลำดับขั้นตอน',
|
||||||
|
organization_id INT NOT NULL COMMENT 'ID ขององค์กรในขั้นตอนนี้',
|
||||||
|
assigned_to INT NULL COMMENT 'ID ของผู้ใช้ที่ได้รับมอบหมาย (NULL = ยังไม่มอบหมาย)',
|
||||||
|
STATUS ENUM(
|
||||||
|
'PENDING',
|
||||||
|
'IN_PROGRESS',
|
||||||
|
'COMPLETED',
|
||||||
|
'REJECTED'
|
||||||
|
) DEFAULT 'PENDING' COMMENT 'สถานะขั้นตอน',
|
||||||
|
comments TEXT NULL COMMENT 'ความคิดเห็น/หมายเหตุ',
|
||||||
|
completed_at DATETIME NULL COMMENT 'วันที่เสร็จสิ้นขั้นตอน',
|
||||||
|
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP COMMENT 'วันที่สร้าง',
|
||||||
|
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT 'วันที่แก้ไขล่าสุด',
|
||||||
|
FOREIGN KEY (circulation_id) REFERENCES circulations (id) ON DELETE CASCADE,
|
||||||
|
FOREIGN KEY (organization_id) REFERENCES organizations (id),
|
||||||
|
FOREIGN KEY (assigned_to) REFERENCES users (user_id) ON DELETE
|
||||||
|
SET NULL,
|
||||||
|
INDEX idx_circulation_routing_circulation (circulation_id),
|
||||||
|
INDEX idx_circulation_routing_status (STATUS)
|
||||||
|
) ENGINE = InnoDB DEFAULT CHARSET = utf8mb4 COLLATE = utf8mb4_general_ci COMMENT = 'ตารางเก็บ Routing/Workflow ของใบเวียน';
|
||||||
|
|
||||||
-- =====================================================
|
-- =====================================================
|
||||||
-- 7. 📤 Transmittals (เอกสารนำส่ง)
|
-- 7. 📤 Transmittals (เอกสารนำส่ง)
|
||||||
-- =====================================================
|
-- =====================================================
|
||||||
|
|||||||
Reference in New Issue
Block a user