@platform-modules/civil-aviation-authority 2.3.280 → 2.3.282

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.
@@ -0,0 +1,409 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.enrichCancellationChatMessage = exports.enrichCancellationWorkflowLog = void 0;
7
+ exports.getWorkflowChatI18nCatalog = getWorkflowChatI18nCatalog;
8
+ exports.resolveBilingualName = resolveBilingualName;
9
+ exports.pickLocalizedName = pickLocalizedName;
10
+ exports.pickArabicName = pickArabicName;
11
+ exports.resolveActorDisplayNames = resolveActorDisplayNames;
12
+ exports.joinDeptSectionBilingualLabels = joinDeptSectionBilingualLabels;
13
+ exports.joinDeptSectionArabicLabels = joinDeptSectionArabicLabels;
14
+ exports.formatWorkflowCommentSuffix = formatWorkflowCommentSuffix;
15
+ exports.formatChatCommentSuffix = formatChatCommentSuffix;
16
+ exports.renderSynchronizedWorkflowMessage = renderSynchronizedWorkflowMessage;
17
+ exports.renderSynchronizedChatMessage = renderSynchronizedChatMessage;
18
+ exports.buildBilingualFromTemplate = buildBilingualFromTemplate;
19
+ exports.workflowTemplate = workflowTemplate;
20
+ exports.chatTemplate = chatTemplate;
21
+ exports.buildSynchronizedWorkflowMessage = buildSynchronizedWorkflowMessage;
22
+ exports.buildSynchronizedChatMessage = buildSynchronizedChatMessage;
23
+ exports.buildApprovalWorkflowContent = buildApprovalWorkflowContent;
24
+ exports.buildHumanApprovalWorkflowContent = buildHumanApprovalWorkflowContent;
25
+ exports.buildApprovalChatMessage = buildApprovalChatMessage;
26
+ exports.resolveWorkflowStatusAr = resolveWorkflowStatusAr;
27
+ exports.resolveChatStatusAr = resolveChatStatusAr;
28
+ exports.extractBilingualActorsFromRecord = extractBilingualActorsFromRecord;
29
+ exports.resolveWorkflowContentAr = resolveWorkflowContentAr;
30
+ exports.resolveChatMessageAr = resolveChatMessageAr;
31
+ exports.enrichWorkflowLog = enrichWorkflowLog;
32
+ exports.enrichChatMessage = enrichChatMessage;
33
+ /**
34
+ * CAA standard bilingual workflow/chat message builder.
35
+ *
36
+ * All services MUST use these helpers (never hardcode message strings).
37
+ * Templates live in workflow-chat-i18n.json; dynamic values use parallel EN/AR params.
38
+ */
39
+ const workflow_chat_i18n_json_1 = __importDefault(require("./workflow-chat-i18n.json"));
40
+ const WORKFLOW_TEMPLATES = workflow_chat_i18n_json_1.default.workflowTemplates;
41
+ const CHAT_TEMPLATES = workflow_chat_i18n_json_1.default.chatTemplates;
42
+ const WORKFLOW_STATUS_LABELS = workflow_chat_i18n_json_1.default.workflowStatusLabels;
43
+ const CHAT_STATUS_LABELS = workflow_chat_i18n_json_1.default.chatStatusLabels;
44
+ function getWorkflowChatI18nCatalog() {
45
+ return workflow_chat_i18n_json_1.default;
46
+ }
47
+ function interpolate(template, params = {}) {
48
+ return template.replace(/\{\{(\w+)\}\}/g, (_, key) => params[key] ?? '');
49
+ }
50
+ /** Arabic DB column preferred; English fallback so AR keeps identical structure to EN. */
51
+ function resolveBilingualName(englishName, arabicName) {
52
+ const ar = arabicName?.trim();
53
+ if (ar)
54
+ return ar;
55
+ return englishName?.trim() || '';
56
+ }
57
+ function pickLocalizedName(englishName, arabicName, fallback = '') {
58
+ return resolveBilingualName(englishName, arabicName) || fallback;
59
+ }
60
+ /** @deprecated Use resolveBilingualName */
61
+ function pickArabicName(arabicName) {
62
+ return arabicName?.trim() || '';
63
+ }
64
+ function joinLabels(...parts) {
65
+ return parts.map((p) => p?.trim()).filter(Boolean).join(' - ');
66
+ }
67
+ /** Build parallel EN / AR actor label from role OR dept+section. */
68
+ function resolveActorDisplayNames(actors) {
69
+ if (actors.roleName?.trim()) {
70
+ const en = actors.roleName.trim();
71
+ return { en, ar: resolveBilingualName(en, actors.roleArabicName) };
72
+ }
73
+ const en = joinLabels(actors.deptName, actors.sectionName);
74
+ const ar = joinLabels(resolveBilingualName(actors.deptName, actors.deptArabicName), resolveBilingualName(actors.sectionName, actors.sectionArabicName));
75
+ return { en, ar };
76
+ }
77
+ /** @deprecated Use resolveActorDisplayNames */
78
+ function joinDeptSectionBilingualLabels(deptEn, deptAr, sectEn, sectAr) {
79
+ return resolveActorDisplayNames({
80
+ deptName: deptEn,
81
+ deptArabicName: deptAr,
82
+ sectionName: sectEn,
83
+ sectionArabicName: sectAr,
84
+ });
85
+ }
86
+ /** @deprecated Use resolveActorDisplayNames */
87
+ function joinDeptSectionArabicLabels(deptArabic, sectionArabic) {
88
+ return joinLabels(deptArabic, sectionArabic);
89
+ }
90
+ function formatWorkflowCommentSuffix(comment) {
91
+ const text = comment?.trim();
92
+ return text ? `: ${text}` : '';
93
+ }
94
+ function formatChatCommentSuffix(comment) {
95
+ const text = comment?.trim();
96
+ return text ? ` - ${text}` : '';
97
+ }
98
+ /** Core renderer — always pass explicit EN and AR param objects with the same keys. */
99
+ function renderSynchronizedWorkflowMessage(templateKey, enParams, arParams) {
100
+ const tpl = WORKFLOW_TEMPLATES[templateKey];
101
+ if (!tpl)
102
+ return { en: templateKey, ar: templateKey };
103
+ return {
104
+ en: interpolate(tpl.en, enParams),
105
+ ar: interpolate(tpl.ar, arParams),
106
+ };
107
+ }
108
+ function renderSynchronizedChatMessage(templateKey, enParams, arParams) {
109
+ const tpl = CHAT_TEMPLATES[templateKey];
110
+ if (!tpl)
111
+ return { en: templateKey, ar: templateKey };
112
+ return {
113
+ en: interpolate(tpl.en, enParams),
114
+ ar: interpolate(tpl.ar, arParams),
115
+ };
116
+ }
117
+ function buildBilingualFromTemplate(templateCatalog, key, params = {}, arParams) {
118
+ const tpl = templateCatalog[key];
119
+ if (!tpl)
120
+ return { en: key, ar: key };
121
+ const arabicParams = arParams ?? params;
122
+ return {
123
+ en: interpolate(tpl.en, params),
124
+ ar: interpolate(tpl.ar, arabicParams),
125
+ };
126
+ }
127
+ function workflowTemplate(key, params = {}, arParams) {
128
+ return buildBilingualFromTemplate(WORKFLOW_TEMPLATES, key, params, arParams);
129
+ }
130
+ function chatTemplate(key, params = {}, arParams) {
131
+ return buildBilingualFromTemplate(CHAT_TEMPLATES, key, params, arParams);
132
+ }
133
+ /**
134
+ * Standard entry point for workflow `content` + `content_ar`.
135
+ * Use for every workflow log insert/update across all CAA modules.
136
+ */
137
+ function buildSynchronizedWorkflowMessage(ctx) {
138
+ const commentWf = formatWorkflowCommentSuffix(ctx.comment);
139
+ const { en: actorEn, ar: actorAr } = resolveActorDisplayNames(ctx);
140
+ switch (ctx.action) {
141
+ case 'request_submitted':
142
+ return workflowTemplate('request_submitted');
143
+ case 'notification_sent_pending':
144
+ return workflowTemplate('notification_sent_pending');
145
+ case 'notification_sent_successfully':
146
+ return workflowTemplate('notification_sent_successfully');
147
+ case 'approval_in_progress':
148
+ return actorEn
149
+ ? renderSynchronizedWorkflowMessage('request_approval_in_progress_from', { name: actorEn }, { name: actorAr })
150
+ : workflowTemplate('request_approval_in_progress');
151
+ case 'approval_pending':
152
+ return actorEn
153
+ ? renderSynchronizedWorkflowMessage('request_approval_pending_from', { name: actorEn }, { name: actorAr })
154
+ : workflowTemplate('request_approval_pending');
155
+ case 'approved':
156
+ return actorEn
157
+ ? renderSynchronizedWorkflowMessage('request_approved_by', { name: actorEn, comment: commentWf }, { name: actorAr, comment: commentWf })
158
+ : renderSynchronizedWorkflowMessage('request_approved', { comment: commentWf }, { comment: commentWf });
159
+ case 'rejected':
160
+ return actorEn
161
+ ? renderSynchronizedWorkflowMessage('request_rejected_by', { name: actorEn, comment: commentWf }, { name: actorAr, comment: commentWf })
162
+ : renderSynchronizedWorkflowMessage('request_rejected', { comment: commentWf }, { comment: commentWf });
163
+ case 'returned_for_modification':
164
+ return actorEn
165
+ ? renderSynchronizedWorkflowMessage('request_returned_for_modification_by', { name: actorEn, comment: commentWf }, { name: actorAr, comment: commentWf })
166
+ : renderSynchronizedWorkflowMessage('request_returned_for_modification', { comment: commentWf }, { comment: commentWf });
167
+ case 'approval_pending_update':
168
+ return actorEn
169
+ ? renderSynchronizedWorkflowMessage('request_approval_pending_from', { name: actorEn, comment: commentWf }, { name: actorAr, comment: commentWf })
170
+ : renderSynchronizedWorkflowMessage('request_approval_pending', { comment: commentWf }, { comment: commentWf });
171
+ default:
172
+ return workflowTemplate('request_submitted');
173
+ }
174
+ }
175
+ /**
176
+ * Standard entry point for chat `message` + `message_ar`.
177
+ * Use for every chat insert/update across all CAA modules.
178
+ */
179
+ function buildSynchronizedChatMessage(ctx) {
180
+ const commentChat = formatChatCommentSuffix(ctx.comment);
181
+ switch (ctx.action) {
182
+ case 'cancellation_submitted': {
183
+ const userEn = ctx.userName?.trim() || 'Unknown User';
184
+ const userAr = resolveBilingualName(userEn, ctx.userArabicName);
185
+ const employeeId = String(ctx.employeeId ?? 'N/A');
186
+ return chatTemplate('cancellation_submitted_by', { userName: userEn, employeeId }, { userName: userAr, employeeId });
187
+ }
188
+ case 'request_received':
189
+ return chatTemplate('request_received');
190
+ case 'approved':
191
+ case 'rejected':
192
+ case 'returned_for_modification': {
193
+ const roleEn = ctx.roleName?.trim() || 'Unknown Role';
194
+ const roleAr = resolveBilingualName(roleEn, ctx.roleArabicName);
195
+ const key = ctx.action === 'approved'
196
+ ? 'request_approved_by_role'
197
+ : ctx.action === 'rejected'
198
+ ? 'request_rejected_by_role'
199
+ : 'request_returned_for_modification_by_role';
200
+ return renderSynchronizedChatMessage(key, { roleName: roleEn, comment: commentChat }, { roleName: roleAr, comment: commentChat });
201
+ }
202
+ default:
203
+ return chatTemplate('request_received');
204
+ }
205
+ }
206
+ // ─── Backward-compatible aliases used by Cancellation pilot ───────────────────
207
+ function buildApprovalWorkflowContent(params) {
208
+ const status = params.status;
209
+ let action;
210
+ if (status === 'Approved')
211
+ action = 'approved';
212
+ else if (status === 'Rejected')
213
+ action = 'rejected';
214
+ else if (status === 'Returned for Modification')
215
+ action = 'returned_for_modification';
216
+ else
217
+ action = 'approval_pending_update';
218
+ return buildSynchronizedWorkflowMessage({
219
+ action,
220
+ roleName: params.roleName,
221
+ roleArabicName: params.roleArabicName,
222
+ comment: params.comment,
223
+ });
224
+ }
225
+ function buildHumanApprovalWorkflowContent(params) {
226
+ return buildSynchronizedWorkflowMessage({
227
+ action: params.isFirst ? 'approval_in_progress' : 'approval_pending',
228
+ roleName: params.roleName,
229
+ roleArabicName: params.roleArabicName,
230
+ deptName: params.deptName,
231
+ deptArabicName: params.deptArabicName,
232
+ sectionName: params.sectionName,
233
+ sectionArabicName: params.sectionArabicName,
234
+ });
235
+ }
236
+ function buildApprovalChatMessage(params) {
237
+ let action = 'approved';
238
+ if (params.status === 'Rejected')
239
+ action = 'rejected';
240
+ else if (params.status === 'Returned for Modification')
241
+ action = 'returned_for_modification';
242
+ return buildSynchronizedChatMessage({
243
+ action,
244
+ roleName: params.roleName,
245
+ roleArabicName: params.roleArabicName,
246
+ comment: params.comment,
247
+ });
248
+ }
249
+ // ─── Status labels ───────────────────────────────────────────────────────────
250
+ function resolveWorkflowStatusAr(status) {
251
+ if (status == null || status === '')
252
+ return null;
253
+ return WORKFLOW_STATUS_LABELS[status] ?? status;
254
+ }
255
+ function resolveChatStatusAr(status) {
256
+ if (status == null || status === '')
257
+ return null;
258
+ return CHAT_STATUS_LABELS[status] ?? status;
259
+ }
260
+ // ─── Legacy row enrichment (read API) ────────────────────────────────────────
261
+ /** Pull bilingual actor fields from joined relations on workflow/chat rows. */
262
+ function extractBilingualActorsFromRecord(record) {
263
+ const role = (record.approver_role ?? record.role);
264
+ const user = (record.approver_user ?? record.user);
265
+ const dept = (record.approver_department ?? record.department);
266
+ const section = (record.approver_section ?? record.section);
267
+ return {
268
+ roleName: role?.name != null ? String(role.name) : null,
269
+ roleArabicName: role?.arabic_name != null ? String(role.arabic_name) : null,
270
+ deptName: dept?.department_name != null ? String(dept.department_name) : null,
271
+ deptArabicName: dept?.department_arabic_name != null ? String(dept.department_arabic_name) : null,
272
+ sectionName: section?.section_name != null ? String(section.section_name) : null,
273
+ sectionArabicName: section?.section_arabic_name != null ? String(section.section_arabic_name) : null,
274
+ userName: user?.employee_name != null ? String(user.employee_name) : null,
275
+ userArabicName: user?.employee_arabic_name != null ? String(user.employee_arabic_name) : null,
276
+ employeeId: user?.employee_id != null ? String(user.employee_id) : null,
277
+ };
278
+ }
279
+ /** Arabic actor label for workflow templates (role, dept+section, or user). */
280
+ function resolveArabicWorkflowActorName(actors, parsedEnglishName) {
281
+ if (actors) {
282
+ const { ar } = resolveActorDisplayNames(actors);
283
+ if (ar)
284
+ return ar;
285
+ if (actors.userName?.trim()) {
286
+ return resolveBilingualName(actors.userName, actors.userArabicName);
287
+ }
288
+ }
289
+ return parsedEnglishName?.trim() || '';
290
+ }
291
+ /** Arabic role/user label for chat templates. */
292
+ function resolveArabicChatRoleName(actors, parsedEnglishRole) {
293
+ if (actors?.roleName?.trim()) {
294
+ return resolveBilingualName(actors.roleName, actors.roleArabicName);
295
+ }
296
+ if (actors?.userName?.trim()) {
297
+ return resolveBilingualName(actors.userName, actors.userArabicName);
298
+ }
299
+ return resolveBilingualName(parsedEnglishRole, actors?.roleArabicName);
300
+ }
301
+ function resolveWorkflowContentAr(content, actors) {
302
+ if (content == null || content.trim() === '')
303
+ return null;
304
+ const normalized = content.trim();
305
+ for (const tpl of Object.values(WORKFLOW_TEMPLATES)) {
306
+ if (tpl.en === normalized)
307
+ return tpl.ar;
308
+ }
309
+ const commentIdx = normalized.indexOf(': ');
310
+ if (commentIdx > 0) {
311
+ const baseEn = normalized.slice(0, commentIdx).trim();
312
+ const commentText = normalized.slice(commentIdx + 2).trim();
313
+ const commentSuffix = formatWorkflowCommentSuffix(commentText);
314
+ for (const tpl of Object.values(WORKFLOW_TEMPLATES)) {
315
+ if (!tpl.en.includes('{{comment}}'))
316
+ continue;
317
+ const withoutComment = tpl.en.replace('{{comment}}', '');
318
+ if (withoutComment.includes('{{name}}')) {
319
+ const staticPrefix = withoutComment.replace('{{name}}', '').trim();
320
+ if (baseEn.startsWith(staticPrefix)) {
321
+ const namePartEn = baseEn.slice(staticPrefix.length).trim();
322
+ const nameAr = resolveArabicWorkflowActorName(actors, namePartEn);
323
+ return interpolate(tpl.ar, { name: nameAr, comment: commentSuffix });
324
+ }
325
+ }
326
+ else if (withoutComment.trim() === baseEn) {
327
+ return interpolate(tpl.ar, { comment: commentSuffix });
328
+ }
329
+ }
330
+ }
331
+ const inProgressPrefix = WORKFLOW_TEMPLATES.request_approval_in_progress_from?.en.split('{{name}}')[0].trim();
332
+ if (inProgressPrefix && normalized.startsWith(inProgressPrefix)) {
333
+ const namePartEn = normalized.slice(inProgressPrefix.length).trim();
334
+ const nameAr = resolveArabicWorkflowActorName(actors, namePartEn);
335
+ return interpolate(WORKFLOW_TEMPLATES.request_approval_in_progress_from.ar, { name: nameAr });
336
+ }
337
+ const pendingPrefix = WORKFLOW_TEMPLATES.request_approval_pending_from?.en.split('{{name}}')[0].trim();
338
+ if (pendingPrefix && normalized.startsWith(pendingPrefix)) {
339
+ const namePartEn = normalized.slice(pendingPrefix.length).trim();
340
+ const nameAr = resolveArabicWorkflowActorName(actors, namePartEn);
341
+ return interpolate(WORKFLOW_TEMPLATES.request_approval_pending_from.ar, { name: nameAr });
342
+ }
343
+ return null;
344
+ }
345
+ function resolveChatMessageAr(message, actors) {
346
+ if (message == null || message.trim() === '')
347
+ return null;
348
+ const normalized = message.trim();
349
+ for (const tpl of Object.values(CHAT_TEMPLATES)) {
350
+ if (tpl.en === normalized)
351
+ return tpl.ar;
352
+ }
353
+ const submittedTpl = CHAT_TEMPLATES.cancellation_submitted_by;
354
+ if (submittedTpl) {
355
+ const prefix = submittedTpl.en.split('{{userName}}')[0];
356
+ if (normalized.startsWith(prefix)) {
357
+ const afterPrefix = normalized.slice(prefix.length);
358
+ const parenMatch = afterPrefix.match(/^(.+?) \((.+)\)$/);
359
+ if (parenMatch) {
360
+ const userEn = parenMatch[1].trim();
361
+ const employeeId = parenMatch[2].trim();
362
+ const userAr = actors?.userName?.trim()
363
+ ? resolveBilingualName(actors.userName, actors.userArabicName)
364
+ : resolveBilingualName(userEn, actors?.userArabicName);
365
+ return interpolate(submittedTpl.ar, { userName: userAr, employeeId });
366
+ }
367
+ }
368
+ }
369
+ for (const tpl of Object.values(CHAT_TEMPLATES)) {
370
+ if (!tpl.en.includes('{{roleName}}'))
371
+ continue;
372
+ const prefix = tpl.en.split('{{roleName}}')[0];
373
+ if (!normalized.startsWith(prefix))
374
+ continue;
375
+ const rest = normalized.slice(prefix.length);
376
+ const commentIdx = rest.lastIndexOf(' - ');
377
+ const roleNameEn = commentIdx >= 0 ? rest.slice(0, commentIdx) : rest;
378
+ const commentSuffix = commentIdx >= 0 ? rest.slice(commentIdx) : '';
379
+ const roleNameAr = resolveArabicChatRoleName(actors, roleNameEn.trim());
380
+ return interpolate(tpl.ar, { roleName: roleNameAr, comment: commentSuffix });
381
+ }
382
+ return null;
383
+ }
384
+ /** Generic workflow log enricher — use in all module repositories. */
385
+ function enrichWorkflowLog(log) {
386
+ const status = log.status != null ? String(log.status) : null;
387
+ const content = log.content != null ? String(log.content) : null;
388
+ const actors = extractBilingualActorsFromRecord(log);
389
+ return {
390
+ ...log,
391
+ content_ar: log.content_ar ?? resolveWorkflowContentAr(content, actors),
392
+ status_ar: log.status_ar ?? resolveWorkflowStatusAr(status),
393
+ };
394
+ }
395
+ /** Generic chat enricher — use in all module repositories. */
396
+ function enrichChatMessage(chat) {
397
+ const status = chat.status != null ? String(chat.status) : null;
398
+ const message = chat.message != null ? String(chat.message) : null;
399
+ const actors = extractBilingualActorsFromRecord(chat);
400
+ return {
401
+ ...chat,
402
+ message_ar: chat.message_ar ?? resolveChatMessageAr(message, actors),
403
+ status_ar: chat.status_ar ?? resolveChatStatusAr(status),
404
+ };
405
+ }
406
+ /** @deprecated Use enrichWorkflowLog */
407
+ exports.enrichCancellationWorkflowLog = enrichWorkflowLog;
408
+ /** @deprecated Use enrichChatMessage */
409
+ exports.enrichCancellationChatMessage = enrichChatMessage;
package/dist/index.d.ts CHANGED
@@ -415,4 +415,4 @@ export * from './models/SlaApprovalsViewModel';
415
415
  export * from './models/ServiceSlaApprovalModel';
416
416
  export * from './sla/sla-table-sync.service';
417
417
  export * from './sla/sla-approval-mirror';
418
- export * from './i18n/workflow-chat-i18n';
418
+ export * from './i18n/workflow-chat-message.builder';
package/dist/index.js CHANGED
@@ -604,4 +604,4 @@ __exportStar(require("./models/SlaApprovalsViewModel"), exports);
604
604
  __exportStar(require("./models/ServiceSlaApprovalModel"), exports);
605
605
  __exportStar(require("./sla/sla-table-sync.service"), exports);
606
606
  __exportStar(require("./sla/sla-approval-mirror"), exports);
607
- __exportStar(require("./i18n/workflow-chat-i18n"), exports);
607
+ __exportStar(require("./i18n/workflow-chat-message.builder"), exports);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@platform-modules/civil-aviation-authority",
3
- "version": "2.3.280",
3
+ "version": "2.3.282",
4
4
  "main": "dist/index.js",
5
5
  "types": "dist/index.d.ts",
6
6
  "scripts": {