@hed-hog/operations 0.0.299 → 0.0.300
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/operations.service.js +1193 -1193
- package/hedhog/data/menu.yaml +198 -198
- package/hedhog/data/role.yaml +23 -23
- package/hedhog/data/route.yaml +317 -317
- package/hedhog/table/operations_approval.yaml +49 -49
- package/hedhog/table/operations_approval_history.yaml +29 -29
- package/hedhog/table/operations_collaborator.yaml +67 -67
- package/hedhog/table/operations_collaborator_schedule_day.yaml +34 -34
- package/hedhog/table/operations_contract.yaml +100 -100
- package/hedhog/table/operations_contract_document.yaml +39 -39
- package/hedhog/table/operations_contract_financial_term.yaml +40 -40
- package/hedhog/table/operations_contract_history.yaml +27 -27
- package/hedhog/table/operations_contract_party.yaml +46 -46
- package/hedhog/table/operations_contract_revision.yaml +38 -38
- package/hedhog/table/operations_contract_signature.yaml +38 -38
- package/hedhog/table/operations_project.yaml +54 -54
- package/hedhog/table/operations_project_assignment.yaml +55 -55
- package/hedhog/table/operations_schedule_adjustment_day.yaml +34 -34
- package/hedhog/table/operations_schedule_adjustment_request.yaml +53 -53
- package/hedhog/table/operations_time_off_request.yaml +57 -57
- package/hedhog/table/operations_timesheet.yaml +41 -41
- package/hedhog/table/operations_timesheet_entry.yaml +40 -40
- package/package.json +4 -4
- package/src/operations.controller.ts +182 -182
- package/src/operations.module.ts +22 -22
- package/src/operations.service.ts +3595 -3595
- package/dist/operations-data.controller.d.ts +0 -139
- package/dist/operations-data.controller.d.ts.map +0 -1
- package/dist/operations-data.controller.js +0 -113
- package/dist/operations-data.controller.js.map +0 -1
- package/dist/operations-growth.controller.d.ts +0 -48
- package/dist/operations-growth.controller.d.ts.map +0 -1
- package/dist/operations-growth.controller.js +0 -90
- package/dist/operations-growth.controller.js.map +0 -1
|
@@ -37,35 +37,35 @@ let OperationsService = class OperationsService {
|
|
|
37
37
|
}
|
|
38
38
|
: { clause: '1 = 0', params: [] };
|
|
39
39
|
const [projects, timesheets, timeOff, schedules, approvals, recentTimesheets] = await Promise.all([
|
|
40
|
-
this.querySingle(`SELECT COUNT(*)::text AS total,
|
|
41
|
-
COUNT(*) FILTER (WHERE status = 'active')::text AS active
|
|
42
|
-
FROM operations_project p
|
|
40
|
+
this.querySingle(`SELECT COUNT(*)::text AS total,
|
|
41
|
+
COUNT(*) FILTER (WHERE status = 'active')::text AS active
|
|
42
|
+
FROM operations_project p
|
|
43
43
|
WHERE p.deleted_at IS NULL AND ${projectFilter.clause}`, projectFilter.params),
|
|
44
|
-
this.querySingle(`SELECT COUNT(*)::text AS total,
|
|
45
|
-
COUNT(*) FILTER (WHERE status = 'submitted')::text AS submitted
|
|
46
|
-
FROM operations_timesheet t
|
|
44
|
+
this.querySingle(`SELECT COUNT(*)::text AS total,
|
|
45
|
+
COUNT(*) FILTER (WHERE status = 'submitted')::text AS submitted
|
|
46
|
+
FROM operations_timesheet t
|
|
47
47
|
WHERE t.deleted_at IS NULL AND ${collaboratorFilter.clause}`, collaboratorFilter.params),
|
|
48
|
-
this.querySingle(`SELECT COUNT(*)::text AS total,
|
|
49
|
-
COUNT(*) FILTER (WHERE status = 'submitted')::text AS submitted
|
|
50
|
-
FROM operations_time_off_request tor
|
|
48
|
+
this.querySingle(`SELECT COUNT(*)::text AS total,
|
|
49
|
+
COUNT(*) FILTER (WHERE status = 'submitted')::text AS submitted
|
|
50
|
+
FROM operations_time_off_request tor
|
|
51
51
|
WHERE tor.deleted_at IS NULL AND ${timeOffFilter.clause}`, timeOffFilter.params),
|
|
52
|
-
this.querySingle(`SELECT COUNT(*)::text AS total,
|
|
53
|
-
COUNT(*) FILTER (WHERE status = 'submitted')::text AS submitted
|
|
54
|
-
FROM operations_schedule_adjustment_request sar
|
|
52
|
+
this.querySingle(`SELECT COUNT(*)::text AS total,
|
|
53
|
+
COUNT(*) FILTER (WHERE status = 'submitted')::text AS submitted
|
|
54
|
+
FROM operations_schedule_adjustment_request sar
|
|
55
55
|
WHERE sar.deleted_at IS NULL AND ${scheduleFilter.clause}`, scheduleFilter.params),
|
|
56
|
-
this.querySingle(`SELECT COUNT(*) FILTER (WHERE status = 'pending')::text AS pending
|
|
57
|
-
FROM operations_approval a
|
|
56
|
+
this.querySingle(`SELECT COUNT(*) FILTER (WHERE status = 'pending')::text AS pending
|
|
57
|
+
FROM operations_approval a
|
|
58
58
|
WHERE ${approvalFilter.clause}`, approvalFilter.params),
|
|
59
|
-
this.queryRows(`SELECT t.id,
|
|
60
|
-
c.display_name AS "collaboratorName",
|
|
61
|
-
t.week_start_date AS "weekStartDate",
|
|
62
|
-
t.week_end_date AS "weekEndDate",
|
|
63
|
-
t.total_hours AS "totalHours",
|
|
64
|
-
t.status
|
|
65
|
-
FROM operations_timesheet t
|
|
66
|
-
JOIN operations_collaborator c ON c.id = t.collaborator_id
|
|
67
|
-
WHERE t.deleted_at IS NULL AND ${collaboratorFilter.clause}
|
|
68
|
-
ORDER BY COALESCE(t.submitted_at, t.updated_at) DESC
|
|
59
|
+
this.queryRows(`SELECT t.id,
|
|
60
|
+
c.display_name AS "collaboratorName",
|
|
61
|
+
t.week_start_date AS "weekStartDate",
|
|
62
|
+
t.week_end_date AS "weekEndDate",
|
|
63
|
+
t.total_hours AS "totalHours",
|
|
64
|
+
t.status
|
|
65
|
+
FROM operations_timesheet t
|
|
66
|
+
JOIN operations_collaborator c ON c.id = t.collaborator_id
|
|
67
|
+
WHERE t.deleted_at IS NULL AND ${collaboratorFilter.clause}
|
|
68
|
+
ORDER BY COALESCE(t.submitted_at, t.updated_at) DESC
|
|
69
69
|
LIMIT 5`, collaboratorFilter.params),
|
|
70
70
|
]);
|
|
71
71
|
return {
|
|
@@ -95,43 +95,43 @@ let OperationsService = class OperationsService {
|
|
|
95
95
|
const actor = await this.getActorContext(userId);
|
|
96
96
|
this.ensureCollaborator(actor);
|
|
97
97
|
const filter = this.buildIdFilter(actor.visibleCollaboratorIds, 'c.id', actor.isDirector);
|
|
98
|
-
return this.queryRows(`SELECT c.id,
|
|
99
|
-
c.user_id AS "userId",
|
|
100
|
-
c.code,
|
|
101
|
-
c.collaborator_type AS "collaboratorType",
|
|
102
|
-
c.display_name AS "displayName",
|
|
103
|
-
c.department,
|
|
104
|
-
c.title,
|
|
105
|
-
c.level_label AS "levelLabel",
|
|
106
|
-
c.weekly_capacity_hours AS "weeklyCapacityHours",
|
|
107
|
-
c.status,
|
|
108
|
-
c.joined_at AS "joinedAt",
|
|
109
|
-
c.left_at AS "leftAt",
|
|
110
|
-
c.notes,
|
|
111
|
-
s.id AS "supervisorId",
|
|
112
|
-
s.display_name AS "supervisorName",
|
|
113
|
-
hiring_contract.id AS "contractId",
|
|
114
|
-
hiring_contract.status AS "contractStatus",
|
|
115
|
-
COUNT(DISTINCT pa.id)::int AS "activeAssignments"
|
|
116
|
-
FROM operations_collaborator c
|
|
117
|
-
LEFT JOIN operations_collaborator s
|
|
118
|
-
ON s.id = c.supervisor_collaborator_id
|
|
119
|
-
LEFT JOIN operations_project_assignment pa
|
|
120
|
-
ON pa.collaborator_id = c.id
|
|
121
|
-
AND pa.deleted_at IS NULL
|
|
122
|
-
AND pa.status IN ('planned', 'active')
|
|
123
|
-
LEFT JOIN LATERAL (
|
|
124
|
-
SELECT oc.id, oc.status
|
|
125
|
-
FROM operations_contract oc
|
|
126
|
-
WHERE oc.related_collaborator_id = c.id
|
|
127
|
-
AND oc.deleted_at IS NULL
|
|
128
|
-
ORDER BY CASE WHEN oc.origin_type = 'employee_hiring' THEN 0 ELSE 1 END,
|
|
129
|
-
oc.created_at DESC
|
|
130
|
-
LIMIT 1
|
|
131
|
-
) hiring_contract ON TRUE
|
|
132
|
-
WHERE c.deleted_at IS NULL
|
|
133
|
-
AND ${filter.clause}
|
|
134
|
-
GROUP BY c.id, s.id, hiring_contract.id, hiring_contract.status
|
|
98
|
+
return this.queryRows(`SELECT c.id,
|
|
99
|
+
c.user_id AS "userId",
|
|
100
|
+
c.code,
|
|
101
|
+
c.collaborator_type AS "collaboratorType",
|
|
102
|
+
c.display_name AS "displayName",
|
|
103
|
+
c.department,
|
|
104
|
+
c.title,
|
|
105
|
+
c.level_label AS "levelLabel",
|
|
106
|
+
c.weekly_capacity_hours AS "weeklyCapacityHours",
|
|
107
|
+
c.status,
|
|
108
|
+
c.joined_at AS "joinedAt",
|
|
109
|
+
c.left_at AS "leftAt",
|
|
110
|
+
c.notes,
|
|
111
|
+
s.id AS "supervisorId",
|
|
112
|
+
s.display_name AS "supervisorName",
|
|
113
|
+
hiring_contract.id AS "contractId",
|
|
114
|
+
hiring_contract.status AS "contractStatus",
|
|
115
|
+
COUNT(DISTINCT pa.id)::int AS "activeAssignments"
|
|
116
|
+
FROM operations_collaborator c
|
|
117
|
+
LEFT JOIN operations_collaborator s
|
|
118
|
+
ON s.id = c.supervisor_collaborator_id
|
|
119
|
+
LEFT JOIN operations_project_assignment pa
|
|
120
|
+
ON pa.collaborator_id = c.id
|
|
121
|
+
AND pa.deleted_at IS NULL
|
|
122
|
+
AND pa.status IN ('planned', 'active')
|
|
123
|
+
LEFT JOIN LATERAL (
|
|
124
|
+
SELECT oc.id, oc.status
|
|
125
|
+
FROM operations_contract oc
|
|
126
|
+
WHERE oc.related_collaborator_id = c.id
|
|
127
|
+
AND oc.deleted_at IS NULL
|
|
128
|
+
ORDER BY CASE WHEN oc.origin_type = 'employee_hiring' THEN 0 ELSE 1 END,
|
|
129
|
+
oc.created_at DESC
|
|
130
|
+
LIMIT 1
|
|
131
|
+
) hiring_contract ON TRUE
|
|
132
|
+
WHERE c.deleted_at IS NULL
|
|
133
|
+
AND ${filter.clause}
|
|
134
|
+
GROUP BY c.id, s.id, hiring_contract.id, hiring_contract.status
|
|
135
135
|
ORDER BY c.display_name ASC`, filter.params);
|
|
136
136
|
}
|
|
137
137
|
async getMyCollaborator(userId) {
|
|
@@ -167,155 +167,155 @@ let OperationsService = class OperationsService {
|
|
|
167
167
|
};
|
|
168
168
|
}
|
|
169
169
|
const teamFilter = this.buildIdFilter(actor.teamCollaboratorIds, 'c.id', false);
|
|
170
|
-
const teamMembers = await this.queryRows(`SELECT c.id,
|
|
171
|
-
c.user_id AS "userId",
|
|
172
|
-
c.code,
|
|
173
|
-
c.display_name AS "displayName",
|
|
174
|
-
c.collaborator_type AS "collaboratorType",
|
|
175
|
-
c.department,
|
|
176
|
-
c.title,
|
|
177
|
-
c.status,
|
|
178
|
-
COUNT(DISTINCT pa.id)::int AS "activeAssignments",
|
|
179
|
-
COUNT(DISTINCT a.id) FILTER (WHERE a.status = 'pending')::int AS "pendingApprovals",
|
|
180
|
-
COUNT(DISTINCT tor.id) FILTER (WHERE tor.status = 'submitted')::int AS "pendingTimeOffRequests",
|
|
181
|
-
COUNT(DISTINCT sar.id) FILTER (WHERE sar.status = 'submitted')::int AS "pendingScheduleAdjustmentRequests"
|
|
182
|
-
FROM operations_collaborator c
|
|
183
|
-
LEFT JOIN operations_project_assignment pa
|
|
184
|
-
ON pa.collaborator_id = c.id
|
|
185
|
-
AND pa.deleted_at IS NULL
|
|
186
|
-
AND pa.status IN ('planned', 'active')
|
|
187
|
-
LEFT JOIN operations_approval a
|
|
188
|
-
ON a.requester_collaborator_id = c.id
|
|
189
|
-
AND a.deleted_at IS NULL
|
|
190
|
-
AND a.status = 'pending'
|
|
191
|
-
LEFT JOIN operations_time_off_request tor
|
|
192
|
-
ON tor.collaborator_id = c.id
|
|
193
|
-
AND tor.deleted_at IS NULL
|
|
194
|
-
AND tor.status = 'submitted'
|
|
195
|
-
LEFT JOIN operations_schedule_adjustment_request sar
|
|
196
|
-
ON sar.collaborator_id = c.id
|
|
197
|
-
AND sar.deleted_at IS NULL
|
|
198
|
-
AND sar.status = 'submitted'
|
|
199
|
-
WHERE c.deleted_at IS NULL AND ${teamFilter.clause}
|
|
200
|
-
GROUP BY c.id
|
|
170
|
+
const teamMembers = await this.queryRows(`SELECT c.id,
|
|
171
|
+
c.user_id AS "userId",
|
|
172
|
+
c.code,
|
|
173
|
+
c.display_name AS "displayName",
|
|
174
|
+
c.collaborator_type AS "collaboratorType",
|
|
175
|
+
c.department,
|
|
176
|
+
c.title,
|
|
177
|
+
c.status,
|
|
178
|
+
COUNT(DISTINCT pa.id)::int AS "activeAssignments",
|
|
179
|
+
COUNT(DISTINCT a.id) FILTER (WHERE a.status = 'pending')::int AS "pendingApprovals",
|
|
180
|
+
COUNT(DISTINCT tor.id) FILTER (WHERE tor.status = 'submitted')::int AS "pendingTimeOffRequests",
|
|
181
|
+
COUNT(DISTINCT sar.id) FILTER (WHERE sar.status = 'submitted')::int AS "pendingScheduleAdjustmentRequests"
|
|
182
|
+
FROM operations_collaborator c
|
|
183
|
+
LEFT JOIN operations_project_assignment pa
|
|
184
|
+
ON pa.collaborator_id = c.id
|
|
185
|
+
AND pa.deleted_at IS NULL
|
|
186
|
+
AND pa.status IN ('planned', 'active')
|
|
187
|
+
LEFT JOIN operations_approval a
|
|
188
|
+
ON a.requester_collaborator_id = c.id
|
|
189
|
+
AND a.deleted_at IS NULL
|
|
190
|
+
AND a.status = 'pending'
|
|
191
|
+
LEFT JOIN operations_time_off_request tor
|
|
192
|
+
ON tor.collaborator_id = c.id
|
|
193
|
+
AND tor.deleted_at IS NULL
|
|
194
|
+
AND tor.status = 'submitted'
|
|
195
|
+
LEFT JOIN operations_schedule_adjustment_request sar
|
|
196
|
+
ON sar.collaborator_id = c.id
|
|
197
|
+
AND sar.deleted_at IS NULL
|
|
198
|
+
AND sar.status = 'submitted'
|
|
199
|
+
WHERE c.deleted_at IS NULL AND ${teamFilter.clause}
|
|
200
|
+
GROUP BY c.id
|
|
201
201
|
ORDER BY c.display_name ASC`, teamFilter.params);
|
|
202
202
|
const [teamProjects, pendingApprovalQueue, pendingTimeOffRequests, pendingScheduleAdjustmentRequests] = await Promise.all([
|
|
203
|
-
this.queryRows(`SELECT p.id,
|
|
204
|
-
p.code,
|
|
205
|
-
p.name,
|
|
206
|
-
p.client_name AS "clientName",
|
|
207
|
-
p.status,
|
|
208
|
-
COUNT(DISTINCT pa.collaborator_id)::int AS "teamSize",
|
|
209
|
-
COUNT(DISTINCT t.id) FILTER (WHERE t.status = 'submitted')::int AS "pendingTimesheets"
|
|
210
|
-
FROM operations_project p
|
|
211
|
-
JOIN operations_project_assignment pa
|
|
212
|
-
ON pa.project_id = p.id
|
|
213
|
-
AND pa.deleted_at IS NULL
|
|
214
|
-
AND pa.status IN ('planned', 'active')
|
|
215
|
-
LEFT JOIN operations_timesheet_entry te
|
|
216
|
-
ON te.project_assignment_id = pa.id
|
|
217
|
-
AND te.deleted_at IS NULL
|
|
218
|
-
LEFT JOIN operations_timesheet t
|
|
219
|
-
ON t.id = te.timesheet_id
|
|
220
|
-
AND t.deleted_at IS NULL
|
|
221
|
-
WHERE p.deleted_at IS NULL
|
|
222
|
-
AND pa.collaborator_id = ANY($1::int[])
|
|
223
|
-
GROUP BY p.id
|
|
203
|
+
this.queryRows(`SELECT p.id,
|
|
204
|
+
p.code,
|
|
205
|
+
p.name,
|
|
206
|
+
p.client_name AS "clientName",
|
|
207
|
+
p.status,
|
|
208
|
+
COUNT(DISTINCT pa.collaborator_id)::int AS "teamSize",
|
|
209
|
+
COUNT(DISTINCT t.id) FILTER (WHERE t.status = 'submitted')::int AS "pendingTimesheets"
|
|
210
|
+
FROM operations_project p
|
|
211
|
+
JOIN operations_project_assignment pa
|
|
212
|
+
ON pa.project_id = p.id
|
|
213
|
+
AND pa.deleted_at IS NULL
|
|
214
|
+
AND pa.status IN ('planned', 'active')
|
|
215
|
+
LEFT JOIN operations_timesheet_entry te
|
|
216
|
+
ON te.project_assignment_id = pa.id
|
|
217
|
+
AND te.deleted_at IS NULL
|
|
218
|
+
LEFT JOIN operations_timesheet t
|
|
219
|
+
ON t.id = te.timesheet_id
|
|
220
|
+
AND t.deleted_at IS NULL
|
|
221
|
+
WHERE p.deleted_at IS NULL
|
|
222
|
+
AND pa.collaborator_id = ANY($1::int[])
|
|
223
|
+
GROUP BY p.id
|
|
224
224
|
ORDER BY p.name ASC`, [actor.teamCollaboratorIds]),
|
|
225
|
-
this.queryRows(`SELECT a.id,
|
|
226
|
-
a.target_type AS "targetType",
|
|
227
|
-
a.target_id AS "targetId",
|
|
228
|
-
a.requester_collaborator_id AS "requesterCollaboratorId",
|
|
229
|
-
requester.display_name AS "requesterName",
|
|
230
|
-
a.approver_collaborator_id AS "approverCollaboratorId",
|
|
231
|
-
approver.display_name AS "approverName",
|
|
232
|
-
a.status,
|
|
233
|
-
a.submitted_at AS "submittedAt",
|
|
234
|
-
a.decided_at AS "decidedAt",
|
|
235
|
-
a.decision_note AS "decisionNote",
|
|
236
|
-
t.week_start_date AS "timesheetWeekStartDate",
|
|
237
|
-
t.week_end_date AS "timesheetWeekEndDate",
|
|
238
|
-
t.total_hours AS "timesheetTotalHours",
|
|
239
|
-
COALESCE(
|
|
240
|
-
STRING_AGG(DISTINCT p.name, ', ') FILTER (WHERE p.name IS NOT NULL),
|
|
241
|
-
''
|
|
242
|
-
) AS "timesheetProjectNames",
|
|
243
|
-
tor.request_type AS "timeOffType",
|
|
244
|
-
tor.start_date AS "timeOffStartDate",
|
|
245
|
-
tor.end_date AS "timeOffEndDate",
|
|
246
|
-
tor.reason AS "timeOffReason",
|
|
247
|
-
sar.request_scope AS "scheduleRequestScope",
|
|
248
|
-
sar.effective_start_date AS "scheduleStartDate",
|
|
249
|
-
sar.effective_end_date AS "scheduleEndDate",
|
|
250
|
-
sar.reason AS "scheduleReason"
|
|
251
|
-
FROM operations_approval a
|
|
252
|
-
JOIN operations_collaborator requester
|
|
253
|
-
ON requester.id = a.requester_collaborator_id
|
|
254
|
-
LEFT JOIN operations_collaborator approver
|
|
255
|
-
ON approver.id = a.approver_collaborator_id
|
|
256
|
-
LEFT JOIN operations_timesheet t
|
|
257
|
-
ON a.target_type = 'timesheet'
|
|
258
|
-
AND t.id = a.target_id
|
|
259
|
-
LEFT JOIN operations_timesheet_entry te
|
|
260
|
-
ON te.timesheet_id = t.id
|
|
261
|
-
AND te.deleted_at IS NULL
|
|
262
|
-
LEFT JOIN operations_project_assignment pa
|
|
263
|
-
ON pa.id = te.project_assignment_id
|
|
264
|
-
LEFT JOIN operations_project p
|
|
265
|
-
ON p.id = pa.project_id
|
|
266
|
-
LEFT JOIN operations_time_off_request tor
|
|
267
|
-
ON a.target_type = 'time_off_request'
|
|
268
|
-
AND tor.id = a.target_id
|
|
269
|
-
LEFT JOIN operations_schedule_adjustment_request sar
|
|
270
|
-
ON a.target_type = 'schedule_adjustment_request'
|
|
271
|
-
AND sar.id = a.target_id
|
|
272
|
-
WHERE a.deleted_at IS NULL
|
|
273
|
-
AND a.status = 'pending'
|
|
274
|
-
AND a.approver_collaborator_id = $1
|
|
275
|
-
GROUP BY a.id, requester.id, approver.id, t.id, tor.id, sar.id
|
|
225
|
+
this.queryRows(`SELECT a.id,
|
|
226
|
+
a.target_type AS "targetType",
|
|
227
|
+
a.target_id AS "targetId",
|
|
228
|
+
a.requester_collaborator_id AS "requesterCollaboratorId",
|
|
229
|
+
requester.display_name AS "requesterName",
|
|
230
|
+
a.approver_collaborator_id AS "approverCollaboratorId",
|
|
231
|
+
approver.display_name AS "approverName",
|
|
232
|
+
a.status,
|
|
233
|
+
a.submitted_at AS "submittedAt",
|
|
234
|
+
a.decided_at AS "decidedAt",
|
|
235
|
+
a.decision_note AS "decisionNote",
|
|
236
|
+
t.week_start_date AS "timesheetWeekStartDate",
|
|
237
|
+
t.week_end_date AS "timesheetWeekEndDate",
|
|
238
|
+
t.total_hours AS "timesheetTotalHours",
|
|
239
|
+
COALESCE(
|
|
240
|
+
STRING_AGG(DISTINCT p.name, ', ') FILTER (WHERE p.name IS NOT NULL),
|
|
241
|
+
''
|
|
242
|
+
) AS "timesheetProjectNames",
|
|
243
|
+
tor.request_type AS "timeOffType",
|
|
244
|
+
tor.start_date AS "timeOffStartDate",
|
|
245
|
+
tor.end_date AS "timeOffEndDate",
|
|
246
|
+
tor.reason AS "timeOffReason",
|
|
247
|
+
sar.request_scope AS "scheduleRequestScope",
|
|
248
|
+
sar.effective_start_date AS "scheduleStartDate",
|
|
249
|
+
sar.effective_end_date AS "scheduleEndDate",
|
|
250
|
+
sar.reason AS "scheduleReason"
|
|
251
|
+
FROM operations_approval a
|
|
252
|
+
JOIN operations_collaborator requester
|
|
253
|
+
ON requester.id = a.requester_collaborator_id
|
|
254
|
+
LEFT JOIN operations_collaborator approver
|
|
255
|
+
ON approver.id = a.approver_collaborator_id
|
|
256
|
+
LEFT JOIN operations_timesheet t
|
|
257
|
+
ON a.target_type = 'timesheet'
|
|
258
|
+
AND t.id = a.target_id
|
|
259
|
+
LEFT JOIN operations_timesheet_entry te
|
|
260
|
+
ON te.timesheet_id = t.id
|
|
261
|
+
AND te.deleted_at IS NULL
|
|
262
|
+
LEFT JOIN operations_project_assignment pa
|
|
263
|
+
ON pa.id = te.project_assignment_id
|
|
264
|
+
LEFT JOIN operations_project p
|
|
265
|
+
ON p.id = pa.project_id
|
|
266
|
+
LEFT JOIN operations_time_off_request tor
|
|
267
|
+
ON a.target_type = 'time_off_request'
|
|
268
|
+
AND tor.id = a.target_id
|
|
269
|
+
LEFT JOIN operations_schedule_adjustment_request sar
|
|
270
|
+
ON a.target_type = 'schedule_adjustment_request'
|
|
271
|
+
AND sar.id = a.target_id
|
|
272
|
+
WHERE a.deleted_at IS NULL
|
|
273
|
+
AND a.status = 'pending'
|
|
274
|
+
AND a.approver_collaborator_id = $1
|
|
275
|
+
GROUP BY a.id, requester.id, approver.id, t.id, tor.id, sar.id
|
|
276
276
|
ORDER BY a.submitted_at DESC, a.id DESC`, [actor.collaboratorId]),
|
|
277
|
-
this.queryRows(`SELECT tor.id,
|
|
278
|
-
tor.collaborator_id AS "collaboratorId",
|
|
279
|
-
c.display_name AS "collaboratorName",
|
|
280
|
-
tor.request_type AS "requestType",
|
|
281
|
-
tor.start_date AS "startDate",
|
|
282
|
-
tor.end_date AS "endDate",
|
|
283
|
-
tor.total_days AS "totalDays",
|
|
284
|
-
tor.status,
|
|
285
|
-
tor.reason,
|
|
286
|
-
tor.submitted_at AS "submittedAt",
|
|
287
|
-
tor.reviewed_at AS "reviewedAt",
|
|
288
|
-
approval.decision_note AS "approverNote"
|
|
289
|
-
FROM operations_time_off_request tor
|
|
290
|
-
JOIN operations_collaborator c ON c.id = tor.collaborator_id
|
|
291
|
-
LEFT JOIN operations_approval approval
|
|
292
|
-
ON approval.target_type = 'time_off_request'
|
|
293
|
-
AND approval.target_id = tor.id
|
|
294
|
-
AND approval.deleted_at IS NULL
|
|
295
|
-
WHERE tor.deleted_at IS NULL
|
|
296
|
-
AND tor.status = 'submitted'
|
|
297
|
-
AND tor.collaborator_id = ANY($1::int[])
|
|
277
|
+
this.queryRows(`SELECT tor.id,
|
|
278
|
+
tor.collaborator_id AS "collaboratorId",
|
|
279
|
+
c.display_name AS "collaboratorName",
|
|
280
|
+
tor.request_type AS "requestType",
|
|
281
|
+
tor.start_date AS "startDate",
|
|
282
|
+
tor.end_date AS "endDate",
|
|
283
|
+
tor.total_days AS "totalDays",
|
|
284
|
+
tor.status,
|
|
285
|
+
tor.reason,
|
|
286
|
+
tor.submitted_at AS "submittedAt",
|
|
287
|
+
tor.reviewed_at AS "reviewedAt",
|
|
288
|
+
approval.decision_note AS "approverNote"
|
|
289
|
+
FROM operations_time_off_request tor
|
|
290
|
+
JOIN operations_collaborator c ON c.id = tor.collaborator_id
|
|
291
|
+
LEFT JOIN operations_approval approval
|
|
292
|
+
ON approval.target_type = 'time_off_request'
|
|
293
|
+
AND approval.target_id = tor.id
|
|
294
|
+
AND approval.deleted_at IS NULL
|
|
295
|
+
WHERE tor.deleted_at IS NULL
|
|
296
|
+
AND tor.status = 'submitted'
|
|
297
|
+
AND tor.collaborator_id = ANY($1::int[])
|
|
298
298
|
ORDER BY tor.start_date ASC, tor.id ASC`, [actor.teamCollaboratorIds]),
|
|
299
|
-
this.queryRows(`SELECT sar.id,
|
|
300
|
-
sar.collaborator_id AS "collaboratorId",
|
|
301
|
-
c.display_name AS "collaboratorName",
|
|
302
|
-
sar.request_scope AS "requestScope",
|
|
303
|
-
sar.effective_start_date AS "effectiveStartDate",
|
|
304
|
-
sar.effective_end_date AS "effectiveEndDate",
|
|
305
|
-
sar.status,
|
|
306
|
-
sar.reason,
|
|
307
|
-
sar.submitted_at AS "submittedAt",
|
|
308
|
-
sar.reviewed_at AS "reviewedAt",
|
|
309
|
-
approval.decision_note AS "approverNote"
|
|
310
|
-
FROM operations_schedule_adjustment_request sar
|
|
311
|
-
JOIN operations_collaborator c ON c.id = sar.collaborator_id
|
|
312
|
-
LEFT JOIN operations_approval approval
|
|
313
|
-
ON approval.target_type = 'schedule_adjustment_request'
|
|
314
|
-
AND approval.target_id = sar.id
|
|
315
|
-
AND approval.deleted_at IS NULL
|
|
316
|
-
WHERE sar.deleted_at IS NULL
|
|
317
|
-
AND sar.status = 'submitted'
|
|
318
|
-
AND sar.collaborator_id = ANY($1::int[])
|
|
299
|
+
this.queryRows(`SELECT sar.id,
|
|
300
|
+
sar.collaborator_id AS "collaboratorId",
|
|
301
|
+
c.display_name AS "collaboratorName",
|
|
302
|
+
sar.request_scope AS "requestScope",
|
|
303
|
+
sar.effective_start_date AS "effectiveStartDate",
|
|
304
|
+
sar.effective_end_date AS "effectiveEndDate",
|
|
305
|
+
sar.status,
|
|
306
|
+
sar.reason,
|
|
307
|
+
sar.submitted_at AS "submittedAt",
|
|
308
|
+
sar.reviewed_at AS "reviewedAt",
|
|
309
|
+
approval.decision_note AS "approverNote"
|
|
310
|
+
FROM operations_schedule_adjustment_request sar
|
|
311
|
+
JOIN operations_collaborator c ON c.id = sar.collaborator_id
|
|
312
|
+
LEFT JOIN operations_approval approval
|
|
313
|
+
ON approval.target_type = 'schedule_adjustment_request'
|
|
314
|
+
AND approval.target_id = sar.id
|
|
315
|
+
AND approval.deleted_at IS NULL
|
|
316
|
+
WHERE sar.deleted_at IS NULL
|
|
317
|
+
AND sar.status = 'submitted'
|
|
318
|
+
AND sar.collaborator_id = ANY($1::int[])
|
|
319
319
|
ORDER BY sar.effective_start_date ASC, sar.id ASC`, [actor.teamCollaboratorIds]),
|
|
320
320
|
]);
|
|
321
321
|
const pendingItemCounts = {
|
|
@@ -328,10 +328,10 @@ let OperationsService = class OperationsService {
|
|
|
328
328
|
teamMembers,
|
|
329
329
|
projectCount: (await this.getAssignedProjectIds(actor.teamCollaboratorIds))
|
|
330
330
|
.length,
|
|
331
|
-
pendingApprovals: Number((_b = (_a = (await this.querySingle(`SELECT COUNT(*)::text AS total
|
|
332
|
-
FROM operations_approval
|
|
333
|
-
WHERE deleted_at IS NULL
|
|
334
|
-
AND status = 'pending'
|
|
331
|
+
pendingApprovals: Number((_b = (_a = (await this.querySingle(`SELECT COUNT(*)::text AS total
|
|
332
|
+
FROM operations_approval
|
|
333
|
+
WHERE deleted_at IS NULL
|
|
334
|
+
AND status = 'pending'
|
|
335
335
|
AND approver_collaborator_id = $1`, [actor.collaboratorId]))) === null || _a === void 0 ? void 0 : _a.total) !== null && _b !== void 0 ? _b : 0),
|
|
336
336
|
pendingItems: pendingItemCounts,
|
|
337
337
|
teamProjects,
|
|
@@ -346,26 +346,26 @@ let OperationsService = class OperationsService {
|
|
|
346
346
|
this.requireFields(data, ['userId', 'code', 'displayName']);
|
|
347
347
|
const collaboratorId = await this.prisma.$transaction(async (tx) => {
|
|
348
348
|
var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o, _p, _q, _r, _s, _t;
|
|
349
|
-
const created = (await tx.$queryRawUnsafe(`INSERT INTO operations_collaborator (
|
|
350
|
-
user_id,
|
|
351
|
-
supervisor_collaborator_id,
|
|
352
|
-
code,
|
|
353
|
-
collaborator_type,
|
|
354
|
-
display_name,
|
|
355
|
-
department,
|
|
356
|
-
title,
|
|
357
|
-
level_label,
|
|
358
|
-
weekly_capacity_hours,
|
|
359
|
-
status,
|
|
360
|
-
joined_at,
|
|
361
|
-
left_at,
|
|
362
|
-
notes,
|
|
363
|
-
created_at,
|
|
364
|
-
updated_at
|
|
365
|
-
) VALUES (
|
|
366
|
-
$1, $2, $3, COALESCE($4, 'other'), $5, $6, $7, $8, $9,
|
|
367
|
-
COALESCE($10, 'active'), $11, $12, $13, NOW(), NOW()
|
|
368
|
-
)
|
|
349
|
+
const created = (await tx.$queryRawUnsafe(`INSERT INTO operations_collaborator (
|
|
350
|
+
user_id,
|
|
351
|
+
supervisor_collaborator_id,
|
|
352
|
+
code,
|
|
353
|
+
collaborator_type,
|
|
354
|
+
display_name,
|
|
355
|
+
department,
|
|
356
|
+
title,
|
|
357
|
+
level_label,
|
|
358
|
+
weekly_capacity_hours,
|
|
359
|
+
status,
|
|
360
|
+
joined_at,
|
|
361
|
+
left_at,
|
|
362
|
+
notes,
|
|
363
|
+
created_at,
|
|
364
|
+
updated_at
|
|
365
|
+
) VALUES (
|
|
366
|
+
$1, $2, $3, COALESCE($4, 'other'), $5, $6, $7, $8, $9,
|
|
367
|
+
COALESCE($10, 'active'), $11, $12, $13, NOW(), NOW()
|
|
368
|
+
)
|
|
369
369
|
RETURNING id`, data.userId, (_a = data.supervisorCollaboratorId) !== null && _a !== void 0 ? _a : null, data.code, (_b = data.collaboratorType) !== null && _b !== void 0 ? _b : 'other', data.displayName, (_c = data.department) !== null && _c !== void 0 ? _c : null, (_d = data.title) !== null && _d !== void 0 ? _d : null, (_e = data.levelLabel) !== null && _e !== void 0 ? _e : null, (_f = data.weeklyCapacityHours) !== null && _f !== void 0 ? _f : null, (_g = data.status) !== null && _g !== void 0 ? _g : 'active', (_h = data.joinedAt) !== null && _h !== void 0 ? _h : null, (_j = data.leftAt) !== null && _j !== void 0 ? _j : null, (_k = data.notes) !== null && _k !== void 0 ? _k : null));
|
|
370
370
|
const createdCollaboratorId = (_l = created[0]) === null || _l === void 0 ? void 0 : _l.id;
|
|
371
371
|
await this.replaceCollaboratorScheduleDays(tx, createdCollaboratorId, data.weeklySchedule);
|
|
@@ -407,9 +407,9 @@ let OperationsService = class OperationsService {
|
|
|
407
407
|
await this.prisma.$transaction(async (tx) => {
|
|
408
408
|
if (updates.length) {
|
|
409
409
|
params.push(collaboratorId);
|
|
410
|
-
await tx.$executeRawUnsafe(`UPDATE operations_collaborator
|
|
411
|
-
SET ${updates.join(', ')},
|
|
412
|
-
updated_at = NOW()
|
|
410
|
+
await tx.$executeRawUnsafe(`UPDATE operations_collaborator
|
|
411
|
+
SET ${updates.join(', ')},
|
|
412
|
+
updated_at = NOW()
|
|
413
413
|
WHERE id = $${params.length}`, ...params);
|
|
414
414
|
}
|
|
415
415
|
if (data.weeklySchedule) {
|
|
@@ -423,37 +423,37 @@ let OperationsService = class OperationsService {
|
|
|
423
423
|
const filter = this.buildIdFilter(actor.visibleProjectIds, 'p.id', actor.isDirector);
|
|
424
424
|
const assignmentParams = [];
|
|
425
425
|
const ownAssignmentSelect = actor.collaboratorId
|
|
426
|
-
? `MAX(CASE WHEN pa.collaborator_id = ${this.param(assignmentParams, actor.collaboratorId)} THEN pa.id END)::int AS "myAssignmentId",
|
|
426
|
+
? `MAX(CASE WHEN pa.collaborator_id = ${this.param(assignmentParams, actor.collaboratorId)} THEN pa.id END)::int AS "myAssignmentId",
|
|
427
427
|
MAX(CASE WHEN pa.collaborator_id = ${this.param(assignmentParams, actor.collaboratorId)} THEN pa.role_label END) AS "myRoleLabel",`
|
|
428
|
-
: `NULL::int AS "myAssignmentId",
|
|
428
|
+
: `NULL::int AS "myAssignmentId",
|
|
429
429
|
NULL::varchar AS "myRoleLabel",`;
|
|
430
|
-
return this.queryRows(`SELECT p.id,
|
|
431
|
-
p.contract_id AS "contractId",
|
|
432
|
-
p.manager_collaborator_id AS "managerCollaboratorId",
|
|
433
|
-
p.code,
|
|
434
|
-
p.name,
|
|
435
|
-
p.client_name AS "clientName",
|
|
436
|
-
p.summary,
|
|
437
|
-
p.status,
|
|
438
|
-
p.progress_percent AS "progressPercent",
|
|
439
|
-
p.delivery_model AS "deliveryModel",
|
|
440
|
-
p.budget_amount AS "budgetAmount",
|
|
441
|
-
p.start_date AS "startDate",
|
|
442
|
-
p.end_date AS "endDate",
|
|
443
|
-
c.name AS "contractName",
|
|
444
|
-
c.status AS "contractStatus",
|
|
445
|
-
m.display_name AS "managerName",
|
|
446
|
-
${ownAssignmentSelect}
|
|
447
|
-
COUNT(DISTINCT pa.id)::int AS "teamSize"
|
|
448
|
-
FROM operations_project p
|
|
449
|
-
LEFT JOIN operations_contract c ON c.id = p.contract_id
|
|
450
|
-
LEFT JOIN operations_collaborator m ON m.id = p.manager_collaborator_id
|
|
451
|
-
LEFT JOIN operations_project_assignment pa
|
|
452
|
-
ON pa.project_id = p.id
|
|
453
|
-
AND pa.deleted_at IS NULL
|
|
454
|
-
AND pa.status IN ('planned', 'active')
|
|
455
|
-
WHERE p.deleted_at IS NULL AND ${filter.clause}
|
|
456
|
-
GROUP BY p.id, c.id, m.id
|
|
430
|
+
return this.queryRows(`SELECT p.id,
|
|
431
|
+
p.contract_id AS "contractId",
|
|
432
|
+
p.manager_collaborator_id AS "managerCollaboratorId",
|
|
433
|
+
p.code,
|
|
434
|
+
p.name,
|
|
435
|
+
p.client_name AS "clientName",
|
|
436
|
+
p.summary,
|
|
437
|
+
p.status,
|
|
438
|
+
p.progress_percent AS "progressPercent",
|
|
439
|
+
p.delivery_model AS "deliveryModel",
|
|
440
|
+
p.budget_amount AS "budgetAmount",
|
|
441
|
+
p.start_date AS "startDate",
|
|
442
|
+
p.end_date AS "endDate",
|
|
443
|
+
c.name AS "contractName",
|
|
444
|
+
c.status AS "contractStatus",
|
|
445
|
+
m.display_name AS "managerName",
|
|
446
|
+
${ownAssignmentSelect}
|
|
447
|
+
COUNT(DISTINCT pa.id)::int AS "teamSize"
|
|
448
|
+
FROM operations_project p
|
|
449
|
+
LEFT JOIN operations_contract c ON c.id = p.contract_id
|
|
450
|
+
LEFT JOIN operations_collaborator m ON m.id = p.manager_collaborator_id
|
|
451
|
+
LEFT JOIN operations_project_assignment pa
|
|
452
|
+
ON pa.project_id = p.id
|
|
453
|
+
AND pa.deleted_at IS NULL
|
|
454
|
+
AND pa.status IN ('planned', 'active')
|
|
455
|
+
WHERE p.deleted_at IS NULL AND ${filter.clause}
|
|
456
|
+
GROUP BY p.id, c.id, m.id
|
|
457
457
|
ORDER BY p.name ASC`, [...assignmentParams, ...filter.params]);
|
|
458
458
|
}
|
|
459
459
|
async getProjectById(userId, projectId) {
|
|
@@ -467,25 +467,25 @@ let OperationsService = class OperationsService {
|
|
|
467
467
|
this.requireFields(data, ['code', 'name']);
|
|
468
468
|
const createdProjectId = await this.prisma.$transaction(async (tx) => {
|
|
469
469
|
var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o, _p, _q, _r, _s, _t, _u, _v, _w, _x, _y;
|
|
470
|
-
const created = await tx.$queryRawUnsafe(`INSERT INTO operations_project (
|
|
471
|
-
contract_id,
|
|
472
|
-
manager_collaborator_id,
|
|
473
|
-
code,
|
|
474
|
-
name,
|
|
475
|
-
client_name,
|
|
476
|
-
summary,
|
|
477
|
-
status,
|
|
478
|
-
progress_percent,
|
|
479
|
-
delivery_model,
|
|
480
|
-
budget_amount,
|
|
481
|
-
start_date,
|
|
482
|
-
end_date,
|
|
483
|
-
created_at,
|
|
484
|
-
updated_at
|
|
485
|
-
) VALUES (
|
|
486
|
-
$1, $2, $3, $4, $5, $6, COALESCE($7, 'planning'), $8,
|
|
487
|
-
COALESCE($9, 'project_delivery'), $10, $11, $12, NOW(), NOW()
|
|
488
|
-
)
|
|
470
|
+
const created = await tx.$queryRawUnsafe(`INSERT INTO operations_project (
|
|
471
|
+
contract_id,
|
|
472
|
+
manager_collaborator_id,
|
|
473
|
+
code,
|
|
474
|
+
name,
|
|
475
|
+
client_name,
|
|
476
|
+
summary,
|
|
477
|
+
status,
|
|
478
|
+
progress_percent,
|
|
479
|
+
delivery_model,
|
|
480
|
+
budget_amount,
|
|
481
|
+
start_date,
|
|
482
|
+
end_date,
|
|
483
|
+
created_at,
|
|
484
|
+
updated_at
|
|
485
|
+
) VALUES (
|
|
486
|
+
$1, $2, $3, $4, $5, $6, COALESCE($7, 'planning'), $8,
|
|
487
|
+
COALESCE($9, 'project_delivery'), $10, $11, $12, NOW(), NOW()
|
|
488
|
+
)
|
|
489
489
|
RETURNING id`, (_a = data.contractId) !== null && _a !== void 0 ? _a : null, (_b = data.managerCollaboratorId) !== null && _b !== void 0 ? _b : null, data.code, data.name, (_c = data.clientName) !== null && _c !== void 0 ? _c : null, (_d = data.summary) !== null && _d !== void 0 ? _d : null, (_e = data.status) !== null && _e !== void 0 ? _e : 'planning', (_f = data.progressPercent) !== null && _f !== void 0 ? _f : null, (_g = data.deliveryModel) !== null && _g !== void 0 ? _g : 'project_delivery', (_h = data.budgetAmount) !== null && _h !== void 0 ? _h : null, (_j = data.startDate) !== null && _j !== void 0 ? _j : null, (_k = data.endDate) !== null && _k !== void 0 ? _k : null);
|
|
490
490
|
const projectId = (_l = created[0]) === null || _l === void 0 ? void 0 : _l.id;
|
|
491
491
|
if ((_m = data.teamAssignments) === null || _m === void 0 ? void 0 : _m.length) {
|
|
@@ -507,9 +507,9 @@ let OperationsService = class OperationsService {
|
|
|
507
507
|
contractName: (_w = data.contractName) !== null && _w !== void 0 ? _w : null,
|
|
508
508
|
description: (_y = (_x = data.contractDescription) !== null && _x !== void 0 ? _x : data.summary) !== null && _y !== void 0 ? _y : null,
|
|
509
509
|
});
|
|
510
|
-
await tx.$executeRawUnsafe(`UPDATE operations_project
|
|
511
|
-
SET contract_id = $1,
|
|
512
|
-
updated_at = NOW()
|
|
510
|
+
await tx.$executeRawUnsafe(`UPDATE operations_project
|
|
511
|
+
SET contract_id = $1,
|
|
512
|
+
updated_at = NOW()
|
|
513
513
|
WHERE id = $2`, contractId, projectId);
|
|
514
514
|
}
|
|
515
515
|
return projectId;
|
|
@@ -537,9 +537,9 @@ let OperationsService = class OperationsService {
|
|
|
537
537
|
await this.prisma.$transaction(async (tx) => {
|
|
538
538
|
if (updates.length) {
|
|
539
539
|
params.push(projectId);
|
|
540
|
-
await tx.$executeRawUnsafe(`UPDATE operations_project
|
|
541
|
-
SET ${updates.join(', ')},
|
|
542
|
-
updated_at = NOW()
|
|
540
|
+
await tx.$executeRawUnsafe(`UPDATE operations_project
|
|
541
|
+
SET ${updates.join(', ')},
|
|
542
|
+
updated_at = NOW()
|
|
543
543
|
WHERE id = $${params.length}`, ...params);
|
|
544
544
|
}
|
|
545
545
|
if (data.teamAssignments) {
|
|
@@ -553,220 +553,220 @@ let OperationsService = class OperationsService {
|
|
|
553
553
|
const params = [];
|
|
554
554
|
const accessClause = actor.isDirector
|
|
555
555
|
? 'c.deleted_at IS NULL'
|
|
556
|
-
: `c.deleted_at IS NULL AND (
|
|
557
|
-
c.related_collaborator_id = ANY(${this.param(params, actor.visibleCollaboratorIds)}::int[])
|
|
558
|
-
OR EXISTS (
|
|
559
|
-
SELECT 1
|
|
560
|
-
FROM operations_project p_access
|
|
561
|
-
WHERE p_access.contract_id = c.id
|
|
562
|
-
AND p_access.deleted_at IS NULL
|
|
563
|
-
AND p_access.id = ANY(${this.param(params, actor.visibleProjectIds)}::int[])
|
|
564
|
-
)
|
|
556
|
+
: `c.deleted_at IS NULL AND (
|
|
557
|
+
c.related_collaborator_id = ANY(${this.param(params, actor.visibleCollaboratorIds)}::int[])
|
|
558
|
+
OR EXISTS (
|
|
559
|
+
SELECT 1
|
|
560
|
+
FROM operations_project p_access
|
|
561
|
+
WHERE p_access.contract_id = c.id
|
|
562
|
+
AND p_access.deleted_at IS NULL
|
|
563
|
+
AND p_access.id = ANY(${this.param(params, actor.visibleProjectIds)}::int[])
|
|
564
|
+
)
|
|
565
565
|
)`;
|
|
566
|
-
return this.queryRows(`SELECT c.id,
|
|
567
|
-
c.code,
|
|
568
|
-
c.name,
|
|
569
|
-
c.contract_category AS "contractCategory",
|
|
570
|
-
c.contract_type AS "contractType",
|
|
571
|
-
c.client_name AS "clientName",
|
|
572
|
-
c.signature_status AS "signatureStatus",
|
|
573
|
-
c.is_active AS "isActive",
|
|
574
|
-
c.billing_model AS "billingModel",
|
|
575
|
-
c.account_manager_collaborator_id AS "accountManagerCollaboratorId",
|
|
576
|
-
c.related_collaborator_id AS "relatedCollaboratorId",
|
|
577
|
-
c.origin_type AS "originType",
|
|
578
|
-
c.origin_id AS "originId",
|
|
579
|
-
c.start_date AS "startDate",
|
|
580
|
-
c.end_date AS "endDate",
|
|
581
|
-
c.signed_at AS "signedAt",
|
|
582
|
-
c.effective_date AS "effectiveDate",
|
|
583
|
-
c.budget_amount AS "budgetAmount",
|
|
584
|
-
c.monthly_hour_cap AS "monthlyHourCap",
|
|
585
|
-
c.status,
|
|
586
|
-
c.description,
|
|
587
|
-
m.display_name AS "accountManagerName",
|
|
588
|
-
linked.display_name AS "relatedCollaboratorName",
|
|
589
|
-
COALESCE(primary_party.display_name, linked.display_name, c.client_name) AS "mainRelatedPartyName",
|
|
590
|
-
COALESCE(financials.value_amount, 0) AS "valueAmount",
|
|
591
|
-
COALESCE(financials.payment_amount, 0) AS "paymentAmount",
|
|
592
|
-
COALESCE(financials.revenue_amount, 0) AS "revenueAmount",
|
|
593
|
-
COALESCE(financials.fine_amount, 0) AS "fineAmount",
|
|
594
|
-
COALESCE(pdf_document.file_name, '') AS "currentPdfFileName",
|
|
595
|
-
COUNT(DISTINCT p.id)::int AS "projectCount"
|
|
596
|
-
FROM operations_contract c
|
|
597
|
-
LEFT JOIN operations_collaborator m ON m.id = c.account_manager_collaborator_id
|
|
598
|
-
LEFT JOIN operations_collaborator linked ON linked.id = c.related_collaborator_id
|
|
599
|
-
LEFT JOIN LATERAL (
|
|
600
|
-
SELECT cp.display_name
|
|
601
|
-
FROM operations_contract_party cp
|
|
602
|
-
WHERE cp.contract_id = c.id
|
|
603
|
-
AND cp.deleted_at IS NULL
|
|
604
|
-
ORDER BY cp.is_primary DESC, cp.id ASC
|
|
605
|
-
LIMIT 1
|
|
606
|
-
) primary_party ON TRUE
|
|
607
|
-
LEFT JOIN LATERAL (
|
|
608
|
-
SELECT
|
|
609
|
-
SUM(CASE WHEN term_type = 'value' THEN amount ELSE 0 END) AS value_amount,
|
|
610
|
-
SUM(CASE WHEN term_type = 'payment' THEN amount ELSE 0 END) AS payment_amount,
|
|
611
|
-
SUM(CASE WHEN term_type = 'revenue' THEN amount ELSE 0 END) AS revenue_amount,
|
|
612
|
-
SUM(CASE WHEN term_type = 'fine' THEN amount ELSE 0 END) AS fine_amount
|
|
613
|
-
FROM operations_contract_financial_term ft
|
|
614
|
-
WHERE ft.contract_id = c.id
|
|
615
|
-
AND ft.deleted_at IS NULL
|
|
616
|
-
) financials ON TRUE
|
|
617
|
-
LEFT JOIN LATERAL (
|
|
618
|
-
SELECT cd.file_name
|
|
619
|
-
FROM operations_contract_document cd
|
|
620
|
-
WHERE cd.contract_id = c.id
|
|
621
|
-
AND cd.deleted_at IS NULL
|
|
622
|
-
AND cd.is_current = true
|
|
623
|
-
AND cd.document_type IN ('uploaded_pdf', 'generated_pdf')
|
|
624
|
-
ORDER BY cd.id DESC
|
|
625
|
-
LIMIT 1
|
|
626
|
-
) pdf_document ON TRUE
|
|
627
|
-
LEFT JOIN operations_project p
|
|
628
|
-
ON p.contract_id = c.id
|
|
629
|
-
AND p.deleted_at IS NULL
|
|
630
|
-
WHERE ${accessClause}
|
|
631
|
-
GROUP BY c.id, m.id, linked.id
|
|
566
|
+
return this.queryRows(`SELECT c.id,
|
|
567
|
+
c.code,
|
|
568
|
+
c.name,
|
|
569
|
+
c.contract_category AS "contractCategory",
|
|
570
|
+
c.contract_type AS "contractType",
|
|
571
|
+
c.client_name AS "clientName",
|
|
572
|
+
c.signature_status AS "signatureStatus",
|
|
573
|
+
c.is_active AS "isActive",
|
|
574
|
+
c.billing_model AS "billingModel",
|
|
575
|
+
c.account_manager_collaborator_id AS "accountManagerCollaboratorId",
|
|
576
|
+
c.related_collaborator_id AS "relatedCollaboratorId",
|
|
577
|
+
c.origin_type AS "originType",
|
|
578
|
+
c.origin_id AS "originId",
|
|
579
|
+
c.start_date AS "startDate",
|
|
580
|
+
c.end_date AS "endDate",
|
|
581
|
+
c.signed_at AS "signedAt",
|
|
582
|
+
c.effective_date AS "effectiveDate",
|
|
583
|
+
c.budget_amount AS "budgetAmount",
|
|
584
|
+
c.monthly_hour_cap AS "monthlyHourCap",
|
|
585
|
+
c.status,
|
|
586
|
+
c.description,
|
|
587
|
+
m.display_name AS "accountManagerName",
|
|
588
|
+
linked.display_name AS "relatedCollaboratorName",
|
|
589
|
+
COALESCE(primary_party.display_name, linked.display_name, c.client_name) AS "mainRelatedPartyName",
|
|
590
|
+
COALESCE(financials.value_amount, 0) AS "valueAmount",
|
|
591
|
+
COALESCE(financials.payment_amount, 0) AS "paymentAmount",
|
|
592
|
+
COALESCE(financials.revenue_amount, 0) AS "revenueAmount",
|
|
593
|
+
COALESCE(financials.fine_amount, 0) AS "fineAmount",
|
|
594
|
+
COALESCE(pdf_document.file_name, '') AS "currentPdfFileName",
|
|
595
|
+
COUNT(DISTINCT p.id)::int AS "projectCount"
|
|
596
|
+
FROM operations_contract c
|
|
597
|
+
LEFT JOIN operations_collaborator m ON m.id = c.account_manager_collaborator_id
|
|
598
|
+
LEFT JOIN operations_collaborator linked ON linked.id = c.related_collaborator_id
|
|
599
|
+
LEFT JOIN LATERAL (
|
|
600
|
+
SELECT cp.display_name
|
|
601
|
+
FROM operations_contract_party cp
|
|
602
|
+
WHERE cp.contract_id = c.id
|
|
603
|
+
AND cp.deleted_at IS NULL
|
|
604
|
+
ORDER BY cp.is_primary DESC, cp.id ASC
|
|
605
|
+
LIMIT 1
|
|
606
|
+
) primary_party ON TRUE
|
|
607
|
+
LEFT JOIN LATERAL (
|
|
608
|
+
SELECT
|
|
609
|
+
SUM(CASE WHEN term_type = 'value' THEN amount ELSE 0 END) AS value_amount,
|
|
610
|
+
SUM(CASE WHEN term_type = 'payment' THEN amount ELSE 0 END) AS payment_amount,
|
|
611
|
+
SUM(CASE WHEN term_type = 'revenue' THEN amount ELSE 0 END) AS revenue_amount,
|
|
612
|
+
SUM(CASE WHEN term_type = 'fine' THEN amount ELSE 0 END) AS fine_amount
|
|
613
|
+
FROM operations_contract_financial_term ft
|
|
614
|
+
WHERE ft.contract_id = c.id
|
|
615
|
+
AND ft.deleted_at IS NULL
|
|
616
|
+
) financials ON TRUE
|
|
617
|
+
LEFT JOIN LATERAL (
|
|
618
|
+
SELECT cd.file_name
|
|
619
|
+
FROM operations_contract_document cd
|
|
620
|
+
WHERE cd.contract_id = c.id
|
|
621
|
+
AND cd.deleted_at IS NULL
|
|
622
|
+
AND cd.is_current = true
|
|
623
|
+
AND cd.document_type IN ('uploaded_pdf', 'generated_pdf')
|
|
624
|
+
ORDER BY cd.id DESC
|
|
625
|
+
LIMIT 1
|
|
626
|
+
) pdf_document ON TRUE
|
|
627
|
+
LEFT JOIN operations_project p
|
|
628
|
+
ON p.contract_id = c.id
|
|
629
|
+
AND p.deleted_at IS NULL
|
|
630
|
+
WHERE ${accessClause}
|
|
631
|
+
GROUP BY c.id, m.id, linked.id
|
|
632
632
|
ORDER BY c.name ASC`, params);
|
|
633
633
|
}
|
|
634
634
|
async getContractById(userId, contractId) {
|
|
635
635
|
var _a, _b, _c;
|
|
636
636
|
const actor = await this.getActorContext(userId);
|
|
637
|
-
const contract = await this.querySingle(`SELECT c.id,
|
|
638
|
-
c.code,
|
|
639
|
-
c.name,
|
|
640
|
-
c.contract_category AS "contractCategory",
|
|
641
|
-
c.contract_type AS "contractType",
|
|
642
|
-
c.client_name AS "clientName",
|
|
643
|
-
c.signature_status AS "signatureStatus",
|
|
644
|
-
c.is_active AS "isActive",
|
|
645
|
-
c.billing_model AS "billingModel",
|
|
646
|
-
c.account_manager_collaborator_id AS "accountManagerCollaboratorId",
|
|
647
|
-
c.related_collaborator_id AS "relatedCollaboratorId",
|
|
648
|
-
c.origin_type AS "originType",
|
|
649
|
-
c.origin_id AS "originId",
|
|
650
|
-
c.start_date AS "startDate",
|
|
651
|
-
c.end_date AS "endDate",
|
|
652
|
-
c.signed_at AS "signedAt",
|
|
653
|
-
c.effective_date AS "effectiveDate",
|
|
654
|
-
c.budget_amount AS "budgetAmount",
|
|
655
|
-
c.monthly_hour_cap AS "monthlyHourCap",
|
|
656
|
-
c.status,
|
|
657
|
-
c.description,
|
|
658
|
-
c.content_html AS "contentHtml",
|
|
659
|
-
m.display_name AS "accountManagerName",
|
|
660
|
-
linked.display_name AS "relatedCollaboratorName"
|
|
661
|
-
FROM operations_contract c
|
|
662
|
-
LEFT JOIN operations_collaborator m ON m.id = c.account_manager_collaborator_id
|
|
663
|
-
LEFT JOIN operations_collaborator linked ON linked.id = c.related_collaborator_id
|
|
664
|
-
WHERE c.id = $1
|
|
637
|
+
const contract = await this.querySingle(`SELECT c.id,
|
|
638
|
+
c.code,
|
|
639
|
+
c.name,
|
|
640
|
+
c.contract_category AS "contractCategory",
|
|
641
|
+
c.contract_type AS "contractType",
|
|
642
|
+
c.client_name AS "clientName",
|
|
643
|
+
c.signature_status AS "signatureStatus",
|
|
644
|
+
c.is_active AS "isActive",
|
|
645
|
+
c.billing_model AS "billingModel",
|
|
646
|
+
c.account_manager_collaborator_id AS "accountManagerCollaboratorId",
|
|
647
|
+
c.related_collaborator_id AS "relatedCollaboratorId",
|
|
648
|
+
c.origin_type AS "originType",
|
|
649
|
+
c.origin_id AS "originId",
|
|
650
|
+
c.start_date AS "startDate",
|
|
651
|
+
c.end_date AS "endDate",
|
|
652
|
+
c.signed_at AS "signedAt",
|
|
653
|
+
c.effective_date AS "effectiveDate",
|
|
654
|
+
c.budget_amount AS "budgetAmount",
|
|
655
|
+
c.monthly_hour_cap AS "monthlyHourCap",
|
|
656
|
+
c.status,
|
|
657
|
+
c.description,
|
|
658
|
+
c.content_html AS "contentHtml",
|
|
659
|
+
m.display_name AS "accountManagerName",
|
|
660
|
+
linked.display_name AS "relatedCollaboratorName"
|
|
661
|
+
FROM operations_contract c
|
|
662
|
+
LEFT JOIN operations_collaborator m ON m.id = c.account_manager_collaborator_id
|
|
663
|
+
LEFT JOIN operations_collaborator linked ON linked.id = c.related_collaborator_id
|
|
664
|
+
WHERE c.id = $1
|
|
665
665
|
AND c.deleted_at IS NULL`, [contractId]);
|
|
666
666
|
if (!contract) {
|
|
667
667
|
throw new common_1.NotFoundException('Contract not found.');
|
|
668
668
|
}
|
|
669
669
|
if (!actor.isDirector) {
|
|
670
|
-
const access = await this.querySingle(`SELECT EXISTS (
|
|
671
|
-
SELECT 1
|
|
672
|
-
FROM operations_contract c
|
|
673
|
-
WHERE c.id = $1
|
|
674
|
-
AND c.deleted_at IS NULL
|
|
675
|
-
AND (
|
|
676
|
-
c.related_collaborator_id = ANY($2::int[])
|
|
677
|
-
OR EXISTS (
|
|
678
|
-
SELECT 1
|
|
679
|
-
FROM operations_project p
|
|
680
|
-
WHERE p.contract_id = c.id
|
|
681
|
-
AND p.deleted_at IS NULL
|
|
682
|
-
AND p.id = ANY($3::int[])
|
|
683
|
-
)
|
|
684
|
-
)
|
|
670
|
+
const access = await this.querySingle(`SELECT EXISTS (
|
|
671
|
+
SELECT 1
|
|
672
|
+
FROM operations_contract c
|
|
673
|
+
WHERE c.id = $1
|
|
674
|
+
AND c.deleted_at IS NULL
|
|
675
|
+
AND (
|
|
676
|
+
c.related_collaborator_id = ANY($2::int[])
|
|
677
|
+
OR EXISTS (
|
|
678
|
+
SELECT 1
|
|
679
|
+
FROM operations_project p
|
|
680
|
+
WHERE p.contract_id = c.id
|
|
681
|
+
AND p.deleted_at IS NULL
|
|
682
|
+
AND p.id = ANY($3::int[])
|
|
683
|
+
)
|
|
684
|
+
)
|
|
685
685
|
) AS exists`, [contractId, actor.visibleCollaboratorIds, actor.visibleProjectIds]);
|
|
686
686
|
if (!(access === null || access === void 0 ? void 0 : access.exists)) {
|
|
687
687
|
throw new common_1.ForbiddenException('You do not have access to this contract.');
|
|
688
688
|
}
|
|
689
689
|
}
|
|
690
690
|
const [projects, scheduleSummary, parties, signatures, financialTerms, documents, revisions, history] = await Promise.all([
|
|
691
|
-
this.queryRows(`SELECT id, code, name, status
|
|
692
|
-
FROM operations_project
|
|
693
|
-
WHERE contract_id = $1
|
|
694
|
-
AND deleted_at IS NULL
|
|
691
|
+
this.queryRows(`SELECT id, code, name, status
|
|
692
|
+
FROM operations_project
|
|
693
|
+
WHERE contract_id = $1
|
|
694
|
+
AND deleted_at IS NULL
|
|
695
695
|
ORDER BY name ASC`, [contractId]),
|
|
696
696
|
contract.relatedCollaboratorId
|
|
697
|
-
? this.queryRows(`SELECT weekday,
|
|
698
|
-
is_working_day AS "isWorkingDay",
|
|
699
|
-
start_time AS "startTime",
|
|
700
|
-
end_time AS "endTime",
|
|
701
|
-
break_minutes AS "breakMinutes"
|
|
702
|
-
FROM operations_collaborator_schedule_day
|
|
703
|
-
WHERE collaborator_id = $1
|
|
704
|
-
AND deleted_at IS NULL
|
|
697
|
+
? this.queryRows(`SELECT weekday,
|
|
698
|
+
is_working_day AS "isWorkingDay",
|
|
699
|
+
start_time AS "startTime",
|
|
700
|
+
end_time AS "endTime",
|
|
701
|
+
break_minutes AS "breakMinutes"
|
|
702
|
+
FROM operations_collaborator_schedule_day
|
|
703
|
+
WHERE collaborator_id = $1
|
|
704
|
+
AND deleted_at IS NULL
|
|
705
705
|
ORDER BY id ASC`, [contract.relatedCollaboratorId])
|
|
706
706
|
: Promise.resolve([]),
|
|
707
|
-
this.queryRows(`SELECT id,
|
|
708
|
-
party_role AS "partyRole",
|
|
709
|
-
party_type AS "partyType",
|
|
710
|
-
display_name AS "displayName",
|
|
711
|
-
document_number AS "documentNumber",
|
|
712
|
-
email,
|
|
713
|
-
phone,
|
|
714
|
-
is_primary AS "isPrimary"
|
|
715
|
-
FROM operations_contract_party
|
|
716
|
-
WHERE contract_id = $1
|
|
717
|
-
AND deleted_at IS NULL
|
|
707
|
+
this.queryRows(`SELECT id,
|
|
708
|
+
party_role AS "partyRole",
|
|
709
|
+
party_type AS "partyType",
|
|
710
|
+
display_name AS "displayName",
|
|
711
|
+
document_number AS "documentNumber",
|
|
712
|
+
email,
|
|
713
|
+
phone,
|
|
714
|
+
is_primary AS "isPrimary"
|
|
715
|
+
FROM operations_contract_party
|
|
716
|
+
WHERE contract_id = $1
|
|
717
|
+
AND deleted_at IS NULL
|
|
718
718
|
ORDER BY is_primary DESC, id ASC`, [contractId]),
|
|
719
|
-
this.queryRows(`SELECT id,
|
|
720
|
-
signer_name AS "signerName",
|
|
721
|
-
signer_role AS "signerRole",
|
|
722
|
-
signer_email AS "signerEmail",
|
|
723
|
-
signer_status AS status,
|
|
724
|
-
signed_at AS "signedAt"
|
|
725
|
-
FROM operations_contract_signature
|
|
726
|
-
WHERE contract_id = $1
|
|
727
|
-
AND deleted_at IS NULL
|
|
719
|
+
this.queryRows(`SELECT id,
|
|
720
|
+
signer_name AS "signerName",
|
|
721
|
+
signer_role AS "signerRole",
|
|
722
|
+
signer_email AS "signerEmail",
|
|
723
|
+
signer_status AS status,
|
|
724
|
+
signed_at AS "signedAt"
|
|
725
|
+
FROM operations_contract_signature
|
|
726
|
+
WHERE contract_id = $1
|
|
727
|
+
AND deleted_at IS NULL
|
|
728
728
|
ORDER BY id ASC`, [contractId]),
|
|
729
|
-
this.queryRows(`SELECT id,
|
|
730
|
-
term_type AS "termType",
|
|
731
|
-
label,
|
|
732
|
-
amount,
|
|
733
|
-
recurrence,
|
|
734
|
-
due_day AS "dueDay",
|
|
735
|
-
notes
|
|
736
|
-
FROM operations_contract_financial_term
|
|
737
|
-
WHERE contract_id = $1
|
|
738
|
-
AND deleted_at IS NULL
|
|
729
|
+
this.queryRows(`SELECT id,
|
|
730
|
+
term_type AS "termType",
|
|
731
|
+
label,
|
|
732
|
+
amount,
|
|
733
|
+
recurrence,
|
|
734
|
+
due_day AS "dueDay",
|
|
735
|
+
notes
|
|
736
|
+
FROM operations_contract_financial_term
|
|
737
|
+
WHERE contract_id = $1
|
|
738
|
+
AND deleted_at IS NULL
|
|
739
739
|
ORDER BY id ASC`, [contractId]),
|
|
740
|
-
this.queryRows(`SELECT id,
|
|
741
|
-
document_type AS "documentType",
|
|
742
|
-
file_name AS "fileName",
|
|
743
|
-
mime_type AS "mimeType",
|
|
744
|
-
file_content_base64 AS "fileContentBase64",
|
|
745
|
-
is_current AS "isCurrent",
|
|
746
|
-
notes,
|
|
747
|
-
created_at AS "createdAt"
|
|
748
|
-
FROM operations_contract_document
|
|
749
|
-
WHERE contract_id = $1
|
|
750
|
-
AND deleted_at IS NULL
|
|
740
|
+
this.queryRows(`SELECT id,
|
|
741
|
+
document_type AS "documentType",
|
|
742
|
+
file_name AS "fileName",
|
|
743
|
+
mime_type AS "mimeType",
|
|
744
|
+
file_content_base64 AS "fileContentBase64",
|
|
745
|
+
is_current AS "isCurrent",
|
|
746
|
+
notes,
|
|
747
|
+
created_at AS "createdAt"
|
|
748
|
+
FROM operations_contract_document
|
|
749
|
+
WHERE contract_id = $1
|
|
750
|
+
AND deleted_at IS NULL
|
|
751
751
|
ORDER BY is_current DESC, id DESC`, [contractId]),
|
|
752
|
-
this.queryRows(`SELECT id,
|
|
753
|
-
revision_type AS "revisionType",
|
|
754
|
-
title,
|
|
755
|
-
effective_date AS "effectiveDate",
|
|
756
|
-
status,
|
|
757
|
-
summary
|
|
758
|
-
FROM operations_contract_revision
|
|
759
|
-
WHERE contract_id = $1
|
|
760
|
-
AND deleted_at IS NULL
|
|
752
|
+
this.queryRows(`SELECT id,
|
|
753
|
+
revision_type AS "revisionType",
|
|
754
|
+
title,
|
|
755
|
+
effective_date AS "effectiveDate",
|
|
756
|
+
status,
|
|
757
|
+
summary
|
|
758
|
+
FROM operations_contract_revision
|
|
759
|
+
WHERE contract_id = $1
|
|
760
|
+
AND deleted_at IS NULL
|
|
761
761
|
ORDER BY effective_date DESC NULLS LAST, id DESC`, [contractId]),
|
|
762
|
-
this.queryRows(`SELECT id,
|
|
763
|
-
actor_user_id AS "actorUserId",
|
|
764
|
-
action,
|
|
765
|
-
note,
|
|
766
|
-
metadata_json AS "metadataJson",
|
|
767
|
-
created_at AS "createdAt"
|
|
768
|
-
FROM operations_contract_history
|
|
769
|
-
WHERE contract_id = $1
|
|
762
|
+
this.queryRows(`SELECT id,
|
|
763
|
+
actor_user_id AS "actorUserId",
|
|
764
|
+
action,
|
|
765
|
+
note,
|
|
766
|
+
metadata_json AS "metadataJson",
|
|
767
|
+
created_at AS "createdAt"
|
|
768
|
+
FROM operations_contract_history
|
|
769
|
+
WHERE contract_id = $1
|
|
770
770
|
ORDER BY id DESC`, [contractId]),
|
|
771
771
|
]);
|
|
772
772
|
return Object.assign(Object.assign({}, contract), { mainRelatedPartyName: (_c = (_b = (_a = parties.find((party) => party.isPrimary)) === null || _a === void 0 ? void 0 : _a.displayName) !== null && _b !== void 0 ? _b : contract.relatedCollaboratorName) !== null && _c !== void 0 ? _c : contract.clientName, projects,
|
|
@@ -784,35 +784,35 @@ let OperationsService = class OperationsService {
|
|
|
784
784
|
this.requireFields(data, ['code', 'name', 'clientName', 'startDate']);
|
|
785
785
|
const createdId = await this.prisma.$transaction(async (tx) => {
|
|
786
786
|
var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o, _p, _q, _r, _s, _t;
|
|
787
|
-
const created = await tx.$queryRawUnsafe(`INSERT INTO operations_contract (
|
|
788
|
-
code,
|
|
789
|
-
name,
|
|
790
|
-
contract_category,
|
|
791
|
-
contract_type,
|
|
792
|
-
client_name,
|
|
793
|
-
signature_status,
|
|
794
|
-
is_active,
|
|
795
|
-
billing_model,
|
|
796
|
-
account_manager_collaborator_id,
|
|
797
|
-
related_collaborator_id,
|
|
798
|
-
origin_type,
|
|
799
|
-
origin_id,
|
|
800
|
-
start_date,
|
|
801
|
-
end_date,
|
|
802
|
-
signed_at,
|
|
803
|
-
effective_date,
|
|
804
|
-
budget_amount,
|
|
805
|
-
monthly_hour_cap,
|
|
806
|
-
status,
|
|
807
|
-
description,
|
|
808
|
-
content_html,
|
|
809
|
-
created_at,
|
|
810
|
-
updated_at
|
|
811
|
-
) VALUES (
|
|
812
|
-
$1, $2, COALESCE($3, 'client'), COALESCE($4, 'service_agreement'), $5, COALESCE($6, 'not_started'),
|
|
813
|
-
COALESCE($7, true), COALESCE($8, 'time_and_material'), $9, $10, COALESCE($11, 'manual'), $12, $13,
|
|
814
|
-
$14, $15, $16, $17, $18, COALESCE($19, 'draft'), $20, $21, NOW(), NOW()
|
|
815
|
-
)
|
|
787
|
+
const created = await tx.$queryRawUnsafe(`INSERT INTO operations_contract (
|
|
788
|
+
code,
|
|
789
|
+
name,
|
|
790
|
+
contract_category,
|
|
791
|
+
contract_type,
|
|
792
|
+
client_name,
|
|
793
|
+
signature_status,
|
|
794
|
+
is_active,
|
|
795
|
+
billing_model,
|
|
796
|
+
account_manager_collaborator_id,
|
|
797
|
+
related_collaborator_id,
|
|
798
|
+
origin_type,
|
|
799
|
+
origin_id,
|
|
800
|
+
start_date,
|
|
801
|
+
end_date,
|
|
802
|
+
signed_at,
|
|
803
|
+
effective_date,
|
|
804
|
+
budget_amount,
|
|
805
|
+
monthly_hour_cap,
|
|
806
|
+
status,
|
|
807
|
+
description,
|
|
808
|
+
content_html,
|
|
809
|
+
created_at,
|
|
810
|
+
updated_at
|
|
811
|
+
) VALUES (
|
|
812
|
+
$1, $2, COALESCE($3, 'client'), COALESCE($4, 'service_agreement'), $5, COALESCE($6, 'not_started'),
|
|
813
|
+
COALESCE($7, true), COALESCE($8, 'time_and_material'), $9, $10, COALESCE($11, 'manual'), $12, $13,
|
|
814
|
+
$14, $15, $16, $17, $18, COALESCE($19, 'draft'), $20, $21, NOW(), NOW()
|
|
815
|
+
)
|
|
816
816
|
RETURNING id`, data.code, data.name, (_a = data.contractCategory) !== null && _a !== void 0 ? _a : 'client', (_b = data.contractType) !== null && _b !== void 0 ? _b : 'service_agreement', data.clientName, (_c = data.signatureStatus) !== null && _c !== void 0 ? _c : 'not_started', (_d = data.isActive) !== null && _d !== void 0 ? _d : true, (_e = data.billingModel) !== null && _e !== void 0 ? _e : 'time_and_material', (_f = data.accountManagerCollaboratorId) !== null && _f !== void 0 ? _f : null, (_g = data.relatedCollaboratorId) !== null && _g !== void 0 ? _g : null, (_h = data.originType) !== null && _h !== void 0 ? _h : 'manual', (_j = data.originId) !== null && _j !== void 0 ? _j : null, data.startDate, (_k = data.endDate) !== null && _k !== void 0 ? _k : null, (_l = data.signedAt) !== null && _l !== void 0 ? _l : null, (_m = data.effectiveDate) !== null && _m !== void 0 ? _m : data.startDate, (_o = data.budgetAmount) !== null && _o !== void 0 ? _o : null, (_p = data.monthlyHourCap) !== null && _p !== void 0 ? _p : null, (_q = data.status) !== null && _q !== void 0 ? _q : 'draft', (_r = data.description) !== null && _r !== void 0 ? _r : null, (_s = data.contentHtml) !== null && _s !== void 0 ? _s : null);
|
|
817
817
|
const contractId = (_t = created[0]) === null || _t === void 0 ? void 0 : _t.id;
|
|
818
818
|
await this.replaceContractParties(tx, contractId, data.parties);
|
|
@@ -859,9 +859,9 @@ let OperationsService = class OperationsService {
|
|
|
859
859
|
await this.prisma.$transaction(async (tx) => {
|
|
860
860
|
if (updates.length) {
|
|
861
861
|
params.push(contractId);
|
|
862
|
-
await tx.$executeRawUnsafe(`UPDATE operations_contract
|
|
863
|
-
SET ${updates.join(', ')},
|
|
864
|
-
updated_at = NOW()
|
|
862
|
+
await tx.$executeRawUnsafe(`UPDATE operations_contract
|
|
863
|
+
SET ${updates.join(', ')},
|
|
864
|
+
updated_at = NOW()
|
|
865
865
|
WHERE id = $${params.length}`, ...params);
|
|
866
866
|
}
|
|
867
867
|
if (data.parties) {
|
|
@@ -886,46 +886,46 @@ let OperationsService = class OperationsService {
|
|
|
886
886
|
async listTimesheets(userId) {
|
|
887
887
|
const actor = await this.getActorContext(userId);
|
|
888
888
|
const filter = this.buildIdFilter(actor.visibleCollaboratorIds, 't.collaborator_id', actor.isDirector);
|
|
889
|
-
const headers = await this.queryRows(`SELECT t.id,
|
|
890
|
-
t.collaborator_id AS "collaboratorId",
|
|
891
|
-
c.display_name AS "collaboratorName",
|
|
892
|
-
t.approver_collaborator_id AS "approverCollaboratorId",
|
|
893
|
-
a.display_name AS "approverName",
|
|
894
|
-
t.week_start_date AS "weekStartDate",
|
|
895
|
-
t.week_end_date AS "weekEndDate",
|
|
896
|
-
t.total_hours AS "totalHours",
|
|
897
|
-
t.status,
|
|
898
|
-
t.submitted_at AS "submittedAt",
|
|
899
|
-
t.reviewed_at AS "reviewedAt",
|
|
900
|
-
t.notes,
|
|
901
|
-
approval.decision_note AS "decisionNote"
|
|
902
|
-
FROM operations_timesheet t
|
|
903
|
-
JOIN operations_collaborator c ON c.id = t.collaborator_id
|
|
904
|
-
LEFT JOIN operations_collaborator a ON a.id = t.approver_collaborator_id
|
|
905
|
-
LEFT JOIN operations_approval approval
|
|
906
|
-
ON approval.target_type = 'timesheet'
|
|
907
|
-
AND approval.target_id = t.id
|
|
908
|
-
AND approval.deleted_at IS NULL
|
|
909
|
-
WHERE t.deleted_at IS NULL AND ${filter.clause}
|
|
889
|
+
const headers = await this.queryRows(`SELECT t.id,
|
|
890
|
+
t.collaborator_id AS "collaboratorId",
|
|
891
|
+
c.display_name AS "collaboratorName",
|
|
892
|
+
t.approver_collaborator_id AS "approverCollaboratorId",
|
|
893
|
+
a.display_name AS "approverName",
|
|
894
|
+
t.week_start_date AS "weekStartDate",
|
|
895
|
+
t.week_end_date AS "weekEndDate",
|
|
896
|
+
t.total_hours AS "totalHours",
|
|
897
|
+
t.status,
|
|
898
|
+
t.submitted_at AS "submittedAt",
|
|
899
|
+
t.reviewed_at AS "reviewedAt",
|
|
900
|
+
t.notes,
|
|
901
|
+
approval.decision_note AS "decisionNote"
|
|
902
|
+
FROM operations_timesheet t
|
|
903
|
+
JOIN operations_collaborator c ON c.id = t.collaborator_id
|
|
904
|
+
LEFT JOIN operations_collaborator a ON a.id = t.approver_collaborator_id
|
|
905
|
+
LEFT JOIN operations_approval approval
|
|
906
|
+
ON approval.target_type = 'timesheet'
|
|
907
|
+
AND approval.target_id = t.id
|
|
908
|
+
AND approval.deleted_at IS NULL
|
|
909
|
+
WHERE t.deleted_at IS NULL AND ${filter.clause}
|
|
910
910
|
ORDER BY t.week_start_date DESC, t.id DESC`, filter.params);
|
|
911
911
|
if (!headers.length) {
|
|
912
912
|
return headers;
|
|
913
913
|
}
|
|
914
|
-
const entries = await this.queryRows(`SELECT e.id,
|
|
915
|
-
e.timesheet_id AS "timesheetId",
|
|
916
|
-
e.project_assignment_id AS "projectAssignmentId",
|
|
917
|
-
pa.project_id AS "projectId",
|
|
918
|
-
p.name AS "projectName",
|
|
919
|
-
pa.role_label AS "roleLabel",
|
|
920
|
-
e.activity_label AS "activityLabel",
|
|
921
|
-
e.work_date AS "workDate",
|
|
922
|
-
e.hours,
|
|
923
|
-
e.description
|
|
924
|
-
FROM operations_timesheet_entry e
|
|
925
|
-
LEFT JOIN operations_project_assignment pa ON pa.id = e.project_assignment_id
|
|
926
|
-
LEFT JOIN operations_project p ON p.id = pa.project_id
|
|
927
|
-
WHERE e.deleted_at IS NULL
|
|
928
|
-
AND e.timesheet_id = ANY($1::int[])
|
|
914
|
+
const entries = await this.queryRows(`SELECT e.id,
|
|
915
|
+
e.timesheet_id AS "timesheetId",
|
|
916
|
+
e.project_assignment_id AS "projectAssignmentId",
|
|
917
|
+
pa.project_id AS "projectId",
|
|
918
|
+
p.name AS "projectName",
|
|
919
|
+
pa.role_label AS "roleLabel",
|
|
920
|
+
e.activity_label AS "activityLabel",
|
|
921
|
+
e.work_date AS "workDate",
|
|
922
|
+
e.hours,
|
|
923
|
+
e.description
|
|
924
|
+
FROM operations_timesheet_entry e
|
|
925
|
+
LEFT JOIN operations_project_assignment pa ON pa.id = e.project_assignment_id
|
|
926
|
+
LEFT JOIN operations_project p ON p.id = pa.project_id
|
|
927
|
+
WHERE e.deleted_at IS NULL
|
|
928
|
+
AND e.timesheet_id = ANY($1::int[])
|
|
929
929
|
ORDER BY e.work_date ASC, e.id ASC`, [headers.map((item) => item.id)]);
|
|
930
930
|
const grouped = this.groupBy(entries, 'timesheetId');
|
|
931
931
|
return headers.map((timesheet) => {
|
|
@@ -949,16 +949,16 @@ let OperationsService = class OperationsService {
|
|
|
949
949
|
const collaborator = await this.getCollaboratorById(collaboratorId);
|
|
950
950
|
const created = await this.prisma.$transaction(async (tx) => {
|
|
951
951
|
var _a, _b, _c, _d;
|
|
952
|
-
const row = (await tx.$queryRawUnsafe(`INSERT INTO operations_timesheet (
|
|
953
|
-
collaborator_id,
|
|
954
|
-
approver_collaborator_id,
|
|
955
|
-
week_start_date,
|
|
956
|
-
week_end_date,
|
|
957
|
-
notes,
|
|
958
|
-
status,
|
|
959
|
-
created_at,
|
|
960
|
-
updated_at
|
|
961
|
-
) VALUES ($1, $2, $3, $4, $5, 'draft', NOW(), NOW())
|
|
952
|
+
const row = (await tx.$queryRawUnsafe(`INSERT INTO operations_timesheet (
|
|
953
|
+
collaborator_id,
|
|
954
|
+
approver_collaborator_id,
|
|
955
|
+
week_start_date,
|
|
956
|
+
week_end_date,
|
|
957
|
+
notes,
|
|
958
|
+
status,
|
|
959
|
+
created_at,
|
|
960
|
+
updated_at
|
|
961
|
+
) VALUES ($1, $2, $3, $4, $5, 'draft', NOW(), NOW())
|
|
962
962
|
RETURNING id`, collaboratorId, (_a = collaborator.supervisorId) !== null && _a !== void 0 ? _a : null, data.weekStartDate, data.weekEndDate, (_b = data.notes) !== null && _b !== void 0 ? _b : null));
|
|
963
963
|
const timesheetId = (_c = row[0]) === null || _c === void 0 ? void 0 : _c.id;
|
|
964
964
|
await this.replaceTimesheetEntries(tx, timesheetId, (_d = data.entries) !== null && _d !== void 0 ? _d : [], collaboratorId);
|
|
@@ -984,9 +984,9 @@ let OperationsService = class OperationsService {
|
|
|
984
984
|
this.pushUpdate(updates, params, 'notes', data.notes);
|
|
985
985
|
if (updates.length) {
|
|
986
986
|
params.push(timesheetId);
|
|
987
|
-
await tx.$executeRawUnsafe(`UPDATE operations_timesheet
|
|
988
|
-
SET ${updates.join(', ')},
|
|
989
|
-
updated_at = NOW()
|
|
987
|
+
await tx.$executeRawUnsafe(`UPDATE operations_timesheet
|
|
988
|
+
SET ${updates.join(', ')},
|
|
989
|
+
updated_at = NOW()
|
|
990
990
|
WHERE id = $${params.length}`, ...params);
|
|
991
991
|
}
|
|
992
992
|
if (data.entries) {
|
|
@@ -1009,11 +1009,11 @@ let OperationsService = class OperationsService {
|
|
|
1009
1009
|
const collaborator = await this.getCollaboratorById(current.collaboratorId);
|
|
1010
1010
|
const approverId = (_b = (_a = current.approverCollaboratorId) !== null && _a !== void 0 ? _a : collaborator.supervisorId) !== null && _b !== void 0 ? _b : null;
|
|
1011
1011
|
await this.prisma.$transaction(async (tx) => {
|
|
1012
|
-
await tx.$executeRawUnsafe(`UPDATE operations_timesheet
|
|
1013
|
-
SET status = 'submitted',
|
|
1014
|
-
approver_collaborator_id = $1,
|
|
1015
|
-
submitted_at = NOW(),
|
|
1016
|
-
updated_at = NOW()
|
|
1012
|
+
await tx.$executeRawUnsafe(`UPDATE operations_timesheet
|
|
1013
|
+
SET status = 'submitted',
|
|
1014
|
+
approver_collaborator_id = $1,
|
|
1015
|
+
submitted_at = NOW(),
|
|
1016
|
+
updated_at = NOW()
|
|
1017
1017
|
WHERE id = $2`, approverId, timesheetId);
|
|
1018
1018
|
await this.upsertApproval(tx, {
|
|
1019
1019
|
targetType: 'timesheet',
|
|
@@ -1027,28 +1027,28 @@ let OperationsService = class OperationsService {
|
|
|
1027
1027
|
async listTimeOffRequests(userId) {
|
|
1028
1028
|
const actor = await this.getActorContext(userId);
|
|
1029
1029
|
const filter = this.buildIdFilter(actor.visibleCollaboratorIds, 'tor.collaborator_id', actor.isDirector);
|
|
1030
|
-
return this.queryRows(`SELECT tor.id,
|
|
1031
|
-
tor.collaborator_id AS "collaboratorId",
|
|
1032
|
-
c.display_name AS "collaboratorName",
|
|
1033
|
-
tor.approver_collaborator_id AS "approverCollaboratorId",
|
|
1034
|
-
a.display_name AS "approverName",
|
|
1035
|
-
tor.request_type AS "requestType",
|
|
1036
|
-
tor.start_date AS "startDate",
|
|
1037
|
-
tor.end_date AS "endDate",
|
|
1038
|
-
tor.total_days AS "totalDays",
|
|
1039
|
-
tor.status,
|
|
1040
|
-
tor.reason,
|
|
1041
|
-
tor.submitted_at AS "submittedAt",
|
|
1042
|
-
tor.reviewed_at AS "reviewedAt",
|
|
1043
|
-
approval.decision_note AS "approverNote"
|
|
1044
|
-
FROM operations_time_off_request tor
|
|
1045
|
-
JOIN operations_collaborator c ON c.id = tor.collaborator_id
|
|
1046
|
-
LEFT JOIN operations_collaborator a ON a.id = tor.approver_collaborator_id
|
|
1047
|
-
LEFT JOIN operations_approval approval
|
|
1048
|
-
ON approval.target_type = 'time_off_request'
|
|
1049
|
-
AND approval.target_id = tor.id
|
|
1050
|
-
AND approval.deleted_at IS NULL
|
|
1051
|
-
WHERE tor.deleted_at IS NULL AND ${filter.clause}
|
|
1030
|
+
return this.queryRows(`SELECT tor.id,
|
|
1031
|
+
tor.collaborator_id AS "collaboratorId",
|
|
1032
|
+
c.display_name AS "collaboratorName",
|
|
1033
|
+
tor.approver_collaborator_id AS "approverCollaboratorId",
|
|
1034
|
+
a.display_name AS "approverName",
|
|
1035
|
+
tor.request_type AS "requestType",
|
|
1036
|
+
tor.start_date AS "startDate",
|
|
1037
|
+
tor.end_date AS "endDate",
|
|
1038
|
+
tor.total_days AS "totalDays",
|
|
1039
|
+
tor.status,
|
|
1040
|
+
tor.reason,
|
|
1041
|
+
tor.submitted_at AS "submittedAt",
|
|
1042
|
+
tor.reviewed_at AS "reviewedAt",
|
|
1043
|
+
approval.decision_note AS "approverNote"
|
|
1044
|
+
FROM operations_time_off_request tor
|
|
1045
|
+
JOIN operations_collaborator c ON c.id = tor.collaborator_id
|
|
1046
|
+
LEFT JOIN operations_collaborator a ON a.id = tor.approver_collaborator_id
|
|
1047
|
+
LEFT JOIN operations_approval approval
|
|
1048
|
+
ON approval.target_type = 'time_off_request'
|
|
1049
|
+
AND approval.target_id = tor.id
|
|
1050
|
+
AND approval.deleted_at IS NULL
|
|
1051
|
+
WHERE tor.deleted_at IS NULL AND ${filter.clause}
|
|
1052
1052
|
ORDER BY tor.start_date DESC, tor.id DESC`, filter.params);
|
|
1053
1053
|
}
|
|
1054
1054
|
async createTimeOffRequest(userId, data) {
|
|
@@ -1067,19 +1067,19 @@ let OperationsService = class OperationsService {
|
|
|
1067
1067
|
const collaborator = await this.getCollaboratorById(collaboratorId);
|
|
1068
1068
|
const created = await this.prisma.$transaction(async (tx) => {
|
|
1069
1069
|
var _a, _b, _c, _d, _e, _f;
|
|
1070
|
-
const row = (await tx.$queryRawUnsafe(`INSERT INTO operations_time_off_request (
|
|
1071
|
-
collaborator_id,
|
|
1072
|
-
approver_collaborator_id,
|
|
1073
|
-
request_type,
|
|
1074
|
-
start_date,
|
|
1075
|
-
end_date,
|
|
1076
|
-
total_days,
|
|
1077
|
-
status,
|
|
1078
|
-
reason,
|
|
1079
|
-
submitted_at,
|
|
1080
|
-
created_at,
|
|
1081
|
-
updated_at
|
|
1082
|
-
) VALUES ($1, $2, COALESCE($3, 'vacation'), $4, $5, $6, 'submitted', $7, NOW(), NOW(), NOW())
|
|
1070
|
+
const row = (await tx.$queryRawUnsafe(`INSERT INTO operations_time_off_request (
|
|
1071
|
+
collaborator_id,
|
|
1072
|
+
approver_collaborator_id,
|
|
1073
|
+
request_type,
|
|
1074
|
+
start_date,
|
|
1075
|
+
end_date,
|
|
1076
|
+
total_days,
|
|
1077
|
+
status,
|
|
1078
|
+
reason,
|
|
1079
|
+
submitted_at,
|
|
1080
|
+
created_at,
|
|
1081
|
+
updated_at
|
|
1082
|
+
) VALUES ($1, $2, COALESCE($3, 'vacation'), $4, $5, $6, 'submitted', $7, NOW(), NOW(), NOW())
|
|
1083
1083
|
RETURNING id`, collaboratorId, (_a = collaborator.supervisorId) !== null && _a !== void 0 ? _a : null, (_b = data.requestType) !== null && _b !== void 0 ? _b : 'vacation', data.startDate, data.endDate, (_c = data.totalDays) !== null && _c !== void 0 ? _c : null, (_d = data.reason) !== null && _d !== void 0 ? _d : null));
|
|
1084
1084
|
const requestId = (_e = row[0]) === null || _e === void 0 ? void 0 : _e.id;
|
|
1085
1085
|
await this.upsertApproval(tx, {
|
|
@@ -1090,65 +1090,65 @@ let OperationsService = class OperationsService {
|
|
|
1090
1090
|
});
|
|
1091
1091
|
return requestId;
|
|
1092
1092
|
});
|
|
1093
|
-
return this.querySingle(`SELECT id,
|
|
1094
|
-
collaborator_id AS "collaboratorId",
|
|
1095
|
-
approver_collaborator_id AS "approverCollaboratorId",
|
|
1096
|
-
request_type AS "requestType",
|
|
1097
|
-
start_date AS "startDate",
|
|
1098
|
-
end_date AS "endDate",
|
|
1099
|
-
total_days AS "totalDays",
|
|
1100
|
-
status,
|
|
1101
|
-
reason,
|
|
1102
|
-
submitted_at AS "submittedAt",
|
|
1103
|
-
reviewed_at AS "reviewedAt"
|
|
1104
|
-
FROM operations_time_off_request
|
|
1093
|
+
return this.querySingle(`SELECT id,
|
|
1094
|
+
collaborator_id AS "collaboratorId",
|
|
1095
|
+
approver_collaborator_id AS "approverCollaboratorId",
|
|
1096
|
+
request_type AS "requestType",
|
|
1097
|
+
start_date AS "startDate",
|
|
1098
|
+
end_date AS "endDate",
|
|
1099
|
+
total_days AS "totalDays",
|
|
1100
|
+
status,
|
|
1101
|
+
reason,
|
|
1102
|
+
submitted_at AS "submittedAt",
|
|
1103
|
+
reviewed_at AS "reviewedAt"
|
|
1104
|
+
FROM operations_time_off_request
|
|
1105
1105
|
WHERE id = $1`, [created]);
|
|
1106
1106
|
}
|
|
1107
1107
|
async listScheduleAdjustments(userId) {
|
|
1108
1108
|
const actor = await this.getActorContext(userId);
|
|
1109
1109
|
const filter = this.buildIdFilter(actor.visibleCollaboratorIds, 'sar.collaborator_id', actor.isDirector);
|
|
1110
|
-
const requests = await this.queryRows(`SELECT sar.id,
|
|
1111
|
-
sar.collaborator_id AS "collaboratorId",
|
|
1112
|
-
c.display_name AS "collaboratorName",
|
|
1113
|
-
sar.approver_collaborator_id AS "approverCollaboratorId",
|
|
1114
|
-
a.display_name AS "approverName",
|
|
1115
|
-
sar.request_scope AS "requestScope",
|
|
1116
|
-
sar.effective_start_date AS "effectiveStartDate",
|
|
1117
|
-
sar.effective_end_date AS "effectiveEndDate",
|
|
1118
|
-
sar.status,
|
|
1119
|
-
sar.reason,
|
|
1120
|
-
sar.submitted_at AS "submittedAt",
|
|
1121
|
-
sar.reviewed_at AS "reviewedAt",
|
|
1122
|
-
approval.decision_note AS "approverNote"
|
|
1123
|
-
FROM operations_schedule_adjustment_request sar
|
|
1124
|
-
JOIN operations_collaborator c ON c.id = sar.collaborator_id
|
|
1125
|
-
LEFT JOIN operations_collaborator a ON a.id = sar.approver_collaborator_id
|
|
1126
|
-
LEFT JOIN operations_approval approval
|
|
1127
|
-
ON approval.target_type = 'schedule_adjustment_request'
|
|
1128
|
-
AND approval.target_id = sar.id
|
|
1129
|
-
AND approval.deleted_at IS NULL
|
|
1130
|
-
WHERE sar.deleted_at IS NULL AND ${filter.clause}
|
|
1110
|
+
const requests = await this.queryRows(`SELECT sar.id,
|
|
1111
|
+
sar.collaborator_id AS "collaboratorId",
|
|
1112
|
+
c.display_name AS "collaboratorName",
|
|
1113
|
+
sar.approver_collaborator_id AS "approverCollaboratorId",
|
|
1114
|
+
a.display_name AS "approverName",
|
|
1115
|
+
sar.request_scope AS "requestScope",
|
|
1116
|
+
sar.effective_start_date AS "effectiveStartDate",
|
|
1117
|
+
sar.effective_end_date AS "effectiveEndDate",
|
|
1118
|
+
sar.status,
|
|
1119
|
+
sar.reason,
|
|
1120
|
+
sar.submitted_at AS "submittedAt",
|
|
1121
|
+
sar.reviewed_at AS "reviewedAt",
|
|
1122
|
+
approval.decision_note AS "approverNote"
|
|
1123
|
+
FROM operations_schedule_adjustment_request sar
|
|
1124
|
+
JOIN operations_collaborator c ON c.id = sar.collaborator_id
|
|
1125
|
+
LEFT JOIN operations_collaborator a ON a.id = sar.approver_collaborator_id
|
|
1126
|
+
LEFT JOIN operations_approval approval
|
|
1127
|
+
ON approval.target_type = 'schedule_adjustment_request'
|
|
1128
|
+
AND approval.target_id = sar.id
|
|
1129
|
+
AND approval.deleted_at IS NULL
|
|
1130
|
+
WHERE sar.deleted_at IS NULL AND ${filter.clause}
|
|
1131
1131
|
ORDER BY sar.effective_start_date DESC, sar.id DESC`, filter.params);
|
|
1132
1132
|
if (!requests.length) {
|
|
1133
1133
|
return requests;
|
|
1134
1134
|
}
|
|
1135
|
-
const days = await this.queryRows(`SELECT schedule_adjustment_request_id AS "requestId",
|
|
1136
|
-
weekday,
|
|
1137
|
-
is_working_day AS "isWorkingDay",
|
|
1138
|
-
start_time AS "startTime",
|
|
1139
|
-
end_time AS "endTime",
|
|
1140
|
-
break_minutes AS "breakMinutes"
|
|
1141
|
-
FROM operations_schedule_adjustment_day
|
|
1142
|
-
WHERE schedule_adjustment_request_id = ANY($1::int[])
|
|
1135
|
+
const days = await this.queryRows(`SELECT schedule_adjustment_request_id AS "requestId",
|
|
1136
|
+
weekday,
|
|
1137
|
+
is_working_day AS "isWorkingDay",
|
|
1138
|
+
start_time AS "startTime",
|
|
1139
|
+
end_time AS "endTime",
|
|
1140
|
+
break_minutes AS "breakMinutes"
|
|
1141
|
+
FROM operations_schedule_adjustment_day
|
|
1142
|
+
WHERE schedule_adjustment_request_id = ANY($1::int[])
|
|
1143
1143
|
ORDER BY id ASC`, [requests.map((item) => item.id)]);
|
|
1144
|
-
const currentSchedule = await this.queryRows(`SELECT collaborator_id AS "collaboratorId",
|
|
1145
|
-
weekday,
|
|
1146
|
-
is_working_day AS "isWorkingDay",
|
|
1147
|
-
start_time AS "startTime",
|
|
1148
|
-
end_time AS "endTime",
|
|
1149
|
-
break_minutes AS "breakMinutes"
|
|
1150
|
-
FROM operations_collaborator_schedule_day
|
|
1151
|
-
WHERE collaborator_id = ANY($1::int[])
|
|
1144
|
+
const currentSchedule = await this.queryRows(`SELECT collaborator_id AS "collaboratorId",
|
|
1145
|
+
weekday,
|
|
1146
|
+
is_working_day AS "isWorkingDay",
|
|
1147
|
+
start_time AS "startTime",
|
|
1148
|
+
end_time AS "endTime",
|
|
1149
|
+
break_minutes AS "breakMinutes"
|
|
1150
|
+
FROM operations_collaborator_schedule_day
|
|
1151
|
+
WHERE collaborator_id = ANY($1::int[])
|
|
1152
1152
|
ORDER BY id ASC`, [this.uniqueNumbers(requests.map((item) => item.collaboratorId))]);
|
|
1153
1153
|
const grouped = this.groupBy(days, 'requestId');
|
|
1154
1154
|
const currentScheduleByCollaborator = this.groupBy(currentSchedule, 'collaboratorId');
|
|
@@ -1176,32 +1176,32 @@ let OperationsService = class OperationsService {
|
|
|
1176
1176
|
const collaborator = await this.getCollaboratorById(collaboratorId);
|
|
1177
1177
|
const created = await this.prisma.$transaction(async (tx) => {
|
|
1178
1178
|
var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k;
|
|
1179
|
-
const row = (await tx.$queryRawUnsafe(`INSERT INTO operations_schedule_adjustment_request (
|
|
1180
|
-
collaborator_id,
|
|
1181
|
-
approver_collaborator_id,
|
|
1182
|
-
request_scope,
|
|
1183
|
-
effective_start_date,
|
|
1184
|
-
effective_end_date,
|
|
1185
|
-
status,
|
|
1186
|
-
reason,
|
|
1187
|
-
submitted_at,
|
|
1188
|
-
created_at,
|
|
1189
|
-
updated_at
|
|
1190
|
-
) VALUES (
|
|
1191
|
-
$1, $2, COALESCE($3, 'temporary'), $4, $5, 'submitted', $6, NOW(), NOW(), NOW()
|
|
1192
|
-
)
|
|
1179
|
+
const row = (await tx.$queryRawUnsafe(`INSERT INTO operations_schedule_adjustment_request (
|
|
1180
|
+
collaborator_id,
|
|
1181
|
+
approver_collaborator_id,
|
|
1182
|
+
request_scope,
|
|
1183
|
+
effective_start_date,
|
|
1184
|
+
effective_end_date,
|
|
1185
|
+
status,
|
|
1186
|
+
reason,
|
|
1187
|
+
submitted_at,
|
|
1188
|
+
created_at,
|
|
1189
|
+
updated_at
|
|
1190
|
+
) VALUES (
|
|
1191
|
+
$1, $2, COALESCE($3, 'temporary'), $4, $5, 'submitted', $6, NOW(), NOW(), NOW()
|
|
1192
|
+
)
|
|
1193
1193
|
RETURNING id`, collaboratorId, (_a = collaborator.supervisorId) !== null && _a !== void 0 ? _a : null, (_b = data.requestScope) !== null && _b !== void 0 ? _b : 'temporary', data.effectiveStartDate, (_c = data.effectiveEndDate) !== null && _c !== void 0 ? _c : null, (_d = data.reason) !== null && _d !== void 0 ? _d : null));
|
|
1194
1194
|
const requestId = (_e = row[0]) === null || _e === void 0 ? void 0 : _e.id;
|
|
1195
1195
|
for (const day of data.days) {
|
|
1196
|
-
await tx.$executeRawUnsafe(`INSERT INTO operations_schedule_adjustment_day (
|
|
1197
|
-
schedule_adjustment_request_id,
|
|
1198
|
-
weekday,
|
|
1199
|
-
is_working_day,
|
|
1200
|
-
start_time,
|
|
1201
|
-
end_time,
|
|
1202
|
-
break_minutes,
|
|
1203
|
-
created_at,
|
|
1204
|
-
updated_at
|
|
1196
|
+
await tx.$executeRawUnsafe(`INSERT INTO operations_schedule_adjustment_day (
|
|
1197
|
+
schedule_adjustment_request_id,
|
|
1198
|
+
weekday,
|
|
1199
|
+
is_working_day,
|
|
1200
|
+
start_time,
|
|
1201
|
+
end_time,
|
|
1202
|
+
break_minutes,
|
|
1203
|
+
created_at,
|
|
1204
|
+
updated_at
|
|
1205
1205
|
) VALUES ($1, $2, $3, $4, $5, $6, NOW(), NOW())`, requestId, day.weekday, (_f = day.isWorkingDay) !== null && _f !== void 0 ? _f : true, (_g = day.startTime) !== null && _g !== void 0 ? _g : null, (_h = day.endTime) !== null && _h !== void 0 ? _h : null, (_j = day.breakMinutes) !== null && _j !== void 0 ? _j : null);
|
|
1206
1206
|
}
|
|
1207
1207
|
await this.upsertApproval(tx, {
|
|
@@ -1212,17 +1212,17 @@ let OperationsService = class OperationsService {
|
|
|
1212
1212
|
});
|
|
1213
1213
|
return requestId;
|
|
1214
1214
|
});
|
|
1215
|
-
return this.querySingle(`SELECT id,
|
|
1216
|
-
collaborator_id AS "collaboratorId",
|
|
1217
|
-
approver_collaborator_id AS "approverCollaboratorId",
|
|
1218
|
-
request_scope AS "requestScope",
|
|
1219
|
-
effective_start_date AS "effectiveStartDate",
|
|
1220
|
-
effective_end_date AS "effectiveEndDate",
|
|
1221
|
-
status,
|
|
1222
|
-
reason,
|
|
1223
|
-
submitted_at AS "submittedAt",
|
|
1224
|
-
reviewed_at AS "reviewedAt"
|
|
1225
|
-
FROM operations_schedule_adjustment_request
|
|
1215
|
+
return this.querySingle(`SELECT id,
|
|
1216
|
+
collaborator_id AS "collaboratorId",
|
|
1217
|
+
approver_collaborator_id AS "approverCollaboratorId",
|
|
1218
|
+
request_scope AS "requestScope",
|
|
1219
|
+
effective_start_date AS "effectiveStartDate",
|
|
1220
|
+
effective_end_date AS "effectiveEndDate",
|
|
1221
|
+
status,
|
|
1222
|
+
reason,
|
|
1223
|
+
submitted_at AS "submittedAt",
|
|
1224
|
+
reviewed_at AS "reviewedAt"
|
|
1225
|
+
FROM operations_schedule_adjustment_request
|
|
1226
1226
|
WHERE id = $1`, [created]);
|
|
1227
1227
|
}
|
|
1228
1228
|
async listApprovals(userId) {
|
|
@@ -1232,55 +1232,55 @@ let OperationsService = class OperationsService {
|
|
|
1232
1232
|
const clause = actor.isDirector
|
|
1233
1233
|
? 'a.deleted_at IS NULL'
|
|
1234
1234
|
: `a.deleted_at IS NULL AND a.approver_collaborator_id = ${this.param(params, actor.collaboratorId)}`;
|
|
1235
|
-
return this.queryRows(`SELECT a.id,
|
|
1236
|
-
a.target_type AS "targetType",
|
|
1237
|
-
a.target_id AS "targetId",
|
|
1238
|
-
a.requester_collaborator_id AS "requesterCollaboratorId",
|
|
1239
|
-
requester.display_name AS "requesterName",
|
|
1240
|
-
a.approver_collaborator_id AS "approverCollaboratorId",
|
|
1241
|
-
approver.display_name AS "approverName",
|
|
1242
|
-
a.status,
|
|
1243
|
-
a.submitted_at AS "submittedAt",
|
|
1244
|
-
a.decided_at AS "decidedAt",
|
|
1245
|
-
a.decision_note AS "decisionNote",
|
|
1246
|
-
t.week_start_date AS "timesheetWeekStartDate",
|
|
1247
|
-
t.week_end_date AS "timesheetWeekEndDate",
|
|
1248
|
-
t.total_hours AS "timesheetTotalHours",
|
|
1249
|
-
COALESCE(
|
|
1250
|
-
STRING_AGG(DISTINCT p.name, ', ') FILTER (WHERE p.name IS NOT NULL),
|
|
1251
|
-
''
|
|
1252
|
-
) AS "timesheetProjectNames",
|
|
1253
|
-
tor.request_type AS "timeOffType",
|
|
1254
|
-
tor.start_date AS "timeOffStartDate",
|
|
1255
|
-
tor.end_date AS "timeOffEndDate",
|
|
1256
|
-
tor.reason AS "timeOffReason",
|
|
1257
|
-
sar.request_scope AS "scheduleRequestScope",
|
|
1258
|
-
sar.effective_start_date AS "scheduleStartDate",
|
|
1259
|
-
sar.effective_end_date AS "scheduleEndDate",
|
|
1260
|
-
sar.reason AS "scheduleReason"
|
|
1261
|
-
FROM operations_approval a
|
|
1262
|
-
JOIN operations_collaborator requester
|
|
1263
|
-
ON requester.id = a.requester_collaborator_id
|
|
1264
|
-
LEFT JOIN operations_collaborator approver
|
|
1265
|
-
ON approver.id = a.approver_collaborator_id
|
|
1266
|
-
LEFT JOIN operations_timesheet t
|
|
1267
|
-
ON a.target_type = 'timesheet'
|
|
1268
|
-
AND t.id = a.target_id
|
|
1269
|
-
LEFT JOIN operations_timesheet_entry te
|
|
1270
|
-
ON te.timesheet_id = t.id
|
|
1271
|
-
AND te.deleted_at IS NULL
|
|
1272
|
-
LEFT JOIN operations_project_assignment pa
|
|
1273
|
-
ON pa.id = te.project_assignment_id
|
|
1274
|
-
LEFT JOIN operations_project p
|
|
1275
|
-
ON p.id = pa.project_id
|
|
1276
|
-
LEFT JOIN operations_time_off_request tor
|
|
1277
|
-
ON a.target_type = 'time_off_request'
|
|
1278
|
-
AND tor.id = a.target_id
|
|
1279
|
-
LEFT JOIN operations_schedule_adjustment_request sar
|
|
1280
|
-
ON a.target_type = 'schedule_adjustment_request'
|
|
1281
|
-
AND sar.id = a.target_id
|
|
1282
|
-
WHERE ${clause}
|
|
1283
|
-
GROUP BY a.id, requester.id, approver.id, t.id, tor.id, sar.id
|
|
1235
|
+
return this.queryRows(`SELECT a.id,
|
|
1236
|
+
a.target_type AS "targetType",
|
|
1237
|
+
a.target_id AS "targetId",
|
|
1238
|
+
a.requester_collaborator_id AS "requesterCollaboratorId",
|
|
1239
|
+
requester.display_name AS "requesterName",
|
|
1240
|
+
a.approver_collaborator_id AS "approverCollaboratorId",
|
|
1241
|
+
approver.display_name AS "approverName",
|
|
1242
|
+
a.status,
|
|
1243
|
+
a.submitted_at AS "submittedAt",
|
|
1244
|
+
a.decided_at AS "decidedAt",
|
|
1245
|
+
a.decision_note AS "decisionNote",
|
|
1246
|
+
t.week_start_date AS "timesheetWeekStartDate",
|
|
1247
|
+
t.week_end_date AS "timesheetWeekEndDate",
|
|
1248
|
+
t.total_hours AS "timesheetTotalHours",
|
|
1249
|
+
COALESCE(
|
|
1250
|
+
STRING_AGG(DISTINCT p.name, ', ') FILTER (WHERE p.name IS NOT NULL),
|
|
1251
|
+
''
|
|
1252
|
+
) AS "timesheetProjectNames",
|
|
1253
|
+
tor.request_type AS "timeOffType",
|
|
1254
|
+
tor.start_date AS "timeOffStartDate",
|
|
1255
|
+
tor.end_date AS "timeOffEndDate",
|
|
1256
|
+
tor.reason AS "timeOffReason",
|
|
1257
|
+
sar.request_scope AS "scheduleRequestScope",
|
|
1258
|
+
sar.effective_start_date AS "scheduleStartDate",
|
|
1259
|
+
sar.effective_end_date AS "scheduleEndDate",
|
|
1260
|
+
sar.reason AS "scheduleReason"
|
|
1261
|
+
FROM operations_approval a
|
|
1262
|
+
JOIN operations_collaborator requester
|
|
1263
|
+
ON requester.id = a.requester_collaborator_id
|
|
1264
|
+
LEFT JOIN operations_collaborator approver
|
|
1265
|
+
ON approver.id = a.approver_collaborator_id
|
|
1266
|
+
LEFT JOIN operations_timesheet t
|
|
1267
|
+
ON a.target_type = 'timesheet'
|
|
1268
|
+
AND t.id = a.target_id
|
|
1269
|
+
LEFT JOIN operations_timesheet_entry te
|
|
1270
|
+
ON te.timesheet_id = t.id
|
|
1271
|
+
AND te.deleted_at IS NULL
|
|
1272
|
+
LEFT JOIN operations_project_assignment pa
|
|
1273
|
+
ON pa.id = te.project_assignment_id
|
|
1274
|
+
LEFT JOIN operations_project p
|
|
1275
|
+
ON p.id = pa.project_id
|
|
1276
|
+
LEFT JOIN operations_time_off_request tor
|
|
1277
|
+
ON a.target_type = 'time_off_request'
|
|
1278
|
+
AND tor.id = a.target_id
|
|
1279
|
+
LEFT JOIN operations_schedule_adjustment_request sar
|
|
1280
|
+
ON a.target_type = 'schedule_adjustment_request'
|
|
1281
|
+
AND sar.id = a.target_id
|
|
1282
|
+
WHERE ${clause}
|
|
1283
|
+
GROUP BY a.id, requester.id, approver.id, t.id, tor.id, sar.id
|
|
1284
1284
|
ORDER BY a.submitted_at DESC, a.id DESC`, params);
|
|
1285
1285
|
}
|
|
1286
1286
|
async approve(userId, approvalId, data) {
|
|
@@ -1349,14 +1349,14 @@ let OperationsService = class OperationsService {
|
|
|
1349
1349
|
async decideApproval(userId, approvalId, action, data) {
|
|
1350
1350
|
const actor = await this.getActorContext(userId);
|
|
1351
1351
|
this.ensureSupervisor(actor);
|
|
1352
|
-
const approval = await this.querySingle(`SELECT id,
|
|
1353
|
-
target_type AS "targetType",
|
|
1354
|
-
target_id AS "targetId",
|
|
1355
|
-
requester_collaborator_id AS "requesterCollaboratorId",
|
|
1356
|
-
approver_collaborator_id AS "approverCollaboratorId",
|
|
1357
|
-
status
|
|
1358
|
-
FROM operations_approval
|
|
1359
|
-
WHERE id = $1
|
|
1352
|
+
const approval = await this.querySingle(`SELECT id,
|
|
1353
|
+
target_type AS "targetType",
|
|
1354
|
+
target_id AS "targetId",
|
|
1355
|
+
requester_collaborator_id AS "requesterCollaboratorId",
|
|
1356
|
+
approver_collaborator_id AS "approverCollaboratorId",
|
|
1357
|
+
status
|
|
1358
|
+
FROM operations_approval
|
|
1359
|
+
WHERE id = $1
|
|
1360
1360
|
AND deleted_at IS NULL`, [approvalId]);
|
|
1361
1361
|
if (!approval) {
|
|
1362
1362
|
throw new common_1.NotFoundException('Approval not found.');
|
|
@@ -1370,47 +1370,47 @@ let OperationsService = class OperationsService {
|
|
|
1370
1370
|
const nextStatus = action === 'approve' ? 'approved' : 'rejected';
|
|
1371
1371
|
await this.prisma.$transaction(async (tx) => {
|
|
1372
1372
|
var _a, _b;
|
|
1373
|
-
await tx.$executeRawUnsafe(`UPDATE operations_approval
|
|
1374
|
-
SET status = $1,
|
|
1375
|
-
decided_at = NOW(),
|
|
1376
|
-
decision_note = $2,
|
|
1377
|
-
updated_at = NOW()
|
|
1373
|
+
await tx.$executeRawUnsafe(`UPDATE operations_approval
|
|
1374
|
+
SET status = $1,
|
|
1375
|
+
decided_at = NOW(),
|
|
1376
|
+
decision_note = $2,
|
|
1377
|
+
updated_at = NOW()
|
|
1378
1378
|
WHERE id = $3`, nextStatus, (_a = data.note) !== null && _a !== void 0 ? _a : null, approvalId);
|
|
1379
1379
|
if (approval.targetType === 'timesheet') {
|
|
1380
|
-
await tx.$executeRawUnsafe(`UPDATE operations_timesheet
|
|
1381
|
-
SET status = $1,
|
|
1382
|
-
reviewed_at = NOW(),
|
|
1383
|
-
approver_collaborator_id = $2,
|
|
1384
|
-
updated_at = NOW()
|
|
1380
|
+
await tx.$executeRawUnsafe(`UPDATE operations_timesheet
|
|
1381
|
+
SET status = $1,
|
|
1382
|
+
reviewed_at = NOW(),
|
|
1383
|
+
approver_collaborator_id = $2,
|
|
1384
|
+
updated_at = NOW()
|
|
1385
1385
|
WHERE id = $3`, nextStatus, actor.collaboratorId, approval.targetId);
|
|
1386
1386
|
}
|
|
1387
1387
|
if (approval.targetType === 'time_off_request') {
|
|
1388
|
-
await tx.$executeRawUnsafe(`UPDATE operations_time_off_request
|
|
1389
|
-
SET status = $1,
|
|
1390
|
-
reviewed_at = NOW(),
|
|
1391
|
-
approver_collaborator_id = $2,
|
|
1392
|
-
submitted_at = COALESCE(submitted_at, NOW()),
|
|
1393
|
-
updated_at = NOW()
|
|
1388
|
+
await tx.$executeRawUnsafe(`UPDATE operations_time_off_request
|
|
1389
|
+
SET status = $1,
|
|
1390
|
+
reviewed_at = NOW(),
|
|
1391
|
+
approver_collaborator_id = $2,
|
|
1392
|
+
submitted_at = COALESCE(submitted_at, NOW()),
|
|
1393
|
+
updated_at = NOW()
|
|
1394
1394
|
WHERE id = $3`, nextStatus, actor.collaboratorId, approval.targetId);
|
|
1395
1395
|
}
|
|
1396
1396
|
if (approval.targetType === 'schedule_adjustment_request') {
|
|
1397
|
-
await tx.$executeRawUnsafe(`UPDATE operations_schedule_adjustment_request
|
|
1398
|
-
SET status = $1,
|
|
1399
|
-
reviewed_at = NOW(),
|
|
1400
|
-
approver_collaborator_id = $2,
|
|
1401
|
-
submitted_at = COALESCE(submitted_at, NOW()),
|
|
1402
|
-
updated_at = NOW()
|
|
1397
|
+
await tx.$executeRawUnsafe(`UPDATE operations_schedule_adjustment_request
|
|
1398
|
+
SET status = $1,
|
|
1399
|
+
reviewed_at = NOW(),
|
|
1400
|
+
approver_collaborator_id = $2,
|
|
1401
|
+
submitted_at = COALESCE(submitted_at, NOW()),
|
|
1402
|
+
updated_at = NOW()
|
|
1403
1403
|
WHERE id = $3`, nextStatus, actor.collaboratorId, approval.targetId);
|
|
1404
1404
|
}
|
|
1405
1405
|
await this.insertApprovalHistory(tx, approvalId, actor.collaboratorId, nextStatus === 'approved' ? 'approved' : 'rejected', (_b = data.note) !== null && _b !== void 0 ? _b : null);
|
|
1406
1406
|
});
|
|
1407
|
-
return this.querySingle(`SELECT id,
|
|
1408
|
-
target_type AS "targetType",
|
|
1409
|
-
target_id AS "targetId",
|
|
1410
|
-
status,
|
|
1411
|
-
decided_at AS "decidedAt",
|
|
1412
|
-
decision_note AS "decisionNote"
|
|
1413
|
-
FROM operations_approval
|
|
1407
|
+
return this.querySingle(`SELECT id,
|
|
1408
|
+
target_type AS "targetType",
|
|
1409
|
+
target_id AS "targetId",
|
|
1410
|
+
status,
|
|
1411
|
+
decided_at AS "decidedAt",
|
|
1412
|
+
decision_note AS "decisionNote"
|
|
1413
|
+
FROM operations_approval
|
|
1414
1414
|
WHERE id = $1`, [approvalId]);
|
|
1415
1415
|
}
|
|
1416
1416
|
async getActorContext(userId) {
|
|
@@ -1459,25 +1459,25 @@ let OperationsService = class OperationsService {
|
|
|
1459
1459
|
};
|
|
1460
1460
|
}
|
|
1461
1461
|
async getCollaboratorByUserId(userId) {
|
|
1462
|
-
return this.querySingle(`SELECT c.id,
|
|
1463
|
-
c.display_name AS "displayName",
|
|
1464
|
-
s.id AS "supervisorId",
|
|
1465
|
-
s.display_name AS "supervisorName"
|
|
1466
|
-
FROM operations_collaborator c
|
|
1467
|
-
LEFT JOIN operations_collaborator s
|
|
1468
|
-
ON s.id = c.supervisor_collaborator_id
|
|
1469
|
-
WHERE c.user_id = $1
|
|
1462
|
+
return this.querySingle(`SELECT c.id,
|
|
1463
|
+
c.display_name AS "displayName",
|
|
1464
|
+
s.id AS "supervisorId",
|
|
1465
|
+
s.display_name AS "supervisorName"
|
|
1466
|
+
FROM operations_collaborator c
|
|
1467
|
+
LEFT JOIN operations_collaborator s
|
|
1468
|
+
ON s.id = c.supervisor_collaborator_id
|
|
1469
|
+
WHERE c.user_id = $1
|
|
1470
1470
|
AND c.deleted_at IS NULL`, [userId]);
|
|
1471
1471
|
}
|
|
1472
1472
|
async getCollaboratorById(collaboratorId) {
|
|
1473
|
-
const collaborator = await this.querySingle(`SELECT c.id,
|
|
1474
|
-
c.display_name AS "displayName",
|
|
1475
|
-
s.id AS "supervisorId",
|
|
1476
|
-
s.display_name AS "supervisorName"
|
|
1477
|
-
FROM operations_collaborator c
|
|
1478
|
-
LEFT JOIN operations_collaborator s
|
|
1479
|
-
ON s.id = c.supervisor_collaborator_id
|
|
1480
|
-
WHERE c.id = $1
|
|
1473
|
+
const collaborator = await this.querySingle(`SELECT c.id,
|
|
1474
|
+
c.display_name AS "displayName",
|
|
1475
|
+
s.id AS "supervisorId",
|
|
1476
|
+
s.display_name AS "supervisorName"
|
|
1477
|
+
FROM operations_collaborator c
|
|
1478
|
+
LEFT JOIN operations_collaborator s
|
|
1479
|
+
ON s.id = c.supervisor_collaborator_id
|
|
1480
|
+
WHERE c.id = $1
|
|
1481
1481
|
AND c.deleted_at IS NULL`, [collaboratorId]);
|
|
1482
1482
|
if (!collaborator) {
|
|
1483
1483
|
throw new common_1.NotFoundException('Collaborator not found.');
|
|
@@ -1486,91 +1486,91 @@ let OperationsService = class OperationsService {
|
|
|
1486
1486
|
}
|
|
1487
1487
|
async getProjectDetails(projectId, actorCollaboratorId) {
|
|
1488
1488
|
var _a, _b, _c, _d, _e, _f, _g;
|
|
1489
|
-
const project = await this.querySingle(`SELECT p.id,
|
|
1490
|
-
p.contract_id AS "contractId",
|
|
1491
|
-
p.manager_collaborator_id AS "managerCollaboratorId",
|
|
1492
|
-
p.code,
|
|
1493
|
-
p.name,
|
|
1494
|
-
p.client_name AS "clientName",
|
|
1495
|
-
p.summary,
|
|
1496
|
-
p.status,
|
|
1497
|
-
p.progress_percent AS "progressPercent",
|
|
1498
|
-
p.delivery_model AS "deliveryModel",
|
|
1499
|
-
p.budget_amount AS "budgetAmount",
|
|
1500
|
-
p.start_date AS "startDate",
|
|
1501
|
-
p.end_date AS "endDate",
|
|
1502
|
-
c.name AS "contractName",
|
|
1503
|
-
c.status AS "contractStatus",
|
|
1504
|
-
c.contract_category AS "contractCategory",
|
|
1505
|
-
m.display_name AS "managerName",
|
|
1506
|
-
MAX(CASE WHEN pa.collaborator_id = $2 THEN pa.id END)::int AS "myAssignmentId",
|
|
1507
|
-
MAX(CASE WHEN pa.collaborator_id = $2 THEN pa.role_label END) AS "myRoleLabel",
|
|
1508
|
-
COUNT(DISTINCT pa.id)::int AS "teamSize"
|
|
1509
|
-
FROM operations_project p
|
|
1510
|
-
LEFT JOIN operations_contract c ON c.id = p.contract_id
|
|
1511
|
-
LEFT JOIN operations_collaborator m ON m.id = p.manager_collaborator_id
|
|
1512
|
-
LEFT JOIN operations_project_assignment pa
|
|
1513
|
-
ON pa.project_id = p.id
|
|
1514
|
-
AND pa.deleted_at IS NULL
|
|
1515
|
-
WHERE p.id = $1
|
|
1516
|
-
AND p.deleted_at IS NULL
|
|
1489
|
+
const project = await this.querySingle(`SELECT p.id,
|
|
1490
|
+
p.contract_id AS "contractId",
|
|
1491
|
+
p.manager_collaborator_id AS "managerCollaboratorId",
|
|
1492
|
+
p.code,
|
|
1493
|
+
p.name,
|
|
1494
|
+
p.client_name AS "clientName",
|
|
1495
|
+
p.summary,
|
|
1496
|
+
p.status,
|
|
1497
|
+
p.progress_percent AS "progressPercent",
|
|
1498
|
+
p.delivery_model AS "deliveryModel",
|
|
1499
|
+
p.budget_amount AS "budgetAmount",
|
|
1500
|
+
p.start_date AS "startDate",
|
|
1501
|
+
p.end_date AS "endDate",
|
|
1502
|
+
c.name AS "contractName",
|
|
1503
|
+
c.status AS "contractStatus",
|
|
1504
|
+
c.contract_category AS "contractCategory",
|
|
1505
|
+
m.display_name AS "managerName",
|
|
1506
|
+
MAX(CASE WHEN pa.collaborator_id = $2 THEN pa.id END)::int AS "myAssignmentId",
|
|
1507
|
+
MAX(CASE WHEN pa.collaborator_id = $2 THEN pa.role_label END) AS "myRoleLabel",
|
|
1508
|
+
COUNT(DISTINCT pa.id)::int AS "teamSize"
|
|
1509
|
+
FROM operations_project p
|
|
1510
|
+
LEFT JOIN operations_contract c ON c.id = p.contract_id
|
|
1511
|
+
LEFT JOIN operations_collaborator m ON m.id = p.manager_collaborator_id
|
|
1512
|
+
LEFT JOIN operations_project_assignment pa
|
|
1513
|
+
ON pa.project_id = p.id
|
|
1514
|
+
AND pa.deleted_at IS NULL
|
|
1515
|
+
WHERE p.id = $1
|
|
1516
|
+
AND p.deleted_at IS NULL
|
|
1517
1517
|
GROUP BY p.id, c.id, m.id`, [projectId, actorCollaboratorId !== null && actorCollaboratorId !== void 0 ? actorCollaboratorId : null]);
|
|
1518
1518
|
if (!project) {
|
|
1519
1519
|
throw new common_1.NotFoundException('Project not found.');
|
|
1520
1520
|
}
|
|
1521
1521
|
const [assignments, relatedContract, timesheetSummary, operationalIndicators] = await Promise.all([
|
|
1522
|
-
this.queryRows(`SELECT pa.id,
|
|
1523
|
-
pa.collaborator_id AS "collaboratorId",
|
|
1524
|
-
c.display_name AS "collaboratorName",
|
|
1525
|
-
pa.role_label AS "roleLabel",
|
|
1526
|
-
pa.allocation_percent AS "allocationPercent",
|
|
1527
|
-
pa.weekly_hours AS "weeklyHours",
|
|
1528
|
-
pa.is_billable AS "isBillable",
|
|
1529
|
-
pa.start_date AS "startDate",
|
|
1530
|
-
pa.end_date AS "endDate",
|
|
1531
|
-
pa.status
|
|
1532
|
-
FROM operations_project_assignment pa
|
|
1533
|
-
JOIN operations_collaborator c ON c.id = pa.collaborator_id
|
|
1534
|
-
WHERE pa.project_id = $1
|
|
1535
|
-
AND pa.deleted_at IS NULL
|
|
1522
|
+
this.queryRows(`SELECT pa.id,
|
|
1523
|
+
pa.collaborator_id AS "collaboratorId",
|
|
1524
|
+
c.display_name AS "collaboratorName",
|
|
1525
|
+
pa.role_label AS "roleLabel",
|
|
1526
|
+
pa.allocation_percent AS "allocationPercent",
|
|
1527
|
+
pa.weekly_hours AS "weeklyHours",
|
|
1528
|
+
pa.is_billable AS "isBillable",
|
|
1529
|
+
pa.start_date AS "startDate",
|
|
1530
|
+
pa.end_date AS "endDate",
|
|
1531
|
+
pa.status
|
|
1532
|
+
FROM operations_project_assignment pa
|
|
1533
|
+
JOIN operations_collaborator c ON c.id = pa.collaborator_id
|
|
1534
|
+
WHERE pa.project_id = $1
|
|
1535
|
+
AND pa.deleted_at IS NULL
|
|
1536
1536
|
ORDER BY c.display_name ASC`, [projectId]),
|
|
1537
1537
|
project.contractId
|
|
1538
|
-
? this.querySingle(`SELECT id,
|
|
1539
|
-
code,
|
|
1540
|
-
name,
|
|
1541
|
-
client_name AS "clientName",
|
|
1542
|
-
contract_category AS "contractCategory",
|
|
1543
|
-
billing_model AS "billingModel",
|
|
1544
|
-
status,
|
|
1545
|
-
start_date AS "startDate",
|
|
1546
|
-
end_date AS "endDate",
|
|
1547
|
-
budget_amount AS "budgetAmount",
|
|
1548
|
-
monthly_hour_cap AS "monthlyHourCap",
|
|
1549
|
-
description,
|
|
1550
|
-
origin_type AS "originType",
|
|
1551
|
-
origin_id AS "originId"
|
|
1552
|
-
FROM operations_contract
|
|
1553
|
-
WHERE id = $1
|
|
1538
|
+
? this.querySingle(`SELECT id,
|
|
1539
|
+
code,
|
|
1540
|
+
name,
|
|
1541
|
+
client_name AS "clientName",
|
|
1542
|
+
contract_category AS "contractCategory",
|
|
1543
|
+
billing_model AS "billingModel",
|
|
1544
|
+
status,
|
|
1545
|
+
start_date AS "startDate",
|
|
1546
|
+
end_date AS "endDate",
|
|
1547
|
+
budget_amount AS "budgetAmount",
|
|
1548
|
+
monthly_hour_cap AS "monthlyHourCap",
|
|
1549
|
+
description,
|
|
1550
|
+
origin_type AS "originType",
|
|
1551
|
+
origin_id AS "originId"
|
|
1552
|
+
FROM operations_contract
|
|
1553
|
+
WHERE id = $1
|
|
1554
1554
|
AND deleted_at IS NULL`, [project.contractId])
|
|
1555
1555
|
: Promise.resolve(null),
|
|
1556
|
-
this.querySingle(`SELECT COUNT(DISTINCT t.id)::text AS "totalTimesheets",
|
|
1557
|
-
COUNT(DISTINCT t.id) FILTER (WHERE t.status = 'submitted')::text AS "pendingTimesheets",
|
|
1558
|
-
COALESCE(SUM(e.hours), 0)::text AS "totalHours"
|
|
1559
|
-
FROM operations_project_assignment pa
|
|
1560
|
-
LEFT JOIN operations_timesheet_entry e
|
|
1561
|
-
ON e.project_assignment_id = pa.id
|
|
1562
|
-
AND e.deleted_at IS NULL
|
|
1563
|
-
LEFT JOIN operations_timesheet t
|
|
1564
|
-
ON t.id = e.timesheet_id
|
|
1565
|
-
AND t.deleted_at IS NULL
|
|
1566
|
-
WHERE pa.project_id = $1
|
|
1556
|
+
this.querySingle(`SELECT COUNT(DISTINCT t.id)::text AS "totalTimesheets",
|
|
1557
|
+
COUNT(DISTINCT t.id) FILTER (WHERE t.status = 'submitted')::text AS "pendingTimesheets",
|
|
1558
|
+
COALESCE(SUM(e.hours), 0)::text AS "totalHours"
|
|
1559
|
+
FROM operations_project_assignment pa
|
|
1560
|
+
LEFT JOIN operations_timesheet_entry e
|
|
1561
|
+
ON e.project_assignment_id = pa.id
|
|
1562
|
+
AND e.deleted_at IS NULL
|
|
1563
|
+
LEFT JOIN operations_timesheet t
|
|
1564
|
+
ON t.id = e.timesheet_id
|
|
1565
|
+
AND t.deleted_at IS NULL
|
|
1566
|
+
WHERE pa.project_id = $1
|
|
1567
1567
|
AND pa.deleted_at IS NULL`, [projectId]),
|
|
1568
|
-
this.querySingle(`SELECT COUNT(*) FILTER (WHERE status IN ('planned', 'active'))::text AS "activeAssignments",
|
|
1569
|
-
COUNT(*) FILTER (WHERE is_billable = true AND status IN ('planned', 'active'))::text AS "billableAssignments",
|
|
1570
|
-
COALESCE(AVG(allocation_percent), 0)::text AS "averageAllocation",
|
|
1571
|
-
COALESCE(SUM(weekly_hours), 0)::text AS "totalWeeklyHours"
|
|
1572
|
-
FROM operations_project_assignment
|
|
1573
|
-
WHERE project_id = $1
|
|
1568
|
+
this.querySingle(`SELECT COUNT(*) FILTER (WHERE status IN ('planned', 'active'))::text AS "activeAssignments",
|
|
1569
|
+
COUNT(*) FILTER (WHERE is_billable = true AND status IN ('planned', 'active'))::text AS "billableAssignments",
|
|
1570
|
+
COALESCE(AVG(allocation_percent), 0)::text AS "averageAllocation",
|
|
1571
|
+
COALESCE(SUM(weekly_hours), 0)::text AS "totalWeeklyHours"
|
|
1572
|
+
FROM operations_project_assignment
|
|
1573
|
+
WHERE project_id = $1
|
|
1574
1574
|
AND deleted_at IS NULL`, [projectId]),
|
|
1575
1575
|
]);
|
|
1576
1576
|
return Object.assign(Object.assign({}, project), { assignments,
|
|
@@ -1587,110 +1587,110 @@ let OperationsService = class OperationsService {
|
|
|
1587
1587
|
}
|
|
1588
1588
|
async getCollaboratorDetails(collaboratorId) {
|
|
1589
1589
|
var _a, _b, _c, _d, _e, _f;
|
|
1590
|
-
const collaborator = await this.querySingle(`SELECT c.id,
|
|
1591
|
-
c.user_id AS "userId",
|
|
1592
|
-
c.code,
|
|
1593
|
-
c.collaborator_type AS "collaboratorType",
|
|
1594
|
-
c.display_name AS "displayName",
|
|
1595
|
-
c.department,
|
|
1596
|
-
c.title,
|
|
1597
|
-
c.level_label AS "levelLabel",
|
|
1598
|
-
c.weekly_capacity_hours AS "weeklyCapacityHours",
|
|
1599
|
-
c.status,
|
|
1600
|
-
c.joined_at AS "joinedAt",
|
|
1601
|
-
c.left_at AS "leftAt",
|
|
1602
|
-
c.notes,
|
|
1603
|
-
s.id AS "supervisorId",
|
|
1604
|
-
s.display_name AS "supervisorName",
|
|
1605
|
-
hiring_contract.id AS "contractId",
|
|
1606
|
-
hiring_contract.status AS "contractStatus",
|
|
1607
|
-
COUNT(DISTINCT pa.id)::int AS "activeAssignments"
|
|
1608
|
-
FROM operations_collaborator c
|
|
1609
|
-
LEFT JOIN operations_collaborator s
|
|
1610
|
-
ON s.id = c.supervisor_collaborator_id
|
|
1611
|
-
LEFT JOIN operations_project_assignment pa
|
|
1612
|
-
ON pa.collaborator_id = c.id
|
|
1613
|
-
AND pa.deleted_at IS NULL
|
|
1614
|
-
AND pa.status IN ('planned', 'active')
|
|
1615
|
-
LEFT JOIN LATERAL (
|
|
1616
|
-
SELECT oc.id, oc.status
|
|
1617
|
-
FROM operations_contract oc
|
|
1618
|
-
WHERE oc.related_collaborator_id = c.id
|
|
1619
|
-
AND oc.deleted_at IS NULL
|
|
1620
|
-
ORDER BY CASE WHEN oc.origin_type = 'employee_hiring' THEN 0 ELSE 1 END,
|
|
1621
|
-
oc.created_at DESC
|
|
1622
|
-
LIMIT 1
|
|
1623
|
-
) hiring_contract ON TRUE
|
|
1624
|
-
WHERE c.id = $1
|
|
1625
|
-
AND c.deleted_at IS NULL
|
|
1590
|
+
const collaborator = await this.querySingle(`SELECT c.id,
|
|
1591
|
+
c.user_id AS "userId",
|
|
1592
|
+
c.code,
|
|
1593
|
+
c.collaborator_type AS "collaboratorType",
|
|
1594
|
+
c.display_name AS "displayName",
|
|
1595
|
+
c.department,
|
|
1596
|
+
c.title,
|
|
1597
|
+
c.level_label AS "levelLabel",
|
|
1598
|
+
c.weekly_capacity_hours AS "weeklyCapacityHours",
|
|
1599
|
+
c.status,
|
|
1600
|
+
c.joined_at AS "joinedAt",
|
|
1601
|
+
c.left_at AS "leftAt",
|
|
1602
|
+
c.notes,
|
|
1603
|
+
s.id AS "supervisorId",
|
|
1604
|
+
s.display_name AS "supervisorName",
|
|
1605
|
+
hiring_contract.id AS "contractId",
|
|
1606
|
+
hiring_contract.status AS "contractStatus",
|
|
1607
|
+
COUNT(DISTINCT pa.id)::int AS "activeAssignments"
|
|
1608
|
+
FROM operations_collaborator c
|
|
1609
|
+
LEFT JOIN operations_collaborator s
|
|
1610
|
+
ON s.id = c.supervisor_collaborator_id
|
|
1611
|
+
LEFT JOIN operations_project_assignment pa
|
|
1612
|
+
ON pa.collaborator_id = c.id
|
|
1613
|
+
AND pa.deleted_at IS NULL
|
|
1614
|
+
AND pa.status IN ('planned', 'active')
|
|
1615
|
+
LEFT JOIN LATERAL (
|
|
1616
|
+
SELECT oc.id, oc.status
|
|
1617
|
+
FROM operations_contract oc
|
|
1618
|
+
WHERE oc.related_collaborator_id = c.id
|
|
1619
|
+
AND oc.deleted_at IS NULL
|
|
1620
|
+
ORDER BY CASE WHEN oc.origin_type = 'employee_hiring' THEN 0 ELSE 1 END,
|
|
1621
|
+
oc.created_at DESC
|
|
1622
|
+
LIMIT 1
|
|
1623
|
+
) hiring_contract ON TRUE
|
|
1624
|
+
WHERE c.id = $1
|
|
1625
|
+
AND c.deleted_at IS NULL
|
|
1626
1626
|
GROUP BY c.id, s.id, hiring_contract.id, hiring_contract.status`, [collaboratorId]);
|
|
1627
1627
|
if (!collaborator) {
|
|
1628
1628
|
throw new common_1.NotFoundException('Collaborator not found.');
|
|
1629
1629
|
}
|
|
1630
1630
|
const [assignedProjects, relatedContracts, weeklySchedule, timesheetSummary, timeOffSummary, scheduleAdjustmentRequests] = await Promise.all([
|
|
1631
|
-
this.queryRows(`SELECT p.id,
|
|
1632
|
-
p.code,
|
|
1633
|
-
p.name,
|
|
1634
|
-
p.status,
|
|
1635
|
-
pa.role_label AS "roleLabel",
|
|
1636
|
-
pa.allocation_percent AS "allocationPercent",
|
|
1637
|
-
pa.weekly_hours AS "weeklyHours",
|
|
1638
|
-
pa.start_date AS "startDate",
|
|
1639
|
-
pa.end_date AS "endDate"
|
|
1640
|
-
FROM operations_project_assignment pa
|
|
1641
|
-
JOIN operations_project p ON p.id = pa.project_id
|
|
1642
|
-
WHERE pa.collaborator_id = $1
|
|
1643
|
-
AND pa.deleted_at IS NULL
|
|
1644
|
-
AND p.deleted_at IS NULL
|
|
1631
|
+
this.queryRows(`SELECT p.id,
|
|
1632
|
+
p.code,
|
|
1633
|
+
p.name,
|
|
1634
|
+
p.status,
|
|
1635
|
+
pa.role_label AS "roleLabel",
|
|
1636
|
+
pa.allocation_percent AS "allocationPercent",
|
|
1637
|
+
pa.weekly_hours AS "weeklyHours",
|
|
1638
|
+
pa.start_date AS "startDate",
|
|
1639
|
+
pa.end_date AS "endDate"
|
|
1640
|
+
FROM operations_project_assignment pa
|
|
1641
|
+
JOIN operations_project p ON p.id = pa.project_id
|
|
1642
|
+
WHERE pa.collaborator_id = $1
|
|
1643
|
+
AND pa.deleted_at IS NULL
|
|
1644
|
+
AND p.deleted_at IS NULL
|
|
1645
1645
|
ORDER BY p.name ASC`, [collaboratorId]),
|
|
1646
|
-
this.queryRows(`SELECT c.id,
|
|
1647
|
-
c.code,
|
|
1648
|
-
c.name,
|
|
1649
|
-
c.contract_category AS "contractCategory",
|
|
1650
|
-
c.client_name AS "clientName",
|
|
1651
|
-
c.billing_model AS "billingModel",
|
|
1652
|
-
c.start_date AS "startDate",
|
|
1653
|
-
c.end_date AS "endDate",
|
|
1654
|
-
c.budget_amount AS "budgetAmount",
|
|
1655
|
-
c.monthly_hour_cap AS "monthlyHourCap",
|
|
1656
|
-
c.status,
|
|
1657
|
-
c.origin_type AS "originType",
|
|
1658
|
-
c.origin_id AS "originId",
|
|
1659
|
-
c.description
|
|
1660
|
-
FROM operations_contract c
|
|
1661
|
-
WHERE c.related_collaborator_id = $1
|
|
1662
|
-
AND c.deleted_at IS NULL
|
|
1646
|
+
this.queryRows(`SELECT c.id,
|
|
1647
|
+
c.code,
|
|
1648
|
+
c.name,
|
|
1649
|
+
c.contract_category AS "contractCategory",
|
|
1650
|
+
c.client_name AS "clientName",
|
|
1651
|
+
c.billing_model AS "billingModel",
|
|
1652
|
+
c.start_date AS "startDate",
|
|
1653
|
+
c.end_date AS "endDate",
|
|
1654
|
+
c.budget_amount AS "budgetAmount",
|
|
1655
|
+
c.monthly_hour_cap AS "monthlyHourCap",
|
|
1656
|
+
c.status,
|
|
1657
|
+
c.origin_type AS "originType",
|
|
1658
|
+
c.origin_id AS "originId",
|
|
1659
|
+
c.description
|
|
1660
|
+
FROM operations_contract c
|
|
1661
|
+
WHERE c.related_collaborator_id = $1
|
|
1662
|
+
AND c.deleted_at IS NULL
|
|
1663
1663
|
ORDER BY c.created_at DESC`, [collaboratorId]),
|
|
1664
|
-
this.queryRows(`SELECT weekday,
|
|
1665
|
-
is_working_day AS "isWorkingDay",
|
|
1666
|
-
start_time AS "startTime",
|
|
1667
|
-
end_time AS "endTime",
|
|
1668
|
-
break_minutes AS "breakMinutes"
|
|
1669
|
-
FROM operations_collaborator_schedule_day
|
|
1670
|
-
WHERE collaborator_id = $1
|
|
1671
|
-
AND deleted_at IS NULL
|
|
1664
|
+
this.queryRows(`SELECT weekday,
|
|
1665
|
+
is_working_day AS "isWorkingDay",
|
|
1666
|
+
start_time AS "startTime",
|
|
1667
|
+
end_time AS "endTime",
|
|
1668
|
+
break_minutes AS "breakMinutes"
|
|
1669
|
+
FROM operations_collaborator_schedule_day
|
|
1670
|
+
WHERE collaborator_id = $1
|
|
1671
|
+
AND deleted_at IS NULL
|
|
1672
1672
|
ORDER BY id ASC`, [collaboratorId]),
|
|
1673
|
-
this.querySingle(`SELECT COUNT(*)::text AS "totalTimesheets",
|
|
1674
|
-
COUNT(*) FILTER (WHERE status = 'submitted')::text AS "pendingTimesheets",
|
|
1675
|
-
COALESCE(SUM(total_hours), 0)::text AS "totalHours"
|
|
1676
|
-
FROM operations_timesheet
|
|
1677
|
-
WHERE collaborator_id = $1
|
|
1673
|
+
this.querySingle(`SELECT COUNT(*)::text AS "totalTimesheets",
|
|
1674
|
+
COUNT(*) FILTER (WHERE status = 'submitted')::text AS "pendingTimesheets",
|
|
1675
|
+
COALESCE(SUM(total_hours), 0)::text AS "totalHours"
|
|
1676
|
+
FROM operations_timesheet
|
|
1677
|
+
WHERE collaborator_id = $1
|
|
1678
1678
|
AND deleted_at IS NULL`, [collaboratorId]),
|
|
1679
|
-
this.querySingle(`SELECT COUNT(*)::text AS "totalRequests",
|
|
1680
|
-
COUNT(*) FILTER (WHERE status = 'submitted')::text AS "pendingRequests",
|
|
1681
|
-
COUNT(*) FILTER (WHERE status = 'approved')::text AS "approvedRequests"
|
|
1682
|
-
FROM operations_time_off_request
|
|
1683
|
-
WHERE collaborator_id = $1
|
|
1679
|
+
this.querySingle(`SELECT COUNT(*)::text AS "totalRequests",
|
|
1680
|
+
COUNT(*) FILTER (WHERE status = 'submitted')::text AS "pendingRequests",
|
|
1681
|
+
COUNT(*) FILTER (WHERE status = 'approved')::text AS "approvedRequests"
|
|
1682
|
+
FROM operations_time_off_request
|
|
1683
|
+
WHERE collaborator_id = $1
|
|
1684
1684
|
AND deleted_at IS NULL`, [collaboratorId]),
|
|
1685
|
-
this.queryRows(`SELECT id,
|
|
1686
|
-
request_scope AS "requestScope",
|
|
1687
|
-
effective_start_date AS "effectiveStartDate",
|
|
1688
|
-
effective_end_date AS "effectiveEndDate",
|
|
1689
|
-
status,
|
|
1690
|
-
reason
|
|
1691
|
-
FROM operations_schedule_adjustment_request
|
|
1692
|
-
WHERE collaborator_id = $1
|
|
1693
|
-
AND deleted_at IS NULL
|
|
1685
|
+
this.queryRows(`SELECT id,
|
|
1686
|
+
request_scope AS "requestScope",
|
|
1687
|
+
effective_start_date AS "effectiveStartDate",
|
|
1688
|
+
effective_end_date AS "effectiveEndDate",
|
|
1689
|
+
status,
|
|
1690
|
+
reason
|
|
1691
|
+
FROM operations_schedule_adjustment_request
|
|
1692
|
+
WHERE collaborator_id = $1
|
|
1693
|
+
AND deleted_at IS NULL
|
|
1694
1694
|
ORDER BY effective_start_date DESC, id DESC`, [collaboratorId]),
|
|
1695
1695
|
]);
|
|
1696
1696
|
return Object.assign(Object.assign({}, collaborator), { assignedProjects,
|
|
@@ -1706,28 +1706,28 @@ let OperationsService = class OperationsService {
|
|
|
1706
1706
|
}, scheduleAdjustmentRequests });
|
|
1707
1707
|
}
|
|
1708
1708
|
async getDirectReportIds(collaboratorId) {
|
|
1709
|
-
return (await this.queryRows(`SELECT id
|
|
1710
|
-
FROM operations_collaborator
|
|
1711
|
-
WHERE supervisor_collaborator_id = $1
|
|
1712
|
-
AND deleted_at IS NULL
|
|
1709
|
+
return (await this.queryRows(`SELECT id
|
|
1710
|
+
FROM operations_collaborator
|
|
1711
|
+
WHERE supervisor_collaborator_id = $1
|
|
1712
|
+
AND deleted_at IS NULL
|
|
1713
1713
|
ORDER BY id ASC`, [collaboratorId])).map((row) => row.id);
|
|
1714
1714
|
}
|
|
1715
1715
|
async getAssignedProjectIds(collaboratorIds) {
|
|
1716
1716
|
if (!collaboratorIds.length)
|
|
1717
1717
|
return [];
|
|
1718
|
-
return (await this.queryRows(`SELECT DISTINCT project_id AS "projectId"
|
|
1719
|
-
FROM operations_project_assignment
|
|
1720
|
-
WHERE deleted_at IS NULL
|
|
1721
|
-
AND status IN ('planned', 'active')
|
|
1718
|
+
return (await this.queryRows(`SELECT DISTINCT project_id AS "projectId"
|
|
1719
|
+
FROM operations_project_assignment
|
|
1720
|
+
WHERE deleted_at IS NULL
|
|
1721
|
+
AND status IN ('planned', 'active')
|
|
1722
1722
|
AND collaborator_id = ANY($1::int[])`, [collaboratorIds])).map((row) => row.projectId);
|
|
1723
1723
|
}
|
|
1724
1724
|
async getTimesheetById(timesheetId) {
|
|
1725
|
-
const timesheet = await this.querySingle(`SELECT id,
|
|
1726
|
-
collaborator_id AS "collaboratorId",
|
|
1727
|
-
approver_collaborator_id AS "approverCollaboratorId",
|
|
1728
|
-
status
|
|
1729
|
-
FROM operations_timesheet
|
|
1730
|
-
WHERE id = $1
|
|
1725
|
+
const timesheet = await this.querySingle(`SELECT id,
|
|
1726
|
+
collaborator_id AS "collaboratorId",
|
|
1727
|
+
approver_collaborator_id AS "approverCollaboratorId",
|
|
1728
|
+
status
|
|
1729
|
+
FROM operations_timesheet
|
|
1730
|
+
WHERE id = $1
|
|
1731
1731
|
AND deleted_at IS NULL`, [timesheetId]);
|
|
1732
1732
|
if (!timesheet) {
|
|
1733
1733
|
throw new common_1.NotFoundException('Timesheet not found.');
|
|
@@ -1736,9 +1736,9 @@ let OperationsService = class OperationsService {
|
|
|
1736
1736
|
}
|
|
1737
1737
|
async replaceTimesheetEntries(client, timesheetId, entries, collaboratorId) {
|
|
1738
1738
|
var _a, _b, _c;
|
|
1739
|
-
await client.$executeRawUnsafe(`UPDATE operations_timesheet_entry
|
|
1740
|
-
SET deleted_at = NOW()
|
|
1741
|
-
WHERE timesheet_id = $1
|
|
1739
|
+
await client.$executeRawUnsafe(`UPDATE operations_timesheet_entry
|
|
1740
|
+
SET deleted_at = NOW()
|
|
1741
|
+
WHERE timesheet_id = $1
|
|
1742
1742
|
AND deleted_at IS NULL`, timesheetId);
|
|
1743
1743
|
if (!entries.length)
|
|
1744
1744
|
return;
|
|
@@ -1746,9 +1746,9 @@ let OperationsService = class OperationsService {
|
|
|
1746
1746
|
.map((entry) => entry.projectAssignmentId)
|
|
1747
1747
|
.filter((value) => typeof value === 'number');
|
|
1748
1748
|
if (assignmentIds.length) {
|
|
1749
|
-
const assignments = (await client.$queryRawUnsafe(`SELECT id, collaborator_id AS "collaboratorId"
|
|
1750
|
-
FROM operations_project_assignment
|
|
1751
|
-
WHERE id = ANY($1::int[])
|
|
1749
|
+
const assignments = (await client.$queryRawUnsafe(`SELECT id, collaborator_id AS "collaboratorId"
|
|
1750
|
+
FROM operations_project_assignment
|
|
1751
|
+
WHERE id = ANY($1::int[])
|
|
1752
1752
|
AND deleted_at IS NULL`, assignmentIds));
|
|
1753
1753
|
const assignmentMap = new Map(assignments.map((assignment) => [
|
|
1754
1754
|
assignment.id,
|
|
@@ -1761,73 +1761,73 @@ let OperationsService = class OperationsService {
|
|
|
1761
1761
|
}
|
|
1762
1762
|
}
|
|
1763
1763
|
for (const entry of entries) {
|
|
1764
|
-
await client.$executeRawUnsafe(`INSERT INTO operations_timesheet_entry (
|
|
1765
|
-
timesheet_id,
|
|
1766
|
-
project_assignment_id,
|
|
1767
|
-
activity_label,
|
|
1768
|
-
work_date,
|
|
1769
|
-
hours,
|
|
1770
|
-
description,
|
|
1771
|
-
created_at,
|
|
1772
|
-
updated_at
|
|
1764
|
+
await client.$executeRawUnsafe(`INSERT INTO operations_timesheet_entry (
|
|
1765
|
+
timesheet_id,
|
|
1766
|
+
project_assignment_id,
|
|
1767
|
+
activity_label,
|
|
1768
|
+
work_date,
|
|
1769
|
+
hours,
|
|
1770
|
+
description,
|
|
1771
|
+
created_at,
|
|
1772
|
+
updated_at
|
|
1773
1773
|
) VALUES ($1, $2, $3, $4, $5, $6, NOW(), NOW())`, timesheetId, (_a = entry.projectAssignmentId) !== null && _a !== void 0 ? _a : null, (_b = entry.activityLabel) !== null && _b !== void 0 ? _b : null, entry.workDate, entry.hours, (_c = entry.description) !== null && _c !== void 0 ? _c : null);
|
|
1774
1774
|
}
|
|
1775
1775
|
}
|
|
1776
1776
|
async refreshTimesheetTotal(client, timesheetId) {
|
|
1777
|
-
await client.$executeRawUnsafe(`UPDATE operations_timesheet
|
|
1778
|
-
SET total_hours = (
|
|
1779
|
-
SELECT COALESCE(SUM(hours), 0)
|
|
1780
|
-
FROM operations_timesheet_entry
|
|
1781
|
-
WHERE timesheet_id = $1
|
|
1782
|
-
AND deleted_at IS NULL
|
|
1783
|
-
),
|
|
1784
|
-
updated_at = NOW()
|
|
1777
|
+
await client.$executeRawUnsafe(`UPDATE operations_timesheet
|
|
1778
|
+
SET total_hours = (
|
|
1779
|
+
SELECT COALESCE(SUM(hours), 0)
|
|
1780
|
+
FROM operations_timesheet_entry
|
|
1781
|
+
WHERE timesheet_id = $1
|
|
1782
|
+
AND deleted_at IS NULL
|
|
1783
|
+
),
|
|
1784
|
+
updated_at = NOW()
|
|
1785
1785
|
WHERE id = $1`, timesheetId);
|
|
1786
1786
|
}
|
|
1787
1787
|
async upsertApproval(client, input) {
|
|
1788
1788
|
var _a, _b;
|
|
1789
|
-
const existing = (await client.$queryRawUnsafe(`SELECT id
|
|
1790
|
-
FROM operations_approval
|
|
1791
|
-
WHERE target_type = $1
|
|
1792
|
-
AND target_id = $2
|
|
1789
|
+
const existing = (await client.$queryRawUnsafe(`SELECT id
|
|
1790
|
+
FROM operations_approval
|
|
1791
|
+
WHERE target_type = $1
|
|
1792
|
+
AND target_id = $2
|
|
1793
1793
|
AND deleted_at IS NULL`, input.targetType, input.targetId));
|
|
1794
1794
|
let approvalId = (_a = existing[0]) === null || _a === void 0 ? void 0 : _a.id;
|
|
1795
1795
|
if (!approvalId) {
|
|
1796
|
-
const created = (await client.$queryRawUnsafe(`INSERT INTO operations_approval (
|
|
1797
|
-
target_type,
|
|
1798
|
-
target_id,
|
|
1799
|
-
requester_collaborator_id,
|
|
1800
|
-
approver_collaborator_id,
|
|
1801
|
-
status,
|
|
1802
|
-
submitted_at,
|
|
1803
|
-
created_at,
|
|
1804
|
-
updated_at
|
|
1805
|
-
) VALUES ($1, $2, $3, $4, 'pending', NOW(), NOW(), NOW())
|
|
1796
|
+
const created = (await client.$queryRawUnsafe(`INSERT INTO operations_approval (
|
|
1797
|
+
target_type,
|
|
1798
|
+
target_id,
|
|
1799
|
+
requester_collaborator_id,
|
|
1800
|
+
approver_collaborator_id,
|
|
1801
|
+
status,
|
|
1802
|
+
submitted_at,
|
|
1803
|
+
created_at,
|
|
1804
|
+
updated_at
|
|
1805
|
+
) VALUES ($1, $2, $3, $4, 'pending', NOW(), NOW(), NOW())
|
|
1806
1806
|
RETURNING id`, input.targetType, input.targetId, input.requesterCollaboratorId, input.approverCollaboratorId));
|
|
1807
1807
|
approvalId = (_b = created[0]) === null || _b === void 0 ? void 0 : _b.id;
|
|
1808
1808
|
await this.insertApprovalHistory(client, approvalId, input.requesterCollaboratorId, 'created', null);
|
|
1809
1809
|
}
|
|
1810
1810
|
else {
|
|
1811
|
-
await client.$executeRawUnsafe(`UPDATE operations_approval
|
|
1812
|
-
SET requester_collaborator_id = $1,
|
|
1813
|
-
approver_collaborator_id = $2,
|
|
1814
|
-
status = 'pending',
|
|
1815
|
-
submitted_at = NOW(),
|
|
1816
|
-
decided_at = NULL,
|
|
1817
|
-
decision_note = NULL,
|
|
1818
|
-
updated_at = NOW()
|
|
1811
|
+
await client.$executeRawUnsafe(`UPDATE operations_approval
|
|
1812
|
+
SET requester_collaborator_id = $1,
|
|
1813
|
+
approver_collaborator_id = $2,
|
|
1814
|
+
status = 'pending',
|
|
1815
|
+
submitted_at = NOW(),
|
|
1816
|
+
decided_at = NULL,
|
|
1817
|
+
decision_note = NULL,
|
|
1818
|
+
updated_at = NOW()
|
|
1819
1819
|
WHERE id = $3`, input.requesterCollaboratorId, input.approverCollaboratorId, approvalId);
|
|
1820
1820
|
await this.insertApprovalHistory(client, approvalId, input.requesterCollaboratorId, 'reopened', null);
|
|
1821
1821
|
}
|
|
1822
1822
|
await this.insertApprovalHistory(client, approvalId, input.requesterCollaboratorId, 'submitted', null);
|
|
1823
1823
|
}
|
|
1824
1824
|
async insertApprovalHistory(client, approvalId, actorCollaboratorId, action, note) {
|
|
1825
|
-
await client.$executeRawUnsafe(`INSERT INTO operations_approval_history (
|
|
1826
|
-
approval_id,
|
|
1827
|
-
actor_collaborator_id,
|
|
1828
|
-
action,
|
|
1829
|
-
note,
|
|
1830
|
-
created_at
|
|
1825
|
+
await client.$executeRawUnsafe(`INSERT INTO operations_approval_history (
|
|
1826
|
+
approval_id,
|
|
1827
|
+
actor_collaborator_id,
|
|
1828
|
+
action,
|
|
1829
|
+
note,
|
|
1830
|
+
created_at
|
|
1831
1831
|
) VALUES ($1, $2, $3, $4, NOW())`, approvalId, actorCollaboratorId, action, note);
|
|
1832
1832
|
}
|
|
1833
1833
|
async assertProjectAccess(actor, projectId) {
|
|
@@ -1926,46 +1926,46 @@ let OperationsService = class OperationsService {
|
|
|
1926
1926
|
const schedule = (weeklySchedule === null || weeklySchedule === void 0 ? void 0 : weeklySchedule.length)
|
|
1927
1927
|
? weeklySchedule
|
|
1928
1928
|
: this.defaultWeeklySchedule();
|
|
1929
|
-
await client.$executeRawUnsafe(`UPDATE operations_collaborator_schedule_day
|
|
1930
|
-
SET deleted_at = NOW(),
|
|
1931
|
-
updated_at = NOW()
|
|
1932
|
-
WHERE collaborator_id = $1
|
|
1929
|
+
await client.$executeRawUnsafe(`UPDATE operations_collaborator_schedule_day
|
|
1930
|
+
SET deleted_at = NOW(),
|
|
1931
|
+
updated_at = NOW()
|
|
1932
|
+
WHERE collaborator_id = $1
|
|
1933
1933
|
AND deleted_at IS NULL`, collaboratorId);
|
|
1934
1934
|
for (const day of schedule) {
|
|
1935
|
-
await client.$executeRawUnsafe(`INSERT INTO operations_collaborator_schedule_day (
|
|
1936
|
-
collaborator_id,
|
|
1937
|
-
weekday,
|
|
1938
|
-
is_working_day,
|
|
1939
|
-
start_time,
|
|
1940
|
-
end_time,
|
|
1941
|
-
break_minutes,
|
|
1942
|
-
created_at,
|
|
1943
|
-
updated_at
|
|
1935
|
+
await client.$executeRawUnsafe(`INSERT INTO operations_collaborator_schedule_day (
|
|
1936
|
+
collaborator_id,
|
|
1937
|
+
weekday,
|
|
1938
|
+
is_working_day,
|
|
1939
|
+
start_time,
|
|
1940
|
+
end_time,
|
|
1941
|
+
break_minutes,
|
|
1942
|
+
created_at,
|
|
1943
|
+
updated_at
|
|
1944
1944
|
) VALUES ($1, $2, $3, $4, $5, $6, NOW(), NOW())`, collaboratorId, day.weekday, (_a = day.isWorkingDay) !== null && _a !== void 0 ? _a : true, day.isWorkingDay === false ? null : (_b = day.startTime) !== null && _b !== void 0 ? _b : null, day.isWorkingDay === false ? null : (_c = day.endTime) !== null && _c !== void 0 ? _c : null, (_d = day.breakMinutes) !== null && _d !== void 0 ? _d : null);
|
|
1945
1945
|
}
|
|
1946
1946
|
}
|
|
1947
1947
|
async replaceProjectAssignments(client, projectId, teamAssignments) {
|
|
1948
1948
|
var _a, _b, _c, _d, _e, _f, _g;
|
|
1949
|
-
await client.$executeRawUnsafe(`UPDATE operations_project_assignment
|
|
1950
|
-
SET deleted_at = NOW(),
|
|
1951
|
-
updated_at = NOW()
|
|
1952
|
-
WHERE project_id = $1
|
|
1949
|
+
await client.$executeRawUnsafe(`UPDATE operations_project_assignment
|
|
1950
|
+
SET deleted_at = NOW(),
|
|
1951
|
+
updated_at = NOW()
|
|
1952
|
+
WHERE project_id = $1
|
|
1953
1953
|
AND deleted_at IS NULL`, projectId);
|
|
1954
1954
|
for (const assignment of teamAssignments !== null && teamAssignments !== void 0 ? teamAssignments : []) {
|
|
1955
|
-
await client.$executeRawUnsafe(`INSERT INTO operations_project_assignment (
|
|
1956
|
-
project_id,
|
|
1957
|
-
collaborator_id,
|
|
1958
|
-
role_label,
|
|
1959
|
-
allocation_percent,
|
|
1960
|
-
weekly_hours,
|
|
1961
|
-
is_billable,
|
|
1962
|
-
start_date,
|
|
1963
|
-
end_date,
|
|
1964
|
-
status,
|
|
1965
|
-
created_at,
|
|
1966
|
-
updated_at
|
|
1967
|
-
) VALUES (
|
|
1968
|
-
$1, $2, $3, $4, $5, $6, $7, $8, COALESCE($9, 'active'), NOW(), NOW()
|
|
1955
|
+
await client.$executeRawUnsafe(`INSERT INTO operations_project_assignment (
|
|
1956
|
+
project_id,
|
|
1957
|
+
collaborator_id,
|
|
1958
|
+
role_label,
|
|
1959
|
+
allocation_percent,
|
|
1960
|
+
weekly_hours,
|
|
1961
|
+
is_billable,
|
|
1962
|
+
start_date,
|
|
1963
|
+
end_date,
|
|
1964
|
+
status,
|
|
1965
|
+
created_at,
|
|
1966
|
+
updated_at
|
|
1967
|
+
) VALUES (
|
|
1968
|
+
$1, $2, $3, $4, $5, $6, $7, $8, COALESCE($9, 'active'), NOW(), NOW()
|
|
1969
1969
|
)`, projectId, assignment.collaboratorId, (_a = assignment.roleLabel) !== null && _a !== void 0 ? _a : 'Team Member', (_b = assignment.allocationPercent) !== null && _b !== void 0 ? _b : null, (_c = assignment.weeklyHours) !== null && _c !== void 0 ? _c : null, (_d = assignment.isBillable) !== null && _d !== void 0 ? _d : true, (_e = assignment.startDate) !== null && _e !== void 0 ? _e : null, (_f = assignment.endDate) !== null && _f !== void 0 ? _f : null, (_g = assignment.status) !== null && _g !== void 0 ? _g : 'active');
|
|
1970
1970
|
}
|
|
1971
1971
|
}
|
|
@@ -2005,197 +2005,197 @@ let OperationsService = class OperationsService {
|
|
|
2005
2005
|
const contractName = input.collaboratorType === 'clt'
|
|
2006
2006
|
? `${input.displayName} Employment Contract`
|
|
2007
2007
|
: `${input.displayName} Service Contract`;
|
|
2008
|
-
await client.$executeRawUnsafe(`INSERT INTO operations_contract (
|
|
2009
|
-
code,
|
|
2010
|
-
name,
|
|
2011
|
-
contract_category,
|
|
2012
|
-
contract_type,
|
|
2013
|
-
client_name,
|
|
2014
|
-
signature_status,
|
|
2015
|
-
is_active,
|
|
2016
|
-
billing_model,
|
|
2017
|
-
account_manager_collaborator_id,
|
|
2018
|
-
related_collaborator_id,
|
|
2019
|
-
origin_type,
|
|
2020
|
-
origin_id,
|
|
2021
|
-
start_date,
|
|
2022
|
-
end_date,
|
|
2023
|
-
signed_at,
|
|
2024
|
-
effective_date,
|
|
2025
|
-
budget_amount,
|
|
2026
|
-
monthly_hour_cap,
|
|
2027
|
-
status,
|
|
2028
|
-
description,
|
|
2029
|
-
content_html,
|
|
2030
|
-
created_by_user_id,
|
|
2031
|
-
updated_by_user_id,
|
|
2032
|
-
created_at,
|
|
2033
|
-
updated_at
|
|
2034
|
-
) VALUES (
|
|
2035
|
-
$1, $2, $3, $4, $5, 'not_started', true, $6, $7, $8, 'employee_hiring', $9, $10, NULL,
|
|
2036
|
-
NULL, $10, $11, $12, 'draft', $13, NULL, $14, $14, NOW(), NOW()
|
|
2008
|
+
await client.$executeRawUnsafe(`INSERT INTO operations_contract (
|
|
2009
|
+
code,
|
|
2010
|
+
name,
|
|
2011
|
+
contract_category,
|
|
2012
|
+
contract_type,
|
|
2013
|
+
client_name,
|
|
2014
|
+
signature_status,
|
|
2015
|
+
is_active,
|
|
2016
|
+
billing_model,
|
|
2017
|
+
account_manager_collaborator_id,
|
|
2018
|
+
related_collaborator_id,
|
|
2019
|
+
origin_type,
|
|
2020
|
+
origin_id,
|
|
2021
|
+
start_date,
|
|
2022
|
+
end_date,
|
|
2023
|
+
signed_at,
|
|
2024
|
+
effective_date,
|
|
2025
|
+
budget_amount,
|
|
2026
|
+
monthly_hour_cap,
|
|
2027
|
+
status,
|
|
2028
|
+
description,
|
|
2029
|
+
content_html,
|
|
2030
|
+
created_by_user_id,
|
|
2031
|
+
updated_by_user_id,
|
|
2032
|
+
created_at,
|
|
2033
|
+
updated_at
|
|
2034
|
+
) VALUES (
|
|
2035
|
+
$1, $2, $3, $4, $5, 'not_started', true, $6, $7, $8, 'employee_hiring', $9, $10, NULL,
|
|
2036
|
+
NULL, $10, $11, $12, 'draft', $13, NULL, $14, $14, NOW(), NOW()
|
|
2037
2037
|
)`, contractCode, contractName, this.mapContractCategoryForCollaboratorType(input.collaboratorType), this.mapContractTypeForCollaboratorType(input.collaboratorType), input.displayName, this.mapBillingModelForCollaboratorType(input.collaboratorType), input.supervisorCollaboratorId, input.collaboratorId, input.collaboratorId, (_a = input.startDate) !== null && _a !== void 0 ? _a : new Date().toISOString().slice(0, 10), (_b = input.compensationAmount) !== null && _b !== void 0 ? _b : null, input.weeklyCapacityHours
|
|
2038
2038
|
? Math.round(Number(input.weeklyCapacityHours) * 4)
|
|
2039
2039
|
: null, (_c = input.description) !== null && _c !== void 0 ? _c : null, createdByUserId);
|
|
2040
2040
|
}
|
|
2041
2041
|
async createProjectContractDraft(client, createdByUserId, input) {
|
|
2042
2042
|
var _a, _b, _c, _d, _e, _f, _g, _h;
|
|
2043
|
-
const created = await client.$queryRawUnsafe(`INSERT INTO operations_contract (
|
|
2044
|
-
code,
|
|
2045
|
-
name,
|
|
2046
|
-
contract_category,
|
|
2047
|
-
contract_type,
|
|
2048
|
-
client_name,
|
|
2049
|
-
signature_status,
|
|
2050
|
-
is_active,
|
|
2051
|
-
billing_model,
|
|
2052
|
-
account_manager_collaborator_id,
|
|
2053
|
-
related_collaborator_id,
|
|
2054
|
-
origin_type,
|
|
2055
|
-
origin_id,
|
|
2056
|
-
start_date,
|
|
2057
|
-
end_date,
|
|
2058
|
-
signed_at,
|
|
2059
|
-
effective_date,
|
|
2060
|
-
budget_amount,
|
|
2061
|
-
monthly_hour_cap,
|
|
2062
|
-
status,
|
|
2063
|
-
description,
|
|
2064
|
-
content_html,
|
|
2065
|
-
created_by_user_id,
|
|
2066
|
-
updated_by_user_id,
|
|
2067
|
-
created_at,
|
|
2068
|
-
updated_at
|
|
2069
|
-
) VALUES (
|
|
2070
|
-
$1, $2, 'client', 'service_agreement', $3, 'not_started', true, $4, $5, NULL, 'client_project', $6,
|
|
2071
|
-
$7, $8, NULL, $7, $9, $10, 'draft', $11, NULL, $12, $12, NOW(), NOW()
|
|
2072
|
-
)
|
|
2043
|
+
const created = await client.$queryRawUnsafe(`INSERT INTO operations_contract (
|
|
2044
|
+
code,
|
|
2045
|
+
name,
|
|
2046
|
+
contract_category,
|
|
2047
|
+
contract_type,
|
|
2048
|
+
client_name,
|
|
2049
|
+
signature_status,
|
|
2050
|
+
is_active,
|
|
2051
|
+
billing_model,
|
|
2052
|
+
account_manager_collaborator_id,
|
|
2053
|
+
related_collaborator_id,
|
|
2054
|
+
origin_type,
|
|
2055
|
+
origin_id,
|
|
2056
|
+
start_date,
|
|
2057
|
+
end_date,
|
|
2058
|
+
signed_at,
|
|
2059
|
+
effective_date,
|
|
2060
|
+
budget_amount,
|
|
2061
|
+
monthly_hour_cap,
|
|
2062
|
+
status,
|
|
2063
|
+
description,
|
|
2064
|
+
content_html,
|
|
2065
|
+
created_by_user_id,
|
|
2066
|
+
updated_by_user_id,
|
|
2067
|
+
created_at,
|
|
2068
|
+
updated_at
|
|
2069
|
+
) VALUES (
|
|
2070
|
+
$1, $2, 'client', 'service_agreement', $3, 'not_started', true, $4, $5, NULL, 'client_project', $6,
|
|
2071
|
+
$7, $8, NULL, $7, $9, $10, 'draft', $11, NULL, $12, $12, NOW(), NOW()
|
|
2072
|
+
)
|
|
2073
2073
|
RETURNING id`, (_a = input.contractCode) !== null && _a !== void 0 ? _a : `PRJ-${input.projectCode}`, (_b = input.contractName) !== null && _b !== void 0 ? _b : `${input.projectName} Service Agreement`, input.clientName, input.billingModel, input.managerCollaboratorId, input.projectId, (_c = input.startDate) !== null && _c !== void 0 ? _c : new Date().toISOString().slice(0, 10), (_d = input.endDate) !== null && _d !== void 0 ? _d : null, (_e = input.budgetAmount) !== null && _e !== void 0 ? _e : null, (_f = input.monthlyHourCap) !== null && _f !== void 0 ? _f : null, (_g = input.description) !== null && _g !== void 0 ? _g : null, createdByUserId);
|
|
2074
2074
|
return (_h = created[0]) === null || _h === void 0 ? void 0 : _h.id;
|
|
2075
2075
|
}
|
|
2076
2076
|
async replaceContractParties(client, contractId, parties) {
|
|
2077
2077
|
var _a, _b, _c, _d, _e, _f;
|
|
2078
|
-
await client.$executeRawUnsafe(`UPDATE operations_contract_party
|
|
2079
|
-
SET deleted_at = NOW(),
|
|
2080
|
-
updated_at = NOW()
|
|
2081
|
-
WHERE contract_id = $1
|
|
2078
|
+
await client.$executeRawUnsafe(`UPDATE operations_contract_party
|
|
2079
|
+
SET deleted_at = NOW(),
|
|
2080
|
+
updated_at = NOW()
|
|
2081
|
+
WHERE contract_id = $1
|
|
2082
2082
|
AND deleted_at IS NULL`, contractId);
|
|
2083
2083
|
for (const party of parties !== null && parties !== void 0 ? parties : []) {
|
|
2084
|
-
await client.$executeRawUnsafe(`INSERT INTO operations_contract_party (
|
|
2085
|
-
contract_id,
|
|
2086
|
-
party_role,
|
|
2087
|
-
party_type,
|
|
2088
|
-
display_name,
|
|
2089
|
-
document_number,
|
|
2090
|
-
email,
|
|
2091
|
-
phone,
|
|
2092
|
-
is_primary,
|
|
2093
|
-
created_at,
|
|
2094
|
-
updated_at
|
|
2095
|
-
) VALUES (
|
|
2096
|
-
$1, COALESCE($2, 'other'), COALESCE($3, 'company'), $4, $5, $6, $7, COALESCE($8, false), NOW(), NOW()
|
|
2084
|
+
await client.$executeRawUnsafe(`INSERT INTO operations_contract_party (
|
|
2085
|
+
contract_id,
|
|
2086
|
+
party_role,
|
|
2087
|
+
party_type,
|
|
2088
|
+
display_name,
|
|
2089
|
+
document_number,
|
|
2090
|
+
email,
|
|
2091
|
+
phone,
|
|
2092
|
+
is_primary,
|
|
2093
|
+
created_at,
|
|
2094
|
+
updated_at
|
|
2095
|
+
) VALUES (
|
|
2096
|
+
$1, COALESCE($2, 'other'), COALESCE($3, 'company'), $4, $5, $6, $7, COALESCE($8, false), NOW(), NOW()
|
|
2097
2097
|
)`, contractId, (_a = party.partyRole) !== null && _a !== void 0 ? _a : 'other', (_b = party.partyType) !== null && _b !== void 0 ? _b : 'company', party.displayName, (_c = party.documentNumber) !== null && _c !== void 0 ? _c : null, (_d = party.email) !== null && _d !== void 0 ? _d : null, (_e = party.phone) !== null && _e !== void 0 ? _e : null, (_f = party.isPrimary) !== null && _f !== void 0 ? _f : false);
|
|
2098
2098
|
}
|
|
2099
2099
|
}
|
|
2100
2100
|
async replaceContractSignatures(client, contractId, signatures) {
|
|
2101
2101
|
var _a, _b, _c, _d;
|
|
2102
|
-
await client.$executeRawUnsafe(`UPDATE operations_contract_signature
|
|
2103
|
-
SET deleted_at = NOW(),
|
|
2104
|
-
updated_at = NOW()
|
|
2105
|
-
WHERE contract_id = $1
|
|
2102
|
+
await client.$executeRawUnsafe(`UPDATE operations_contract_signature
|
|
2103
|
+
SET deleted_at = NOW(),
|
|
2104
|
+
updated_at = NOW()
|
|
2105
|
+
WHERE contract_id = $1
|
|
2106
2106
|
AND deleted_at IS NULL`, contractId);
|
|
2107
2107
|
for (const signature of signatures !== null && signatures !== void 0 ? signatures : []) {
|
|
2108
|
-
await client.$executeRawUnsafe(`INSERT INTO operations_contract_signature (
|
|
2109
|
-
contract_id,
|
|
2110
|
-
signer_name,
|
|
2111
|
-
signer_role,
|
|
2112
|
-
signer_email,
|
|
2113
|
-
signer_status,
|
|
2114
|
-
signed_at,
|
|
2115
|
-
created_at,
|
|
2116
|
-
updated_at
|
|
2117
|
-
) VALUES (
|
|
2118
|
-
$1, $2, $3, $4, COALESCE($5, 'pending'), $6, NOW(), NOW()
|
|
2108
|
+
await client.$executeRawUnsafe(`INSERT INTO operations_contract_signature (
|
|
2109
|
+
contract_id,
|
|
2110
|
+
signer_name,
|
|
2111
|
+
signer_role,
|
|
2112
|
+
signer_email,
|
|
2113
|
+
signer_status,
|
|
2114
|
+
signed_at,
|
|
2115
|
+
created_at,
|
|
2116
|
+
updated_at
|
|
2117
|
+
) VALUES (
|
|
2118
|
+
$1, $2, $3, $4, COALESCE($5, 'pending'), $6, NOW(), NOW()
|
|
2119
2119
|
)`, contractId, signature.signerName, (_a = signature.signerRole) !== null && _a !== void 0 ? _a : null, (_b = signature.signerEmail) !== null && _b !== void 0 ? _b : null, (_c = signature.status) !== null && _c !== void 0 ? _c : 'pending', (_d = signature.signedAt) !== null && _d !== void 0 ? _d : null);
|
|
2120
2120
|
}
|
|
2121
2121
|
}
|
|
2122
2122
|
async replaceContractFinancialTerms(client, contractId, financialTerms) {
|
|
2123
2123
|
var _a, _b, _c, _d;
|
|
2124
|
-
await client.$executeRawUnsafe(`UPDATE operations_contract_financial_term
|
|
2125
|
-
SET deleted_at = NOW(),
|
|
2126
|
-
updated_at = NOW()
|
|
2127
|
-
WHERE contract_id = $1
|
|
2124
|
+
await client.$executeRawUnsafe(`UPDATE operations_contract_financial_term
|
|
2125
|
+
SET deleted_at = NOW(),
|
|
2126
|
+
updated_at = NOW()
|
|
2127
|
+
WHERE contract_id = $1
|
|
2128
2128
|
AND deleted_at IS NULL`, contractId);
|
|
2129
2129
|
for (const term of financialTerms !== null && financialTerms !== void 0 ? financialTerms : []) {
|
|
2130
|
-
await client.$executeRawUnsafe(`INSERT INTO operations_contract_financial_term (
|
|
2131
|
-
contract_id,
|
|
2132
|
-
term_type,
|
|
2133
|
-
label,
|
|
2134
|
-
amount,
|
|
2135
|
-
recurrence,
|
|
2136
|
-
due_day,
|
|
2137
|
-
notes,
|
|
2138
|
-
created_at,
|
|
2139
|
-
updated_at
|
|
2140
|
-
) VALUES (
|
|
2141
|
-
$1, COALESCE($2, 'value'), $3, $4, COALESCE($5, 'one_time'), $6, $7, NOW(), NOW()
|
|
2130
|
+
await client.$executeRawUnsafe(`INSERT INTO operations_contract_financial_term (
|
|
2131
|
+
contract_id,
|
|
2132
|
+
term_type,
|
|
2133
|
+
label,
|
|
2134
|
+
amount,
|
|
2135
|
+
recurrence,
|
|
2136
|
+
due_day,
|
|
2137
|
+
notes,
|
|
2138
|
+
created_at,
|
|
2139
|
+
updated_at
|
|
2140
|
+
) VALUES (
|
|
2141
|
+
$1, COALESCE($2, 'value'), $3, $4, COALESCE($5, 'one_time'), $6, $7, NOW(), NOW()
|
|
2142
2142
|
)`, contractId, (_a = term.termType) !== null && _a !== void 0 ? _a : 'value', term.label, term.amount, (_b = term.recurrence) !== null && _b !== void 0 ? _b : 'one_time', (_c = term.dueDay) !== null && _c !== void 0 ? _c : null, (_d = term.notes) !== null && _d !== void 0 ? _d : null);
|
|
2143
2143
|
}
|
|
2144
2144
|
}
|
|
2145
2145
|
async replaceContractRevisions(client, contractId, revisions) {
|
|
2146
2146
|
var _a, _b, _c, _d;
|
|
2147
|
-
await client.$executeRawUnsafe(`UPDATE operations_contract_revision
|
|
2148
|
-
SET deleted_at = NOW(),
|
|
2149
|
-
updated_at = NOW()
|
|
2150
|
-
WHERE contract_id = $1
|
|
2147
|
+
await client.$executeRawUnsafe(`UPDATE operations_contract_revision
|
|
2148
|
+
SET deleted_at = NOW(),
|
|
2149
|
+
updated_at = NOW()
|
|
2150
|
+
WHERE contract_id = $1
|
|
2151
2151
|
AND deleted_at IS NULL`, contractId);
|
|
2152
2152
|
for (const revision of revisions !== null && revisions !== void 0 ? revisions : []) {
|
|
2153
|
-
await client.$executeRawUnsafe(`INSERT INTO operations_contract_revision (
|
|
2154
|
-
contract_id,
|
|
2155
|
-
revision_type,
|
|
2156
|
-
title,
|
|
2157
|
-
effective_date,
|
|
2158
|
-
status,
|
|
2159
|
-
summary,
|
|
2160
|
-
created_at,
|
|
2161
|
-
updated_at
|
|
2162
|
-
) VALUES (
|
|
2163
|
-
$1, COALESCE($2, 'revision'), $3, $4, COALESCE($5, 'draft'), $6, NOW(), NOW()
|
|
2153
|
+
await client.$executeRawUnsafe(`INSERT INTO operations_contract_revision (
|
|
2154
|
+
contract_id,
|
|
2155
|
+
revision_type,
|
|
2156
|
+
title,
|
|
2157
|
+
effective_date,
|
|
2158
|
+
status,
|
|
2159
|
+
summary,
|
|
2160
|
+
created_at,
|
|
2161
|
+
updated_at
|
|
2162
|
+
) VALUES (
|
|
2163
|
+
$1, COALESCE($2, 'revision'), $3, $4, COALESCE($5, 'draft'), $6, NOW(), NOW()
|
|
2164
2164
|
)`, contractId, (_a = revision.revisionType) !== null && _a !== void 0 ? _a : 'revision', revision.title, (_b = revision.effectiveDate) !== null && _b !== void 0 ? _b : null, (_c = revision.status) !== null && _c !== void 0 ? _c : 'draft', (_d = revision.summary) !== null && _d !== void 0 ? _d : null);
|
|
2165
2165
|
}
|
|
2166
2166
|
}
|
|
2167
2167
|
async replaceContractPdfDocument(client, contractId, document) {
|
|
2168
2168
|
var _a;
|
|
2169
|
-
await client.$executeRawUnsafe(`UPDATE operations_contract_document
|
|
2170
|
-
SET is_current = false,
|
|
2171
|
-
updated_at = NOW()
|
|
2172
|
-
WHERE contract_id = $1
|
|
2173
|
-
AND deleted_at IS NULL
|
|
2169
|
+
await client.$executeRawUnsafe(`UPDATE operations_contract_document
|
|
2170
|
+
SET is_current = false,
|
|
2171
|
+
updated_at = NOW()
|
|
2172
|
+
WHERE contract_id = $1
|
|
2173
|
+
AND deleted_at IS NULL
|
|
2174
2174
|
AND document_type IN ('uploaded_pdf', 'generated_pdf')`, contractId);
|
|
2175
|
-
await client.$executeRawUnsafe(`INSERT INTO operations_contract_document (
|
|
2176
|
-
contract_id,
|
|
2177
|
-
document_type,
|
|
2178
|
-
file_name,
|
|
2179
|
-
mime_type,
|
|
2180
|
-
file_content_base64,
|
|
2181
|
-
is_current,
|
|
2182
|
-
notes,
|
|
2183
|
-
created_at,
|
|
2184
|
-
updated_at
|
|
2185
|
-
) VALUES (
|
|
2186
|
-
$1, 'uploaded_pdf', $2, $3, $4, true, $5, NOW(), NOW()
|
|
2175
|
+
await client.$executeRawUnsafe(`INSERT INTO operations_contract_document (
|
|
2176
|
+
contract_id,
|
|
2177
|
+
document_type,
|
|
2178
|
+
file_name,
|
|
2179
|
+
mime_type,
|
|
2180
|
+
file_content_base64,
|
|
2181
|
+
is_current,
|
|
2182
|
+
notes,
|
|
2183
|
+
created_at,
|
|
2184
|
+
updated_at
|
|
2185
|
+
) VALUES (
|
|
2186
|
+
$1, 'uploaded_pdf', $2, $3, $4, true, $5, NOW(), NOW()
|
|
2187
2187
|
)`, contractId, document.fileName, document.mimeType, document.fileContentBase64, (_a = document.notes) !== null && _a !== void 0 ? _a : null);
|
|
2188
2188
|
}
|
|
2189
2189
|
async insertContractHistory(client, contractId, actorUserId, action, note, metadataJson) {
|
|
2190
|
-
await client.$executeRawUnsafe(`INSERT INTO operations_contract_history (
|
|
2191
|
-
contract_id,
|
|
2192
|
-
actor_user_id,
|
|
2193
|
-
action,
|
|
2194
|
-
note,
|
|
2195
|
-
metadata_json,
|
|
2196
|
-
created_at
|
|
2197
|
-
) VALUES (
|
|
2198
|
-
$1, $2, $3, $4, $5, NOW()
|
|
2190
|
+
await client.$executeRawUnsafe(`INSERT INTO operations_contract_history (
|
|
2191
|
+
contract_id,
|
|
2192
|
+
actor_user_id,
|
|
2193
|
+
action,
|
|
2194
|
+
note,
|
|
2195
|
+
metadata_json,
|
|
2196
|
+
created_at
|
|
2197
|
+
) VALUES (
|
|
2198
|
+
$1, $2, $3, $4, $5, NOW()
|
|
2199
2199
|
)`, contractId, actorUserId, action, note, metadataJson !== null && metadataJson !== void 0 ? metadataJson : null);
|
|
2200
2200
|
}
|
|
2201
2201
|
requireFields(input, required) {
|