@platform-modules/civil-aviation-authority 2.3.282 → 2.3.291
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 +162 -1
- package/dist/i18n/workflow-chat-message.builder.d.ts +178 -1
- package/dist/i18n/workflow-chat-message.builder.js +406 -13
- package/dist/models/AccessCardChatModel.d.ts +2 -0
- package/dist/models/AccessCardChatModel.js +8 -0
- package/dist/models/AccessCardWorkflowModel.d.ts +2 -0
- package/dist/models/AccessCardWorkflowModel.js +8 -0
- package/dist/models/AccommodationChatModel.d.ts +2 -0
- package/dist/models/AccommodationChatModel.js +8 -0
- package/dist/models/AccommodationWorkflowModel.d.ts +2 -0
- package/dist/models/AccommodationWorkflowModel.js +8 -0
- package/dist/models/AirportEntryPermitChatModel.d.ts +2 -0
- package/dist/models/AirportEntryPermitChatModel.js +8 -0
- package/dist/models/AirportEntryPermitWorkflowModel.d.ts +2 -0
- package/dist/models/AirportEntryPermitWorkflowModel.js +8 -0
- package/dist/models/AnnualTrainingPlanChatModel.d.ts +2 -0
- package/dist/models/AnnualTrainingPlanChatModel.js +8 -0
- package/dist/models/AnnualTrainingPlanWorkflowModel.d.ts +2 -0
- package/dist/models/AnnualTrainingPlanWorkflowModel.js +8 -0
- package/dist/models/AppealAgainstAdministrativeDecisionRequestModel.d.ts +4 -4
- package/dist/models/AppealAgainstAdministrativeDecisionRequestModel.js +8 -8
- package/dist/models/AssignTasksEmpChatModel.d.ts +2 -0
- package/dist/models/AssignTasksEmpChatModel.js +8 -0
- package/dist/models/AssignTasksEmpWorkflowModel.d.ts +2 -0
- package/dist/models/AssignTasksEmpWorkflowModel.js +8 -0
- package/dist/models/ComplaintLostPropertyReportChatModel.d.ts +2 -0
- package/dist/models/ComplaintLostPropertyReportChatModel.js +8 -0
- package/dist/models/ComplaintLostPropertyReportWorkflowModel.d.ts +2 -0
- package/dist/models/ComplaintLostPropertyReportWorkflowModel.js +8 -0
- package/dist/models/CyberSecurityAuditRequestModel.d.ts +2 -0
- package/dist/models/CyberSecurityAuditRequestModel.js +8 -0
- package/dist/models/CyberSecurityRiskManagementRiskModel.d.ts +2 -0
- package/dist/models/CyberSecurityRiskManagementRiskModel.js +8 -0
- package/dist/models/DutyMissionChatModel.d.ts +2 -0
- package/dist/models/DutyMissionChatModel.js +8 -0
- package/dist/models/DutyMissionWorkflowModel.d.ts +2 -0
- package/dist/models/DutyMissionWorkflowModel.js +8 -0
- package/dist/models/EventSupportChatModel.d.ts +2 -0
- package/dist/models/EventSupportChatModel.js +8 -0
- package/dist/models/EventSupportWorkflowModel.d.ts +2 -0
- package/dist/models/EventSupportWorkflowModel.js +8 -0
- package/dist/models/FollowUpReportChatModel.d.ts +2 -0
- package/dist/models/FollowUpReportChatModel.js +8 -0
- package/dist/models/FollowUpReportWorkflowModel.d.ts +2 -0
- package/dist/models/FollowUpReportWorkflowModel.js +8 -0
- package/dist/models/FoodChatModel.d.ts +2 -0
- package/dist/models/FoodChatModel.js +8 -0
- package/dist/models/FoodWorkflowModel.d.ts +2 -0
- package/dist/models/FoodWorkflowModel.js +8 -0
- package/dist/models/HallChatModel.d.ts +2 -0
- package/dist/models/HallChatModel.js +8 -0
- package/dist/models/HallWorkflowModel.d.ts +2 -0
- package/dist/models/HallWorkflowModel.js +8 -0
- package/dist/models/HotelChatModel.d.ts +2 -0
- package/dist/models/HotelChatModel.js +8 -0
- package/dist/models/HotelWorkFlowModel.d.ts +2 -0
- package/dist/models/HotelWorkFlowModel.js +8 -0
- package/dist/models/HousingContractCancelChatModel.d.ts +2 -0
- package/dist/models/HousingContractCancelChatModel.js +8 -0
- package/dist/models/HousingContractCancelWorkflowModel.d.ts +2 -0
- package/dist/models/HousingContractCancelWorkflowModel.js +8 -0
- package/dist/models/HousingContractRenewalChatModel.d.ts +2 -0
- package/dist/models/HousingContractRenewalChatModel.js +8 -0
- package/dist/models/HousingContractRenewalWorkflowModel.d.ts +2 -0
- package/dist/models/HousingContractRenewalWorkflowModel.js +8 -0
- package/dist/models/HrServiceChatModel.d.ts +2 -0
- package/dist/models/HrServiceChatModel.js +8 -0
- package/dist/models/HrServiceWorkflowModel.d.ts +2 -0
- package/dist/models/HrServiceWorkflowModel.js +8 -0
- package/dist/models/ITRequestChatModel.d.ts +2 -0
- package/dist/models/ITRequestChatModel.js +8 -0
- package/dist/models/ImportExportMaterialChatModel.d.ts +2 -0
- package/dist/models/ImportExportMaterialChatModel.js +8 -0
- package/dist/models/ImportExportMaterialWorkflowModel.d.ts +2 -0
- package/dist/models/ImportExportMaterialWorkflowModel.js +8 -0
- package/dist/models/InformationSecurityChatModel.d.ts +2 -0
- package/dist/models/InformationSecurityChatModel.js +8 -0
- package/dist/models/InformationSecurityWorkflowModel.d.ts +2 -0
- package/dist/models/InformationSecurityWorkflowModel.js +8 -0
- package/dist/models/ItWorkflowModel.d.ts +2 -0
- package/dist/models/ItWorkflowModel.js +8 -0
- package/dist/models/LegalComplaintChatModel.d.ts +2 -0
- package/dist/models/LegalComplaintChatModel.js +8 -0
- package/dist/models/LegalComplaintWorkflowModel.d.ts +2 -0
- package/dist/models/LegalComplaintWorkflowModel.js +8 -0
- package/dist/models/LegalConsultationChatModel.d.ts +2 -0
- package/dist/models/LegalConsultationChatModel.js +8 -0
- package/dist/models/LegalConsultationWorkflowModel.d.ts +2 -0
- package/dist/models/LegalConsultationWorkflowModel.js +8 -0
- package/dist/models/LegalContractReviewChatModel.d.ts +2 -0
- package/dist/models/LegalContractReviewChatModel.js +8 -0
- package/dist/models/LegalContractReviewWorkflowModel.d.ts +2 -0
- package/dist/models/LegalContractReviewWorkflowModel.js +8 -0
- package/dist/models/LogisticsChatModel.d.ts +2 -0
- package/dist/models/LogisticsChatModel.js +8 -0
- package/dist/models/LogisticsVehicleMaintenanceChatModel.d.ts +2 -0
- package/dist/models/LogisticsVehicleMaintenanceChatModel.js +8 -0
- package/dist/models/LogisticsVehicleMaintenanceWorkflowModel.d.ts +2 -0
- package/dist/models/LogisticsVehicleMaintenanceWorkflowModel.js +8 -0
- package/dist/models/LogisticsWorkflowModel.d.ts +2 -0
- package/dist/models/LogisticsWorkflowModel.js +8 -0
- package/dist/models/MaintenanceChatModel.d.ts +2 -0
- package/dist/models/MaintenanceChatModel.js +8 -0
- package/dist/models/MaintenanceExternalStationsChatModel.d.ts +2 -0
- package/dist/models/MaintenanceExternalStationsChatModel.js +8 -0
- package/dist/models/MaintenanceExternalStationsWorkflowModel.d.ts +2 -0
- package/dist/models/MaintenanceExternalStationsWorkflowModel.js +8 -0
- package/dist/models/MaintenanceRequestModel.d.ts +3 -1
- package/dist/models/MaintenanceRequestModel.js +2 -0
- package/dist/models/MaintenanceWorkflowModel.d.ts +2 -0
- package/dist/models/MaintenanceWorkflowModel.js +8 -0
- package/dist/models/MediaPublicationsChatModel.d.ts +2 -0
- package/dist/models/MediaPublicationsChatModel.js +8 -0
- package/dist/models/MediaPublicationsWorkflowModel.d.ts +2 -0
- package/dist/models/MediaPublicationsWorkflowModel.js +8 -0
- package/dist/models/MultiPurposeHallChatModel.d.ts +2 -0
- package/dist/models/MultiPurposeHallChatModel.js +8 -0
- package/dist/models/MultiPurposeHallWorkflowModel.d.ts +2 -0
- package/dist/models/MultiPurposeHallWorkflowModel.js +8 -0
- package/dist/models/RequestATenderRequestModel.d.ts +2 -0
- package/dist/models/RequestATenderRequestModel.js +8 -0
- package/dist/models/RequestForCoverageChatModel.d.ts +2 -0
- package/dist/models/RequestForCoverageChatModel.js +8 -0
- package/dist/models/RequestForCoverageWorkflowModel.d.ts +2 -0
- package/dist/models/RequestForCoverageWorkflowModel.js +8 -0
- package/dist/models/RequestForPresidentsCoverageChatModel.d.ts +2 -0
- package/dist/models/RequestForPresidentsCoverageChatModel.js +8 -0
- package/dist/models/RequestForPresidentsCoverageWorkflowModel.d.ts +2 -0
- package/dist/models/RequestForPresidentsCoverageWorkflowModel.js +8 -0
- package/dist/models/ResidentialUnitRentalChatModel.d.ts +2 -0
- package/dist/models/ResidentialUnitRentalChatModel.js +8 -0
- package/dist/models/ResidentialUnitRentalRequestModel.d.ts +1 -1
- package/dist/models/ResidentialUnitRentalRequestModel.js +2 -2
- package/dist/models/ResidentialUnitRentalWorkflowModel.d.ts +2 -0
- package/dist/models/ResidentialUnitRentalWorkflowModel.js +8 -0
- package/dist/models/RespondToEnquiriesChatModel.d.ts +2 -0
- package/dist/models/RespondToEnquiriesChatModel.js +8 -0
- package/dist/models/RespondToEnquiriesWorkflowModel.d.ts +2 -0
- package/dist/models/RespondToEnquiriesWorkflowModel.js +8 -0
- package/dist/models/ScholarshipChatModel.d.ts +2 -0
- package/dist/models/ScholarshipChatModel.js +8 -0
- package/dist/models/ScholarshipWorkflowModel.d.ts +2 -0
- package/dist/models/ScholarshipWorkflowModel.js +8 -0
- package/dist/models/SecurityAwarenessChatModel.d.ts +2 -0
- package/dist/models/SecurityAwarenessChatModel.js +8 -0
- package/dist/models/SecurityAwarenessWorkflowModel.d.ts +2 -0
- package/dist/models/SecurityAwarenessWorkflowModel.js +8 -0
- package/dist/models/SecurityThreatChatModel.d.ts +2 -0
- package/dist/models/SecurityThreatChatModel.js +8 -0
- package/dist/models/SecurityThreatWorkflowModel.d.ts +2 -0
- package/dist/models/SecurityThreatWorkflowModel.js +8 -0
- package/dist/models/ServiceExtensionAfter60ChatModel.d.ts +2 -0
- package/dist/models/ServiceExtensionAfter60ChatModel.js +8 -0
- package/dist/models/ServiceExtensionAfter60WorkflowModel.d.ts +2 -0
- package/dist/models/ServiceExtensionAfter60WorkflowModel.js +8 -0
- package/dist/models/StudyLeaveChatModel.d.ts +2 -0
- package/dist/models/StudyLeaveChatModel.js +8 -0
- package/dist/models/StudyLeaveWorkflowModel.d.ts +2 -0
- package/dist/models/StudyLeaveWorkflowModel.js +8 -0
- package/dist/models/TrainingChatModel.d.ts +2 -0
- package/dist/models/TrainingChatModel.js +8 -0
- package/dist/models/TrainingRoomBookingChatModel.d.ts +2 -0
- package/dist/models/TrainingRoomBookingChatModel.js +8 -0
- package/dist/models/TrainingRoomBookingWorkflowModel.d.ts +2 -0
- package/dist/models/TrainingRoomBookingWorkflowModel.js +8 -0
- package/dist/models/TrainingWorkflowModel.d.ts +2 -0
- package/dist/models/TrainingWorkflowModel.js +8 -0
- package/dist/models/VipHallChatModel.d.ts +2 -0
- package/dist/models/VipHallChatModel.js +8 -0
- package/dist/models/VipHallWorkflowModel.d.ts +2 -0
- package/dist/models/VipHallWorkflowModel.js +8 -0
- package/dist/models/VpnRequestChatModel.d.ts +2 -0
- package/dist/models/VpnRequestChatModel.js +8 -0
- package/dist/models/VpnWorkflowModel.d.ts +2 -0
- package/dist/models/VpnWorkflowModel.js +8 -0
- package/dist/models/WorkingHoursExtensionChatModel.d.ts +2 -0
- package/dist/models/WorkingHoursExtensionChatModel.js +8 -0
- package/dist/models/WorkingHoursExtensionWorkflowModel.d.ts +2 -0
- package/dist/models/WorkingHoursExtensionWorkflowModel.js +8 -0
- package/package.json +1 -1
- package/sql/add_all_workflow_chat_arabic_columns.sql +1 -0
- package/sql/caa_api_payload_changes_2026_07.sql +32 -0
- package/src/i18n/workflow-chat-i18n.json +162 -1
- package/src/i18n/workflow-chat-message.builder.ts +680 -13
- package/src/models/AccessCardChatModel.ts +6 -0
- package/src/models/AccessCardWorkflowModel.ts +6 -0
- package/src/models/AccommodationChatModel.ts +7 -1
- package/src/models/AccommodationWorkflowModel.ts +6 -0
- package/src/models/AirportEntryPermitChatModel.ts +6 -0
- package/src/models/AirportEntryPermitWorkflowModel.ts +6 -0
- package/src/models/AnnualTrainingPlanChatModel.ts +6 -0
- package/src/models/AnnualTrainingPlanWorkflowModel.ts +6 -0
- package/src/models/AppealAgainstAdministrativeDecisionRequestModel.ts +8 -8
- package/src/models/AssignTasksEmpChatModel.ts +6 -0
- package/src/models/AssignTasksEmpWorkflowModel.ts +6 -0
- package/src/models/ComplaintLostPropertyReportChatModel.ts +6 -0
- package/src/models/ComplaintLostPropertyReportWorkflowModel.ts +6 -0
- package/src/models/CyberSecurityAuditRequestModel.ts +6 -0
- package/src/models/CyberSecurityRiskManagementRiskModel.ts +6 -0
- package/src/models/DutyMissionChatModel.ts +6 -0
- package/src/models/DutyMissionWorkflowModel.ts +6 -0
- package/src/models/EventSupportChatModel.ts +6 -0
- package/src/models/EventSupportWorkflowModel.ts +6 -0
- package/src/models/FollowUpReportChatModel.ts +6 -0
- package/src/models/FollowUpReportWorkflowModel.ts +6 -0
- package/src/models/FoodChatModel.ts +6 -0
- package/src/models/FoodWorkflowModel.ts +6 -0
- package/src/models/HallChatModel.ts +6 -0
- package/src/models/HallWorkflowModel.ts +6 -0
- package/src/models/HotelChatModel.ts +6 -0
- package/src/models/HotelWorkFlowModel.ts +6 -0
- package/src/models/HousingContractCancelChatModel.ts +6 -0
- package/src/models/HousingContractCancelWorkflowModel.ts +6 -0
- package/src/models/HousingContractRenewalChatModel.ts +6 -0
- package/src/models/HousingContractRenewalWorkflowModel.ts +6 -0
- package/src/models/HrServiceChatModel.ts +6 -0
- package/src/models/HrServiceWorkflowModel.ts +6 -0
- package/src/models/ITRequestChatModel.ts +6 -0
- package/src/models/ImportExportMaterialChatModel.ts +6 -0
- package/src/models/ImportExportMaterialWorkflowModel.ts +6 -0
- package/src/models/InformationSecurityChatModel.ts +6 -0
- package/src/models/InformationSecurityWorkflowModel.ts +6 -0
- package/src/models/ItWorkflowModel.ts +6 -0
- package/src/models/LegalComplaintChatModel.ts +6 -0
- package/src/models/LegalComplaintWorkflowModel.ts +6 -0
- package/src/models/LegalConsultationChatModel.ts +6 -0
- package/src/models/LegalConsultationWorkflowModel.ts +6 -0
- package/src/models/LegalContractReviewChatModel.ts +6 -0
- package/src/models/LegalContractReviewWorkflowModel.ts +6 -0
- package/src/models/LogisticsChatModel.ts +6 -0
- package/src/models/LogisticsVehicleMaintenanceChatModel.ts +6 -0
- package/src/models/LogisticsVehicleMaintenanceWorkflowModel.ts +6 -0
- package/src/models/LogisticsWorkflowModel.ts +6 -0
- package/src/models/MaintenanceChatModel.ts +6 -0
- package/src/models/MaintenanceExternalStationsChatModel.ts +6 -0
- package/src/models/MaintenanceExternalStationsWorkflowModel.ts +6 -0
- package/src/models/MaintenanceRequestModel.ts +2 -0
- package/src/models/MaintenanceWorkflowModel.ts +6 -0
- package/src/models/MediaPublicationsChatModel.ts +6 -0
- package/src/models/MediaPublicationsWorkflowModel.ts +6 -0
- package/src/models/MultiPurposeHallChatModel.ts +6 -0
- package/src/models/MultiPurposeHallWorkflowModel.ts +6 -0
- package/src/models/RequestATenderRequestModel.ts +6 -0
- package/src/models/RequestForCoverageChatModel.ts +6 -0
- package/src/models/RequestForCoverageWorkflowModel.ts +6 -0
- package/src/models/RequestForPresidentsCoverageChatModel.ts +6 -0
- package/src/models/RequestForPresidentsCoverageWorkflowModel.ts +6 -0
- package/src/models/ResidentialUnitRentalChatModel.ts +6 -0
- package/src/models/ResidentialUnitRentalRequestModel.ts +2 -2
- package/src/models/ResidentialUnitRentalWorkflowModel.ts +8 -2
- package/src/models/RespondToEnquiriesChatModel.ts +6 -0
- package/src/models/RespondToEnquiriesWorkflowModel.ts +6 -0
- package/src/models/ScholarshipChatModel.ts +6 -0
- package/src/models/ScholarshipWorkflowModel.ts +6 -0
- package/src/models/SecurityAwarenessChatModel.ts +6 -0
- package/src/models/SecurityAwarenessWorkflowModel.ts +6 -0
- package/src/models/SecurityThreatChatModel.ts +6 -0
- package/src/models/SecurityThreatWorkflowModel.ts +6 -0
- package/src/models/ServiceExtensionAfter60ChatModel.ts +6 -0
- package/src/models/ServiceExtensionAfter60WorkflowModel.ts +6 -0
- package/src/models/StudyLeaveChatModel.ts +6 -0
- package/src/models/StudyLeaveWorkflowModel.ts +6 -0
- package/src/models/TrainingChatModel.ts +6 -0
- package/src/models/TrainingRoomBookingChatModel.ts +6 -0
- package/src/models/TrainingRoomBookingWorkflowModel.ts +6 -0
- package/src/models/TrainingWorkflowModel.ts +6 -0
- package/src/models/VipHallChatModel.ts +6 -0
- package/src/models/VipHallWorkflowModel.ts +6 -0
- package/src/models/VpnRequestChatModel.ts +6 -0
- package/src/models/VpnWorkflowModel.ts +6 -0
- package/src/models/WorkingHoursExtensionChatModel.ts +6 -0
- package/src/models/WorkingHoursExtensionWorkflowModel.ts +6 -0
|
@@ -11,6 +11,7 @@ export type BilingualText = { en: string; ar: string };
|
|
|
11
11
|
export type WorkflowChatI18nCatalog = {
|
|
12
12
|
workflowTemplates: Record<string, BilingualText>;
|
|
13
13
|
chatTemplates: Record<string, BilingualText>;
|
|
14
|
+
notificationTemplates?: Record<string, BilingualText>;
|
|
14
15
|
workflowStatusLabels: Record<string, string>;
|
|
15
16
|
chatStatusLabels: Record<string, string>;
|
|
16
17
|
};
|
|
@@ -41,6 +42,7 @@ export type WorkflowMessageAction =
|
|
|
41
42
|
|
|
42
43
|
export type ChatMessageAction =
|
|
43
44
|
| 'cancellation_submitted'
|
|
45
|
+
| 'request_submitted'
|
|
44
46
|
| 'request_received'
|
|
45
47
|
| 'approved'
|
|
46
48
|
| 'rejected'
|
|
@@ -60,6 +62,7 @@ export type ChatMessageContext = BilingualActorNames & {
|
|
|
60
62
|
|
|
61
63
|
const WORKFLOW_TEMPLATES = catalog.workflowTemplates as Record<string, BilingualText>;
|
|
62
64
|
const CHAT_TEMPLATES = catalog.chatTemplates as Record<string, BilingualText>;
|
|
65
|
+
const NOTIFICATION_TEMPLATES = (catalog as { notificationTemplates?: Record<string, BilingualText> }).notificationTemplates ?? {};
|
|
63
66
|
const WORKFLOW_STATUS_LABELS = catalog.workflowStatusLabels as Record<string, string>;
|
|
64
67
|
const CHAT_STATUS_LABELS = catalog.chatStatusLabels as Record<string, string>;
|
|
65
68
|
|
|
@@ -305,6 +308,16 @@ export function buildSynchronizedChatMessage(ctx: ChatMessageContext): Bilingual
|
|
|
305
308
|
{ userName: userAr, employeeId },
|
|
306
309
|
);
|
|
307
310
|
}
|
|
311
|
+
case 'request_submitted': {
|
|
312
|
+
const userEn = ctx.userName?.trim() || 'Unknown User';
|
|
313
|
+
const userAr = resolveBilingualName(userEn, ctx.userArabicName);
|
|
314
|
+
const employeeId = String(ctx.employeeId ?? 'N/A');
|
|
315
|
+
return chatTemplate(
|
|
316
|
+
'request_submitted_by',
|
|
317
|
+
{ userName: userEn, employeeId },
|
|
318
|
+
{ userName: userAr, employeeId },
|
|
319
|
+
);
|
|
320
|
+
}
|
|
308
321
|
case 'request_received':
|
|
309
322
|
return chatTemplate('request_received');
|
|
310
323
|
case 'approved':
|
|
@@ -331,6 +344,61 @@ export function buildSynchronizedChatMessage(ctx: ChatMessageContext): Bilingual
|
|
|
331
344
|
|
|
332
345
|
// ─── Backward-compatible aliases used by Cancellation pilot ───────────────────
|
|
333
346
|
|
|
347
|
+
/** Standard workflow log UPDATE fields for all CAA module repositories. */
|
|
348
|
+
export function buildWorkflowLogUpdateFields(params: {
|
|
349
|
+
approvalStatus: string;
|
|
350
|
+
workflowStatus: string;
|
|
351
|
+
roleName?: string | null;
|
|
352
|
+
roleArabicName?: string | null;
|
|
353
|
+
comment?: string | null;
|
|
354
|
+
}): { content: string; content_ar: string; status: string; status_ar: string | null } {
|
|
355
|
+
let action: WorkflowMessageAction;
|
|
356
|
+
if (params.approvalStatus === 'Approved') action = 'approved';
|
|
357
|
+
else if (params.approvalStatus === 'Rejected') action = 'rejected';
|
|
358
|
+
else if (params.approvalStatus === 'Returned for Modification') action = 'returned_for_modification';
|
|
359
|
+
else action = 'approval_pending_update';
|
|
360
|
+
|
|
361
|
+
const bilingual = buildSynchronizedWorkflowMessage({
|
|
362
|
+
action,
|
|
363
|
+
roleName: params.roleName,
|
|
364
|
+
roleArabicName: params.roleArabicName,
|
|
365
|
+
comment: params.comment,
|
|
366
|
+
});
|
|
367
|
+
|
|
368
|
+
return {
|
|
369
|
+
content: bilingual.en,
|
|
370
|
+
content_ar: bilingual.ar,
|
|
371
|
+
status: params.workflowStatus,
|
|
372
|
+
status_ar: resolveWorkflowStatusAr(params.workflowStatus),
|
|
373
|
+
};
|
|
374
|
+
}
|
|
375
|
+
|
|
376
|
+
/** Bilingual workflow insert fields from builder output. */
|
|
377
|
+
export function toWorkflowPersistFields(
|
|
378
|
+
bilingual: BilingualText,
|
|
379
|
+
status: string,
|
|
380
|
+
): { content: string; content_ar: string; status: string; status_ar: string | null } {
|
|
381
|
+
return {
|
|
382
|
+
content: bilingual.en,
|
|
383
|
+
content_ar: bilingual.ar,
|
|
384
|
+
status,
|
|
385
|
+
status_ar: resolveWorkflowStatusAr(status),
|
|
386
|
+
};
|
|
387
|
+
}
|
|
388
|
+
|
|
389
|
+
/** Bilingual chat insert fields from builder output. */
|
|
390
|
+
export function toChatPersistFields(
|
|
391
|
+
bilingual: BilingualText,
|
|
392
|
+
status: string,
|
|
393
|
+
): { message: string; message_ar: string; status: string; status_ar: string | null } {
|
|
394
|
+
return {
|
|
395
|
+
message: bilingual.en,
|
|
396
|
+
message_ar: bilingual.ar,
|
|
397
|
+
status,
|
|
398
|
+
status_ar: resolveChatStatusAr(status),
|
|
399
|
+
};
|
|
400
|
+
}
|
|
401
|
+
|
|
334
402
|
export function buildApprovalWorkflowContent(params: {
|
|
335
403
|
status: 'Approved' | 'Rejected' | 'Returned for Modification' | 'Pending' | string;
|
|
336
404
|
roleName?: string | null;
|
|
@@ -378,6 +446,22 @@ export function buildApprovalChatMessage(params: {
|
|
|
378
446
|
roleArabicName?: string | null;
|
|
379
447
|
comment?: string | null;
|
|
380
448
|
}): BilingualText {
|
|
449
|
+
if (params.status === 'Closed') {
|
|
450
|
+
return buildClosedChatMessage({
|
|
451
|
+
roleName: params.roleName,
|
|
452
|
+
roleArabicName: params.roleArabicName,
|
|
453
|
+
comment: params.comment,
|
|
454
|
+
});
|
|
455
|
+
}
|
|
456
|
+
if (params.status === 'Request For Change' || params.status === 'RFC') {
|
|
457
|
+
return buildRequestForChangeChatMessage({
|
|
458
|
+
roleName: params.roleName,
|
|
459
|
+
roleArabicName: params.roleArabicName,
|
|
460
|
+
comment: params.comment,
|
|
461
|
+
variant: 'by',
|
|
462
|
+
});
|
|
463
|
+
}
|
|
464
|
+
|
|
381
465
|
let action: ChatMessageAction = 'approved';
|
|
382
466
|
if (params.status === 'Rejected') action = 'rejected';
|
|
383
467
|
else if (params.status === 'Returned for Modification') action = 'returned_for_modification';
|
|
@@ -390,6 +474,589 @@ export function buildApprovalChatMessage(params: {
|
|
|
390
474
|
});
|
|
391
475
|
}
|
|
392
476
|
|
|
477
|
+
// ─── Specialized chat/workflow builders ─────────────────────────────────────
|
|
478
|
+
|
|
479
|
+
function formatDotCommentSuffix(comment?: string | null): string {
|
|
480
|
+
const text = comment?.trim();
|
|
481
|
+
return text ? `. Comment: ${text}` : '';
|
|
482
|
+
}
|
|
483
|
+
|
|
484
|
+
function formatColonCommentSuffix(comment?: string | null): string {
|
|
485
|
+
const text = comment?.trim();
|
|
486
|
+
return text ? `: ${text}` : '';
|
|
487
|
+
}
|
|
488
|
+
|
|
489
|
+
function formatReassignCommentSuffix(comment?: string | null): string {
|
|
490
|
+
const text = comment?.trim();
|
|
491
|
+
return text ? `:${text}` : '';
|
|
492
|
+
}
|
|
493
|
+
|
|
494
|
+
export function buildClosedChatMessage(params: {
|
|
495
|
+
roleName?: string | null;
|
|
496
|
+
roleArabicName?: string | null;
|
|
497
|
+
comment?: string | null;
|
|
498
|
+
}): BilingualText {
|
|
499
|
+
const roleEn = params.roleName?.trim() || 'Unknown Role';
|
|
500
|
+
const roleAr = resolveBilingualName(roleEn, params.roleArabicName);
|
|
501
|
+
const comment = formatDotCommentSuffix(params.comment);
|
|
502
|
+
return renderSynchronizedChatMessage(
|
|
503
|
+
'request_closed_by_role',
|
|
504
|
+
{ roleName: roleEn, comment },
|
|
505
|
+
{ roleName: roleAr, comment },
|
|
506
|
+
);
|
|
507
|
+
}
|
|
508
|
+
|
|
509
|
+
export function buildClosedWorkflowMessage(params: {
|
|
510
|
+
roleName?: string | null;
|
|
511
|
+
roleArabicName?: string | null;
|
|
512
|
+
comment?: string | null;
|
|
513
|
+
}): BilingualText {
|
|
514
|
+
const comment = formatWorkflowCommentSuffix(params.comment);
|
|
515
|
+
const roleEn = params.roleName?.trim();
|
|
516
|
+
if (roleEn) {
|
|
517
|
+
const roleAr = resolveBilingualName(roleEn, params.roleArabicName);
|
|
518
|
+
return renderSynchronizedWorkflowMessage(
|
|
519
|
+
'request_closed_by',
|
|
520
|
+
{ name: roleEn, comment },
|
|
521
|
+
{ name: roleAr, comment },
|
|
522
|
+
);
|
|
523
|
+
}
|
|
524
|
+
return renderSynchronizedWorkflowMessage('request_closed', { comment }, { comment });
|
|
525
|
+
}
|
|
526
|
+
|
|
527
|
+
export function buildRequestForChangeChatMessage(params: {
|
|
528
|
+
roleName?: string | null;
|
|
529
|
+
roleArabicName?: string | null;
|
|
530
|
+
comment?: string | null;
|
|
531
|
+
variant?: 'by' | 'requested_by';
|
|
532
|
+
}): BilingualText {
|
|
533
|
+
const roleEn = params.roleName?.trim() || 'Unknown Role';
|
|
534
|
+
const roleAr = resolveBilingualName(roleEn, params.roleArabicName);
|
|
535
|
+
const comment =
|
|
536
|
+
params.variant === 'requested_by'
|
|
537
|
+
? formatChatCommentSuffix(params.comment)
|
|
538
|
+
: formatColonCommentSuffix(params.comment);
|
|
539
|
+
const key =
|
|
540
|
+
params.variant === 'requested_by'
|
|
541
|
+
? 'request_for_change_requested_by_role'
|
|
542
|
+
: 'request_for_change_by_role';
|
|
543
|
+
return renderSynchronizedChatMessage(key, { roleName: roleEn, comment }, { roleName: roleAr, comment });
|
|
544
|
+
}
|
|
545
|
+
|
|
546
|
+
export function buildAttachmentUploadedChatMessage(fileName: string): BilingualText {
|
|
547
|
+
const name = fileName?.trim() || 'file';
|
|
548
|
+
return renderSynchronizedChatMessage('attachment_uploaded', { fileName: name }, { fileName: name });
|
|
549
|
+
}
|
|
550
|
+
|
|
551
|
+
/** User-typed chat text, or bilingual [Attachment] placeholder when empty. */
|
|
552
|
+
export function buildUserOrAttachmentChatMessage(userMessage?: string | null): BilingualText {
|
|
553
|
+
const text = userMessage?.trim();
|
|
554
|
+
if (text) return { en: text, ar: text };
|
|
555
|
+
return chatTemplate('attachment_placeholder');
|
|
556
|
+
}
|
|
557
|
+
|
|
558
|
+
export function buildTaskInProgressChatMessage(params: {
|
|
559
|
+
roleName?: string | null;
|
|
560
|
+
roleArabicName?: string | null;
|
|
561
|
+
}): BilingualText {
|
|
562
|
+
const roleEn = params.roleName?.trim() || 'Employee';
|
|
563
|
+
const roleAr = resolveBilingualName(roleEn, params.roleArabicName);
|
|
564
|
+
return renderSynchronizedChatMessage(
|
|
565
|
+
'task_status_in_progress_by_role',
|
|
566
|
+
{ roleName: roleEn },
|
|
567
|
+
{ roleName: roleAr },
|
|
568
|
+
);
|
|
569
|
+
}
|
|
570
|
+
|
|
571
|
+
export function buildTaskCompletedChatMessage(params: {
|
|
572
|
+
roleName?: string | null;
|
|
573
|
+
roleArabicName?: string | null;
|
|
574
|
+
comment?: string | null;
|
|
575
|
+
}): BilingualText {
|
|
576
|
+
const roleEn = params.roleName?.trim() || 'Employee';
|
|
577
|
+
const roleAr = resolveBilingualName(roleEn, params.roleArabicName);
|
|
578
|
+
const comment = formatDotCommentSuffix(params.comment);
|
|
579
|
+
return renderSynchronizedChatMessage(
|
|
580
|
+
'task_completed_by_role',
|
|
581
|
+
{ roleName: roleEn, comment },
|
|
582
|
+
{ roleName: roleAr, comment },
|
|
583
|
+
);
|
|
584
|
+
}
|
|
585
|
+
|
|
586
|
+
export function buildTaskStatusUpdatedChatMessage(status: string, statusAr?: string | null): BilingualText {
|
|
587
|
+
const statusEn = status?.trim() || 'Updated';
|
|
588
|
+
const statusArResolved = statusAr?.trim() || resolveChatStatusAr(statusEn) || statusEn;
|
|
589
|
+
return renderSynchronizedChatMessage(
|
|
590
|
+
'task_status_updated',
|
|
591
|
+
{ status: statusEn },
|
|
592
|
+
{ status: statusArResolved },
|
|
593
|
+
);
|
|
594
|
+
}
|
|
595
|
+
|
|
596
|
+
export function buildItHelpdeskAssignedChatMessage(params: {
|
|
597
|
+
level: number;
|
|
598
|
+
assignedRoleName?: string | null;
|
|
599
|
+
assignedRoleArabicName?: string | null;
|
|
600
|
+
assignedUserName?: string | null;
|
|
601
|
+
assignedUserArabicName?: string | null;
|
|
602
|
+
comment?: string | null;
|
|
603
|
+
}): BilingualText {
|
|
604
|
+
const assignedRoleEn = params.assignedRoleName?.trim() || 'Role';
|
|
605
|
+
const assignedRoleAr = resolveBilingualName(assignedRoleEn, params.assignedRoleArabicName);
|
|
606
|
+
const assignedUserEn = params.assignedUserName?.trim() || 'User';
|
|
607
|
+
const assignedUserAr = resolveBilingualName(assignedUserEn, params.assignedUserArabicName);
|
|
608
|
+
const comment = params.comment?.trim() ? ` - ${params.comment.trim()}` : '';
|
|
609
|
+
const templateKey = params.level === 1 ? 'it_helpdesk_hos_assigned' : 'it_helpdesk_technician_assigned';
|
|
610
|
+
const enParams: Record<string, string> = {
|
|
611
|
+
assignedRoleName: assignedRoleEn,
|
|
612
|
+
assignedUserName: assignedUserEn,
|
|
613
|
+
comment,
|
|
614
|
+
};
|
|
615
|
+
const arParams: Record<string, string> = {
|
|
616
|
+
assignedRoleName: assignedRoleAr,
|
|
617
|
+
assignedUserName: assignedUserAr,
|
|
618
|
+
comment,
|
|
619
|
+
};
|
|
620
|
+
if (params.level !== 1) {
|
|
621
|
+
enParams.level = String(params.level);
|
|
622
|
+
arParams.level = String(params.level);
|
|
623
|
+
}
|
|
624
|
+
return renderSynchronizedChatMessage(templateKey, enParams, arParams);
|
|
625
|
+
}
|
|
626
|
+
|
|
627
|
+
export function buildItHelpdeskReassignedChatMessage(params: {
|
|
628
|
+
level: number;
|
|
629
|
+
approverRoleName?: string | null;
|
|
630
|
+
approverRoleArabicName?: string | null;
|
|
631
|
+
reassignedRoleName?: string | null;
|
|
632
|
+
reassignedRoleArabicName?: string | null;
|
|
633
|
+
comment?: string | null;
|
|
634
|
+
}): BilingualText {
|
|
635
|
+
const approverEn = params.approverRoleName?.trim() || 'Role';
|
|
636
|
+
const approverAr = resolveBilingualName(approverEn, params.approverRoleArabicName);
|
|
637
|
+
const comment = formatReassignCommentSuffix(params.comment);
|
|
638
|
+
if (params.level === 1) {
|
|
639
|
+
const reassignedEn = params.reassignedRoleName?.trim() || 'Role';
|
|
640
|
+
const reassignedAr = resolveBilingualName(reassignedEn, params.reassignedRoleArabicName);
|
|
641
|
+
return renderSynchronizedChatMessage(
|
|
642
|
+
'it_helpdesk_reassigned_to_role',
|
|
643
|
+
{ approverRoleName: approverEn, reassignedRoleName: reassignedEn, comment },
|
|
644
|
+
{ approverRoleName: approverAr, reassignedRoleName: reassignedAr, comment },
|
|
645
|
+
);
|
|
646
|
+
}
|
|
647
|
+
if (params.level === 2) {
|
|
648
|
+
return renderSynchronizedChatMessage(
|
|
649
|
+
'it_helpdesk_reassigned_to_l3',
|
|
650
|
+
{ approverRoleName: approverEn, comment },
|
|
651
|
+
{ approverRoleName: approverAr, comment },
|
|
652
|
+
);
|
|
653
|
+
}
|
|
654
|
+
const level = String(params.level);
|
|
655
|
+
return renderSynchronizedChatMessage(
|
|
656
|
+
'it_helpdesk_reassigned_generic',
|
|
657
|
+
{ approverRoleName: approverEn, level, comment },
|
|
658
|
+
{ approverRoleName: approverAr, level, comment },
|
|
659
|
+
);
|
|
660
|
+
}
|
|
661
|
+
|
|
662
|
+
export function buildRequestSubmittedWithRefChatMessage(params: {
|
|
663
|
+
requestLabel: string;
|
|
664
|
+
requestLabelAr?: string | null;
|
|
665
|
+
requestId: number | string;
|
|
666
|
+
userName?: string | null;
|
|
667
|
+
userArabicName?: string | null;
|
|
668
|
+
employeeId?: string | number | null;
|
|
669
|
+
}): BilingualText {
|
|
670
|
+
const userEn = params.userName?.trim() || 'Unknown User';
|
|
671
|
+
const userAr = resolveBilingualName(userEn, params.userArabicName);
|
|
672
|
+
const labelEn = params.requestLabel?.trim() || 'Request';
|
|
673
|
+
const labelAr = params.requestLabelAr?.trim() || labelEn;
|
|
674
|
+
const requestId = String(params.requestId);
|
|
675
|
+
const employeeId = String(params.employeeId ?? 'N/A');
|
|
676
|
+
return renderSynchronizedChatMessage(
|
|
677
|
+
'request_submitted_with_ref',
|
|
678
|
+
{ requestLabel: labelEn, requestId, userName: userEn, employeeId },
|
|
679
|
+
{ requestLabel: labelAr, requestId, userName: userAr, employeeId },
|
|
680
|
+
);
|
|
681
|
+
}
|
|
682
|
+
|
|
683
|
+
export function buildSecurityAccessApprovalChatMessage(params: {
|
|
684
|
+
productLabel: string;
|
|
685
|
+
productLabelAr?: string | null;
|
|
686
|
+
requestId: number | string;
|
|
687
|
+
approvalLevel: number | string;
|
|
688
|
+
decision: 'approve' | 'reject';
|
|
689
|
+
comment?: string | null;
|
|
690
|
+
}): BilingualText {
|
|
691
|
+
const statusWord = params.decision === 'approve' ? 'approved' : 'rejected';
|
|
692
|
+
const statusWordAr = params.decision === 'approve' ? 'الموافقة على' : 'رفض';
|
|
693
|
+
const comment = params.comment?.trim() ? ` Comment: ${params.comment.trim()}` : '';
|
|
694
|
+
const labelEn = params.productLabel?.trim() || 'Security Access';
|
|
695
|
+
const labelAr = params.productLabelAr?.trim() || labelEn;
|
|
696
|
+
return renderSynchronizedChatMessage(
|
|
697
|
+
'security_access_approval_step',
|
|
698
|
+
{
|
|
699
|
+
productLabel: labelEn,
|
|
700
|
+
requestId: String(params.requestId),
|
|
701
|
+
statusWord,
|
|
702
|
+
approvalLevel: String(params.approvalLevel),
|
|
703
|
+
comment,
|
|
704
|
+
statusWordAr,
|
|
705
|
+
},
|
|
706
|
+
{
|
|
707
|
+
productLabel: labelAr,
|
|
708
|
+
requestId: String(params.requestId),
|
|
709
|
+
statusWord,
|
|
710
|
+
approvalLevel: String(params.approvalLevel),
|
|
711
|
+
comment,
|
|
712
|
+
statusWordAr,
|
|
713
|
+
},
|
|
714
|
+
);
|
|
715
|
+
}
|
|
716
|
+
|
|
717
|
+
function renderSynchronizedNotificationMessage(
|
|
718
|
+
templateKey: string,
|
|
719
|
+
enParams: Record<string, string>,
|
|
720
|
+
arParams: Record<string, string>,
|
|
721
|
+
): BilingualText {
|
|
722
|
+
const tpl = NOTIFICATION_TEMPLATES[templateKey];
|
|
723
|
+
if (!tpl) return { en: templateKey, ar: templateKey };
|
|
724
|
+
return {
|
|
725
|
+
en: interpolate(tpl.en, enParams),
|
|
726
|
+
ar: interpolate(tpl.ar, arParams),
|
|
727
|
+
};
|
|
728
|
+
}
|
|
729
|
+
|
|
730
|
+
function normalizeDisplayValue(value: unknown): string {
|
|
731
|
+
if (value === undefined || value === null || String(value).trim() === '') return 'Not specified';
|
|
732
|
+
return String(value);
|
|
733
|
+
}
|
|
734
|
+
|
|
735
|
+
function normalizeDisplayDate(value: unknown): string {
|
|
736
|
+
if (value === undefined || value === null || String(value).trim() === '') return 'Not specified';
|
|
737
|
+
const d = new Date(value as string | number | Date);
|
|
738
|
+
if (!isNaN(d.getTime())) return d.toISOString().slice(0, 10);
|
|
739
|
+
return String(value);
|
|
740
|
+
}
|
|
741
|
+
|
|
742
|
+
export function buildItHelpdeskReassignModifiers(params: {
|
|
743
|
+
sectionFrom?: number | null;
|
|
744
|
+
sectionTo?: number | null;
|
|
745
|
+
departmentFrom?: number | null;
|
|
746
|
+
departmentTo?: number | null;
|
|
747
|
+
}): { en: string; ar: string } {
|
|
748
|
+
let en = '';
|
|
749
|
+
let ar = '';
|
|
750
|
+
if (
|
|
751
|
+
params.sectionFrom != null &&
|
|
752
|
+
params.sectionTo != null &&
|
|
753
|
+
params.sectionFrom !== params.sectionTo
|
|
754
|
+
) {
|
|
755
|
+
en += ` (Section modified from ${params.sectionFrom} to ${params.sectionTo})`;
|
|
756
|
+
ar += ` (تم تعديل القسم من ${params.sectionFrom} إلى ${params.sectionTo})`;
|
|
757
|
+
}
|
|
758
|
+
if (
|
|
759
|
+
params.departmentFrom != null &&
|
|
760
|
+
params.departmentTo != null &&
|
|
761
|
+
params.departmentFrom !== params.departmentTo
|
|
762
|
+
) {
|
|
763
|
+
en += ` (Department modified from ${params.departmentFrom} to ${params.departmentTo})`;
|
|
764
|
+
ar += ` (تم تعديل الإدارة من ${params.departmentFrom} إلى ${params.departmentTo})`;
|
|
765
|
+
}
|
|
766
|
+
return { en, ar };
|
|
767
|
+
}
|
|
768
|
+
|
|
769
|
+
export type ItHelpdeskMuscatWorkflowParams =
|
|
770
|
+
| {
|
|
771
|
+
variant: 'hos_assigned';
|
|
772
|
+
approverRoleName: string;
|
|
773
|
+
approverRoleArabicName?: string | null;
|
|
774
|
+
assignedRoleName: string;
|
|
775
|
+
assignedRoleArabicName?: string | null;
|
|
776
|
+
comment?: string | null;
|
|
777
|
+
}
|
|
778
|
+
| {
|
|
779
|
+
variant: 'technician_assigned';
|
|
780
|
+
level: number;
|
|
781
|
+
approverRoleName: string;
|
|
782
|
+
approverRoleArabicName?: string | null;
|
|
783
|
+
comment?: string | null;
|
|
784
|
+
}
|
|
785
|
+
| {
|
|
786
|
+
variant: 'reassigned_technician' | 'reassigned_l3' | 'reassigned_generic';
|
|
787
|
+
approverRoleName: string;
|
|
788
|
+
approverRoleArabicName?: string | null;
|
|
789
|
+
level?: number;
|
|
790
|
+
comment?: string | null;
|
|
791
|
+
modifiers?: { en: string; ar: string };
|
|
792
|
+
}
|
|
793
|
+
| {
|
|
794
|
+
variant: 'closed_level1' | 'closed_level2';
|
|
795
|
+
approverRoleName: string;
|
|
796
|
+
approverRoleArabicName?: string | null;
|
|
797
|
+
comment?: string | null;
|
|
798
|
+
}
|
|
799
|
+
| {
|
|
800
|
+
variant: 'l3_approved' | 'l3_rejected';
|
|
801
|
+
roleName: string;
|
|
802
|
+
roleArabicName?: string | null;
|
|
803
|
+
userName: string;
|
|
804
|
+
userArabicName?: string | null;
|
|
805
|
+
comment?: string | null;
|
|
806
|
+
}
|
|
807
|
+
| {
|
|
808
|
+
variant: 'level_approved';
|
|
809
|
+
level: number;
|
|
810
|
+
approverRoleName: string;
|
|
811
|
+
approverRoleArabicName?: string | null;
|
|
812
|
+
comment?: string | null;
|
|
813
|
+
}
|
|
814
|
+
| {
|
|
815
|
+
variant: 'rejected' | 'l3_step_rejected';
|
|
816
|
+
approverRoleName: string;
|
|
817
|
+
approverRoleArabicName?: string | null;
|
|
818
|
+
comment?: string | null;
|
|
819
|
+
}
|
|
820
|
+
| {
|
|
821
|
+
variant: 'generic_status';
|
|
822
|
+
approverRoleName: string;
|
|
823
|
+
approverRoleArabicName?: string | null;
|
|
824
|
+
status: string;
|
|
825
|
+
comment?: string | null;
|
|
826
|
+
}
|
|
827
|
+
| {
|
|
828
|
+
variant: 'technician_completed' | 'routing_rejected';
|
|
829
|
+
roleName: string;
|
|
830
|
+
roleArabicName?: string | null;
|
|
831
|
+
comment?: string | null;
|
|
832
|
+
}
|
|
833
|
+
| { variant: 'routing_resolved' };
|
|
834
|
+
|
|
835
|
+
export function buildItHelpdeskMuscatWorkflowLog(params: ItHelpdeskMuscatWorkflowParams): BilingualText {
|
|
836
|
+
const comment = formatColonCommentSuffix(
|
|
837
|
+
'comment' in params ? params.comment : undefined,
|
|
838
|
+
);
|
|
839
|
+
const modifiers = 'modifiers' in params && params.modifiers ? params.modifiers : { en: '', ar: '' };
|
|
840
|
+
|
|
841
|
+
switch (params.variant) {
|
|
842
|
+
case 'hos_assigned': {
|
|
843
|
+
const approverEn = params.approverRoleName.trim();
|
|
844
|
+
const approverAr = resolveBilingualName(approverEn, params.approverRoleArabicName);
|
|
845
|
+
const assignedEn = params.assignedRoleName.trim();
|
|
846
|
+
const assignedAr = resolveBilingualName(assignedEn, params.assignedRoleArabicName);
|
|
847
|
+
return renderSynchronizedWorkflowMessage(
|
|
848
|
+
'it_helpdesk_wf_hos_assigned',
|
|
849
|
+
{ approverRoleName: approverEn, assignedRoleName: assignedEn, comment },
|
|
850
|
+
{ approverRoleName: approverAr, assignedRoleName: assignedAr, comment },
|
|
851
|
+
);
|
|
852
|
+
}
|
|
853
|
+
case 'technician_assigned': {
|
|
854
|
+
const approverEn = params.approverRoleName.trim();
|
|
855
|
+
const approverAr = resolveBilingualName(approverEn, params.approverRoleArabicName);
|
|
856
|
+
return renderSynchronizedWorkflowMessage(
|
|
857
|
+
'it_helpdesk_wf_technician_assigned',
|
|
858
|
+
{ level: String(params.level), approverRoleName: approverEn, comment },
|
|
859
|
+
{ level: String(params.level), approverRoleName: approverAr, comment },
|
|
860
|
+
);
|
|
861
|
+
}
|
|
862
|
+
case 'reassigned_technician': {
|
|
863
|
+
const approverEn = params.approverRoleName.trim();
|
|
864
|
+
const approverAr = resolveBilingualName(approverEn, params.approverRoleArabicName);
|
|
865
|
+
return renderSynchronizedWorkflowMessage(
|
|
866
|
+
'it_helpdesk_wf_reassigned_technician',
|
|
867
|
+
{ approverRoleName: approverEn, comment, modifiers: modifiers.en },
|
|
868
|
+
{ approverRoleName: approverAr, comment, modifiers: modifiers.ar },
|
|
869
|
+
);
|
|
870
|
+
}
|
|
871
|
+
case 'reassigned_l3': {
|
|
872
|
+
const approverEn = params.approverRoleName.trim();
|
|
873
|
+
const approverAr = resolveBilingualName(approverEn, params.approverRoleArabicName);
|
|
874
|
+
return renderSynchronizedWorkflowMessage(
|
|
875
|
+
'it_helpdesk_wf_reassigned_l3',
|
|
876
|
+
{ approverRoleName: approverEn, comment, modifiers: modifiers.en },
|
|
877
|
+
{ approverRoleName: approverAr, comment, modifiers: modifiers.ar },
|
|
878
|
+
);
|
|
879
|
+
}
|
|
880
|
+
case 'reassigned_generic': {
|
|
881
|
+
const approverEn = params.approverRoleName.trim();
|
|
882
|
+
const approverAr = resolveBilingualName(approverEn, params.approverRoleArabicName);
|
|
883
|
+
const level = String(params.level ?? '');
|
|
884
|
+
return renderSynchronizedWorkflowMessage(
|
|
885
|
+
'it_helpdesk_wf_reassigned_generic',
|
|
886
|
+
{ approverRoleName: approverEn, level, comment, modifiers: modifiers.en },
|
|
887
|
+
{ approverRoleName: approverAr, level, comment, modifiers: modifiers.ar },
|
|
888
|
+
);
|
|
889
|
+
}
|
|
890
|
+
case 'closed_level1': {
|
|
891
|
+
const approverEn = params.approverRoleName.trim();
|
|
892
|
+
const approverAr = resolveBilingualName(approverEn, params.approverRoleArabicName);
|
|
893
|
+
return renderSynchronizedWorkflowMessage(
|
|
894
|
+
'it_helpdesk_wf_closed_request',
|
|
895
|
+
{ approverRoleName: approverEn, comment },
|
|
896
|
+
{ approverRoleName: approverAr, comment },
|
|
897
|
+
);
|
|
898
|
+
}
|
|
899
|
+
case 'closed_level2': {
|
|
900
|
+
const approverEn = params.approverRoleName.trim();
|
|
901
|
+
const approverAr = resolveBilingualName(approverEn, params.approverRoleArabicName);
|
|
902
|
+
return renderSynchronizedWorkflowMessage(
|
|
903
|
+
'it_helpdesk_wf_closed_request_cap',
|
|
904
|
+
{ approverRoleName: approverEn, comment },
|
|
905
|
+
{ approverRoleName: approverAr, comment },
|
|
906
|
+
);
|
|
907
|
+
}
|
|
908
|
+
case 'l3_approved': {
|
|
909
|
+
const roleEn = params.roleName.trim();
|
|
910
|
+
const roleAr = resolveBilingualName(roleEn, params.roleArabicName);
|
|
911
|
+
const userEn = params.userName.trim();
|
|
912
|
+
const userAr = resolveBilingualName(userEn, params.userArabicName);
|
|
913
|
+
return renderSynchronizedWorkflowMessage(
|
|
914
|
+
'it_helpdesk_wf_l3_approved_by',
|
|
915
|
+
{ roleName: roleEn, userName: userEn, comment },
|
|
916
|
+
{ roleName: roleAr, userName: userAr, comment },
|
|
917
|
+
);
|
|
918
|
+
}
|
|
919
|
+
case 'l3_rejected': {
|
|
920
|
+
const roleEn = params.roleName.trim();
|
|
921
|
+
const roleAr = resolveBilingualName(roleEn, params.roleArabicName);
|
|
922
|
+
const userEn = params.userName.trim();
|
|
923
|
+
const userAr = resolveBilingualName(userEn, params.userArabicName);
|
|
924
|
+
return renderSynchronizedWorkflowMessage(
|
|
925
|
+
'it_helpdesk_wf_l3_rejected_by',
|
|
926
|
+
{ roleName: roleEn, userName: userEn, comment },
|
|
927
|
+
{ roleName: roleAr, userName: userAr, comment },
|
|
928
|
+
);
|
|
929
|
+
}
|
|
930
|
+
case 'level_approved': {
|
|
931
|
+
const approverEn = params.approverRoleName.trim();
|
|
932
|
+
const approverAr = resolveBilingualName(approverEn, params.approverRoleArabicName);
|
|
933
|
+
return renderSynchronizedWorkflowMessage(
|
|
934
|
+
'it_helpdesk_wf_level_approved',
|
|
935
|
+
{ level: String(params.level), approverRoleName: approverEn, comment },
|
|
936
|
+
{ level: String(params.level), approverRoleName: approverAr, comment },
|
|
937
|
+
);
|
|
938
|
+
}
|
|
939
|
+
case 'rejected':
|
|
940
|
+
case 'l3_step_rejected': {
|
|
941
|
+
const key =
|
|
942
|
+
params.variant === 'l3_step_rejected'
|
|
943
|
+
? 'it_helpdesk_wf_l3_step_rejected'
|
|
944
|
+
: 'it_helpdesk_wf_rejected';
|
|
945
|
+
const roleEn = params.approverRoleName.trim();
|
|
946
|
+
const roleAr = resolveBilingualName(roleEn, params.approverRoleArabicName);
|
|
947
|
+
return renderSynchronizedWorkflowMessage(
|
|
948
|
+
key,
|
|
949
|
+
{ approverRoleName: roleEn, roleName: roleEn, comment },
|
|
950
|
+
{ approverRoleName: roleAr, roleName: roleAr, comment },
|
|
951
|
+
);
|
|
952
|
+
}
|
|
953
|
+
case 'generic_status': {
|
|
954
|
+
const approverEn = params.approverRoleName.trim();
|
|
955
|
+
const approverAr = resolveBilingualName(approverEn, params.approverRoleArabicName);
|
|
956
|
+
const statusEn = params.status.toLowerCase();
|
|
957
|
+
const statusAr = resolveChatStatusAr(params.status) ?? statusEn;
|
|
958
|
+
return renderSynchronizedWorkflowMessage(
|
|
959
|
+
'it_helpdesk_wf_status_by_role',
|
|
960
|
+
{ status: statusEn, statusAr, approverRoleName: approverEn, comment },
|
|
961
|
+
{ status: statusEn, statusAr, approverRoleName: approverAr, comment },
|
|
962
|
+
);
|
|
963
|
+
}
|
|
964
|
+
case 'technician_completed': {
|
|
965
|
+
const roleEn = params.roleName.trim();
|
|
966
|
+
const roleAr = resolveBilingualName(roleEn, params.roleArabicName);
|
|
967
|
+
return renderSynchronizedWorkflowMessage(
|
|
968
|
+
'it_helpdesk_wf_technician_completed',
|
|
969
|
+
{ roleName: roleEn, comment },
|
|
970
|
+
{ roleName: roleAr, comment },
|
|
971
|
+
);
|
|
972
|
+
}
|
|
973
|
+
case 'routing_rejected':
|
|
974
|
+
return renderSynchronizedWorkflowMessage(
|
|
975
|
+
'it_helpdesk_wf_routing_rejected',
|
|
976
|
+
{ comment },
|
|
977
|
+
{ comment },
|
|
978
|
+
);
|
|
979
|
+
case 'routing_resolved':
|
|
980
|
+
return workflowTemplate('it_helpdesk_wf_routing_resolved');
|
|
981
|
+
default:
|
|
982
|
+
return workflowTemplate('request_submitted');
|
|
983
|
+
}
|
|
984
|
+
}
|
|
985
|
+
|
|
986
|
+
export type LogisticsActualReturnParams = {
|
|
987
|
+
requestId?: number | string | null;
|
|
988
|
+
requestTypeLabel?: string | null;
|
|
989
|
+
actual_return_date?: string | Date | null;
|
|
990
|
+
actual_vehicle_return_time?: string | null;
|
|
991
|
+
reason?: string | null;
|
|
992
|
+
};
|
|
993
|
+
|
|
994
|
+
export function buildLogisticsActualReturnChatMessage(params: {
|
|
995
|
+
roleName: string;
|
|
996
|
+
roleArabicName?: string | null;
|
|
997
|
+
returnDetails: LogisticsActualReturnParams;
|
|
998
|
+
}): BilingualText {
|
|
999
|
+
const roleEn = params.roleName.trim() || 'Unknown Role';
|
|
1000
|
+
const roleAr = resolveBilingualName(roleEn, params.roleArabicName);
|
|
1001
|
+
const date = normalizeDisplayDate(params.returnDetails.actual_return_date);
|
|
1002
|
+
const time = normalizeDisplayValue(params.returnDetails.actual_vehicle_return_time);
|
|
1003
|
+
const reason = normalizeDisplayValue(params.returnDetails.reason);
|
|
1004
|
+
return renderSynchronizedChatMessage(
|
|
1005
|
+
'logistics_actual_return_updated',
|
|
1006
|
+
{ roleName: roleEn, date, time, reason },
|
|
1007
|
+
{ roleName: roleAr, date, time, reason },
|
|
1008
|
+
);
|
|
1009
|
+
}
|
|
1010
|
+
|
|
1011
|
+
export function buildLogisticsActualReturnNotificationBody(
|
|
1012
|
+
params: LogisticsActualReturnParams,
|
|
1013
|
+
): BilingualText {
|
|
1014
|
+
const requestLabel = params.requestTypeLabel
|
|
1015
|
+
? `${params.requestTypeLabel} Request`
|
|
1016
|
+
: 'Vehicle Request';
|
|
1017
|
+
const requestLabelAr = params.requestTypeLabel
|
|
1018
|
+
? `طلب ${params.requestTypeLabel}`
|
|
1019
|
+
: 'طلب المركبة';
|
|
1020
|
+
const requestId = normalizeDisplayValue(params.requestId);
|
|
1021
|
+
const en = [
|
|
1022
|
+
`${requestLabel} #${requestId}`,
|
|
1023
|
+
`Actual Return Date: ${normalizeDisplayDate(params.actual_return_date)}`,
|
|
1024
|
+
`Actual Return Time: ${normalizeDisplayValue(params.actual_vehicle_return_time)}`,
|
|
1025
|
+
`Reason: ${normalizeDisplayValue(params.reason)}`,
|
|
1026
|
+
].join('\n');
|
|
1027
|
+
const ar = [
|
|
1028
|
+
`${requestLabelAr} رقم ${requestId}`,
|
|
1029
|
+
`تاريخ الإرجاع الفعلي: ${normalizeDisplayDate(params.actual_return_date)}`,
|
|
1030
|
+
`وقت الإرجاع الفعلي: ${normalizeDisplayValue(params.actual_vehicle_return_time)}`,
|
|
1031
|
+
`السبب: ${normalizeDisplayValue(params.reason)}`,
|
|
1032
|
+
].join('\n');
|
|
1033
|
+
return { en, ar };
|
|
1034
|
+
}
|
|
1035
|
+
|
|
1036
|
+
export function buildLogisticsActualReturnNotificationTitle(
|
|
1037
|
+
params: LogisticsActualReturnParams,
|
|
1038
|
+
): BilingualText {
|
|
1039
|
+
const requestLabel = params.requestTypeLabel || 'Vehicle';
|
|
1040
|
+
const requestId = String(params.requestId ?? '');
|
|
1041
|
+
return renderSynchronizedNotificationMessage(
|
|
1042
|
+
'logistics_actual_return_title',
|
|
1043
|
+
{ requestLabel, requestId },
|
|
1044
|
+
{ requestLabel, requestId },
|
|
1045
|
+
);
|
|
1046
|
+
}
|
|
1047
|
+
|
|
1048
|
+
export function buildItHelpdeskCloseNotificationMessage(params: {
|
|
1049
|
+
requestId: number | string;
|
|
1050
|
+
status: 'Approved' | 'Rejected';
|
|
1051
|
+
}): BilingualText {
|
|
1052
|
+
const requestId = String(params.requestId);
|
|
1053
|
+
const key =
|
|
1054
|
+
params.status === 'Rejected'
|
|
1055
|
+
? 'it_helpdesk_notif_request_rejected'
|
|
1056
|
+
: 'it_helpdesk_notif_request_closed';
|
|
1057
|
+
return renderSynchronizedNotificationMessage(key, { requestId }, { requestId });
|
|
1058
|
+
}
|
|
1059
|
+
|
|
393
1060
|
// ─── Status labels ───────────────────────────────────────────────────────────
|
|
394
1061
|
|
|
395
1062
|
export function resolveWorkflowStatusAr(status: string | null | undefined): string | null {
|
|
@@ -515,20 +1182,20 @@ export function resolveChatMessageAr(
|
|
|
515
1182
|
if (tpl.en === normalized) return tpl.ar;
|
|
516
1183
|
}
|
|
517
1184
|
|
|
518
|
-
const
|
|
519
|
-
|
|
1185
|
+
for (const tplKey of ['request_submitted_by', 'cancellation_submitted_by'] as const) {
|
|
1186
|
+
const submittedTpl = CHAT_TEMPLATES[tplKey];
|
|
1187
|
+
if (!submittedTpl) continue;
|
|
520
1188
|
const prefix = submittedTpl.en.split('{{userName}}')[0];
|
|
521
|
-
if (normalized.startsWith(prefix))
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
}
|
|
1189
|
+
if (!normalized.startsWith(prefix)) continue;
|
|
1190
|
+
const afterPrefix = normalized.slice(prefix.length);
|
|
1191
|
+
const parenMatch = afterPrefix.match(/^(.+?) \((.+)\)$/);
|
|
1192
|
+
if (parenMatch) {
|
|
1193
|
+
const userEn = parenMatch[1].trim();
|
|
1194
|
+
const employeeId = parenMatch[2].trim();
|
|
1195
|
+
const userAr = actors?.userName?.trim()
|
|
1196
|
+
? resolveBilingualName(actors.userName, actors.userArabicName)
|
|
1197
|
+
: resolveBilingualName(userEn, actors?.userArabicName);
|
|
1198
|
+
return interpolate(submittedTpl.ar, { userName: userAr, employeeId });
|
|
532
1199
|
}
|
|
533
1200
|
}
|
|
534
1201
|
|