@platform-modules/civil-aviation-authority 2.3.296 → 2.3.298
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/dist/i18n/workflow-chat-i18n.json +68 -0
- package/dist/i18n/workflow-chat-message.builder.d.ts +41 -0
- package/dist/i18n/workflow-chat-message.builder.js +284 -7
- package/package.json +1 -1
- package/src/i18n/workflow-chat-i18n.json +68 -0
- package/src/i18n/workflow-chat-message.builder.ts +397 -8
|
@@ -131,6 +131,70 @@
|
|
|
131
131
|
"it_helpdesk_wf_routing_resolved": {
|
|
132
132
|
"en": "Workflow routing completed - request resolved at L3",
|
|
133
133
|
"ar": "تم استكمال مسار سير العمل - تم حل الطلب في المستوى الثالث (L3)"
|
|
134
|
+
},
|
|
135
|
+
"it_helpdesk_wf_routing_l3_reassign": {
|
|
136
|
+
"en": "Workflow routed to L3 assignment path - request reassigned by {{userName}}{{comment}}",
|
|
137
|
+
"ar": "تم توجيه سير العمل إلى مسار تعيين المستوى الثالث (L3) - تمت إعادة تعيين الطلب بواسطة {{userName}}{{comment}}"
|
|
138
|
+
},
|
|
139
|
+
"it_helpdesk_wf_routing_direct_approval": {
|
|
140
|
+
"en": "Workflow routed to direct resolution path - request approved by {{roleName}}{{comment}}",
|
|
141
|
+
"ar": "تم توجيه سير العمل إلى مسار الحل المباشر - تمت الموافقة على الطلب من قبل {{roleName}}{{comment}}"
|
|
142
|
+
},
|
|
143
|
+
"it_helpdesk_wf_routing_decision": {
|
|
144
|
+
"en": "Workflow decision made - {{status}} by {{roleName}}{{comment}}",
|
|
145
|
+
"ar": "تم اتخاذ قرار سير العمل - {{statusAr}} الطلب من قبل {{roleName}}{{comment}}"
|
|
146
|
+
},
|
|
147
|
+
"it_helpdesk_wf_l3_assignment_pending": {
|
|
148
|
+
"en": "L3 Technical Support assignment pending - request reassigned by {{roleName}}{{comment}}",
|
|
149
|
+
"ar": "تعيين دعم المستوى الثالث (L3) قيد الانتظار - تمت إعادة تعيين الطلب من قبل {{roleName}}{{comment}}"
|
|
150
|
+
},
|
|
151
|
+
"it_helpdesk_wf_l3_role_approved": {
|
|
152
|
+
"en": "{{roleName}} approved the request{{comment}}",
|
|
153
|
+
"ar": "تمت الموافقة على الطلب من قبل {{roleName}}{{commentAr}}"
|
|
154
|
+
},
|
|
155
|
+
"it_helpdesk_wf_l3_role_rejected": {
|
|
156
|
+
"en": "{{roleName}} rejected the request{{comment}}",
|
|
157
|
+
"ar": "تم رفض الطلب من قبل {{roleName}}{{commentAr}}"
|
|
158
|
+
},
|
|
159
|
+
"it_helpdesk_wf_role_outcome_by_user_rejected": {
|
|
160
|
+
"en": "{{roleName}} rejected the request by {{userName}}{{comment}}",
|
|
161
|
+
"ar": "تم رفض الطلب من قبل {{roleName}} بواسطة {{userName}}{{comment}}"
|
|
162
|
+
},
|
|
163
|
+
"it_helpdesk_wf_role_outcome_by_user_closed": {
|
|
164
|
+
"en": "{{roleName}} closed the request by {{userName}}{{comment}}",
|
|
165
|
+
"ar": "تم إغلاق الطلب من قبل {{roleName}} بواسطة {{userName}}{{comment}}"
|
|
166
|
+
},
|
|
167
|
+
"it_helpdesk_wf_routing_technician_rejected": {
|
|
168
|
+
"en": "Workflow routing completed - request rejected at technician level{{comment}}",
|
|
169
|
+
"ar": "تم استكمال مسار سير العمل - تم رفض الطلب على مستوى الفني{{comment}}"
|
|
170
|
+
},
|
|
171
|
+
"it_helpdesk_wf_hos_not_required_rejected": {
|
|
172
|
+
"en": "HOS notification not required, request rejected by {{userName}}{{comment}}",
|
|
173
|
+
"ar": "إشعار رئيس القسم غير مطلوب، تم رفض الطلب بواسطة {{userName}}{{comment}}"
|
|
174
|
+
},
|
|
175
|
+
"it_helpdesk_wf_hos_not_required_closed": {
|
|
176
|
+
"en": "HOS notification not required, request closed by {{userName}}{{comment}}",
|
|
177
|
+
"ar": "إشعار رئيس القسم غير مطلوب، تم إغلاق الطلب بواسطة {{userName}}{{comment}}"
|
|
178
|
+
},
|
|
179
|
+
"it_helpdesk_wf_l3_not_required_rejected": {
|
|
180
|
+
"en": "L3 assignment not required, request rejected by {{userName}}{{comment}}",
|
|
181
|
+
"ar": "تعيين المستوى الثالث (L3) غير مطلوب، تم رفض الطلب بواسطة {{userName}}{{comment}}"
|
|
182
|
+
},
|
|
183
|
+
"it_helpdesk_wf_l3_not_required_closed": {
|
|
184
|
+
"en": "L3 assignment not required, request closed by {{userName}}{{comment}}",
|
|
185
|
+
"ar": "تعيين المستوى الثالث (L3) غير مطلوب، تم إغلاق الطلب بواسطة {{userName}}{{comment}}"
|
|
186
|
+
},
|
|
187
|
+
"request_assigned": {
|
|
188
|
+
"en": "Request Assigned",
|
|
189
|
+
"ar": "تم تعيين الطلب"
|
|
190
|
+
},
|
|
191
|
+
"request_pending_from": {
|
|
192
|
+
"en": "Request Pending from {{name}}",
|
|
193
|
+
"ar": "الطلب قيد الانتظار من {{name}}"
|
|
194
|
+
},
|
|
195
|
+
"request_pending": {
|
|
196
|
+
"en": "Request Pending",
|
|
197
|
+
"ar": "الطلب قيد الانتظار"
|
|
134
198
|
}
|
|
135
199
|
},
|
|
136
200
|
"chatTemplates": {
|
|
@@ -262,6 +326,10 @@
|
|
|
262
326
|
"Pending": "قيد الانتظار",
|
|
263
327
|
"Not Yet Started": "لم يبدأ بعد"
|
|
264
328
|
},
|
|
329
|
+
"roleLabels": {
|
|
330
|
+
"L3 Technical Support": "دعم المستوى الثالث (L3) التقني",
|
|
331
|
+
"IT Technician": "فني تكنولوجيا المعلومات"
|
|
332
|
+
},
|
|
265
333
|
"chatStatusLabels": {
|
|
266
334
|
"Submitted": "تم التقديم",
|
|
267
335
|
"Received": "تم الاستلام",
|
|
@@ -264,6 +264,47 @@ export type ItHelpdeskMuscatWorkflowParams = {
|
|
|
264
264
|
comment?: string | null;
|
|
265
265
|
} | {
|
|
266
266
|
variant: 'routing_resolved';
|
|
267
|
+
} | {
|
|
268
|
+
variant: 'routing_l3_reassign';
|
|
269
|
+
userName: string;
|
|
270
|
+
userArabicName?: string | null;
|
|
271
|
+
comment?: string | null;
|
|
272
|
+
} | {
|
|
273
|
+
variant: 'routing_direct_approval';
|
|
274
|
+
roleName: string;
|
|
275
|
+
roleArabicName?: string | null;
|
|
276
|
+
comment?: string | null;
|
|
277
|
+
} | {
|
|
278
|
+
variant: 'routing_decision';
|
|
279
|
+
status: string;
|
|
280
|
+
roleName: string;
|
|
281
|
+
roleArabicName?: string | null;
|
|
282
|
+
comment?: string | null;
|
|
283
|
+
} | {
|
|
284
|
+
variant: 'l3_assignment_pending';
|
|
285
|
+
roleName: string;
|
|
286
|
+
roleArabicName?: string | null;
|
|
287
|
+
comment?: string | null;
|
|
288
|
+
} | {
|
|
289
|
+
variant: 'l3_role_approved' | 'l3_role_rejected';
|
|
290
|
+
roleName: string;
|
|
291
|
+
roleArabicName?: string | null;
|
|
292
|
+
comment?: string | null;
|
|
293
|
+
} | {
|
|
294
|
+
variant: 'role_outcome_by_user_rejected' | 'role_outcome_by_user_closed';
|
|
295
|
+
roleName: string;
|
|
296
|
+
roleArabicName?: string | null;
|
|
297
|
+
userName: string;
|
|
298
|
+
userArabicName?: string | null;
|
|
299
|
+
comment?: string | null;
|
|
300
|
+
} | {
|
|
301
|
+
variant: 'routing_technician_rejected';
|
|
302
|
+
comment?: string | null;
|
|
303
|
+
} | {
|
|
304
|
+
variant: 'hos_not_required_rejected' | 'hos_not_required_closed' | 'l3_not_required_rejected' | 'l3_not_required_closed';
|
|
305
|
+
userName: string;
|
|
306
|
+
userArabicName?: string | null;
|
|
307
|
+
comment?: string | null;
|
|
267
308
|
};
|
|
268
309
|
export declare function buildItHelpdeskMuscatWorkflowLog(params: ItHelpdeskMuscatWorkflowParams): BilingualText;
|
|
269
310
|
export type LogisticsActualReturnParams = {
|
|
@@ -67,6 +67,7 @@ const CHAT_TEMPLATES = workflow_chat_i18n_json_1.default.chatTemplates;
|
|
|
67
67
|
const NOTIFICATION_TEMPLATES = workflow_chat_i18n_json_1.default.notificationTemplates ?? {};
|
|
68
68
|
const WORKFLOW_STATUS_LABELS = workflow_chat_i18n_json_1.default.workflowStatusLabels;
|
|
69
69
|
const CHAT_STATUS_LABELS = workflow_chat_i18n_json_1.default.chatStatusLabels;
|
|
70
|
+
const ROLE_LABELS = workflow_chat_i18n_json_1.default.roleLabels ?? {};
|
|
70
71
|
function getWorkflowChatI18nCatalog() {
|
|
71
72
|
return workflow_chat_i18n_json_1.default;
|
|
72
73
|
}
|
|
@@ -325,6 +326,19 @@ function buildRequestApprovedAssignedWorkflowFields(params) {
|
|
|
325
326
|
}
|
|
326
327
|
/** Standard workflow log UPDATE fields for all CAA module repositories. */
|
|
327
328
|
function buildWorkflowLogUpdateFields(params) {
|
|
329
|
+
if (params.approvalStatus === 'Closed') {
|
|
330
|
+
const closed = buildClosedWorkflowMessage({
|
|
331
|
+
roleName: params.roleName,
|
|
332
|
+
roleArabicName: params.roleArabicName,
|
|
333
|
+
comment: params.comment,
|
|
334
|
+
});
|
|
335
|
+
return {
|
|
336
|
+
content: closed.en,
|
|
337
|
+
content_ar: closed.ar,
|
|
338
|
+
status: params.workflowStatus,
|
|
339
|
+
status_ar: resolveWorkflowStatusAr(params.workflowStatus),
|
|
340
|
+
};
|
|
341
|
+
}
|
|
328
342
|
const isApprovedLike = params.approvalStatus === 'Approved' || params.approvalStatus === 'Assigned';
|
|
329
343
|
if (isApprovedLike) {
|
|
330
344
|
const assignment = tryParseRequestAssignedComment(params.comment);
|
|
@@ -457,6 +471,23 @@ function formatColonCommentSuffix(comment) {
|
|
|
457
471
|
const text = comment?.trim();
|
|
458
472
|
return text ? `: ${text}` : '';
|
|
459
473
|
}
|
|
474
|
+
function formatBilingualColonCommentSuffix(comment) {
|
|
475
|
+
const text = comment?.trim();
|
|
476
|
+
if (!text)
|
|
477
|
+
return { en: '', ar: '' };
|
|
478
|
+
const statusKey = text.charAt(0).toUpperCase() + text.slice(1).toLowerCase();
|
|
479
|
+
const arText = resolveChatStatusAr(statusKey) ?? text;
|
|
480
|
+
return { en: `: ${text}`, ar: `: ${arText}` };
|
|
481
|
+
}
|
|
482
|
+
function splitWorkflowColonComment(content) {
|
|
483
|
+
const idx = content.indexOf(': ');
|
|
484
|
+
if (idx <= 0)
|
|
485
|
+
return { base: content.trim() };
|
|
486
|
+
return {
|
|
487
|
+
base: content.slice(0, idx).trim(),
|
|
488
|
+
comment: content.slice(idx + 2).trim() || undefined,
|
|
489
|
+
};
|
|
490
|
+
}
|
|
460
491
|
function formatReassignCommentSuffix(comment) {
|
|
461
492
|
const text = comment?.trim();
|
|
462
493
|
return text ? `:${text}` : '';
|
|
@@ -724,6 +755,65 @@ function buildItHelpdeskMuscatWorkflowLog(params) {
|
|
|
724
755
|
return renderSynchronizedWorkflowMessage('it_helpdesk_wf_routing_rejected', { comment }, { comment });
|
|
725
756
|
case 'routing_resolved':
|
|
726
757
|
return workflowTemplate('it_helpdesk_wf_routing_resolved');
|
|
758
|
+
case 'routing_l3_reassign': {
|
|
759
|
+
const userEn = params.userName.trim();
|
|
760
|
+
const userAr = resolveBilingualName(userEn, params.userArabicName);
|
|
761
|
+
return renderSynchronizedWorkflowMessage('it_helpdesk_wf_routing_l3_reassign', { userName: userEn, comment }, { userName: userAr, comment });
|
|
762
|
+
}
|
|
763
|
+
case 'routing_direct_approval': {
|
|
764
|
+
const roleEn = params.roleName.trim();
|
|
765
|
+
const roleAr = resolveBilingualName(roleEn, params.roleArabicName);
|
|
766
|
+
return renderSynchronizedWorkflowMessage('it_helpdesk_wf_routing_direct_approval', { roleName: roleEn, comment }, { roleName: roleAr, comment });
|
|
767
|
+
}
|
|
768
|
+
case 'routing_decision': {
|
|
769
|
+
const roleEn = params.roleName.trim();
|
|
770
|
+
const roleAr = resolveBilingualName(roleEn, params.roleArabicName);
|
|
771
|
+
const statusEn = params.status.toLowerCase();
|
|
772
|
+
const statusAr = resolveItHelpdeskGenericStatusAr(params.status);
|
|
773
|
+
return renderSynchronizedWorkflowMessage('it_helpdesk_wf_routing_decision', { status: statusEn, statusAr, roleName: roleEn, comment }, { status: statusEn, statusAr, roleName: roleAr, comment });
|
|
774
|
+
}
|
|
775
|
+
case 'l3_assignment_pending': {
|
|
776
|
+
const roleEn = params.roleName.trim();
|
|
777
|
+
const roleAr = resolveBilingualName(roleEn, params.roleArabicName);
|
|
778
|
+
return renderSynchronizedWorkflowMessage('it_helpdesk_wf_l3_assignment_pending', { roleName: roleEn, comment }, { roleName: roleAr, comment });
|
|
779
|
+
}
|
|
780
|
+
case 'l3_role_approved':
|
|
781
|
+
case 'l3_role_rejected': {
|
|
782
|
+
const roleEn = params.roleName.trim();
|
|
783
|
+
const roleAr = resolveBilingualName(roleEn, params.roleArabicName ?? ROLE_LABELS[roleEn] ?? null);
|
|
784
|
+
const biComment = formatBilingualColonCommentSuffix(params.comment);
|
|
785
|
+
const key = params.variant === 'l3_role_approved'
|
|
786
|
+
? 'it_helpdesk_wf_l3_role_approved'
|
|
787
|
+
: 'it_helpdesk_wf_l3_role_rejected';
|
|
788
|
+
return renderSynchronizedWorkflowMessage(key, { roleName: roleEn, comment: biComment.en }, { roleName: roleAr, commentAr: biComment.ar });
|
|
789
|
+
}
|
|
790
|
+
case 'role_outcome_by_user_rejected':
|
|
791
|
+
case 'role_outcome_by_user_closed': {
|
|
792
|
+
const roleEn = params.roleName.trim();
|
|
793
|
+
const roleAr = resolveBilingualName(roleEn, params.roleArabicName);
|
|
794
|
+
const userEn = params.userName.trim();
|
|
795
|
+
const userAr = resolveBilingualName(userEn, params.userArabicName);
|
|
796
|
+
const key = params.variant === 'role_outcome_by_user_rejected'
|
|
797
|
+
? 'it_helpdesk_wf_role_outcome_by_user_rejected'
|
|
798
|
+
: 'it_helpdesk_wf_role_outcome_by_user_closed';
|
|
799
|
+
return renderSynchronizedWorkflowMessage(key, { roleName: roleEn, userName: userEn, comment }, { roleName: roleAr, userName: userAr, comment });
|
|
800
|
+
}
|
|
801
|
+
case 'routing_technician_rejected':
|
|
802
|
+
return renderSynchronizedWorkflowMessage('it_helpdesk_wf_routing_technician_rejected', { comment }, { comment });
|
|
803
|
+
case 'hos_not_required_rejected':
|
|
804
|
+
case 'hos_not_required_closed':
|
|
805
|
+
case 'l3_not_required_rejected':
|
|
806
|
+
case 'l3_not_required_closed': {
|
|
807
|
+
const userEn = params.userName.trim();
|
|
808
|
+
const userAr = resolveBilingualName(userEn, params.userArabicName);
|
|
809
|
+
const keyMap = {
|
|
810
|
+
hos_not_required_rejected: 'it_helpdesk_wf_hos_not_required_rejected',
|
|
811
|
+
hos_not_required_closed: 'it_helpdesk_wf_hos_not_required_closed',
|
|
812
|
+
l3_not_required_rejected: 'it_helpdesk_wf_l3_not_required_rejected',
|
|
813
|
+
l3_not_required_closed: 'it_helpdesk_wf_l3_not_required_closed',
|
|
814
|
+
};
|
|
815
|
+
return renderSynchronizedWorkflowMessage(keyMap[params.variant], { userName: userEn, comment }, { userName: userAr, comment });
|
|
816
|
+
}
|
|
727
817
|
default:
|
|
728
818
|
return workflowTemplate('request_submitted');
|
|
729
819
|
}
|
|
@@ -815,19 +905,23 @@ function resolveArabicWorkflowActorName(actors, parsedEnglishName) {
|
|
|
815
905
|
/** Arabic role/user label for chat templates. */
|
|
816
906
|
function resolveArabicChatRoleName(actors, parsedEnglishRole) {
|
|
817
907
|
const parsed = parsedEnglishRole?.trim();
|
|
818
|
-
if (
|
|
819
|
-
|
|
820
|
-
|
|
821
|
-
return resolveBilingualName(
|
|
908
|
+
if (parsed) {
|
|
909
|
+
if (actors?.roleName?.trim() &&
|
|
910
|
+
parsed.toLowerCase() === actors.roleName.trim().toLowerCase()) {
|
|
911
|
+
return resolveBilingualName(parsed, actors.roleArabicName);
|
|
822
912
|
}
|
|
913
|
+
const catalogAr = ROLE_LABELS[parsed];
|
|
914
|
+
if (catalogAr)
|
|
915
|
+
return catalogAr;
|
|
916
|
+
return parsed;
|
|
823
917
|
}
|
|
824
|
-
if (actors?.
|
|
825
|
-
return resolveBilingualName(
|
|
918
|
+
if (actors?.roleName?.trim()) {
|
|
919
|
+
return resolveBilingualName(actors.roleName, actors.roleArabicName);
|
|
826
920
|
}
|
|
827
921
|
if (actors?.userName?.trim()) {
|
|
828
922
|
return resolveBilingualName(actors.userName, actors.userArabicName);
|
|
829
923
|
}
|
|
830
|
-
return
|
|
924
|
+
return '';
|
|
831
925
|
}
|
|
832
926
|
function escapeRegexLiteral(value) {
|
|
833
927
|
return value.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
|
|
@@ -908,6 +1002,14 @@ function buildArabicWorkflowTemplateParams(params, actors) {
|
|
|
908
1002
|
const normalizedStatus = params.status.charAt(0).toUpperCase() + params.status.slice(1).toLowerCase();
|
|
909
1003
|
arParams.statusAr = resolveItHelpdeskGenericStatusAr(normalizedStatus);
|
|
910
1004
|
}
|
|
1005
|
+
if (params.userName !== undefined) {
|
|
1006
|
+
arParams.userName = actors?.userName?.trim()
|
|
1007
|
+
? resolveBilingualName(actors.userName, actors.userArabicName)
|
|
1008
|
+
: resolveBilingualName(params.userName.trim(), actors?.userArabicName);
|
|
1009
|
+
}
|
|
1010
|
+
if (params.commentAr !== undefined) {
|
|
1011
|
+
arParams.commentAr = params.commentAr;
|
|
1012
|
+
}
|
|
911
1013
|
return arParams;
|
|
912
1014
|
}
|
|
913
1015
|
function countTemplatePlaceholders(templateEn) {
|
|
@@ -916,6 +1018,128 @@ function countTemplatePlaceholders(templateEn) {
|
|
|
916
1018
|
function listWorkflowTemplatesBySpecificity() {
|
|
917
1019
|
return Object.entries(WORKFLOW_TEMPLATES).sort(([, a], [, b]) => countTemplatePlaceholders(b.en) - countTemplatePlaceholders(a.en));
|
|
918
1020
|
}
|
|
1021
|
+
/** Parse legacy IT Helpdesk Muscat EN workflow strings before generic template matching. */
|
|
1022
|
+
function tryResolveItHelpdeskMuscatLegacyWorkflowAr(content, actors) {
|
|
1023
|
+
const { base, comment } = splitWorkflowColonComment(content);
|
|
1024
|
+
let m = base.match(/^Workflow routed to L3 assignment path - request reassigned by (.+)$/i);
|
|
1025
|
+
if (m) {
|
|
1026
|
+
return buildItHelpdeskMuscatWorkflowLog({
|
|
1027
|
+
variant: 'routing_l3_reassign',
|
|
1028
|
+
userName: m[1].trim(),
|
|
1029
|
+
userArabicName: actors?.userArabicName,
|
|
1030
|
+
comment,
|
|
1031
|
+
}).ar;
|
|
1032
|
+
}
|
|
1033
|
+
m = base.match(/^Workflow routed to direct resolution path - request approved by (.+)$/i);
|
|
1034
|
+
if (m) {
|
|
1035
|
+
return buildItHelpdeskMuscatWorkflowLog({
|
|
1036
|
+
variant: 'routing_direct_approval',
|
|
1037
|
+
roleName: m[1].trim(),
|
|
1038
|
+
roleArabicName: actors?.roleArabicName,
|
|
1039
|
+
comment,
|
|
1040
|
+
}).ar;
|
|
1041
|
+
}
|
|
1042
|
+
m = base.match(/^Workflow decision made - (\w+) by (.+)$/i);
|
|
1043
|
+
if (m) {
|
|
1044
|
+
return buildItHelpdeskMuscatWorkflowLog({
|
|
1045
|
+
variant: 'routing_decision',
|
|
1046
|
+
status: m[1],
|
|
1047
|
+
roleName: m[2].trim(),
|
|
1048
|
+
roleArabicName: actors?.roleArabicName,
|
|
1049
|
+
comment,
|
|
1050
|
+
}).ar;
|
|
1051
|
+
}
|
|
1052
|
+
m = base.match(/^L3 Technical Support assignment pending - request reassigned by (.+)$/i);
|
|
1053
|
+
if (m) {
|
|
1054
|
+
return buildItHelpdeskMuscatWorkflowLog({
|
|
1055
|
+
variant: 'l3_assignment_pending',
|
|
1056
|
+
roleName: m[1].trim(),
|
|
1057
|
+
roleArabicName: actors?.roleArabicName,
|
|
1058
|
+
comment,
|
|
1059
|
+
}).ar;
|
|
1060
|
+
}
|
|
1061
|
+
m = base.match(/^L3 Technical Support approved the request$/i);
|
|
1062
|
+
if (m) {
|
|
1063
|
+
return buildItHelpdeskMuscatWorkflowLog({
|
|
1064
|
+
variant: 'l3_role_approved',
|
|
1065
|
+
roleName: 'L3 Technical Support',
|
|
1066
|
+
comment,
|
|
1067
|
+
}).ar;
|
|
1068
|
+
}
|
|
1069
|
+
m = base.match(/^L3 Technical Support rejected the request$/i);
|
|
1070
|
+
if (m) {
|
|
1071
|
+
return buildItHelpdeskMuscatWorkflowLog({
|
|
1072
|
+
variant: 'l3_role_rejected',
|
|
1073
|
+
roleName: 'L3 Technical Support',
|
|
1074
|
+
comment,
|
|
1075
|
+
}).ar;
|
|
1076
|
+
}
|
|
1077
|
+
m = base.match(/^(.+?) rejected the request by (.+)$/i);
|
|
1078
|
+
if (m && !m[1].toLowerCase().includes('workflow')) {
|
|
1079
|
+
return buildItHelpdeskMuscatWorkflowLog({
|
|
1080
|
+
variant: 'role_outcome_by_user_rejected',
|
|
1081
|
+
roleName: m[1].trim(),
|
|
1082
|
+
roleArabicName: actors?.roleArabicName,
|
|
1083
|
+
userName: m[2].trim(),
|
|
1084
|
+
userArabicName: actors?.userArabicName,
|
|
1085
|
+
comment,
|
|
1086
|
+
}).ar;
|
|
1087
|
+
}
|
|
1088
|
+
m = base.match(/^(.+?) closed the request by (.+)$/i);
|
|
1089
|
+
if (m) {
|
|
1090
|
+
return buildItHelpdeskMuscatWorkflowLog({
|
|
1091
|
+
variant: 'role_outcome_by_user_closed',
|
|
1092
|
+
roleName: m[1].trim(),
|
|
1093
|
+
roleArabicName: actors?.roleArabicName,
|
|
1094
|
+
userName: m[2].trim(),
|
|
1095
|
+
userArabicName: actors?.userArabicName,
|
|
1096
|
+
comment,
|
|
1097
|
+
}).ar;
|
|
1098
|
+
}
|
|
1099
|
+
if (/^Workflow routing completed - request rejected at technician level$/i.test(base)) {
|
|
1100
|
+
return buildItHelpdeskMuscatWorkflowLog({
|
|
1101
|
+
variant: 'routing_technician_rejected',
|
|
1102
|
+
comment,
|
|
1103
|
+
}).ar;
|
|
1104
|
+
}
|
|
1105
|
+
m = base.match(/^HOS notification not required, request rejected by (.+)$/i);
|
|
1106
|
+
if (m) {
|
|
1107
|
+
return buildItHelpdeskMuscatWorkflowLog({
|
|
1108
|
+
variant: 'hos_not_required_rejected',
|
|
1109
|
+
userName: m[1].trim(),
|
|
1110
|
+
userArabicName: actors?.userArabicName,
|
|
1111
|
+
comment,
|
|
1112
|
+
}).ar;
|
|
1113
|
+
}
|
|
1114
|
+
m = base.match(/^HOS notification not required, request closed by (.+)$/i);
|
|
1115
|
+
if (m) {
|
|
1116
|
+
return buildItHelpdeskMuscatWorkflowLog({
|
|
1117
|
+
variant: 'hos_not_required_closed',
|
|
1118
|
+
userName: m[1].trim(),
|
|
1119
|
+
userArabicName: actors?.userArabicName,
|
|
1120
|
+
comment,
|
|
1121
|
+
}).ar;
|
|
1122
|
+
}
|
|
1123
|
+
m = base.match(/^L3 assignment not required, request rejected by (.+)$/i);
|
|
1124
|
+
if (m) {
|
|
1125
|
+
return buildItHelpdeskMuscatWorkflowLog({
|
|
1126
|
+
variant: 'l3_not_required_rejected',
|
|
1127
|
+
userName: m[1].trim(),
|
|
1128
|
+
userArabicName: actors?.userArabicName,
|
|
1129
|
+
comment,
|
|
1130
|
+
}).ar;
|
|
1131
|
+
}
|
|
1132
|
+
m = base.match(/^L3 assignment not required, request closed by (.+)$/i);
|
|
1133
|
+
if (m) {
|
|
1134
|
+
return buildItHelpdeskMuscatWorkflowLog({
|
|
1135
|
+
variant: 'l3_not_required_closed',
|
|
1136
|
+
userName: m[1].trim(),
|
|
1137
|
+
userArabicName: actors?.userArabicName,
|
|
1138
|
+
comment,
|
|
1139
|
+
}).ar;
|
|
1140
|
+
}
|
|
1141
|
+
return null;
|
|
1142
|
+
}
|
|
919
1143
|
function resolveWorkflowContentAr(content, actors) {
|
|
920
1144
|
if (content == null || content.trim() === '')
|
|
921
1145
|
return null;
|
|
@@ -924,6 +1148,9 @@ function resolveWorkflowContentAr(content, actors) {
|
|
|
924
1148
|
if (embeddedAssignment) {
|
|
925
1149
|
return buildAssignmentWorkflowFieldsFromActors(embeddedAssignment, actors).ar;
|
|
926
1150
|
}
|
|
1151
|
+
const itHelpdeskLegacyAr = tryResolveItHelpdeskMuscatLegacyWorkflowAr(normalized, actors);
|
|
1152
|
+
if (itHelpdeskLegacyAr)
|
|
1153
|
+
return itHelpdeskLegacyAr;
|
|
927
1154
|
for (const tpl of Object.values(WORKFLOW_TEMPLATES)) {
|
|
928
1155
|
if (tpl.en === normalized || tpl.en.toLowerCase() === normalized.toLowerCase())
|
|
929
1156
|
return tpl.ar;
|
|
@@ -992,6 +1219,25 @@ function resolveWorkflowContentAr(content, actors) {
|
|
|
992
1219
|
const nameAr = resolveArabicWorkflowActorName(actors, namePartEn);
|
|
993
1220
|
return interpolate(WORKFLOW_TEMPLATES.request_approval_pending_from.ar, { name: nameAr });
|
|
994
1221
|
}
|
|
1222
|
+
// Assign Tasks to Employee workflow (legacy EN strings)
|
|
1223
|
+
if (normalized === 'Request Assigned') {
|
|
1224
|
+
return WORKFLOW_TEMPLATES.request_assigned?.ar ?? null;
|
|
1225
|
+
}
|
|
1226
|
+
if (normalized === 'Request Pending') {
|
|
1227
|
+
return WORKFLOW_TEMPLATES.request_pending?.ar ?? null;
|
|
1228
|
+
}
|
|
1229
|
+
const assignTasksPendingPrefix = WORKFLOW_TEMPLATES.request_pending_from?.en.split('{{name}}')[0].trim();
|
|
1230
|
+
if (assignTasksPendingPrefix && normalized.startsWith(assignTasksPendingPrefix)) {
|
|
1231
|
+
const namePartEn = normalized.slice(assignTasksPendingPrefix.length).trim();
|
|
1232
|
+
const nameAr = resolveArabicWorkflowActorName(actors, namePartEn);
|
|
1233
|
+
return interpolate(WORKFLOW_TEMPLATES.request_pending_from.ar, { name: nameAr });
|
|
1234
|
+
}
|
|
1235
|
+
if (normalized.toLowerCase() === 'notification sent pending') {
|
|
1236
|
+
return WORKFLOW_TEMPLATES.notification_sent_pending?.ar ?? null;
|
|
1237
|
+
}
|
|
1238
|
+
if (normalized.toLowerCase() === 'notification sent successfully') {
|
|
1239
|
+
return WORKFLOW_TEMPLATES.notification_sent_successfully?.ar ?? null;
|
|
1240
|
+
}
|
|
995
1241
|
if (normalized === 'Approval Pending from HR Section' ||
|
|
996
1242
|
normalized === 'Approval Pending from Records Department') {
|
|
997
1243
|
return WORKFLOW_TEMPLATES.request_approval_pending?.ar ?? null;
|
|
@@ -1043,6 +1289,28 @@ function enrichWorkflowLog(log) {
|
|
|
1043
1289
|
content_ar = resolvedAr;
|
|
1044
1290
|
}
|
|
1045
1291
|
}
|
|
1292
|
+
const inProgressPrefix = WORKFLOW_TEMPLATES.request_approval_in_progress_from?.en.split('{{name}}')[0].trim();
|
|
1293
|
+
if (content &&
|
|
1294
|
+
inProgressPrefix &&
|
|
1295
|
+
content.startsWith(inProgressPrefix) &&
|
|
1296
|
+
existingAr &&
|
|
1297
|
+
resolvedAr &&
|
|
1298
|
+
existingAr !== resolvedAr) {
|
|
1299
|
+
const namePartEn = content.slice(inProgressPrefix.length).trim();
|
|
1300
|
+
if (namePartEn && existingAr.includes(namePartEn)) {
|
|
1301
|
+
content_ar = resolvedAr;
|
|
1302
|
+
}
|
|
1303
|
+
}
|
|
1304
|
+
if (content &&
|
|
1305
|
+
existingAr &&
|
|
1306
|
+
resolvedAr &&
|
|
1307
|
+
existingAr !== resolvedAr &&
|
|
1308
|
+
/[A-Za-z]/.test(existingAr) &&
|
|
1309
|
+
(actors?.deptArabicName?.trim() ||
|
|
1310
|
+
actors?.sectionArabicName?.trim() ||
|
|
1311
|
+
actors?.roleArabicName?.trim())) {
|
|
1312
|
+
content_ar = resolvedAr;
|
|
1313
|
+
}
|
|
1046
1314
|
if (content &&
|
|
1047
1315
|
existingAr &&
|
|
1048
1316
|
resolvedAr &&
|
|
@@ -1059,6 +1327,15 @@ function enrichWorkflowLog(log) {
|
|
|
1059
1327
|
existingAr.includes(actors.roleName.trim())) {
|
|
1060
1328
|
content_ar = resolvedAr;
|
|
1061
1329
|
}
|
|
1330
|
+
const itHelpdeskMixedEnglish = /routed to L3|assignment path|Workflow decision made|L3 Technical Support approved|L3 assignment not required|HOS notification not required|routing completed/i;
|
|
1331
|
+
if (content &&
|
|
1332
|
+
existingAr &&
|
|
1333
|
+
resolvedAr &&
|
|
1334
|
+
existingAr !== resolvedAr &&
|
|
1335
|
+
(itHelpdeskMixedEnglish.test(content) ||
|
|
1336
|
+
/routed to|routing completed|assignment path|\sby\s/i.test(existingAr))) {
|
|
1337
|
+
content_ar = resolvedAr;
|
|
1338
|
+
}
|
|
1062
1339
|
if ((content_ar == null || content_ar === '') && content) {
|
|
1063
1340
|
const notificationAr = resolveWorkflowContentAr(content, actors);
|
|
1064
1341
|
if (notificationAr)
|
package/package.json
CHANGED
|
@@ -131,6 +131,70 @@
|
|
|
131
131
|
"it_helpdesk_wf_routing_resolved": {
|
|
132
132
|
"en": "Workflow routing completed - request resolved at L3",
|
|
133
133
|
"ar": "تم استكمال مسار سير العمل - تم حل الطلب في المستوى الثالث (L3)"
|
|
134
|
+
},
|
|
135
|
+
"it_helpdesk_wf_routing_l3_reassign": {
|
|
136
|
+
"en": "Workflow routed to L3 assignment path - request reassigned by {{userName}}{{comment}}",
|
|
137
|
+
"ar": "تم توجيه سير العمل إلى مسار تعيين المستوى الثالث (L3) - تمت إعادة تعيين الطلب بواسطة {{userName}}{{comment}}"
|
|
138
|
+
},
|
|
139
|
+
"it_helpdesk_wf_routing_direct_approval": {
|
|
140
|
+
"en": "Workflow routed to direct resolution path - request approved by {{roleName}}{{comment}}",
|
|
141
|
+
"ar": "تم توجيه سير العمل إلى مسار الحل المباشر - تمت الموافقة على الطلب من قبل {{roleName}}{{comment}}"
|
|
142
|
+
},
|
|
143
|
+
"it_helpdesk_wf_routing_decision": {
|
|
144
|
+
"en": "Workflow decision made - {{status}} by {{roleName}}{{comment}}",
|
|
145
|
+
"ar": "تم اتخاذ قرار سير العمل - {{statusAr}} الطلب من قبل {{roleName}}{{comment}}"
|
|
146
|
+
},
|
|
147
|
+
"it_helpdesk_wf_l3_assignment_pending": {
|
|
148
|
+
"en": "L3 Technical Support assignment pending - request reassigned by {{roleName}}{{comment}}",
|
|
149
|
+
"ar": "تعيين دعم المستوى الثالث (L3) قيد الانتظار - تمت إعادة تعيين الطلب من قبل {{roleName}}{{comment}}"
|
|
150
|
+
},
|
|
151
|
+
"it_helpdesk_wf_l3_role_approved": {
|
|
152
|
+
"en": "{{roleName}} approved the request{{comment}}",
|
|
153
|
+
"ar": "تمت الموافقة على الطلب من قبل {{roleName}}{{commentAr}}"
|
|
154
|
+
},
|
|
155
|
+
"it_helpdesk_wf_l3_role_rejected": {
|
|
156
|
+
"en": "{{roleName}} rejected the request{{comment}}",
|
|
157
|
+
"ar": "تم رفض الطلب من قبل {{roleName}}{{commentAr}}"
|
|
158
|
+
},
|
|
159
|
+
"it_helpdesk_wf_role_outcome_by_user_rejected": {
|
|
160
|
+
"en": "{{roleName}} rejected the request by {{userName}}{{comment}}",
|
|
161
|
+
"ar": "تم رفض الطلب من قبل {{roleName}} بواسطة {{userName}}{{comment}}"
|
|
162
|
+
},
|
|
163
|
+
"it_helpdesk_wf_role_outcome_by_user_closed": {
|
|
164
|
+
"en": "{{roleName}} closed the request by {{userName}}{{comment}}",
|
|
165
|
+
"ar": "تم إغلاق الطلب من قبل {{roleName}} بواسطة {{userName}}{{comment}}"
|
|
166
|
+
},
|
|
167
|
+
"it_helpdesk_wf_routing_technician_rejected": {
|
|
168
|
+
"en": "Workflow routing completed - request rejected at technician level{{comment}}",
|
|
169
|
+
"ar": "تم استكمال مسار سير العمل - تم رفض الطلب على مستوى الفني{{comment}}"
|
|
170
|
+
},
|
|
171
|
+
"it_helpdesk_wf_hos_not_required_rejected": {
|
|
172
|
+
"en": "HOS notification not required, request rejected by {{userName}}{{comment}}",
|
|
173
|
+
"ar": "إشعار رئيس القسم غير مطلوب، تم رفض الطلب بواسطة {{userName}}{{comment}}"
|
|
174
|
+
},
|
|
175
|
+
"it_helpdesk_wf_hos_not_required_closed": {
|
|
176
|
+
"en": "HOS notification not required, request closed by {{userName}}{{comment}}",
|
|
177
|
+
"ar": "إشعار رئيس القسم غير مطلوب، تم إغلاق الطلب بواسطة {{userName}}{{comment}}"
|
|
178
|
+
},
|
|
179
|
+
"it_helpdesk_wf_l3_not_required_rejected": {
|
|
180
|
+
"en": "L3 assignment not required, request rejected by {{userName}}{{comment}}",
|
|
181
|
+
"ar": "تعيين المستوى الثالث (L3) غير مطلوب، تم رفض الطلب بواسطة {{userName}}{{comment}}"
|
|
182
|
+
},
|
|
183
|
+
"it_helpdesk_wf_l3_not_required_closed": {
|
|
184
|
+
"en": "L3 assignment not required, request closed by {{userName}}{{comment}}",
|
|
185
|
+
"ar": "تعيين المستوى الثالث (L3) غير مطلوب، تم إغلاق الطلب بواسطة {{userName}}{{comment}}"
|
|
186
|
+
},
|
|
187
|
+
"request_assigned": {
|
|
188
|
+
"en": "Request Assigned",
|
|
189
|
+
"ar": "تم تعيين الطلب"
|
|
190
|
+
},
|
|
191
|
+
"request_pending_from": {
|
|
192
|
+
"en": "Request Pending from {{name}}",
|
|
193
|
+
"ar": "الطلب قيد الانتظار من {{name}}"
|
|
194
|
+
},
|
|
195
|
+
"request_pending": {
|
|
196
|
+
"en": "Request Pending",
|
|
197
|
+
"ar": "الطلب قيد الانتظار"
|
|
134
198
|
}
|
|
135
199
|
},
|
|
136
200
|
"chatTemplates": {
|
|
@@ -262,6 +326,10 @@
|
|
|
262
326
|
"Pending": "قيد الانتظار",
|
|
263
327
|
"Not Yet Started": "لم يبدأ بعد"
|
|
264
328
|
},
|
|
329
|
+
"roleLabels": {
|
|
330
|
+
"L3 Technical Support": "دعم المستوى الثالث (L3) التقني",
|
|
331
|
+
"IT Technician": "فني تكنولوجيا المعلومات"
|
|
332
|
+
},
|
|
265
333
|
"chatStatusLabels": {
|
|
266
334
|
"Submitted": "تم التقديم",
|
|
267
335
|
"Received": "تم الاستلام",
|
|
@@ -65,6 +65,7 @@ const CHAT_TEMPLATES = catalog.chatTemplates as Record<string, BilingualText>;
|
|
|
65
65
|
const NOTIFICATION_TEMPLATES = (catalog as { notificationTemplates?: Record<string, BilingualText> }).notificationTemplates ?? {};
|
|
66
66
|
const WORKFLOW_STATUS_LABELS = catalog.workflowStatusLabels as Record<string, string>;
|
|
67
67
|
const CHAT_STATUS_LABELS = catalog.chatStatusLabels as Record<string, string>;
|
|
68
|
+
const ROLE_LABELS = (catalog as { roleLabels?: Record<string, string> }).roleLabels ?? {};
|
|
68
69
|
|
|
69
70
|
export function getWorkflowChatI18nCatalog(): WorkflowChatI18nCatalog {
|
|
70
71
|
return catalog as WorkflowChatI18nCatalog;
|
|
@@ -475,6 +476,20 @@ export function buildWorkflowLogUpdateFields(params: {
|
|
|
475
476
|
roleArabicName?: string | null;
|
|
476
477
|
comment?: string | null;
|
|
477
478
|
}): { content: string; content_ar: string; status: string; status_ar: string | null } {
|
|
479
|
+
if (params.approvalStatus === 'Closed') {
|
|
480
|
+
const closed = buildClosedWorkflowMessage({
|
|
481
|
+
roleName: params.roleName,
|
|
482
|
+
roleArabicName: params.roleArabicName,
|
|
483
|
+
comment: params.comment,
|
|
484
|
+
});
|
|
485
|
+
return {
|
|
486
|
+
content: closed.en,
|
|
487
|
+
content_ar: closed.ar,
|
|
488
|
+
status: params.workflowStatus,
|
|
489
|
+
status_ar: resolveWorkflowStatusAr(params.workflowStatus),
|
|
490
|
+
};
|
|
491
|
+
}
|
|
492
|
+
|
|
478
493
|
const isApprovedLike =
|
|
479
494
|
params.approvalStatus === 'Approved' || params.approvalStatus === 'Assigned';
|
|
480
495
|
|
|
@@ -642,6 +657,23 @@ function formatColonCommentSuffix(comment?: string | null): string {
|
|
|
642
657
|
return text ? `: ${text}` : '';
|
|
643
658
|
}
|
|
644
659
|
|
|
660
|
+
function formatBilingualColonCommentSuffix(comment?: string | null): { en: string; ar: string } {
|
|
661
|
+
const text = comment?.trim();
|
|
662
|
+
if (!text) return { en: '', ar: '' };
|
|
663
|
+
const statusKey = text.charAt(0).toUpperCase() + text.slice(1).toLowerCase();
|
|
664
|
+
const arText = resolveChatStatusAr(statusKey) ?? text;
|
|
665
|
+
return { en: `: ${text}`, ar: `: ${arText}` };
|
|
666
|
+
}
|
|
667
|
+
|
|
668
|
+
function splitWorkflowColonComment(content: string): { base: string; comment?: string } {
|
|
669
|
+
const idx = content.indexOf(': ');
|
|
670
|
+
if (idx <= 0) return { base: content.trim() };
|
|
671
|
+
return {
|
|
672
|
+
base: content.slice(0, idx).trim(),
|
|
673
|
+
comment: content.slice(idx + 2).trim() || undefined,
|
|
674
|
+
};
|
|
675
|
+
}
|
|
676
|
+
|
|
645
677
|
function formatReassignCommentSuffix(comment?: string | null): string {
|
|
646
678
|
const text = comment?.trim();
|
|
647
679
|
return text ? `:${text}` : '';
|
|
@@ -986,7 +1018,53 @@ export type ItHelpdeskMuscatWorkflowParams =
|
|
|
986
1018
|
roleArabicName?: string | null;
|
|
987
1019
|
comment?: string | null;
|
|
988
1020
|
}
|
|
989
|
-
| { variant: 'routing_resolved' }
|
|
1021
|
+
| { variant: 'routing_resolved' }
|
|
1022
|
+
| {
|
|
1023
|
+
variant: 'routing_l3_reassign';
|
|
1024
|
+
userName: string;
|
|
1025
|
+
userArabicName?: string | null;
|
|
1026
|
+
comment?: string | null;
|
|
1027
|
+
}
|
|
1028
|
+
| {
|
|
1029
|
+
variant: 'routing_direct_approval';
|
|
1030
|
+
roleName: string;
|
|
1031
|
+
roleArabicName?: string | null;
|
|
1032
|
+
comment?: string | null;
|
|
1033
|
+
}
|
|
1034
|
+
| {
|
|
1035
|
+
variant: 'routing_decision';
|
|
1036
|
+
status: string;
|
|
1037
|
+
roleName: string;
|
|
1038
|
+
roleArabicName?: string | null;
|
|
1039
|
+
comment?: string | null;
|
|
1040
|
+
}
|
|
1041
|
+
| {
|
|
1042
|
+
variant: 'l3_assignment_pending';
|
|
1043
|
+
roleName: string;
|
|
1044
|
+
roleArabicName?: string | null;
|
|
1045
|
+
comment?: string | null;
|
|
1046
|
+
}
|
|
1047
|
+
| {
|
|
1048
|
+
variant: 'l3_role_approved' | 'l3_role_rejected';
|
|
1049
|
+
roleName: string;
|
|
1050
|
+
roleArabicName?: string | null;
|
|
1051
|
+
comment?: string | null;
|
|
1052
|
+
}
|
|
1053
|
+
| {
|
|
1054
|
+
variant: 'role_outcome_by_user_rejected' | 'role_outcome_by_user_closed';
|
|
1055
|
+
roleName: string;
|
|
1056
|
+
roleArabicName?: string | null;
|
|
1057
|
+
userName: string;
|
|
1058
|
+
userArabicName?: string | null;
|
|
1059
|
+
comment?: string | null;
|
|
1060
|
+
}
|
|
1061
|
+
| { variant: 'routing_technician_rejected'; comment?: string | null }
|
|
1062
|
+
| {
|
|
1063
|
+
variant: 'hos_not_required_rejected' | 'hos_not_required_closed' | 'l3_not_required_rejected' | 'l3_not_required_closed';
|
|
1064
|
+
userName: string;
|
|
1065
|
+
userArabicName?: string | null;
|
|
1066
|
+
comment?: string | null;
|
|
1067
|
+
};
|
|
990
1068
|
|
|
991
1069
|
function resolveItHelpdeskGenericStatusAr(status: string): string {
|
|
992
1070
|
switch (status.trim()) {
|
|
@@ -1151,6 +1229,102 @@ export function buildItHelpdeskMuscatWorkflowLog(params: ItHelpdeskMuscatWorkflo
|
|
|
1151
1229
|
);
|
|
1152
1230
|
case 'routing_resolved':
|
|
1153
1231
|
return workflowTemplate('it_helpdesk_wf_routing_resolved');
|
|
1232
|
+
case 'routing_l3_reassign': {
|
|
1233
|
+
const userEn = params.userName.trim();
|
|
1234
|
+
const userAr = resolveBilingualName(userEn, params.userArabicName);
|
|
1235
|
+
return renderSynchronizedWorkflowMessage(
|
|
1236
|
+
'it_helpdesk_wf_routing_l3_reassign',
|
|
1237
|
+
{ userName: userEn, comment },
|
|
1238
|
+
{ userName: userAr, comment },
|
|
1239
|
+
);
|
|
1240
|
+
}
|
|
1241
|
+
case 'routing_direct_approval': {
|
|
1242
|
+
const roleEn = params.roleName.trim();
|
|
1243
|
+
const roleAr = resolveBilingualName(roleEn, params.roleArabicName);
|
|
1244
|
+
return renderSynchronizedWorkflowMessage(
|
|
1245
|
+
'it_helpdesk_wf_routing_direct_approval',
|
|
1246
|
+
{ roleName: roleEn, comment },
|
|
1247
|
+
{ roleName: roleAr, comment },
|
|
1248
|
+
);
|
|
1249
|
+
}
|
|
1250
|
+
case 'routing_decision': {
|
|
1251
|
+
const roleEn = params.roleName.trim();
|
|
1252
|
+
const roleAr = resolveBilingualName(roleEn, params.roleArabicName);
|
|
1253
|
+
const statusEn = params.status.toLowerCase();
|
|
1254
|
+
const statusAr = resolveItHelpdeskGenericStatusAr(params.status);
|
|
1255
|
+
return renderSynchronizedWorkflowMessage(
|
|
1256
|
+
'it_helpdesk_wf_routing_decision',
|
|
1257
|
+
{ status: statusEn, statusAr, roleName: roleEn, comment },
|
|
1258
|
+
{ status: statusEn, statusAr, roleName: roleAr, comment },
|
|
1259
|
+
);
|
|
1260
|
+
}
|
|
1261
|
+
case 'l3_assignment_pending': {
|
|
1262
|
+
const roleEn = params.roleName.trim();
|
|
1263
|
+
const roleAr = resolveBilingualName(roleEn, params.roleArabicName);
|
|
1264
|
+
return renderSynchronizedWorkflowMessage(
|
|
1265
|
+
'it_helpdesk_wf_l3_assignment_pending',
|
|
1266
|
+
{ roleName: roleEn, comment },
|
|
1267
|
+
{ roleName: roleAr, comment },
|
|
1268
|
+
);
|
|
1269
|
+
}
|
|
1270
|
+
case 'l3_role_approved':
|
|
1271
|
+
case 'l3_role_rejected': {
|
|
1272
|
+
const roleEn = params.roleName.trim();
|
|
1273
|
+
const roleAr = resolveBilingualName(
|
|
1274
|
+
roleEn,
|
|
1275
|
+
params.roleArabicName ?? ROLE_LABELS[roleEn] ?? null,
|
|
1276
|
+
);
|
|
1277
|
+
const biComment = formatBilingualColonCommentSuffix(params.comment);
|
|
1278
|
+
const key =
|
|
1279
|
+
params.variant === 'l3_role_approved'
|
|
1280
|
+
? 'it_helpdesk_wf_l3_role_approved'
|
|
1281
|
+
: 'it_helpdesk_wf_l3_role_rejected';
|
|
1282
|
+
return renderSynchronizedWorkflowMessage(
|
|
1283
|
+
key,
|
|
1284
|
+
{ roleName: roleEn, comment: biComment.en },
|
|
1285
|
+
{ roleName: roleAr, commentAr: biComment.ar },
|
|
1286
|
+
);
|
|
1287
|
+
}
|
|
1288
|
+
case 'role_outcome_by_user_rejected':
|
|
1289
|
+
case 'role_outcome_by_user_closed': {
|
|
1290
|
+
const roleEn = params.roleName.trim();
|
|
1291
|
+
const roleAr = resolveBilingualName(roleEn, params.roleArabicName);
|
|
1292
|
+
const userEn = params.userName.trim();
|
|
1293
|
+
const userAr = resolveBilingualName(userEn, params.userArabicName);
|
|
1294
|
+
const key =
|
|
1295
|
+
params.variant === 'role_outcome_by_user_rejected'
|
|
1296
|
+
? 'it_helpdesk_wf_role_outcome_by_user_rejected'
|
|
1297
|
+
: 'it_helpdesk_wf_role_outcome_by_user_closed';
|
|
1298
|
+
return renderSynchronizedWorkflowMessage(
|
|
1299
|
+
key,
|
|
1300
|
+
{ roleName: roleEn, userName: userEn, comment },
|
|
1301
|
+
{ roleName: roleAr, userName: userAr, comment },
|
|
1302
|
+
);
|
|
1303
|
+
}
|
|
1304
|
+
case 'routing_technician_rejected':
|
|
1305
|
+
return renderSynchronizedWorkflowMessage(
|
|
1306
|
+
'it_helpdesk_wf_routing_technician_rejected',
|
|
1307
|
+
{ comment },
|
|
1308
|
+
{ comment },
|
|
1309
|
+
);
|
|
1310
|
+
case 'hos_not_required_rejected':
|
|
1311
|
+
case 'hos_not_required_closed':
|
|
1312
|
+
case 'l3_not_required_rejected':
|
|
1313
|
+
case 'l3_not_required_closed': {
|
|
1314
|
+
const userEn = params.userName.trim();
|
|
1315
|
+
const userAr = resolveBilingualName(userEn, params.userArabicName);
|
|
1316
|
+
const keyMap = {
|
|
1317
|
+
hos_not_required_rejected: 'it_helpdesk_wf_hos_not_required_rejected',
|
|
1318
|
+
hos_not_required_closed: 'it_helpdesk_wf_hos_not_required_closed',
|
|
1319
|
+
l3_not_required_rejected: 'it_helpdesk_wf_l3_not_required_rejected',
|
|
1320
|
+
l3_not_required_closed: 'it_helpdesk_wf_l3_not_required_closed',
|
|
1321
|
+
} as const;
|
|
1322
|
+
return renderSynchronizedWorkflowMessage(
|
|
1323
|
+
keyMap[params.variant],
|
|
1324
|
+
{ userName: userEn, comment },
|
|
1325
|
+
{ userName: userAr, comment },
|
|
1326
|
+
);
|
|
1327
|
+
}
|
|
1154
1328
|
default:
|
|
1155
1329
|
return workflowTemplate('request_submitted');
|
|
1156
1330
|
}
|
|
@@ -1287,19 +1461,24 @@ function resolveArabicChatRoleName(
|
|
|
1287
1461
|
parsedEnglishRole?: string,
|
|
1288
1462
|
): string {
|
|
1289
1463
|
const parsed = parsedEnglishRole?.trim();
|
|
1290
|
-
if (
|
|
1291
|
-
|
|
1292
|
-
|
|
1293
|
-
|
|
1464
|
+
if (parsed) {
|
|
1465
|
+
if (
|
|
1466
|
+
actors?.roleName?.trim() &&
|
|
1467
|
+
parsed.toLowerCase() === actors.roleName.trim().toLowerCase()
|
|
1468
|
+
) {
|
|
1469
|
+
return resolveBilingualName(parsed, actors.roleArabicName);
|
|
1294
1470
|
}
|
|
1471
|
+
const catalogAr = ROLE_LABELS[parsed];
|
|
1472
|
+
if (catalogAr) return catalogAr;
|
|
1473
|
+
return parsed;
|
|
1295
1474
|
}
|
|
1296
|
-
if (actors?.
|
|
1297
|
-
return resolveBilingualName(
|
|
1475
|
+
if (actors?.roleName?.trim()) {
|
|
1476
|
+
return resolveBilingualName(actors.roleName, actors.roleArabicName);
|
|
1298
1477
|
}
|
|
1299
1478
|
if (actors?.userName?.trim()) {
|
|
1300
1479
|
return resolveBilingualName(actors.userName, actors.userArabicName);
|
|
1301
1480
|
}
|
|
1302
|
-
return
|
|
1481
|
+
return '';
|
|
1303
1482
|
}
|
|
1304
1483
|
|
|
1305
1484
|
function escapeRegexLiteral(value: string): string {
|
|
@@ -1399,6 +1578,14 @@ function buildArabicWorkflowTemplateParams(
|
|
|
1399
1578
|
params.status.charAt(0).toUpperCase() + params.status.slice(1).toLowerCase();
|
|
1400
1579
|
arParams.statusAr = resolveItHelpdeskGenericStatusAr(normalizedStatus);
|
|
1401
1580
|
}
|
|
1581
|
+
if (params.userName !== undefined) {
|
|
1582
|
+
arParams.userName = actors?.userName?.trim()
|
|
1583
|
+
? resolveBilingualName(actors.userName, actors.userArabicName)
|
|
1584
|
+
: resolveBilingualName(params.userName.trim(), actors?.userArabicName);
|
|
1585
|
+
}
|
|
1586
|
+
if (params.commentAr !== undefined) {
|
|
1587
|
+
arParams.commentAr = params.commentAr;
|
|
1588
|
+
}
|
|
1402
1589
|
return arParams;
|
|
1403
1590
|
}
|
|
1404
1591
|
|
|
@@ -1412,6 +1599,146 @@ function listWorkflowTemplatesBySpecificity(): Array<[string, BilingualText]> {
|
|
|
1412
1599
|
);
|
|
1413
1600
|
}
|
|
1414
1601
|
|
|
1602
|
+
/** Parse legacy IT Helpdesk Muscat EN workflow strings before generic template matching. */
|
|
1603
|
+
function tryResolveItHelpdeskMuscatLegacyWorkflowAr(
|
|
1604
|
+
content: string,
|
|
1605
|
+
actors?: BilingualActorNames,
|
|
1606
|
+
): string | null {
|
|
1607
|
+
const { base, comment } = splitWorkflowColonComment(content);
|
|
1608
|
+
|
|
1609
|
+
let m = base.match(/^Workflow routed to L3 assignment path - request reassigned by (.+)$/i);
|
|
1610
|
+
if (m) {
|
|
1611
|
+
return buildItHelpdeskMuscatWorkflowLog({
|
|
1612
|
+
variant: 'routing_l3_reassign',
|
|
1613
|
+
userName: m[1].trim(),
|
|
1614
|
+
userArabicName: actors?.userArabicName,
|
|
1615
|
+
comment,
|
|
1616
|
+
}).ar;
|
|
1617
|
+
}
|
|
1618
|
+
|
|
1619
|
+
m = base.match(/^Workflow routed to direct resolution path - request approved by (.+)$/i);
|
|
1620
|
+
if (m) {
|
|
1621
|
+
return buildItHelpdeskMuscatWorkflowLog({
|
|
1622
|
+
variant: 'routing_direct_approval',
|
|
1623
|
+
roleName: m[1].trim(),
|
|
1624
|
+
roleArabicName: actors?.roleArabicName,
|
|
1625
|
+
comment,
|
|
1626
|
+
}).ar;
|
|
1627
|
+
}
|
|
1628
|
+
|
|
1629
|
+
m = base.match(/^Workflow decision made - (\w+) by (.+)$/i);
|
|
1630
|
+
if (m) {
|
|
1631
|
+
return buildItHelpdeskMuscatWorkflowLog({
|
|
1632
|
+
variant: 'routing_decision',
|
|
1633
|
+
status: m[1],
|
|
1634
|
+
roleName: m[2].trim(),
|
|
1635
|
+
roleArabicName: actors?.roleArabicName,
|
|
1636
|
+
comment,
|
|
1637
|
+
}).ar;
|
|
1638
|
+
}
|
|
1639
|
+
|
|
1640
|
+
m = base.match(/^L3 Technical Support assignment pending - request reassigned by (.+)$/i);
|
|
1641
|
+
if (m) {
|
|
1642
|
+
return buildItHelpdeskMuscatWorkflowLog({
|
|
1643
|
+
variant: 'l3_assignment_pending',
|
|
1644
|
+
roleName: m[1].trim(),
|
|
1645
|
+
roleArabicName: actors?.roleArabicName,
|
|
1646
|
+
comment,
|
|
1647
|
+
}).ar;
|
|
1648
|
+
}
|
|
1649
|
+
|
|
1650
|
+
m = base.match(/^L3 Technical Support approved the request$/i);
|
|
1651
|
+
if (m) {
|
|
1652
|
+
return buildItHelpdeskMuscatWorkflowLog({
|
|
1653
|
+
variant: 'l3_role_approved',
|
|
1654
|
+
roleName: 'L3 Technical Support',
|
|
1655
|
+
comment,
|
|
1656
|
+
}).ar;
|
|
1657
|
+
}
|
|
1658
|
+
|
|
1659
|
+
m = base.match(/^L3 Technical Support rejected the request$/i);
|
|
1660
|
+
if (m) {
|
|
1661
|
+
return buildItHelpdeskMuscatWorkflowLog({
|
|
1662
|
+
variant: 'l3_role_rejected',
|
|
1663
|
+
roleName: 'L3 Technical Support',
|
|
1664
|
+
comment,
|
|
1665
|
+
}).ar;
|
|
1666
|
+
}
|
|
1667
|
+
|
|
1668
|
+
m = base.match(/^(.+?) rejected the request by (.+)$/i);
|
|
1669
|
+
if (m && !m[1].toLowerCase().includes('workflow')) {
|
|
1670
|
+
return buildItHelpdeskMuscatWorkflowLog({
|
|
1671
|
+
variant: 'role_outcome_by_user_rejected',
|
|
1672
|
+
roleName: m[1].trim(),
|
|
1673
|
+
roleArabicName: actors?.roleArabicName,
|
|
1674
|
+
userName: m[2].trim(),
|
|
1675
|
+
userArabicName: actors?.userArabicName,
|
|
1676
|
+
comment,
|
|
1677
|
+
}).ar;
|
|
1678
|
+
}
|
|
1679
|
+
|
|
1680
|
+
m = base.match(/^(.+?) closed the request by (.+)$/i);
|
|
1681
|
+
if (m) {
|
|
1682
|
+
return buildItHelpdeskMuscatWorkflowLog({
|
|
1683
|
+
variant: 'role_outcome_by_user_closed',
|
|
1684
|
+
roleName: m[1].trim(),
|
|
1685
|
+
roleArabicName: actors?.roleArabicName,
|
|
1686
|
+
userName: m[2].trim(),
|
|
1687
|
+
userArabicName: actors?.userArabicName,
|
|
1688
|
+
comment,
|
|
1689
|
+
}).ar;
|
|
1690
|
+
}
|
|
1691
|
+
|
|
1692
|
+
if (/^Workflow routing completed - request rejected at technician level$/i.test(base)) {
|
|
1693
|
+
return buildItHelpdeskMuscatWorkflowLog({
|
|
1694
|
+
variant: 'routing_technician_rejected',
|
|
1695
|
+
comment,
|
|
1696
|
+
}).ar;
|
|
1697
|
+
}
|
|
1698
|
+
|
|
1699
|
+
m = base.match(/^HOS notification not required, request rejected by (.+)$/i);
|
|
1700
|
+
if (m) {
|
|
1701
|
+
return buildItHelpdeskMuscatWorkflowLog({
|
|
1702
|
+
variant: 'hos_not_required_rejected',
|
|
1703
|
+
userName: m[1].trim(),
|
|
1704
|
+
userArabicName: actors?.userArabicName,
|
|
1705
|
+
comment,
|
|
1706
|
+
}).ar;
|
|
1707
|
+
}
|
|
1708
|
+
|
|
1709
|
+
m = base.match(/^HOS notification not required, request closed by (.+)$/i);
|
|
1710
|
+
if (m) {
|
|
1711
|
+
return buildItHelpdeskMuscatWorkflowLog({
|
|
1712
|
+
variant: 'hos_not_required_closed',
|
|
1713
|
+
userName: m[1].trim(),
|
|
1714
|
+
userArabicName: actors?.userArabicName,
|
|
1715
|
+
comment,
|
|
1716
|
+
}).ar;
|
|
1717
|
+
}
|
|
1718
|
+
|
|
1719
|
+
m = base.match(/^L3 assignment not required, request rejected by (.+)$/i);
|
|
1720
|
+
if (m) {
|
|
1721
|
+
return buildItHelpdeskMuscatWorkflowLog({
|
|
1722
|
+
variant: 'l3_not_required_rejected',
|
|
1723
|
+
userName: m[1].trim(),
|
|
1724
|
+
userArabicName: actors?.userArabicName,
|
|
1725
|
+
comment,
|
|
1726
|
+
}).ar;
|
|
1727
|
+
}
|
|
1728
|
+
|
|
1729
|
+
m = base.match(/^L3 assignment not required, request closed by (.+)$/i);
|
|
1730
|
+
if (m) {
|
|
1731
|
+
return buildItHelpdeskMuscatWorkflowLog({
|
|
1732
|
+
variant: 'l3_not_required_closed',
|
|
1733
|
+
userName: m[1].trim(),
|
|
1734
|
+
userArabicName: actors?.userArabicName,
|
|
1735
|
+
comment,
|
|
1736
|
+
}).ar;
|
|
1737
|
+
}
|
|
1738
|
+
|
|
1739
|
+
return null;
|
|
1740
|
+
}
|
|
1741
|
+
|
|
1415
1742
|
export function resolveWorkflowContentAr(
|
|
1416
1743
|
content: string | null | undefined,
|
|
1417
1744
|
actors?: BilingualActorNames,
|
|
@@ -1424,6 +1751,9 @@ export function resolveWorkflowContentAr(
|
|
|
1424
1751
|
return buildAssignmentWorkflowFieldsFromActors(embeddedAssignment, actors).ar;
|
|
1425
1752
|
}
|
|
1426
1753
|
|
|
1754
|
+
const itHelpdeskLegacyAr = tryResolveItHelpdeskMuscatLegacyWorkflowAr(normalized, actors);
|
|
1755
|
+
if (itHelpdeskLegacyAr) return itHelpdeskLegacyAr;
|
|
1756
|
+
|
|
1427
1757
|
for (const tpl of Object.values(WORKFLOW_TEMPLATES)) {
|
|
1428
1758
|
if (tpl.en === normalized || tpl.en.toLowerCase() === normalized.toLowerCase()) return tpl.ar;
|
|
1429
1759
|
}
|
|
@@ -1492,6 +1822,27 @@ export function resolveWorkflowContentAr(
|
|
|
1492
1822
|
const nameAr = resolveArabicWorkflowActorName(actors, namePartEn);
|
|
1493
1823
|
return interpolate(WORKFLOW_TEMPLATES.request_approval_pending_from.ar, { name: nameAr });
|
|
1494
1824
|
}
|
|
1825
|
+
|
|
1826
|
+
// Assign Tasks to Employee workflow (legacy EN strings)
|
|
1827
|
+
if (normalized === 'Request Assigned') {
|
|
1828
|
+
return WORKFLOW_TEMPLATES.request_assigned?.ar ?? null;
|
|
1829
|
+
}
|
|
1830
|
+
if (normalized === 'Request Pending') {
|
|
1831
|
+
return WORKFLOW_TEMPLATES.request_pending?.ar ?? null;
|
|
1832
|
+
}
|
|
1833
|
+
const assignTasksPendingPrefix = WORKFLOW_TEMPLATES.request_pending_from?.en.split('{{name}}')[0].trim();
|
|
1834
|
+
if (assignTasksPendingPrefix && normalized.startsWith(assignTasksPendingPrefix)) {
|
|
1835
|
+
const namePartEn = normalized.slice(assignTasksPendingPrefix.length).trim();
|
|
1836
|
+
const nameAr = resolveArabicWorkflowActorName(actors, namePartEn);
|
|
1837
|
+
return interpolate(WORKFLOW_TEMPLATES.request_pending_from.ar, { name: nameAr });
|
|
1838
|
+
}
|
|
1839
|
+
if (normalized.toLowerCase() === 'notification sent pending') {
|
|
1840
|
+
return WORKFLOW_TEMPLATES.notification_sent_pending?.ar ?? null;
|
|
1841
|
+
}
|
|
1842
|
+
if (normalized.toLowerCase() === 'notification sent successfully') {
|
|
1843
|
+
return WORKFLOW_TEMPLATES.notification_sent_successfully?.ar ?? null;
|
|
1844
|
+
}
|
|
1845
|
+
|
|
1495
1846
|
if (
|
|
1496
1847
|
normalized === 'Approval Pending from HR Section' ||
|
|
1497
1848
|
normalized === 'Approval Pending from Records Department'
|
|
@@ -1557,6 +1908,32 @@ export function enrichWorkflowLog(log: Record<string, unknown>): Record<string,
|
|
|
1557
1908
|
content_ar = resolvedAr;
|
|
1558
1909
|
}
|
|
1559
1910
|
}
|
|
1911
|
+
const inProgressPrefix = WORKFLOW_TEMPLATES.request_approval_in_progress_from?.en.split('{{name}}')[0].trim();
|
|
1912
|
+
if (
|
|
1913
|
+
content &&
|
|
1914
|
+
inProgressPrefix &&
|
|
1915
|
+
content.startsWith(inProgressPrefix) &&
|
|
1916
|
+
existingAr &&
|
|
1917
|
+
resolvedAr &&
|
|
1918
|
+
existingAr !== resolvedAr
|
|
1919
|
+
) {
|
|
1920
|
+
const namePartEn = content.slice(inProgressPrefix.length).trim();
|
|
1921
|
+
if (namePartEn && existingAr.includes(namePartEn)) {
|
|
1922
|
+
content_ar = resolvedAr;
|
|
1923
|
+
}
|
|
1924
|
+
}
|
|
1925
|
+
if (
|
|
1926
|
+
content &&
|
|
1927
|
+
existingAr &&
|
|
1928
|
+
resolvedAr &&
|
|
1929
|
+
existingAr !== resolvedAr &&
|
|
1930
|
+
/[A-Za-z]/.test(existingAr) &&
|
|
1931
|
+
(actors?.deptArabicName?.trim() ||
|
|
1932
|
+
actors?.sectionArabicName?.trim() ||
|
|
1933
|
+
actors?.roleArabicName?.trim())
|
|
1934
|
+
) {
|
|
1935
|
+
content_ar = resolvedAr;
|
|
1936
|
+
}
|
|
1560
1937
|
if (
|
|
1561
1938
|
content &&
|
|
1562
1939
|
existingAr &&
|
|
@@ -1577,6 +1954,18 @@ export function enrichWorkflowLog(log: Record<string, unknown>): Record<string,
|
|
|
1577
1954
|
) {
|
|
1578
1955
|
content_ar = resolvedAr;
|
|
1579
1956
|
}
|
|
1957
|
+
const itHelpdeskMixedEnglish =
|
|
1958
|
+
/routed to L3|assignment path|Workflow decision made|L3 Technical Support approved|L3 assignment not required|HOS notification not required|routing completed/i;
|
|
1959
|
+
if (
|
|
1960
|
+
content &&
|
|
1961
|
+
existingAr &&
|
|
1962
|
+
resolvedAr &&
|
|
1963
|
+
existingAr !== resolvedAr &&
|
|
1964
|
+
(itHelpdeskMixedEnglish.test(content) ||
|
|
1965
|
+
/routed to|routing completed|assignment path|\sby\s/i.test(existingAr))
|
|
1966
|
+
) {
|
|
1967
|
+
content_ar = resolvedAr;
|
|
1968
|
+
}
|
|
1580
1969
|
if ((content_ar == null || content_ar === '') && content) {
|
|
1581
1970
|
const notificationAr = resolveWorkflowContentAr(content, actors);
|
|
1582
1971
|
if (notificationAr) content_ar = notificationAr;
|