@platform-modules/civil-aviation-authority 2.3.291 → 2.3.293
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/data-source.js +4 -0
- package/dist/i18n/workflow-chat-i18n.json +54 -42
- package/dist/i18n/workflow-chat-message.builder.d.ts +21 -0
- package/dist/i18n/workflow-chat-message.builder.js +270 -33
- package/dist/index.d.ts +2 -0
- package/dist/index.js +2 -0
- package/dist/models/ContractServiceRequestDocumentModel.d.ts +13 -0
- package/dist/models/ContractServiceRequestDocumentModel.js +60 -0
- package/dist/models/ContractServiceRequestModel.d.ts +2 -0
- package/dist/models/ContractServiceRequestModel.js +8 -0
- package/dist/models/FollowUpReportItemModel.d.ts +20 -0
- package/dist/models/FollowUpReportItemModel.js +90 -0
- package/dist/models/FollowUpReportRequestModel.d.ts +12 -1
- package/dist/models/FollowUpReportRequestModel.js +27 -1
- package/dist/models/RespondToEnquiriesAttachmentModel.d.ts +2 -1
- package/dist/models/RespondToEnquiriesAttachmentModel.js +7 -2
- package/package.json +1 -1
- package/sql/caa_api_payload_changes_2026_07.sql +40 -0
- package/src/data-source.ts +4 -0
- package/src/i18n/workflow-chat-i18n.json +54 -42
- package/src/i18n/workflow-chat-message.builder.ts +333 -31
- package/src/index.ts +4 -1
- package/src/models/ContractServiceRequestDocumentModel.ts +35 -0
- package/src/models/ContractServiceRequestModel.ts +6 -0
- package/src/models/FollowUpReportItemModel.ts +59 -0
- package/src/models/FollowUpReportRequestModel.ts +24 -0
- package/src/models/RespondToEnquiriesAttachmentModel.ts +6 -1
|
@@ -20,9 +20,12 @@ exports.workflowTemplate = workflowTemplate;
|
|
|
20
20
|
exports.chatTemplate = chatTemplate;
|
|
21
21
|
exports.buildSynchronizedWorkflowMessage = buildSynchronizedWorkflowMessage;
|
|
22
22
|
exports.buildSynchronizedChatMessage = buildSynchronizedChatMessage;
|
|
23
|
+
exports.tryParseRequestAssignedComment = tryParseRequestAssignedComment;
|
|
24
|
+
exports.buildRequestApprovedAssignedWorkflowFields = buildRequestApprovedAssignedWorkflowFields;
|
|
23
25
|
exports.buildWorkflowLogUpdateFields = buildWorkflowLogUpdateFields;
|
|
24
26
|
exports.toWorkflowPersistFields = toWorkflowPersistFields;
|
|
25
27
|
exports.toChatPersistFields = toChatPersistFields;
|
|
28
|
+
exports.buildUserEnteredChatPersistFields = buildUserEnteredChatPersistFields;
|
|
26
29
|
exports.buildApprovalWorkflowContent = buildApprovalWorkflowContent;
|
|
27
30
|
exports.buildHumanApprovalWorkflowContent = buildHumanApprovalWorkflowContent;
|
|
28
31
|
exports.buildApprovalChatMessage = buildApprovalChatMessage;
|
|
@@ -49,6 +52,7 @@ exports.resolveChatStatusAr = resolveChatStatusAr;
|
|
|
49
52
|
exports.extractBilingualActorsFromRecord = extractBilingualActorsFromRecord;
|
|
50
53
|
exports.resolveWorkflowContentAr = resolveWorkflowContentAr;
|
|
51
54
|
exports.resolveChatMessageAr = resolveChatMessageAr;
|
|
55
|
+
exports.isSystemGeneratedChatMessage = isSystemGeneratedChatMessage;
|
|
52
56
|
exports.enrichWorkflowLog = enrichWorkflowLog;
|
|
53
57
|
exports.enrichChatMessage = enrichChatMessage;
|
|
54
58
|
/**
|
|
@@ -231,9 +235,73 @@ function buildSynchronizedChatMessage(ctx) {
|
|
|
231
235
|
return chatTemplate('request_received');
|
|
232
236
|
}
|
|
233
237
|
}
|
|
234
|
-
|
|
238
|
+
/** Parse legacy English-only assignment comments used as workflow log suffixes. */
|
|
239
|
+
function tryParseRequestAssignedComment(comment) {
|
|
240
|
+
const text = comment?.trim();
|
|
241
|
+
if (!text)
|
|
242
|
+
return null;
|
|
243
|
+
const technicianMatch = text.match(/^Request assigned to technician (.+?) by (.+?) \((.+?) - (.+?)\)$/);
|
|
244
|
+
if (technicianMatch) {
|
|
245
|
+
return {
|
|
246
|
+
assignedUserName: technicianMatch[1].trim(),
|
|
247
|
+
roleName: technicianMatch[2].trim(),
|
|
248
|
+
actorUserName: technicianMatch[3].trim(),
|
|
249
|
+
employeeId: technicianMatch[4].trim(),
|
|
250
|
+
assigneeLabel: 'technician',
|
|
251
|
+
};
|
|
252
|
+
}
|
|
253
|
+
const userMatch = text.match(/^Request assigned to (.+?) by (.+?) \((.+?) - (.+?)\)$/);
|
|
254
|
+
if (userMatch) {
|
|
255
|
+
return {
|
|
256
|
+
assignedUserName: userMatch[1].trim(),
|
|
257
|
+
roleName: userMatch[2].trim(),
|
|
258
|
+
actorUserName: userMatch[3].trim(),
|
|
259
|
+
employeeId: userMatch[4].trim(),
|
|
260
|
+
assigneeLabel: 'user',
|
|
261
|
+
};
|
|
262
|
+
}
|
|
263
|
+
return null;
|
|
264
|
+
}
|
|
265
|
+
/** Bilingual workflow content for approved assignment steps (HR, IT, Tender, etc.). */
|
|
266
|
+
function buildRequestApprovedAssignedWorkflowFields(params) {
|
|
267
|
+
const assignedUserEn = params.assignedUserName?.trim() || 'User';
|
|
268
|
+
const roleEn = params.roleName?.trim() || 'Approver';
|
|
269
|
+
const roleAr = resolveBilingualName(roleEn, params.roleArabicName);
|
|
270
|
+
const actorEn = params.actorUserName?.trim() || 'User';
|
|
271
|
+
const employeeId = String(params.employeeId ?? 'N/A');
|
|
272
|
+
const templateKey = params.assigneeLabel === 'technician'
|
|
273
|
+
? 'request_approved_assigned_to_technician'
|
|
274
|
+
: 'request_approved_assigned_to_user';
|
|
275
|
+
return renderSynchronizedWorkflowMessage(templateKey, {
|
|
276
|
+
assignedUserName: assignedUserEn,
|
|
277
|
+
roleName: roleEn,
|
|
278
|
+
actorUserName: actorEn,
|
|
279
|
+
employeeId,
|
|
280
|
+
}, {
|
|
281
|
+
assignedUserName: assignedUserEn,
|
|
282
|
+
roleName: roleAr,
|
|
283
|
+
actorUserName: actorEn,
|
|
284
|
+
employeeId,
|
|
285
|
+
});
|
|
286
|
+
}
|
|
235
287
|
/** Standard workflow log UPDATE fields for all CAA module repositories. */
|
|
236
288
|
function buildWorkflowLogUpdateFields(params) {
|
|
289
|
+
if (params.approvalStatus === 'Approved') {
|
|
290
|
+
const assignment = tryParseRequestAssignedComment(params.comment);
|
|
291
|
+
if (assignment) {
|
|
292
|
+
const bilingual = buildRequestApprovedAssignedWorkflowFields({
|
|
293
|
+
...assignment,
|
|
294
|
+
roleName: params.roleName?.trim() || assignment.roleName,
|
|
295
|
+
roleArabicName: params.roleArabicName,
|
|
296
|
+
});
|
|
297
|
+
return {
|
|
298
|
+
content: bilingual.en,
|
|
299
|
+
content_ar: bilingual.ar,
|
|
300
|
+
status: params.workflowStatus,
|
|
301
|
+
status_ar: resolveWorkflowStatusAr(params.workflowStatus),
|
|
302
|
+
};
|
|
303
|
+
}
|
|
304
|
+
}
|
|
237
305
|
let action;
|
|
238
306
|
if (params.approvalStatus === 'Approved')
|
|
239
307
|
action = 'approved';
|
|
@@ -274,6 +342,15 @@ function toChatPersistFields(bilingual, status) {
|
|
|
274
342
|
status_ar: resolveChatStatusAr(status),
|
|
275
343
|
};
|
|
276
344
|
}
|
|
345
|
+
/** User-typed chat — never auto-translate; message_ar stays null. */
|
|
346
|
+
function buildUserEnteredChatPersistFields(message, status) {
|
|
347
|
+
return {
|
|
348
|
+
message,
|
|
349
|
+
message_ar: null,
|
|
350
|
+
status,
|
|
351
|
+
status_ar: resolveChatStatusAr(status),
|
|
352
|
+
};
|
|
353
|
+
}
|
|
277
354
|
function buildApprovalWorkflowContent(params) {
|
|
278
355
|
const status = params.status;
|
|
279
356
|
let action;
|
|
@@ -505,6 +582,22 @@ function buildItHelpdeskReassignModifiers(params) {
|
|
|
505
582
|
}
|
|
506
583
|
return { en, ar };
|
|
507
584
|
}
|
|
585
|
+
function resolveItHelpdeskGenericStatusAr(status) {
|
|
586
|
+
switch (status.trim()) {
|
|
587
|
+
case 'Approved':
|
|
588
|
+
return 'تمت الموافقة على';
|
|
589
|
+
case 'Rejected':
|
|
590
|
+
return 'تم رفض';
|
|
591
|
+
case 'Closed':
|
|
592
|
+
return 'تم إغلاق';
|
|
593
|
+
case 'Assigned':
|
|
594
|
+
return 'تم تعيين';
|
|
595
|
+
case 'Reassigned':
|
|
596
|
+
return 'تمت إعادة تعيين';
|
|
597
|
+
default:
|
|
598
|
+
return resolveChatStatusAr(status) ?? status.toLowerCase();
|
|
599
|
+
}
|
|
600
|
+
}
|
|
508
601
|
function buildItHelpdeskMuscatWorkflowLog(params) {
|
|
509
602
|
const comment = formatColonCommentSuffix('comment' in params ? params.comment : undefined);
|
|
510
603
|
const modifiers = 'modifiers' in params && params.modifiers ? params.modifiers : { en: '', ar: '' };
|
|
@@ -579,7 +672,7 @@ function buildItHelpdeskMuscatWorkflowLog(params) {
|
|
|
579
672
|
const approverEn = params.approverRoleName.trim();
|
|
580
673
|
const approverAr = resolveBilingualName(approverEn, params.approverRoleArabicName);
|
|
581
674
|
const statusEn = params.status.toLowerCase();
|
|
582
|
-
const statusAr =
|
|
675
|
+
const statusAr = resolveItHelpdeskGenericStatusAr(params.status);
|
|
583
676
|
return renderSynchronizedWorkflowMessage('it_helpdesk_wf_status_by_role', { status: statusEn, statusAr, approverRoleName: approverEn, comment }, { status: statusEn, statusAr, approverRoleName: approverAr, comment });
|
|
584
677
|
}
|
|
585
678
|
case 'technician_completed': {
|
|
@@ -681,22 +774,124 @@ function resolveArabicWorkflowActorName(actors, parsedEnglishName) {
|
|
|
681
774
|
}
|
|
682
775
|
/** Arabic role/user label for chat templates. */
|
|
683
776
|
function resolveArabicChatRoleName(actors, parsedEnglishRole) {
|
|
777
|
+
const parsed = parsedEnglishRole?.trim();
|
|
684
778
|
if (actors?.roleName?.trim()) {
|
|
685
|
-
|
|
779
|
+
const actorRole = actors.roleName.trim();
|
|
780
|
+
if (!parsed || parsed.toLowerCase() === actorRole.toLowerCase()) {
|
|
781
|
+
return resolveBilingualName(actorRole, actors.roleArabicName);
|
|
782
|
+
}
|
|
783
|
+
}
|
|
784
|
+
if (actors?.roleArabicName?.trim() && parsed) {
|
|
785
|
+
return resolveBilingualName(parsed, actors.roleArabicName);
|
|
686
786
|
}
|
|
687
787
|
if (actors?.userName?.trim()) {
|
|
688
788
|
return resolveBilingualName(actors.userName, actors.userArabicName);
|
|
689
789
|
}
|
|
690
|
-
return resolveBilingualName(
|
|
790
|
+
return resolveBilingualName(parsed, actors?.roleArabicName);
|
|
791
|
+
}
|
|
792
|
+
function escapeRegexLiteral(value) {
|
|
793
|
+
return value.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
|
|
794
|
+
}
|
|
795
|
+
/** Match a templated EN message and extract placeholder values (full-structure match). */
|
|
796
|
+
function matchTemplateMessage(templateEn, message) {
|
|
797
|
+
if (!/\{\{\w+\}\}/.test(templateEn))
|
|
798
|
+
return null;
|
|
799
|
+
const captures = [];
|
|
800
|
+
let regexBody = '';
|
|
801
|
+
let cursor = 0;
|
|
802
|
+
let groupIndex = 0;
|
|
803
|
+
const tokenRe = /\{\{(\w+)\}\}/g;
|
|
804
|
+
let tokenMatch;
|
|
805
|
+
while ((tokenMatch = tokenRe.exec(templateEn)) !== null) {
|
|
806
|
+
regexBody += escapeRegexLiteral(templateEn.slice(cursor, tokenMatch.index));
|
|
807
|
+
const key = tokenMatch[1];
|
|
808
|
+
const afterToken = templateEn.slice(tokenMatch.index + tokenMatch[0].length);
|
|
809
|
+
if (key === 'comment') {
|
|
810
|
+
groupIndex += 1;
|
|
811
|
+
captures.push({ key, groupIndex });
|
|
812
|
+
regexBody += '(.*)';
|
|
813
|
+
cursor = tokenMatch.index + tokenMatch[0].length;
|
|
814
|
+
continue;
|
|
815
|
+
}
|
|
816
|
+
if (afterToken.startsWith('{{comment}}')) {
|
|
817
|
+
groupIndex += 1;
|
|
818
|
+
captures.push({ key, groupIndex });
|
|
819
|
+
groupIndex += 1;
|
|
820
|
+
captures.push({ key: 'comment', groupIndex });
|
|
821
|
+
regexBody += '([^:]+?)(: .*)?';
|
|
822
|
+
tokenRe.lastIndex = tokenMatch.index + tokenMatch[0].length + '{{comment}}'.length;
|
|
823
|
+
cursor = tokenRe.lastIndex;
|
|
824
|
+
continue;
|
|
825
|
+
}
|
|
826
|
+
groupIndex += 1;
|
|
827
|
+
captures.push({ key, groupIndex });
|
|
828
|
+
regexBody += '(.+?)';
|
|
829
|
+
cursor = tokenMatch.index + tokenMatch[0].length;
|
|
830
|
+
}
|
|
831
|
+
regexBody += escapeRegexLiteral(templateEn.slice(cursor));
|
|
832
|
+
const match = message.match(new RegExp(`^${regexBody}$`, 's'));
|
|
833
|
+
if (!match)
|
|
834
|
+
return null;
|
|
835
|
+
const params = {};
|
|
836
|
+
captures.forEach(({ key, groupIndex: idx }) => {
|
|
837
|
+
params[key] = match[idx] ?? '';
|
|
838
|
+
});
|
|
839
|
+
return params;
|
|
840
|
+
}
|
|
841
|
+
function buildArabicChatTemplateParams(params, actors) {
|
|
842
|
+
const arParams = { ...params };
|
|
843
|
+
if (params.roleName !== undefined) {
|
|
844
|
+
arParams.roleName = resolveArabicChatRoleName(actors, params.roleName.trim());
|
|
845
|
+
}
|
|
846
|
+
if (params.userName !== undefined) {
|
|
847
|
+
arParams.userName = actors?.userName?.trim()
|
|
848
|
+
? resolveBilingualName(actors.userName, actors.userArabicName)
|
|
849
|
+
: resolveBilingualName(params.userName.trim(), actors?.userArabicName);
|
|
850
|
+
}
|
|
851
|
+
return arParams;
|
|
852
|
+
}
|
|
853
|
+
function buildArabicWorkflowTemplateParams(params, actors) {
|
|
854
|
+
const arParams = { ...params };
|
|
855
|
+
if (params.roleName !== undefined) {
|
|
856
|
+
arParams.roleName = resolveArabicChatRoleName(actors, params.roleName.trim());
|
|
857
|
+
}
|
|
858
|
+
if (params.approverRoleName !== undefined) {
|
|
859
|
+
arParams.approverRoleName = resolveArabicChatRoleName(actors, params.approverRoleName.trim());
|
|
860
|
+
}
|
|
861
|
+
if (params.assignedRoleName !== undefined) {
|
|
862
|
+
arParams.assignedRoleName = resolveArabicChatRoleName(actors, params.assignedRoleName.trim());
|
|
863
|
+
}
|
|
864
|
+
if (params.name !== undefined) {
|
|
865
|
+
arParams.name = resolveArabicWorkflowActorName(actors, params.name.trim());
|
|
866
|
+
}
|
|
867
|
+
if (params.status !== undefined && params.statusAr === undefined) {
|
|
868
|
+
const normalizedStatus = params.status.charAt(0).toUpperCase() + params.status.slice(1).toLowerCase();
|
|
869
|
+
arParams.statusAr = resolveItHelpdeskGenericStatusAr(normalizedStatus);
|
|
870
|
+
}
|
|
871
|
+
return arParams;
|
|
872
|
+
}
|
|
873
|
+
function countTemplatePlaceholders(templateEn) {
|
|
874
|
+
return (templateEn.match(/\{\{\w+\}\}/g) || []).length;
|
|
875
|
+
}
|
|
876
|
+
function listWorkflowTemplatesBySpecificity() {
|
|
877
|
+
return Object.entries(WORKFLOW_TEMPLATES).sort(([, a], [, b]) => countTemplatePlaceholders(b.en) - countTemplatePlaceholders(a.en));
|
|
691
878
|
}
|
|
692
879
|
function resolveWorkflowContentAr(content, actors) {
|
|
693
880
|
if (content == null || content.trim() === '')
|
|
694
881
|
return null;
|
|
695
882
|
const normalized = content.trim();
|
|
696
883
|
for (const tpl of Object.values(WORKFLOW_TEMPLATES)) {
|
|
697
|
-
if (tpl.en === normalized)
|
|
884
|
+
if (tpl.en === normalized || tpl.en.toLowerCase() === normalized.toLowerCase())
|
|
698
885
|
return tpl.ar;
|
|
699
886
|
}
|
|
887
|
+
for (const [, tpl] of listWorkflowTemplatesBySpecificity()) {
|
|
888
|
+
if (!/\{\{\w+\}\}/.test(tpl.en))
|
|
889
|
+
continue;
|
|
890
|
+
const params = matchTemplateMessage(tpl.en, normalized);
|
|
891
|
+
if (!params)
|
|
892
|
+
continue;
|
|
893
|
+
return interpolate(tpl.ar, buildArabicWorkflowTemplateParams(params, actors));
|
|
894
|
+
}
|
|
700
895
|
const commentIdx = normalized.indexOf(': ');
|
|
701
896
|
if (commentIdx > 0) {
|
|
702
897
|
const baseEn = normalized.slice(0, commentIdx).trim();
|
|
@@ -731,6 +926,28 @@ function resolveWorkflowContentAr(content, actors) {
|
|
|
731
926
|
const nameAr = resolveArabicWorkflowActorName(actors, namePartEn);
|
|
732
927
|
return interpolate(WORKFLOW_TEMPLATES.request_approval_pending_from.ar, { name: nameAr });
|
|
733
928
|
}
|
|
929
|
+
// Legacy HR worker strings (pre-i18n catalog)
|
|
930
|
+
if (normalized === 'Send Notification') {
|
|
931
|
+
return WORKFLOW_TEMPLATES.notification_sent_pending?.ar ?? null;
|
|
932
|
+
}
|
|
933
|
+
const notificationSuccessVariants = [
|
|
934
|
+
'notification sent successfully',
|
|
935
|
+
'notification sent sucessfully',
|
|
936
|
+
'notification sent',
|
|
937
|
+
];
|
|
938
|
+
if (notificationSuccessVariants.includes(normalized.toLowerCase())) {
|
|
939
|
+
return WORKFLOW_TEMPLATES.notification_sent_successfully?.ar ?? null;
|
|
940
|
+
}
|
|
941
|
+
const legacyPendingPrefix = 'Approval pending from ';
|
|
942
|
+
if (normalized.startsWith(legacyPendingPrefix)) {
|
|
943
|
+
const namePartEn = normalized.slice(legacyPendingPrefix.length).trim();
|
|
944
|
+
const nameAr = resolveArabicWorkflowActorName(actors, namePartEn);
|
|
945
|
+
return interpolate(WORKFLOW_TEMPLATES.request_approval_pending_from.ar, { name: nameAr });
|
|
946
|
+
}
|
|
947
|
+
if (normalized === 'Approval Pending from HR Section' ||
|
|
948
|
+
normalized === 'Approval Pending from Records Department') {
|
|
949
|
+
return WORKFLOW_TEMPLATES.request_approval_pending?.ar ?? null;
|
|
950
|
+
}
|
|
734
951
|
return null;
|
|
735
952
|
}
|
|
736
953
|
function resolveChatMessageAr(message, actors) {
|
|
@@ -741,47 +958,67 @@ function resolveChatMessageAr(message, actors) {
|
|
|
741
958
|
if (tpl.en === normalized)
|
|
742
959
|
return tpl.ar;
|
|
743
960
|
}
|
|
744
|
-
for (const tplKey of ['request_submitted_by', 'cancellation_submitted_by']) {
|
|
745
|
-
const submittedTpl = CHAT_TEMPLATES[tplKey];
|
|
746
|
-
if (!submittedTpl)
|
|
747
|
-
continue;
|
|
748
|
-
const prefix = submittedTpl.en.split('{{userName}}')[0];
|
|
749
|
-
if (!normalized.startsWith(prefix))
|
|
750
|
-
continue;
|
|
751
|
-
const afterPrefix = normalized.slice(prefix.length);
|
|
752
|
-
const parenMatch = afterPrefix.match(/^(.+?) \((.+)\)$/);
|
|
753
|
-
if (parenMatch) {
|
|
754
|
-
const userEn = parenMatch[1].trim();
|
|
755
|
-
const employeeId = parenMatch[2].trim();
|
|
756
|
-
const userAr = actors?.userName?.trim()
|
|
757
|
-
? resolveBilingualName(actors.userName, actors.userArabicName)
|
|
758
|
-
: resolveBilingualName(userEn, actors?.userArabicName);
|
|
759
|
-
return interpolate(submittedTpl.ar, { userName: userAr, employeeId });
|
|
760
|
-
}
|
|
761
|
-
}
|
|
762
961
|
for (const tpl of Object.values(CHAT_TEMPLATES)) {
|
|
763
|
-
if (
|
|
962
|
+
if (!/\{\{\w+\}\}/.test(tpl.en))
|
|
764
963
|
continue;
|
|
765
|
-
const
|
|
766
|
-
if (!
|
|
964
|
+
const params = matchTemplateMessage(tpl.en, normalized);
|
|
965
|
+
if (!params)
|
|
767
966
|
continue;
|
|
768
|
-
|
|
769
|
-
const commentIdx = rest.lastIndexOf(' - ');
|
|
770
|
-
const roleNameEn = commentIdx >= 0 ? rest.slice(0, commentIdx) : rest;
|
|
771
|
-
const commentSuffix = commentIdx >= 0 ? rest.slice(commentIdx) : '';
|
|
772
|
-
const roleNameAr = resolveArabicChatRoleName(actors, roleNameEn.trim());
|
|
773
|
-
return interpolate(tpl.ar, { roleName: roleNameAr, comment: commentSuffix });
|
|
967
|
+
return interpolate(tpl.ar, buildArabicChatTemplateParams(params, actors));
|
|
774
968
|
}
|
|
775
969
|
return null;
|
|
776
970
|
}
|
|
971
|
+
/** True when message matches a known system chat template (safe to resolve message_ar). */
|
|
972
|
+
function isSystemGeneratedChatMessage(message, actors) {
|
|
973
|
+
return resolveChatMessageAr(message, actors) != null;
|
|
974
|
+
}
|
|
777
975
|
/** Generic workflow log enricher — use in all module repositories. */
|
|
778
976
|
function enrichWorkflowLog(log) {
|
|
779
977
|
const status = log.status != null ? String(log.status) : null;
|
|
780
978
|
const content = log.content != null ? String(log.content) : null;
|
|
781
979
|
const actors = extractBilingualActorsFromRecord(log);
|
|
980
|
+
const resolvedAr = resolveWorkflowContentAr(content, actors);
|
|
981
|
+
const existingAr = log.content_ar != null && String(log.content_ar).trim() !== ''
|
|
982
|
+
? String(log.content_ar)
|
|
983
|
+
: null;
|
|
984
|
+
// Re-resolve when stored AR still embeds the English actor parsed from `content`.
|
|
985
|
+
const pendingPrefix = WORKFLOW_TEMPLATES.request_approval_pending_from?.en.split('{{name}}')[0].trim();
|
|
986
|
+
let content_ar = existingAr ?? resolvedAr;
|
|
987
|
+
if (content &&
|
|
988
|
+
pendingPrefix &&
|
|
989
|
+
content.startsWith(pendingPrefix) &&
|
|
990
|
+
existingAr &&
|
|
991
|
+
resolvedAr &&
|
|
992
|
+
existingAr !== resolvedAr) {
|
|
993
|
+
const namePartEn = content.slice(pendingPrefix.length).trim();
|
|
994
|
+
if (namePartEn && existingAr.includes(namePartEn)) {
|
|
995
|
+
content_ar = resolvedAr;
|
|
996
|
+
}
|
|
997
|
+
}
|
|
998
|
+
if (content &&
|
|
999
|
+
existingAr &&
|
|
1000
|
+
resolvedAr &&
|
|
1001
|
+
existingAr !== resolvedAr &&
|
|
1002
|
+
/Request assigned to/i.test(existingAr)) {
|
|
1003
|
+
content_ar = resolvedAr;
|
|
1004
|
+
}
|
|
1005
|
+
if (content &&
|
|
1006
|
+
existingAr &&
|
|
1007
|
+
resolvedAr &&
|
|
1008
|
+
existingAr !== resolvedAr &&
|
|
1009
|
+
actors?.roleName?.trim() &&
|
|
1010
|
+
actors?.roleArabicName?.trim() &&
|
|
1011
|
+
existingAr.includes(actors.roleName.trim())) {
|
|
1012
|
+
content_ar = resolvedAr;
|
|
1013
|
+
}
|
|
1014
|
+
if ((content_ar == null || content_ar === '') && content) {
|
|
1015
|
+
const notificationAr = resolveWorkflowContentAr(content, actors);
|
|
1016
|
+
if (notificationAr)
|
|
1017
|
+
content_ar = notificationAr;
|
|
1018
|
+
}
|
|
782
1019
|
return {
|
|
783
1020
|
...log,
|
|
784
|
-
content_ar
|
|
1021
|
+
content_ar,
|
|
785
1022
|
status_ar: log.status_ar ?? resolveWorkflowStatusAr(status),
|
|
786
1023
|
};
|
|
787
1024
|
}
|
package/dist/index.d.ts
CHANGED
|
@@ -354,6 +354,7 @@ export * from './models/MaintenanceAttachmentModel';
|
|
|
354
354
|
export * from './models/MaintenanceChatModel';
|
|
355
355
|
export * from './models/MaintenanceWorkflowModel';
|
|
356
356
|
export * from './models/FollowUpReportRequestModel';
|
|
357
|
+
export * from './models/FollowUpReportItemModel';
|
|
357
358
|
export * from './models/FollowUpReportApprovalModel';
|
|
358
359
|
export * from './models/FollowUpReportAttachmentModel';
|
|
359
360
|
export * from './models/FollowUpReportChatModel';
|
|
@@ -408,6 +409,7 @@ export { RespondToEnquiriesRequestAttachment } from './models/RespondToEnquiries
|
|
|
408
409
|
export * from './models/RequestATenderRequestModel';
|
|
409
410
|
export * from './models/RequestTenderAnalysisRequestModel';
|
|
410
411
|
export * from './models/ContractServiceRequestModel';
|
|
412
|
+
export * from './models/ContractServiceRequestDocumentModel';
|
|
411
413
|
export * from './models/SlaConfigModel';
|
|
412
414
|
export * from './models/SlaRequestModel';
|
|
413
415
|
export * from './models/SlaMyRequestsViewModel';
|
package/dist/index.js
CHANGED
|
@@ -527,6 +527,7 @@ __exportStar(require("./models/MaintenanceAttachmentModel"), exports);
|
|
|
527
527
|
__exportStar(require("./models/MaintenanceChatModel"), exports);
|
|
528
528
|
__exportStar(require("./models/MaintenanceWorkflowModel"), exports);
|
|
529
529
|
__exportStar(require("./models/FollowUpReportRequestModel"), exports);
|
|
530
|
+
__exportStar(require("./models/FollowUpReportItemModel"), exports);
|
|
530
531
|
__exportStar(require("./models/FollowUpReportApprovalModel"), exports);
|
|
531
532
|
__exportStar(require("./models/FollowUpReportAttachmentModel"), exports);
|
|
532
533
|
__exportStar(require("./models/FollowUpReportChatModel"), exports);
|
|
@@ -597,6 +598,7 @@ Object.defineProperty(exports, "RespondToEnquiriesRequestAttachment", { enumerab
|
|
|
597
598
|
__exportStar(require("./models/RequestATenderRequestModel"), exports);
|
|
598
599
|
__exportStar(require("./models/RequestTenderAnalysisRequestModel"), exports);
|
|
599
600
|
__exportStar(require("./models/ContractServiceRequestModel"), exports);
|
|
601
|
+
__exportStar(require("./models/ContractServiceRequestDocumentModel"), exports);
|
|
600
602
|
__exportStar(require("./models/SlaConfigModel"), exports);
|
|
601
603
|
__exportStar(require("./models/SlaRequestModel"), exports);
|
|
602
604
|
__exportStar(require("./models/SlaMyRequestsViewModel"), exports);
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { BaseModel } from './BaseModel';
|
|
2
|
+
export declare class ContractServiceRequestDocument extends BaseModel {
|
|
3
|
+
request_id: number;
|
|
4
|
+
service_id: number | null;
|
|
5
|
+
sub_service_id: number | null;
|
|
6
|
+
document_name: string;
|
|
7
|
+
description: string | null;
|
|
8
|
+
file_url: string;
|
|
9
|
+
file_name: string | null;
|
|
10
|
+
file_type: string | null;
|
|
11
|
+
file_size: number | null;
|
|
12
|
+
uploaded_by: number;
|
|
13
|
+
}
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
|
|
3
|
+
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
4
|
+
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
|
5
|
+
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
|
|
6
|
+
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
7
|
+
};
|
|
8
|
+
var __metadata = (this && this.__metadata) || function (k, v) {
|
|
9
|
+
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
|
|
10
|
+
};
|
|
11
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
12
|
+
exports.ContractServiceRequestDocument = void 0;
|
|
13
|
+
const typeorm_1 = require("typeorm");
|
|
14
|
+
const BaseModel_1 = require("./BaseModel");
|
|
15
|
+
let ContractServiceRequestDocument = class ContractServiceRequestDocument extends BaseModel_1.BaseModel {
|
|
16
|
+
};
|
|
17
|
+
exports.ContractServiceRequestDocument = ContractServiceRequestDocument;
|
|
18
|
+
__decorate([
|
|
19
|
+
(0, typeorm_1.Column)({ type: 'integer', nullable: false }),
|
|
20
|
+
__metadata("design:type", Number)
|
|
21
|
+
], ContractServiceRequestDocument.prototype, "request_id", void 0);
|
|
22
|
+
__decorate([
|
|
23
|
+
(0, typeorm_1.Column)({ type: 'integer', nullable: true }),
|
|
24
|
+
__metadata("design:type", Object)
|
|
25
|
+
], ContractServiceRequestDocument.prototype, "service_id", void 0);
|
|
26
|
+
__decorate([
|
|
27
|
+
(0, typeorm_1.Column)({ type: 'integer', nullable: true }),
|
|
28
|
+
__metadata("design:type", Object)
|
|
29
|
+
], ContractServiceRequestDocument.prototype, "sub_service_id", void 0);
|
|
30
|
+
__decorate([
|
|
31
|
+
(0, typeorm_1.Column)({ type: 'varchar', length: 500, nullable: false }),
|
|
32
|
+
__metadata("design:type", String)
|
|
33
|
+
], ContractServiceRequestDocument.prototype, "document_name", void 0);
|
|
34
|
+
__decorate([
|
|
35
|
+
(0, typeorm_1.Column)({ type: 'text', nullable: true }),
|
|
36
|
+
__metadata("design:type", Object)
|
|
37
|
+
], ContractServiceRequestDocument.prototype, "description", void 0);
|
|
38
|
+
__decorate([
|
|
39
|
+
(0, typeorm_1.Column)({ type: 'varchar', length: 500, nullable: false }),
|
|
40
|
+
__metadata("design:type", String)
|
|
41
|
+
], ContractServiceRequestDocument.prototype, "file_url", void 0);
|
|
42
|
+
__decorate([
|
|
43
|
+
(0, typeorm_1.Column)({ type: 'varchar', length: 255, nullable: true }),
|
|
44
|
+
__metadata("design:type", Object)
|
|
45
|
+
], ContractServiceRequestDocument.prototype, "file_name", void 0);
|
|
46
|
+
__decorate([
|
|
47
|
+
(0, typeorm_1.Column)({ type: 'varchar', length: 100, nullable: true }),
|
|
48
|
+
__metadata("design:type", Object)
|
|
49
|
+
], ContractServiceRequestDocument.prototype, "file_type", void 0);
|
|
50
|
+
__decorate([
|
|
51
|
+
(0, typeorm_1.Column)({ type: 'bigint', nullable: true }),
|
|
52
|
+
__metadata("design:type", Object)
|
|
53
|
+
], ContractServiceRequestDocument.prototype, "file_size", void 0);
|
|
54
|
+
__decorate([
|
|
55
|
+
(0, typeorm_1.Column)({ type: 'integer', nullable: false }),
|
|
56
|
+
__metadata("design:type", Number)
|
|
57
|
+
], ContractServiceRequestDocument.prototype, "uploaded_by", void 0);
|
|
58
|
+
exports.ContractServiceRequestDocument = ContractServiceRequestDocument = __decorate([
|
|
59
|
+
(0, typeorm_1.Entity)({ name: 'contract_service_request_documents' })
|
|
60
|
+
], ContractServiceRequestDocument);
|
|
@@ -14,6 +14,8 @@ export declare class ContractServiceRequest extends BaseModel {
|
|
|
14
14
|
request_id: string | null;
|
|
15
15
|
project_or_budget_code: string;
|
|
16
16
|
company_name: string;
|
|
17
|
+
company_phone_number: string | null;
|
|
18
|
+
notes: string | null;
|
|
17
19
|
status: RespondToEnquiriesRequestStatus;
|
|
18
20
|
reviewer_user_id: number | null;
|
|
19
21
|
assigned_to_user_id: number | null;
|
|
@@ -68,6 +68,14 @@ __decorate([
|
|
|
68
68
|
(0, typeorm_1.Column)({ type: "varchar", length: 255, nullable: false }),
|
|
69
69
|
__metadata("design:type", String)
|
|
70
70
|
], ContractServiceRequest.prototype, "company_name", void 0);
|
|
71
|
+
__decorate([
|
|
72
|
+
(0, typeorm_1.Column)({ type: "varchar", length: 30, nullable: true }),
|
|
73
|
+
__metadata("design:type", Object)
|
|
74
|
+
], ContractServiceRequest.prototype, "company_phone_number", void 0);
|
|
75
|
+
__decorate([
|
|
76
|
+
(0, typeorm_1.Column)({ type: "text", nullable: true }),
|
|
77
|
+
__metadata("design:type", Object)
|
|
78
|
+
], ContractServiceRequest.prototype, "notes", void 0);
|
|
71
79
|
__decorate([
|
|
72
80
|
(0, typeorm_1.Column)({
|
|
73
81
|
type: "enum",
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { BaseModel } from './BaseModel';
|
|
2
|
+
import { FollowUpReportSubjectClassification } from './FollowUpReportRequestModel';
|
|
3
|
+
export declare class FollowUpReportItem extends BaseModel {
|
|
4
|
+
request_id: number;
|
|
5
|
+
service_id: number | null;
|
|
6
|
+
sub_service_id: number | null;
|
|
7
|
+
reference_type: string | null;
|
|
8
|
+
letter_date: Date | null;
|
|
9
|
+
subject: string | null;
|
|
10
|
+
subject_classification: FollowUpReportSubjectClassification | null;
|
|
11
|
+
general_manager_comment: string | null;
|
|
12
|
+
response_date_target: string | null;
|
|
13
|
+
action_status: string | null;
|
|
14
|
+
action_taken: string | null;
|
|
15
|
+
delay_period: string | null;
|
|
16
|
+
file_url: string | null;
|
|
17
|
+
file_name: string | null;
|
|
18
|
+
file_type: string | null;
|
|
19
|
+
file_size: number | null;
|
|
20
|
+
}
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
|
|
3
|
+
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
4
|
+
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
|
5
|
+
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
|
|
6
|
+
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
7
|
+
};
|
|
8
|
+
var __metadata = (this && this.__metadata) || function (k, v) {
|
|
9
|
+
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
|
|
10
|
+
};
|
|
11
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
12
|
+
exports.FollowUpReportItem = void 0;
|
|
13
|
+
const typeorm_1 = require("typeorm");
|
|
14
|
+
const BaseModel_1 = require("./BaseModel");
|
|
15
|
+
const FollowUpReportRequestModel_1 = require("./FollowUpReportRequestModel");
|
|
16
|
+
let FollowUpReportItem = class FollowUpReportItem extends BaseModel_1.BaseModel {
|
|
17
|
+
};
|
|
18
|
+
exports.FollowUpReportItem = FollowUpReportItem;
|
|
19
|
+
__decorate([
|
|
20
|
+
(0, typeorm_1.Column)({ type: 'integer', nullable: false }),
|
|
21
|
+
__metadata("design:type", Number)
|
|
22
|
+
], FollowUpReportItem.prototype, "request_id", void 0);
|
|
23
|
+
__decorate([
|
|
24
|
+
(0, typeorm_1.Column)({ type: 'integer', nullable: true }),
|
|
25
|
+
__metadata("design:type", Object)
|
|
26
|
+
], FollowUpReportItem.prototype, "service_id", void 0);
|
|
27
|
+
__decorate([
|
|
28
|
+
(0, typeorm_1.Column)({ type: 'integer', nullable: true }),
|
|
29
|
+
__metadata("design:type", Object)
|
|
30
|
+
], FollowUpReportItem.prototype, "sub_service_id", void 0);
|
|
31
|
+
__decorate([
|
|
32
|
+
(0, typeorm_1.Column)({ type: 'varchar', length: 100, nullable: true }),
|
|
33
|
+
__metadata("design:type", Object)
|
|
34
|
+
], FollowUpReportItem.prototype, "reference_type", void 0);
|
|
35
|
+
__decorate([
|
|
36
|
+
(0, typeorm_1.Column)({ type: 'date', nullable: true }),
|
|
37
|
+
__metadata("design:type", Object)
|
|
38
|
+
], FollowUpReportItem.prototype, "letter_date", void 0);
|
|
39
|
+
__decorate([
|
|
40
|
+
(0, typeorm_1.Column)({ type: 'varchar', length: 500, nullable: true }),
|
|
41
|
+
__metadata("design:type", Object)
|
|
42
|
+
], FollowUpReportItem.prototype, "subject", void 0);
|
|
43
|
+
__decorate([
|
|
44
|
+
(0, typeorm_1.Column)({
|
|
45
|
+
type: 'enum',
|
|
46
|
+
enum: FollowUpReportRequestModel_1.FollowUpReportSubjectClassification,
|
|
47
|
+
enumName: 'maintenance_subject_classification_en',
|
|
48
|
+
nullable: true,
|
|
49
|
+
}),
|
|
50
|
+
__metadata("design:type", Object)
|
|
51
|
+
], FollowUpReportItem.prototype, "subject_classification", void 0);
|
|
52
|
+
__decorate([
|
|
53
|
+
(0, typeorm_1.Column)({ type: 'varchar', length: 500, nullable: true }),
|
|
54
|
+
__metadata("design:type", Object)
|
|
55
|
+
], FollowUpReportItem.prototype, "general_manager_comment", void 0);
|
|
56
|
+
__decorate([
|
|
57
|
+
(0, typeorm_1.Column)({ type: 'varchar', length: 255, nullable: true }),
|
|
58
|
+
__metadata("design:type", Object)
|
|
59
|
+
], FollowUpReportItem.prototype, "response_date_target", void 0);
|
|
60
|
+
__decorate([
|
|
61
|
+
(0, typeorm_1.Column)({ type: 'varchar', length: 255, nullable: true }),
|
|
62
|
+
__metadata("design:type", Object)
|
|
63
|
+
], FollowUpReportItem.prototype, "action_status", void 0);
|
|
64
|
+
__decorate([
|
|
65
|
+
(0, typeorm_1.Column)({ type: 'text', nullable: true }),
|
|
66
|
+
__metadata("design:type", Object)
|
|
67
|
+
], FollowUpReportItem.prototype, "action_taken", void 0);
|
|
68
|
+
__decorate([
|
|
69
|
+
(0, typeorm_1.Column)({ type: 'varchar', length: 100, nullable: true }),
|
|
70
|
+
__metadata("design:type", Object)
|
|
71
|
+
], FollowUpReportItem.prototype, "delay_period", void 0);
|
|
72
|
+
__decorate([
|
|
73
|
+
(0, typeorm_1.Column)({ type: 'varchar', length: 500, nullable: true }),
|
|
74
|
+
__metadata("design:type", Object)
|
|
75
|
+
], FollowUpReportItem.prototype, "file_url", void 0);
|
|
76
|
+
__decorate([
|
|
77
|
+
(0, typeorm_1.Column)({ type: 'varchar', length: 255, nullable: true }),
|
|
78
|
+
__metadata("design:type", Object)
|
|
79
|
+
], FollowUpReportItem.prototype, "file_name", void 0);
|
|
80
|
+
__decorate([
|
|
81
|
+
(0, typeorm_1.Column)({ type: 'varchar', length: 100, nullable: true }),
|
|
82
|
+
__metadata("design:type", Object)
|
|
83
|
+
], FollowUpReportItem.prototype, "file_type", void 0);
|
|
84
|
+
__decorate([
|
|
85
|
+
(0, typeorm_1.Column)({ type: 'bigint', nullable: true }),
|
|
86
|
+
__metadata("design:type", Object)
|
|
87
|
+
], FollowUpReportItem.prototype, "file_size", void 0);
|
|
88
|
+
exports.FollowUpReportItem = FollowUpReportItem = __decorate([
|
|
89
|
+
(0, typeorm_1.Entity)({ name: 'followup_report_items' })
|
|
90
|
+
], FollowUpReportItem);
|
|
@@ -5,8 +5,14 @@ export declare enum FollowUpReportSubjectClassification {
|
|
|
5
5
|
VERY_URGENT = "Very Urgent",
|
|
6
6
|
CONFIDENTIAL = "Confidential",
|
|
7
7
|
INFORMATIONAL = "Informational",
|
|
8
|
-
NORMAL = "Normal"
|
|
8
|
+
NORMAL = "Normal",
|
|
9
|
+
IMPORTANT = "Important",
|
|
10
|
+
HIGHLY_CONFIDENTIAL = "Highly Confidential",
|
|
11
|
+
RESTRICTED = "Restricted",
|
|
12
|
+
LIMITED = "Limited"
|
|
9
13
|
}
|
|
14
|
+
/** Allowed API/DB values for follow-up report subject classification. */
|
|
15
|
+
export declare const FOLLOW_UP_REPORT_SUBJECT_CLASSIFICATION_VALUES: FollowUpReportSubjectClassification[];
|
|
10
16
|
/** Concerned department under General Manager of Support Services */
|
|
11
17
|
export declare enum FollowUpReportConcernedDepartment {
|
|
12
18
|
IT = "IT",
|
|
@@ -36,6 +42,11 @@ export declare class FollowUpReportRequests extends BaseModel {
|
|
|
36
42
|
concerned_department: FollowUpReportConcernedDepartment;
|
|
37
43
|
date_from: Date;
|
|
38
44
|
date_to: Date;
|
|
45
|
+
general_manager_comment: string | null;
|
|
46
|
+
response_date_target: string | null;
|
|
47
|
+
action_status: string | null;
|
|
48
|
+
action_taken: string | null;
|
|
49
|
+
delay_period: string | null;
|
|
39
50
|
request_submission_date: Date;
|
|
40
51
|
status: FollowUpReportRequestStatus;
|
|
41
52
|
workflow_execution_id: string | null;
|