@platform-modules/foreign-ministry 1.3.355 → 1.3.359

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 (83) hide show
  1. package/dist/auth/authenticate-jwt-session.d.ts +19 -0
  2. package/dist/auth/authenticate-jwt-session.js +35 -0
  3. package/dist/auth/jwt-token.helper.d.ts +18 -0
  4. package/dist/auth/jwt-token.helper.js +58 -0
  5. package/dist/auth/user-session-validation.d.ts +42 -0
  6. package/dist/auth/user-session-validation.js +95 -0
  7. package/dist/helpers/employee-evaluation-request.utils.d.ts +12 -0
  8. package/dist/helpers/employee-evaluation-request.utils.js +85 -0
  9. package/dist/i18n/workflow-chat-i18n.d.ts +5 -0
  10. package/dist/i18n/workflow-chat-i18n.js +21 -0
  11. package/dist/i18n/workflow-chat-i18n.json +320 -0
  12. package/dist/i18n/workflow-chat-message.builder.d.ts +325 -0
  13. package/dist/i18n/workflow-chat-message.builder.js +924 -0
  14. package/dist/index.d.ts +1 -1
  15. package/dist/index.js +4 -3
  16. package/dist/models/InitiatorEmployeeNominationRequestModel.d.ts +2 -1
  17. package/dist/models/InitiatorEmployeeNominationRequestModel.js +3 -3
  18. package/dist/models/ProjectTasksModel.d.ts +1 -1
  19. package/dist/models/ProjectTasksModel.js +1 -1
  20. package/dist/models/SlaApprovalsViewModel.js +54 -54
  21. package/dist/models/SlaMyRequestsViewModel.js +57 -57
  22. package/package.json +2 -2
  23. package/scripts/check-column-types.js +38 -38
  24. package/scripts/check-service-tables.js +42 -42
  25. package/scripts/sync-sla-reports-sql.js +92 -92
  26. package/sql/initiator_employee_nomination_initiator_id.sql +12 -0
  27. package/sql/sla-reports-sync.manifest.json +9 -9
  28. package/sql/sla_reports_admin_procedures.sql +321 -322
  29. package/sql/sla_reports_approvals_workbook.sql +427 -430
  30. package/sql/sla_reports_procedures.sql +883 -886
  31. package/sql/sla_requests_status_to_varchar.sql +28 -28
  32. package/sql/vw_sla_approvals.sql +115 -115
  33. package/sql/vw_sla_my_requests.sql +60 -60
  34. package/src/helpers/employee-evaluation-request.utils.ts +127 -0
  35. package/src/helpers/evaluation-eligibility.utils.ts +126 -126
  36. package/src/index.ts +1 -0
  37. package/src/models/DiplomaticAcademyRequestModel.ts +80 -80
  38. package/src/models/DocumentationFileModel.ts +40 -40
  39. package/src/models/EmbassyEvaluationCycleModel.ts +45 -45
  40. package/src/models/EmbassyEvaluationRequestModel.ts +59 -59
  41. package/src/models/EmployeeEvaluationAnswerModel.ts +26 -26
  42. package/src/models/EvaluationEligibilitySettingModel.ts +51 -51
  43. package/src/models/EvaluationFormModel.ts +44 -44
  44. package/src/models/InitiatorEmployeeNominationRequestModel.ts +3 -2
  45. package/src/models/LanguageCourseRequestModel.ts +67 -67
  46. package/src/models/LeaveApprovalsModel.ts +66 -66
  47. package/src/models/LeaveConfigModel.ts +71 -71
  48. package/src/models/MissionTravelApprovalModel.ts +101 -101
  49. package/src/models/MissionTravelAttachmentModel.ts +56 -56
  50. package/src/models/MissionTravelChatModel.ts +52 -52
  51. package/src/models/MissionTravelPersonModel.ts +105 -105
  52. package/src/models/MissionTravelWorkflowModel.ts +54 -54
  53. package/src/models/ProjectContactsModel.ts +51 -51
  54. package/src/models/ProjectFaqModel.ts +36 -36
  55. package/src/models/ProjectInvoicesModel.ts +41 -41
  56. package/src/models/ProjectModel.ts +75 -75
  57. package/src/models/ProjectTasksModel.ts +75 -75
  58. package/src/models/ServiceSlaApprovalModel.ts +63 -63
  59. package/src/models/ServicesNotificationConfigsModel.ts +55 -55
  60. package/src/models/SlaApprovalsViewModel.ts +142 -142
  61. package/src/models/SlaMyRequestsViewModel.ts +192 -192
  62. package/src/models/SlaRequestModel.ts +57 -57
  63. package/src/sla-report-views.ts +3 -3
  64. package/dist/helpers/sla-request-status.helper.d.ts +0 -3
  65. package/dist/helpers/sla-request-status.helper.js +0 -36
  66. package/dist/models/EmbassyEvaluationDepartmentSettingModel.d.ts +0 -14
  67. package/dist/models/EmbassyEvaluationDepartmentSettingModel.js +0 -56
  68. package/dist/models/EvaluationMastersModel.d.ts +0 -16
  69. package/dist/models/EvaluationMastersModel.js +0 -67
  70. package/dist/models/EvaluationQuestionMasterModel.d.ts +0 -10
  71. package/dist/models/EvaluationQuestionMasterModel.js +0 -42
  72. package/dist/models/EvaluationSectionMasterModel.d.ts +0 -7
  73. package/dist/models/EvaluationSectionMasterModel.js +0 -36
  74. package/dist/models/EvaluationWorkflowModel.d.ts +0 -60
  75. package/dist/models/EvaluationWorkflowModel.js +0 -215
  76. package/dist/models/IneligibleForEvaluationModel.d.ts +0 -8
  77. package/dist/models/IneligibleForEvaluationModel.js +0 -44
  78. package/dist/models/MissionTravelClassConfigModel.d.ts +0 -10
  79. package/dist/models/MissionTravelClassConfigModel.js +0 -50
  80. package/dist/models/MissionTravelPerdiemModel.d.ts +0 -10
  81. package/dist/models/MissionTravelPerdiemModel.js +0 -54
  82. package/dist/models/UuidAuditModel.d.ts +0 -9
  83. package/dist/models/UuidAuditModel.js +0 -41
@@ -0,0 +1,19 @@
1
+ import type { UserSessionReader } from './user-session-validation';
2
+ export type JwtAuthFailure = {
3
+ ok: false;
4
+ statusCode: 401;
5
+ message: string;
6
+ };
7
+ export type JwtAuthSuccess = {
8
+ ok: true;
9
+ claims: Record<string, unknown>;
10
+ userId: number;
11
+ sessionId: number | null;
12
+ };
13
+ export type JwtAuthResult = JwtAuthSuccess | JwtAuthFailure;
14
+ /**
15
+ * After jwt.verify(), enforce server-side session binding (logout revocation).
16
+ */
17
+ export declare function authorizeVerifiedJwtSession(verified: Record<string, unknown>, sessionReader: UserSessionReader, options?: {
18
+ requireActiveSession?: boolean;
19
+ }): Promise<JwtAuthResult>;
@@ -0,0 +1,35 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.authorizeVerifiedJwtSession = authorizeVerifiedJwtSession;
4
+ const jwt_token_helper_1 = require("./jwt-token.helper");
5
+ const user_session_validation_1 = require("./user-session-validation");
6
+ /**
7
+ * After jwt.verify(), enforce server-side session binding (logout revocation).
8
+ */
9
+ async function authorizeVerifiedJwtSession(verified, sessionReader, options) {
10
+ const parsed = (0, jwt_token_helper_1.parseVerifiedJwtClaims)(verified);
11
+ if (!parsed) {
12
+ return { ok: false, statusCode: 401, message: 'Invalid Token' };
13
+ }
14
+ const requireActiveSession = options?.requireActiveSession !== false;
15
+ if (requireActiveSession) {
16
+ const sessionValid = await (0, user_session_validation_1.validateUserSessionBinding)(parsed.userId, parsed.sessionId, sessionReader);
17
+ if (!sessionValid) {
18
+ return { ok: false, statusCode: 401, message: 'Session Expired please login again' };
19
+ }
20
+ if (parsed.sessionId != null) {
21
+ const isCurrent = await (0, user_session_validation_1.validateJwtSessionIsCurrent)(parsed.userId, parsed.sessionId, sessionReader);
22
+ if (!isCurrent) {
23
+ return { ok: false, statusCode: 401, message: 'Session Expired please login again' };
24
+ }
25
+ }
26
+ }
27
+ const sessionId = await (0, user_session_validation_1.resolveAuthorizedSessionId)(parsed.userId, parsed.sessionId, sessionReader);
28
+ const { sessionId: _jwtSessionId, ...claimsWithoutSession } = parsed.raw;
29
+ return {
30
+ ok: true,
31
+ claims: claimsWithoutSession,
32
+ userId: parsed.userId,
33
+ sessionId,
34
+ };
35
+ }
@@ -0,0 +1,18 @@
1
+ /**
2
+ * Extract portal API JWT from standard request headers.
3
+ * Supports `jwt` header (legacy) and `Authorization: Bearer <token>`.
4
+ */
5
+ export declare function extractJwtToken(headers: Record<string, string | string[] | undefined> | undefined): string | null;
6
+ export type JwtTokenRequest = {
7
+ headers: Record<string, string | string[] | undefined>;
8
+ body?: unknown;
9
+ };
10
+ /** JWT from headers (`jwt`, `Authorization: Bearer`) or JSON body (`token`, `jwt`, `access_token`). */
11
+ export declare function extractJwtTokenFromRequest(request: JwtTokenRequest): string | null;
12
+ export type VerifiedJwtClaims = {
13
+ userId: number;
14
+ sessionId: number | null;
15
+ raw: Record<string, unknown>;
16
+ };
17
+ /** Parse verified JWT payload into userId + sessionId. */
18
+ export declare function parseVerifiedJwtClaims(verified: Record<string, unknown>): VerifiedJwtClaims | null;
@@ -0,0 +1,58 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.extractJwtToken = extractJwtToken;
4
+ exports.extractJwtTokenFromRequest = extractJwtTokenFromRequest;
5
+ exports.parseVerifiedJwtClaims = parseVerifiedJwtClaims;
6
+ /**
7
+ * Extract portal API JWT from standard request headers.
8
+ * Supports `jwt` header (legacy) and `Authorization: Bearer <token>`.
9
+ */
10
+ function extractJwtToken(headers) {
11
+ if (!headers)
12
+ return null;
13
+ const pick = (value) => {
14
+ const raw = Array.isArray(value) ? value[0] : value;
15
+ const trimmed = raw?.trim();
16
+ return trimmed ? trimmed : null;
17
+ };
18
+ const fromJwtHeader = pick(headers.jwt ?? headers.JWT);
19
+ if (fromJwtHeader)
20
+ return fromJwtHeader;
21
+ const authorization = pick(headers.authorization ?? headers.Authorization);
22
+ if (!authorization)
23
+ return null;
24
+ const bearerMatch = /^Bearer\s+(.+)$/i.exec(authorization);
25
+ if (bearerMatch?.[1]?.trim())
26
+ return bearerMatch[1].trim();
27
+ return authorization;
28
+ }
29
+ /** JWT from headers (`jwt`, `Authorization: Bearer`) or JSON body (`token`, `jwt`, `access_token`). */
30
+ function extractJwtTokenFromRequest(request) {
31
+ const fromHeaders = extractJwtToken(request.headers);
32
+ if (fromHeaders)
33
+ return fromHeaders;
34
+ const body = request.body;
35
+ if (!body || typeof body !== 'object')
36
+ return null;
37
+ for (const key of ['token', 'jwt', 'access_token']) {
38
+ const value = body[key];
39
+ if (typeof value === 'string' && value.trim())
40
+ return value.trim();
41
+ }
42
+ return null;
43
+ }
44
+ /** Parse verified JWT payload into userId + sessionId. */
45
+ function parseVerifiedJwtClaims(verified) {
46
+ const userId = Number(verified.userId);
47
+ if (!Number.isFinite(userId) || userId <= 0)
48
+ return null;
49
+ const sessionIdRaw = verified.sessionId;
50
+ const parsedSessionId = sessionIdRaw == null || sessionIdRaw === '' ? null : Number(sessionIdRaw);
51
+ return {
52
+ userId,
53
+ sessionId: parsedSessionId != null && Number.isFinite(parsedSessionId) && parsedSessionId > 0
54
+ ? parsedSessionId
55
+ : null,
56
+ raw: verified,
57
+ };
58
+ }
@@ -0,0 +1,42 @@
1
+ /**
2
+ * Server-side JWT session binding (VAPT M003/M004).
3
+ * JWT remains valid cryptographically until exp; access is allowed only while
4
+ * the bound user_sessions row is active and not expired.
5
+ */
6
+ export type UserSessionRow = {
7
+ id?: number;
8
+ };
9
+ export type UserSessionReader = {
10
+ isSessionActiveById(sessionId: number, userId: number): Promise<boolean>;
11
+ /** Legacy fallback when REQUIRE_JWT_SESSION_ID=false and token has no sessionId. */
12
+ isSessionActive?(userId: number): Promise<UserSessionRow | null | undefined>;
13
+ /** Latest active session row id for user (highest id). */
14
+ getLatestActiveSessionId?(userId: number): Promise<number | null>;
15
+ };
16
+ /** Default true — only the newest active session may use the API when JWT carries sessionId. */
17
+ export declare function isSingleSessionOnLogin(): boolean;
18
+ /** When true (default), JWT must include sessionId and that session must be active. */
19
+ export declare function isRequireJwtSessionId(): boolean;
20
+ export declare function resolveJwtSessionId(sessionId: unknown): number | null;
21
+ /**
22
+ * Validate that a verified JWT is still authorized (not logged out / expired server-side).
23
+ */
24
+ export declare function validateUserSessionBinding(userId: number, sessionId: number | null | undefined, reader: UserSessionReader): Promise<boolean>;
25
+ /** After row-level active check, enforce single-session policy (reject superseded JWTs). */
26
+ export declare function validateJwtSessionIsCurrent(userId: number, sessionId: number, reader: UserSessionReader): Promise<boolean>;
27
+ /** Resolve session id for request meta: JWT claim first, else latest active DB row. */
28
+ export declare function resolveAuthorizedSessionId(userId: number, jwtSessionId: number | null, reader: UserSessionReader): Promise<number | null>;
29
+ /** Shared TypeORM filters: active, not deleted, not past expires_at. */
30
+ export declare function applyActiveUserSessionFilters(qb: {
31
+ andWhere: (clause: string, params?: Record<string, unknown>) => unknown;
32
+ orderBy?: (sort: string, order?: 'ASC' | 'DESC') => unknown;
33
+ }, alias?: string): void;
34
+ /** Prefer newest active session when multiple rows match (legacy path). */
35
+ export declare function applyLatestActiveUserSessionOrdering(qb: {
36
+ orderBy: (sort: string, order?: 'ASC' | 'DESC') => unknown;
37
+ }, alias?: string): void;
38
+ /** @deprecated Use applyActiveUserSessionFilters — kept for backward compatibility. */
39
+ export declare function activeUserSessionSql(alias?: string): {
40
+ clause: string;
41
+ params: Record<string, unknown>;
42
+ };
@@ -0,0 +1,95 @@
1
+ "use strict";
2
+ /**
3
+ * Server-side JWT session binding (VAPT M003/M004).
4
+ * JWT remains valid cryptographically until exp; access is allowed only while
5
+ * the bound user_sessions row is active and not expired.
6
+ */
7
+ Object.defineProperty(exports, "__esModule", { value: true });
8
+ exports.isSingleSessionOnLogin = isSingleSessionOnLogin;
9
+ exports.isRequireJwtSessionId = isRequireJwtSessionId;
10
+ exports.resolveJwtSessionId = resolveJwtSessionId;
11
+ exports.validateUserSessionBinding = validateUserSessionBinding;
12
+ exports.validateJwtSessionIsCurrent = validateJwtSessionIsCurrent;
13
+ exports.resolveAuthorizedSessionId = resolveAuthorizedSessionId;
14
+ exports.applyActiveUserSessionFilters = applyActiveUserSessionFilters;
15
+ exports.applyLatestActiveUserSessionOrdering = applyLatestActiveUserSessionOrdering;
16
+ exports.activeUserSessionSql = activeUserSessionSql;
17
+ /** Default true — only the newest active session may use the API when JWT carries sessionId. */
18
+ function isSingleSessionOnLogin() {
19
+ const raw = (process.env.SINGLE_SESSION_ON_LOGIN ?? 'true').trim().toLowerCase();
20
+ return raw !== 'false' && raw !== '0' && raw !== 'no';
21
+ }
22
+ /** When true (default), JWT must include sessionId and that session must be active. */
23
+ function isRequireJwtSessionId() {
24
+ const raw = (process.env.REQUIRE_JWT_SESSION_ID ?? 'true').trim().toLowerCase();
25
+ return raw !== 'false' && raw !== '0' && raw !== 'no';
26
+ }
27
+ function resolveJwtSessionId(sessionId) {
28
+ if (sessionId == null || sessionId === '')
29
+ return null;
30
+ const sid = Number(sessionId);
31
+ if (!Number.isFinite(sid) || sid <= 0)
32
+ return null;
33
+ return sid;
34
+ }
35
+ /**
36
+ * Validate that a verified JWT is still authorized (not logged out / expired server-side).
37
+ */
38
+ async function validateUserSessionBinding(userId, sessionId, reader) {
39
+ if (!Number.isFinite(userId) || userId <= 0)
40
+ return false;
41
+ const sid = resolveJwtSessionId(sessionId);
42
+ if (sid != null) {
43
+ return reader.isSessionActiveById(sid, userId);
44
+ }
45
+ if (isRequireJwtSessionId()) {
46
+ return false;
47
+ }
48
+ if (!reader.isSessionActive)
49
+ return false;
50
+ const legacy = await reader.isSessionActive(userId);
51
+ return !!legacy;
52
+ }
53
+ /** After row-level active check, enforce single-session policy (reject superseded JWTs). */
54
+ async function validateJwtSessionIsCurrent(userId, sessionId, reader) {
55
+ if (!isSingleSessionOnLogin() || !reader.getLatestActiveSessionId)
56
+ return true;
57
+ const latest = await reader.getLatestActiveSessionId(userId);
58
+ if (latest == null)
59
+ return true;
60
+ return latest === sessionId;
61
+ }
62
+ /** Resolve session id for request meta: JWT claim first, else latest active DB row. */
63
+ async function resolveAuthorizedSessionId(userId, jwtSessionId, reader) {
64
+ if (jwtSessionId != null)
65
+ return jwtSessionId;
66
+ if (reader.getLatestActiveSessionId) {
67
+ return reader.getLatestActiveSessionId(userId);
68
+ }
69
+ if (!reader.isSessionActive)
70
+ return null;
71
+ const legacy = await reader.isSessionActive(userId);
72
+ const legacyId = Number(legacy?.id);
73
+ return Number.isFinite(legacyId) && legacyId > 0 ? legacyId : null;
74
+ }
75
+ /** Shared TypeORM filters: active, not deleted, not past expires_at. */
76
+ function applyActiveUserSessionFilters(qb, alias = 'user_sessions') {
77
+ qb.andWhere(`${alias}.is_active = :is_active`, { is_active: true });
78
+ qb.andWhere(`(${alias}.is_deleted IS NULL OR ${alias}.is_deleted = :is_deleted)`, { is_deleted: false });
79
+ qb.andWhere(`(${alias}.expires_at IS NULL OR ${alias}.expires_at > :session_now)`, { session_now: new Date() });
80
+ }
81
+ /** Prefer newest active session when multiple rows match (legacy path). */
82
+ function applyLatestActiveUserSessionOrdering(qb, alias = 'user_sessions') {
83
+ qb.orderBy(`${alias}.id`, 'DESC');
84
+ }
85
+ /** @deprecated Use applyActiveUserSessionFilters — kept for backward compatibility. */
86
+ function activeUserSessionSql(alias = 'user_sessions') {
87
+ return {
88
+ clause: `${alias}.is_active = :is_active AND (${alias}.is_deleted IS NULL OR ${alias}.is_deleted = :is_deleted) AND (${alias}.expires_at IS NULL OR ${alias}.expires_at > :session_now)`,
89
+ params: {
90
+ is_active: true,
91
+ is_deleted: false,
92
+ session_now: new Date(),
93
+ },
94
+ };
95
+ }
@@ -34,3 +34,15 @@ export declare function persistEmployeeEvaluationScores(manager: EntityManager,
34
34
  averageScore: number;
35
35
  employeeCount: number;
36
36
  }>;
37
+ /** Sync person_scores/answers on an existing request (draft update or draft promotion). */
38
+ export declare function syncEmployeeEvaluationScores(manager: EntityManager, opts: {
39
+ requestId: number;
40
+ formId: number;
41
+ createdBy: string;
42
+ employees: NormalizedEmployeeSubmission[];
43
+ validateAnswers?: boolean;
44
+ }): Promise<{
45
+ totalScore: number | null;
46
+ averageScore: number | null;
47
+ employeeCount: number;
48
+ }>;
@@ -5,6 +5,7 @@ exports.normalizeEmployeeSubmissions = normalizeEmployeeSubmissions;
5
5
  exports.normalizeEmployeeDraftSubmissions = normalizeEmployeeDraftSubmissions;
6
6
  exports.resolveMaxEmployeesPerRequest = resolveMaxEmployeesPerRequest;
7
7
  exports.persistEmployeeEvaluationScores = persistEmployeeEvaluationScores;
8
+ exports.syncEmployeeEvaluationScores = syncEmployeeEvaluationScores;
8
9
  const EmployeeEvaluationAnswerModel_1 = require("../models/EmployeeEvaluationAnswerModel");
9
10
  const EmployeeEvaluationPersonScoreModel_1 = require("../models/EmployeeEvaluationPersonScoreModel");
10
11
  const EmployeeEvaluationRequestModel_1 = require("../models/EmployeeEvaluationRequestModel");
@@ -213,3 +214,87 @@ async function persistEmployeeEvaluationScores(manager, opts) {
213
214
  });
214
215
  return { totalScore: requestTotal, averageScore, employeeCount };
215
216
  }
217
+ /** Sync person_scores/answers on an existing request (draft update or draft promotion). */
218
+ async function syncEmployeeEvaluationScores(manager, opts) {
219
+ const { requestId, formId, createdBy, employees, validateAnswers = false } = opts;
220
+ const payloadUserIds = new Set(employees.map((e) => e.user_id));
221
+ const existingScores = await manager.find(EmployeeEvaluationPersonScoreModel_1.EmployeeEvaluationPersonScore, {
222
+ where: { request_id: requestId, is_deleted: false },
223
+ });
224
+ for (const ps of existingScores) {
225
+ if (!payloadUserIds.has(ps.user_id)) {
226
+ await manager.update(EmployeeEvaluationPersonScoreModel_1.EmployeeEvaluationPersonScore, { id: ps.id }, { is_deleted: true, updated_by: createdBy });
227
+ await manager.update(EmployeeEvaluationAnswerModel_1.EmployeeEvaluationAnswers, { request_id: requestId, user_id: ps.user_id, is_deleted: false }, { is_deleted: true, updated_by: createdBy });
228
+ }
229
+ }
230
+ for (const emp of employees) {
231
+ const existingPerson = existingScores.find((p) => p.user_id === emp.user_id);
232
+ if (existingPerson) {
233
+ await manager.update(EmployeeEvaluationPersonScoreModel_1.EmployeeEvaluationPersonScore, { id: existingPerson.id }, { is_rca: Boolean(emp.is_rca), updated_by: createdBy });
234
+ await manager.update(EmployeeEvaluationAnswerModel_1.EmployeeEvaluationAnswers, { request_id: requestId, user_id: emp.user_id, is_deleted: false }, { is_deleted: true, updated_by: createdBy });
235
+ }
236
+ else {
237
+ await manager.save(EmployeeEvaluationPersonScoreModel_1.EmployeeEvaluationPersonScore, manager.create(EmployeeEvaluationPersonScoreModel_1.EmployeeEvaluationPersonScore, {
238
+ request_id: requestId,
239
+ user_id: emp.user_id,
240
+ is_rca: Boolean(emp.is_rca),
241
+ us_feedback: null,
242
+ total_score: null,
243
+ created_by: createdBy,
244
+ is_deleted: false,
245
+ }));
246
+ }
247
+ if (emp.answers.length > 0) {
248
+ let personTotal = 0;
249
+ for (const ans of emp.answers) {
250
+ const qMeta = await manager.findOne(EvaluationFormQuestionModel_1.EvaluationFormQuestion, {
251
+ where: { id: ans.question_id, is_deleted: false },
252
+ });
253
+ const questionSectionId = qMeta?.form_section_id;
254
+ if (validateAnswers) {
255
+ if (!qMeta || questionSectionId == null || questionSectionId !== ans.section_id) {
256
+ throw new Error(`Invalid question ${ans.question_id} for section ${ans.section_id}`);
257
+ }
258
+ if (qMeta.max_score != null && ans.score > qMeta.max_score) {
259
+ throw new Error(`score ${ans.score} exceeds max_score ${qMeta.max_score} for question ${ans.question_id}`);
260
+ }
261
+ }
262
+ else if (qMeta &&
263
+ qMeta.form_section_id != null &&
264
+ qMeta.form_section_id !== ans.section_id) {
265
+ throw new Error(`Invalid question ${ans.question_id} for section ${ans.section_id}`);
266
+ }
267
+ personTotal += ans.score;
268
+ await manager.save(EmployeeEvaluationAnswerModel_1.EmployeeEvaluationAnswers, manager.create(EmployeeEvaluationAnswerModel_1.EmployeeEvaluationAnswers, {
269
+ request_id: requestId,
270
+ user_id: emp.user_id,
271
+ form_id: formId,
272
+ section_id: ans.section_id,
273
+ question_id: ans.question_id,
274
+ score: ans.score,
275
+ remarks: ans.remarks ?? null,
276
+ created_by: createdBy,
277
+ is_deleted: false,
278
+ }));
279
+ }
280
+ await manager.update(EmployeeEvaluationPersonScoreModel_1.EmployeeEvaluationPersonScore, { request_id: requestId, user_id: emp.user_id, is_deleted: false }, { total_score: personTotal, updated_by: createdBy });
281
+ }
282
+ }
283
+ const personRows = await manager.find(EmployeeEvaluationPersonScoreModel_1.EmployeeEvaluationPersonScore, {
284
+ where: { request_id: requestId, is_deleted: false },
285
+ });
286
+ const scores = personRows.map((p) => p.total_score ?? 0);
287
+ const requestTotal = scores.reduce((a, b) => a + b, 0);
288
+ const average = personRows.length ? requestTotal / personRows.length : 0;
289
+ await manager.update(EmployeeEvaluationRequestModel_1.EmployeeEvaluationRequests, { id: requestId }, {
290
+ total_score: personRows.length ? requestTotal : null,
291
+ average_score: personRows.length ? average : null,
292
+ employee_count: personRows.length,
293
+ updated_by: createdBy,
294
+ });
295
+ return {
296
+ totalScore: personRows.length ? requestTotal : null,
297
+ averageScore: personRows.length ? average : null,
298
+ employeeCount: personRows.length,
299
+ };
300
+ }
@@ -0,0 +1,5 @@
1
+ /**
2
+ * Re-exports the FM standard bilingual message builder.
3
+ * Import from '@platform-modules/foreign-ministry' in all services.
4
+ */
5
+ export * from './workflow-chat-message.builder';
@@ -0,0 +1,21 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __exportStar = (this && this.__exportStar) || function(m, exports) {
14
+ for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
15
+ };
16
+ Object.defineProperty(exports, "__esModule", { value: true });
17
+ /**
18
+ * Re-exports the FM standard bilingual message builder.
19
+ * Import from '@platform-modules/foreign-ministry' in all services.
20
+ */
21
+ __exportStar(require("./workflow-chat-message.builder"), exports);