@platform-modules/civil-aviation-authority 2.3.298 → 2.3.300
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.env +2 -8
- package/dist/i18n/workflow-chat-message.builder.d.ts +9 -0
- package/dist/i18n/workflow-chat-message.builder.js +53 -2
- package/dist/models/FollowUpReportRequestModel.js +6 -1
- package/package.json +1 -1
- package/scripts/run-enum-fix.js +29 -8
- package/sql/caa_api_payload_changes_2026_07.sql +55 -6
- package/sql/fix_maintenance_subject_classification_enum_2026_07.sql +68 -12
- package/src/i18n/workflow-chat-message.builder.ts +75 -2
- package/src/models/FollowUpReportRequestModel.ts +6 -1
package/.env
CHANGED
|
@@ -2,17 +2,11 @@ DB_HOST=164.52.222.169
|
|
|
2
2
|
DB_PORT=5432
|
|
3
3
|
DB_USER=postgres_admin_user
|
|
4
4
|
DB_PASS=pg_admin_user_pwd_caa_fa_$%^&OIukhjgcvbn
|
|
5
|
-
DB_NAME=
|
|
5
|
+
DB_NAME=CAA
|
|
6
6
|
|
|
7
7
|
|
|
8
8
|
# DB_HOST=localhost
|
|
9
9
|
# DB_PORT=5432
|
|
10
10
|
# DB_USER=postgres
|
|
11
11
|
# DB_PASS=stevejobs
|
|
12
|
-
# DB_NAME=CAA
|
|
13
|
-
|
|
14
|
-
# DB_HOST=10.44.3.201
|
|
15
|
-
# DB_PORT=5432
|
|
16
|
-
# DB_USER=appuser
|
|
17
|
-
# DB_PASS=HamaCaa7489
|
|
18
|
-
# DB_NAME=caa_prd_db
|
|
12
|
+
# DB_NAME=CAA
|
|
@@ -58,6 +58,15 @@ export declare function renderSynchronizedWorkflowMessage(templateKey: string, e
|
|
|
58
58
|
export declare function renderSynchronizedChatMessage(templateKey: string, enParams: Record<string, string>, arParams: Record<string, string>): BilingualText;
|
|
59
59
|
export declare function buildBilingualFromTemplate(templateCatalog: Record<string, BilingualText>, key: string, params?: Record<string, string>, arParams?: Record<string, string>): BilingualText;
|
|
60
60
|
export declare function workflowTemplate(key: string, params?: Record<string, string>, arParams?: Record<string, string>): BilingualText;
|
|
61
|
+
/** Create/submit step for assign-tasks-emp workflow logs. */
|
|
62
|
+
export declare function buildAssignTasksEmpAssignedWorkflowFields(): BilingualText;
|
|
63
|
+
/** Approval step — pending from assigned employee. */
|
|
64
|
+
export declare function buildAssignTasksEmpPendingFromWorkflowFields(params: {
|
|
65
|
+
userName: string;
|
|
66
|
+
userArabicName?: string | null;
|
|
67
|
+
}): BilingualText;
|
|
68
|
+
/** Approval step fallback when assignee name is unavailable. */
|
|
69
|
+
export declare function buildAssignTasksEmpPendingWorkflowFields(): BilingualText;
|
|
61
70
|
export declare function chatTemplate(key: string, params?: Record<string, string>, arParams?: Record<string, string>): BilingualText;
|
|
62
71
|
/**
|
|
63
72
|
* Standard entry point for workflow `content` + `content_ar`.
|
|
@@ -17,6 +17,9 @@ exports.renderSynchronizedWorkflowMessage = renderSynchronizedWorkflowMessage;
|
|
|
17
17
|
exports.renderSynchronizedChatMessage = renderSynchronizedChatMessage;
|
|
18
18
|
exports.buildBilingualFromTemplate = buildBilingualFromTemplate;
|
|
19
19
|
exports.workflowTemplate = workflowTemplate;
|
|
20
|
+
exports.buildAssignTasksEmpAssignedWorkflowFields = buildAssignTasksEmpAssignedWorkflowFields;
|
|
21
|
+
exports.buildAssignTasksEmpPendingFromWorkflowFields = buildAssignTasksEmpPendingFromWorkflowFields;
|
|
22
|
+
exports.buildAssignTasksEmpPendingWorkflowFields = buildAssignTasksEmpPendingWorkflowFields;
|
|
20
23
|
exports.chatTemplate = chatTemplate;
|
|
21
24
|
exports.buildSynchronizedWorkflowMessage = buildSynchronizedWorkflowMessage;
|
|
22
25
|
exports.buildSynchronizedChatMessage = buildSynchronizedChatMessage;
|
|
@@ -154,6 +157,45 @@ function buildBilingualFromTemplate(templateCatalog, key, params = {}, arParams)
|
|
|
154
157
|
function workflowTemplate(key, params = {}, arParams) {
|
|
155
158
|
return buildBilingualFromTemplate(WORKFLOW_TEMPLATES, key, params, arParams);
|
|
156
159
|
}
|
|
160
|
+
/** Assign-tasks-emp workflow templates (catalog + runtime fallback when dist JSON is stale). */
|
|
161
|
+
const ASSIGN_TASKS_EMP_WF_FALLBACKS = {
|
|
162
|
+
request_assigned: { en: 'Request Assigned', ar: 'تم تعيين الطلب' },
|
|
163
|
+
request_pending_from: { en: 'Request Pending from {{name}}', ar: 'الطلب قيد الانتظار من {{name}}' },
|
|
164
|
+
request_pending: { en: 'Request Pending', ar: 'الطلب قيد الانتظار' },
|
|
165
|
+
};
|
|
166
|
+
function resolveAssignTasksEmpWorkflowTemplate(key, enParams = {}, arParams) {
|
|
167
|
+
const tpl = WORKFLOW_TEMPLATES[key] ?? ASSIGN_TASKS_EMP_WF_FALLBACKS[key];
|
|
168
|
+
const arabicParams = arParams ?? enParams;
|
|
169
|
+
return {
|
|
170
|
+
en: interpolate(tpl.en, enParams),
|
|
171
|
+
ar: interpolate(tpl.ar, arabicParams),
|
|
172
|
+
};
|
|
173
|
+
}
|
|
174
|
+
/** Create/submit step for assign-tasks-emp workflow logs. */
|
|
175
|
+
function buildAssignTasksEmpAssignedWorkflowFields() {
|
|
176
|
+
return resolveAssignTasksEmpWorkflowTemplate('request_assigned');
|
|
177
|
+
}
|
|
178
|
+
/** Approval step — pending from assigned employee. */
|
|
179
|
+
function buildAssignTasksEmpPendingFromWorkflowFields(params) {
|
|
180
|
+
const nameEn = params.userName.trim() || 'Unknown User';
|
|
181
|
+
const nameAr = resolveBilingualName(nameEn, params.userArabicName);
|
|
182
|
+
return resolveAssignTasksEmpWorkflowTemplate('request_pending_from', { name: nameEn }, { name: nameAr });
|
|
183
|
+
}
|
|
184
|
+
/** Approval step fallback when assignee name is unavailable. */
|
|
185
|
+
function buildAssignTasksEmpPendingWorkflowFields() {
|
|
186
|
+
return resolveAssignTasksEmpWorkflowTemplate('request_pending');
|
|
187
|
+
}
|
|
188
|
+
function resolveStoredAssignTasksEmpTemplateKey(content, actors) {
|
|
189
|
+
const normalized = content?.trim();
|
|
190
|
+
if (!normalized || !(normalized in ASSIGN_TASKS_EMP_WF_FALLBACKS))
|
|
191
|
+
return null;
|
|
192
|
+
if (normalized === 'request_pending_from') {
|
|
193
|
+
const nameEn = actors?.userName?.trim() || 'Unknown User';
|
|
194
|
+
const nameAr = resolveArabicWorkflowActorName(actors, nameEn);
|
|
195
|
+
return resolveAssignTasksEmpWorkflowTemplate('request_pending_from', { name: nameEn }, { name: nameAr });
|
|
196
|
+
}
|
|
197
|
+
return resolveAssignTasksEmpWorkflowTemplate(normalized);
|
|
198
|
+
}
|
|
157
199
|
function chatTemplate(key, params = {}, arParams) {
|
|
158
200
|
return buildBilingualFromTemplate(CHAT_TEMPLATES, key, params, arParams);
|
|
159
201
|
}
|
|
@@ -1144,6 +1186,9 @@ function resolveWorkflowContentAr(content, actors) {
|
|
|
1144
1186
|
if (content == null || content.trim() === '')
|
|
1145
1187
|
return null;
|
|
1146
1188
|
const normalized = content.trim();
|
|
1189
|
+
const assignTasksEmpFromKey = resolveStoredAssignTasksEmpTemplateKey(normalized, actors);
|
|
1190
|
+
if (assignTasksEmpFromKey)
|
|
1191
|
+
return assignTasksEmpFromKey.ar;
|
|
1147
1192
|
const embeddedAssignment = tryParseRequestAssignedComment(normalized);
|
|
1148
1193
|
if (embeddedAssignment) {
|
|
1149
1194
|
return buildAssignmentWorkflowFieldsFromActors(embeddedAssignment, actors).ar;
|
|
@@ -1269,9 +1314,11 @@ function isSystemGeneratedChatMessage(message, actors) {
|
|
|
1269
1314
|
/** Generic workflow log enricher — use in all module repositories. */
|
|
1270
1315
|
function enrichWorkflowLog(log) {
|
|
1271
1316
|
const status = log.status != null ? String(log.status) : null;
|
|
1272
|
-
const
|
|
1317
|
+
const rawContent = log.content != null ? String(log.content) : null;
|
|
1273
1318
|
const actors = extractBilingualActorsFromRecord(log);
|
|
1274
|
-
const
|
|
1319
|
+
const assignTasksEmpResolved = resolveStoredAssignTasksEmpTemplateKey(rawContent, actors);
|
|
1320
|
+
const content = assignTasksEmpResolved?.en ?? rawContent;
|
|
1321
|
+
const resolvedAr = assignTasksEmpResolved?.ar ?? resolveWorkflowContentAr(content, actors);
|
|
1275
1322
|
const existingAr = log.content_ar != null && String(log.content_ar).trim() !== ''
|
|
1276
1323
|
? String(log.content_ar)
|
|
1277
1324
|
: null;
|
|
@@ -1341,8 +1388,12 @@ function enrichWorkflowLog(log) {
|
|
|
1341
1388
|
if (notificationAr)
|
|
1342
1389
|
content_ar = notificationAr;
|
|
1343
1390
|
}
|
|
1391
|
+
if (assignTasksEmpResolved) {
|
|
1392
|
+
content_ar = assignTasksEmpResolved.ar;
|
|
1393
|
+
}
|
|
1344
1394
|
return {
|
|
1345
1395
|
...log,
|
|
1396
|
+
...(content !== rawContent ? { content } : {}),
|
|
1346
1397
|
content_ar,
|
|
1347
1398
|
status_ar: log.status_ar ?? resolveWorkflowStatusAr(status),
|
|
1348
1399
|
};
|
|
@@ -80,7 +80,12 @@ __decorate([
|
|
|
80
80
|
__metadata("design:type", String)
|
|
81
81
|
], FollowUpReportRequests.prototype, "subject", void 0);
|
|
82
82
|
__decorate([
|
|
83
|
-
(0, typeorm_1.Column)({
|
|
83
|
+
(0, typeorm_1.Column)({
|
|
84
|
+
type: 'varchar',
|
|
85
|
+
length: 100,
|
|
86
|
+
nullable: false,
|
|
87
|
+
default: FollowUpReportSubjectClassification.NORMAL,
|
|
88
|
+
}),
|
|
84
89
|
__metadata("design:type", String)
|
|
85
90
|
], FollowUpReportRequests.prototype, "subject_classification", void 0);
|
|
86
91
|
__decorate([
|
package/package.json
CHANGED
package/scripts/run-enum-fix.js
CHANGED
|
@@ -1,30 +1,51 @@
|
|
|
1
|
-
require('dotenv').config();
|
|
2
1
|
const fs = require('fs');
|
|
3
2
|
const path = require('path');
|
|
4
3
|
const { Client } = require('pg');
|
|
5
4
|
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
5
|
+
function loadEnv() {
|
|
6
|
+
try {
|
|
7
|
+
require('dotenv').config({ path: path.join(__dirname, '..', '.env') });
|
|
8
|
+
} catch {
|
|
9
|
+
// dotenv is optional at runtime if env vars are already set
|
|
10
|
+
}
|
|
11
|
+
}
|
|
9
12
|
|
|
10
|
-
|
|
13
|
+
function getDbConfig() {
|
|
14
|
+
const config = {
|
|
11
15
|
host: process.env.DB_HOST,
|
|
12
16
|
port: Number(process.env.DB_PORT || 5432),
|
|
13
17
|
user: process.env.DB_USER,
|
|
14
18
|
password: process.env.DB_PASS,
|
|
15
19
|
database: process.env.DB_NAME,
|
|
16
|
-
}
|
|
20
|
+
};
|
|
21
|
+
|
|
22
|
+
const missing = ['DB_HOST', 'DB_USER', 'DB_PASS', 'DB_NAME'].filter((key) => !process.env[key]);
|
|
23
|
+
if (missing.length > 0) {
|
|
24
|
+
throw new Error(
|
|
25
|
+
`Missing database env vars in shared_models/.env: ${missing.join(', ')}`,
|
|
26
|
+
);
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
return config;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
async function main() {
|
|
33
|
+
loadEnv();
|
|
34
|
+
|
|
35
|
+
const sqlPath = path.join(__dirname, '..', 'sql', 'fix_maintenance_subject_classification_enum_2026_07.sql');
|
|
36
|
+
const sql = fs.readFileSync(sqlPath, 'utf8');
|
|
37
|
+
const client = new Client(getDbConfig());
|
|
17
38
|
|
|
18
39
|
await client.connect();
|
|
19
40
|
try {
|
|
20
41
|
await client.query(sql);
|
|
21
|
-
console.log('
|
|
42
|
+
console.log('Enum repair SQL applied successfully.');
|
|
22
43
|
} finally {
|
|
23
44
|
await client.end();
|
|
24
45
|
}
|
|
25
46
|
}
|
|
26
47
|
|
|
27
48
|
main().catch((error) => {
|
|
28
|
-
console.error('
|
|
49
|
+
console.error('Enum repair failed:', error.message);
|
|
29
50
|
process.exit(1);
|
|
30
51
|
});
|
|
@@ -32,13 +32,62 @@ ALTER TABLE cyber_security_risk_management_risks
|
|
|
32
32
|
ADD COLUMN IF NOT EXISTS action TEXT;
|
|
33
33
|
|
|
34
34
|
-- 7. Follow-up report: subject_classification as varchar (avoids TypeORM PG enum sync failures)
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
35
|
+
DO $$
|
|
36
|
+
BEGIN
|
|
37
|
+
IF EXISTS (
|
|
38
|
+
SELECT 1 FROM information_schema.tables
|
|
39
|
+
WHERE table_schema = 'public' AND table_name = 'followup_report_requests'
|
|
40
|
+
) THEN
|
|
41
|
+
IF NOT EXISTS (
|
|
42
|
+
SELECT 1 FROM information_schema.columns
|
|
43
|
+
WHERE table_schema = 'public'
|
|
44
|
+
AND table_name = 'followup_report_requests'
|
|
45
|
+
AND column_name = 'subject_classification'
|
|
46
|
+
) THEN
|
|
47
|
+
ALTER TABLE followup_report_requests
|
|
48
|
+
ADD COLUMN subject_classification VARCHAR(100);
|
|
49
|
+
END IF;
|
|
50
|
+
|
|
51
|
+
BEGIN
|
|
52
|
+
ALTER TABLE followup_report_requests
|
|
53
|
+
ALTER COLUMN subject_classification TYPE VARCHAR(100)
|
|
54
|
+
USING COALESCE(subject_classification::text, 'Normal');
|
|
55
|
+
EXCEPTION WHEN OTHERS THEN NULL;
|
|
56
|
+
END;
|
|
57
|
+
|
|
58
|
+
UPDATE followup_report_requests
|
|
59
|
+
SET subject_classification = 'Normal'
|
|
60
|
+
WHERE subject_classification IS NULL OR TRIM(subject_classification) = '';
|
|
61
|
+
|
|
62
|
+
ALTER TABLE followup_report_requests
|
|
63
|
+
ALTER COLUMN subject_classification SET DEFAULT 'Normal';
|
|
38
64
|
|
|
39
|
-
ALTER TABLE followup_report_requests
|
|
40
|
-
|
|
41
|
-
|
|
65
|
+
ALTER TABLE followup_report_requests
|
|
66
|
+
ALTER COLUMN subject_classification SET NOT NULL;
|
|
67
|
+
END IF;
|
|
68
|
+
|
|
69
|
+
IF EXISTS (
|
|
70
|
+
SELECT 1 FROM information_schema.tables
|
|
71
|
+
WHERE table_schema = 'public' AND table_name = 'followup_report_items'
|
|
72
|
+
) THEN
|
|
73
|
+
IF NOT EXISTS (
|
|
74
|
+
SELECT 1 FROM information_schema.columns
|
|
75
|
+
WHERE table_schema = 'public'
|
|
76
|
+
AND table_name = 'followup_report_items'
|
|
77
|
+
AND column_name = 'subject_classification'
|
|
78
|
+
) THEN
|
|
79
|
+
ALTER TABLE followup_report_items
|
|
80
|
+
ADD COLUMN subject_classification VARCHAR(100);
|
|
81
|
+
END IF;
|
|
82
|
+
|
|
83
|
+
BEGIN
|
|
84
|
+
ALTER TABLE followup_report_items
|
|
85
|
+
ALTER COLUMN subject_classification TYPE VARCHAR(100)
|
|
86
|
+
USING subject_classification::text;
|
|
87
|
+
EXCEPTION WHEN OTHERS THEN NULL;
|
|
88
|
+
END;
|
|
89
|
+
END IF;
|
|
90
|
+
END $$;
|
|
42
91
|
|
|
43
92
|
DROP TYPE IF EXISTS maintenance_subject_classification_en_old;
|
|
44
93
|
|
|
@@ -1,20 +1,76 @@
|
|
|
1
|
-
-- Repair
|
|
2
|
-
-- Safe to re-run.
|
|
1
|
+
-- Repair follow-up report subject_classification for TypeORM schema sync.
|
|
2
|
+
-- Safe to re-run. Skips tables/columns that do not exist yet.
|
|
3
3
|
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
4
|
+
DO $$
|
|
5
|
+
BEGIN
|
|
6
|
+
IF EXISTS (
|
|
7
|
+
SELECT 1
|
|
8
|
+
FROM information_schema.tables
|
|
9
|
+
WHERE table_schema = 'public'
|
|
10
|
+
AND table_name = 'followup_report_requests'
|
|
11
|
+
) THEN
|
|
12
|
+
IF NOT EXISTS (
|
|
13
|
+
SELECT 1
|
|
14
|
+
FROM information_schema.columns
|
|
15
|
+
WHERE table_schema = 'public'
|
|
16
|
+
AND table_name = 'followup_report_requests'
|
|
17
|
+
AND column_name = 'subject_classification'
|
|
18
|
+
) THEN
|
|
19
|
+
ALTER TABLE followup_report_requests
|
|
20
|
+
ADD COLUMN subject_classification VARCHAR(100);
|
|
21
|
+
END IF;
|
|
22
|
+
|
|
23
|
+
BEGIN
|
|
24
|
+
ALTER TABLE followup_report_requests
|
|
25
|
+
ALTER COLUMN subject_classification TYPE VARCHAR(100)
|
|
26
|
+
USING COALESCE(subject_classification::text, 'Normal');
|
|
27
|
+
EXCEPTION
|
|
28
|
+
WHEN OTHERS THEN
|
|
29
|
+
NULL;
|
|
30
|
+
END;
|
|
31
|
+
|
|
32
|
+
UPDATE followup_report_requests
|
|
33
|
+
SET subject_classification = 'Normal'
|
|
34
|
+
WHERE subject_classification IS NULL
|
|
35
|
+
OR TRIM(subject_classification) = '';
|
|
36
|
+
|
|
37
|
+
ALTER TABLE followup_report_requests
|
|
38
|
+
ALTER COLUMN subject_classification SET DEFAULT 'Normal';
|
|
8
39
|
|
|
9
|
-
|
|
10
|
-
ALTER
|
|
11
|
-
|
|
12
|
-
|
|
40
|
+
ALTER TABLE followup_report_requests
|
|
41
|
+
ALTER COLUMN subject_classification SET NOT NULL;
|
|
42
|
+
END IF;
|
|
43
|
+
|
|
44
|
+
IF EXISTS (
|
|
45
|
+
SELECT 1
|
|
46
|
+
FROM information_schema.tables
|
|
47
|
+
WHERE table_schema = 'public'
|
|
48
|
+
AND table_name = 'followup_report_items'
|
|
49
|
+
) THEN
|
|
50
|
+
IF NOT EXISTS (
|
|
51
|
+
SELECT 1
|
|
52
|
+
FROM information_schema.columns
|
|
53
|
+
WHERE table_schema = 'public'
|
|
54
|
+
AND table_name = 'followup_report_items'
|
|
55
|
+
AND column_name = 'subject_classification'
|
|
56
|
+
) THEN
|
|
57
|
+
ALTER TABLE followup_report_items
|
|
58
|
+
ADD COLUMN subject_classification VARCHAR(100);
|
|
59
|
+
END IF;
|
|
60
|
+
|
|
61
|
+
BEGIN
|
|
62
|
+
ALTER TABLE followup_report_items
|
|
63
|
+
ALTER COLUMN subject_classification TYPE VARCHAR(100)
|
|
64
|
+
USING subject_classification::text;
|
|
65
|
+
EXCEPTION
|
|
66
|
+
WHEN OTHERS THEN
|
|
67
|
+
NULL;
|
|
68
|
+
END;
|
|
69
|
+
END IF;
|
|
70
|
+
END $$;
|
|
13
71
|
|
|
14
|
-
-- 3) Drop leftover TypeORM enum type if nothing depends on it
|
|
15
72
|
DROP TYPE IF EXISTS maintenance_subject_classification_en_old;
|
|
16
73
|
|
|
17
|
-
-- 4) Drop orphaned live enum only when no column uses it anymore
|
|
18
74
|
DO $$
|
|
19
75
|
BEGIN
|
|
20
76
|
IF NOT EXISTS (
|
|
@@ -199,6 +199,70 @@ export function workflowTemplate(
|
|
|
199
199
|
return buildBilingualFromTemplate(WORKFLOW_TEMPLATES, key, params, arParams);
|
|
200
200
|
}
|
|
201
201
|
|
|
202
|
+
/** Assign-tasks-emp workflow templates (catalog + runtime fallback when dist JSON is stale). */
|
|
203
|
+
const ASSIGN_TASKS_EMP_WF_FALLBACKS = {
|
|
204
|
+
request_assigned: { en: 'Request Assigned', ar: 'تم تعيين الطلب' },
|
|
205
|
+
request_pending_from: { en: 'Request Pending from {{name}}', ar: 'الطلب قيد الانتظار من {{name}}' },
|
|
206
|
+
request_pending: { en: 'Request Pending', ar: 'الطلب قيد الانتظار' },
|
|
207
|
+
} as const;
|
|
208
|
+
|
|
209
|
+
type AssignTasksEmpWorkflowTemplateKey = keyof typeof ASSIGN_TASKS_EMP_WF_FALLBACKS;
|
|
210
|
+
|
|
211
|
+
function resolveAssignTasksEmpWorkflowTemplate(
|
|
212
|
+
key: AssignTasksEmpWorkflowTemplateKey,
|
|
213
|
+
enParams: Record<string, string> = {},
|
|
214
|
+
arParams?: Record<string, string>,
|
|
215
|
+
): BilingualText {
|
|
216
|
+
const tpl = WORKFLOW_TEMPLATES[key] ?? ASSIGN_TASKS_EMP_WF_FALLBACKS[key];
|
|
217
|
+
const arabicParams = arParams ?? enParams;
|
|
218
|
+
return {
|
|
219
|
+
en: interpolate(tpl.en, enParams),
|
|
220
|
+
ar: interpolate(tpl.ar, arabicParams),
|
|
221
|
+
};
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
/** Create/submit step for assign-tasks-emp workflow logs. */
|
|
225
|
+
export function buildAssignTasksEmpAssignedWorkflowFields(): BilingualText {
|
|
226
|
+
return resolveAssignTasksEmpWorkflowTemplate('request_assigned');
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
/** Approval step — pending from assigned employee. */
|
|
230
|
+
export function buildAssignTasksEmpPendingFromWorkflowFields(params: {
|
|
231
|
+
userName: string;
|
|
232
|
+
userArabicName?: string | null;
|
|
233
|
+
}): BilingualText {
|
|
234
|
+
const nameEn = params.userName.trim() || 'Unknown User';
|
|
235
|
+
const nameAr = resolveBilingualName(nameEn, params.userArabicName);
|
|
236
|
+
return resolveAssignTasksEmpWorkflowTemplate(
|
|
237
|
+
'request_pending_from',
|
|
238
|
+
{ name: nameEn },
|
|
239
|
+
{ name: nameAr },
|
|
240
|
+
);
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
/** Approval step fallback when assignee name is unavailable. */
|
|
244
|
+
export function buildAssignTasksEmpPendingWorkflowFields(): BilingualText {
|
|
245
|
+
return resolveAssignTasksEmpWorkflowTemplate('request_pending');
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
function resolveStoredAssignTasksEmpTemplateKey(
|
|
249
|
+
content: string | null | undefined,
|
|
250
|
+
actors?: BilingualActorNames,
|
|
251
|
+
): BilingualText | null {
|
|
252
|
+
const normalized = content?.trim();
|
|
253
|
+
if (!normalized || !(normalized in ASSIGN_TASKS_EMP_WF_FALLBACKS)) return null;
|
|
254
|
+
if (normalized === 'request_pending_from') {
|
|
255
|
+
const nameEn = actors?.userName?.trim() || 'Unknown User';
|
|
256
|
+
const nameAr = resolveArabicWorkflowActorName(actors, nameEn);
|
|
257
|
+
return resolveAssignTasksEmpWorkflowTemplate(
|
|
258
|
+
'request_pending_from',
|
|
259
|
+
{ name: nameEn },
|
|
260
|
+
{ name: nameAr },
|
|
261
|
+
);
|
|
262
|
+
}
|
|
263
|
+
return resolveAssignTasksEmpWorkflowTemplate(normalized as AssignTasksEmpWorkflowTemplateKey);
|
|
264
|
+
}
|
|
265
|
+
|
|
202
266
|
export function chatTemplate(
|
|
203
267
|
key: string,
|
|
204
268
|
params: Record<string, string> = {},
|
|
@@ -1746,6 +1810,9 @@ export function resolveWorkflowContentAr(
|
|
|
1746
1810
|
if (content == null || content.trim() === '') return null;
|
|
1747
1811
|
const normalized = content.trim();
|
|
1748
1812
|
|
|
1813
|
+
const assignTasksEmpFromKey = resolveStoredAssignTasksEmpTemplateKey(normalized, actors);
|
|
1814
|
+
if (assignTasksEmpFromKey) return assignTasksEmpFromKey.ar;
|
|
1815
|
+
|
|
1749
1816
|
const embeddedAssignment = tryParseRequestAssignedComment(normalized);
|
|
1750
1817
|
if (embeddedAssignment) {
|
|
1751
1818
|
return buildAssignmentWorkflowFieldsFromActors(embeddedAssignment, actors).ar;
|
|
@@ -1885,9 +1952,11 @@ export function isSystemGeneratedChatMessage(
|
|
|
1885
1952
|
/** Generic workflow log enricher — use in all module repositories. */
|
|
1886
1953
|
export function enrichWorkflowLog(log: Record<string, unknown>): Record<string, unknown> {
|
|
1887
1954
|
const status = log.status != null ? String(log.status) : null;
|
|
1888
|
-
const
|
|
1955
|
+
const rawContent = log.content != null ? String(log.content) : null;
|
|
1889
1956
|
const actors = extractBilingualActorsFromRecord(log);
|
|
1890
|
-
const
|
|
1957
|
+
const assignTasksEmpResolved = resolveStoredAssignTasksEmpTemplateKey(rawContent, actors);
|
|
1958
|
+
const content = assignTasksEmpResolved?.en ?? rawContent;
|
|
1959
|
+
const resolvedAr = assignTasksEmpResolved?.ar ?? resolveWorkflowContentAr(content, actors);
|
|
1891
1960
|
const existingAr =
|
|
1892
1961
|
log.content_ar != null && String(log.content_ar).trim() !== ''
|
|
1893
1962
|
? String(log.content_ar)
|
|
@@ -1970,8 +2039,12 @@ export function enrichWorkflowLog(log: Record<string, unknown>): Record<string,
|
|
|
1970
2039
|
const notificationAr = resolveWorkflowContentAr(content, actors);
|
|
1971
2040
|
if (notificationAr) content_ar = notificationAr;
|
|
1972
2041
|
}
|
|
2042
|
+
if (assignTasksEmpResolved) {
|
|
2043
|
+
content_ar = assignTasksEmpResolved.ar;
|
|
2044
|
+
}
|
|
1973
2045
|
return {
|
|
1974
2046
|
...log,
|
|
2047
|
+
...(content !== rawContent ? { content } : {}),
|
|
1975
2048
|
content_ar,
|
|
1976
2049
|
status_ar: log.status_ar ?? resolveWorkflowStatusAr(status),
|
|
1977
2050
|
};
|
|
@@ -62,7 +62,12 @@ export class FollowUpReportRequests extends BaseModel {
|
|
|
62
62
|
@Column({ type: 'varchar', length: 500, nullable: false })
|
|
63
63
|
subject: string;
|
|
64
64
|
|
|
65
|
-
@Column({
|
|
65
|
+
@Column({
|
|
66
|
+
type: 'varchar',
|
|
67
|
+
length: 100,
|
|
68
|
+
nullable: false,
|
|
69
|
+
default: FollowUpReportSubjectClassification.NORMAL,
|
|
70
|
+
})
|
|
66
71
|
subject_classification: FollowUpReportSubjectClassification;
|
|
67
72
|
|
|
68
73
|
@Column({ type: 'text', nullable: false })
|