@platform-modules/civil-aviation-authority 2.3.295 → 2.3.297
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 +56 -0
- package/dist/i18n/workflow-chat-message.builder.d.ts +41 -1
- package/dist/i18n/workflow-chat-message.builder.js +287 -16
- package/package.json +1 -1
- package/src/i18n/workflow-chat-i18n.json +56 -0
- package/src/i18n/workflow-chat-message.builder.ts +407 -19
|
@@ -131,6 +131,58 @@
|
|
|
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}}"
|
|
134
186
|
}
|
|
135
187
|
},
|
|
136
188
|
"chatTemplates": {
|
|
@@ -262,6 +314,10 @@
|
|
|
262
314
|
"Pending": "قيد الانتظار",
|
|
263
315
|
"Not Yet Started": "لم يبدأ بعد"
|
|
264
316
|
},
|
|
317
|
+
"roleLabels": {
|
|
318
|
+
"L3 Technical Support": "دعم المستوى الثالث (L3) التقني",
|
|
319
|
+
"IT Technician": "فني تكنولوجيا المعلومات"
|
|
320
|
+
},
|
|
265
321
|
"chatStatusLabels": {
|
|
266
322
|
"Submitted": "تم التقديم",
|
|
267
323
|
"Received": "تم الاستلام",
|
|
@@ -77,7 +77,6 @@ export type RequestApprovedAssignedWorkflowParams = {
|
|
|
77
77
|
employeeId: string | number;
|
|
78
78
|
assigneeLabel?: 'user' | 'technician';
|
|
79
79
|
};
|
|
80
|
-
/** Parse legacy English-only assignment comments used as workflow log suffixes. */
|
|
81
80
|
export declare function tryParseRequestAssignedComment(comment?: string | null): Omit<RequestApprovedAssignedWorkflowParams, 'roleArabicName'> | null;
|
|
82
81
|
/** Bilingual workflow content for approved assignment steps (HR, IT, Tender, etc.). */
|
|
83
82
|
export declare function buildRequestApprovedAssignedWorkflowFields(params: RequestApprovedAssignedWorkflowParams): BilingualText;
|
|
@@ -265,6 +264,47 @@ export type ItHelpdeskMuscatWorkflowParams = {
|
|
|
265
264
|
comment?: string | null;
|
|
266
265
|
} | {
|
|
267
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;
|
|
268
308
|
};
|
|
269
309
|
export declare function buildItHelpdeskMuscatWorkflowLog(params: ItHelpdeskMuscatWorkflowParams): BilingualText;
|
|
270
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
|
}
|
|
@@ -178,10 +179,19 @@ function buildSynchronizedWorkflowMessage(ctx) {
|
|
|
178
179
|
return actorEn
|
|
179
180
|
? renderSynchronizedWorkflowMessage('request_approval_pending_from', { name: actorEn }, { name: actorAr })
|
|
180
181
|
: workflowTemplate('request_approval_pending');
|
|
181
|
-
case 'approved':
|
|
182
|
+
case 'approved': {
|
|
183
|
+
const assignment = tryParseRequestAssignedComment(ctx.comment);
|
|
184
|
+
if (assignment) {
|
|
185
|
+
return buildRequestApprovedAssignedWorkflowFields({
|
|
186
|
+
...assignment,
|
|
187
|
+
roleName: ctx.roleName?.trim() || assignment.roleName,
|
|
188
|
+
roleArabicName: ctx.roleArabicName,
|
|
189
|
+
});
|
|
190
|
+
}
|
|
182
191
|
return actorEn
|
|
183
192
|
? renderSynchronizedWorkflowMessage('request_approved_by', { name: actorEn, comment: commentWf }, { name: actorAr, comment: commentWf })
|
|
184
193
|
: renderSynchronizedWorkflowMessage('request_approved', { comment: commentWf }, { comment: commentWf });
|
|
194
|
+
}
|
|
185
195
|
case 'rejected':
|
|
186
196
|
return actorEn
|
|
187
197
|
? renderSynchronizedWorkflowMessage('request_rejected_by', { name: actorEn, comment: commentWf }, { name: actorAr, comment: commentWf })
|
|
@@ -236,11 +246,11 @@ function buildSynchronizedChatMessage(ctx) {
|
|
|
236
246
|
}
|
|
237
247
|
}
|
|
238
248
|
/** Parse legacy English-only assignment comments used as workflow log suffixes. */
|
|
239
|
-
function
|
|
240
|
-
const
|
|
241
|
-
if (!
|
|
249
|
+
function parseRequestAssignedCommentText(text) {
|
|
250
|
+
const normalized = text.trim();
|
|
251
|
+
if (!normalized)
|
|
242
252
|
return null;
|
|
243
|
-
const technicianMatch =
|
|
253
|
+
const technicianMatch = normalized.match(/^request assigned to technician (.+?) by (.+?) \((.+?) - (.+?)\)$/i);
|
|
244
254
|
if (technicianMatch) {
|
|
245
255
|
return {
|
|
246
256
|
assignedUserName: technicianMatch[1].trim(),
|
|
@@ -250,7 +260,7 @@ function tryParseRequestAssignedComment(comment) {
|
|
|
250
260
|
assigneeLabel: 'technician',
|
|
251
261
|
};
|
|
252
262
|
}
|
|
253
|
-
const userMatch =
|
|
263
|
+
const userMatch = normalized.match(/^request assigned to (.+?) by (.+?) \((.+?) - (.+?)\)$/i);
|
|
254
264
|
if (userMatch) {
|
|
255
265
|
return {
|
|
256
266
|
assignedUserName: userMatch[1].trim(),
|
|
@@ -262,6 +272,36 @@ function tryParseRequestAssignedComment(comment) {
|
|
|
262
272
|
}
|
|
263
273
|
return null;
|
|
264
274
|
}
|
|
275
|
+
function tryParseRequestAssignedComment(comment) {
|
|
276
|
+
let text = comment?.trim();
|
|
277
|
+
if (!text)
|
|
278
|
+
return null;
|
|
279
|
+
if (text.startsWith(':')) {
|
|
280
|
+
text = text.replace(/^:\s*/, '').trim();
|
|
281
|
+
}
|
|
282
|
+
const direct = parseRequestAssignedCommentText(text);
|
|
283
|
+
if (direct)
|
|
284
|
+
return direct;
|
|
285
|
+
const colonIdx = text.indexOf(': ');
|
|
286
|
+
if (colonIdx >= 0) {
|
|
287
|
+
const afterColon = text.slice(colonIdx + 2).trim();
|
|
288
|
+
const parsedAfterColon = parseRequestAssignedCommentText(afterColon);
|
|
289
|
+
if (parsedAfterColon)
|
|
290
|
+
return parsedAfterColon;
|
|
291
|
+
}
|
|
292
|
+
const assignMatch = text.match(/request assigned to/i);
|
|
293
|
+
if (assignMatch && assignMatch.index != null && assignMatch.index >= 0) {
|
|
294
|
+
return parseRequestAssignedCommentText(text.slice(assignMatch.index).trim());
|
|
295
|
+
}
|
|
296
|
+
return null;
|
|
297
|
+
}
|
|
298
|
+
function buildAssignmentWorkflowFieldsFromActors(assignment, actors) {
|
|
299
|
+
return buildRequestApprovedAssignedWorkflowFields({
|
|
300
|
+
...assignment,
|
|
301
|
+
roleName: actors?.roleName?.trim() || assignment.roleName,
|
|
302
|
+
roleArabicName: actors?.roleArabicName ?? null,
|
|
303
|
+
});
|
|
304
|
+
}
|
|
265
305
|
/** Bilingual workflow content for approved assignment steps (HR, IT, Tender, etc.). */
|
|
266
306
|
function buildRequestApprovedAssignedWorkflowFields(params) {
|
|
267
307
|
const assignedUserEn = params.assignedUserName?.trim() || 'User';
|
|
@@ -286,7 +326,8 @@ function buildRequestApprovedAssignedWorkflowFields(params) {
|
|
|
286
326
|
}
|
|
287
327
|
/** Standard workflow log UPDATE fields for all CAA module repositories. */
|
|
288
328
|
function buildWorkflowLogUpdateFields(params) {
|
|
289
|
-
|
|
329
|
+
const isApprovedLike = params.approvalStatus === 'Approved' || params.approvalStatus === 'Assigned';
|
|
330
|
+
if (isApprovedLike) {
|
|
290
331
|
const assignment = tryParseRequestAssignedComment(params.comment);
|
|
291
332
|
if (assignment) {
|
|
292
333
|
const bilingual = buildRequestApprovedAssignedWorkflowFields({
|
|
@@ -303,7 +344,7 @@ function buildWorkflowLogUpdateFields(params) {
|
|
|
303
344
|
}
|
|
304
345
|
}
|
|
305
346
|
let action;
|
|
306
|
-
if (params.approvalStatus === 'Approved')
|
|
347
|
+
if (params.approvalStatus === 'Approved' || params.approvalStatus === 'Assigned')
|
|
307
348
|
action = 'approved';
|
|
308
349
|
else if (params.approvalStatus === 'Rejected')
|
|
309
350
|
action = 'rejected';
|
|
@@ -417,6 +458,23 @@ function formatColonCommentSuffix(comment) {
|
|
|
417
458
|
const text = comment?.trim();
|
|
418
459
|
return text ? `: ${text}` : '';
|
|
419
460
|
}
|
|
461
|
+
function formatBilingualColonCommentSuffix(comment) {
|
|
462
|
+
const text = comment?.trim();
|
|
463
|
+
if (!text)
|
|
464
|
+
return { en: '', ar: '' };
|
|
465
|
+
const statusKey = text.charAt(0).toUpperCase() + text.slice(1).toLowerCase();
|
|
466
|
+
const arText = resolveChatStatusAr(statusKey) ?? text;
|
|
467
|
+
return { en: `: ${text}`, ar: `: ${arText}` };
|
|
468
|
+
}
|
|
469
|
+
function splitWorkflowColonComment(content) {
|
|
470
|
+
const idx = content.indexOf(': ');
|
|
471
|
+
if (idx <= 0)
|
|
472
|
+
return { base: content.trim() };
|
|
473
|
+
return {
|
|
474
|
+
base: content.slice(0, idx).trim(),
|
|
475
|
+
comment: content.slice(idx + 2).trim() || undefined,
|
|
476
|
+
};
|
|
477
|
+
}
|
|
420
478
|
function formatReassignCommentSuffix(comment) {
|
|
421
479
|
const text = comment?.trim();
|
|
422
480
|
return text ? `:${text}` : '';
|
|
@@ -684,6 +742,65 @@ function buildItHelpdeskMuscatWorkflowLog(params) {
|
|
|
684
742
|
return renderSynchronizedWorkflowMessage('it_helpdesk_wf_routing_rejected', { comment }, { comment });
|
|
685
743
|
case 'routing_resolved':
|
|
686
744
|
return workflowTemplate('it_helpdesk_wf_routing_resolved');
|
|
745
|
+
case 'routing_l3_reassign': {
|
|
746
|
+
const userEn = params.userName.trim();
|
|
747
|
+
const userAr = resolveBilingualName(userEn, params.userArabicName);
|
|
748
|
+
return renderSynchronizedWorkflowMessage('it_helpdesk_wf_routing_l3_reassign', { userName: userEn, comment }, { userName: userAr, comment });
|
|
749
|
+
}
|
|
750
|
+
case 'routing_direct_approval': {
|
|
751
|
+
const roleEn = params.roleName.trim();
|
|
752
|
+
const roleAr = resolveBilingualName(roleEn, params.roleArabicName);
|
|
753
|
+
return renderSynchronizedWorkflowMessage('it_helpdesk_wf_routing_direct_approval', { roleName: roleEn, comment }, { roleName: roleAr, comment });
|
|
754
|
+
}
|
|
755
|
+
case 'routing_decision': {
|
|
756
|
+
const roleEn = params.roleName.trim();
|
|
757
|
+
const roleAr = resolveBilingualName(roleEn, params.roleArabicName);
|
|
758
|
+
const statusEn = params.status.toLowerCase();
|
|
759
|
+
const statusAr = resolveItHelpdeskGenericStatusAr(params.status);
|
|
760
|
+
return renderSynchronizedWorkflowMessage('it_helpdesk_wf_routing_decision', { status: statusEn, statusAr, roleName: roleEn, comment }, { status: statusEn, statusAr, roleName: roleAr, comment });
|
|
761
|
+
}
|
|
762
|
+
case 'l3_assignment_pending': {
|
|
763
|
+
const roleEn = params.roleName.trim();
|
|
764
|
+
const roleAr = resolveBilingualName(roleEn, params.roleArabicName);
|
|
765
|
+
return renderSynchronizedWorkflowMessage('it_helpdesk_wf_l3_assignment_pending', { roleName: roleEn, comment }, { roleName: roleAr, comment });
|
|
766
|
+
}
|
|
767
|
+
case 'l3_role_approved':
|
|
768
|
+
case 'l3_role_rejected': {
|
|
769
|
+
const roleEn = params.roleName.trim();
|
|
770
|
+
const roleAr = resolveBilingualName(roleEn, params.roleArabicName ?? ROLE_LABELS[roleEn] ?? null);
|
|
771
|
+
const biComment = formatBilingualColonCommentSuffix(params.comment);
|
|
772
|
+
const key = params.variant === 'l3_role_approved'
|
|
773
|
+
? 'it_helpdesk_wf_l3_role_approved'
|
|
774
|
+
: 'it_helpdesk_wf_l3_role_rejected';
|
|
775
|
+
return renderSynchronizedWorkflowMessage(key, { roleName: roleEn, comment: biComment.en }, { roleName: roleAr, commentAr: biComment.ar });
|
|
776
|
+
}
|
|
777
|
+
case 'role_outcome_by_user_rejected':
|
|
778
|
+
case 'role_outcome_by_user_closed': {
|
|
779
|
+
const roleEn = params.roleName.trim();
|
|
780
|
+
const roleAr = resolveBilingualName(roleEn, params.roleArabicName);
|
|
781
|
+
const userEn = params.userName.trim();
|
|
782
|
+
const userAr = resolveBilingualName(userEn, params.userArabicName);
|
|
783
|
+
const key = params.variant === 'role_outcome_by_user_rejected'
|
|
784
|
+
? 'it_helpdesk_wf_role_outcome_by_user_rejected'
|
|
785
|
+
: 'it_helpdesk_wf_role_outcome_by_user_closed';
|
|
786
|
+
return renderSynchronizedWorkflowMessage(key, { roleName: roleEn, userName: userEn, comment }, { roleName: roleAr, userName: userAr, comment });
|
|
787
|
+
}
|
|
788
|
+
case 'routing_technician_rejected':
|
|
789
|
+
return renderSynchronizedWorkflowMessage('it_helpdesk_wf_routing_technician_rejected', { comment }, { comment });
|
|
790
|
+
case 'hos_not_required_rejected':
|
|
791
|
+
case 'hos_not_required_closed':
|
|
792
|
+
case 'l3_not_required_rejected':
|
|
793
|
+
case 'l3_not_required_closed': {
|
|
794
|
+
const userEn = params.userName.trim();
|
|
795
|
+
const userAr = resolveBilingualName(userEn, params.userArabicName);
|
|
796
|
+
const keyMap = {
|
|
797
|
+
hos_not_required_rejected: 'it_helpdesk_wf_hos_not_required_rejected',
|
|
798
|
+
hos_not_required_closed: 'it_helpdesk_wf_hos_not_required_closed',
|
|
799
|
+
l3_not_required_rejected: 'it_helpdesk_wf_l3_not_required_rejected',
|
|
800
|
+
l3_not_required_closed: 'it_helpdesk_wf_l3_not_required_closed',
|
|
801
|
+
};
|
|
802
|
+
return renderSynchronizedWorkflowMessage(keyMap[params.variant], { userName: userEn, comment }, { userName: userAr, comment });
|
|
803
|
+
}
|
|
687
804
|
default:
|
|
688
805
|
return workflowTemplate('request_submitted');
|
|
689
806
|
}
|
|
@@ -775,19 +892,23 @@ function resolveArabicWorkflowActorName(actors, parsedEnglishName) {
|
|
|
775
892
|
/** Arabic role/user label for chat templates. */
|
|
776
893
|
function resolveArabicChatRoleName(actors, parsedEnglishRole) {
|
|
777
894
|
const parsed = parsedEnglishRole?.trim();
|
|
778
|
-
if (
|
|
779
|
-
|
|
780
|
-
|
|
781
|
-
return resolveBilingualName(
|
|
895
|
+
if (parsed) {
|
|
896
|
+
if (actors?.roleName?.trim() &&
|
|
897
|
+
parsed.toLowerCase() === actors.roleName.trim().toLowerCase()) {
|
|
898
|
+
return resolveBilingualName(parsed, actors.roleArabicName);
|
|
782
899
|
}
|
|
900
|
+
const catalogAr = ROLE_LABELS[parsed];
|
|
901
|
+
if (catalogAr)
|
|
902
|
+
return catalogAr;
|
|
903
|
+
return parsed;
|
|
783
904
|
}
|
|
784
|
-
if (actors?.
|
|
785
|
-
return resolveBilingualName(
|
|
905
|
+
if (actors?.roleName?.trim()) {
|
|
906
|
+
return resolveBilingualName(actors.roleName, actors.roleArabicName);
|
|
786
907
|
}
|
|
787
908
|
if (actors?.userName?.trim()) {
|
|
788
909
|
return resolveBilingualName(actors.userName, actors.userArabicName);
|
|
789
910
|
}
|
|
790
|
-
return
|
|
911
|
+
return '';
|
|
791
912
|
}
|
|
792
913
|
function escapeRegexLiteral(value) {
|
|
793
914
|
return value.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
|
|
@@ -868,6 +989,14 @@ function buildArabicWorkflowTemplateParams(params, actors) {
|
|
|
868
989
|
const normalizedStatus = params.status.charAt(0).toUpperCase() + params.status.slice(1).toLowerCase();
|
|
869
990
|
arParams.statusAr = resolveItHelpdeskGenericStatusAr(normalizedStatus);
|
|
870
991
|
}
|
|
992
|
+
if (params.userName !== undefined) {
|
|
993
|
+
arParams.userName = actors?.userName?.trim()
|
|
994
|
+
? resolveBilingualName(actors.userName, actors.userArabicName)
|
|
995
|
+
: resolveBilingualName(params.userName.trim(), actors?.userArabicName);
|
|
996
|
+
}
|
|
997
|
+
if (params.commentAr !== undefined) {
|
|
998
|
+
arParams.commentAr = params.commentAr;
|
|
999
|
+
}
|
|
871
1000
|
return arParams;
|
|
872
1001
|
}
|
|
873
1002
|
function countTemplatePlaceholders(templateEn) {
|
|
@@ -876,10 +1005,139 @@ function countTemplatePlaceholders(templateEn) {
|
|
|
876
1005
|
function listWorkflowTemplatesBySpecificity() {
|
|
877
1006
|
return Object.entries(WORKFLOW_TEMPLATES).sort(([, a], [, b]) => countTemplatePlaceholders(b.en) - countTemplatePlaceholders(a.en));
|
|
878
1007
|
}
|
|
1008
|
+
/** Parse legacy IT Helpdesk Muscat EN workflow strings before generic template matching. */
|
|
1009
|
+
function tryResolveItHelpdeskMuscatLegacyWorkflowAr(content, actors) {
|
|
1010
|
+
const { base, comment } = splitWorkflowColonComment(content);
|
|
1011
|
+
let m = base.match(/^Workflow routed to L3 assignment path - request reassigned by (.+)$/i);
|
|
1012
|
+
if (m) {
|
|
1013
|
+
return buildItHelpdeskMuscatWorkflowLog({
|
|
1014
|
+
variant: 'routing_l3_reassign',
|
|
1015
|
+
userName: m[1].trim(),
|
|
1016
|
+
userArabicName: actors?.userArabicName,
|
|
1017
|
+
comment,
|
|
1018
|
+
}).ar;
|
|
1019
|
+
}
|
|
1020
|
+
m = base.match(/^Workflow routed to direct resolution path - request approved by (.+)$/i);
|
|
1021
|
+
if (m) {
|
|
1022
|
+
return buildItHelpdeskMuscatWorkflowLog({
|
|
1023
|
+
variant: 'routing_direct_approval',
|
|
1024
|
+
roleName: m[1].trim(),
|
|
1025
|
+
roleArabicName: actors?.roleArabicName,
|
|
1026
|
+
comment,
|
|
1027
|
+
}).ar;
|
|
1028
|
+
}
|
|
1029
|
+
m = base.match(/^Workflow decision made - (\w+) by (.+)$/i);
|
|
1030
|
+
if (m) {
|
|
1031
|
+
return buildItHelpdeskMuscatWorkflowLog({
|
|
1032
|
+
variant: 'routing_decision',
|
|
1033
|
+
status: m[1],
|
|
1034
|
+
roleName: m[2].trim(),
|
|
1035
|
+
roleArabicName: actors?.roleArabicName,
|
|
1036
|
+
comment,
|
|
1037
|
+
}).ar;
|
|
1038
|
+
}
|
|
1039
|
+
m = base.match(/^L3 Technical Support assignment pending - request reassigned by (.+)$/i);
|
|
1040
|
+
if (m) {
|
|
1041
|
+
return buildItHelpdeskMuscatWorkflowLog({
|
|
1042
|
+
variant: 'l3_assignment_pending',
|
|
1043
|
+
roleName: m[1].trim(),
|
|
1044
|
+
roleArabicName: actors?.roleArabicName,
|
|
1045
|
+
comment,
|
|
1046
|
+
}).ar;
|
|
1047
|
+
}
|
|
1048
|
+
m = base.match(/^L3 Technical Support approved the request$/i);
|
|
1049
|
+
if (m) {
|
|
1050
|
+
return buildItHelpdeskMuscatWorkflowLog({
|
|
1051
|
+
variant: 'l3_role_approved',
|
|
1052
|
+
roleName: 'L3 Technical Support',
|
|
1053
|
+
comment,
|
|
1054
|
+
}).ar;
|
|
1055
|
+
}
|
|
1056
|
+
m = base.match(/^L3 Technical Support rejected the request$/i);
|
|
1057
|
+
if (m) {
|
|
1058
|
+
return buildItHelpdeskMuscatWorkflowLog({
|
|
1059
|
+
variant: 'l3_role_rejected',
|
|
1060
|
+
roleName: 'L3 Technical Support',
|
|
1061
|
+
comment,
|
|
1062
|
+
}).ar;
|
|
1063
|
+
}
|
|
1064
|
+
m = base.match(/^(.+?) rejected the request by (.+)$/i);
|
|
1065
|
+
if (m && !m[1].toLowerCase().includes('workflow')) {
|
|
1066
|
+
return buildItHelpdeskMuscatWorkflowLog({
|
|
1067
|
+
variant: 'role_outcome_by_user_rejected',
|
|
1068
|
+
roleName: m[1].trim(),
|
|
1069
|
+
roleArabicName: actors?.roleArabicName,
|
|
1070
|
+
userName: m[2].trim(),
|
|
1071
|
+
userArabicName: actors?.userArabicName,
|
|
1072
|
+
comment,
|
|
1073
|
+
}).ar;
|
|
1074
|
+
}
|
|
1075
|
+
m = base.match(/^(.+?) closed the request by (.+)$/i);
|
|
1076
|
+
if (m) {
|
|
1077
|
+
return buildItHelpdeskMuscatWorkflowLog({
|
|
1078
|
+
variant: 'role_outcome_by_user_closed',
|
|
1079
|
+
roleName: m[1].trim(),
|
|
1080
|
+
roleArabicName: actors?.roleArabicName,
|
|
1081
|
+
userName: m[2].trim(),
|
|
1082
|
+
userArabicName: actors?.userArabicName,
|
|
1083
|
+
comment,
|
|
1084
|
+
}).ar;
|
|
1085
|
+
}
|
|
1086
|
+
if (/^Workflow routing completed - request rejected at technician level$/i.test(base)) {
|
|
1087
|
+
return buildItHelpdeskMuscatWorkflowLog({
|
|
1088
|
+
variant: 'routing_technician_rejected',
|
|
1089
|
+
comment,
|
|
1090
|
+
}).ar;
|
|
1091
|
+
}
|
|
1092
|
+
m = base.match(/^HOS notification not required, request rejected by (.+)$/i);
|
|
1093
|
+
if (m) {
|
|
1094
|
+
return buildItHelpdeskMuscatWorkflowLog({
|
|
1095
|
+
variant: 'hos_not_required_rejected',
|
|
1096
|
+
userName: m[1].trim(),
|
|
1097
|
+
userArabicName: actors?.userArabicName,
|
|
1098
|
+
comment,
|
|
1099
|
+
}).ar;
|
|
1100
|
+
}
|
|
1101
|
+
m = base.match(/^HOS notification not required, request closed by (.+)$/i);
|
|
1102
|
+
if (m) {
|
|
1103
|
+
return buildItHelpdeskMuscatWorkflowLog({
|
|
1104
|
+
variant: 'hos_not_required_closed',
|
|
1105
|
+
userName: m[1].trim(),
|
|
1106
|
+
userArabicName: actors?.userArabicName,
|
|
1107
|
+
comment,
|
|
1108
|
+
}).ar;
|
|
1109
|
+
}
|
|
1110
|
+
m = base.match(/^L3 assignment not required, request rejected by (.+)$/i);
|
|
1111
|
+
if (m) {
|
|
1112
|
+
return buildItHelpdeskMuscatWorkflowLog({
|
|
1113
|
+
variant: 'l3_not_required_rejected',
|
|
1114
|
+
userName: m[1].trim(),
|
|
1115
|
+
userArabicName: actors?.userArabicName,
|
|
1116
|
+
comment,
|
|
1117
|
+
}).ar;
|
|
1118
|
+
}
|
|
1119
|
+
m = base.match(/^L3 assignment not required, request closed by (.+)$/i);
|
|
1120
|
+
if (m) {
|
|
1121
|
+
return buildItHelpdeskMuscatWorkflowLog({
|
|
1122
|
+
variant: 'l3_not_required_closed',
|
|
1123
|
+
userName: m[1].trim(),
|
|
1124
|
+
userArabicName: actors?.userArabicName,
|
|
1125
|
+
comment,
|
|
1126
|
+
}).ar;
|
|
1127
|
+
}
|
|
1128
|
+
return null;
|
|
1129
|
+
}
|
|
879
1130
|
function resolveWorkflowContentAr(content, actors) {
|
|
880
1131
|
if (content == null || content.trim() === '')
|
|
881
1132
|
return null;
|
|
882
1133
|
const normalized = content.trim();
|
|
1134
|
+
const embeddedAssignment = tryParseRequestAssignedComment(normalized);
|
|
1135
|
+
if (embeddedAssignment) {
|
|
1136
|
+
return buildAssignmentWorkflowFieldsFromActors(embeddedAssignment, actors).ar;
|
|
1137
|
+
}
|
|
1138
|
+
const itHelpdeskLegacyAr = tryResolveItHelpdeskMuscatLegacyWorkflowAr(normalized, actors);
|
|
1139
|
+
if (itHelpdeskLegacyAr)
|
|
1140
|
+
return itHelpdeskLegacyAr;
|
|
883
1141
|
for (const tpl of Object.values(WORKFLOW_TEMPLATES)) {
|
|
884
1142
|
if (tpl.en === normalized || tpl.en.toLowerCase() === normalized.toLowerCase())
|
|
885
1143
|
return tpl.ar;
|
|
@@ -896,6 +1154,10 @@ function resolveWorkflowContentAr(content, actors) {
|
|
|
896
1154
|
if (commentIdx > 0) {
|
|
897
1155
|
const baseEn = normalized.slice(0, commentIdx).trim();
|
|
898
1156
|
const commentText = normalized.slice(commentIdx + 2).trim();
|
|
1157
|
+
const assignment = tryParseRequestAssignedComment(commentText);
|
|
1158
|
+
if (assignment) {
|
|
1159
|
+
return buildAssignmentWorkflowFieldsFromActors(assignment, actors).ar;
|
|
1160
|
+
}
|
|
899
1161
|
const commentSuffix = formatWorkflowCommentSuffix(commentText);
|
|
900
1162
|
for (const tpl of Object.values(WORKFLOW_TEMPLATES)) {
|
|
901
1163
|
if (!tpl.en.includes('{{comment}}'))
|
|
@@ -999,7 +1261,7 @@ function enrichWorkflowLog(log) {
|
|
|
999
1261
|
existingAr &&
|
|
1000
1262
|
resolvedAr &&
|
|
1001
1263
|
existingAr !== resolvedAr &&
|
|
1002
|
-
/
|
|
1264
|
+
(/request assigned to/i.test(content) || /request assigned to/i.test(existingAr))) {
|
|
1003
1265
|
content_ar = resolvedAr;
|
|
1004
1266
|
}
|
|
1005
1267
|
if (content &&
|
|
@@ -1011,6 +1273,15 @@ function enrichWorkflowLog(log) {
|
|
|
1011
1273
|
existingAr.includes(actors.roleName.trim())) {
|
|
1012
1274
|
content_ar = resolvedAr;
|
|
1013
1275
|
}
|
|
1276
|
+
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;
|
|
1277
|
+
if (content &&
|
|
1278
|
+
existingAr &&
|
|
1279
|
+
resolvedAr &&
|
|
1280
|
+
existingAr !== resolvedAr &&
|
|
1281
|
+
(itHelpdeskMixedEnglish.test(content) ||
|
|
1282
|
+
/routed to|routing completed|assignment path|\sby\s/i.test(existingAr))) {
|
|
1283
|
+
content_ar = resolvedAr;
|
|
1284
|
+
}
|
|
1014
1285
|
if ((content_ar == null || content_ar === '') && content) {
|
|
1015
1286
|
const notificationAr = resolveWorkflowContentAr(content, actors);
|
|
1016
1287
|
if (notificationAr)
|
package/package.json
CHANGED
|
@@ -131,6 +131,58 @@
|
|
|
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}}"
|
|
134
186
|
}
|
|
135
187
|
},
|
|
136
188
|
"chatTemplates": {
|
|
@@ -262,6 +314,10 @@
|
|
|
262
314
|
"Pending": "قيد الانتظار",
|
|
263
315
|
"Not Yet Started": "لم يبدأ بعد"
|
|
264
316
|
},
|
|
317
|
+
"roleLabels": {
|
|
318
|
+
"L3 Technical Support": "دعم المستوى الثالث (L3) التقني",
|
|
319
|
+
"IT Technician": "فني تكنولوجيا المعلومات"
|
|
320
|
+
},
|
|
265
321
|
"chatStatusLabels": {
|
|
266
322
|
"Submitted": "تم التقديم",
|
|
267
323
|
"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;
|
|
@@ -237,7 +238,15 @@ export function buildSynchronizedWorkflowMessage(ctx: WorkflowMessageContext): B
|
|
|
237
238
|
{ name: actorAr },
|
|
238
239
|
)
|
|
239
240
|
: workflowTemplate('request_approval_pending');
|
|
240
|
-
case 'approved':
|
|
241
|
+
case 'approved': {
|
|
242
|
+
const assignment = tryParseRequestAssignedComment(ctx.comment);
|
|
243
|
+
if (assignment) {
|
|
244
|
+
return buildRequestApprovedAssignedWorkflowFields({
|
|
245
|
+
...assignment,
|
|
246
|
+
roleName: ctx.roleName?.trim() || assignment.roleName,
|
|
247
|
+
roleArabicName: ctx.roleArabicName,
|
|
248
|
+
});
|
|
249
|
+
}
|
|
241
250
|
return actorEn
|
|
242
251
|
? renderSynchronizedWorkflowMessage(
|
|
243
252
|
'request_approved_by',
|
|
@@ -249,6 +258,7 @@ export function buildSynchronizedWorkflowMessage(ctx: WorkflowMessageContext): B
|
|
|
249
258
|
{ comment: commentWf },
|
|
250
259
|
{ comment: commentWf },
|
|
251
260
|
);
|
|
261
|
+
}
|
|
252
262
|
case 'rejected':
|
|
253
263
|
return actorEn
|
|
254
264
|
? renderSynchronizedWorkflowMessage(
|
|
@@ -354,14 +364,14 @@ export type RequestApprovedAssignedWorkflowParams = {
|
|
|
354
364
|
};
|
|
355
365
|
|
|
356
366
|
/** Parse legacy English-only assignment comments used as workflow log suffixes. */
|
|
357
|
-
|
|
358
|
-
|
|
367
|
+
function parseRequestAssignedCommentText(
|
|
368
|
+
text: string,
|
|
359
369
|
): Omit<RequestApprovedAssignedWorkflowParams, 'roleArabicName'> | null {
|
|
360
|
-
const
|
|
361
|
-
if (!
|
|
370
|
+
const normalized = text.trim();
|
|
371
|
+
if (!normalized) return null;
|
|
362
372
|
|
|
363
|
-
const technicianMatch =
|
|
364
|
-
/^
|
|
373
|
+
const technicianMatch = normalized.match(
|
|
374
|
+
/^request assigned to technician (.+?) by (.+?) \((.+?) - (.+?)\)$/i,
|
|
365
375
|
);
|
|
366
376
|
if (technicianMatch) {
|
|
367
377
|
return {
|
|
@@ -373,7 +383,7 @@ export function tryParseRequestAssignedComment(
|
|
|
373
383
|
};
|
|
374
384
|
}
|
|
375
385
|
|
|
376
|
-
const userMatch =
|
|
386
|
+
const userMatch = normalized.match(/^request assigned to (.+?) by (.+?) \((.+?) - (.+?)\)$/i);
|
|
377
387
|
if (userMatch) {
|
|
378
388
|
return {
|
|
379
389
|
assignedUserName: userMatch[1].trim(),
|
|
@@ -387,6 +397,45 @@ export function tryParseRequestAssignedComment(
|
|
|
387
397
|
return null;
|
|
388
398
|
}
|
|
389
399
|
|
|
400
|
+
export function tryParseRequestAssignedComment(
|
|
401
|
+
comment?: string | null,
|
|
402
|
+
): Omit<RequestApprovedAssignedWorkflowParams, 'roleArabicName'> | null {
|
|
403
|
+
let text = comment?.trim();
|
|
404
|
+
if (!text) return null;
|
|
405
|
+
|
|
406
|
+
if (text.startsWith(':')) {
|
|
407
|
+
text = text.replace(/^:\s*/, '').trim();
|
|
408
|
+
}
|
|
409
|
+
|
|
410
|
+
const direct = parseRequestAssignedCommentText(text);
|
|
411
|
+
if (direct) return direct;
|
|
412
|
+
|
|
413
|
+
const colonIdx = text.indexOf(': ');
|
|
414
|
+
if (colonIdx >= 0) {
|
|
415
|
+
const afterColon = text.slice(colonIdx + 2).trim();
|
|
416
|
+
const parsedAfterColon = parseRequestAssignedCommentText(afterColon);
|
|
417
|
+
if (parsedAfterColon) return parsedAfterColon;
|
|
418
|
+
}
|
|
419
|
+
|
|
420
|
+
const assignMatch = text.match(/request assigned to/i);
|
|
421
|
+
if (assignMatch && assignMatch.index != null && assignMatch.index >= 0) {
|
|
422
|
+
return parseRequestAssignedCommentText(text.slice(assignMatch.index).trim());
|
|
423
|
+
}
|
|
424
|
+
|
|
425
|
+
return null;
|
|
426
|
+
}
|
|
427
|
+
|
|
428
|
+
function buildAssignmentWorkflowFieldsFromActors(
|
|
429
|
+
assignment: Omit<RequestApprovedAssignedWorkflowParams, 'roleArabicName'>,
|
|
430
|
+
actors?: BilingualActorNames,
|
|
431
|
+
): BilingualText {
|
|
432
|
+
return buildRequestApprovedAssignedWorkflowFields({
|
|
433
|
+
...assignment,
|
|
434
|
+
roleName: actors?.roleName?.trim() || assignment.roleName,
|
|
435
|
+
roleArabicName: actors?.roleArabicName ?? null,
|
|
436
|
+
});
|
|
437
|
+
}
|
|
438
|
+
|
|
390
439
|
/** Bilingual workflow content for approved assignment steps (HR, IT, Tender, etc.). */
|
|
391
440
|
export function buildRequestApprovedAssignedWorkflowFields(
|
|
392
441
|
params: RequestApprovedAssignedWorkflowParams,
|
|
@@ -427,7 +476,10 @@ export function buildWorkflowLogUpdateFields(params: {
|
|
|
427
476
|
roleArabicName?: string | null;
|
|
428
477
|
comment?: string | null;
|
|
429
478
|
}): { content: string; content_ar: string; status: string; status_ar: string | null } {
|
|
430
|
-
|
|
479
|
+
const isApprovedLike =
|
|
480
|
+
params.approvalStatus === 'Approved' || params.approvalStatus === 'Assigned';
|
|
481
|
+
|
|
482
|
+
if (isApprovedLike) {
|
|
431
483
|
const assignment = tryParseRequestAssignedComment(params.comment);
|
|
432
484
|
if (assignment) {
|
|
433
485
|
const bilingual = buildRequestApprovedAssignedWorkflowFields({
|
|
@@ -445,7 +497,7 @@ export function buildWorkflowLogUpdateFields(params: {
|
|
|
445
497
|
}
|
|
446
498
|
|
|
447
499
|
let action: WorkflowMessageAction;
|
|
448
|
-
if (params.approvalStatus === 'Approved') action = 'approved';
|
|
500
|
+
if (params.approvalStatus === 'Approved' || params.approvalStatus === 'Assigned') action = 'approved';
|
|
449
501
|
else if (params.approvalStatus === 'Rejected') action = 'rejected';
|
|
450
502
|
else if (params.approvalStatus === 'Returned for Modification') action = 'returned_for_modification';
|
|
451
503
|
else action = 'approval_pending_update';
|
|
@@ -591,6 +643,23 @@ function formatColonCommentSuffix(comment?: string | null): string {
|
|
|
591
643
|
return text ? `: ${text}` : '';
|
|
592
644
|
}
|
|
593
645
|
|
|
646
|
+
function formatBilingualColonCommentSuffix(comment?: string | null): { en: string; ar: string } {
|
|
647
|
+
const text = comment?.trim();
|
|
648
|
+
if (!text) return { en: '', ar: '' };
|
|
649
|
+
const statusKey = text.charAt(0).toUpperCase() + text.slice(1).toLowerCase();
|
|
650
|
+
const arText = resolveChatStatusAr(statusKey) ?? text;
|
|
651
|
+
return { en: `: ${text}`, ar: `: ${arText}` };
|
|
652
|
+
}
|
|
653
|
+
|
|
654
|
+
function splitWorkflowColonComment(content: string): { base: string; comment?: string } {
|
|
655
|
+
const idx = content.indexOf(': ');
|
|
656
|
+
if (idx <= 0) return { base: content.trim() };
|
|
657
|
+
return {
|
|
658
|
+
base: content.slice(0, idx).trim(),
|
|
659
|
+
comment: content.slice(idx + 2).trim() || undefined,
|
|
660
|
+
};
|
|
661
|
+
}
|
|
662
|
+
|
|
594
663
|
function formatReassignCommentSuffix(comment?: string | null): string {
|
|
595
664
|
const text = comment?.trim();
|
|
596
665
|
return text ? `:${text}` : '';
|
|
@@ -935,7 +1004,53 @@ export type ItHelpdeskMuscatWorkflowParams =
|
|
|
935
1004
|
roleArabicName?: string | null;
|
|
936
1005
|
comment?: string | null;
|
|
937
1006
|
}
|
|
938
|
-
| { variant: 'routing_resolved' }
|
|
1007
|
+
| { variant: 'routing_resolved' }
|
|
1008
|
+
| {
|
|
1009
|
+
variant: 'routing_l3_reassign';
|
|
1010
|
+
userName: string;
|
|
1011
|
+
userArabicName?: string | null;
|
|
1012
|
+
comment?: string | null;
|
|
1013
|
+
}
|
|
1014
|
+
| {
|
|
1015
|
+
variant: 'routing_direct_approval';
|
|
1016
|
+
roleName: string;
|
|
1017
|
+
roleArabicName?: string | null;
|
|
1018
|
+
comment?: string | null;
|
|
1019
|
+
}
|
|
1020
|
+
| {
|
|
1021
|
+
variant: 'routing_decision';
|
|
1022
|
+
status: string;
|
|
1023
|
+
roleName: string;
|
|
1024
|
+
roleArabicName?: string | null;
|
|
1025
|
+
comment?: string | null;
|
|
1026
|
+
}
|
|
1027
|
+
| {
|
|
1028
|
+
variant: 'l3_assignment_pending';
|
|
1029
|
+
roleName: string;
|
|
1030
|
+
roleArabicName?: string | null;
|
|
1031
|
+
comment?: string | null;
|
|
1032
|
+
}
|
|
1033
|
+
| {
|
|
1034
|
+
variant: 'l3_role_approved' | 'l3_role_rejected';
|
|
1035
|
+
roleName: string;
|
|
1036
|
+
roleArabicName?: string | null;
|
|
1037
|
+
comment?: string | null;
|
|
1038
|
+
}
|
|
1039
|
+
| {
|
|
1040
|
+
variant: 'role_outcome_by_user_rejected' | 'role_outcome_by_user_closed';
|
|
1041
|
+
roleName: string;
|
|
1042
|
+
roleArabicName?: string | null;
|
|
1043
|
+
userName: string;
|
|
1044
|
+
userArabicName?: string | null;
|
|
1045
|
+
comment?: string | null;
|
|
1046
|
+
}
|
|
1047
|
+
| { variant: 'routing_technician_rejected'; comment?: string | null }
|
|
1048
|
+
| {
|
|
1049
|
+
variant: 'hos_not_required_rejected' | 'hos_not_required_closed' | 'l3_not_required_rejected' | 'l3_not_required_closed';
|
|
1050
|
+
userName: string;
|
|
1051
|
+
userArabicName?: string | null;
|
|
1052
|
+
comment?: string | null;
|
|
1053
|
+
};
|
|
939
1054
|
|
|
940
1055
|
function resolveItHelpdeskGenericStatusAr(status: string): string {
|
|
941
1056
|
switch (status.trim()) {
|
|
@@ -1100,6 +1215,102 @@ export function buildItHelpdeskMuscatWorkflowLog(params: ItHelpdeskMuscatWorkflo
|
|
|
1100
1215
|
);
|
|
1101
1216
|
case 'routing_resolved':
|
|
1102
1217
|
return workflowTemplate('it_helpdesk_wf_routing_resolved');
|
|
1218
|
+
case 'routing_l3_reassign': {
|
|
1219
|
+
const userEn = params.userName.trim();
|
|
1220
|
+
const userAr = resolveBilingualName(userEn, params.userArabicName);
|
|
1221
|
+
return renderSynchronizedWorkflowMessage(
|
|
1222
|
+
'it_helpdesk_wf_routing_l3_reassign',
|
|
1223
|
+
{ userName: userEn, comment },
|
|
1224
|
+
{ userName: userAr, comment },
|
|
1225
|
+
);
|
|
1226
|
+
}
|
|
1227
|
+
case 'routing_direct_approval': {
|
|
1228
|
+
const roleEn = params.roleName.trim();
|
|
1229
|
+
const roleAr = resolveBilingualName(roleEn, params.roleArabicName);
|
|
1230
|
+
return renderSynchronizedWorkflowMessage(
|
|
1231
|
+
'it_helpdesk_wf_routing_direct_approval',
|
|
1232
|
+
{ roleName: roleEn, comment },
|
|
1233
|
+
{ roleName: roleAr, comment },
|
|
1234
|
+
);
|
|
1235
|
+
}
|
|
1236
|
+
case 'routing_decision': {
|
|
1237
|
+
const roleEn = params.roleName.trim();
|
|
1238
|
+
const roleAr = resolveBilingualName(roleEn, params.roleArabicName);
|
|
1239
|
+
const statusEn = params.status.toLowerCase();
|
|
1240
|
+
const statusAr = resolveItHelpdeskGenericStatusAr(params.status);
|
|
1241
|
+
return renderSynchronizedWorkflowMessage(
|
|
1242
|
+
'it_helpdesk_wf_routing_decision',
|
|
1243
|
+
{ status: statusEn, statusAr, roleName: roleEn, comment },
|
|
1244
|
+
{ status: statusEn, statusAr, roleName: roleAr, comment },
|
|
1245
|
+
);
|
|
1246
|
+
}
|
|
1247
|
+
case 'l3_assignment_pending': {
|
|
1248
|
+
const roleEn = params.roleName.trim();
|
|
1249
|
+
const roleAr = resolveBilingualName(roleEn, params.roleArabicName);
|
|
1250
|
+
return renderSynchronizedWorkflowMessage(
|
|
1251
|
+
'it_helpdesk_wf_l3_assignment_pending',
|
|
1252
|
+
{ roleName: roleEn, comment },
|
|
1253
|
+
{ roleName: roleAr, comment },
|
|
1254
|
+
);
|
|
1255
|
+
}
|
|
1256
|
+
case 'l3_role_approved':
|
|
1257
|
+
case 'l3_role_rejected': {
|
|
1258
|
+
const roleEn = params.roleName.trim();
|
|
1259
|
+
const roleAr = resolveBilingualName(
|
|
1260
|
+
roleEn,
|
|
1261
|
+
params.roleArabicName ?? ROLE_LABELS[roleEn] ?? null,
|
|
1262
|
+
);
|
|
1263
|
+
const biComment = formatBilingualColonCommentSuffix(params.comment);
|
|
1264
|
+
const key =
|
|
1265
|
+
params.variant === 'l3_role_approved'
|
|
1266
|
+
? 'it_helpdesk_wf_l3_role_approved'
|
|
1267
|
+
: 'it_helpdesk_wf_l3_role_rejected';
|
|
1268
|
+
return renderSynchronizedWorkflowMessage(
|
|
1269
|
+
key,
|
|
1270
|
+
{ roleName: roleEn, comment: biComment.en },
|
|
1271
|
+
{ roleName: roleAr, commentAr: biComment.ar },
|
|
1272
|
+
);
|
|
1273
|
+
}
|
|
1274
|
+
case 'role_outcome_by_user_rejected':
|
|
1275
|
+
case 'role_outcome_by_user_closed': {
|
|
1276
|
+
const roleEn = params.roleName.trim();
|
|
1277
|
+
const roleAr = resolveBilingualName(roleEn, params.roleArabicName);
|
|
1278
|
+
const userEn = params.userName.trim();
|
|
1279
|
+
const userAr = resolveBilingualName(userEn, params.userArabicName);
|
|
1280
|
+
const key =
|
|
1281
|
+
params.variant === 'role_outcome_by_user_rejected'
|
|
1282
|
+
? 'it_helpdesk_wf_role_outcome_by_user_rejected'
|
|
1283
|
+
: 'it_helpdesk_wf_role_outcome_by_user_closed';
|
|
1284
|
+
return renderSynchronizedWorkflowMessage(
|
|
1285
|
+
key,
|
|
1286
|
+
{ roleName: roleEn, userName: userEn, comment },
|
|
1287
|
+
{ roleName: roleAr, userName: userAr, comment },
|
|
1288
|
+
);
|
|
1289
|
+
}
|
|
1290
|
+
case 'routing_technician_rejected':
|
|
1291
|
+
return renderSynchronizedWorkflowMessage(
|
|
1292
|
+
'it_helpdesk_wf_routing_technician_rejected',
|
|
1293
|
+
{ comment },
|
|
1294
|
+
{ comment },
|
|
1295
|
+
);
|
|
1296
|
+
case 'hos_not_required_rejected':
|
|
1297
|
+
case 'hos_not_required_closed':
|
|
1298
|
+
case 'l3_not_required_rejected':
|
|
1299
|
+
case 'l3_not_required_closed': {
|
|
1300
|
+
const userEn = params.userName.trim();
|
|
1301
|
+
const userAr = resolveBilingualName(userEn, params.userArabicName);
|
|
1302
|
+
const keyMap = {
|
|
1303
|
+
hos_not_required_rejected: 'it_helpdesk_wf_hos_not_required_rejected',
|
|
1304
|
+
hos_not_required_closed: 'it_helpdesk_wf_hos_not_required_closed',
|
|
1305
|
+
l3_not_required_rejected: 'it_helpdesk_wf_l3_not_required_rejected',
|
|
1306
|
+
l3_not_required_closed: 'it_helpdesk_wf_l3_not_required_closed',
|
|
1307
|
+
} as const;
|
|
1308
|
+
return renderSynchronizedWorkflowMessage(
|
|
1309
|
+
keyMap[params.variant],
|
|
1310
|
+
{ userName: userEn, comment },
|
|
1311
|
+
{ userName: userAr, comment },
|
|
1312
|
+
);
|
|
1313
|
+
}
|
|
1103
1314
|
default:
|
|
1104
1315
|
return workflowTemplate('request_submitted');
|
|
1105
1316
|
}
|
|
@@ -1236,19 +1447,24 @@ function resolveArabicChatRoleName(
|
|
|
1236
1447
|
parsedEnglishRole?: string,
|
|
1237
1448
|
): string {
|
|
1238
1449
|
const parsed = parsedEnglishRole?.trim();
|
|
1239
|
-
if (
|
|
1240
|
-
|
|
1241
|
-
|
|
1242
|
-
|
|
1450
|
+
if (parsed) {
|
|
1451
|
+
if (
|
|
1452
|
+
actors?.roleName?.trim() &&
|
|
1453
|
+
parsed.toLowerCase() === actors.roleName.trim().toLowerCase()
|
|
1454
|
+
) {
|
|
1455
|
+
return resolveBilingualName(parsed, actors.roleArabicName);
|
|
1243
1456
|
}
|
|
1457
|
+
const catalogAr = ROLE_LABELS[parsed];
|
|
1458
|
+
if (catalogAr) return catalogAr;
|
|
1459
|
+
return parsed;
|
|
1244
1460
|
}
|
|
1245
|
-
if (actors?.
|
|
1246
|
-
return resolveBilingualName(
|
|
1461
|
+
if (actors?.roleName?.trim()) {
|
|
1462
|
+
return resolveBilingualName(actors.roleName, actors.roleArabicName);
|
|
1247
1463
|
}
|
|
1248
1464
|
if (actors?.userName?.trim()) {
|
|
1249
1465
|
return resolveBilingualName(actors.userName, actors.userArabicName);
|
|
1250
1466
|
}
|
|
1251
|
-
return
|
|
1467
|
+
return '';
|
|
1252
1468
|
}
|
|
1253
1469
|
|
|
1254
1470
|
function escapeRegexLiteral(value: string): string {
|
|
@@ -1348,6 +1564,14 @@ function buildArabicWorkflowTemplateParams(
|
|
|
1348
1564
|
params.status.charAt(0).toUpperCase() + params.status.slice(1).toLowerCase();
|
|
1349
1565
|
arParams.statusAr = resolveItHelpdeskGenericStatusAr(normalizedStatus);
|
|
1350
1566
|
}
|
|
1567
|
+
if (params.userName !== undefined) {
|
|
1568
|
+
arParams.userName = actors?.userName?.trim()
|
|
1569
|
+
? resolveBilingualName(actors.userName, actors.userArabicName)
|
|
1570
|
+
: resolveBilingualName(params.userName.trim(), actors?.userArabicName);
|
|
1571
|
+
}
|
|
1572
|
+
if (params.commentAr !== undefined) {
|
|
1573
|
+
arParams.commentAr = params.commentAr;
|
|
1574
|
+
}
|
|
1351
1575
|
return arParams;
|
|
1352
1576
|
}
|
|
1353
1577
|
|
|
@@ -1361,6 +1585,146 @@ function listWorkflowTemplatesBySpecificity(): Array<[string, BilingualText]> {
|
|
|
1361
1585
|
);
|
|
1362
1586
|
}
|
|
1363
1587
|
|
|
1588
|
+
/** Parse legacy IT Helpdesk Muscat EN workflow strings before generic template matching. */
|
|
1589
|
+
function tryResolveItHelpdeskMuscatLegacyWorkflowAr(
|
|
1590
|
+
content: string,
|
|
1591
|
+
actors?: BilingualActorNames,
|
|
1592
|
+
): string | null {
|
|
1593
|
+
const { base, comment } = splitWorkflowColonComment(content);
|
|
1594
|
+
|
|
1595
|
+
let m = base.match(/^Workflow routed to L3 assignment path - request reassigned by (.+)$/i);
|
|
1596
|
+
if (m) {
|
|
1597
|
+
return buildItHelpdeskMuscatWorkflowLog({
|
|
1598
|
+
variant: 'routing_l3_reassign',
|
|
1599
|
+
userName: m[1].trim(),
|
|
1600
|
+
userArabicName: actors?.userArabicName,
|
|
1601
|
+
comment,
|
|
1602
|
+
}).ar;
|
|
1603
|
+
}
|
|
1604
|
+
|
|
1605
|
+
m = base.match(/^Workflow routed to direct resolution path - request approved by (.+)$/i);
|
|
1606
|
+
if (m) {
|
|
1607
|
+
return buildItHelpdeskMuscatWorkflowLog({
|
|
1608
|
+
variant: 'routing_direct_approval',
|
|
1609
|
+
roleName: m[1].trim(),
|
|
1610
|
+
roleArabicName: actors?.roleArabicName,
|
|
1611
|
+
comment,
|
|
1612
|
+
}).ar;
|
|
1613
|
+
}
|
|
1614
|
+
|
|
1615
|
+
m = base.match(/^Workflow decision made - (\w+) by (.+)$/i);
|
|
1616
|
+
if (m) {
|
|
1617
|
+
return buildItHelpdeskMuscatWorkflowLog({
|
|
1618
|
+
variant: 'routing_decision',
|
|
1619
|
+
status: m[1],
|
|
1620
|
+
roleName: m[2].trim(),
|
|
1621
|
+
roleArabicName: actors?.roleArabicName,
|
|
1622
|
+
comment,
|
|
1623
|
+
}).ar;
|
|
1624
|
+
}
|
|
1625
|
+
|
|
1626
|
+
m = base.match(/^L3 Technical Support assignment pending - request reassigned by (.+)$/i);
|
|
1627
|
+
if (m) {
|
|
1628
|
+
return buildItHelpdeskMuscatWorkflowLog({
|
|
1629
|
+
variant: 'l3_assignment_pending',
|
|
1630
|
+
roleName: m[1].trim(),
|
|
1631
|
+
roleArabicName: actors?.roleArabicName,
|
|
1632
|
+
comment,
|
|
1633
|
+
}).ar;
|
|
1634
|
+
}
|
|
1635
|
+
|
|
1636
|
+
m = base.match(/^L3 Technical Support approved the request$/i);
|
|
1637
|
+
if (m) {
|
|
1638
|
+
return buildItHelpdeskMuscatWorkflowLog({
|
|
1639
|
+
variant: 'l3_role_approved',
|
|
1640
|
+
roleName: 'L3 Technical Support',
|
|
1641
|
+
comment,
|
|
1642
|
+
}).ar;
|
|
1643
|
+
}
|
|
1644
|
+
|
|
1645
|
+
m = base.match(/^L3 Technical Support rejected the request$/i);
|
|
1646
|
+
if (m) {
|
|
1647
|
+
return buildItHelpdeskMuscatWorkflowLog({
|
|
1648
|
+
variant: 'l3_role_rejected',
|
|
1649
|
+
roleName: 'L3 Technical Support',
|
|
1650
|
+
comment,
|
|
1651
|
+
}).ar;
|
|
1652
|
+
}
|
|
1653
|
+
|
|
1654
|
+
m = base.match(/^(.+?) rejected the request by (.+)$/i);
|
|
1655
|
+
if (m && !m[1].toLowerCase().includes('workflow')) {
|
|
1656
|
+
return buildItHelpdeskMuscatWorkflowLog({
|
|
1657
|
+
variant: 'role_outcome_by_user_rejected',
|
|
1658
|
+
roleName: m[1].trim(),
|
|
1659
|
+
roleArabicName: actors?.roleArabicName,
|
|
1660
|
+
userName: m[2].trim(),
|
|
1661
|
+
userArabicName: actors?.userArabicName,
|
|
1662
|
+
comment,
|
|
1663
|
+
}).ar;
|
|
1664
|
+
}
|
|
1665
|
+
|
|
1666
|
+
m = base.match(/^(.+?) closed the request by (.+)$/i);
|
|
1667
|
+
if (m) {
|
|
1668
|
+
return buildItHelpdeskMuscatWorkflowLog({
|
|
1669
|
+
variant: 'role_outcome_by_user_closed',
|
|
1670
|
+
roleName: m[1].trim(),
|
|
1671
|
+
roleArabicName: actors?.roleArabicName,
|
|
1672
|
+
userName: m[2].trim(),
|
|
1673
|
+
userArabicName: actors?.userArabicName,
|
|
1674
|
+
comment,
|
|
1675
|
+
}).ar;
|
|
1676
|
+
}
|
|
1677
|
+
|
|
1678
|
+
if (/^Workflow routing completed - request rejected at technician level$/i.test(base)) {
|
|
1679
|
+
return buildItHelpdeskMuscatWorkflowLog({
|
|
1680
|
+
variant: 'routing_technician_rejected',
|
|
1681
|
+
comment,
|
|
1682
|
+
}).ar;
|
|
1683
|
+
}
|
|
1684
|
+
|
|
1685
|
+
m = base.match(/^HOS notification not required, request rejected by (.+)$/i);
|
|
1686
|
+
if (m) {
|
|
1687
|
+
return buildItHelpdeskMuscatWorkflowLog({
|
|
1688
|
+
variant: 'hos_not_required_rejected',
|
|
1689
|
+
userName: m[1].trim(),
|
|
1690
|
+
userArabicName: actors?.userArabicName,
|
|
1691
|
+
comment,
|
|
1692
|
+
}).ar;
|
|
1693
|
+
}
|
|
1694
|
+
|
|
1695
|
+
m = base.match(/^HOS notification not required, request closed by (.+)$/i);
|
|
1696
|
+
if (m) {
|
|
1697
|
+
return buildItHelpdeskMuscatWorkflowLog({
|
|
1698
|
+
variant: 'hos_not_required_closed',
|
|
1699
|
+
userName: m[1].trim(),
|
|
1700
|
+
userArabicName: actors?.userArabicName,
|
|
1701
|
+
comment,
|
|
1702
|
+
}).ar;
|
|
1703
|
+
}
|
|
1704
|
+
|
|
1705
|
+
m = base.match(/^L3 assignment not required, request rejected by (.+)$/i);
|
|
1706
|
+
if (m) {
|
|
1707
|
+
return buildItHelpdeskMuscatWorkflowLog({
|
|
1708
|
+
variant: 'l3_not_required_rejected',
|
|
1709
|
+
userName: m[1].trim(),
|
|
1710
|
+
userArabicName: actors?.userArabicName,
|
|
1711
|
+
comment,
|
|
1712
|
+
}).ar;
|
|
1713
|
+
}
|
|
1714
|
+
|
|
1715
|
+
m = base.match(/^L3 assignment not required, request closed by (.+)$/i);
|
|
1716
|
+
if (m) {
|
|
1717
|
+
return buildItHelpdeskMuscatWorkflowLog({
|
|
1718
|
+
variant: 'l3_not_required_closed',
|
|
1719
|
+
userName: m[1].trim(),
|
|
1720
|
+
userArabicName: actors?.userArabicName,
|
|
1721
|
+
comment,
|
|
1722
|
+
}).ar;
|
|
1723
|
+
}
|
|
1724
|
+
|
|
1725
|
+
return null;
|
|
1726
|
+
}
|
|
1727
|
+
|
|
1364
1728
|
export function resolveWorkflowContentAr(
|
|
1365
1729
|
content: string | null | undefined,
|
|
1366
1730
|
actors?: BilingualActorNames,
|
|
@@ -1368,6 +1732,14 @@ export function resolveWorkflowContentAr(
|
|
|
1368
1732
|
if (content == null || content.trim() === '') return null;
|
|
1369
1733
|
const normalized = content.trim();
|
|
1370
1734
|
|
|
1735
|
+
const embeddedAssignment = tryParseRequestAssignedComment(normalized);
|
|
1736
|
+
if (embeddedAssignment) {
|
|
1737
|
+
return buildAssignmentWorkflowFieldsFromActors(embeddedAssignment, actors).ar;
|
|
1738
|
+
}
|
|
1739
|
+
|
|
1740
|
+
const itHelpdeskLegacyAr = tryResolveItHelpdeskMuscatLegacyWorkflowAr(normalized, actors);
|
|
1741
|
+
if (itHelpdeskLegacyAr) return itHelpdeskLegacyAr;
|
|
1742
|
+
|
|
1371
1743
|
for (const tpl of Object.values(WORKFLOW_TEMPLATES)) {
|
|
1372
1744
|
if (tpl.en === normalized || tpl.en.toLowerCase() === normalized.toLowerCase()) return tpl.ar;
|
|
1373
1745
|
}
|
|
@@ -1383,6 +1755,10 @@ export function resolveWorkflowContentAr(
|
|
|
1383
1755
|
if (commentIdx > 0) {
|
|
1384
1756
|
const baseEn = normalized.slice(0, commentIdx).trim();
|
|
1385
1757
|
const commentText = normalized.slice(commentIdx + 2).trim();
|
|
1758
|
+
const assignment = tryParseRequestAssignedComment(commentText);
|
|
1759
|
+
if (assignment) {
|
|
1760
|
+
return buildAssignmentWorkflowFieldsFromActors(assignment, actors).ar;
|
|
1761
|
+
}
|
|
1386
1762
|
const commentSuffix = formatWorkflowCommentSuffix(commentText);
|
|
1387
1763
|
|
|
1388
1764
|
for (const tpl of Object.values(WORKFLOW_TEMPLATES)) {
|
|
@@ -1502,7 +1878,7 @@ export function enrichWorkflowLog(log: Record<string, unknown>): Record<string,
|
|
|
1502
1878
|
existingAr &&
|
|
1503
1879
|
resolvedAr &&
|
|
1504
1880
|
existingAr !== resolvedAr &&
|
|
1505
|
-
/
|
|
1881
|
+
(/request assigned to/i.test(content) || /request assigned to/i.test(existingAr))
|
|
1506
1882
|
) {
|
|
1507
1883
|
content_ar = resolvedAr;
|
|
1508
1884
|
}
|
|
@@ -1517,6 +1893,18 @@ export function enrichWorkflowLog(log: Record<string, unknown>): Record<string,
|
|
|
1517
1893
|
) {
|
|
1518
1894
|
content_ar = resolvedAr;
|
|
1519
1895
|
}
|
|
1896
|
+
const itHelpdeskMixedEnglish =
|
|
1897
|
+
/routed to L3|assignment path|Workflow decision made|L3 Technical Support approved|L3 assignment not required|HOS notification not required|routing completed/i;
|
|
1898
|
+
if (
|
|
1899
|
+
content &&
|
|
1900
|
+
existingAr &&
|
|
1901
|
+
resolvedAr &&
|
|
1902
|
+
existingAr !== resolvedAr &&
|
|
1903
|
+
(itHelpdeskMixedEnglish.test(content) ||
|
|
1904
|
+
/routed to|routing completed|assignment path|\sby\s/i.test(existingAr))
|
|
1905
|
+
) {
|
|
1906
|
+
content_ar = resolvedAr;
|
|
1907
|
+
}
|
|
1520
1908
|
if ((content_ar == null || content_ar === '') && content) {
|
|
1521
1909
|
const notificationAr = resolveWorkflowContentAr(content, actors);
|
|
1522
1910
|
if (notificationAr) content_ar = notificationAr;
|