@platform-modules/foreign-ministry 1.3.337 → 1.3.338

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.
Files changed (78) hide show
  1. package/dist/helpers/sla-request-status.helper.d.ts +3 -0
  2. package/dist/helpers/sla-request-status.helper.js +36 -0
  3. package/dist/models/EmbassyEvaluationDepartmentSettingModel.d.ts +14 -0
  4. package/dist/models/EmbassyEvaluationDepartmentSettingModel.js +56 -0
  5. package/dist/models/EvaluationMastersModel.d.ts +16 -0
  6. package/dist/models/EvaluationMastersModel.js +67 -0
  7. package/dist/models/EvaluationQuestionMasterModel.d.ts +10 -0
  8. package/dist/models/EvaluationQuestionMasterModel.js +42 -0
  9. package/dist/models/EvaluationSectionMasterModel.d.ts +7 -0
  10. package/dist/models/EvaluationSectionMasterModel.js +36 -0
  11. package/dist/models/EvaluationWorkflowModel.d.ts +60 -0
  12. package/dist/models/EvaluationWorkflowModel.js +215 -0
  13. package/dist/models/IneligibleForEvaluationModel.d.ts +8 -0
  14. package/dist/models/IneligibleForEvaluationModel.js +44 -0
  15. package/dist/models/LMSExternalEntityTrainedPersonModel.d.ts +2 -0
  16. package/dist/models/LMSExternalEntityTrainedPersonModel.js +8 -0
  17. package/dist/models/MissionTravelClassConfigModel.d.ts +10 -0
  18. package/dist/models/MissionTravelClassConfigModel.js +50 -0
  19. package/dist/models/MissionTravelPerdiemModel.d.ts +10 -0
  20. package/dist/models/MissionTravelPerdiemModel.js +54 -0
  21. package/dist/models/SlaApprovalsViewModel.js +47 -47
  22. package/dist/models/SlaMyRequestsViewModel.js +52 -52
  23. package/dist/models/UuidAuditModel.d.ts +9 -0
  24. package/dist/models/UuidAuditModel.js +41 -0
  25. package/package.json +1 -1
  26. package/scripts/check-column-types.js +38 -38
  27. package/scripts/check-service-tables.js +42 -42
  28. package/scripts/sync-sla-reports-sql.js +92 -95
  29. package/sql/add_lms_external_entity_trained_people_dates.sql +4 -0
  30. package/sql/sla-reports-sync.manifest.json +9 -9
  31. package/sql/sla_reports_admin_procedures.sql +304 -283
  32. package/sql/sla_reports_approvals_workbook.sql +383 -383
  33. package/sql/sla_reports_procedures.sql +886 -874
  34. package/sql/sla_requests_status_to_varchar.sql +28 -28
  35. package/sql/vw_sla_approvals.sql +108 -108
  36. package/sql/vw_sla_my_requests.sql +55 -55
  37. package/src/data-source.ts +686 -686
  38. package/src/helpers/employee-evaluation-request.utils.ts +178 -178
  39. package/src/helpers/evaluation-eligibility.utils.ts +126 -126
  40. package/src/index.ts +617 -617
  41. package/src/models/DiplomaticAcademyRequestModel.ts +80 -80
  42. package/src/models/DocumentationFileModel.ts +40 -40
  43. package/src/models/EmbassyEvaluationCycleModel.ts +45 -45
  44. package/src/models/EmbassyEvaluationRequestModel.ts +59 -59
  45. package/src/models/EmployeeEvaluationAnswerModel.ts +26 -26
  46. package/src/models/EvaluationEligibilitySettingModel.ts +51 -51
  47. package/src/models/EvaluationFormModel.ts +44 -44
  48. package/src/models/LMSExternalEntityTrainedPersonModel.ts +51 -45
  49. package/src/models/LanguageCourseRequestModel.ts +67 -67
  50. package/src/models/LeaveApprovalsModel.ts +66 -66
  51. package/src/models/LeaveConfigModel.ts +71 -71
  52. package/src/models/MissionTravelApprovalModel.ts +101 -101
  53. package/src/models/MissionTravelAttachmentModel.ts +56 -56
  54. package/src/models/MissionTravelChatModel.ts +52 -52
  55. package/src/models/MissionTravelPersonModel.ts +105 -105
  56. package/src/models/MissionTravelWorkflowModel.ts +54 -54
  57. package/src/models/ProjectContactsModel.ts +51 -51
  58. package/src/models/ProjectFaqModel.ts +36 -36
  59. package/src/models/ProjectInvoicesModel.ts +41 -41
  60. package/src/models/ProjectModel.ts +75 -75
  61. package/src/models/ProjectTasksModel.ts +75 -75
  62. package/src/models/ServiceSlaApprovalModel.ts +63 -63
  63. package/src/models/ServicesNotificationConfigsModel.ts +55 -55
  64. package/src/models/SlaApprovalsViewModel.ts +135 -135
  65. package/src/models/SlaMyRequestsViewModel.ts +172 -172
  66. package/src/models/SlaRequestModel.ts +57 -57
  67. package/src/sla-report-views.ts +3 -3
  68. package/dist/auth/authenticate-jwt-session.d.ts +0 -19
  69. package/dist/auth/authenticate-jwt-session.js +0 -35
  70. package/dist/auth/jwt-token.helper.d.ts +0 -18
  71. package/dist/auth/jwt-token.helper.js +0 -58
  72. package/dist/auth/user-session-validation.d.ts +0 -42
  73. package/dist/auth/user-session-validation.js +0 -95
  74. package/dist/i18n/workflow-chat-i18n.d.ts +0 -5
  75. package/dist/i18n/workflow-chat-i18n.js +0 -21
  76. package/dist/i18n/workflow-chat-i18n.json +0 -320
  77. package/dist/i18n/workflow-chat-message.builder.d.ts +0 -325
  78. package/dist/i18n/workflow-chat-message.builder.js +0 -924
@@ -1,283 +1,304 @@
1
- -- Admin SLA reports + approvals Excel export
2
- -- Prerequisites: sla_reports_procedures.sql, vw_sla_my_requests.sql, vw_sla_approvals.sql
3
- -- Applied via: npm run sync:sla-sql (after sla_reports_procedures.sql in manifest)
4
-
5
- CREATE OR REPLACE FUNCTION sla_filtered_request_fields(p_request_obj JSONB)
6
- RETURNS JSONB
7
- LANGUAGE sql
8
- IMMUTABLE
9
- AS $$
10
- SELECT
11
- COALESCE(p_request_obj, '{}'::jsonb)
12
- - 'id' - 'status' - 'role_id' - 'user_id' - 'createdBy' - 'created_at'
13
- - 'updated_by' - 'updated_at' - 'req_user_department_id' - 'workflow_execution_id'
14
- - 'department_id' - 'req_user_section_id' - 'service_type_id' - 'service_type'
15
- - 'created_by' - 'service_id' - 'sub_service_id' - 'attachments'
16
- - 'is_deleted' - 'sla_request' - 'sla_request_id';
17
- $$;
18
-
19
- -- Admin list views: served by Reports_Service TypeORM (sla-my-requests-view.query.ts, sla-approvals-view.query.ts)
20
-
21
- -- ---------------------------------------------------------------------------
22
- -- ADMIN — my requests Excel (optional p_target_user_id)
23
- -- Per sub-service Requests + Approvals sheets (same as user my-requests download)
24
- -- ---------------------------------------------------------------------------
25
- CREATE OR REPLACE FUNCTION sp_sla_admin_my_requests_excel_export(
26
- p_target_user_id INT DEFAULT NULL,
27
- p_service_ids INT[] DEFAULT NULL,
28
- p_sub_service_ids INT[] DEFAULT NULL,
29
- p_statuses TEXT[] DEFAULT ARRAY['Pending','In Progress','Approved','Rejected'],
30
- p_from_date DATE DEFAULT NULL,
31
- p_to_date DATE DEFAULT NULL,
32
- p_search_text TEXT DEFAULT NULL,
33
- p_sort_by TEXT DEFAULT 'created_at',
34
- p_sort_order TEXT DEFAULT 'DESC'
35
- )
36
- RETURNS TABLE (
37
- sheet_order INT,
38
- sub_service_id INT,
39
- sub_service_name TEXT,
40
- sheet_name TEXT,
41
- headers JSONB,
42
- rows JSONB
43
- )
44
- LANGUAGE plpgsql
45
- STABLE
46
- AS $$
47
- DECLARE
48
- v_sort_col TEXT;
49
- v_sort_dir TEXT;
50
- v_sub RECORD;
51
- v_row RECORD;
52
- v_dyn_keys TEXT[];
53
- v_dyn_labels TEXT[];
54
- v_common_labels TEXT[] := ARRAY[
55
- 'SLA Request ID', 'Request ID', 'User', 'Status', 'Created At',
56
- 'Created By', 'Department', 'Section'
57
- ];
58
- v_headers_labels TEXT[];
59
- v_headers_json JSONB;
60
- v_cells TEXT[];
61
- v_all_rows JSONB;
62
- v_k TEXT;
63
- v_sheet_order INT := 0;
64
- v_user_filter TEXT;
65
- BEGIN
66
- v_user_filter := CASE WHEN p_target_user_id IS NULL THEN 'TRUE' ELSE format('v.user_id = %s', p_target_user_id) END;
67
-
68
- v_sort_col := CASE lower(trim(p_sort_by))
69
- WHEN 'updated_at' THEN 'v.created_at'
70
- WHEN 'id' THEN 'v.sla_request_id'
71
- WHEN 'status' THEN 'v.status'
72
- WHEN 'request_id' THEN 'v.request_id'
73
- ELSE 'v.created_at'
74
- END;
75
- v_sort_dir := CASE WHEN upper(trim(p_sort_order)) = 'ASC' THEN 'ASC' ELSE 'DESC' END;
76
-
77
- FOR v_sub IN
78
- EXECUTE format($q$
79
- SELECT DISTINCT
80
- COALESCE(sr.sub_service_id, 0) AS sub_service_id_num,
81
- COALESCE(NULLIF(trim(subsvc.sub_service_name), ''), NULLIF(trim(v.sub_service_name), ''), 'Uncategorized') AS sub_service_name
82
- FROM vw_sla_my_requests v
83
- INNER JOIN sla_requests sr ON sr.id = v.sla_request_id AND COALESCE(sr.is_deleted, false) = false
84
- LEFT JOIN fm_sub_services subsvc ON subsvc.id = sr.sub_service_id
85
- WHERE %s
86
- AND v.status = ANY($1)
87
- AND ($2 IS NULL OR cardinality($2) = 0 OR sr.service_id = ANY($2))
88
- AND ($3 IS NULL OR cardinality($3) = 0 OR sr.sub_service_id = ANY($3))
89
- AND ($4 IS NULL OR v.created_at::date >= $4)
90
- AND ($5 IS NULL OR v.created_at::date <= $5)
91
- AND ($6 IS NULL OR trim($6) = '' OR CAST(v.request_id AS TEXT) ILIKE '%%' || trim($6) || '%%')
92
- ORDER BY sub_service_name ASC
93
- $q$, v_user_filter)
94
- USING p_statuses, p_service_ids, p_sub_service_ids, p_from_date, p_to_date, p_search_text
95
- LOOP
96
- v_sheet_order := v_sheet_order + 1;
97
-
98
- EXECUTE format($q$
99
- SELECT COALESCE(array_agg(DISTINCT keys.k ORDER BY keys.k), ARRAY[]::TEXT[])
100
- FROM vw_sla_my_requests v
101
- INNER JOIN sla_requests sr ON sr.id = v.sla_request_id AND COALESCE(sr.is_deleted, false) = false
102
- CROSS JOIN LATERAL jsonb_object_keys(COALESCE(v.request_fields, '{}'::jsonb)) AS keys(k)
103
- WHERE %s
104
- AND v.status = ANY($1)
105
- AND ($2 IS NULL OR cardinality($2) = 0 OR sr.service_id = ANY($2))
106
- AND ($3 IS NULL OR cardinality($3) = 0 OR sr.sub_service_id = ANY($3))
107
- AND ($4 IS NULL OR v.created_at::date >= $4)
108
- AND ($5 IS NULL OR v.created_at::date <= $5)
109
- AND ($6 IS NULL OR trim($6) = '' OR CAST(v.request_id AS TEXT) ILIKE '%%' || trim($6) || '%%')
110
- AND COALESCE(sr.sub_service_id, 0) = %s
111
- $q$, v_user_filter, v_sub.sub_service_id_num)
112
- INTO v_dyn_keys
113
- USING p_statuses, p_service_ids, p_sub_service_ids, p_from_date, p_to_date, p_search_text;
114
-
115
- v_dyn_labels := ARRAY[]::TEXT[];
116
- IF v_dyn_keys IS NOT NULL THEN
117
- FOREACH v_k IN ARRAY v_dyn_keys LOOP
118
- v_dyn_labels := array_append(v_dyn_labels, sla_excel_header_label(v_k));
119
- END LOOP;
120
- END IF;
121
-
122
- v_headers_labels := ARRAY(
123
- SELECT sla_excel_header_label(lbl)
124
- FROM unnest(v_common_labels || COALESCE(v_dyn_labels, ARRAY[]::TEXT[])) AS u(lbl)
125
- );
126
- v_headers_json := to_jsonb(v_headers_labels);
127
- v_all_rows := '[]'::jsonb;
128
-
129
- FOR v_row IN
130
- EXECUTE format($q$
131
- SELECT
132
- v.sla_request_id, v.request_id, v.status, v.created_at, v.created_by,
133
- v.req_user_department_id, v.req_user_section_id, v.request_fields,
134
- TRIM(COALESCE(u.employee_name, '')) AS user_name
135
- FROM vw_sla_my_requests v
136
- INNER JOIN sla_requests sr ON sr.id = v.sla_request_id AND COALESCE(sr.is_deleted, false) = false
137
- LEFT JOIN users u ON u.id = v.user_id AND COALESCE(u.is_deleted, false) = false
138
- WHERE %s
139
- AND v.status = ANY($1)
140
- AND ($2 IS NULL OR cardinality($2) = 0 OR sr.service_id = ANY($2))
141
- AND ($3 IS NULL OR cardinality($3) = 0 OR sr.sub_service_id = ANY($3))
142
- AND ($4 IS NULL OR v.created_at::date >= $4)
143
- AND ($5 IS NULL OR v.created_at::date <= $5)
144
- AND ($6 IS NULL OR trim($6) = '' OR CAST(v.request_id AS TEXT) ILIKE '%%' || trim($6) || '%%')
145
- AND COALESCE(sr.sub_service_id, 0) = %s
146
- ORDER BY %s %s, v.sla_request_id ASC
147
- $q$, v_user_filter, v_sub.sub_service_id_num, v_sort_col, v_sort_dir)
148
- USING p_statuses, p_service_ids, p_sub_service_ids, p_from_date, p_to_date, p_search_text
149
- LOOP
150
- v_cells := ARRAY[
151
- COALESCE(v_row.sla_request_id::TEXT, ''),
152
- COALESCE(v_row.request_id::TEXT, ''),
153
- COALESCE(v_row.user_name, ''),
154
- COALESCE(v_row.status, ''),
155
- COALESCE(to_char(v_row.created_at AT TIME ZONE 'UTC', 'YYYY-MM-DD HH24:MI:SS'), ''),
156
- COALESCE(v_row.created_by, ''),
157
- COALESCE(v_row.req_user_department_id, ''),
158
- COALESCE(v_row.req_user_section_id, '')
159
- ];
160
- IF v_dyn_keys IS NOT NULL THEN
161
- FOREACH v_k IN ARRAY v_dyn_keys LOOP
162
- v_cells := array_append(v_cells, COALESCE(sla_request_field_cell(v_row.request_fields, v_k), ''));
163
- END LOOP;
164
- END IF;
165
- v_all_rows := v_all_rows || jsonb_build_array(to_jsonb(v_cells));
166
- END LOOP;
167
-
168
- sheet_order := v_sheet_order;
169
- sub_service_id := NULLIF(v_sub.sub_service_id_num, 0);
170
- sub_service_name := v_sub.sub_service_name;
171
- sheet_name := sla_excel_sheet_name(v_sub.sub_service_name);
172
- headers := v_headers_json;
173
- rows := v_all_rows;
174
- RETURN NEXT;
175
- END LOOP;
176
-
177
- RETURN QUERY
178
- SELECT *
179
- FROM sla_my_requests_approvals_excel_sheet(
180
- v_user_filter,
181
- p_statuses,
182
- p_service_ids,
183
- p_sub_service_ids,
184
- p_from_date,
185
- p_to_date,
186
- p_search_text,
187
- v_sheet_order + 1
188
- );
189
-
190
- RETURN;
191
- END;
192
- $$;
193
-
194
- -- ---------------------------------------------------------------------------
195
- -- APPROVALS — Excel export (approver-scoped; user download)
196
- -- Workbook: per sub-service Requests + Approvals (see sla_reports_approvals_workbook.sql)
197
- -- ---------------------------------------------------------------------------
198
- DROP FUNCTION IF EXISTS sp_sla_approvals_excel_export_internal(
199
- TEXT, BOOLEAN, INT, INT[], INT[], TEXT[], TEXT[], DATE, DATE, TEXT, TEXT, TEXT
200
- );
201
-
202
- CREATE OR REPLACE FUNCTION sp_sla_approvals_excel_export(
203
- p_approver_user_id INT,
204
- p_service_ids INT[] DEFAULT NULL,
205
- p_sub_service_ids INT[] DEFAULT NULL,
206
- p_request_statuses TEXT[] DEFAULT ARRAY['Pending','In Progress','Approved','Rejected'],
207
- p_approval_statuses TEXT[] DEFAULT ARRAY['In Progress','Approved','Rejected'],
208
- p_from_date DATE DEFAULT NULL,
209
- p_to_date DATE DEFAULT NULL,
210
- p_search_text TEXT DEFAULT NULL,
211
- p_sort_by TEXT DEFAULT 'created_at',
212
- p_sort_order TEXT DEFAULT 'DESC'
213
- )
214
- RETURNS TABLE (
215
- sheet_order INT, sub_service_id INT, sub_service_name TEXT, sheet_name TEXT, headers JSONB, rows JSONB
216
- )
217
- LANGUAGE plpgsql
218
- STABLE
219
- AS $$
220
- DECLARE
221
- v_exists TEXT := sla_approval_queue_exists_sql(p_approver_user_id);
222
- v_own TEXT := format('sr.user_id != %s', p_approver_user_id);
223
- BEGIN
224
- RETURN QUERY
225
- SELECT * FROM sp_sla_approvals_workbook_excel_export(
226
- v_exists,
227
- v_own,
228
- p_service_ids,
229
- p_sub_service_ids,
230
- p_request_statuses,
231
- p_approval_statuses,
232
- p_from_date,
233
- p_to_date,
234
- p_search_text,
235
- p_sort_by,
236
- p_sort_order
237
- );
238
- END;
239
- $$;
240
-
241
- -- ---------------------------------------------------------------------------
242
- -- ADMIN — approvals Excel
243
- -- Per sub-service Requests + Approvals; optional approver_user_id (NULL = all queues)
244
- -- Does not exclude own requests (unlike user approvals download)
245
- -- ---------------------------------------------------------------------------
246
- CREATE OR REPLACE FUNCTION sp_sla_admin_approvals_excel_export(
247
- p_target_approver_user_id INT DEFAULT NULL,
248
- p_service_ids INT[] DEFAULT NULL,
249
- p_sub_service_ids INT[] DEFAULT NULL,
250
- p_request_statuses TEXT[] DEFAULT ARRAY['Pending','In Progress','Approved','Rejected'],
251
- p_approval_statuses TEXT[] DEFAULT ARRAY['In Progress','Approved','Rejected'],
252
- p_from_date DATE DEFAULT NULL,
253
- p_to_date DATE DEFAULT NULL,
254
- p_search_text TEXT DEFAULT NULL,
255
- p_sort_by TEXT DEFAULT 'created_at',
256
- p_sort_order TEXT DEFAULT 'DESC'
257
- )
258
- RETURNS TABLE (
259
- sheet_order INT, sub_service_id INT, sub_service_name TEXT, sheet_name TEXT, headers JSONB, rows JSONB
260
- )
261
- LANGUAGE plpgsql
262
- STABLE
263
- AS $$
264
- DECLARE
265
- v_exists TEXT := sla_approval_queue_exists_sql_optional(p_target_approver_user_id);
266
- v_own TEXT := 'TRUE';
267
- BEGIN
268
- RETURN QUERY
269
- SELECT * FROM sp_sla_approvals_workbook_excel_export(
270
- v_exists,
271
- v_own,
272
- p_service_ids,
273
- p_sub_service_ids,
274
- p_request_statuses,
275
- p_approval_statuses,
276
- p_from_date,
277
- p_to_date,
278
- p_search_text,
279
- p_sort_by,
280
- p_sort_order
281
- );
282
- END;
283
- $$;
1
+ -- Admin SLA reports + approvals Excel export
2
+ -- Prerequisites: sla_reports_procedures.sql, vw_sla_my_requests.sql, vw_sla_approvals.sql
3
+ -- Applied via: npm run sync:sla-sql (after sla_reports_procedures.sql in manifest)
4
+
5
+ CREATE OR REPLACE FUNCTION sla_filtered_request_fields(p_request_obj JSONB)
6
+ RETURNS JSONB
7
+ LANGUAGE sql
8
+ IMMUTABLE
9
+ AS $$
10
+ SELECT
11
+ COALESCE(p_request_obj, '{}'::jsonb)
12
+ - 'id' - 'status' - 'role_id' - 'user_id' - 'createdBy' - 'created_at'
13
+ - 'updated_by' - 'updated_at' - 'req_user_department_id' - 'workflow_execution_id'
14
+ - 'department_id' - 'req_user_section_id' - 'service_type_id' - 'service_type'
15
+ - 'created_by' - 'service_id' - 'sub_service_id' - 'attachments'
16
+ - 'is_deleted' - 'sla_request' - 'sla_request_id';
17
+ $$;
18
+
19
+ -- Admin list views: served by Reports_Service TypeORM (sla-my-requests-view.query.ts, sla-approvals-view.query.ts)
20
+
21
+ -- ---------------------------------------------------------------------------
22
+ -- ADMIN — my requests Excel (optional p_target_user_id)
23
+ -- Per sub-service Requests + Approvals sheets (same as user my-requests download)
24
+ -- ---------------------------------------------------------------------------
25
+ DROP FUNCTION IF EXISTS sp_sla_admin_my_requests_excel_export(INT, INT[], INT[], TEXT[], DATE, DATE, TEXT, TEXT, TEXT);
26
+
27
+ CREATE OR REPLACE FUNCTION sp_sla_admin_my_requests_excel_export(
28
+ p_target_user_id INT DEFAULT NULL,
29
+ p_service_ids INT[] DEFAULT NULL,
30
+ p_sub_service_ids INT[] DEFAULT NULL,
31
+ p_statuses TEXT[] DEFAULT ARRAY['Pending','In Progress','Approved','Rejected'],
32
+ p_from_date DATE DEFAULT NULL,
33
+ p_to_date DATE DEFAULT NULL,
34
+ p_search_text TEXT DEFAULT NULL,
35
+ p_sort_by TEXT DEFAULT 'created_at',
36
+ p_sort_order TEXT DEFAULT 'DESC',
37
+ p_extra_filter_sql TEXT DEFAULT 'TRUE'
38
+ )
39
+ RETURNS TABLE (
40
+ sheet_order INT,
41
+ sub_service_id INT,
42
+ sub_service_name TEXT,
43
+ sheet_name TEXT,
44
+ headers JSONB,
45
+ rows JSONB
46
+ )
47
+ LANGUAGE plpgsql
48
+ STABLE
49
+ AS $$
50
+ DECLARE
51
+ v_sort_col TEXT;
52
+ v_sort_dir TEXT;
53
+ v_sub RECORD;
54
+ v_row RECORD;
55
+ v_dyn_keys TEXT[];
56
+ v_dyn_labels TEXT[];
57
+ v_common_labels TEXT[] := ARRAY[
58
+ 'SLA Request ID', 'Request ID', 'User', 'Status', 'Created At',
59
+ 'Created By', 'Department', 'Section'
60
+ ];
61
+ v_headers_labels TEXT[];
62
+ v_headers_json JSONB;
63
+ v_cells TEXT[];
64
+ v_all_rows JSONB;
65
+ v_k TEXT;
66
+ v_sheet_order INT := 0;
67
+ v_user_filter TEXT;
68
+ BEGIN
69
+ v_user_filter := format(
70
+ '(%s) AND (%s)',
71
+ CASE WHEN p_target_user_id IS NULL THEN 'TRUE' ELSE format('v.user_id = %s', p_target_user_id) END,
72
+ COALESCE(NULLIF(trim(p_extra_filter_sql), ''), 'TRUE')
73
+ );
74
+
75
+ v_sort_col := CASE lower(trim(p_sort_by))
76
+ WHEN 'updated_at' THEN 'v.created_at'
77
+ WHEN 'id' THEN 'v.sla_request_id'
78
+ WHEN 'status' THEN 'v.status'
79
+ WHEN 'request_id' THEN 'v.request_id'
80
+ ELSE 'v.created_at'
81
+ END;
82
+ v_sort_dir := CASE WHEN upper(trim(p_sort_order)) = 'ASC' THEN 'ASC' ELSE 'DESC' END;
83
+
84
+ FOR v_sub IN
85
+ EXECUTE format($q$
86
+ SELECT DISTINCT
87
+ COALESCE(sr.sub_service_id, 0) AS sub_service_id_num,
88
+ COALESCE(NULLIF(trim(subsvc.sub_service_name), ''), NULLIF(trim(v.sub_service_name), ''), 'Uncategorized') AS sub_service_name
89
+ FROM vw_sla_my_requests v
90
+ INNER JOIN sla_requests sr ON sr.id = v.sla_request_id AND COALESCE(sr.is_deleted, false) = false
91
+ LEFT JOIN fm_sub_services subsvc ON subsvc.id = sr.sub_service_id
92
+ WHERE %s
93
+ AND v.status = ANY($1)
94
+ AND ($2 IS NULL OR cardinality($2) = 0 OR sr.service_id = ANY($2))
95
+ AND ($3 IS NULL OR cardinality($3) = 0 OR sr.sub_service_id = ANY($3))
96
+ AND ($4 IS NULL OR v.created_at::date >= $4)
97
+ AND ($5 IS NULL OR v.created_at::date <= $5)
98
+ AND ($6 IS NULL OR trim($6) = '' OR CAST(v.request_id AS TEXT) ILIKE '%%' || trim($6) || '%%')
99
+ ORDER BY sub_service_name ASC
100
+ $q$, v_user_filter)
101
+ USING p_statuses, p_service_ids, p_sub_service_ids, p_from_date, p_to_date, p_search_text
102
+ LOOP
103
+ v_sheet_order := v_sheet_order + 1;
104
+
105
+ EXECUTE format($q$
106
+ SELECT COALESCE(array_agg(DISTINCT keys.k ORDER BY keys.k), ARRAY[]::TEXT[])
107
+ FROM vw_sla_my_requests v
108
+ INNER JOIN sla_requests sr ON sr.id = v.sla_request_id AND COALESCE(sr.is_deleted, false) = false
109
+ CROSS JOIN LATERAL jsonb_object_keys(COALESCE(v.request_fields, '{}'::jsonb)) AS keys(k)
110
+ WHERE %s
111
+ AND v.status = ANY($1)
112
+ AND ($2 IS NULL OR cardinality($2) = 0 OR sr.service_id = ANY($2))
113
+ AND ($3 IS NULL OR cardinality($3) = 0 OR sr.sub_service_id = ANY($3))
114
+ AND ($4 IS NULL OR v.created_at::date >= $4)
115
+ AND ($5 IS NULL OR v.created_at::date <= $5)
116
+ AND ($6 IS NULL OR trim($6) = '' OR CAST(v.request_id AS TEXT) ILIKE '%%' || trim($6) || '%%')
117
+ AND COALESCE(sr.sub_service_id, 0) = %s
118
+ $q$, v_user_filter, v_sub.sub_service_id_num)
119
+ INTO v_dyn_keys
120
+ USING p_statuses, p_service_ids, p_sub_service_ids, p_from_date, p_to_date, p_search_text;
121
+
122
+ v_dyn_labels := ARRAY[]::TEXT[];
123
+ IF v_dyn_keys IS NOT NULL THEN
124
+ FOREACH v_k IN ARRAY v_dyn_keys LOOP
125
+ v_dyn_labels := array_append(v_dyn_labels, sla_excel_header_label(v_k));
126
+ END LOOP;
127
+ END IF;
128
+
129
+ v_headers_labels := ARRAY(
130
+ SELECT sla_excel_header_label(lbl)
131
+ FROM unnest(v_common_labels || COALESCE(v_dyn_labels, ARRAY[]::TEXT[])) AS u(lbl)
132
+ );
133
+ v_headers_json := to_jsonb(v_headers_labels);
134
+ v_all_rows := '[]'::jsonb;
135
+
136
+ FOR v_row IN
137
+ EXECUTE format($q$
138
+ SELECT
139
+ v.sla_request_id, v.request_id, v.status, v.created_at, v.created_by,
140
+ v.req_user_department_id, v.req_user_section_id, v.request_fields,
141
+ TRIM(COALESCE(u.employee_name, '')) AS user_name
142
+ FROM vw_sla_my_requests v
143
+ INNER JOIN sla_requests sr ON sr.id = v.sla_request_id AND COALESCE(sr.is_deleted, false) = false
144
+ LEFT JOIN users u ON u.id = v.user_id AND COALESCE(u.is_deleted, false) = false
145
+ WHERE %s
146
+ AND v.status = ANY($1)
147
+ AND ($2 IS NULL OR cardinality($2) = 0 OR sr.service_id = ANY($2))
148
+ AND ($3 IS NULL OR cardinality($3) = 0 OR sr.sub_service_id = ANY($3))
149
+ AND ($4 IS NULL OR v.created_at::date >= $4)
150
+ AND ($5 IS NULL OR v.created_at::date <= $5)
151
+ AND ($6 IS NULL OR trim($6) = '' OR CAST(v.request_id AS TEXT) ILIKE '%%' || trim($6) || '%%')
152
+ AND COALESCE(sr.sub_service_id, 0) = %s
153
+ ORDER BY %s %s, v.sla_request_id ASC
154
+ $q$, v_user_filter, v_sub.sub_service_id_num, v_sort_col, v_sort_dir)
155
+ USING p_statuses, p_service_ids, p_sub_service_ids, p_from_date, p_to_date, p_search_text
156
+ LOOP
157
+ v_cells := ARRAY[
158
+ COALESCE(v_row.sla_request_id::TEXT, ''),
159
+ COALESCE(v_row.request_id::TEXT, ''),
160
+ COALESCE(v_row.user_name, ''),
161
+ COALESCE(v_row.status, ''),
162
+ COALESCE(to_char(v_row.created_at AT TIME ZONE 'UTC', 'YYYY-MM-DD HH24:MI:SS'), ''),
163
+ COALESCE(v_row.created_by, ''),
164
+ COALESCE(v_row.req_user_department_id, ''),
165
+ COALESCE(v_row.req_user_section_id, '')
166
+ ];
167
+ IF v_dyn_keys IS NOT NULL THEN
168
+ FOREACH v_k IN ARRAY v_dyn_keys LOOP
169
+ v_cells := array_append(v_cells, COALESCE(sla_request_field_cell(v_row.request_fields, v_k), ''));
170
+ END LOOP;
171
+ END IF;
172
+ v_all_rows := v_all_rows || jsonb_build_array(to_jsonb(v_cells));
173
+ END LOOP;
174
+
175
+ sheet_order := v_sheet_order;
176
+ sub_service_id := NULLIF(v_sub.sub_service_id_num, 0);
177
+ sub_service_name := v_sub.sub_service_name;
178
+ sheet_name := sla_excel_sheet_name(v_sub.sub_service_name);
179
+ headers := v_headers_json;
180
+ rows := v_all_rows;
181
+ RETURN NEXT;
182
+ END LOOP;
183
+
184
+ RETURN QUERY
185
+ SELECT *
186
+ FROM sla_my_requests_approvals_excel_sheet(
187
+ v_user_filter,
188
+ p_statuses,
189
+ p_service_ids,
190
+ p_sub_service_ids,
191
+ p_from_date,
192
+ p_to_date,
193
+ p_search_text,
194
+ v_sheet_order + 1
195
+ );
196
+
197
+ RETURN;
198
+ END;
199
+ $$;
200
+
201
+ -- ---------------------------------------------------------------------------
202
+ -- APPROVALS Excel export (approver-scoped; user download)
203
+ -- Workbook: per sub-service Requests + Approvals (see sla_reports_approvals_workbook.sql)
204
+ -- ---------------------------------------------------------------------------
205
+ DROP FUNCTION IF EXISTS sp_sla_approvals_excel_export_internal(
206
+ TEXT, BOOLEAN, INT, INT[], INT[], TEXT[], TEXT[], DATE, DATE, TEXT, TEXT, TEXT
207
+ );
208
+
209
+ DROP FUNCTION IF EXISTS sp_sla_approvals_excel_export(
210
+ INT, INT[], INT[], TEXT[], TEXT[], DATE, DATE, TEXT, TEXT, TEXT
211
+ );
212
+
213
+ CREATE OR REPLACE FUNCTION sp_sla_approvals_excel_export(
214
+ p_approver_user_id INT,
215
+ p_service_ids INT[] DEFAULT NULL,
216
+ p_sub_service_ids INT[] DEFAULT NULL,
217
+ p_request_statuses TEXT[] DEFAULT ARRAY['Pending','In Progress','Approved','Rejected'],
218
+ p_approval_statuses TEXT[] DEFAULT ARRAY['In Progress','Approved','Rejected'],
219
+ p_from_date DATE DEFAULT NULL,
220
+ p_to_date DATE DEFAULT NULL,
221
+ p_search_text TEXT DEFAULT NULL,
222
+ p_sort_by TEXT DEFAULT 'created_at',
223
+ p_sort_order TEXT DEFAULT 'DESC',
224
+ p_extra_filter_sql TEXT DEFAULT 'TRUE'
225
+ )
226
+ RETURNS TABLE (
227
+ sheet_order INT, sub_service_id INT, sub_service_name TEXT, sheet_name TEXT, headers JSONB, rows JSONB
228
+ )
229
+ LANGUAGE plpgsql
230
+ STABLE
231
+ AS $$
232
+ DECLARE
233
+ v_exists TEXT := sla_approval_queue_exists_sql(p_approver_user_id);
234
+ v_own TEXT := format(
235
+ '(%s) AND (%s)',
236
+ format('sr.user_id != %s', p_approver_user_id),
237
+ COALESCE(NULLIF(trim(p_extra_filter_sql), ''), 'TRUE')
238
+ );
239
+ BEGIN
240
+ RETURN QUERY
241
+ SELECT * FROM sp_sla_approvals_workbook_excel_export(
242
+ v_exists,
243
+ v_own,
244
+ p_service_ids,
245
+ p_sub_service_ids,
246
+ p_request_statuses,
247
+ p_approval_statuses,
248
+ p_from_date,
249
+ p_to_date,
250
+ p_search_text,
251
+ p_sort_by,
252
+ p_sort_order
253
+ );
254
+ END;
255
+ $$;
256
+
257
+ -- ---------------------------------------------------------------------------
258
+ -- ADMIN — approvals Excel
259
+ -- Per sub-service Requests + Approvals; optional approver_user_id (NULL = all queues)
260
+ -- Does not exclude own requests (unlike user approvals download)
261
+ -- ---------------------------------------------------------------------------
262
+ DROP FUNCTION IF EXISTS sp_sla_admin_approvals_excel_export(
263
+ INT, INT[], INT[], TEXT[], TEXT[], DATE, DATE, TEXT, TEXT, TEXT
264
+ );
265
+
266
+ CREATE OR REPLACE FUNCTION sp_sla_admin_approvals_excel_export(
267
+ p_target_approver_user_id INT DEFAULT NULL,
268
+ p_service_ids INT[] DEFAULT NULL,
269
+ p_sub_service_ids INT[] DEFAULT NULL,
270
+ p_request_statuses TEXT[] DEFAULT ARRAY['Pending','In Progress','Approved','Rejected'],
271
+ p_approval_statuses TEXT[] DEFAULT ARRAY['In Progress','Approved','Rejected'],
272
+ p_from_date DATE DEFAULT NULL,
273
+ p_to_date DATE DEFAULT NULL,
274
+ p_search_text TEXT DEFAULT NULL,
275
+ p_sort_by TEXT DEFAULT 'created_at',
276
+ p_sort_order TEXT DEFAULT 'DESC',
277
+ p_extra_filter_sql TEXT DEFAULT 'TRUE'
278
+ )
279
+ RETURNS TABLE (
280
+ sheet_order INT, sub_service_id INT, sub_service_name TEXT, sheet_name TEXT, headers JSONB, rows JSONB
281
+ )
282
+ LANGUAGE plpgsql
283
+ STABLE
284
+ AS $$
285
+ DECLARE
286
+ v_exists TEXT := sla_approval_queue_exists_sql_optional(p_target_approver_user_id);
287
+ v_own TEXT := COALESCE(NULLIF(trim(p_extra_filter_sql), ''), 'TRUE');
288
+ BEGIN
289
+ RETURN QUERY
290
+ SELECT * FROM sp_sla_approvals_workbook_excel_export(
291
+ v_exists,
292
+ v_own,
293
+ p_service_ids,
294
+ p_sub_service_ids,
295
+ p_request_statuses,
296
+ p_approval_statuses,
297
+ p_from_date,
298
+ p_to_date,
299
+ p_search_text,
300
+ p_sort_by,
301
+ p_sort_order
302
+ );
303
+ END;
304
+ $$;