@platform-modules/civil-aviation-authority 2.3.274 → 2.3.277
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/.env +10 -10
- package/dist/i18n/workflow-chat-i18n.d.ts +40 -0
- package/dist/i18n/workflow-chat-i18n.js +140 -0
- package/dist/i18n/workflow-chat-i18n.json +78 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.js +1 -0
- package/dist/models/CancellationChatModel.d.ts +2 -0
- package/dist/models/CancellationChatModel.js +8 -0
- package/dist/models/CancellationWorkflowModel.d.ts +2 -0
- package/dist/models/CancellationWorkflowModel.js +8 -0
- package/package.json +3 -3
- package/sql/add_cancellation_workflow_chat_arabic_columns.sql +10 -0
- package/src/i18n/workflow-chat-i18n.json +78 -0
- package/src/i18n/workflow-chat-i18n.ts +169 -0
- package/src/index.ts +2 -1
- package/src/models/CancellationChatModel.ts +6 -0
- package/src/models/CancellationWorkflowModel.ts +6 -0
- package/tsconfig.json +1 -0
package/.env
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
1
|
+
DB_HOST=164.52.222.169
|
|
2
|
+
DB_PORT=5432
|
|
3
|
+
DB_USER=postgres_admin_user
|
|
4
|
+
DB_PASS=pg_admin_user_pwd_caa_fa_$%^&OIukhjgcvbn
|
|
5
|
+
DB_NAME=CAA
|
|
6
6
|
|
|
7
7
|
|
|
8
8
|
# DB_HOST=localhost
|
|
@@ -11,8 +11,8 @@
|
|
|
11
11
|
# DB_PASS=stevejobs
|
|
12
12
|
# DB_NAME=CAA
|
|
13
13
|
|
|
14
|
-
DB_HOST=10.44.3.201
|
|
15
|
-
DB_PORT=5432
|
|
16
|
-
DB_USER=appuser
|
|
17
|
-
DB_PASS=HamaCaa7489
|
|
18
|
-
DB_NAME=caa_prd_db
|
|
14
|
+
# DB_HOST=10.44.3.201
|
|
15
|
+
# DB_PORT=5432
|
|
16
|
+
# DB_USER=appuser
|
|
17
|
+
# DB_PASS=HamaCaa7489
|
|
18
|
+
# DB_NAME=caa_prd_db
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
export type BilingualText = {
|
|
2
|
+
en: string;
|
|
3
|
+
ar: string;
|
|
4
|
+
};
|
|
5
|
+
type WorkflowChatI18nCatalog = {
|
|
6
|
+
workflowTemplates: Record<string, BilingualText>;
|
|
7
|
+
chatTemplates: Record<string, BilingualText>;
|
|
8
|
+
workflowStatusLabels: Record<string, string>;
|
|
9
|
+
chatStatusLabels: Record<string, string>;
|
|
10
|
+
};
|
|
11
|
+
/** Read-only view of the shared workflow/chat translation catalog. */
|
|
12
|
+
export declare function getWorkflowChatI18nCatalog(): WorkflowChatI18nCatalog;
|
|
13
|
+
export declare function buildBilingualFromTemplate(templateCatalog: Record<string, BilingualText>, key: string, params?: Record<string, string>): BilingualText;
|
|
14
|
+
export declare function workflowTemplate(key: string, params?: Record<string, string>): BilingualText;
|
|
15
|
+
export declare function chatTemplate(key: string, params?: Record<string, string>): BilingualText;
|
|
16
|
+
export declare function resolveWorkflowStatusAr(status: string | null | undefined): string | null;
|
|
17
|
+
export declare function resolveChatStatusAr(status: string | null | undefined): string | null;
|
|
18
|
+
export declare function pickLocalizedName(englishName?: string | null, arabicName?: string | null, fallback?: string): string;
|
|
19
|
+
export declare function buildApprovalWorkflowContent(params: {
|
|
20
|
+
status: 'Approved' | 'Rejected' | 'Pending' | string;
|
|
21
|
+
roleName?: string | null;
|
|
22
|
+
roleArabicName?: string | null;
|
|
23
|
+
comment?: string | null;
|
|
24
|
+
}): BilingualText;
|
|
25
|
+
export declare function buildHumanApprovalWorkflowContent(params: {
|
|
26
|
+
isFirst: boolean;
|
|
27
|
+
roleName?: string | null;
|
|
28
|
+
roleArabicName?: string | null;
|
|
29
|
+
deptSectionEn?: string | null;
|
|
30
|
+
deptSectionAr?: string | null;
|
|
31
|
+
}): BilingualText;
|
|
32
|
+
export declare function buildApprovalChatMessage(params: {
|
|
33
|
+
status: 'Approved' | 'Rejected' | string;
|
|
34
|
+
roleName?: string | null;
|
|
35
|
+
roleArabicName?: string | null;
|
|
36
|
+
comment?: string | null;
|
|
37
|
+
}): BilingualText;
|
|
38
|
+
export declare function enrichCancellationWorkflowLog(log: Record<string, unknown>): Record<string, unknown>;
|
|
39
|
+
export declare function enrichCancellationChatMessage(chat: Record<string, unknown>): Record<string, unknown>;
|
|
40
|
+
export {};
|
|
@@ -0,0 +1,140 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.getWorkflowChatI18nCatalog = getWorkflowChatI18nCatalog;
|
|
7
|
+
exports.buildBilingualFromTemplate = buildBilingualFromTemplate;
|
|
8
|
+
exports.workflowTemplate = workflowTemplate;
|
|
9
|
+
exports.chatTemplate = chatTemplate;
|
|
10
|
+
exports.resolveWorkflowStatusAr = resolveWorkflowStatusAr;
|
|
11
|
+
exports.resolveChatStatusAr = resolveChatStatusAr;
|
|
12
|
+
exports.pickLocalizedName = pickLocalizedName;
|
|
13
|
+
exports.buildApprovalWorkflowContent = buildApprovalWorkflowContent;
|
|
14
|
+
exports.buildHumanApprovalWorkflowContent = buildHumanApprovalWorkflowContent;
|
|
15
|
+
exports.buildApprovalChatMessage = buildApprovalChatMessage;
|
|
16
|
+
exports.enrichCancellationWorkflowLog = enrichCancellationWorkflowLog;
|
|
17
|
+
exports.enrichCancellationChatMessage = enrichCancellationChatMessage;
|
|
18
|
+
const workflow_chat_i18n_json_1 = __importDefault(require("./workflow-chat-i18n.json"));
|
|
19
|
+
const WORKFLOW_TEMPLATES = workflow_chat_i18n_json_1.default.workflowTemplates;
|
|
20
|
+
const CHAT_TEMPLATES = workflow_chat_i18n_json_1.default.chatTemplates;
|
|
21
|
+
const WORKFLOW_STATUS_LABELS = workflow_chat_i18n_json_1.default.workflowStatusLabels;
|
|
22
|
+
const CHAT_STATUS_LABELS = workflow_chat_i18n_json_1.default.chatStatusLabels;
|
|
23
|
+
/** Read-only view of the shared workflow/chat translation catalog. */
|
|
24
|
+
function getWorkflowChatI18nCatalog() {
|
|
25
|
+
return workflow_chat_i18n_json_1.default;
|
|
26
|
+
}
|
|
27
|
+
function interpolate(template, params = {}) {
|
|
28
|
+
return template.replace(/\{\{(\w+)\}\}/g, (_, key) => params[key] ?? '');
|
|
29
|
+
}
|
|
30
|
+
function buildBilingualFromTemplate(templateCatalog, key, params = {}) {
|
|
31
|
+
const tpl = templateCatalog[key];
|
|
32
|
+
if (!tpl) {
|
|
33
|
+
return { en: key, ar: key };
|
|
34
|
+
}
|
|
35
|
+
return {
|
|
36
|
+
en: interpolate(tpl.en, params),
|
|
37
|
+
ar: interpolate(tpl.ar, params),
|
|
38
|
+
};
|
|
39
|
+
}
|
|
40
|
+
function workflowTemplate(key, params = {}) {
|
|
41
|
+
return buildBilingualFromTemplate(WORKFLOW_TEMPLATES, key, params);
|
|
42
|
+
}
|
|
43
|
+
function chatTemplate(key, params = {}) {
|
|
44
|
+
return buildBilingualFromTemplate(CHAT_TEMPLATES, key, params);
|
|
45
|
+
}
|
|
46
|
+
function resolveWorkflowStatusAr(status) {
|
|
47
|
+
if (status == null || status === '')
|
|
48
|
+
return null;
|
|
49
|
+
return WORKFLOW_STATUS_LABELS[status] ?? status;
|
|
50
|
+
}
|
|
51
|
+
function resolveChatStatusAr(status) {
|
|
52
|
+
if (status == null || status === '')
|
|
53
|
+
return null;
|
|
54
|
+
return CHAT_STATUS_LABELS[status] ?? status;
|
|
55
|
+
}
|
|
56
|
+
function pickLocalizedName(englishName, arabicName, fallback = '') {
|
|
57
|
+
const ar = arabicName?.trim();
|
|
58
|
+
if (ar)
|
|
59
|
+
return ar;
|
|
60
|
+
const en = englishName?.trim();
|
|
61
|
+
if (en)
|
|
62
|
+
return en;
|
|
63
|
+
return fallback;
|
|
64
|
+
}
|
|
65
|
+
function buildApprovalWorkflowContent(params) {
|
|
66
|
+
const nameEn = params.roleName?.trim() || '';
|
|
67
|
+
const nameAr = pickLocalizedName(params.roleName, params.roleArabicName, nameEn || 'Unknown');
|
|
68
|
+
let base;
|
|
69
|
+
if (params.status === 'Approved') {
|
|
70
|
+
base = nameEn
|
|
71
|
+
? workflowTemplate('request_approved_by', { name: nameEn })
|
|
72
|
+
: workflowTemplate('request_approved');
|
|
73
|
+
if (nameEn) {
|
|
74
|
+
base.ar = workflowTemplate('request_approved_by', { name: nameAr }).ar;
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
else if (params.status === 'Rejected') {
|
|
78
|
+
base = nameEn
|
|
79
|
+
? workflowTemplate('request_rejected_by', { name: nameEn })
|
|
80
|
+
: workflowTemplate('request_rejected');
|
|
81
|
+
if (nameEn) {
|
|
82
|
+
base.ar = workflowTemplate('request_rejected_by', { name: nameAr }).ar;
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
else {
|
|
86
|
+
base = nameEn
|
|
87
|
+
? workflowTemplate('request_approval_pending_from', { name: nameEn })
|
|
88
|
+
: workflowTemplate('request_approval_pending');
|
|
89
|
+
if (nameEn) {
|
|
90
|
+
base.ar = workflowTemplate('request_approval_pending_from', { name: nameAr }).ar;
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
const comment = params.comment?.trim();
|
|
94
|
+
if (!comment)
|
|
95
|
+
return base;
|
|
96
|
+
return {
|
|
97
|
+
en: `${base.en}: ${comment}`,
|
|
98
|
+
ar: `${base.ar}: ${comment}`,
|
|
99
|
+
};
|
|
100
|
+
}
|
|
101
|
+
function buildHumanApprovalWorkflowContent(params) {
|
|
102
|
+
const nameEn = params.roleName?.trim() || params.deptSectionEn?.trim() || '';
|
|
103
|
+
const nameAr = params.roleName
|
|
104
|
+
? pickLocalizedName(params.roleName, params.roleArabicName, nameEn)
|
|
105
|
+
: params.deptSectionAr?.trim() || params.deptSectionEn?.trim() || nameEn;
|
|
106
|
+
if (nameEn) {
|
|
107
|
+
const key = params.isFirst ? 'request_approval_in_progress_from' : 'request_approval_pending_from';
|
|
108
|
+
return {
|
|
109
|
+
en: workflowTemplate(key, { name: nameEn }).en,
|
|
110
|
+
ar: workflowTemplate(key, { name: nameAr || nameEn }).ar,
|
|
111
|
+
};
|
|
112
|
+
}
|
|
113
|
+
return params.isFirst
|
|
114
|
+
? workflowTemplate('request_approval_in_progress')
|
|
115
|
+
: workflowTemplate('request_approval_pending');
|
|
116
|
+
}
|
|
117
|
+
function buildApprovalChatMessage(params) {
|
|
118
|
+
const roleEn = params.roleName?.trim() || 'Unknown Role';
|
|
119
|
+
const roleAr = pickLocalizedName(params.roleName, params.roleArabicName, roleEn);
|
|
120
|
+
const commentSuffix = params.comment?.trim() ? ` - ${params.comment.trim()}` : '';
|
|
121
|
+
const key = params.status === 'Approved' ? 'request_approved_by_role' : 'request_rejected_by_role';
|
|
122
|
+
return {
|
|
123
|
+
en: chatTemplate(key, { roleName: roleEn, comment: commentSuffix }).en,
|
|
124
|
+
ar: chatTemplate(key, { roleName: roleAr, comment: commentSuffix }).ar,
|
|
125
|
+
};
|
|
126
|
+
}
|
|
127
|
+
function enrichCancellationWorkflowLog(log) {
|
|
128
|
+
const status = log.status != null ? String(log.status) : null;
|
|
129
|
+
return {
|
|
130
|
+
...log,
|
|
131
|
+
status_ar: log.status_ar ?? resolveWorkflowStatusAr(status),
|
|
132
|
+
};
|
|
133
|
+
}
|
|
134
|
+
function enrichCancellationChatMessage(chat) {
|
|
135
|
+
const status = chat.status != null ? String(chat.status) : null;
|
|
136
|
+
return {
|
|
137
|
+
...chat,
|
|
138
|
+
status_ar: chat.status_ar ?? resolveChatStatusAr(status),
|
|
139
|
+
};
|
|
140
|
+
}
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
{
|
|
2
|
+
"workflowTemplates": {
|
|
3
|
+
"request_submitted": {
|
|
4
|
+
"en": "Request Submitted",
|
|
5
|
+
"ar": "تم تقديم الطلب"
|
|
6
|
+
},
|
|
7
|
+
"notification_sent_pending": {
|
|
8
|
+
"en": "Notification sent Pending",
|
|
9
|
+
"ar": "في انتظار إرسال الإشعار"
|
|
10
|
+
},
|
|
11
|
+
"notification_sent_successfully": {
|
|
12
|
+
"en": "Notification sent successfully",
|
|
13
|
+
"ar": "تم إرسال الإشعار بنجاح"
|
|
14
|
+
},
|
|
15
|
+
"request_approval_in_progress": {
|
|
16
|
+
"en": "Request Approval In Progress",
|
|
17
|
+
"ar": "الموافقة على الطلب قيد التنفيذ"
|
|
18
|
+
},
|
|
19
|
+
"request_approval_pending": {
|
|
20
|
+
"en": "Request Approval Pending",
|
|
21
|
+
"ar": "في انتظار الموافقة على الطلب"
|
|
22
|
+
},
|
|
23
|
+
"request_approval_in_progress_from": {
|
|
24
|
+
"en": "Request Approval In Progress from {{name}}",
|
|
25
|
+
"ar": "الموافقة على الطلب قيد التنفيذ من {{name}}"
|
|
26
|
+
},
|
|
27
|
+
"request_approval_pending_from": {
|
|
28
|
+
"en": "Request Approval Pending from {{name}}",
|
|
29
|
+
"ar": "في انتظار موافقة {{name}}"
|
|
30
|
+
},
|
|
31
|
+
"request_approved_by": {
|
|
32
|
+
"en": "Request Approved by {{name}}",
|
|
33
|
+
"ar": "تمت الموافقة على الطلب من قبل {{name}}"
|
|
34
|
+
},
|
|
35
|
+
"request_rejected_by": {
|
|
36
|
+
"en": "Request Rejected by {{name}}",
|
|
37
|
+
"ar": "تم رفض الطلب من قبل {{name}}"
|
|
38
|
+
},
|
|
39
|
+
"request_approved": {
|
|
40
|
+
"en": "Request Approved",
|
|
41
|
+
"ar": "تمت الموافقة على الطلب"
|
|
42
|
+
},
|
|
43
|
+
"request_rejected": {
|
|
44
|
+
"en": "Request Rejected",
|
|
45
|
+
"ar": "تم رفض الطلب"
|
|
46
|
+
}
|
|
47
|
+
},
|
|
48
|
+
"chatTemplates": {
|
|
49
|
+
"cancellation_submitted_by": {
|
|
50
|
+
"en": "Cancellation request submitted by {{userName}} ({{employeeId}})",
|
|
51
|
+
"ar": "تم تقديم طلب الإلغاء بواسطة {{userName}} ({{employeeId}})"
|
|
52
|
+
},
|
|
53
|
+
"request_received": {
|
|
54
|
+
"en": "Request Received",
|
|
55
|
+
"ar": "تم استلام الطلب"
|
|
56
|
+
},
|
|
57
|
+
"request_approved_by_role": {
|
|
58
|
+
"en": "Request Approved by: {{roleName}}{{comment}}",
|
|
59
|
+
"ar": "تمت الموافقة على الطلب من قبل: {{roleName}}{{comment}}"
|
|
60
|
+
},
|
|
61
|
+
"request_rejected_by_role": {
|
|
62
|
+
"en": "Request Rejected by: {{roleName}}{{comment}}",
|
|
63
|
+
"ar": "تم رفض الطلب من قبل: {{roleName}}{{comment}}"
|
|
64
|
+
}
|
|
65
|
+
},
|
|
66
|
+
"workflowStatusLabels": {
|
|
67
|
+
"Completed": "مكتمل",
|
|
68
|
+
"Pending": "قيد الانتظار",
|
|
69
|
+
"Not Yet Started": "لم يبدأ بعد"
|
|
70
|
+
},
|
|
71
|
+
"chatStatusLabels": {
|
|
72
|
+
"Submitted": "تم التقديم",
|
|
73
|
+
"Received": "تم الاستلام",
|
|
74
|
+
"Approved": "موافق عليه",
|
|
75
|
+
"Rejected": "مرفوض",
|
|
76
|
+
"Pending": "قيد الانتظار"
|
|
77
|
+
}
|
|
78
|
+
}
|
package/dist/index.d.ts
CHANGED
package/dist/index.js
CHANGED
|
@@ -604,3 +604,4 @@ __exportStar(require("./models/SlaApprovalsViewModel"), exports);
|
|
|
604
604
|
__exportStar(require("./models/ServiceSlaApprovalModel"), exports);
|
|
605
605
|
__exportStar(require("./sla/sla-table-sync.service"), exports);
|
|
606
606
|
__exportStar(require("./sla/sla-approval-mirror"), exports);
|
|
607
|
+
__exportStar(require("./i18n/workflow-chat-i18n"), exports);
|
|
@@ -13,6 +13,8 @@ export declare class CancellationRequestChat extends BaseModel {
|
|
|
13
13
|
user_id: number;
|
|
14
14
|
role_id: number | null;
|
|
15
15
|
message: string;
|
|
16
|
+
message_ar: string | null;
|
|
16
17
|
messageType: CancellationMessageType;
|
|
17
18
|
status: string | null;
|
|
19
|
+
status_ar: string | null;
|
|
18
20
|
}
|
|
@@ -47,6 +47,10 @@ __decorate([
|
|
|
47
47
|
(0, typeorm_1.Column)({ type: "text", nullable: false }),
|
|
48
48
|
__metadata("design:type", String)
|
|
49
49
|
], CancellationRequestChat.prototype, "message", void 0);
|
|
50
|
+
__decorate([
|
|
51
|
+
(0, typeorm_1.Column)({ type: "text", nullable: true }),
|
|
52
|
+
__metadata("design:type", Object)
|
|
53
|
+
], CancellationRequestChat.prototype, "message_ar", void 0);
|
|
50
54
|
__decorate([
|
|
51
55
|
(0, typeorm_1.Column)({
|
|
52
56
|
type: "enum",
|
|
@@ -60,6 +64,10 @@ __decorate([
|
|
|
60
64
|
(0, typeorm_1.Column)({ type: "text", nullable: true }),
|
|
61
65
|
__metadata("design:type", Object)
|
|
62
66
|
], CancellationRequestChat.prototype, "status", void 0);
|
|
67
|
+
__decorate([
|
|
68
|
+
(0, typeorm_1.Column)({ type: "varchar", length: 100, nullable: true }),
|
|
69
|
+
__metadata("design:type", Object)
|
|
70
|
+
], CancellationRequestChat.prototype, "status_ar", void 0);
|
|
63
71
|
exports.CancellationRequestChat = CancellationRequestChat = __decorate([
|
|
64
72
|
(0, typeorm_1.Entity)({ name: "cancellation_chats" })
|
|
65
73
|
], CancellationRequestChat);
|
|
@@ -9,7 +9,9 @@ export declare class CancellationWorkFlow extends BaseModel {
|
|
|
9
9
|
service_id: number | null;
|
|
10
10
|
sub_service_id: number | null;
|
|
11
11
|
content: string;
|
|
12
|
+
content_ar: string | null;
|
|
12
13
|
status: CancellationWorkFlowStatus;
|
|
14
|
+
status_ar: string | null;
|
|
13
15
|
user_id: number | null;
|
|
14
16
|
role_id: number | null;
|
|
15
17
|
department_id: number | null;
|
|
@@ -37,10 +37,18 @@ __decorate([
|
|
|
37
37
|
(0, typeorm_1.Column)({ type: "varchar", length: 500, nullable: false }),
|
|
38
38
|
__metadata("design:type", String)
|
|
39
39
|
], CancellationWorkFlow.prototype, "content", void 0);
|
|
40
|
+
__decorate([
|
|
41
|
+
(0, typeorm_1.Column)({ type: "varchar", length: 500, nullable: true }),
|
|
42
|
+
__metadata("design:type", Object)
|
|
43
|
+
], CancellationWorkFlow.prototype, "content_ar", void 0);
|
|
40
44
|
__decorate([
|
|
41
45
|
(0, typeorm_1.Column)({ type: "enum", enum: CancellationWorkFlowStatus, default: CancellationWorkFlowStatus.NOT_YET_STARTED, nullable: false }),
|
|
42
46
|
__metadata("design:type", String)
|
|
43
47
|
], CancellationWorkFlow.prototype, "status", void 0);
|
|
48
|
+
__decorate([
|
|
49
|
+
(0, typeorm_1.Column)({ type: "varchar", length: 100, nullable: true }),
|
|
50
|
+
__metadata("design:type", Object)
|
|
51
|
+
], CancellationWorkFlow.prototype, "status_ar", void 0);
|
|
44
52
|
__decorate([
|
|
45
53
|
(0, typeorm_1.Column)({ type: "integer", nullable: true }),
|
|
46
54
|
__metadata("design:type", Object)
|
package/package.json
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@platform-modules/civil-aviation-authority",
|
|
3
|
-
"version": "2.3.
|
|
3
|
+
"version": "2.3.277",
|
|
4
4
|
"main": "dist/index.js",
|
|
5
5
|
"types": "dist/index.d.ts",
|
|
6
|
-
|
|
7
|
-
"build": "tsc",
|
|
6
|
+
"scripts": {
|
|
7
|
+
"build": "tsc && node -e \"require('fs').mkdirSync('dist/i18n',{recursive:true}); require('fs').copyFileSync('src/i18n/workflow-chat-i18n.json','dist/i18n/workflow-chat-i18n.json')\"",
|
|
8
8
|
"dev": "ts-node src/scripts.ts",
|
|
9
9
|
"sync:sla-sql": "node scripts/sync-sla-reports-sql.js"
|
|
10
10
|
},
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
-- Pilot: Arabic columns for cancellation workflow and chat tables (CAA).
|
|
2
|
+
-- Run once per environment before deploying updated services.
|
|
3
|
+
|
|
4
|
+
ALTER TABLE IF EXISTS cancellation_workflows
|
|
5
|
+
ADD COLUMN IF NOT EXISTS content_ar VARCHAR(500) NULL,
|
|
6
|
+
ADD COLUMN IF NOT EXISTS status_ar VARCHAR(100) NULL;
|
|
7
|
+
|
|
8
|
+
ALTER TABLE IF EXISTS cancellation_chats
|
|
9
|
+
ADD COLUMN IF NOT EXISTS message_ar TEXT NULL,
|
|
10
|
+
ADD COLUMN IF NOT EXISTS status_ar VARCHAR(100) NULL;
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
{
|
|
2
|
+
"workflowTemplates": {
|
|
3
|
+
"request_submitted": {
|
|
4
|
+
"en": "Request Submitted",
|
|
5
|
+
"ar": "تم تقديم الطلب"
|
|
6
|
+
},
|
|
7
|
+
"notification_sent_pending": {
|
|
8
|
+
"en": "Notification sent Pending",
|
|
9
|
+
"ar": "في انتظار إرسال الإشعار"
|
|
10
|
+
},
|
|
11
|
+
"notification_sent_successfully": {
|
|
12
|
+
"en": "Notification sent successfully",
|
|
13
|
+
"ar": "تم إرسال الإشعار بنجاح"
|
|
14
|
+
},
|
|
15
|
+
"request_approval_in_progress": {
|
|
16
|
+
"en": "Request Approval In Progress",
|
|
17
|
+
"ar": "الموافقة على الطلب قيد التنفيذ"
|
|
18
|
+
},
|
|
19
|
+
"request_approval_pending": {
|
|
20
|
+
"en": "Request Approval Pending",
|
|
21
|
+
"ar": "في انتظار الموافقة على الطلب"
|
|
22
|
+
},
|
|
23
|
+
"request_approval_in_progress_from": {
|
|
24
|
+
"en": "Request Approval In Progress from {{name}}",
|
|
25
|
+
"ar": "الموافقة على الطلب قيد التنفيذ من {{name}}"
|
|
26
|
+
},
|
|
27
|
+
"request_approval_pending_from": {
|
|
28
|
+
"en": "Request Approval Pending from {{name}}",
|
|
29
|
+
"ar": "في انتظار موافقة {{name}}"
|
|
30
|
+
},
|
|
31
|
+
"request_approved_by": {
|
|
32
|
+
"en": "Request Approved by {{name}}",
|
|
33
|
+
"ar": "تمت الموافقة على الطلب من قبل {{name}}"
|
|
34
|
+
},
|
|
35
|
+
"request_rejected_by": {
|
|
36
|
+
"en": "Request Rejected by {{name}}",
|
|
37
|
+
"ar": "تم رفض الطلب من قبل {{name}}"
|
|
38
|
+
},
|
|
39
|
+
"request_approved": {
|
|
40
|
+
"en": "Request Approved",
|
|
41
|
+
"ar": "تمت الموافقة على الطلب"
|
|
42
|
+
},
|
|
43
|
+
"request_rejected": {
|
|
44
|
+
"en": "Request Rejected",
|
|
45
|
+
"ar": "تم رفض الطلب"
|
|
46
|
+
}
|
|
47
|
+
},
|
|
48
|
+
"chatTemplates": {
|
|
49
|
+
"cancellation_submitted_by": {
|
|
50
|
+
"en": "Cancellation request submitted by {{userName}} ({{employeeId}})",
|
|
51
|
+
"ar": "تم تقديم طلب الإلغاء بواسطة {{userName}} ({{employeeId}})"
|
|
52
|
+
},
|
|
53
|
+
"request_received": {
|
|
54
|
+
"en": "Request Received",
|
|
55
|
+
"ar": "تم استلام الطلب"
|
|
56
|
+
},
|
|
57
|
+
"request_approved_by_role": {
|
|
58
|
+
"en": "Request Approved by: {{roleName}}{{comment}}",
|
|
59
|
+
"ar": "تمت الموافقة على الطلب من قبل: {{roleName}}{{comment}}"
|
|
60
|
+
},
|
|
61
|
+
"request_rejected_by_role": {
|
|
62
|
+
"en": "Request Rejected by: {{roleName}}{{comment}}",
|
|
63
|
+
"ar": "تم رفض الطلب من قبل: {{roleName}}{{comment}}"
|
|
64
|
+
}
|
|
65
|
+
},
|
|
66
|
+
"workflowStatusLabels": {
|
|
67
|
+
"Completed": "مكتمل",
|
|
68
|
+
"Pending": "قيد الانتظار",
|
|
69
|
+
"Not Yet Started": "لم يبدأ بعد"
|
|
70
|
+
},
|
|
71
|
+
"chatStatusLabels": {
|
|
72
|
+
"Submitted": "تم التقديم",
|
|
73
|
+
"Received": "تم الاستلام",
|
|
74
|
+
"Approved": "موافق عليه",
|
|
75
|
+
"Rejected": "مرفوض",
|
|
76
|
+
"Pending": "قيد الانتظار"
|
|
77
|
+
}
|
|
78
|
+
}
|
|
@@ -0,0 +1,169 @@
|
|
|
1
|
+
import catalog from './workflow-chat-i18n.json';
|
|
2
|
+
|
|
3
|
+
export type BilingualText = { en: string; ar: string };
|
|
4
|
+
|
|
5
|
+
type WorkflowChatI18nCatalog = {
|
|
6
|
+
workflowTemplates: Record<string, BilingualText>;
|
|
7
|
+
chatTemplates: Record<string, BilingualText>;
|
|
8
|
+
workflowStatusLabels: Record<string, string>;
|
|
9
|
+
chatStatusLabels: Record<string, string>;
|
|
10
|
+
};
|
|
11
|
+
|
|
12
|
+
const WORKFLOW_TEMPLATES = catalog.workflowTemplates as Record<string, BilingualText>;
|
|
13
|
+
const CHAT_TEMPLATES = catalog.chatTemplates as Record<string, BilingualText>;
|
|
14
|
+
const WORKFLOW_STATUS_LABELS = catalog.workflowStatusLabels as Record<string, string>;
|
|
15
|
+
const CHAT_STATUS_LABELS = catalog.chatStatusLabels as Record<string, string>;
|
|
16
|
+
|
|
17
|
+
/** Read-only view of the shared workflow/chat translation catalog. */
|
|
18
|
+
export function getWorkflowChatI18nCatalog(): WorkflowChatI18nCatalog {
|
|
19
|
+
return catalog as WorkflowChatI18nCatalog;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
function interpolate(template: string, params: Record<string, string> = {}): string {
|
|
23
|
+
return template.replace(/\{\{(\w+)\}\}/g, (_, key: string) => params[key] ?? '');
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
export function buildBilingualFromTemplate(
|
|
27
|
+
templateCatalog: Record<string, BilingualText>,
|
|
28
|
+
key: string,
|
|
29
|
+
params: Record<string, string> = {}
|
|
30
|
+
): BilingualText {
|
|
31
|
+
const tpl = templateCatalog[key];
|
|
32
|
+
if (!tpl) {
|
|
33
|
+
return { en: key, ar: key };
|
|
34
|
+
}
|
|
35
|
+
return {
|
|
36
|
+
en: interpolate(tpl.en, params),
|
|
37
|
+
ar: interpolate(tpl.ar, params),
|
|
38
|
+
};
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
export function workflowTemplate(key: string, params: Record<string, string> = {}): BilingualText {
|
|
42
|
+
return buildBilingualFromTemplate(WORKFLOW_TEMPLATES, key, params);
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
export function chatTemplate(key: string, params: Record<string, string> = {}): BilingualText {
|
|
46
|
+
return buildBilingualFromTemplate(CHAT_TEMPLATES, key, params);
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
export function resolveWorkflowStatusAr(status: string | null | undefined): string | null {
|
|
50
|
+
if (status == null || status === '') return null;
|
|
51
|
+
return WORKFLOW_STATUS_LABELS[status] ?? status;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
export function resolveChatStatusAr(status: string | null | undefined): string | null {
|
|
55
|
+
if (status == null || status === '') return null;
|
|
56
|
+
return CHAT_STATUS_LABELS[status] ?? status;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
export function pickLocalizedName(
|
|
60
|
+
englishName?: string | null,
|
|
61
|
+
arabicName?: string | null,
|
|
62
|
+
fallback = ''
|
|
63
|
+
): string {
|
|
64
|
+
const ar = arabicName?.trim();
|
|
65
|
+
if (ar) return ar;
|
|
66
|
+
const en = englishName?.trim();
|
|
67
|
+
if (en) return en;
|
|
68
|
+
return fallback;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
export function buildApprovalWorkflowContent(params: {
|
|
72
|
+
status: 'Approved' | 'Rejected' | 'Pending' | string;
|
|
73
|
+
roleName?: string | null;
|
|
74
|
+
roleArabicName?: string | null;
|
|
75
|
+
comment?: string | null;
|
|
76
|
+
}): BilingualText {
|
|
77
|
+
const nameEn = params.roleName?.trim() || '';
|
|
78
|
+
const nameAr = pickLocalizedName(params.roleName, params.roleArabicName, nameEn || 'Unknown');
|
|
79
|
+
|
|
80
|
+
let base: BilingualText;
|
|
81
|
+
if (params.status === 'Approved') {
|
|
82
|
+
base = nameEn
|
|
83
|
+
? workflowTemplate('request_approved_by', { name: nameEn })
|
|
84
|
+
: workflowTemplate('request_approved');
|
|
85
|
+
if (nameEn) {
|
|
86
|
+
base.ar = workflowTemplate('request_approved_by', { name: nameAr }).ar;
|
|
87
|
+
}
|
|
88
|
+
} else if (params.status === 'Rejected') {
|
|
89
|
+
base = nameEn
|
|
90
|
+
? workflowTemplate('request_rejected_by', { name: nameEn })
|
|
91
|
+
: workflowTemplate('request_rejected');
|
|
92
|
+
if (nameEn) {
|
|
93
|
+
base.ar = workflowTemplate('request_rejected_by', { name: nameAr }).ar;
|
|
94
|
+
}
|
|
95
|
+
} else {
|
|
96
|
+
base = nameEn
|
|
97
|
+
? workflowTemplate('request_approval_pending_from', { name: nameEn })
|
|
98
|
+
: workflowTemplate('request_approval_pending');
|
|
99
|
+
if (nameEn) {
|
|
100
|
+
base.ar = workflowTemplate('request_approval_pending_from', { name: nameAr }).ar;
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
const comment = params.comment?.trim();
|
|
105
|
+
if (!comment) return base;
|
|
106
|
+
|
|
107
|
+
return {
|
|
108
|
+
en: `${base.en}: ${comment}`,
|
|
109
|
+
ar: `${base.ar}: ${comment}`,
|
|
110
|
+
};
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
export function buildHumanApprovalWorkflowContent(params: {
|
|
114
|
+
isFirst: boolean;
|
|
115
|
+
roleName?: string | null;
|
|
116
|
+
roleArabicName?: string | null;
|
|
117
|
+
deptSectionEn?: string | null;
|
|
118
|
+
deptSectionAr?: string | null;
|
|
119
|
+
}): BilingualText {
|
|
120
|
+
const nameEn = params.roleName?.trim() || params.deptSectionEn?.trim() || '';
|
|
121
|
+
const nameAr = params.roleName
|
|
122
|
+
? pickLocalizedName(params.roleName, params.roleArabicName, nameEn)
|
|
123
|
+
: params.deptSectionAr?.trim() || params.deptSectionEn?.trim() || nameEn;
|
|
124
|
+
|
|
125
|
+
if (nameEn) {
|
|
126
|
+
const key = params.isFirst ? 'request_approval_in_progress_from' : 'request_approval_pending_from';
|
|
127
|
+
return {
|
|
128
|
+
en: workflowTemplate(key, { name: nameEn }).en,
|
|
129
|
+
ar: workflowTemplate(key, { name: nameAr || nameEn }).ar,
|
|
130
|
+
};
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
return params.isFirst
|
|
134
|
+
? workflowTemplate('request_approval_in_progress')
|
|
135
|
+
: workflowTemplate('request_approval_pending');
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
export function buildApprovalChatMessage(params: {
|
|
139
|
+
status: 'Approved' | 'Rejected' | string;
|
|
140
|
+
roleName?: string | null;
|
|
141
|
+
roleArabicName?: string | null;
|
|
142
|
+
comment?: string | null;
|
|
143
|
+
}): BilingualText {
|
|
144
|
+
const roleEn = params.roleName?.trim() || 'Unknown Role';
|
|
145
|
+
const roleAr = pickLocalizedName(params.roleName, params.roleArabicName, roleEn);
|
|
146
|
+
const commentSuffix = params.comment?.trim() ? ` - ${params.comment.trim()}` : '';
|
|
147
|
+
const key = params.status === 'Approved' ? 'request_approved_by_role' : 'request_rejected_by_role';
|
|
148
|
+
|
|
149
|
+
return {
|
|
150
|
+
en: chatTemplate(key, { roleName: roleEn, comment: commentSuffix }).en,
|
|
151
|
+
ar: chatTemplate(key, { roleName: roleAr, comment: commentSuffix }).ar,
|
|
152
|
+
};
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
export function enrichCancellationWorkflowLog(log: Record<string, unknown>): Record<string, unknown> {
|
|
156
|
+
const status = log.status != null ? String(log.status) : null;
|
|
157
|
+
return {
|
|
158
|
+
...log,
|
|
159
|
+
status_ar: log.status_ar ?? resolveWorkflowStatusAr(status),
|
|
160
|
+
};
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
export function enrichCancellationChatMessage(chat: Record<string, unknown>): Record<string, unknown> {
|
|
164
|
+
const status = chat.status != null ? String(chat.status) : null;
|
|
165
|
+
return {
|
|
166
|
+
...chat,
|
|
167
|
+
status_ar: chat.status_ar ?? resolveChatStatusAr(status),
|
|
168
|
+
};
|
|
169
|
+
}
|
package/src/index.ts
CHANGED
|
@@ -503,4 +503,5 @@ export * from './models/SlaMyRequestsViewModel';
|
|
|
503
503
|
export * from './models/SlaApprovalsViewModel';
|
|
504
504
|
export * from './models/ServiceSlaApprovalModel';
|
|
505
505
|
export * from './sla/sla-table-sync.service';
|
|
506
|
-
export * from './sla/sla-approval-mirror';
|
|
506
|
+
export * from './sla/sla-approval-mirror';
|
|
507
|
+
export * from './i18n/workflow-chat-i18n';
|
|
@@ -29,6 +29,9 @@ export class CancellationRequestChat extends BaseModel {
|
|
|
29
29
|
@Column({ type: "text", nullable: false })
|
|
30
30
|
message: string;
|
|
31
31
|
|
|
32
|
+
@Column({ type: "text", nullable: true })
|
|
33
|
+
message_ar: string | null;
|
|
34
|
+
|
|
32
35
|
@Column({
|
|
33
36
|
type: "enum",
|
|
34
37
|
enum: CancellationMessageType,
|
|
@@ -39,4 +42,7 @@ export class CancellationRequestChat extends BaseModel {
|
|
|
39
42
|
|
|
40
43
|
@Column({ type: "text", nullable: true })
|
|
41
44
|
status: string | null;
|
|
45
|
+
|
|
46
|
+
@Column({ type: "varchar", length: 100, nullable: true })
|
|
47
|
+
status_ar: string | null;
|
|
42
48
|
}
|
|
@@ -21,9 +21,15 @@ export class CancellationWorkFlow extends BaseModel {
|
|
|
21
21
|
@Column({ type: "varchar", length: 500, nullable: false })
|
|
22
22
|
content: string;
|
|
23
23
|
|
|
24
|
+
@Column({ type: "varchar", length: 500, nullable: true })
|
|
25
|
+
content_ar: string | null;
|
|
26
|
+
|
|
24
27
|
@Column({ type: "enum", enum: CancellationWorkFlowStatus, default: CancellationWorkFlowStatus.NOT_YET_STARTED, nullable: false })
|
|
25
28
|
status: CancellationWorkFlowStatus;
|
|
26
29
|
|
|
30
|
+
@Column({ type: "varchar", length: 100, nullable: true })
|
|
31
|
+
status_ar: string | null;
|
|
32
|
+
|
|
27
33
|
@Column({ type: "integer", nullable: true })
|
|
28
34
|
user_id: number | null;
|
|
29
35
|
|