@platform-modules/civil-aviation-authority 2.3.279 → 2.3.281

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,350 @@
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.resolveWorkflowContentAr = resolveWorkflowContentAr;
29
+ exports.resolveChatMessageAr = resolveChatMessageAr;
30
+ exports.enrichWorkflowLog = enrichWorkflowLog;
31
+ exports.enrichChatMessage = enrichChatMessage;
32
+ /**
33
+ * CAA standard bilingual workflow/chat message builder.
34
+ *
35
+ * All services MUST use these helpers (never hardcode message strings).
36
+ * Templates live in workflow-chat-i18n.json; dynamic values use parallel EN/AR params.
37
+ */
38
+ const workflow_chat_i18n_json_1 = __importDefault(require("./workflow-chat-i18n.json"));
39
+ const WORKFLOW_TEMPLATES = workflow_chat_i18n_json_1.default.workflowTemplates;
40
+ const CHAT_TEMPLATES = workflow_chat_i18n_json_1.default.chatTemplates;
41
+ const WORKFLOW_STATUS_LABELS = workflow_chat_i18n_json_1.default.workflowStatusLabels;
42
+ const CHAT_STATUS_LABELS = workflow_chat_i18n_json_1.default.chatStatusLabels;
43
+ function getWorkflowChatI18nCatalog() {
44
+ return workflow_chat_i18n_json_1.default;
45
+ }
46
+ function interpolate(template, params = {}) {
47
+ return template.replace(/\{\{(\w+)\}\}/g, (_, key) => params[key] ?? '');
48
+ }
49
+ /** Arabic DB column preferred; English fallback so AR keeps identical structure to EN. */
50
+ function resolveBilingualName(englishName, arabicName) {
51
+ const ar = arabicName?.trim();
52
+ if (ar)
53
+ return ar;
54
+ return englishName?.trim() || '';
55
+ }
56
+ function pickLocalizedName(englishName, arabicName, fallback = '') {
57
+ return resolveBilingualName(englishName, arabicName) || fallback;
58
+ }
59
+ /** @deprecated Use resolveBilingualName */
60
+ function pickArabicName(arabicName) {
61
+ return arabicName?.trim() || '';
62
+ }
63
+ function joinLabels(...parts) {
64
+ return parts.map((p) => p?.trim()).filter(Boolean).join(' - ');
65
+ }
66
+ /** Build parallel EN / AR actor label from role OR dept+section. */
67
+ function resolveActorDisplayNames(actors) {
68
+ if (actors.roleName?.trim()) {
69
+ const en = actors.roleName.trim();
70
+ return { en, ar: resolveBilingualName(en, actors.roleArabicName) };
71
+ }
72
+ const en = joinLabels(actors.deptName, actors.sectionName);
73
+ const ar = joinLabels(resolveBilingualName(actors.deptName, actors.deptArabicName), resolveBilingualName(actors.sectionName, actors.sectionArabicName));
74
+ return { en, ar };
75
+ }
76
+ /** @deprecated Use resolveActorDisplayNames */
77
+ function joinDeptSectionBilingualLabels(deptEn, deptAr, sectEn, sectAr) {
78
+ return resolveActorDisplayNames({
79
+ deptName: deptEn,
80
+ deptArabicName: deptAr,
81
+ sectionName: sectEn,
82
+ sectionArabicName: sectAr,
83
+ });
84
+ }
85
+ /** @deprecated Use resolveActorDisplayNames */
86
+ function joinDeptSectionArabicLabels(deptArabic, sectionArabic) {
87
+ return joinLabels(deptArabic, sectionArabic);
88
+ }
89
+ function formatWorkflowCommentSuffix(comment) {
90
+ const text = comment?.trim();
91
+ return text ? `: ${text}` : '';
92
+ }
93
+ function formatChatCommentSuffix(comment) {
94
+ const text = comment?.trim();
95
+ return text ? ` - ${text}` : '';
96
+ }
97
+ /** Core renderer — always pass explicit EN and AR param objects with the same keys. */
98
+ function renderSynchronizedWorkflowMessage(templateKey, enParams, arParams) {
99
+ const tpl = WORKFLOW_TEMPLATES[templateKey];
100
+ if (!tpl)
101
+ return { en: templateKey, ar: templateKey };
102
+ return {
103
+ en: interpolate(tpl.en, enParams),
104
+ ar: interpolate(tpl.ar, arParams),
105
+ };
106
+ }
107
+ function renderSynchronizedChatMessage(templateKey, enParams, arParams) {
108
+ const tpl = CHAT_TEMPLATES[templateKey];
109
+ if (!tpl)
110
+ return { en: templateKey, ar: templateKey };
111
+ return {
112
+ en: interpolate(tpl.en, enParams),
113
+ ar: interpolate(tpl.ar, arParams),
114
+ };
115
+ }
116
+ function buildBilingualFromTemplate(templateCatalog, key, params = {}, arParams) {
117
+ const tpl = templateCatalog[key];
118
+ if (!tpl)
119
+ return { en: key, ar: key };
120
+ const arabicParams = arParams ?? params;
121
+ return {
122
+ en: interpolate(tpl.en, params),
123
+ ar: interpolate(tpl.ar, arabicParams),
124
+ };
125
+ }
126
+ function workflowTemplate(key, params = {}, arParams) {
127
+ return buildBilingualFromTemplate(WORKFLOW_TEMPLATES, key, params, arParams);
128
+ }
129
+ function chatTemplate(key, params = {}, arParams) {
130
+ return buildBilingualFromTemplate(CHAT_TEMPLATES, key, params, arParams);
131
+ }
132
+ /**
133
+ * Standard entry point for workflow `content` + `content_ar`.
134
+ * Use for every workflow log insert/update across all CAA modules.
135
+ */
136
+ function buildSynchronizedWorkflowMessage(ctx) {
137
+ const commentWf = formatWorkflowCommentSuffix(ctx.comment);
138
+ const { en: actorEn, ar: actorAr } = resolveActorDisplayNames(ctx);
139
+ switch (ctx.action) {
140
+ case 'request_submitted':
141
+ return workflowTemplate('request_submitted');
142
+ case 'notification_sent_pending':
143
+ return workflowTemplate('notification_sent_pending');
144
+ case 'notification_sent_successfully':
145
+ return workflowTemplate('notification_sent_successfully');
146
+ case 'approval_in_progress':
147
+ return actorEn
148
+ ? renderSynchronizedWorkflowMessage('request_approval_in_progress_from', { name: actorEn }, { name: actorAr })
149
+ : workflowTemplate('request_approval_in_progress');
150
+ case 'approval_pending':
151
+ return actorEn
152
+ ? renderSynchronizedWorkflowMessage('request_approval_pending_from', { name: actorEn }, { name: actorAr })
153
+ : workflowTemplate('request_approval_pending');
154
+ case 'approved':
155
+ return actorEn
156
+ ? renderSynchronizedWorkflowMessage('request_approved_by', { name: actorEn, comment: commentWf }, { name: actorAr, comment: commentWf })
157
+ : renderSynchronizedWorkflowMessage('request_approved', { comment: commentWf }, { comment: commentWf });
158
+ case 'rejected':
159
+ return actorEn
160
+ ? renderSynchronizedWorkflowMessage('request_rejected_by', { name: actorEn, comment: commentWf }, { name: actorAr, comment: commentWf })
161
+ : renderSynchronizedWorkflowMessage('request_rejected', { comment: commentWf }, { comment: commentWf });
162
+ case 'returned_for_modification':
163
+ return actorEn
164
+ ? renderSynchronizedWorkflowMessage('request_returned_for_modification_by', { name: actorEn, comment: commentWf }, { name: actorAr, comment: commentWf })
165
+ : renderSynchronizedWorkflowMessage('request_returned_for_modification', { comment: commentWf }, { comment: commentWf });
166
+ case 'approval_pending_update':
167
+ return actorEn
168
+ ? renderSynchronizedWorkflowMessage('request_approval_pending_from', { name: actorEn, comment: commentWf }, { name: actorAr, comment: commentWf })
169
+ : renderSynchronizedWorkflowMessage('request_approval_pending', { comment: commentWf }, { comment: commentWf });
170
+ default:
171
+ return workflowTemplate('request_submitted');
172
+ }
173
+ }
174
+ /**
175
+ * Standard entry point for chat `message` + `message_ar`.
176
+ * Use for every chat insert/update across all CAA modules.
177
+ */
178
+ function buildSynchronizedChatMessage(ctx) {
179
+ const commentChat = formatChatCommentSuffix(ctx.comment);
180
+ switch (ctx.action) {
181
+ case 'cancellation_submitted': {
182
+ const userEn = ctx.userName?.trim() || 'Unknown User';
183
+ const userAr = resolveBilingualName(userEn, ctx.userArabicName);
184
+ const employeeId = String(ctx.employeeId ?? 'N/A');
185
+ return chatTemplate('cancellation_submitted_by', { userName: userEn, employeeId }, { userName: userAr, employeeId });
186
+ }
187
+ case 'request_received':
188
+ return chatTemplate('request_received');
189
+ case 'approved':
190
+ case 'rejected':
191
+ case 'returned_for_modification': {
192
+ const roleEn = ctx.roleName?.trim() || 'Unknown Role';
193
+ const roleAr = resolveBilingualName(roleEn, ctx.roleArabicName);
194
+ const key = ctx.action === 'approved'
195
+ ? 'request_approved_by_role'
196
+ : ctx.action === 'rejected'
197
+ ? 'request_rejected_by_role'
198
+ : 'request_returned_for_modification_by_role';
199
+ return renderSynchronizedChatMessage(key, { roleName: roleEn, comment: commentChat }, { roleName: roleAr, comment: commentChat });
200
+ }
201
+ default:
202
+ return chatTemplate('request_received');
203
+ }
204
+ }
205
+ // ─── Backward-compatible aliases used by Cancellation pilot ───────────────────
206
+ function buildApprovalWorkflowContent(params) {
207
+ const status = params.status;
208
+ let action;
209
+ if (status === 'Approved')
210
+ action = 'approved';
211
+ else if (status === 'Rejected')
212
+ action = 'rejected';
213
+ else if (status === 'Returned for Modification')
214
+ action = 'returned_for_modification';
215
+ else
216
+ action = 'approval_pending_update';
217
+ return buildSynchronizedWorkflowMessage({
218
+ action,
219
+ roleName: params.roleName,
220
+ roleArabicName: params.roleArabicName,
221
+ comment: params.comment,
222
+ });
223
+ }
224
+ function buildHumanApprovalWorkflowContent(params) {
225
+ return buildSynchronizedWorkflowMessage({
226
+ action: params.isFirst ? 'approval_in_progress' : 'approval_pending',
227
+ roleName: params.roleName,
228
+ roleArabicName: params.roleArabicName,
229
+ deptName: params.deptName,
230
+ deptArabicName: params.deptArabicName,
231
+ sectionName: params.sectionName,
232
+ sectionArabicName: params.sectionArabicName,
233
+ });
234
+ }
235
+ function buildApprovalChatMessage(params) {
236
+ let action = 'approved';
237
+ if (params.status === 'Rejected')
238
+ action = 'rejected';
239
+ else if (params.status === 'Returned for Modification')
240
+ action = 'returned_for_modification';
241
+ return buildSynchronizedChatMessage({
242
+ action,
243
+ roleName: params.roleName,
244
+ roleArabicName: params.roleArabicName,
245
+ comment: params.comment,
246
+ });
247
+ }
248
+ // ─── Status labels ───────────────────────────────────────────────────────────
249
+ function resolveWorkflowStatusAr(status) {
250
+ if (status == null || status === '')
251
+ return null;
252
+ return WORKFLOW_STATUS_LABELS[status] ?? status;
253
+ }
254
+ function resolveChatStatusAr(status) {
255
+ if (status == null || status === '')
256
+ return null;
257
+ return CHAT_STATUS_LABELS[status] ?? status;
258
+ }
259
+ // ─── Legacy row enrichment (read API) ────────────────────────────────────────
260
+ function resolveWorkflowContentAr(content) {
261
+ if (content == null || content.trim() === '')
262
+ return null;
263
+ const normalized = content.trim();
264
+ for (const tpl of Object.values(WORKFLOW_TEMPLATES)) {
265
+ if (tpl.en === normalized)
266
+ return tpl.ar;
267
+ }
268
+ const commentIdx = normalized.indexOf(': ');
269
+ if (commentIdx > 0) {
270
+ const baseEn = normalized.slice(0, commentIdx).trim();
271
+ const commentText = normalized.slice(commentIdx + 2).trim();
272
+ const commentSuffix = formatWorkflowCommentSuffix(commentText);
273
+ for (const tpl of Object.values(WORKFLOW_TEMPLATES)) {
274
+ if (!tpl.en.includes('{{comment}}'))
275
+ continue;
276
+ const withoutComment = tpl.en.replace('{{comment}}', '');
277
+ if (withoutComment.includes('{{name}}')) {
278
+ const staticPrefix = withoutComment.replace('{{name}}', '').trim();
279
+ if (baseEn.startsWith(staticPrefix)) {
280
+ const namePart = baseEn.slice(staticPrefix.length).trim();
281
+ return interpolate(tpl.ar, { name: namePart, comment: commentSuffix });
282
+ }
283
+ }
284
+ else if (withoutComment.trim() === baseEn) {
285
+ return interpolate(tpl.ar, { comment: commentSuffix });
286
+ }
287
+ }
288
+ }
289
+ const inProgressPrefix = WORKFLOW_TEMPLATES.request_approval_in_progress_from?.en.split('{{name}}')[0].trim();
290
+ if (inProgressPrefix && normalized.startsWith(inProgressPrefix)) {
291
+ const namePart = normalized.slice(inProgressPrefix.length).trim();
292
+ return interpolate(WORKFLOW_TEMPLATES.request_approval_in_progress_from.ar, { name: namePart });
293
+ }
294
+ const pendingPrefix = WORKFLOW_TEMPLATES.request_approval_pending_from?.en.split('{{name}}')[0].trim();
295
+ if (pendingPrefix && normalized.startsWith(pendingPrefix)) {
296
+ const namePart = normalized.slice(pendingPrefix.length).trim();
297
+ return interpolate(WORKFLOW_TEMPLATES.request_approval_pending_from.ar, { name: namePart });
298
+ }
299
+ return null;
300
+ }
301
+ function resolveChatMessageAr(message) {
302
+ if (message == null || message.trim() === '')
303
+ return null;
304
+ const normalized = message.trim();
305
+ for (const tpl of Object.values(CHAT_TEMPLATES)) {
306
+ if (tpl.en === normalized)
307
+ return tpl.ar;
308
+ }
309
+ for (const tpl of Object.values(CHAT_TEMPLATES)) {
310
+ if (!tpl.en.includes('{{roleName}}'))
311
+ continue;
312
+ const prefix = tpl.en.split('{{roleName}}')[0];
313
+ if (!normalized.startsWith(prefix))
314
+ continue;
315
+ const rest = normalized.slice(prefix.length);
316
+ const commentIdx = rest.lastIndexOf(' - ');
317
+ if (commentIdx >= 0) {
318
+ return interpolate(tpl.ar, {
319
+ roleName: rest.slice(0, commentIdx),
320
+ comment: rest.slice(commentIdx),
321
+ });
322
+ }
323
+ return interpolate(tpl.ar, { roleName: rest, comment: '' });
324
+ }
325
+ return null;
326
+ }
327
+ /** Generic workflow log enricher — use in all module repositories. */
328
+ function enrichWorkflowLog(log) {
329
+ const status = log.status != null ? String(log.status) : null;
330
+ const content = log.content != null ? String(log.content) : null;
331
+ return {
332
+ ...log,
333
+ content_ar: log.content_ar ?? resolveWorkflowContentAr(content),
334
+ status_ar: log.status_ar ?? resolveWorkflowStatusAr(status),
335
+ };
336
+ }
337
+ /** Generic chat enricher — use in all module repositories. */
338
+ function enrichChatMessage(chat) {
339
+ const status = chat.status != null ? String(chat.status) : null;
340
+ const message = chat.message != null ? String(chat.message) : null;
341
+ return {
342
+ ...chat,
343
+ message_ar: chat.message_ar ?? resolveChatMessageAr(message),
344
+ status_ar: chat.status_ar ?? resolveChatStatusAr(status),
345
+ };
346
+ }
347
+ /** @deprecated Use enrichWorkflowLog */
348
+ exports.enrichCancellationWorkflowLog = enrichWorkflowLog;
349
+ /** @deprecated Use enrichChatMessage */
350
+ 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.279",
3
+ "version": "2.3.281",
4
4
  "main": "dist/index.js",
5
5
  "types": "dist/index.d.ts",
6
6
  "scripts": {
@@ -58,6 +58,10 @@
58
58
  "en": "Cancellation request submitted by {{userName}} ({{employeeId}})",
59
59
  "ar": "تم تقديم طلب الإلغاء بواسطة {{userName}} ({{employeeId}})"
60
60
  },
61
+ "cancellation_submitted": {
62
+ "en": "Cancellation request submitted",
63
+ "ar": "تم تقديم طلب الإلغاء"
64
+ },
61
65
  "request_received": {
62
66
  "en": "Request Received",
63
67
  "ar": "تم استلام الطلب"
@@ -73,6 +77,18 @@
73
77
  "request_returned_for_modification_by_role": {
74
78
  "en": "Request Returned for Modification by: {{roleName}}{{comment}}",
75
79
  "ar": "تم إرجاع الطلب للتعديل من قبل: {{roleName}}{{comment}}"
80
+ },
81
+ "request_approved": {
82
+ "en": "Request Approved{{comment}}",
83
+ "ar": "تمت الموافقة على الطلب{{comment}}"
84
+ },
85
+ "request_rejected": {
86
+ "en": "Request Rejected{{comment}}",
87
+ "ar": "تم رفض الطلب{{comment}}"
88
+ },
89
+ "request_returned_for_modification": {
90
+ "en": "Request Returned for Modification{{comment}}",
91
+ "ar": "تم إرجاع الطلب للتعديل{{comment}}"
76
92
  }
77
93
  },
78
94
  "workflowStatusLabels": {