@hed-hog/operations 0.0.306 → 0.0.310
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/controllers/operations-approvals.controller.d.ts +114 -1
- package/dist/controllers/operations-approvals.controller.d.ts.map +1 -1
- package/dist/controllers/operations-approvals.controller.js +16 -3
- package/dist/controllers/operations-approvals.controller.js.map +1 -1
- package/dist/controllers/operations-collaborators.controller.d.ts +16 -1
- package/dist/controllers/operations-collaborators.controller.d.ts.map +1 -1
- package/dist/controllers/operations-collaborators.controller.js +16 -3
- package/dist/controllers/operations-collaborators.controller.js.map +1 -1
- package/dist/controllers/operations-contracts.controller.d.ts +14 -453
- package/dist/controllers/operations-contracts.controller.d.ts.map +1 -1
- package/dist/controllers/operations-contracts.controller.js +11 -112
- package/dist/controllers/operations-contracts.controller.js.map +1 -1
- package/dist/controllers/operations-org-structure.controller.d.ts +65 -2
- package/dist/controllers/operations-org-structure.controller.d.ts.map +1 -1
- package/dist/controllers/operations-org-structure.controller.js +18 -5
- package/dist/controllers/operations-org-structure.controller.js.map +1 -1
- package/dist/controllers/operations-projects.controller.d.ts +28 -4
- package/dist/controllers/operations-projects.controller.d.ts.map +1 -1
- package/dist/controllers/operations-projects.controller.js +17 -5
- package/dist/controllers/operations-projects.controller.js.map +1 -1
- package/dist/controllers/operations-timesheets.controller.d.ts +31 -4
- package/dist/controllers/operations-timesheets.controller.d.ts.map +1 -1
- package/dist/controllers/operations-timesheets.controller.js +16 -11
- package/dist/controllers/operations-timesheets.controller.js.map +1 -1
- package/dist/dto/list-approvals.dto.d.ts +6 -0
- package/dist/dto/list-approvals.dto.d.ts.map +1 -0
- package/dist/dto/list-approvals.dto.js +28 -0
- package/dist/dto/list-approvals.dto.js.map +1 -0
- package/dist/dto/list-collaborator-types.dto.d.ts +3 -1
- package/dist/dto/list-collaborator-types.dto.d.ts.map +1 -1
- package/dist/dto/list-collaborator-types.dto.js +7 -1
- package/dist/dto/list-collaborator-types.dto.js.map +1 -1
- package/dist/dto/list-collaborators.dto.d.ts +1 -0
- package/dist/dto/list-collaborators.dto.d.ts.map +1 -1
- package/dist/dto/list-collaborators.dto.js +5 -0
- package/dist/dto/list-collaborators.dto.js.map +1 -1
- package/dist/dto/list-contracts.dto.d.ts +8 -0
- package/dist/dto/list-contracts.dto.d.ts.map +1 -0
- package/dist/dto/list-contracts.dto.js +38 -0
- package/dist/dto/list-contracts.dto.js.map +1 -0
- package/dist/dto/list-departments.dto.d.ts +5 -0
- package/dist/dto/list-departments.dto.d.ts.map +1 -0
- package/dist/dto/list-departments.dto.js +23 -0
- package/dist/dto/list-departments.dto.js.map +1 -0
- package/dist/dto/list-projects.dto.d.ts +5 -0
- package/dist/dto/list-projects.dto.d.ts.map +1 -0
- package/dist/dto/list-projects.dto.js +23 -0
- package/dist/dto/list-projects.dto.js.map +1 -0
- package/dist/dto/list-schedule-adjustments.dto.d.ts +5 -0
- package/dist/dto/list-schedule-adjustments.dto.d.ts.map +1 -0
- package/dist/dto/list-schedule-adjustments.dto.js +23 -0
- package/dist/dto/list-schedule-adjustments.dto.js.map +1 -0
- package/dist/dto/list-time-off-requests.dto.d.ts +5 -0
- package/dist/dto/list-time-off-requests.dto.d.ts.map +1 -0
- package/dist/dto/list-time-off-requests.dto.js +23 -0
- package/dist/dto/list-time-off-requests.dto.js.map +1 -0
- package/dist/dto/list-timesheets.dto.d.ts +5 -0
- package/dist/dto/list-timesheets.dto.d.ts.map +1 -0
- package/dist/dto/list-timesheets.dto.js +23 -0
- package/dist/dto/list-timesheets.dto.js.map +1 -0
- package/dist/dto/reorder-collaborator-types.dto.d.ts +4 -0
- package/dist/dto/reorder-collaborator-types.dto.d.ts.map +1 -0
- package/dist/dto/reorder-collaborator-types.dto.js +25 -0
- package/dist/dto/reorder-collaborator-types.dto.js.map +1 -0
- package/dist/operations.service.d.ts +340 -271
- package/dist/operations.service.d.ts.map +1 -1
- package/dist/operations.service.js +1007 -1043
- package/dist/operations.service.js.map +1 -1
- package/dist/operations.service.spec.js +0 -22
- package/dist/operations.service.spec.js.map +1 -1
- package/hedhog/data/menu.yaml +0 -36
- package/hedhog/data/route.yaml +42 -73
- package/hedhog/frontend/app/_components/collaborator-form-screen.tsx.ejs +8 -1
- package/hedhog/frontend/app/_components/collaborator-select-with-create.tsx.ejs +15 -10
- package/hedhog/frontend/app/_components/contract-details-screen.tsx.ejs +108 -213
- package/hedhog/frontend/app/_components/contract-form-screen.tsx.ejs +251 -2039
- package/hedhog/frontend/app/_components/project-details-screen.tsx.ejs +167 -60
- package/hedhog/frontend/app/_components/project-form-screen.tsx.ejs +70 -301
- package/hedhog/frontend/app/_components/system-user-select-with-create.tsx.ejs +102 -51
- package/hedhog/frontend/app/_lib/types.ts.ejs +19 -24
- package/hedhog/frontend/app/_lib/utils/format.ts.ejs +14 -9
- package/hedhog/frontend/app/approvals/page.tsx.ejs +842 -150
- package/hedhog/frontend/app/collaborator-types/page.tsx.ejs +445 -153
- package/hedhog/frontend/app/collaborators/page.tsx.ejs +118 -49
- package/hedhog/frontend/app/contracts/[id]/page.tsx.ejs +2 -2
- package/hedhog/frontend/app/contracts/page.tsx.ejs +215 -617
- package/hedhog/frontend/app/departments/page.tsx.ejs +257 -113
- package/hedhog/frontend/app/projects/page.tsx.ejs +90 -51
- package/hedhog/frontend/app/schedule-adjustments/page.tsx.ejs +412 -147
- package/hedhog/frontend/app/time-off/page.tsx.ejs +400 -123
- package/hedhog/frontend/app/timesheets/page.tsx.ejs +460 -365
- package/hedhog/frontend/messages/en.json +143 -14
- package/hedhog/frontend/messages/pt.json +192 -54
- package/hedhog/table/operations_contract.yaml +0 -9
- package/package.json +4 -4
- package/src/controllers/operations-approvals.controller.ts +9 -3
- package/src/controllers/operations-collaborators.controller.ts +15 -2
- package/src/controllers/operations-contracts.controller.ts +8 -92
- package/src/controllers/operations-org-structure.controller.ts +17 -4
- package/src/controllers/operations-projects.controller.ts +10 -4
- package/src/controllers/operations-timesheets.controller.ts +17 -8
- package/src/dto/list-approvals.dto.ts +12 -0
- package/src/dto/list-collaborator-types.dto.ts +7 -2
- package/src/dto/list-collaborators.dto.ts +4 -0
- package/src/dto/list-contracts.dto.ts +20 -0
- package/src/dto/list-departments.dto.ts +8 -0
- package/src/dto/list-projects.dto.ts +8 -0
- package/src/dto/list-schedule-adjustments.dto.ts +8 -0
- package/src/dto/list-time-off-requests.dto.ts +8 -0
- package/src/dto/list-timesheets.dto.ts +8 -0
- package/src/dto/reorder-collaborator-types.dto.ts +10 -0
- package/src/operations.service.spec.ts +0 -30
- package/src/operations.service.ts +1557 -1806
- package/hedhog/frontend/app/_components/contract-creation-wizard.tsx.ejs +0 -631
- package/hedhog/frontend/app/_components/contract-template-form-screen.tsx.ejs +0 -526
- package/hedhog/frontend/app/_components/contract-template-select-with-create.tsx.ejs +0 -247
- package/hedhog/frontend/app/_components/contract-wizard-sheet.tsx.ejs +0 -3520
- package/hedhog/frontend/app/contracts/templates/page.tsx.ejs +0 -380
- package/hedhog/frontend/app/team/page.tsx.ejs +0 -352
- package/hedhog/table/operations_contract_financial_term.yaml +0 -40
- package/hedhog/table/operations_contract_revision.yaml +0 -38
- package/hedhog/table/operations_contract_signature.yaml +0 -38
- package/hedhog/table/operations_contract_template.yaml +0 -58
|
@@ -102,11 +102,6 @@ const PARTY_ROLE_VALUES = [
|
|
|
102
102
|
'other',
|
|
103
103
|
];
|
|
104
104
|
const PARTY_TYPE_VALUES = ['individual', 'company', 'internal_team', 'other'];
|
|
105
|
-
const SIGNATURE_ITEM_STATUS_VALUES = ['pending', 'signed', 'rejected'];
|
|
106
|
-
const FINANCIAL_TERM_TYPE_VALUES = ['value', 'payment', 'revenue', 'fine', 'other'];
|
|
107
|
-
const RECURRENCE_VALUES = ['one_time', 'monthly', 'quarterly', 'yearly', 'other'];
|
|
108
|
-
const REVISION_TYPE_VALUES = ['amendment', 'renewal', 'revision', 'addendum', 'other'];
|
|
109
|
-
const REVISION_STATUS_VALUES = ['draft', 'active', 'completed', 'cancelled'];
|
|
110
105
|
const TASK_STATUS_VALUES = ['todo', 'doing', 'review', 'done'];
|
|
111
106
|
let OperationsService = OperationsService_1 = class OperationsService {
|
|
112
107
|
constructor(prisma, aiService, integrationApi, fileService, settingService, accessService, localeService) {
|
|
@@ -154,35 +149,82 @@ let OperationsService = OperationsService_1 = class OperationsService {
|
|
|
154
149
|
LIMIT 1`));
|
|
155
150
|
return (_b = (_a = fallbackLocales[0]) === null || _a === void 0 ? void 0 : _a.id) !== null && _b !== void 0 ? _b : null;
|
|
156
151
|
}
|
|
157
|
-
async listCollaboratorTypes(userId, filters) {
|
|
152
|
+
async listCollaboratorTypes(userId, filters = {}) {
|
|
153
|
+
var _a, _b;
|
|
158
154
|
const actor = await this.getActorContext(userId);
|
|
159
155
|
this.ensureCollaborator(actor);
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
156
|
+
const params = [];
|
|
157
|
+
const where = [];
|
|
158
|
+
if (filters.active === true || filters.status === 'active') {
|
|
159
|
+
where.push('(ct.deleted_at IS NULL AND ct.is_active = true)');
|
|
160
|
+
}
|
|
161
|
+
else if (filters.status === 'inactive') {
|
|
162
|
+
where.push('(ct.deleted_at IS NOT NULL OR ct.is_active = false)');
|
|
163
|
+
}
|
|
164
|
+
const pagination = this.shouldPaginate(filters)
|
|
165
|
+
? this.normalizePaginationParams(filters, {
|
|
166
|
+
defaultSortField: 'sortOrder',
|
|
167
|
+
defaultSortOrder: 'asc',
|
|
168
|
+
allowedSortFields: ['name', 'slug', 'category', 'sortOrder', 'createdAt'],
|
|
169
|
+
})
|
|
170
|
+
: null;
|
|
171
|
+
if (pagination === null || pagination === void 0 ? void 0 : pagination.search) {
|
|
172
|
+
const searchPlaceholder = this.param(params, `%${pagination.search}%`);
|
|
173
|
+
where.push(`(
|
|
174
|
+
COALESCE(ct.name, '') ILIKE ${searchPlaceholder}
|
|
175
|
+
OR COALESCE(ct.slug, '') ILIKE ${searchPlaceholder}
|
|
176
|
+
OR COALESCE(ct.description, '') ILIKE ${searchPlaceholder}
|
|
177
|
+
OR COALESCE(ct.category, '') ILIKE ${searchPlaceholder}
|
|
178
|
+
)`);
|
|
179
|
+
}
|
|
180
|
+
const whereClause = where.length ? `WHERE ${where.join(' AND ')}` : '';
|
|
181
|
+
const baseQuery = `SELECT ct.id,
|
|
182
|
+
ct.slug,
|
|
183
|
+
ct.name,
|
|
184
|
+
ct.description,
|
|
185
|
+
ct.category,
|
|
186
|
+
ct.is_active AS "isActive",
|
|
187
|
+
ct.sort_order AS "sortOrder",
|
|
188
|
+
CASE
|
|
189
|
+
WHEN ct.deleted_at IS NULL AND ct.is_active THEN 'active'
|
|
190
|
+
ELSE 'inactive'
|
|
191
|
+
END AS status,
|
|
192
|
+
COUNT(DISTINCT c.id)::int AS "collaboratorCount",
|
|
193
|
+
ct.created_at AS "createdAt",
|
|
194
|
+
ct.updated_at AS "updatedAt"
|
|
195
|
+
FROM operations_collaborator_type ct
|
|
196
|
+
LEFT JOIN operations_collaborator c
|
|
197
|
+
ON c.deleted_at IS NULL
|
|
198
|
+
AND c.collaborator_type_id = ct.id
|
|
199
|
+
${whereClause}
|
|
200
|
+
GROUP BY ct.id`;
|
|
201
|
+
if (!pagination) {
|
|
202
|
+
return this.queryRows(`${baseQuery}
|
|
203
|
+
ORDER BY CASE
|
|
204
|
+
WHEN ct.deleted_at IS NULL AND ct.is_active THEN 0
|
|
205
|
+
ELSE 1
|
|
206
|
+
END ASC,
|
|
207
|
+
ct.sort_order ASC,
|
|
208
|
+
ct.name ASC`, params);
|
|
209
|
+
}
|
|
210
|
+
const totalRow = await this.querySingle(`SELECT COUNT(*)::text AS total
|
|
174
211
|
FROM operations_collaborator_type ct
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
212
|
+
${whereClause}`, params);
|
|
213
|
+
const sortColumn = (_a = {
|
|
214
|
+
name: 'ct.name',
|
|
215
|
+
slug: 'ct.slug',
|
|
216
|
+
category: 'ct.category',
|
|
217
|
+
sortOrder: 'ct.sort_order',
|
|
218
|
+
createdAt: 'ct.created_at',
|
|
219
|
+
}[pagination.sortField]) !== null && _a !== void 0 ? _a : 'ct.name';
|
|
220
|
+
const queryParams = [...params];
|
|
221
|
+
const limitPlaceholder = this.param(queryParams, pagination.pageSize);
|
|
222
|
+
const offsetPlaceholder = this.param(queryParams, pagination.offset);
|
|
223
|
+
const rows = await this.queryRows(`${baseQuery}
|
|
224
|
+
ORDER BY ${sortColumn} ${pagination.sortOrder.toUpperCase()}, ct.id ASC
|
|
225
|
+
LIMIT ${limitPlaceholder}
|
|
226
|
+
OFFSET ${offsetPlaceholder}`, queryParams);
|
|
227
|
+
return this.buildPaginationResult(rows, Number((_b = totalRow === null || totalRow === void 0 ? void 0 : totalRow.total) !== null && _b !== void 0 ? _b : 0), pagination.page, pagination.pageSize);
|
|
186
228
|
}
|
|
187
229
|
async createCollaboratorType(userId, data) {
|
|
188
230
|
const actor = await this.getActorContext(userId);
|
|
@@ -196,6 +238,9 @@ let OperationsService = OperationsService_1 = class OperationsService {
|
|
|
196
238
|
await this.assertCollaboratorTypeNameAvailable(tx, name);
|
|
197
239
|
const nextSlug = await this.buildCollaboratorTypeSlug(tx, name, data.slug);
|
|
198
240
|
const nextIsActive = (_a = data.isActive) !== null && _a !== void 0 ? _a : (data.status ? data.status === 'active' : true);
|
|
241
|
+
const nextSortOrder = data.sortOrder !== undefined && Number.isFinite(Number(data.sortOrder))
|
|
242
|
+
? Number(data.sortOrder)
|
|
243
|
+
: await this.getNextCollaboratorTypeSortOrder(tx);
|
|
199
244
|
const created = (await tx.$queryRawUnsafe(`INSERT INTO operations_collaborator_type (
|
|
200
245
|
slug,
|
|
201
246
|
name,
|
|
@@ -211,7 +256,7 @@ let OperationsService = OperationsService_1 = class OperationsService {
|
|
|
211
256
|
CASE WHEN $5::boolean THEN NULL ELSE NOW() END,
|
|
212
257
|
NOW(), NOW()
|
|
213
258
|
)
|
|
214
|
-
RETURNING id`, nextSlug, name, this.normalizeOptionalText(data.description), this.normalizeOptionalText(data.category), nextIsActive,
|
|
259
|
+
RETURNING id`, nextSlug, name, this.normalizeOptionalText(data.description), this.normalizeOptionalText(data.category), nextIsActive, nextSortOrder));
|
|
215
260
|
const createdCollaboratorTypeId = (_b = created[0]) === null || _b === void 0 ? void 0 : _b.id;
|
|
216
261
|
if (!createdCollaboratorTypeId) {
|
|
217
262
|
throw new common_1.BadRequestException('Unable to create the collaborator type.');
|
|
@@ -261,6 +306,40 @@ let OperationsService = OperationsService_1 = class OperationsService {
|
|
|
261
306
|
return this.getCollaboratorTypeById(tx, collaboratorTypeId, true);
|
|
262
307
|
});
|
|
263
308
|
}
|
|
309
|
+
async reorderCollaboratorTypes(userId, ids) {
|
|
310
|
+
const actor = await this.getActorContext(userId);
|
|
311
|
+
this.ensureDirector(actor);
|
|
312
|
+
const normalizedIds = [
|
|
313
|
+
...new Set(ids
|
|
314
|
+
.map((value) => Number(value))
|
|
315
|
+
.filter((value) => Number.isInteger(value) && value > 0)),
|
|
316
|
+
];
|
|
317
|
+
if (!normalizedIds.length) {
|
|
318
|
+
throw new common_1.BadRequestException('At least one collaborator type is required.');
|
|
319
|
+
}
|
|
320
|
+
return this.prisma.$transaction(async (tx) => {
|
|
321
|
+
const existingRows = (await tx.$queryRawUnsafe(`SELECT id
|
|
322
|
+
FROM operations_collaborator_type
|
|
323
|
+
WHERE id = ANY($1::int[])`, normalizedIds));
|
|
324
|
+
if (existingRows.length !== normalizedIds.length) {
|
|
325
|
+
throw new common_1.NotFoundException('One or more collaborator types were not found.');
|
|
326
|
+
}
|
|
327
|
+
await tx.$executeRawUnsafe(`UPDATE operations_collaborator_type AS ct
|
|
328
|
+
SET sort_order = updates.sort_order,
|
|
329
|
+
updated_at = NOW()
|
|
330
|
+
FROM (
|
|
331
|
+
SELECT UNNEST($1::int[]) AS id,
|
|
332
|
+
GENERATE_SERIES(1, array_length($1::int[], 1)) AS sort_order
|
|
333
|
+
) AS updates
|
|
334
|
+
WHERE ct.id = updates.id`, normalizedIds);
|
|
335
|
+
return this.listCollaboratorTypes(userId, {
|
|
336
|
+
page: 1,
|
|
337
|
+
pageSize: Math.max(normalizedIds.length, 1),
|
|
338
|
+
sortField: 'sortOrder',
|
|
339
|
+
sortOrder: 'asc',
|
|
340
|
+
});
|
|
341
|
+
});
|
|
342
|
+
}
|
|
264
343
|
async listProjectRoles(userId) {
|
|
265
344
|
const actor = await this.getActorContext(userId);
|
|
266
345
|
this.ensureCollaborator(actor);
|
|
@@ -409,11 +488,54 @@ let OperationsService = OperationsService_1 = class OperationsService {
|
|
|
409
488
|
recentTimesheets,
|
|
410
489
|
};
|
|
411
490
|
}
|
|
412
|
-
async listCollaborators(userId) {
|
|
491
|
+
async listCollaborators(userId, filters = {}) {
|
|
492
|
+
var _a, _b;
|
|
413
493
|
const actor = await this.getActorContext(userId);
|
|
414
494
|
this.ensureCollaborator(actor);
|
|
415
495
|
const filter = this.buildIdFilter(actor.visibleCollaboratorIds, 'c.id', actor.isDirector);
|
|
416
|
-
|
|
496
|
+
const pagination = this.shouldPaginate(filters)
|
|
497
|
+
? this.normalizePaginationParams(filters, {
|
|
498
|
+
defaultSortField: 'displayName',
|
|
499
|
+
defaultSortOrder: 'asc',
|
|
500
|
+
allowedSortFields: ['displayName', 'code', 'joinedAt', 'status'],
|
|
501
|
+
})
|
|
502
|
+
: null;
|
|
503
|
+
const params = [...filter.params];
|
|
504
|
+
const where = ['c.deleted_at IS NULL', filter.clause];
|
|
505
|
+
if (filters.status && filters.status !== 'all') {
|
|
506
|
+
where.push(`c.status::text = ${this.param(params, filters.status)}`);
|
|
507
|
+
}
|
|
508
|
+
if (filters.collaboratorTypeId) {
|
|
509
|
+
where.push(`c.collaborator_type_id = ${this.param(params, Number(filters.collaboratorTypeId))}`);
|
|
510
|
+
}
|
|
511
|
+
else if (filters.collaboratorType && filters.collaboratorType !== 'all') {
|
|
512
|
+
const collaboratorTypePlaceholder = this.param(params, filters.collaboratorType);
|
|
513
|
+
where.push(`(
|
|
514
|
+
collaborator_type.slug = ${collaboratorTypePlaceholder}
|
|
515
|
+
OR collaborator_type.name = ${collaboratorTypePlaceholder}
|
|
516
|
+
)`);
|
|
517
|
+
}
|
|
518
|
+
if (filters.departmentId) {
|
|
519
|
+
where.push(`c.department_id = ${this.param(params, Number(filters.departmentId))}`);
|
|
520
|
+
}
|
|
521
|
+
if (filters.jobTitleId) {
|
|
522
|
+
where.push(`c.job_title_id = ${this.param(params, Number(filters.jobTitleId))}`);
|
|
523
|
+
}
|
|
524
|
+
if (pagination === null || pagination === void 0 ? void 0 : pagination.search) {
|
|
525
|
+
const searchPlaceholder = this.param(params, `%${pagination.search}%`);
|
|
526
|
+
where.push(`(
|
|
527
|
+
COALESCE(c.display_name, '') ILIKE ${searchPlaceholder}
|
|
528
|
+
OR COALESCE(person_record.name, '') ILIKE ${searchPlaceholder}
|
|
529
|
+
OR COALESCE(c.code, '') ILIKE ${searchPlaceholder}
|
|
530
|
+
OR COALESCE(department_record.name, '') ILIKE ${searchPlaceholder}
|
|
531
|
+
OR COALESCE(c.department, '') ILIKE ${searchPlaceholder}
|
|
532
|
+
OR COALESCE(job_title_record.name, '') ILIKE ${searchPlaceholder}
|
|
533
|
+
OR COALESCE(c.title, '') ILIKE ${searchPlaceholder}
|
|
534
|
+
OR COALESCE(s.display_name, '') ILIKE ${searchPlaceholder}
|
|
535
|
+
)`);
|
|
536
|
+
}
|
|
537
|
+
const whereClause = where.join(' AND ');
|
|
538
|
+
const baseQuery = `SELECT c.id,
|
|
417
539
|
c.user_id AS "userId",
|
|
418
540
|
c.person_id AS "personId",
|
|
419
541
|
c.code,
|
|
@@ -466,10 +588,122 @@ let OperationsService = OperationsService_1 = class OperationsService {
|
|
|
466
588
|
oc.created_at DESC
|
|
467
589
|
LIMIT 1
|
|
468
590
|
) hiring_contract ON TRUE
|
|
469
|
-
WHERE
|
|
470
|
-
AND ${filter.clause}
|
|
591
|
+
WHERE ${whereClause}
|
|
471
592
|
GROUP BY c.id, person_record.id, collaborator_type.id, department_record.id, job_title_record.id, s.id, hiring_contract.id, hiring_contract.status, hiring_contract.budget_amount
|
|
472
|
-
|
|
593
|
+
`;
|
|
594
|
+
if (!pagination) {
|
|
595
|
+
return this.queryRows(`${baseQuery}
|
|
596
|
+
ORDER BY COALESCE(NULLIF(c.display_name, ''), person_record.name) ASC`, params);
|
|
597
|
+
}
|
|
598
|
+
const totalRow = await this.querySingle(`SELECT COUNT(*)::text AS total
|
|
599
|
+
FROM (
|
|
600
|
+
SELECT c.id
|
|
601
|
+
FROM operations_collaborator c
|
|
602
|
+
LEFT JOIN person person_record
|
|
603
|
+
ON person_record.id = c.person_id
|
|
604
|
+
LEFT JOIN operations_collaborator_type collaborator_type
|
|
605
|
+
ON collaborator_type.id = c.collaborator_type_id
|
|
606
|
+
AND collaborator_type.deleted_at IS NULL
|
|
607
|
+
LEFT JOIN operations_department department_record
|
|
608
|
+
ON department_record.id = c.department_id
|
|
609
|
+
AND department_record.deleted_at IS NULL
|
|
610
|
+
LEFT JOIN operations_job_title job_title_record
|
|
611
|
+
ON job_title_record.id = c.job_title_id
|
|
612
|
+
AND job_title_record.deleted_at IS NULL
|
|
613
|
+
LEFT JOIN operations_collaborator s
|
|
614
|
+
ON s.id = c.supervisor_collaborator_id
|
|
615
|
+
WHERE ${whereClause}
|
|
616
|
+
GROUP BY c.id, person_record.id, collaborator_type.id, department_record.id, job_title_record.id, s.id
|
|
617
|
+
) collaborator_rows`, params);
|
|
618
|
+
const sortColumn = (_a = {
|
|
619
|
+
displayName: `COALESCE(NULLIF(c.display_name, ''), person_record.name)`,
|
|
620
|
+
code: 'c.code',
|
|
621
|
+
joinedAt: 'c.joined_at',
|
|
622
|
+
status: 'c.status',
|
|
623
|
+
}[pagination.sortField]) !== null && _a !== void 0 ? _a : `COALESCE(NULLIF(c.display_name, ''), person_record.name)`;
|
|
624
|
+
const queryParams = [...params];
|
|
625
|
+
const limitPlaceholder = this.param(queryParams, pagination.pageSize);
|
|
626
|
+
const offsetPlaceholder = this.param(queryParams, pagination.offset);
|
|
627
|
+
const rows = await this.queryRows(`${baseQuery}
|
|
628
|
+
ORDER BY ${sortColumn} ${pagination.sortOrder.toUpperCase()}, c.id ASC
|
|
629
|
+
LIMIT ${limitPlaceholder}
|
|
630
|
+
OFFSET ${offsetPlaceholder}`, queryParams);
|
|
631
|
+
return this.buildPaginationResult(rows, Number((_b = totalRow === null || totalRow === void 0 ? void 0 : totalRow.total) !== null && _b !== void 0 ? _b : 0), pagination.page, pagination.pageSize);
|
|
632
|
+
}
|
|
633
|
+
async getCollaboratorStats(userId, filters = {}) {
|
|
634
|
+
var _a, _b, _c, _d, _e;
|
|
635
|
+
const actor = await this.getActorContext(userId);
|
|
636
|
+
this.ensureCollaborator(actor);
|
|
637
|
+
const filter = this.buildIdFilter(actor.visibleCollaboratorIds, 'c.id', actor.isDirector);
|
|
638
|
+
const params = [...filter.params];
|
|
639
|
+
const where = ['c.deleted_at IS NULL', filter.clause];
|
|
640
|
+
if (filters.status && filters.status !== 'all') {
|
|
641
|
+
where.push(`c.status::text = ${this.param(params, filters.status)}`);
|
|
642
|
+
}
|
|
643
|
+
if (filters.collaboratorTypeId) {
|
|
644
|
+
where.push(`c.collaborator_type_id = ${this.param(params, Number(filters.collaboratorTypeId))}`);
|
|
645
|
+
}
|
|
646
|
+
else if (filters.collaboratorType && filters.collaboratorType !== 'all') {
|
|
647
|
+
const collaboratorTypePlaceholder = this.param(params, filters.collaboratorType);
|
|
648
|
+
where.push(`(
|
|
649
|
+
collaborator_type.slug = ${collaboratorTypePlaceholder}
|
|
650
|
+
OR collaborator_type.name = ${collaboratorTypePlaceholder}
|
|
651
|
+
)`);
|
|
652
|
+
}
|
|
653
|
+
if (filters.departmentId) {
|
|
654
|
+
where.push(`c.department_id = ${this.param(params, Number(filters.departmentId))}`);
|
|
655
|
+
}
|
|
656
|
+
if (filters.jobTitleId) {
|
|
657
|
+
where.push(`c.job_title_id = ${this.param(params, Number(filters.jobTitleId))}`);
|
|
658
|
+
}
|
|
659
|
+
const normalizedSearch = String((_a = filters.search) !== null && _a !== void 0 ? _a : '').trim();
|
|
660
|
+
if (normalizedSearch) {
|
|
661
|
+
const searchPlaceholder = this.param(params, `%${normalizedSearch}%`);
|
|
662
|
+
where.push(`(
|
|
663
|
+
COALESCE(c.display_name, '') ILIKE ${searchPlaceholder}
|
|
664
|
+
OR COALESCE(person_record.name, '') ILIKE ${searchPlaceholder}
|
|
665
|
+
OR COALESCE(c.code, '') ILIKE ${searchPlaceholder}
|
|
666
|
+
OR COALESCE(department_record.name, '') ILIKE ${searchPlaceholder}
|
|
667
|
+
OR COALESCE(c.department, '') ILIKE ${searchPlaceholder}
|
|
668
|
+
OR COALESCE(job_title_record.name, '') ILIKE ${searchPlaceholder}
|
|
669
|
+
OR COALESCE(c.title, '') ILIKE ${searchPlaceholder}
|
|
670
|
+
OR COALESCE(s.display_name, '') ILIKE ${searchPlaceholder}
|
|
671
|
+
)`);
|
|
672
|
+
}
|
|
673
|
+
const result = await this.querySingle(`SELECT COUNT(DISTINCT c.id)::int AS total,
|
|
674
|
+
COUNT(DISTINCT c.id) FILTER (WHERE c.status = 'active')::int AS active,
|
|
675
|
+
COUNT(DISTINCT c.id) FILTER (WHERE c.status = 'on_leave')::int AS "onLeave",
|
|
676
|
+
COUNT(DISTINCT c.id) FILTER (WHERE hiring_contract.id IS NOT NULL)::int AS "withContracts"
|
|
677
|
+
FROM operations_collaborator c
|
|
678
|
+
LEFT JOIN person person_record
|
|
679
|
+
ON person_record.id = c.person_id
|
|
680
|
+
LEFT JOIN operations_collaborator_type collaborator_type
|
|
681
|
+
ON collaborator_type.id = c.collaborator_type_id
|
|
682
|
+
AND collaborator_type.deleted_at IS NULL
|
|
683
|
+
LEFT JOIN operations_department department_record
|
|
684
|
+
ON department_record.id = c.department_id
|
|
685
|
+
AND department_record.deleted_at IS NULL
|
|
686
|
+
LEFT JOIN operations_job_title job_title_record
|
|
687
|
+
ON job_title_record.id = c.job_title_id
|
|
688
|
+
AND job_title_record.deleted_at IS NULL
|
|
689
|
+
LEFT JOIN operations_collaborator s
|
|
690
|
+
ON s.id = c.supervisor_collaborator_id
|
|
691
|
+
LEFT JOIN LATERAL (
|
|
692
|
+
SELECT oc.id
|
|
693
|
+
FROM operations_contract oc
|
|
694
|
+
WHERE oc.related_collaborator_id = c.id
|
|
695
|
+
AND oc.deleted_at IS NULL
|
|
696
|
+
ORDER BY CASE WHEN oc.origin_type = 'employee_hiring' THEN 0 ELSE 1 END,
|
|
697
|
+
oc.created_at DESC
|
|
698
|
+
LIMIT 1
|
|
699
|
+
) hiring_contract ON TRUE
|
|
700
|
+
WHERE ${where.join(' AND ')}`, params);
|
|
701
|
+
return {
|
|
702
|
+
total: Number((_b = result === null || result === void 0 ? void 0 : result.total) !== null && _b !== void 0 ? _b : 0),
|
|
703
|
+
active: Number((_c = result === null || result === void 0 ? void 0 : result.active) !== null && _c !== void 0 ? _c : 0),
|
|
704
|
+
onLeave: Number((_d = result === null || result === void 0 ? void 0 : result.onLeave) !== null && _d !== void 0 ? _d : 0),
|
|
705
|
+
withContracts: Number((_e = result === null || result === void 0 ? void 0 : result.withContracts) !== null && _e !== void 0 ? _e : 0),
|
|
706
|
+
};
|
|
473
707
|
}
|
|
474
708
|
async getMyCollaborator(userId) {
|
|
475
709
|
const actor = await this.getActorContext(userId);
|
|
@@ -596,12 +830,12 @@ let OperationsService = OperationsService_1 = class OperationsService {
|
|
|
596
830
|
''
|
|
597
831
|
) AS "timesheetProjectNames",
|
|
598
832
|
tor.request_type AS "timeOffType",
|
|
599
|
-
tor.start_date AS "timeOffStartDate",
|
|
600
|
-
tor.end_date AS "timeOffEndDate",
|
|
833
|
+
tor.start_date::text AS "timeOffStartDate",
|
|
834
|
+
tor.end_date::text AS "timeOffEndDate",
|
|
601
835
|
tor.reason AS "timeOffReason",
|
|
602
836
|
sar.request_scope AS "scheduleRequestScope",
|
|
603
|
-
sar.effective_start_date AS "scheduleStartDate",
|
|
604
|
-
sar.effective_end_date AS "scheduleEndDate",
|
|
837
|
+
sar.effective_start_date::text AS "scheduleStartDate",
|
|
838
|
+
sar.effective_end_date::text AS "scheduleEndDate",
|
|
605
839
|
sar.reason AS "scheduleReason"
|
|
606
840
|
FROM operations_approval a
|
|
607
841
|
JOIN operations_collaborator requester
|
|
@@ -633,8 +867,8 @@ let OperationsService = OperationsService_1 = class OperationsService {
|
|
|
633
867
|
tor.collaborator_id AS "collaboratorId",
|
|
634
868
|
c.display_name AS "collaboratorName",
|
|
635
869
|
tor.request_type AS "requestType",
|
|
636
|
-
tor.start_date AS "startDate",
|
|
637
|
-
tor.end_date AS "endDate",
|
|
870
|
+
tor.start_date::text AS "startDate",
|
|
871
|
+
tor.end_date::text AS "endDate",
|
|
638
872
|
tor.total_days AS "totalDays",
|
|
639
873
|
tor.status,
|
|
640
874
|
tor.reason,
|
|
@@ -655,8 +889,8 @@ let OperationsService = OperationsService_1 = class OperationsService {
|
|
|
655
889
|
sar.collaborator_id AS "collaboratorId",
|
|
656
890
|
c.display_name AS "collaboratorName",
|
|
657
891
|
sar.request_scope AS "requestScope",
|
|
658
|
-
sar.effective_start_date AS "effectiveStartDate",
|
|
659
|
-
sar.effective_end_date AS "effectiveEndDate",
|
|
892
|
+
sar.effective_start_date::text AS "effectiveStartDate",
|
|
893
|
+
sar.effective_end_date::text AS "effectiveEndDate",
|
|
660
894
|
sar.status,
|
|
661
895
|
sar.reason,
|
|
662
896
|
sar.submitted_at AS "submittedAt",
|
|
@@ -851,31 +1085,77 @@ let OperationsService = OperationsService_1 = class OperationsService {
|
|
|
851
1085
|
});
|
|
852
1086
|
return this.getCollaboratorByIdForUser(userId, collaboratorId);
|
|
853
1087
|
}
|
|
854
|
-
async listDepartments(userId) {
|
|
1088
|
+
async listDepartments(userId, filters = {}) {
|
|
1089
|
+
var _a, _b;
|
|
855
1090
|
const actor = await this.getActorContext(userId);
|
|
856
1091
|
this.ensureCollaborator(actor);
|
|
857
|
-
|
|
858
|
-
|
|
859
|
-
|
|
860
|
-
|
|
861
|
-
|
|
862
|
-
|
|
863
|
-
|
|
864
|
-
|
|
865
|
-
|
|
866
|
-
|
|
867
|
-
|
|
868
|
-
|
|
869
|
-
|
|
870
|
-
|
|
871
|
-
|
|
872
|
-
|
|
873
|
-
|
|
874
|
-
|
|
1092
|
+
const pagination = this.shouldPaginate(filters)
|
|
1093
|
+
? this.normalizePaginationParams(filters, {
|
|
1094
|
+
defaultSortField: 'name',
|
|
1095
|
+
defaultSortOrder: 'asc',
|
|
1096
|
+
allowedSortFields: ['name', 'code', 'createdAt', 'updatedAt'],
|
|
1097
|
+
})
|
|
1098
|
+
: null;
|
|
1099
|
+
const params = [];
|
|
1100
|
+
const where = [];
|
|
1101
|
+
if (filters.status === 'active') {
|
|
1102
|
+
where.push('d.deleted_at IS NULL');
|
|
1103
|
+
}
|
|
1104
|
+
else if (filters.status === 'inactive') {
|
|
1105
|
+
where.push('d.deleted_at IS NOT NULL');
|
|
1106
|
+
}
|
|
1107
|
+
if (pagination === null || pagination === void 0 ? void 0 : pagination.search) {
|
|
1108
|
+
const searchPlaceholder = this.param(params, `%${pagination.search}%`);
|
|
1109
|
+
where.push(`(
|
|
1110
|
+
COALESCE(d.name, '') ILIKE ${searchPlaceholder}
|
|
1111
|
+
OR COALESCE(d.code, '') ILIKE ${searchPlaceholder}
|
|
1112
|
+
OR COALESCE(d.description, '') ILIKE ${searchPlaceholder}
|
|
1113
|
+
)`);
|
|
1114
|
+
}
|
|
1115
|
+
const whereClause = where.length ? `WHERE ${where.join(' AND ')}` : '';
|
|
1116
|
+
const baseQuery = `SELECT d.id,
|
|
1117
|
+
d.slug,
|
|
1118
|
+
d.code,
|
|
1119
|
+
d.name,
|
|
1120
|
+
d.description,
|
|
1121
|
+
CASE WHEN d.deleted_at IS NULL THEN 'active' ELSE 'inactive' END AS status,
|
|
1122
|
+
COUNT(DISTINCT c.id)::int AS "collaboratorCount",
|
|
1123
|
+
d.created_at AS "createdAt",
|
|
1124
|
+
d.updated_at AS "updatedAt"
|
|
1125
|
+
FROM operations_department d
|
|
1126
|
+
LEFT JOIN operations_collaborator c
|
|
1127
|
+
ON c.deleted_at IS NULL
|
|
1128
|
+
AND (
|
|
1129
|
+
c.department_id = d.id
|
|
1130
|
+
OR (
|
|
1131
|
+
c.department_id IS NULL
|
|
1132
|
+
AND LOWER(COALESCE(c.department, '')) = LOWER(d.name)
|
|
875
1133
|
)
|
|
876
|
-
|
|
877
|
-
|
|
878
|
-
|
|
1134
|
+
)
|
|
1135
|
+
${whereClause}
|
|
1136
|
+
GROUP BY d.id`;
|
|
1137
|
+
if (!pagination) {
|
|
1138
|
+
return this.queryRows(`${baseQuery}
|
|
1139
|
+
ORDER BY CASE WHEN d.deleted_at IS NULL THEN 0 ELSE 1 END ASC,
|
|
1140
|
+
d.name ASC`, params);
|
|
1141
|
+
}
|
|
1142
|
+
const totalRow = await this.querySingle(`SELECT COUNT(*)::text AS total
|
|
1143
|
+
FROM operations_department d
|
|
1144
|
+
${whereClause}`, params);
|
|
1145
|
+
const sortColumn = (_a = {
|
|
1146
|
+
name: 'd.name',
|
|
1147
|
+
code: 'd.code',
|
|
1148
|
+
createdAt: 'd.created_at',
|
|
1149
|
+
updatedAt: 'd.updated_at',
|
|
1150
|
+
}[pagination.sortField]) !== null && _a !== void 0 ? _a : 'd.name';
|
|
1151
|
+
const queryParams = [...params];
|
|
1152
|
+
const limitPlaceholder = this.param(queryParams, pagination.pageSize);
|
|
1153
|
+
const offsetPlaceholder = this.param(queryParams, pagination.offset);
|
|
1154
|
+
const rows = await this.queryRows(`${baseQuery}
|
|
1155
|
+
ORDER BY ${sortColumn} ${pagination.sortOrder.toUpperCase()}, d.id ASC
|
|
1156
|
+
LIMIT ${limitPlaceholder}
|
|
1157
|
+
OFFSET ${offsetPlaceholder}`, queryParams);
|
|
1158
|
+
return this.buildPaginationResult(rows, Number((_b = totalRow === null || totalRow === void 0 ? void 0 : totalRow.total) !== null && _b !== void 0 ? _b : 0), pagination.page, pagination.pageSize);
|
|
879
1159
|
}
|
|
880
1160
|
async listJobTitles(userId) {
|
|
881
1161
|
const actor = await this.getActorContext(userId);
|
|
@@ -1015,7 +1295,8 @@ let OperationsService = OperationsService_1 = class OperationsService {
|
|
|
1015
1295
|
return this.getDepartmentById(tx, departmentId, true);
|
|
1016
1296
|
});
|
|
1017
1297
|
}
|
|
1018
|
-
async listProjects(userId) {
|
|
1298
|
+
async listProjects(userId, filters = {}) {
|
|
1299
|
+
var _a, _b;
|
|
1019
1300
|
const actor = await this.getActorContext(userId);
|
|
1020
1301
|
const filter = this.buildIdFilter(actor.visibleProjectIds, 'p.id', actor.isDirector);
|
|
1021
1302
|
const assignmentParams = [];
|
|
@@ -1024,7 +1305,30 @@ let OperationsService = OperationsService_1 = class OperationsService {
|
|
|
1024
1305
|
MAX(CASE WHEN pa.collaborator_id = ${this.param(assignmentParams, actor.collaboratorId)} THEN pa.role_label END) AS "myRoleLabel",`
|
|
1025
1306
|
: `NULL::int AS "myAssignmentId",
|
|
1026
1307
|
NULL::varchar AS "myRoleLabel",`;
|
|
1027
|
-
|
|
1308
|
+
const pagination = this.shouldPaginate(filters)
|
|
1309
|
+
? this.normalizePaginationParams(filters, {
|
|
1310
|
+
defaultSortField: 'name',
|
|
1311
|
+
defaultSortOrder: 'asc',
|
|
1312
|
+
allowedSortFields: ['name', 'code', 'clientName', 'startDate', 'endDate', 'status'],
|
|
1313
|
+
})
|
|
1314
|
+
: null;
|
|
1315
|
+
const params = [...assignmentParams, ...filter.params];
|
|
1316
|
+
const where = ['p.deleted_at IS NULL', filter.clause];
|
|
1317
|
+
if (filters.status && filters.status !== 'all') {
|
|
1318
|
+
where.push(`p.status::text = ${this.param(params, filters.status)}`);
|
|
1319
|
+
}
|
|
1320
|
+
if (pagination === null || pagination === void 0 ? void 0 : pagination.search) {
|
|
1321
|
+
const searchPlaceholder = this.param(params, `%${pagination.search}%`);
|
|
1322
|
+
where.push(`(
|
|
1323
|
+
COALESCE(p.name, '') ILIKE ${searchPlaceholder}
|
|
1324
|
+
OR COALESCE(p.code, '') ILIKE ${searchPlaceholder}
|
|
1325
|
+
OR COALESCE(p.client_name, '') ILIKE ${searchPlaceholder}
|
|
1326
|
+
OR COALESCE(c.name, '') ILIKE ${searchPlaceholder}
|
|
1327
|
+
OR COALESCE(m.display_name, '') ILIKE ${searchPlaceholder}
|
|
1328
|
+
)`);
|
|
1329
|
+
}
|
|
1330
|
+
const whereClause = where.join(' AND ');
|
|
1331
|
+
const baseQuery = `SELECT p.id,
|
|
1028
1332
|
p.contract_id AS "contractId",
|
|
1029
1333
|
p.manager_collaborator_id AS "managerCollaboratorId",
|
|
1030
1334
|
p.code,
|
|
@@ -1049,9 +1353,32 @@ let OperationsService = OperationsService_1 = class OperationsService {
|
|
|
1049
1353
|
ON pa.project_id = p.id
|
|
1050
1354
|
AND pa.deleted_at IS NULL
|
|
1051
1355
|
AND pa.status IN ('planned', 'active')
|
|
1052
|
-
WHERE
|
|
1053
|
-
GROUP BY p.id, c.id, m.id
|
|
1054
|
-
|
|
1356
|
+
WHERE ${whereClause}
|
|
1357
|
+
GROUP BY p.id, c.id, m.id`;
|
|
1358
|
+
if (!pagination) {
|
|
1359
|
+
return this.queryRows(`${baseQuery} ORDER BY p.name ASC`, params);
|
|
1360
|
+
}
|
|
1361
|
+
const totalRow = await this.querySingle(`SELECT COUNT(*)::text AS total
|
|
1362
|
+
FROM operations_project p
|
|
1363
|
+
LEFT JOIN operations_contract c ON c.id = p.contract_id
|
|
1364
|
+
LEFT JOIN operations_collaborator m ON m.id = p.manager_collaborator_id
|
|
1365
|
+
WHERE ${whereClause}`, params);
|
|
1366
|
+
const sortColumn = (_a = {
|
|
1367
|
+
name: 'p.name',
|
|
1368
|
+
code: 'p.code',
|
|
1369
|
+
clientName: 'p.client_name',
|
|
1370
|
+
startDate: 'p.start_date',
|
|
1371
|
+
endDate: 'p.end_date',
|
|
1372
|
+
status: 'p.status',
|
|
1373
|
+
}[pagination.sortField]) !== null && _a !== void 0 ? _a : 'p.name';
|
|
1374
|
+
const queryParams = [...params];
|
|
1375
|
+
const limitPlaceholder = this.param(queryParams, pagination.pageSize);
|
|
1376
|
+
const offsetPlaceholder = this.param(queryParams, pagination.offset);
|
|
1377
|
+
const rows = await this.queryRows(`${baseQuery}
|
|
1378
|
+
ORDER BY ${sortColumn} ${pagination.sortOrder.toUpperCase()}, p.id ASC
|
|
1379
|
+
LIMIT ${limitPlaceholder}
|
|
1380
|
+
OFFSET ${offsetPlaceholder}`, queryParams);
|
|
1381
|
+
return this.buildPaginationResult(rows, Number((_b = totalRow === null || totalRow === void 0 ? void 0 : totalRow.total) !== null && _b !== void 0 ? _b : 0), pagination.page, pagination.pageSize);
|
|
1055
1382
|
}
|
|
1056
1383
|
async listProjectOptions(userId, paginationParams) {
|
|
1057
1384
|
var _a, _b;
|
|
@@ -1154,7 +1481,7 @@ let OperationsService = OperationsService_1 = class OperationsService {
|
|
|
1154
1481
|
filters.push(`COALESCE(t.project_id, pa.project_id) = ${this.param(params, paginationParams.projectId)}`);
|
|
1155
1482
|
}
|
|
1156
1483
|
if (paginationParams.status) {
|
|
1157
|
-
filters.push(`t.status = ${this.param(params, paginationParams.status)}`);
|
|
1484
|
+
filters.push(`t.status::text = ${this.param(params, paginationParams.status)}`);
|
|
1158
1485
|
}
|
|
1159
1486
|
const whereClause = filters.join(' AND ');
|
|
1160
1487
|
const totalRow = await this.querySingle(`SELECT COUNT(*)::text AS total
|
|
@@ -1598,7 +1925,7 @@ let OperationsService = OperationsService_1 = class OperationsService {
|
|
|
1598
1925
|
this.ensureDirector(actor);
|
|
1599
1926
|
this.requireFields(data, ['code', 'name']);
|
|
1600
1927
|
const createdProjectId = await this.prisma.$transaction(async (tx) => {
|
|
1601
|
-
var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o
|
|
1928
|
+
var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o;
|
|
1602
1929
|
const created = await tx.$queryRawUnsafe(`INSERT INTO operations_project (
|
|
1603
1930
|
contract_id,
|
|
1604
1931
|
manager_collaborator_id,
|
|
@@ -1627,28 +1954,6 @@ let OperationsService = OperationsService_1 = class OperationsService {
|
|
|
1627
1954
|
if ((_o = data.teamAssignments) === null || _o === void 0 ? void 0 : _o.length) {
|
|
1628
1955
|
await this.replaceProjectAssignments(tx, projectId, data.teamAssignments);
|
|
1629
1956
|
}
|
|
1630
|
-
if (!data.contractId && data.autoGenerateContractDraft !== false) {
|
|
1631
|
-
const contractId = await this.createProjectContractDraft(tx, actor.userId, {
|
|
1632
|
-
projectId,
|
|
1633
|
-
contractTemplateId: (_p = data.contractTemplateId) !== null && _p !== void 0 ? _p : null,
|
|
1634
|
-
projectCode: data.code,
|
|
1635
|
-
projectName: data.name,
|
|
1636
|
-
clientName: (_q = data.clientName) !== null && _q !== void 0 ? _q : data.name,
|
|
1637
|
-
managerCollaboratorId: (_r = data.managerCollaboratorId) !== null && _r !== void 0 ? _r : null,
|
|
1638
|
-
startDate: (_s = data.startDate) !== null && _s !== void 0 ? _s : null,
|
|
1639
|
-
endDate: (_t = data.endDate) !== null && _t !== void 0 ? _t : null,
|
|
1640
|
-
budgetAmount: (_u = data.budgetAmount) !== null && _u !== void 0 ? _u : null,
|
|
1641
|
-
monthlyHourCap: (_v = data.monthlyHourCap) !== null && _v !== void 0 ? _v : null,
|
|
1642
|
-
billingModel: (_w = data.billingModel) !== null && _w !== void 0 ? _w : 'time_and_material',
|
|
1643
|
-
contractCode: (_x = data.contractCode) !== null && _x !== void 0 ? _x : null,
|
|
1644
|
-
contractName: (_y = data.contractName) !== null && _y !== void 0 ? _y : null,
|
|
1645
|
-
description: (_0 = (_z = data.contractDescription) !== null && _z !== void 0 ? _z : data.summary) !== null && _0 !== void 0 ? _0 : null,
|
|
1646
|
-
});
|
|
1647
|
-
await tx.$executeRawUnsafe(`UPDATE operations_project
|
|
1648
|
-
SET contract_id = $1,
|
|
1649
|
-
updated_at = NOW()
|
|
1650
|
-
WHERE id = $2`, contractId, projectId);
|
|
1651
|
-
}
|
|
1652
1957
|
return projectId;
|
|
1653
1958
|
});
|
|
1654
1959
|
return this.getProjectById(userId, createdProjectId);
|
|
@@ -1673,7 +1978,7 @@ let OperationsService = OperationsService_1 = class OperationsService {
|
|
|
1673
1978
|
this.pushUpdate(updates, params, 'start_date', data.startDate, 'date');
|
|
1674
1979
|
this.pushUpdate(updates, params, 'end_date', data.endDate, 'date');
|
|
1675
1980
|
await this.prisma.$transaction(async (tx) => {
|
|
1676
|
-
var _a, _b
|
|
1981
|
+
var _a, _b;
|
|
1677
1982
|
if (updates.length) {
|
|
1678
1983
|
params.push(projectId);
|
|
1679
1984
|
await tx.$executeRawUnsafe(`UPDATE operations_project
|
|
@@ -1687,30 +1992,7 @@ let OperationsService = OperationsService_1 = class OperationsService {
|
|
|
1687
1992
|
const nextContractId = data.contractId !== undefined
|
|
1688
1993
|
? data.contractId
|
|
1689
1994
|
: ((_b = (_a = currentProject.relatedContract) === null || _a === void 0 ? void 0 : _a.id) !== null && _b !== void 0 ? _b : null);
|
|
1690
|
-
|
|
1691
|
-
if (shouldGenerateDraft) {
|
|
1692
|
-
const contractId = await this.createProjectContractDraft(tx, actor.userId, {
|
|
1693
|
-
projectId,
|
|
1694
|
-
contractTemplateId: (_c = data.contractTemplateId) !== null && _c !== void 0 ? _c : null,
|
|
1695
|
-
projectCode: (_d = data.code) !== null && _d !== void 0 ? _d : currentProject.code,
|
|
1696
|
-
projectName: (_e = data.name) !== null && _e !== void 0 ? _e : currentProject.name,
|
|
1697
|
-
clientName: (_g = (_f = data.clientName) !== null && _f !== void 0 ? _f : currentProject.clientName) !== null && _g !== void 0 ? _g : currentProject.name,
|
|
1698
|
-
managerCollaboratorId: (_j = (_h = data.managerCollaboratorId) !== null && _h !== void 0 ? _h : currentProject.managerCollaboratorId) !== null && _j !== void 0 ? _j : null,
|
|
1699
|
-
startDate: (_l = (_k = data.startDate) !== null && _k !== void 0 ? _k : currentProject.startDate) !== null && _l !== void 0 ? _l : null,
|
|
1700
|
-
endDate: (_o = (_m = data.endDate) !== null && _m !== void 0 ? _m : currentProject.endDate) !== null && _o !== void 0 ? _o : null,
|
|
1701
|
-
budgetAmount: (_q = (_p = data.budgetAmount) !== null && _p !== void 0 ? _p : currentProject.budgetAmount) !== null && _q !== void 0 ? _q : null,
|
|
1702
|
-
monthlyHourCap: (_t = (_r = data.monthlyHourCap) !== null && _r !== void 0 ? _r : (_s = currentProject.relatedContract) === null || _s === void 0 ? void 0 : _s.monthlyHourCap) !== null && _t !== void 0 ? _t : null,
|
|
1703
|
-
billingModel: (_w = (_u = data.billingModel) !== null && _u !== void 0 ? _u : (_v = currentProject.relatedContract) === null || _v === void 0 ? void 0 : _v.billingModel) !== null && _w !== void 0 ? _w : 'time_and_material',
|
|
1704
|
-
contractCode: (_z = (_x = data.contractCode) !== null && _x !== void 0 ? _x : (_y = currentProject.relatedContract) === null || _y === void 0 ? void 0 : _y.code) !== null && _z !== void 0 ? _z : null,
|
|
1705
|
-
contractName: (_2 = (_0 = data.contractName) !== null && _0 !== void 0 ? _0 : (_1 = currentProject.relatedContract) === null || _1 === void 0 ? void 0 : _1.name) !== null && _2 !== void 0 ? _2 : null,
|
|
1706
|
-
description: (_7 = (_6 = (_5 = (_3 = data.contractDescription) !== null && _3 !== void 0 ? _3 : (_4 = currentProject.relatedContract) === null || _4 === void 0 ? void 0 : _4.description) !== null && _5 !== void 0 ? _5 : data.summary) !== null && _6 !== void 0 ? _6 : currentProject.summary) !== null && _7 !== void 0 ? _7 : null,
|
|
1707
|
-
});
|
|
1708
|
-
await tx.$executeRawUnsafe(`UPDATE operations_project
|
|
1709
|
-
SET contract_id = $1,
|
|
1710
|
-
updated_at = NOW()
|
|
1711
|
-
WHERE id = $2`, contractId, projectId);
|
|
1712
|
-
}
|
|
1713
|
-
else if (nextContractId &&
|
|
1995
|
+
if (nextContractId &&
|
|
1714
1996
|
(data.monthlyHourCap !== undefined || data.billingModel !== undefined)) {
|
|
1715
1997
|
const contractUpdates = [];
|
|
1716
1998
|
const contractParams = [];
|
|
@@ -1729,138 +2011,8 @@ let OperationsService = OperationsService_1 = class OperationsService {
|
|
|
1729
2011
|
});
|
|
1730
2012
|
return this.getProjectById(userId, projectId);
|
|
1731
2013
|
}
|
|
1732
|
-
async
|
|
1733
|
-
|
|
1734
|
-
this.ensureDirector(actor);
|
|
1735
|
-
return this.queryRows(`SELECT t.id,
|
|
1736
|
-
t.slug,
|
|
1737
|
-
t.code,
|
|
1738
|
-
t.name,
|
|
1739
|
-
t.description,
|
|
1740
|
-
t.contract_category AS "contractCategory",
|
|
1741
|
-
t.contract_type AS "contractType",
|
|
1742
|
-
t.billing_model AS "billingModel",
|
|
1743
|
-
t.signature_status AS "signatureStatus",
|
|
1744
|
-
t.is_active AS "isActive",
|
|
1745
|
-
t.status,
|
|
1746
|
-
t.content_html AS "contentHtml",
|
|
1747
|
-
t.created_at AS "createdAt",
|
|
1748
|
-
t.updated_at AS "updatedAt",
|
|
1749
|
-
COUNT(DISTINCT c.id)::int AS "usageCount"
|
|
1750
|
-
FROM operations_contract_template t
|
|
1751
|
-
LEFT JOIN operations_contract c
|
|
1752
|
-
ON c.contract_template_id = t.id
|
|
1753
|
-
AND c.deleted_at IS NULL
|
|
1754
|
-
WHERE t.deleted_at IS NULL
|
|
1755
|
-
GROUP BY t.id
|
|
1756
|
-
ORDER BY CASE
|
|
1757
|
-
WHEN t.status = 'active' THEN 0
|
|
1758
|
-
WHEN t.status = 'draft' THEN 1
|
|
1759
|
-
WHEN t.status = 'inactive' THEN 2
|
|
1760
|
-
ELSE 3
|
|
1761
|
-
END,
|
|
1762
|
-
t.name ASC`);
|
|
1763
|
-
}
|
|
1764
|
-
async getContractTemplateById(userId, templateId) {
|
|
1765
|
-
const actor = await this.getActorContext(userId);
|
|
1766
|
-
this.ensureDirector(actor);
|
|
1767
|
-
return this.getContractTemplateRecord(this.prisma, templateId);
|
|
1768
|
-
}
|
|
1769
|
-
async createContractTemplate(userId, data) {
|
|
1770
|
-
const actor = await this.getActorContext(userId);
|
|
1771
|
-
this.ensureDirector(actor);
|
|
1772
|
-
const name = this.normalizeOptionalText(data.name);
|
|
1773
|
-
if (!name) {
|
|
1774
|
-
throw new common_1.BadRequestException('Contract template name is required.');
|
|
1775
|
-
}
|
|
1776
|
-
return this.prisma.$transaction(async (tx) => {
|
|
1777
|
-
var _a, _b, _c, _d, _e, _f, _g, _h, _j;
|
|
1778
|
-
await this.assertContractTemplateNameAvailable(tx, name);
|
|
1779
|
-
const nextCode = (_b = (_a = this.normalizeOptionalText(data.code)) === null || _a === void 0 ? void 0 : _a.toUpperCase()) !== null && _b !== void 0 ? _b : null;
|
|
1780
|
-
if (nextCode) {
|
|
1781
|
-
await this.assertContractTemplateCodeAvailable(tx, nextCode);
|
|
1782
|
-
}
|
|
1783
|
-
const nextStatus = (_c = data.status) !== null && _c !== void 0 ? _c : 'active';
|
|
1784
|
-
const isActive = (_d = data.isActive) !== null && _d !== void 0 ? _d : !['inactive', 'archived'].includes(nextStatus);
|
|
1785
|
-
const created = (await tx.$queryRawUnsafe(`INSERT INTO operations_contract_template (
|
|
1786
|
-
slug,
|
|
1787
|
-
code,
|
|
1788
|
-
name,
|
|
1789
|
-
description,
|
|
1790
|
-
contract_category,
|
|
1791
|
-
contract_type,
|
|
1792
|
-
billing_model,
|
|
1793
|
-
signature_status,
|
|
1794
|
-
is_active,
|
|
1795
|
-
status,
|
|
1796
|
-
content_html,
|
|
1797
|
-
created_at,
|
|
1798
|
-
updated_at
|
|
1799
|
-
) VALUES (
|
|
1800
|
-
$1, $2, $3, $4,
|
|
1801
|
-
$5::text::operations_contract_template_contract_category_49bb07a713_enum,
|
|
1802
|
-
$6::text::operations_contract_template_contract_type_3962dbda6a_enum,
|
|
1803
|
-
$7::text::operations_contract_template_billing_model_384a7c60e2_enum,
|
|
1804
|
-
$8::text::operations_contract_template_signature_status_56cb6d625b_enum,
|
|
1805
|
-
$9, $10::text::operations_contract_template_status_c9d2e90231_enum, $11,
|
|
1806
|
-
NOW(), NOW()
|
|
1807
|
-
)
|
|
1808
|
-
RETURNING id`, await this.generateUniqueContractTemplateSlug(tx, name), nextCode, name, this.normalizeOptionalText(data.description), (_e = data.contractCategory) !== null && _e !== void 0 ? _e : 'client', (_f = data.contractType) !== null && _f !== void 0 ? _f : 'service_agreement', (_g = data.billingModel) !== null && _g !== void 0 ? _g : 'time_and_material', (_h = data.signatureStatus) !== null && _h !== void 0 ? _h : 'not_started', isActive, nextStatus, this.normalizeOptionalText(data.contentHtml)));
|
|
1809
|
-
const templateId = (_j = created[0]) === null || _j === void 0 ? void 0 : _j.id;
|
|
1810
|
-
if (!templateId) {
|
|
1811
|
-
throw new common_1.BadRequestException('Unable to create the contract template.');
|
|
1812
|
-
}
|
|
1813
|
-
return this.getContractTemplateRecord(tx, templateId, true);
|
|
1814
|
-
});
|
|
1815
|
-
}
|
|
1816
|
-
async updateContractTemplate(userId, templateId, data) {
|
|
1817
|
-
const actor = await this.getActorContext(userId);
|
|
1818
|
-
this.ensureDirector(actor);
|
|
1819
|
-
return this.prisma.$transaction(async (tx) => {
|
|
1820
|
-
var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o, _p, _q, _r;
|
|
1821
|
-
const current = await this.getContractTemplateRecord(tx, templateId, true);
|
|
1822
|
-
const nextName = data.name !== undefined
|
|
1823
|
-
? this.normalizeOptionalText(data.name)
|
|
1824
|
-
: current.name;
|
|
1825
|
-
if (!nextName) {
|
|
1826
|
-
throw new common_1.BadRequestException('Contract template name is required.');
|
|
1827
|
-
}
|
|
1828
|
-
if (String(nextName).toLowerCase() !== String(current.name).toLowerCase()) {
|
|
1829
|
-
await this.assertContractTemplateNameAvailable(tx, nextName, templateId);
|
|
1830
|
-
}
|
|
1831
|
-
const nextCode = data.code !== undefined
|
|
1832
|
-
? (_b = (_a = this.normalizeOptionalText(data.code)) === null || _a === void 0 ? void 0 : _a.toUpperCase()) !== null && _b !== void 0 ? _b : null
|
|
1833
|
-
: ((_c = current.code) !== null && _c !== void 0 ? _c : null);
|
|
1834
|
-
if (nextCode) {
|
|
1835
|
-
await this.assertContractTemplateCodeAvailable(tx, nextCode, templateId);
|
|
1836
|
-
}
|
|
1837
|
-
const nextStatus = (_e = (_d = data.status) !== null && _d !== void 0 ? _d : current.status) !== null && _e !== void 0 ? _e : 'active';
|
|
1838
|
-
const nextIsActive = (_f = data.isActive) !== null && _f !== void 0 ? _f : !['inactive', 'archived'].includes(nextStatus);
|
|
1839
|
-
const nextSlug = String(nextName).toLowerCase() !== String(current.name).toLowerCase()
|
|
1840
|
-
? await this.generateUniqueContractTemplateSlug(tx, nextName, templateId)
|
|
1841
|
-
: current.slug;
|
|
1842
|
-
await tx.$executeRawUnsafe(`UPDATE operations_contract_template
|
|
1843
|
-
SET slug = $1,
|
|
1844
|
-
code = $2,
|
|
1845
|
-
name = $3,
|
|
1846
|
-
description = $4,
|
|
1847
|
-
contract_category = $5::text::operations_contract_template_contract_category_49bb07a713_enum,
|
|
1848
|
-
contract_type = $6::text::operations_contract_template_contract_type_3962dbda6a_enum,
|
|
1849
|
-
billing_model = $7::text::operations_contract_template_billing_model_384a7c60e2_enum,
|
|
1850
|
-
signature_status = $8::text::operations_contract_template_signature_status_56cb6d625b_enum,
|
|
1851
|
-
is_active = $9,
|
|
1852
|
-
status = $10::text::operations_contract_template_status_c9d2e90231_enum,
|
|
1853
|
-
content_html = $11,
|
|
1854
|
-
updated_at = NOW()
|
|
1855
|
-
WHERE id = $12`, nextSlug, nextCode, nextName, data.description !== undefined
|
|
1856
|
-
? this.normalizeOptionalText(data.description)
|
|
1857
|
-
: ((_g = current.description) !== null && _g !== void 0 ? _g : null), (_j = (_h = data.contractCategory) !== null && _h !== void 0 ? _h : current.contractCategory) !== null && _j !== void 0 ? _j : 'client', (_l = (_k = data.contractType) !== null && _k !== void 0 ? _k : current.contractType) !== null && _l !== void 0 ? _l : 'service_agreement', (_o = (_m = data.billingModel) !== null && _m !== void 0 ? _m : current.billingModel) !== null && _o !== void 0 ? _o : 'time_and_material', (_q = (_p = data.signatureStatus) !== null && _p !== void 0 ? _p : current.signatureStatus) !== null && _q !== void 0 ? _q : 'not_started', nextIsActive, nextStatus, data.contentHtml !== undefined
|
|
1858
|
-
? this.normalizeOptionalText(data.contentHtml)
|
|
1859
|
-
: ((_r = current.contentHtml) !== null && _r !== void 0 ? _r : null), templateId);
|
|
1860
|
-
return this.getContractTemplateRecord(tx, templateId, true);
|
|
1861
|
-
});
|
|
1862
|
-
}
|
|
1863
|
-
async listContracts(userId) {
|
|
2014
|
+
async listContracts(userId, filters = {}) {
|
|
2015
|
+
var _a, _b;
|
|
1864
2016
|
const actor = await this.getActorContext(userId);
|
|
1865
2017
|
const params = [];
|
|
1866
2018
|
const accessClause = actor.isDirector
|
|
@@ -1872,10 +2024,41 @@ let OperationsService = OperationsService_1 = class OperationsService {
|
|
|
1872
2024
|
FROM operations_project p_access
|
|
1873
2025
|
WHERE p_access.contract_id = c.id
|
|
1874
2026
|
AND p_access.deleted_at IS NULL
|
|
1875
|
-
|
|
2027
|
+
AND p_access.id = ANY(${this.param(params, actor.visibleProjectIds)}::int[])
|
|
1876
2028
|
)
|
|
1877
2029
|
)`;
|
|
1878
|
-
|
|
2030
|
+
const pagination = this.shouldPaginate(filters)
|
|
2031
|
+
? this.normalizePaginationParams(filters, {
|
|
2032
|
+
defaultSortField: 'name',
|
|
2033
|
+
defaultSortOrder: 'asc',
|
|
2034
|
+
allowedSortFields: ['name', 'code', 'clientName', 'startDate', 'endDate', 'status'],
|
|
2035
|
+
})
|
|
2036
|
+
: null;
|
|
2037
|
+
const where = [accessClause];
|
|
2038
|
+
if (filters.status && filters.status !== 'all') {
|
|
2039
|
+
where.push(`c.status::text = ${this.param(params, filters.status)}`);
|
|
2040
|
+
}
|
|
2041
|
+
if (filters.contractCategory && filters.contractCategory !== 'all') {
|
|
2042
|
+
where.push(`c.contract_category = ${this.param(params, filters.contractCategory)}::text::operations_contract_contract_category_70d553ea09_enum`);
|
|
2043
|
+
}
|
|
2044
|
+
if (filters.originType && filters.originType !== 'all') {
|
|
2045
|
+
where.push(`c.origin_type = ${this.param(params, filters.originType)}::text::operations_contract_origin_type_07a7cc2b5d_enum`);
|
|
2046
|
+
}
|
|
2047
|
+
if (filters.isActive === 'true' || filters.isActive === 'false') {
|
|
2048
|
+
where.push(`c.is_active = ${this.param(params, filters.isActive === 'true')}`);
|
|
2049
|
+
}
|
|
2050
|
+
if (pagination === null || pagination === void 0 ? void 0 : pagination.search) {
|
|
2051
|
+
const searchPlaceholder = this.param(params, `%${pagination.search}%`);
|
|
2052
|
+
where.push(`(
|
|
2053
|
+
COALESCE(c.name, '') ILIKE ${searchPlaceholder}
|
|
2054
|
+
OR COALESCE(c.code, '') ILIKE ${searchPlaceholder}
|
|
2055
|
+
OR COALESCE(c.client_name, '') ILIKE ${searchPlaceholder}
|
|
2056
|
+
OR COALESCE(m.display_name, '') ILIKE ${searchPlaceholder}
|
|
2057
|
+
OR COALESCE(linked.display_name, '') ILIKE ${searchPlaceholder}
|
|
2058
|
+
)`);
|
|
2059
|
+
}
|
|
2060
|
+
const whereClause = where.join(' AND ');
|
|
2061
|
+
const baseQuery = `SELECT c.id,
|
|
1879
2062
|
c.code,
|
|
1880
2063
|
c.name,
|
|
1881
2064
|
c.contract_category AS "contractCategory",
|
|
@@ -1886,10 +2069,6 @@ let OperationsService = OperationsService_1 = class OperationsService {
|
|
|
1886
2069
|
c.billing_model AS "billingModel",
|
|
1887
2070
|
c.account_manager_collaborator_id AS "accountManagerCollaboratorId",
|
|
1888
2071
|
c.related_collaborator_id AS "relatedCollaboratorId",
|
|
1889
|
-
c.contract_template_id AS "contractTemplateId",
|
|
1890
|
-
template.name AS "contractTemplateName",
|
|
1891
|
-
template.slug AS "contractTemplateSlug",
|
|
1892
|
-
template.code AS "contractTemplateCode",
|
|
1893
2072
|
c.origin_type AS "originType",
|
|
1894
2073
|
c.origin_id AS "originId",
|
|
1895
2074
|
c.start_date AS "startDate",
|
|
@@ -1905,17 +2084,11 @@ let OperationsService = OperationsService_1 = class OperationsService {
|
|
|
1905
2084
|
m.display_name AS "accountManagerName",
|
|
1906
2085
|
linked.display_name AS "relatedCollaboratorName",
|
|
1907
2086
|
MAX(COALESCE(primary_party.display_name, linked.display_name, c.client_name)) AS "mainRelatedPartyName",
|
|
1908
|
-
MAX(COALESCE(financials.value_amount, 0)) AS "valueAmount",
|
|
1909
|
-
MAX(COALESCE(financials.payment_amount, 0)) AS "paymentAmount",
|
|
1910
|
-
MAX(COALESCE(financials.revenue_amount, 0)) AS "revenueAmount",
|
|
1911
|
-
MAX(COALESCE(financials.fine_amount, 0)) AS "fineAmount",
|
|
1912
2087
|
MAX(COALESCE(pdf_document.file_name, '')) AS "currentPdfFileName",
|
|
1913
2088
|
COUNT(DISTINCT p.id)::int AS "projectCount"
|
|
1914
2089
|
FROM operations_contract c
|
|
1915
2090
|
LEFT JOIN operations_collaborator m ON m.id = c.account_manager_collaborator_id
|
|
1916
2091
|
LEFT JOIN operations_collaborator linked ON linked.id = c.related_collaborator_id
|
|
1917
|
-
LEFT JOIN operations_contract_template template
|
|
1918
|
-
ON template.id = c.contract_template_id
|
|
1919
2092
|
LEFT JOIN LATERAL (
|
|
1920
2093
|
SELECT cp.display_name
|
|
1921
2094
|
FROM operations_contract_party cp
|
|
@@ -1924,16 +2097,6 @@ let OperationsService = OperationsService_1 = class OperationsService {
|
|
|
1924
2097
|
ORDER BY cp.is_primary DESC, cp.id ASC
|
|
1925
2098
|
LIMIT 1
|
|
1926
2099
|
) primary_party ON TRUE
|
|
1927
|
-
LEFT JOIN LATERAL (
|
|
1928
|
-
SELECT
|
|
1929
|
-
SUM(CASE WHEN term_type = 'value' THEN amount ELSE 0 END) AS value_amount,
|
|
1930
|
-
SUM(CASE WHEN term_type = 'payment' THEN amount ELSE 0 END) AS payment_amount,
|
|
1931
|
-
SUM(CASE WHEN term_type = 'revenue' THEN amount ELSE 0 END) AS revenue_amount,
|
|
1932
|
-
SUM(CASE WHEN term_type = 'fine' THEN amount ELSE 0 END) AS fine_amount
|
|
1933
|
-
FROM operations_contract_financial_term ft
|
|
1934
|
-
WHERE ft.contract_id = c.id
|
|
1935
|
-
AND ft.deleted_at IS NULL
|
|
1936
|
-
) financials ON TRUE
|
|
1937
2100
|
LEFT JOIN LATERAL (
|
|
1938
2101
|
SELECT cd.file_name
|
|
1939
2102
|
FROM operations_contract_document cd
|
|
@@ -1947,9 +2110,71 @@ let OperationsService = OperationsService_1 = class OperationsService {
|
|
|
1947
2110
|
LEFT JOIN operations_project p
|
|
1948
2111
|
ON p.contract_id = c.id
|
|
1949
2112
|
AND p.deleted_at IS NULL
|
|
1950
|
-
WHERE ${
|
|
1951
|
-
GROUP BY c.id, m.id, linked.id
|
|
1952
|
-
|
|
2113
|
+
WHERE ${whereClause}
|
|
2114
|
+
GROUP BY c.id, m.id, linked.id`;
|
|
2115
|
+
if (!pagination) {
|
|
2116
|
+
return this.queryRows(`${baseQuery}
|
|
2117
|
+
ORDER BY COALESCE(c.name, c.code, CONCAT('draft-', c.id)) ASC`, params);
|
|
2118
|
+
}
|
|
2119
|
+
const totalRow = await this.querySingle(`SELECT COUNT(*)::text AS total
|
|
2120
|
+
FROM operations_contract c
|
|
2121
|
+
LEFT JOIN operations_collaborator m ON m.id = c.account_manager_collaborator_id
|
|
2122
|
+
LEFT JOIN operations_collaborator linked ON linked.id = c.related_collaborator_id
|
|
2123
|
+
WHERE ${whereClause}`, params);
|
|
2124
|
+
const sortColumn = (_a = {
|
|
2125
|
+
name: `COALESCE(c.name, c.code, CONCAT('draft-', c.id))`,
|
|
2126
|
+
code: 'c.code',
|
|
2127
|
+
clientName: 'c.client_name',
|
|
2128
|
+
startDate: 'c.start_date',
|
|
2129
|
+
endDate: 'c.end_date',
|
|
2130
|
+
status: 'c.status',
|
|
2131
|
+
}[pagination.sortField]) !== null && _a !== void 0 ? _a : `COALESCE(c.name, c.code, CONCAT('draft-', c.id))`;
|
|
2132
|
+
const queryParams = [...params];
|
|
2133
|
+
const limitPlaceholder = this.param(queryParams, pagination.pageSize);
|
|
2134
|
+
const offsetPlaceholder = this.param(queryParams, pagination.offset);
|
|
2135
|
+
const rows = await this.queryRows(`${baseQuery}
|
|
2136
|
+
ORDER BY ${sortColumn} ${pagination.sortOrder.toUpperCase()}, c.id ASC
|
|
2137
|
+
LIMIT ${limitPlaceholder}
|
|
2138
|
+
OFFSET ${offsetPlaceholder}`, queryParams);
|
|
2139
|
+
return this.buildPaginationResult(rows, Number((_b = totalRow === null || totalRow === void 0 ? void 0 : totalRow.total) !== null && _b !== void 0 ? _b : 0), pagination.page, pagination.pageSize);
|
|
2140
|
+
}
|
|
2141
|
+
async getContractStats(userId) {
|
|
2142
|
+
var _a, _b, _c, _d;
|
|
2143
|
+
const actor = await this.getActorContext(userId);
|
|
2144
|
+
const params = [];
|
|
2145
|
+
const accessClause = actor.isDirector
|
|
2146
|
+
? 'c.deleted_at IS NULL'
|
|
2147
|
+
: `c.deleted_at IS NULL AND (
|
|
2148
|
+
c.related_collaborator_id = ANY(${this.param(params, actor.visibleCollaboratorIds)}::int[])
|
|
2149
|
+
OR EXISTS (
|
|
2150
|
+
SELECT 1
|
|
2151
|
+
FROM operations_project p_access
|
|
2152
|
+
WHERE p_access.contract_id = c.id
|
|
2153
|
+
AND p_access.deleted_at IS NULL
|
|
2154
|
+
AND p_access.id = ANY(${this.param(params, actor.visibleProjectIds)}::int[])
|
|
2155
|
+
)
|
|
2156
|
+
)`;
|
|
2157
|
+
const stats = await this.querySingle(`SELECT COUNT(*)::int AS total,
|
|
2158
|
+
COUNT(*) FILTER (WHERE c.is_active = true)::int AS active,
|
|
2159
|
+
COUNT(*) FILTER (WHERE c.is_active = false)::int AS inactive,
|
|
2160
|
+
COUNT(*) FILTER (
|
|
2161
|
+
WHERE EXISTS (
|
|
2162
|
+
SELECT 1
|
|
2163
|
+
FROM operations_contract_document cd
|
|
2164
|
+
WHERE cd.contract_id = c.id
|
|
2165
|
+
AND cd.deleted_at IS NULL
|
|
2166
|
+
AND cd.is_current = true
|
|
2167
|
+
AND cd.document_type IN ('source_upload', 'generated_pdf')
|
|
2168
|
+
)
|
|
2169
|
+
)::int AS "withFile"
|
|
2170
|
+
FROM operations_contract c
|
|
2171
|
+
WHERE ${accessClause}`, params);
|
|
2172
|
+
return {
|
|
2173
|
+
total: Number((_a = stats === null || stats === void 0 ? void 0 : stats.total) !== null && _a !== void 0 ? _a : 0),
|
|
2174
|
+
active: Number((_b = stats === null || stats === void 0 ? void 0 : stats.active) !== null && _b !== void 0 ? _b : 0),
|
|
2175
|
+
inactive: Number((_c = stats === null || stats === void 0 ? void 0 : stats.inactive) !== null && _c !== void 0 ? _c : 0),
|
|
2176
|
+
withFile: Number((_d = stats === null || stats === void 0 ? void 0 : stats.withFile) !== null && _d !== void 0 ? _d : 0),
|
|
2177
|
+
};
|
|
1953
2178
|
}
|
|
1954
2179
|
async getContractById(userId, contractId) {
|
|
1955
2180
|
var _a, _b, _c;
|
|
@@ -1965,10 +2190,6 @@ let OperationsService = OperationsService_1 = class OperationsService {
|
|
|
1965
2190
|
c.billing_model AS "billingModel",
|
|
1966
2191
|
c.account_manager_collaborator_id AS "accountManagerCollaboratorId",
|
|
1967
2192
|
c.related_collaborator_id AS "relatedCollaboratorId",
|
|
1968
|
-
c.contract_template_id AS "contractTemplateId",
|
|
1969
|
-
template.name AS "contractTemplateName",
|
|
1970
|
-
template.slug AS "contractTemplateSlug",
|
|
1971
|
-
template.code AS "contractTemplateCode",
|
|
1972
2193
|
c.origin_type AS "originType",
|
|
1973
2194
|
c.origin_id AS "originId",
|
|
1974
2195
|
c.start_date AS "startDate",
|
|
@@ -1987,8 +2208,6 @@ let OperationsService = OperationsService_1 = class OperationsService {
|
|
|
1987
2208
|
FROM operations_contract c
|
|
1988
2209
|
LEFT JOIN operations_collaborator m ON m.id = c.account_manager_collaborator_id
|
|
1989
2210
|
LEFT JOIN operations_collaborator linked ON linked.id = c.related_collaborator_id
|
|
1990
|
-
LEFT JOIN operations_contract_template template
|
|
1991
|
-
ON template.id = c.contract_template_id
|
|
1992
2211
|
WHERE c.id = $1
|
|
1993
2212
|
AND c.deleted_at IS NULL`, [contractId]);
|
|
1994
2213
|
if (!contract) {
|
|
@@ -2015,7 +2234,7 @@ let OperationsService = OperationsService_1 = class OperationsService {
|
|
|
2015
2234
|
throw new common_1.ForbiddenException('You do not have access to this contract.');
|
|
2016
2235
|
}
|
|
2017
2236
|
}
|
|
2018
|
-
const [projects, scheduleSummary, parties,
|
|
2237
|
+
const [projects, scheduleSummary, parties, documents, history] = await Promise.all([
|
|
2019
2238
|
this.queryRows(`SELECT id, code, name, status
|
|
2020
2239
|
FROM operations_project
|
|
2021
2240
|
WHERE contract_id = $1
|
|
@@ -2044,27 +2263,6 @@ let OperationsService = OperationsService_1 = class OperationsService {
|
|
|
2044
2263
|
WHERE contract_id = $1
|
|
2045
2264
|
AND deleted_at IS NULL
|
|
2046
2265
|
ORDER BY is_primary DESC, id ASC`, [contractId]),
|
|
2047
|
-
this.queryRows(`SELECT id,
|
|
2048
|
-
signer_name AS "signerName",
|
|
2049
|
-
signer_role AS "signerRole",
|
|
2050
|
-
signer_email AS "signerEmail",
|
|
2051
|
-
signer_status AS status,
|
|
2052
|
-
signed_at AS "signedAt"
|
|
2053
|
-
FROM operations_contract_signature
|
|
2054
|
-
WHERE contract_id = $1
|
|
2055
|
-
AND deleted_at IS NULL
|
|
2056
|
-
ORDER BY id ASC`, [contractId]),
|
|
2057
|
-
this.queryRows(`SELECT id,
|
|
2058
|
-
term_type AS "termType",
|
|
2059
|
-
label,
|
|
2060
|
-
amount,
|
|
2061
|
-
recurrence,
|
|
2062
|
-
due_day AS "dueDay",
|
|
2063
|
-
notes
|
|
2064
|
-
FROM operations_contract_financial_term
|
|
2065
|
-
WHERE contract_id = $1
|
|
2066
|
-
AND deleted_at IS NULL
|
|
2067
|
-
ORDER BY id ASC`, [contractId]),
|
|
2068
2266
|
this.queryRows(`SELECT id,
|
|
2069
2267
|
document_type AS "documentType",
|
|
2070
2268
|
file_id AS "fileId",
|
|
@@ -2080,16 +2278,6 @@ let OperationsService = OperationsService_1 = class OperationsService {
|
|
|
2080
2278
|
WHERE contract_id = $1
|
|
2081
2279
|
AND deleted_at IS NULL
|
|
2082
2280
|
ORDER BY is_current DESC, id DESC`, [contractId]),
|
|
2083
|
-
this.queryRows(`SELECT id,
|
|
2084
|
-
revision_type AS "revisionType",
|
|
2085
|
-
title,
|
|
2086
|
-
effective_date AS "effectiveDate",
|
|
2087
|
-
status,
|
|
2088
|
-
summary
|
|
2089
|
-
FROM operations_contract_revision
|
|
2090
|
-
WHERE contract_id = $1
|
|
2091
|
-
AND deleted_at IS NULL
|
|
2092
|
-
ORDER BY effective_date DESC NULLS LAST, id DESC`, [contractId]),
|
|
2093
2281
|
this.queryRows(`SELECT id,
|
|
2094
2282
|
actor_user_id AS "actorUserId",
|
|
2095
2283
|
action,
|
|
@@ -2103,17 +2291,14 @@ let OperationsService = OperationsService_1 = class OperationsService {
|
|
|
2103
2291
|
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,
|
|
2104
2292
|
scheduleSummary,
|
|
2105
2293
|
parties,
|
|
2106
|
-
signatures,
|
|
2107
|
-
financialTerms,
|
|
2108
2294
|
documents,
|
|
2109
|
-
revisions,
|
|
2110
2295
|
history });
|
|
2111
2296
|
}
|
|
2112
2297
|
async createContract(userId, data) {
|
|
2113
2298
|
const actor = await this.getActorContext(userId);
|
|
2114
2299
|
this.ensureDirector(actor);
|
|
2115
2300
|
const createdId = await this.prisma.$transaction(async (tx) => {
|
|
2116
|
-
var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o, _p, _q, _r, _s, _t, _u, _v, _w, _x, _y, _z
|
|
2301
|
+
var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o, _p, _q, _r, _s, _t, _u, _v, _w, _x, _y, _z;
|
|
2117
2302
|
const normalizedCode = (_b = (_a = this.normalizeOptionalText(data.code)) === null || _a === void 0 ? void 0 : _a.toUpperCase()) !== null && _b !== void 0 ? _b : (await this.generateContractCode(tx));
|
|
2118
2303
|
const created = await tx.$queryRawUnsafe(`INSERT INTO operations_contract (
|
|
2119
2304
|
code,
|
|
@@ -2126,7 +2311,6 @@ let OperationsService = OperationsService_1 = class OperationsService {
|
|
|
2126
2311
|
billing_model,
|
|
2127
2312
|
account_manager_collaborator_id,
|
|
2128
2313
|
related_collaborator_id,
|
|
2129
|
-
contract_template_id,
|
|
2130
2314
|
origin_type,
|
|
2131
2315
|
origin_id,
|
|
2132
2316
|
start_date,
|
|
@@ -2152,24 +2336,20 @@ let OperationsService = OperationsService_1 = class OperationsService {
|
|
|
2152
2336
|
$8::operations_contract_billing_model_409dc7fea2_enum,
|
|
2153
2337
|
$9,
|
|
2154
2338
|
$10,
|
|
2155
|
-
$11,
|
|
2156
|
-
$12
|
|
2157
|
-
$13,
|
|
2158
|
-
$14::date,
|
|
2159
|
-
$
|
|
2160
|
-
$20::
|
|
2161
|
-
$21
|
|
2339
|
+
$11::operations_contract_origin_type_07a7cc2b5d_enum,
|
|
2340
|
+
$12,
|
|
2341
|
+
$13::date,
|
|
2342
|
+
$14::date, $15::date, $16::date, $17, $18,
|
|
2343
|
+
$19::operations_contract_status_a0395962df_enum,
|
|
2344
|
+
$20::operations_contract_creation_mode_98ba669209_enum,
|
|
2345
|
+
$21,
|
|
2162
2346
|
$22,
|
|
2163
2347
|
$23,
|
|
2164
|
-
$24,
|
|
2165
2348
|
NOW(), NOW()
|
|
2166
2349
|
)
|
|
2167
|
-
RETURNING id`, normalizedCode, this.normalizeOptionalText(data.name), (_c = data.contractCategory) !== null && _c !== void 0 ? _c : 'client', (_d = data.contractType) !== null && _d !== void 0 ? _d : 'service_agreement', this.normalizeOptionalText(data.clientName), (_e = data.signatureStatus) !== null && _e !== void 0 ? _e : 'not_started', (_f = data.isActive) !== null && _f !== void 0 ? _f : true, (_g = data.billingModel) !== null && _g !== void 0 ? _g : 'time_and_material', (_h = data.accountManagerCollaboratorId) !== null && _h !== void 0 ? _h : null, (_j = data.relatedCollaboratorId) !== null && _j !== void 0 ? _j : null, (_k = data.
|
|
2168
|
-
const contractId = (
|
|
2350
|
+
RETURNING id`, normalizedCode, this.normalizeOptionalText(data.name), (_c = data.contractCategory) !== null && _c !== void 0 ? _c : 'client', (_d = data.contractType) !== null && _d !== void 0 ? _d : 'service_agreement', this.normalizeOptionalText(data.clientName), (_e = data.signatureStatus) !== null && _e !== void 0 ? _e : 'not_started', (_f = data.isActive) !== null && _f !== void 0 ? _f : true, (_g = data.billingModel) !== null && _g !== void 0 ? _g : 'time_and_material', (_h = data.accountManagerCollaboratorId) !== null && _h !== void 0 ? _h : null, (_j = data.relatedCollaboratorId) !== null && _j !== void 0 ? _j : null, (_k = data.originType) !== null && _k !== void 0 ? _k : 'manual', (_l = data.originId) !== null && _l !== void 0 ? _l : null, this.normalizeOptionalText((_m = data.startDate) !== null && _m !== void 0 ? _m : null), (_o = data.endDate) !== null && _o !== void 0 ? _o : null, (_p = data.signedAt) !== null && _p !== void 0 ? _p : null, (_r = (_q = data.effectiveDate) !== null && _q !== void 0 ? _q : data.startDate) !== null && _r !== void 0 ? _r : null, (_s = data.budgetAmount) !== null && _s !== void 0 ? _s : null, (_t = data.monthlyHourCap) !== null && _t !== void 0 ? _t : null, (_u = data.status) !== null && _u !== void 0 ? _u : 'draft', (_v = data.creationMode) !== null && _v !== void 0 ? _v : 'blank', (_w = data.wizardStep) !== null && _w !== void 0 ? _w : 0, (_x = data.description) !== null && _x !== void 0 ? _x : null, (_y = data.contentHtml) !== null && _y !== void 0 ? _y : null);
|
|
2351
|
+
const contractId = (_z = created[0]) === null || _z === void 0 ? void 0 : _z.id;
|
|
2169
2352
|
await this.replaceContractParties(tx, contractId, data.parties);
|
|
2170
|
-
await this.replaceContractSignatures(tx, contractId, data.signatures);
|
|
2171
|
-
await this.replaceContractFinancialTerms(tx, contractId, data.financialTerms);
|
|
2172
|
-
await this.replaceContractRevisions(tx, contractId, data.revisions);
|
|
2173
2353
|
if (data.replaceUploadedPdfDocument) {
|
|
2174
2354
|
await this.replaceContractDocument(tx, contractId, 'source_upload', data.replaceUploadedPdfDocument);
|
|
2175
2355
|
}
|
|
@@ -2180,258 +2360,8 @@ let OperationsService = OperationsService_1 = class OperationsService {
|
|
|
2180
2360
|
});
|
|
2181
2361
|
return this.getContractById(userId, createdId);
|
|
2182
2362
|
}
|
|
2183
|
-
async createContractDraft(userId, data) {
|
|
2184
|
-
const actor = await this.getActorContext(userId);
|
|
2185
|
-
this.ensureDirector(actor);
|
|
2186
|
-
const creationMode = this.normalizeEnumValue(data.creationMode, CONTRACT_CREATION_MODE_VALUES, 'blank');
|
|
2187
|
-
const selectedTemplate = data.templateId && data.templateId > 0
|
|
2188
|
-
? await this.getContractTemplateById(userId, data.templateId)
|
|
2189
|
-
: null;
|
|
2190
|
-
const duplicateSource = data.duplicateFromId && data.duplicateFromId > 0
|
|
2191
|
-
? await this.getContractById(userId, data.duplicateFromId)
|
|
2192
|
-
: null;
|
|
2193
|
-
const storedSourceFile = data.sourceFileId && data.sourceFileId > 0
|
|
2194
|
-
? await this.prisma.file.findUnique({
|
|
2195
|
-
where: { id: data.sourceFileId },
|
|
2196
|
-
include: { file_mimetype: true },
|
|
2197
|
-
})
|
|
2198
|
-
: null;
|
|
2199
|
-
if (data.sourceFileId && !storedSourceFile) {
|
|
2200
|
-
throw new common_1.NotFoundException('Source contract file not found.');
|
|
2201
|
-
}
|
|
2202
|
-
const createdId = await this.prisma.$transaction(async (tx) => {
|
|
2203
|
-
var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o, _p, _q, _r, _s, _t, _u, _v, _w, _x, _y, _z, _0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16;
|
|
2204
|
-
const generatedCode = await this.generateContractCode(tx);
|
|
2205
|
-
const duplicateNameBase = (_b = (_a = this.normalizeOptionalText(duplicateSource === null || duplicateSource === void 0 ? void 0 : duplicateSource.name)) !== null && _a !== void 0 ? _a : this.normalizeOptionalText(duplicateSource === null || duplicateSource === void 0 ? void 0 : duplicateSource.code)) !== null && _b !== void 0 ? _b : 'Contract';
|
|
2206
|
-
const created = await tx.$queryRawUnsafe(`INSERT INTO operations_contract (
|
|
2207
|
-
code,
|
|
2208
|
-
name,
|
|
2209
|
-
contract_category,
|
|
2210
|
-
contract_type,
|
|
2211
|
-
client_name,
|
|
2212
|
-
signature_status,
|
|
2213
|
-
is_active,
|
|
2214
|
-
billing_model,
|
|
2215
|
-
account_manager_collaborator_id,
|
|
2216
|
-
related_collaborator_id,
|
|
2217
|
-
contract_template_id,
|
|
2218
|
-
origin_type,
|
|
2219
|
-
origin_id,
|
|
2220
|
-
start_date,
|
|
2221
|
-
end_date,
|
|
2222
|
-
signed_at,
|
|
2223
|
-
effective_date,
|
|
2224
|
-
budget_amount,
|
|
2225
|
-
monthly_hour_cap,
|
|
2226
|
-
status,
|
|
2227
|
-
creation_mode,
|
|
2228
|
-
wizard_step,
|
|
2229
|
-
description,
|
|
2230
|
-
content_html,
|
|
2231
|
-
created_by_user_id,
|
|
2232
|
-
updated_by_user_id,
|
|
2233
|
-
created_at,
|
|
2234
|
-
updated_at
|
|
2235
|
-
) VALUES (
|
|
2236
|
-
$1,
|
|
2237
|
-
$2,
|
|
2238
|
-
$3::operations_contract_contract_category_70d553ea09_enum,
|
|
2239
|
-
$4::operations_contract_contract_type_48331e2ebf_enum,
|
|
2240
|
-
$5,
|
|
2241
|
-
$6::operations_contract_signature_status_2cb7282a7b_enum,
|
|
2242
|
-
$7,
|
|
2243
|
-
$8::operations_contract_billing_model_409dc7fea2_enum,
|
|
2244
|
-
$9,
|
|
2245
|
-
$10,
|
|
2246
|
-
$11,
|
|
2247
|
-
$12::operations_contract_origin_type_07a7cc2b5d_enum,
|
|
2248
|
-
$13,
|
|
2249
|
-
$14::date,
|
|
2250
|
-
$15::date,
|
|
2251
|
-
$16::date,
|
|
2252
|
-
$17::date,
|
|
2253
|
-
$18,
|
|
2254
|
-
$19,
|
|
2255
|
-
$20::operations_contract_status_a0395962df_enum,
|
|
2256
|
-
$21::operations_contract_creation_mode_98ba669209_enum,
|
|
2257
|
-
$22,
|
|
2258
|
-
$23,
|
|
2259
|
-
$24,
|
|
2260
|
-
$25,
|
|
2261
|
-
$25,
|
|
2262
|
-
NOW(),
|
|
2263
|
-
NOW()
|
|
2264
|
-
)
|
|
2265
|
-
RETURNING id`, generatedCode, creationMode === 'duplicate'
|
|
2266
|
-
? `${duplicateNameBase} Copy`
|
|
2267
|
-
: this.normalizeOptionalText(selectedTemplate === null || selectedTemplate === void 0 ? void 0 : selectedTemplate.name), (_d = (_c = duplicateSource === null || duplicateSource === void 0 ? void 0 : duplicateSource.contractCategory) !== null && _c !== void 0 ? _c : selectedTemplate === null || selectedTemplate === void 0 ? void 0 : selectedTemplate.contractCategory) !== null && _d !== void 0 ? _d : 'client', (_f = (_e = duplicateSource === null || duplicateSource === void 0 ? void 0 : duplicateSource.contractType) !== null && _e !== void 0 ? _e : selectedTemplate === null || selectedTemplate === void 0 ? void 0 : selectedTemplate.contractType) !== null && _f !== void 0 ? _f : 'service_agreement', this.normalizeOptionalText(duplicateSource === null || duplicateSource === void 0 ? void 0 : duplicateSource.clientName), (_h = (_g = duplicateSource === null || duplicateSource === void 0 ? void 0 : duplicateSource.signatureStatus) !== null && _g !== void 0 ? _g : selectedTemplate === null || selectedTemplate === void 0 ? void 0 : selectedTemplate.signatureStatus) !== null && _h !== void 0 ? _h : 'not_started', (_j = duplicateSource === null || duplicateSource === void 0 ? void 0 : duplicateSource.isActive) !== null && _j !== void 0 ? _j : true, (_l = (_k = duplicateSource === null || duplicateSource === void 0 ? void 0 : duplicateSource.billingModel) !== null && _k !== void 0 ? _k : selectedTemplate === null || selectedTemplate === void 0 ? void 0 : selectedTemplate.billingModel) !== null && _l !== void 0 ? _l : 'time_and_material', (_m = duplicateSource === null || duplicateSource === void 0 ? void 0 : duplicateSource.accountManagerCollaboratorId) !== null && _m !== void 0 ? _m : null, (_o = duplicateSource === null || duplicateSource === void 0 ? void 0 : duplicateSource.relatedCollaboratorId) !== null && _o !== void 0 ? _o : null, (_q = (_p = duplicateSource === null || duplicateSource === void 0 ? void 0 : duplicateSource.contractTemplateId) !== null && _p !== void 0 ? _p : selectedTemplate === null || selectedTemplate === void 0 ? void 0 : selectedTemplate.id) !== null && _q !== void 0 ? _q : null, (_r = duplicateSource === null || duplicateSource === void 0 ? void 0 : duplicateSource.originType) !== null && _r !== void 0 ? _r : 'manual', (_s = duplicateSource === null || duplicateSource === void 0 ? void 0 : duplicateSource.originId) !== null && _s !== void 0 ? _s : null, (_t = duplicateSource === null || duplicateSource === void 0 ? void 0 : duplicateSource.startDate) !== null && _t !== void 0 ? _t : null, (_u = duplicateSource === null || duplicateSource === void 0 ? void 0 : duplicateSource.endDate) !== null && _u !== void 0 ? _u : null, (_v = duplicateSource === null || duplicateSource === void 0 ? void 0 : duplicateSource.signedAt) !== null && _v !== void 0 ? _v : null, (_w = duplicateSource === null || duplicateSource === void 0 ? void 0 : duplicateSource.effectiveDate) !== null && _w !== void 0 ? _w : null, (_x = duplicateSource === null || duplicateSource === void 0 ? void 0 : duplicateSource.budgetAmount) !== null && _x !== void 0 ? _x : null, (_y = duplicateSource === null || duplicateSource === void 0 ? void 0 : duplicateSource.monthlyHourCap) !== null && _y !== void 0 ? _y : null, 'draft', creationMode, creationMode === 'upload' ? 0 : creationMode === 'blank' ? 0 : 1, (_0 = (_z = duplicateSource === null || duplicateSource === void 0 ? void 0 : duplicateSource.description) !== null && _z !== void 0 ? _z : selectedTemplate === null || selectedTemplate === void 0 ? void 0 : selectedTemplate.description) !== null && _0 !== void 0 ? _0 : null, (_2 = (_1 = duplicateSource === null || duplicateSource === void 0 ? void 0 : duplicateSource.contentHtml) !== null && _1 !== void 0 ? _1 : selectedTemplate === null || selectedTemplate === void 0 ? void 0 : selectedTemplate.contentHtml) !== null && _2 !== void 0 ? _2 : null, userId);
|
|
2268
|
-
const contractId = (_3 = created[0]) === null || _3 === void 0 ? void 0 : _3.id;
|
|
2269
|
-
if (duplicateSource) {
|
|
2270
|
-
await this.replaceContractParties(tx, contractId, duplicateSource.parties);
|
|
2271
|
-
await this.replaceContractSignatures(tx, contractId, duplicateSource.signatures);
|
|
2272
|
-
await this.replaceContractFinancialTerms(tx, contractId, duplicateSource.financialTerms);
|
|
2273
|
-
await this.replaceContractRevisions(tx, contractId, duplicateSource.revisions);
|
|
2274
|
-
const currentSourceDocument = (_4 = duplicateSource.documents.find((document) => document.isCurrent && document.documentType === 'source_upload')) !== null && _4 !== void 0 ? _4 : null;
|
|
2275
|
-
if (currentSourceDocument) {
|
|
2276
|
-
await this.replaceContractDocument(tx, contractId, 'source_upload', {
|
|
2277
|
-
fileId: (_5 = currentSourceDocument.fileId) !== null && _5 !== void 0 ? _5 : null,
|
|
2278
|
-
fileName: currentSourceDocument.fileName,
|
|
2279
|
-
mimeType: currentSourceDocument.mimeType,
|
|
2280
|
-
fileContentBase64: (_6 = currentSourceDocument.fileContentBase64) !== null && _6 !== void 0 ? _6 : null,
|
|
2281
|
-
notes: (_7 = currentSourceDocument.notes) !== null && _7 !== void 0 ? _7 : null,
|
|
2282
|
-
extractionStatus: (_8 = currentSourceDocument.extractionStatus) !== null && _8 !== void 0 ? _8 : 'skipped',
|
|
2283
|
-
extractionSummary: (_9 = currentSourceDocument.extractionSummary) !== null && _9 !== void 0 ? _9 : null,
|
|
2284
|
-
});
|
|
2285
|
-
}
|
|
2286
|
-
}
|
|
2287
|
-
if (storedSourceFile) {
|
|
2288
|
-
await this.replaceContractDocument(tx, contractId, 'source_upload', {
|
|
2289
|
-
fileId: storedSourceFile.id,
|
|
2290
|
-
fileName: (_10 = this.normalizeOptionalText(data.sourceFileName)) !== null && _10 !== void 0 ? _10 : storedSourceFile.filename,
|
|
2291
|
-
mimeType: (_13 = (_11 = this.normalizeOptionalText(data.sourceMimeType)) !== null && _11 !== void 0 ? _11 : (_12 = storedSourceFile.file_mimetype) === null || _12 === void 0 ? void 0 : _12.name) !== null && _13 !== void 0 ? _13 : 'application/pdf',
|
|
2292
|
-
notes: 'Source contract document uploaded during draft creation.',
|
|
2293
|
-
extractionStatus: 'pending',
|
|
2294
|
-
extractionSummary: null,
|
|
2295
|
-
});
|
|
2296
|
-
}
|
|
2297
|
-
await this.insertContractHistory(tx, contractId, userId, 'draft_created', `Contract draft created with mode ${creationMode}.`, JSON.stringify({
|
|
2298
|
-
creationMode,
|
|
2299
|
-
templateId: (_14 = selectedTemplate === null || selectedTemplate === void 0 ? void 0 : selectedTemplate.id) !== null && _14 !== void 0 ? _14 : null,
|
|
2300
|
-
duplicateFromId: (_15 = duplicateSource === null || duplicateSource === void 0 ? void 0 : duplicateSource.id) !== null && _15 !== void 0 ? _15 : null,
|
|
2301
|
-
sourceFileId: (_16 = storedSourceFile === null || storedSourceFile === void 0 ? void 0 : storedSourceFile.id) !== null && _16 !== void 0 ? _16 : null,
|
|
2302
|
-
}));
|
|
2303
|
-
return contractId;
|
|
2304
|
-
});
|
|
2305
|
-
return this.getContractById(userId, createdId);
|
|
2306
|
-
}
|
|
2307
|
-
async extractContractSource(userId, contractId, data) {
|
|
2308
|
-
var _a, _b;
|
|
2309
|
-
const actor = await this.getActorContext(userId);
|
|
2310
|
-
this.ensureDirector(actor);
|
|
2311
|
-
const contract = await this.getContractById(userId, contractId);
|
|
2312
|
-
const sourceDocument = contract.documents.find((document) => document.isCurrent && document.documentType === 'source_upload');
|
|
2313
|
-
if (!sourceDocument) {
|
|
2314
|
-
throw new common_1.BadRequestException('No source document is attached to this contract draft.');
|
|
2315
|
-
}
|
|
2316
|
-
await this.prisma.$executeRawUnsafe(`UPDATE operations_contract_document
|
|
2317
|
-
SET extraction_status = 'processing',
|
|
2318
|
-
updated_at = NOW()
|
|
2319
|
-
WHERE id = $1`, sourceDocument.id);
|
|
2320
|
-
try {
|
|
2321
|
-
const extracted = await this.extractContractDraft(userId, {
|
|
2322
|
-
contractId,
|
|
2323
|
-
provider: (_a = data.provider) !== null && _a !== void 0 ? _a : null,
|
|
2324
|
-
promptMessage: (_b = data.promptMessage) !== null && _b !== void 0 ? _b : null,
|
|
2325
|
-
});
|
|
2326
|
-
await this.prisma.$executeRawUnsafe(`UPDATE operations_contract_document
|
|
2327
|
-
SET extraction_status = 'completed',
|
|
2328
|
-
extraction_summary = $2,
|
|
2329
|
-
updated_at = NOW()
|
|
2330
|
-
WHERE id = $1`, sourceDocument.id, extracted.summary || extracted.description || extracted.name || null);
|
|
2331
|
-
await this.insertContractHistory(this.prisma, contractId, userId, 'source_extracted', 'Source contract document extracted with AI.');
|
|
2332
|
-
return extracted;
|
|
2333
|
-
}
|
|
2334
|
-
catch (error) {
|
|
2335
|
-
await this.prisma.$executeRawUnsafe(`UPDATE operations_contract_document
|
|
2336
|
-
SET extraction_status = 'failed',
|
|
2337
|
-
updated_at = NOW()
|
|
2338
|
-
WHERE id = $1`, sourceDocument.id);
|
|
2339
|
-
throw error;
|
|
2340
|
-
}
|
|
2341
|
-
}
|
|
2342
|
-
async generateContractContent(userId, contractId, data = {}) {
|
|
2343
|
-
const actor = await this.getActorContext(userId);
|
|
2344
|
-
this.ensureDirector(actor);
|
|
2345
|
-
const contract = await this.getContractById(userId, contractId);
|
|
2346
|
-
const contentHtml = await this.generateContractContentHtml(contract, data);
|
|
2347
|
-
await this.prisma.$transaction(async (tx) => {
|
|
2348
|
-
var _a;
|
|
2349
|
-
await tx.$executeRawUnsafe(`UPDATE operations_contract
|
|
2350
|
-
SET content_html = $2,
|
|
2351
|
-
wizard_step = CASE
|
|
2352
|
-
WHEN COALESCE(wizard_step, 0) < 4 THEN 4
|
|
2353
|
-
ELSE wizard_step
|
|
2354
|
-
END,
|
|
2355
|
-
updated_by_user_id = $3,
|
|
2356
|
-
updated_at = NOW()
|
|
2357
|
-
WHERE id = $1`, contractId, contentHtml, userId);
|
|
2358
|
-
await this.insertContractHistory(tx, contractId, userId, 'content_generated', 'Contract content generated automatically for editing.', JSON.stringify({
|
|
2359
|
-
provider: (_a = data.provider) !== null && _a !== void 0 ? _a : null,
|
|
2360
|
-
overwrite: Boolean(data.overwrite),
|
|
2361
|
-
hasPrompt: Boolean(this.normalizeOptionalText(data.promptMessage)),
|
|
2362
|
-
}));
|
|
2363
|
-
});
|
|
2364
|
-
return this.getContractById(userId, contractId);
|
|
2365
|
-
}
|
|
2366
|
-
async reviewContractLegally(userId, contractId, data = {}) {
|
|
2367
|
-
const actor = await this.getActorContext(userId);
|
|
2368
|
-
this.ensureDirector(actor);
|
|
2369
|
-
const contract = await this.getContractById(userId, contractId);
|
|
2370
|
-
const review = await this.buildContractLegalReview(contract, data);
|
|
2371
|
-
await this.insertContractHistory(this.prisma, contractId, userId, 'legal_reviewed', 'Advisory legal checklist updated for this contract.', JSON.stringify(review));
|
|
2372
|
-
return review;
|
|
2373
|
-
}
|
|
2374
|
-
async generateContractPdf(userId, contractId) {
|
|
2375
|
-
const actor = await this.getActorContext(userId);
|
|
2376
|
-
this.ensureDirector(actor);
|
|
2377
|
-
const contract = await this.getContractById(userId, contractId);
|
|
2378
|
-
const pdfBuffer = await this.renderContractPdfBuffer(contract);
|
|
2379
|
-
const fileName = this.buildContractPdfFileName(contract);
|
|
2380
|
-
const uploadedFile = await this.fileService.upload('operations/contracts/generated', {
|
|
2381
|
-
fieldname: 'file',
|
|
2382
|
-
originalname: fileName,
|
|
2383
|
-
encoding: '7bit',
|
|
2384
|
-
mimetype: 'application/pdf',
|
|
2385
|
-
size: pdfBuffer.length,
|
|
2386
|
-
destination: '',
|
|
2387
|
-
filename: fileName,
|
|
2388
|
-
path: '',
|
|
2389
|
-
buffer: pdfBuffer,
|
|
2390
|
-
});
|
|
2391
|
-
await this.prisma.$transaction(async (tx) => {
|
|
2392
|
-
await this.replaceContractDocument(tx, contractId, 'generated_pdf', {
|
|
2393
|
-
fileId: uploadedFile.id,
|
|
2394
|
-
fileName,
|
|
2395
|
-
mimeType: 'application/pdf',
|
|
2396
|
-
notes: 'PDF generated from contract rich text content.',
|
|
2397
|
-
extractionStatus: 'skipped',
|
|
2398
|
-
extractionSummary: null,
|
|
2399
|
-
});
|
|
2400
|
-
await this.insertContractHistory(tx, contractId, userId, 'pdf_generated', 'Generated a branded PDF version of the contract.');
|
|
2401
|
-
});
|
|
2402
|
-
return {
|
|
2403
|
-
contractId,
|
|
2404
|
-
fileId: uploadedFile.id,
|
|
2405
|
-
fileName,
|
|
2406
|
-
mimeType: 'application/pdf',
|
|
2407
|
-
documentType: 'generated_pdf',
|
|
2408
|
-
downloadUrl: `/file/open/${uploadedFile.id}`,
|
|
2409
|
-
};
|
|
2410
|
-
}
|
|
2411
|
-
async extractContractDraft(userId, data) {
|
|
2412
|
-
var _a;
|
|
2413
|
-
const actor = await this.getActorContext(userId);
|
|
2414
|
-
this.ensureDirector(actor);
|
|
2415
|
-
const uploadFile = await this.resolveContractExtractionFile(userId, data);
|
|
2416
|
-
const aiResult = await this.aiService.chat({
|
|
2417
|
-
provider: data.provider === 'gemini' ? 'gemini' : 'openai',
|
|
2418
|
-
model: data.provider === 'gemini' ? 'gemini-1.5-flash' : 'gpt-4o-mini',
|
|
2419
|
-
message: this.normalizeExtractionString(data.promptMessage) ||
|
|
2420
|
-
'Analyze the attached contract and extract a structured draft for the contract form.',
|
|
2421
|
-
systemPrompt: this.buildContractExtractionSystemPrompt(),
|
|
2422
|
-
}, uploadFile);
|
|
2423
|
-
const parsed = this.parseAiJsonPayload(String((_a = aiResult === null || aiResult === void 0 ? void 0 : aiResult.content) !== null && _a !== void 0 ? _a : ''));
|
|
2424
|
-
const draft = this.normalizeContractExtractDraft(parsed);
|
|
2425
|
-
const warnings = [...draft.warnings];
|
|
2426
|
-
if (uploadFile.mimetype === 'application/msword' ||
|
|
2427
|
-
uploadFile.mimetype ===
|
|
2428
|
-
'application/vnd.openxmlformats-officedocument.wordprocessingml.document') {
|
|
2429
|
-
warnings.push('Word extraction is best-effort. Review names, dates, and values before saving.');
|
|
2430
|
-
}
|
|
2431
|
-
return Object.assign(Object.assign({}, draft), { warnings: Array.from(new Set(warnings.filter(Boolean))) });
|
|
2432
|
-
}
|
|
2433
2363
|
async createContractFromProposalIntegration(payload) {
|
|
2434
|
-
var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o, _p, _q, _r, _s, _t, _u, _v, _w, _x, _y
|
|
2364
|
+
var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o, _p, _q, _r, _s, _t, _u, _v, _w, _x, _y;
|
|
2435
2365
|
const sourceEntityId = String(payload.proposalId || '').trim();
|
|
2436
2366
|
if (!sourceEntityId) {
|
|
2437
2367
|
throw new common_1.BadRequestException('proposalId is required for CRM proposal integration.');
|
|
@@ -2455,30 +2385,6 @@ let OperationsService = OperationsService_1 = class OperationsService {
|
|
|
2455
2385
|
const billingModel = (_u = proposal.billingModel) !== null && _u !== void 0 ? _u : 'fixed_price';
|
|
2456
2386
|
const clientName = (_x = (_w = (_v = this.normalizeOptionalText(person.tradeName)) !== null && _v !== void 0 ? _v : this.normalizeOptionalText(person.name)) !== null && _w !== void 0 ? _w : this.normalizeOptionalText(proposal.title)) !== null && _x !== void 0 ? _x : `Proposal ${sourceEntityId}`;
|
|
2457
2387
|
const contractName = (_y = this.normalizeOptionalText(proposal.title)) !== null && _y !== void 0 ? _y : `Proposal ${sourceEntityId}`;
|
|
2458
|
-
const financialTerms = items
|
|
2459
|
-
.map((item) => {
|
|
2460
|
-
var _a, _b, _c;
|
|
2461
|
-
return ({
|
|
2462
|
-
termType: this.normalizeEnumValue(item.termType, FINANCIAL_TERM_TYPE_VALUES, 'value'),
|
|
2463
|
-
label: (_a = this.normalizeOptionalText(item.name)) !== null && _a !== void 0 ? _a : 'Commercial term',
|
|
2464
|
-
amount: Number((_b = item.amount) !== null && _b !== void 0 ? _b : Number(item.totalAmountCents || 0) / 100),
|
|
2465
|
-
recurrence: this.normalizeEnumValue(item.recurrence, RECURRENCE_VALUES, 'one_time'),
|
|
2466
|
-
dueDay: (_c = item.dueDay) !== null && _c !== void 0 ? _c : null,
|
|
2467
|
-
notes: this.normalizeOptionalText(item.description),
|
|
2468
|
-
});
|
|
2469
|
-
})
|
|
2470
|
-
.filter((term) => Number.isFinite(term.amount) && term.amount > 0);
|
|
2471
|
-
const fallbackAmount = Number((_z = proposal.totalAmount) !== null && _z !== void 0 ? _z : 0);
|
|
2472
|
-
if (financialTerms.length === 0 && Number.isFinite(fallbackAmount) && fallbackAmount > 0) {
|
|
2473
|
-
financialTerms.push({
|
|
2474
|
-
termType: 'revenue',
|
|
2475
|
-
label: contractName,
|
|
2476
|
-
amount: fallbackAmount,
|
|
2477
|
-
recurrence: 'one_time',
|
|
2478
|
-
dueDay: null,
|
|
2479
|
-
notes: this.normalizeOptionalText(proposal.notes),
|
|
2480
|
-
});
|
|
2481
|
-
}
|
|
2482
2388
|
const primaryPartyRole = ['employee', 'contractor'].includes(contractCategory)
|
|
2483
2389
|
? 'employee'
|
|
2484
2390
|
: ['supplier', 'vendor'].includes(contractCategory)
|
|
@@ -2487,7 +2393,7 @@ let OperationsService = OperationsService_1 = class OperationsService {
|
|
|
2487
2393
|
? 'partner'
|
|
2488
2394
|
: 'client';
|
|
2489
2395
|
return this.prisma.$transaction(async (tx) => {
|
|
2490
|
-
var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o
|
|
2396
|
+
var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o;
|
|
2491
2397
|
await tx.$queryRawUnsafe(`SELECT pg_advisory_xact_lock(hashtext($1))`, `operations:crm_proposal:${sourceEntityId}`);
|
|
2492
2398
|
const existingContracts = await tx.$queryRawUnsafe(`SELECT id, code
|
|
2493
2399
|
FROM operations_contract
|
|
@@ -2515,7 +2421,6 @@ let OperationsService = OperationsService_1 = class OperationsService {
|
|
|
2515
2421
|
billing_model,
|
|
2516
2422
|
account_manager_collaborator_id,
|
|
2517
2423
|
related_collaborator_id,
|
|
2518
|
-
contract_template_id,
|
|
2519
2424
|
origin_type,
|
|
2520
2425
|
origin_id,
|
|
2521
2426
|
start_date,
|
|
@@ -2563,8 +2468,8 @@ let OperationsService = OperationsService_1 = class OperationsService {
|
|
|
2563
2468
|
NOW(),
|
|
2564
2469
|
NOW()
|
|
2565
2470
|
)
|
|
2566
|
-
RETURNING id`, generatedCode, contractName, contractCategory, contractType, clientName, 'not_started', true, billingModel, null, null, null, 'crm_proposal', sourceEntityId, (_b = proposal.validFrom) !== null && _b !== void 0 ? _b : null, (_c = proposal.validUntil) !== null && _c !== void 0 ? _c : null, null, (_d = proposal.validFrom) !== null && _d !== void 0 ? _d : null,
|
|
2567
|
-
const contractId = (
|
|
2471
|
+
RETURNING id`, generatedCode, contractName, contractCategory, contractType, clientName, 'not_started', true, billingModel, null, null, null, 'crm_proposal', sourceEntityId, (_b = proposal.validFrom) !== null && _b !== void 0 ? _b : null, (_c = proposal.validUntil) !== null && _c !== void 0 ? _c : null, null, (_d = proposal.validFrom) !== null && _d !== void 0 ? _d : null, Number((_e = proposal.totalAmount) !== null && _e !== void 0 ? _e : 0) > 0 ? Number((_f = proposal.totalAmount) !== null && _f !== void 0 ? _f : 0) : null, null, 'draft', 'blank', 1, this.normalizeOptionalText(proposal.notes), this.normalizeOptionalText((_g = payload.revision) === null || _g === void 0 ? void 0 : _g.contentHtml), Number(payload.approvedByUserId) || null);
|
|
2472
|
+
const contractId = (_h = created[0]) === null || _h === void 0 ? void 0 : _h.id;
|
|
2568
2473
|
if (!contractId) {
|
|
2569
2474
|
throw new common_1.BadRequestException('Could not create contract draft from proposal.');
|
|
2570
2475
|
}
|
|
@@ -2579,27 +2484,10 @@ let OperationsService = OperationsService_1 = class OperationsService {
|
|
|
2579
2484
|
isPrimary: true,
|
|
2580
2485
|
},
|
|
2581
2486
|
]);
|
|
2582
|
-
await this.
|
|
2583
|
-
termType: term.termType,
|
|
2584
|
-
label: term.label,
|
|
2585
|
-
amount: term.amount,
|
|
2586
|
-
recurrence: term.recurrence,
|
|
2587
|
-
dueDay: term.dueDay,
|
|
2588
|
-
notes: term.notes,
|
|
2589
|
-
})));
|
|
2590
|
-
await this.replaceContractRevisions(tx, contractId, [
|
|
2591
|
-
{
|
|
2592
|
-
revisionType: 'revision',
|
|
2593
|
-
title: (_h = (_g = payload.revision) === null || _g === void 0 ? void 0 : _g.title) !== null && _h !== void 0 ? _h : contractName,
|
|
2594
|
-
effectiveDate: (_j = proposal.validFrom) !== null && _j !== void 0 ? _j : null,
|
|
2595
|
-
status: 'draft',
|
|
2596
|
-
summary: (_l = this.normalizeOptionalText((_k = payload.revision) === null || _k === void 0 ? void 0 : _k.summary)) !== null && _l !== void 0 ? _l : this.normalizeOptionalText(proposal.notes),
|
|
2597
|
-
},
|
|
2598
|
-
]);
|
|
2599
|
-
await this.insertContractHistory(tx, contractId, Number(payload.approvedByUserId) || null, 'created', `Draft contract generated from CRM proposal ${(_m = proposal.code) !== null && _m !== void 0 ? _m : sourceEntityId}.`, JSON.stringify({
|
|
2487
|
+
await this.insertContractHistory(tx, contractId, Number(payload.approvedByUserId) || null, 'created', `Draft contract generated from CRM proposal ${(_j = proposal.code) !== null && _j !== void 0 ? _j : sourceEntityId}.`, JSON.stringify({
|
|
2600
2488
|
correlationId: payload.correlationId || `proposal:${sourceEntityId}`,
|
|
2601
|
-
proposalId: (
|
|
2602
|
-
proposalRevisionId: (
|
|
2489
|
+
proposalId: (_k = payload.proposalId) !== null && _k !== void 0 ? _k : (Number(sourceEntityId) > 0 ? Number(sourceEntityId) : null),
|
|
2490
|
+
proposalRevisionId: (_l = payload.proposalRevisionId) !== null && _l !== void 0 ? _l : null,
|
|
2603
2491
|
sourceModule: 'contact',
|
|
2604
2492
|
sourceEntity: 'proposal',
|
|
2605
2493
|
sourceId: sourceEntityId,
|
|
@@ -2620,10 +2508,9 @@ let OperationsService = OperationsService_1 = class OperationsService {
|
|
|
2620
2508
|
billingModel,
|
|
2621
2509
|
originType: 'crm_proposal',
|
|
2622
2510
|
originId: sourceEntityId,
|
|
2623
|
-
startDate: (
|
|
2624
|
-
endDate: (
|
|
2511
|
+
startDate: (_m = proposal.validFrom) !== null && _m !== void 0 ? _m : null,
|
|
2512
|
+
endDate: (_o = proposal.validUntil) !== null && _o !== void 0 ? _o : null,
|
|
2625
2513
|
description: this.normalizeOptionalText(proposal.notes),
|
|
2626
|
-
financialTerms,
|
|
2627
2514
|
}, payload, String(payload.locale || '').trim() || 'en', Number(payload.approvedByUserId) || undefined),
|
|
2628
2515
|
metadata: {
|
|
2629
2516
|
producer: 'operations',
|
|
@@ -2644,7 +2531,7 @@ let OperationsService = OperationsService_1 = class OperationsService {
|
|
|
2644
2531
|
});
|
|
2645
2532
|
}
|
|
2646
2533
|
buildContractCreatedEventPayload(contract, payload, locale = 'en', createdByUserId) {
|
|
2647
|
-
var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o, _p, _q, _r, _s, _t, _u, _v, _w, _x, _y, _z, _0
|
|
2534
|
+
var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o, _p, _q, _r, _s, _t, _u, _v, _w, _x, _y, _z, _0;
|
|
2648
2535
|
return {
|
|
2649
2536
|
contractId: contract.id,
|
|
2650
2537
|
proposalId: (_a = payload.proposalId) !== null && _a !== void 0 ? _a : null,
|
|
@@ -2674,19 +2561,18 @@ let OperationsService = OperationsService_1 = class OperationsService {
|
|
|
2674
2561
|
startDate: (_r = contract.startDate) !== null && _r !== void 0 ? _r : null,
|
|
2675
2562
|
endDate: (_s = contract.endDate) !== null && _s !== void 0 ? _s : null,
|
|
2676
2563
|
description: (_t = contract.description) !== null && _t !== void 0 ? _t : null,
|
|
2677
|
-
financialTerms: (_u = contract.financialTerms) !== null && _u !== void 0 ? _u : [],
|
|
2678
2564
|
},
|
|
2679
|
-
proposal: (
|
|
2680
|
-
code: (
|
|
2681
|
-
title: (
|
|
2682
|
-
totalAmount: (
|
|
2683
|
-
notes: (
|
|
2565
|
+
proposal: (_u = payload.proposal) !== null && _u !== void 0 ? _u : {
|
|
2566
|
+
code: (_v = payload.code) !== null && _v !== void 0 ? _v : null,
|
|
2567
|
+
title: (_w = payload.title) !== null && _w !== void 0 ? _w : null,
|
|
2568
|
+
totalAmount: (_x = payload.total) !== null && _x !== void 0 ? _x : null,
|
|
2569
|
+
notes: (_z = (_y = payload.commercialTerms) === null || _y === void 0 ? void 0 : _y.notes) !== null && _z !== void 0 ? _z : null,
|
|
2684
2570
|
},
|
|
2685
|
-
person: (
|
|
2571
|
+
person: (_0 = payload.person) !== null && _0 !== void 0 ? _0 : null,
|
|
2686
2572
|
};
|
|
2687
2573
|
}
|
|
2688
2574
|
async buildContractActivatedEventPayload(contract, locale = 'en', activatedByUserId) {
|
|
2689
|
-
var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o, _p, _q, _r, _s, _t, _u, _v, _w, _x, _y, _z, _0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10
|
|
2575
|
+
var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o, _p, _q, _r, _s, _t, _u, _v, _w, _x, _y, _z, _0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10;
|
|
2690
2576
|
let personId = null;
|
|
2691
2577
|
let proposalId = null;
|
|
2692
2578
|
let personRecord = null;
|
|
@@ -2747,18 +2633,7 @@ let OperationsService = OperationsService_1 = class OperationsService {
|
|
|
2747
2633
|
}
|
|
2748
2634
|
}
|
|
2749
2635
|
}
|
|
2750
|
-
const
|
|
2751
|
-
var _a, _b, _c, _d, _e;
|
|
2752
|
-
return ({
|
|
2753
|
-
label: term.label,
|
|
2754
|
-
termType: (_a = term.termType) !== null && _a !== void 0 ? _a : 'value',
|
|
2755
|
-
amount: Number((_b = term.amount) !== null && _b !== void 0 ? _b : 0),
|
|
2756
|
-
recurrence: (_c = term.recurrence) !== null && _c !== void 0 ? _c : 'one_time',
|
|
2757
|
-
dueDay: (_d = term.dueDay) !== null && _d !== void 0 ? _d : null,
|
|
2758
|
-
notes: (_e = term.notes) !== null && _e !== void 0 ? _e : null,
|
|
2759
|
-
});
|
|
2760
|
-
});
|
|
2761
|
-
const totalAmount = financialTerms.reduce((sum, term) => sum + (Number.isFinite(term.amount) ? term.amount : 0), 0) || Number((_h = contract.budgetAmount) !== null && _h !== void 0 ? _h : 0);
|
|
2636
|
+
const totalAmount = Number((_g = contract.budgetAmount) !== null && _g !== void 0 ? _g : 0);
|
|
2762
2637
|
return {
|
|
2763
2638
|
contractId: contract.id,
|
|
2764
2639
|
proposalId,
|
|
@@ -2766,7 +2641,7 @@ let OperationsService = OperationsService_1 = class OperationsService {
|
|
|
2766
2641
|
activatedByUserId: activatedByUserId !== null && activatedByUserId !== void 0 ? activatedByUserId : null,
|
|
2767
2642
|
signedByUserId: activatedByUserId !== null && activatedByUserId !== void 0 ? activatedByUserId : null,
|
|
2768
2643
|
activatedAt: new Date().toISOString(),
|
|
2769
|
-
signedAt: (
|
|
2644
|
+
signedAt: (_k = (_j = (_h = contract.signedAt) !== null && _h !== void 0 ? _h : contract.effectiveDate) !== null && _j !== void 0 ? _j : contract.startDate) !== null && _k !== void 0 ? _k : null,
|
|
2770
2645
|
locale,
|
|
2771
2646
|
correlationId: proposalId ? `proposal:${proposalId}` : `contract:${contract.id}`,
|
|
2772
2647
|
sourceModule: 'operations',
|
|
@@ -2776,38 +2651,37 @@ let OperationsService = OperationsService_1 = class OperationsService {
|
|
|
2776
2651
|
source_entity: 'contract',
|
|
2777
2652
|
source_id: String(contract.id),
|
|
2778
2653
|
contract: {
|
|
2779
|
-
code: (
|
|
2780
|
-
name: (
|
|
2781
|
-
clientName: (
|
|
2782
|
-
contractCategory: (
|
|
2783
|
-
contractType: (
|
|
2784
|
-
billingModel: (
|
|
2785
|
-
originType: (
|
|
2786
|
-
originId: (
|
|
2787
|
-
startDate: (
|
|
2788
|
-
endDate: (
|
|
2789
|
-
signedAt: (
|
|
2790
|
-
effectiveDate: (
|
|
2791
|
-
budgetAmount: (
|
|
2792
|
-
description: (
|
|
2793
|
-
|
|
2794
|
-
parties: (_1 = contract.parties) !== null && _1 !== void 0 ? _1 : [],
|
|
2654
|
+
code: (_l = contract.code) !== null && _l !== void 0 ? _l : null,
|
|
2655
|
+
name: (_m = contract.name) !== null && _m !== void 0 ? _m : null,
|
|
2656
|
+
clientName: (_o = contract.clientName) !== null && _o !== void 0 ? _o : null,
|
|
2657
|
+
contractCategory: (_p = contract.contractCategory) !== null && _p !== void 0 ? _p : 'client',
|
|
2658
|
+
contractType: (_q = contract.contractType) !== null && _q !== void 0 ? _q : 'service_agreement',
|
|
2659
|
+
billingModel: (_r = contract.billingModel) !== null && _r !== void 0 ? _r : 'fixed_price',
|
|
2660
|
+
originType: (_s = contract.originType) !== null && _s !== void 0 ? _s : 'manual',
|
|
2661
|
+
originId: (_t = contract.originId) !== null && _t !== void 0 ? _t : null,
|
|
2662
|
+
startDate: (_u = contract.startDate) !== null && _u !== void 0 ? _u : null,
|
|
2663
|
+
endDate: (_v = contract.endDate) !== null && _v !== void 0 ? _v : null,
|
|
2664
|
+
signedAt: (_w = contract.signedAt) !== null && _w !== void 0 ? _w : null,
|
|
2665
|
+
effectiveDate: (_x = contract.effectiveDate) !== null && _x !== void 0 ? _x : null,
|
|
2666
|
+
budgetAmount: (_y = contract.budgetAmount) !== null && _y !== void 0 ? _y : null,
|
|
2667
|
+
description: (_z = contract.description) !== null && _z !== void 0 ? _z : null,
|
|
2668
|
+
parties: (_0 = contract.parties) !== null && _0 !== void 0 ? _0 : [],
|
|
2795
2669
|
},
|
|
2796
2670
|
person: personRecord
|
|
2797
2671
|
? {
|
|
2798
|
-
id: (
|
|
2799
|
-
name: (
|
|
2800
|
-
tradeName: (
|
|
2801
|
-
email: (
|
|
2802
|
-
phone: (
|
|
2803
|
-
document: (
|
|
2672
|
+
id: (_1 = personRecord.id) !== null && _1 !== void 0 ? _1 : null,
|
|
2673
|
+
name: (_2 = personRecord.name) !== null && _2 !== void 0 ? _2 : null,
|
|
2674
|
+
tradeName: (_3 = personRecord.trade_name) !== null && _3 !== void 0 ? _3 : null,
|
|
2675
|
+
email: (_4 = personRecord.email) !== null && _4 !== void 0 ? _4 : null,
|
|
2676
|
+
phone: (_5 = personRecord.phone) !== null && _5 !== void 0 ? _5 : null,
|
|
2677
|
+
document: (_6 = personRecord.document) !== null && _6 !== void 0 ? _6 : null,
|
|
2804
2678
|
}
|
|
2805
2679
|
: null,
|
|
2806
2680
|
receivable: {
|
|
2807
2681
|
personId,
|
|
2808
|
-
documentNumber: (
|
|
2682
|
+
documentNumber: (_7 = contract.code) !== null && _7 !== void 0 ? _7 : `CONTRACT-${contract.id}`,
|
|
2809
2683
|
totalAmount,
|
|
2810
|
-
description: (
|
|
2684
|
+
description: (_10 = (_9 = (_8 = contract.description) !== null && _8 !== void 0 ? _8 : contract.name) !== null && _9 !== void 0 ? _9 : contract.code) !== null && _10 !== void 0 ? _10 : null,
|
|
2811
2685
|
},
|
|
2812
2686
|
};
|
|
2813
2687
|
}
|
|
@@ -2832,7 +2706,6 @@ let OperationsService = OperationsService_1 = class OperationsService {
|
|
|
2832
2706
|
this.pushUpdate(updates, params, 'billing_model', data.billingModel, 'operations_contract_billing_model_409dc7fea2_enum');
|
|
2833
2707
|
this.pushUpdate(updates, params, 'account_manager_collaborator_id', data.accountManagerCollaboratorId);
|
|
2834
2708
|
this.pushUpdate(updates, params, 'related_collaborator_id', data.relatedCollaboratorId);
|
|
2835
|
-
this.pushUpdate(updates, params, 'contract_template_id', data.contractTemplateId);
|
|
2836
2709
|
this.pushUpdate(updates, params, 'origin_type', data.originType, 'operations_contract_origin_type_07a7cc2b5d_enum');
|
|
2837
2710
|
this.pushUpdate(updates, params, 'origin_id', data.originId);
|
|
2838
2711
|
this.pushUpdate(updates, params, 'start_date', data.startDate, 'date');
|
|
@@ -2847,7 +2720,7 @@ let OperationsService = OperationsService_1 = class OperationsService {
|
|
|
2847
2720
|
this.pushUpdate(updates, params, 'description', data.description);
|
|
2848
2721
|
this.pushUpdate(updates, params, 'content_html', data.contentHtml);
|
|
2849
2722
|
await this.prisma.$transaction(async (tx) => {
|
|
2850
|
-
var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o, _p, _q, _r, _s, _t, _u, _v, _w, _x
|
|
2723
|
+
var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o, _p, _q, _r, _s, _t, _u, _v, _w, _x;
|
|
2851
2724
|
if (updates.length) {
|
|
2852
2725
|
params.push(contractId);
|
|
2853
2726
|
await tx.$executeRawUnsafe(`UPDATE operations_contract
|
|
@@ -2858,15 +2731,6 @@ let OperationsService = OperationsService_1 = class OperationsService {
|
|
|
2858
2731
|
if (data.parties) {
|
|
2859
2732
|
await this.replaceContractParties(tx, contractId, data.parties);
|
|
2860
2733
|
}
|
|
2861
|
-
if (data.signatures) {
|
|
2862
|
-
await this.replaceContractSignatures(tx, contractId, data.signatures);
|
|
2863
|
-
}
|
|
2864
|
-
if (data.financialTerms) {
|
|
2865
|
-
await this.replaceContractFinancialTerms(tx, contractId, data.financialTerms);
|
|
2866
|
-
}
|
|
2867
|
-
if (data.revisions) {
|
|
2868
|
-
await this.replaceContractRevisions(tx, contractId, data.revisions);
|
|
2869
|
-
}
|
|
2870
2734
|
if (data.replaceUploadedPdfDocument) {
|
|
2871
2735
|
await this.replaceContractDocument(tx, contractId, 'source_upload', data.replaceUploadedPdfDocument);
|
|
2872
2736
|
}
|
|
@@ -2888,8 +2752,7 @@ let OperationsService = OperationsService_1 = class OperationsService {
|
|
|
2888
2752
|
effectiveDate: (_m = data.effectiveDate) !== null && _m !== void 0 ? _m : current.effectiveDate,
|
|
2889
2753
|
budgetAmount: (_o = data.budgetAmount) !== null && _o !== void 0 ? _o : current.budgetAmount,
|
|
2890
2754
|
description: (_p = data.description) !== null && _p !== void 0 ? _p : current.description,
|
|
2891
|
-
|
|
2892
|
-
parties: (_r = data.parties) !== null && _r !== void 0 ? _r : current.parties,
|
|
2755
|
+
parties: (_q = data.parties) !== null && _q !== void 0 ? _q : current.parties,
|
|
2893
2756
|
}, 'en', userId);
|
|
2894
2757
|
if (shouldPublishSigned) {
|
|
2895
2758
|
await this.integrationApi.publishEvent({
|
|
@@ -2897,15 +2760,15 @@ let OperationsService = OperationsService_1 = class OperationsService {
|
|
|
2897
2760
|
sourceModule: 'operations',
|
|
2898
2761
|
aggregateType: 'contract',
|
|
2899
2762
|
aggregateId: String(contractId),
|
|
2900
|
-
payload: Object.assign(Object.assign({}, contractEventPayload), { signedByUserId: userId !== null && userId !== void 0 ? userId : null, signedAt: (
|
|
2763
|
+
payload: Object.assign(Object.assign({}, contractEventPayload), { signedByUserId: userId !== null && userId !== void 0 ? userId : null, signedAt: (_t = (_s = (_r = data.signedAt) !== null && _r !== void 0 ? _r : current.signedAt) !== null && _s !== void 0 ? _s : contractEventPayload.signedAt) !== null && _t !== void 0 ? _t : new Date().toISOString() }),
|
|
2901
2764
|
metadata: {
|
|
2902
2765
|
producer: 'operations',
|
|
2903
2766
|
correlationId: contractEventPayload.correlationId || `contract:${contractId}`,
|
|
2904
2767
|
sourceModule: 'operations',
|
|
2905
2768
|
sourceEntity: 'contract',
|
|
2906
2769
|
sourceId: String(contractId),
|
|
2907
|
-
originType: (
|
|
2908
|
-
originId: (
|
|
2770
|
+
originType: (_u = data.originType) !== null && _u !== void 0 ? _u : current.originType,
|
|
2771
|
+
originId: (_v = data.originId) !== null && _v !== void 0 ? _v : current.originId,
|
|
2909
2772
|
lifecycle: 'signed',
|
|
2910
2773
|
},
|
|
2911
2774
|
}, {
|
|
@@ -2925,8 +2788,8 @@ let OperationsService = OperationsService_1 = class OperationsService {
|
|
|
2925
2788
|
sourceModule: 'operations',
|
|
2926
2789
|
sourceEntity: 'contract',
|
|
2927
2790
|
sourceId: String(contractId),
|
|
2928
|
-
originType: (
|
|
2929
|
-
originId: (
|
|
2791
|
+
originType: (_w = data.originType) !== null && _w !== void 0 ? _w : current.originType,
|
|
2792
|
+
originId: (_x = data.originId) !== null && _x !== void 0 ? _x : current.originId,
|
|
2930
2793
|
lifecycle: 'activated',
|
|
2931
2794
|
},
|
|
2932
2795
|
}, {
|
|
@@ -2950,10 +2813,7 @@ let OperationsService = OperationsService_1 = class OperationsService {
|
|
|
2950
2813
|
AND deleted_at IS NULL`, contractId);
|
|
2951
2814
|
for (const tableName of [
|
|
2952
2815
|
'operations_contract_party',
|
|
2953
|
-
'operations_contract_signature',
|
|
2954
|
-
'operations_contract_financial_term',
|
|
2955
2816
|
'operations_contract_document',
|
|
2956
|
-
'operations_contract_revision',
|
|
2957
2817
|
]) {
|
|
2958
2818
|
await tx.$executeRawUnsafe(`UPDATE ${tableName}
|
|
2959
2819
|
SET deleted_at = NOW(),
|
|
@@ -2972,9 +2832,43 @@ let OperationsService = OperationsService_1 = class OperationsService {
|
|
|
2972
2832
|
});
|
|
2973
2833
|
return { success: true };
|
|
2974
2834
|
}
|
|
2975
|
-
async listTimesheets(userId) {
|
|
2835
|
+
async listTimesheets(userId, filters = {}) {
|
|
2836
|
+
var _a, _b, _c, _d, _e, _f;
|
|
2976
2837
|
const actor = await this.getActorContext(userId);
|
|
2977
2838
|
const filter = this.buildIdFilter(actor.visibleCollaboratorIds, 't.collaborator_id', actor.isDirector);
|
|
2839
|
+
const pagination = this.shouldPaginate(filters)
|
|
2840
|
+
? this.normalizePaginationParams(filters, {
|
|
2841
|
+
defaultSortField: 'weekStartDate',
|
|
2842
|
+
defaultSortOrder: 'desc',
|
|
2843
|
+
allowedSortFields: ['weekStartDate', 'weekEndDate', 'collaboratorName', 'status'],
|
|
2844
|
+
})
|
|
2845
|
+
: null;
|
|
2846
|
+
const params = [...filter.params];
|
|
2847
|
+
const where = ['t.deleted_at IS NULL', filter.clause];
|
|
2848
|
+
if (filters.status && filters.status !== 'all') {
|
|
2849
|
+
where.push(`t.status::text = ${this.param(params, filters.status)}`);
|
|
2850
|
+
}
|
|
2851
|
+
if (pagination === null || pagination === void 0 ? void 0 : pagination.search) {
|
|
2852
|
+
const searchPlaceholder = this.param(params, `%${pagination.search}%`);
|
|
2853
|
+
where.push(`(
|
|
2854
|
+
COALESCE(c.display_name, '') ILIKE ${searchPlaceholder}
|
|
2855
|
+
OR COALESCE(a.display_name, '') ILIKE ${searchPlaceholder}
|
|
2856
|
+
OR COALESCE(t.notes, '') ILIKE ${searchPlaceholder}
|
|
2857
|
+
OR COALESCE(approval.decision_note, '') ILIKE ${searchPlaceholder}
|
|
2858
|
+
)`);
|
|
2859
|
+
}
|
|
2860
|
+
const whereClause = where.join(' AND ');
|
|
2861
|
+
const sortColumn = (_b = {
|
|
2862
|
+
weekStartDate: 't.week_start_date',
|
|
2863
|
+
weekEndDate: 't.week_end_date',
|
|
2864
|
+
collaboratorName: 'c.display_name',
|
|
2865
|
+
status: 't.status',
|
|
2866
|
+
}[(_a = pagination === null || pagination === void 0 ? void 0 : pagination.sortField) !== null && _a !== void 0 ? _a : 'weekStartDate']) !== null && _b !== void 0 ? _b : 't.week_start_date';
|
|
2867
|
+
const headerParams = [...params];
|
|
2868
|
+
const limitSql = pagination
|
|
2869
|
+
? `LIMIT ${this.param(headerParams, pagination.pageSize)}
|
|
2870
|
+
OFFSET ${this.param(headerParams, pagination.offset)}`
|
|
2871
|
+
: '';
|
|
2978
2872
|
const headers = await this.queryRows(`SELECT t.id,
|
|
2979
2873
|
t.collaborator_id AS "collaboratorId",
|
|
2980
2874
|
c.display_name AS "collaboratorName",
|
|
@@ -2995,11 +2889,26 @@ let OperationsService = OperationsService_1 = class OperationsService {
|
|
|
2995
2889
|
ON approval.target_type = 'timesheet'
|
|
2996
2890
|
AND approval.target_id = t.id
|
|
2997
2891
|
AND approval.deleted_at IS NULL
|
|
2998
|
-
WHERE
|
|
2999
|
-
ORDER BY
|
|
2892
|
+
WHERE ${whereClause}
|
|
2893
|
+
ORDER BY ${sortColumn} ${(_d = (_c = pagination === null || pagination === void 0 ? void 0 : pagination.sortOrder) === null || _c === void 0 ? void 0 : _c.toUpperCase()) !== null && _d !== void 0 ? _d : 'DESC'}, t.id DESC
|
|
2894
|
+
${limitSql}`, headerParams);
|
|
3000
2895
|
if (!headers.length) {
|
|
2896
|
+
if (pagination) {
|
|
2897
|
+
return this.buildPaginationResult([], 0, pagination.page, pagination.pageSize);
|
|
2898
|
+
}
|
|
3001
2899
|
return headers;
|
|
3002
2900
|
}
|
|
2901
|
+
const total = pagination
|
|
2902
|
+
? Number((_f = (_e = (await this.querySingle(`SELECT COUNT(*)::text AS total
|
|
2903
|
+
FROM operations_timesheet t
|
|
2904
|
+
JOIN operations_collaborator c ON c.id = t.collaborator_id
|
|
2905
|
+
LEFT JOIN operations_collaborator a ON a.id = t.approver_collaborator_id
|
|
2906
|
+
LEFT JOIN operations_approval approval
|
|
2907
|
+
ON approval.target_type = 'timesheet'
|
|
2908
|
+
AND approval.target_id = t.id
|
|
2909
|
+
AND approval.deleted_at IS NULL
|
|
2910
|
+
WHERE ${whereClause}`, params))) === null || _e === void 0 ? void 0 : _e.total) !== null && _f !== void 0 ? _f : 0)
|
|
2911
|
+
: 0;
|
|
3003
2912
|
const entries = await this.queryRows(`SELECT e.id,
|
|
3004
2913
|
e.timesheet_id AS "timesheetId",
|
|
3005
2914
|
e.project_assignment_id AS "projectAssignmentId",
|
|
@@ -3026,10 +2935,14 @@ let OperationsService = OperationsService_1 = class OperationsService {
|
|
|
3026
2935
|
AND e.timesheet_id = ANY($1::int[])
|
|
3027
2936
|
ORDER BY e.work_date ASC, e.id ASC`, [headers.map((item) => item.id)]);
|
|
3028
2937
|
const grouped = this.groupBy(entries, 'timesheetId');
|
|
3029
|
-
|
|
2938
|
+
const data = headers.map((timesheet) => {
|
|
3030
2939
|
var _a;
|
|
3031
2940
|
return (Object.assign(Object.assign({}, timesheet), { entries: (_a = grouped[timesheet.id]) !== null && _a !== void 0 ? _a : [] }));
|
|
3032
2941
|
});
|
|
2942
|
+
if (!pagination) {
|
|
2943
|
+
return data;
|
|
2944
|
+
}
|
|
2945
|
+
return this.buildPaginationResult(data, total, pagination.page, pagination.pageSize);
|
|
3033
2946
|
}
|
|
3034
2947
|
async createTimesheet(userId, data) {
|
|
3035
2948
|
const actor = await this.getActorContext(userId);
|
|
@@ -3142,17 +3055,40 @@ let OperationsService = OperationsService_1 = class OperationsService {
|
|
|
3142
3055
|
});
|
|
3143
3056
|
return this.listSingleTimesheet(actor, timesheetId);
|
|
3144
3057
|
}
|
|
3145
|
-
async listTimeOffRequests(userId) {
|
|
3058
|
+
async listTimeOffRequests(userId, filters = {}) {
|
|
3059
|
+
var _a, _b;
|
|
3146
3060
|
const actor = await this.getActorContext(userId);
|
|
3147
3061
|
const filter = this.buildIdFilter(actor.visibleCollaboratorIds, 'tor.collaborator_id', actor.isDirector);
|
|
3148
|
-
|
|
3062
|
+
const pagination = this.shouldPaginate(filters)
|
|
3063
|
+
? this.normalizePaginationParams(filters, {
|
|
3064
|
+
defaultSortField: 'startDate',
|
|
3065
|
+
defaultSortOrder: 'desc',
|
|
3066
|
+
allowedSortFields: ['startDate', 'endDate', 'collaboratorName', 'status'],
|
|
3067
|
+
})
|
|
3068
|
+
: null;
|
|
3069
|
+
const params = [...filter.params];
|
|
3070
|
+
const where = ['tor.deleted_at IS NULL', filter.clause];
|
|
3071
|
+
if (filters.status && filters.status !== 'all') {
|
|
3072
|
+
where.push(`tor.status::text = ${this.param(params, filters.status)}`);
|
|
3073
|
+
}
|
|
3074
|
+
if (pagination === null || pagination === void 0 ? void 0 : pagination.search) {
|
|
3075
|
+
const searchPlaceholder = this.param(params, `%${pagination.search}%`);
|
|
3076
|
+
where.push(`(
|
|
3077
|
+
COALESCE(c.display_name, '') ILIKE ${searchPlaceholder}
|
|
3078
|
+
OR COALESCE(a.display_name, '') ILIKE ${searchPlaceholder}
|
|
3079
|
+
OR COALESCE(tor.reason, '') ILIKE ${searchPlaceholder}
|
|
3080
|
+
OR COALESCE(tor.request_type::text, '') ILIKE ${searchPlaceholder}
|
|
3081
|
+
)`);
|
|
3082
|
+
}
|
|
3083
|
+
const whereClause = where.join(' AND ');
|
|
3084
|
+
const baseQuery = `SELECT tor.id,
|
|
3149
3085
|
tor.collaborator_id AS "collaboratorId",
|
|
3150
3086
|
c.display_name AS "collaboratorName",
|
|
3151
3087
|
tor.approver_collaborator_id AS "approverCollaboratorId",
|
|
3152
3088
|
a.display_name AS "approverName",
|
|
3153
3089
|
tor.request_type AS "requestType",
|
|
3154
|
-
tor.start_date AS "startDate",
|
|
3155
|
-
tor.end_date AS "endDate",
|
|
3090
|
+
tor.start_date::text AS "startDate",
|
|
3091
|
+
tor.end_date::text AS "endDate",
|
|
3156
3092
|
tor.total_days AS "totalDays",
|
|
3157
3093
|
tor.status,
|
|
3158
3094
|
tor.reason,
|
|
@@ -3166,8 +3102,30 @@ let OperationsService = OperationsService_1 = class OperationsService {
|
|
|
3166
3102
|
ON approval.target_type = 'time_off_request'
|
|
3167
3103
|
AND approval.target_id = tor.id
|
|
3168
3104
|
AND approval.deleted_at IS NULL
|
|
3169
|
-
WHERE
|
|
3170
|
-
|
|
3105
|
+
WHERE ${whereClause}`;
|
|
3106
|
+
if (!pagination) {
|
|
3107
|
+
return this.queryRows(`${baseQuery}
|
|
3108
|
+
ORDER BY tor.start_date DESC, tor.id DESC`, params);
|
|
3109
|
+
}
|
|
3110
|
+
const totalRow = await this.querySingle(`SELECT COUNT(*)::text AS total
|
|
3111
|
+
FROM operations_time_off_request tor
|
|
3112
|
+
JOIN operations_collaborator c ON c.id = tor.collaborator_id
|
|
3113
|
+
LEFT JOIN operations_collaborator a ON a.id = tor.approver_collaborator_id
|
|
3114
|
+
WHERE ${whereClause}`, params);
|
|
3115
|
+
const sortColumn = (_a = {
|
|
3116
|
+
startDate: 'tor.start_date',
|
|
3117
|
+
endDate: 'tor.end_date',
|
|
3118
|
+
collaboratorName: 'c.display_name',
|
|
3119
|
+
status: 'tor.status',
|
|
3120
|
+
}[pagination.sortField]) !== null && _a !== void 0 ? _a : 'tor.start_date';
|
|
3121
|
+
const queryParams = [...params];
|
|
3122
|
+
const limitPlaceholder = this.param(queryParams, pagination.pageSize);
|
|
3123
|
+
const offsetPlaceholder = this.param(queryParams, pagination.offset);
|
|
3124
|
+
const rows = await this.queryRows(`${baseQuery}
|
|
3125
|
+
ORDER BY ${sortColumn} ${pagination.sortOrder.toUpperCase()}, tor.id DESC
|
|
3126
|
+
LIMIT ${limitPlaceholder}
|
|
3127
|
+
OFFSET ${offsetPlaceholder}`, queryParams);
|
|
3128
|
+
return this.buildPaginationResult(rows, Number((_b = totalRow === null || totalRow === void 0 ? void 0 : totalRow.total) !== null && _b !== void 0 ? _b : 0), pagination.page, pagination.pageSize);
|
|
3171
3129
|
}
|
|
3172
3130
|
async createTimeOffRequest(userId, data) {
|
|
3173
3131
|
const actor = await this.getActorContext(userId);
|
|
@@ -3222,8 +3180,8 @@ let OperationsService = OperationsService_1 = class OperationsService {
|
|
|
3222
3180
|
collaborator_id AS "collaboratorId",
|
|
3223
3181
|
approver_collaborator_id AS "approverCollaboratorId",
|
|
3224
3182
|
request_type AS "requestType",
|
|
3225
|
-
start_date AS "startDate",
|
|
3226
|
-
end_date AS "endDate",
|
|
3183
|
+
start_date::text AS "startDate",
|
|
3184
|
+
end_date::text AS "endDate",
|
|
3227
3185
|
total_days AS "totalDays",
|
|
3228
3186
|
status,
|
|
3229
3187
|
reason,
|
|
@@ -3232,17 +3190,56 @@ let OperationsService = OperationsService_1 = class OperationsService {
|
|
|
3232
3190
|
FROM operations_time_off_request
|
|
3233
3191
|
WHERE id = $1`, [created]);
|
|
3234
3192
|
}
|
|
3235
|
-
async listScheduleAdjustments(userId) {
|
|
3193
|
+
async listScheduleAdjustments(userId, filters = {}) {
|
|
3194
|
+
var _a, _b, _c, _d, _e, _f;
|
|
3236
3195
|
const actor = await this.getActorContext(userId);
|
|
3237
3196
|
const filter = this.buildIdFilter(actor.visibleCollaboratorIds, 'sar.collaborator_id', actor.isDirector);
|
|
3197
|
+
const pagination = this.shouldPaginate(filters)
|
|
3198
|
+
? this.normalizePaginationParams(filters, {
|
|
3199
|
+
defaultSortField: 'effectiveStartDate',
|
|
3200
|
+
defaultSortOrder: 'desc',
|
|
3201
|
+
allowedSortFields: [
|
|
3202
|
+
'effectiveStartDate',
|
|
3203
|
+
'effectiveEndDate',
|
|
3204
|
+
'collaboratorName',
|
|
3205
|
+
'status',
|
|
3206
|
+
],
|
|
3207
|
+
})
|
|
3208
|
+
: null;
|
|
3209
|
+
const params = [...filter.params];
|
|
3210
|
+
const where = ['sar.deleted_at IS NULL', filter.clause];
|
|
3211
|
+
if (filters.status && filters.status !== 'all') {
|
|
3212
|
+
where.push(`sar.status::text = ${this.param(params, filters.status)}`);
|
|
3213
|
+
}
|
|
3214
|
+
if (pagination === null || pagination === void 0 ? void 0 : pagination.search) {
|
|
3215
|
+
const searchPlaceholder = this.param(params, `%${pagination.search}%`);
|
|
3216
|
+
where.push(`(
|
|
3217
|
+
COALESCE(c.display_name, '') ILIKE ${searchPlaceholder}
|
|
3218
|
+
OR COALESCE(a.display_name, '') ILIKE ${searchPlaceholder}
|
|
3219
|
+
OR COALESCE(sar.reason, '') ILIKE ${searchPlaceholder}
|
|
3220
|
+
OR COALESCE(sar.request_scope::text, '') ILIKE ${searchPlaceholder}
|
|
3221
|
+
)`);
|
|
3222
|
+
}
|
|
3223
|
+
const whereClause = where.join(' AND ');
|
|
3224
|
+
const sortColumn = (_b = {
|
|
3225
|
+
effectiveStartDate: 'sar.effective_start_date',
|
|
3226
|
+
effectiveEndDate: 'sar.effective_end_date',
|
|
3227
|
+
collaboratorName: 'c.display_name',
|
|
3228
|
+
status: 'sar.status',
|
|
3229
|
+
}[(_a = pagination === null || pagination === void 0 ? void 0 : pagination.sortField) !== null && _a !== void 0 ? _a : 'effectiveStartDate']) !== null && _b !== void 0 ? _b : 'sar.effective_start_date';
|
|
3230
|
+
const queryParams = [...params];
|
|
3231
|
+
const limitSql = pagination
|
|
3232
|
+
? `LIMIT ${this.param(queryParams, pagination.pageSize)}
|
|
3233
|
+
OFFSET ${this.param(queryParams, pagination.offset)}`
|
|
3234
|
+
: '';
|
|
3238
3235
|
const requests = await this.queryRows(`SELECT sar.id,
|
|
3239
3236
|
sar.collaborator_id AS "collaboratorId",
|
|
3240
3237
|
c.display_name AS "collaboratorName",
|
|
3241
3238
|
sar.approver_collaborator_id AS "approverCollaboratorId",
|
|
3242
3239
|
a.display_name AS "approverName",
|
|
3243
3240
|
sar.request_scope AS "requestScope",
|
|
3244
|
-
sar.effective_start_date AS "effectiveStartDate",
|
|
3245
|
-
sar.effective_end_date AS "effectiveEndDate",
|
|
3241
|
+
sar.effective_start_date::text AS "effectiveStartDate",
|
|
3242
|
+
sar.effective_end_date::text AS "effectiveEndDate",
|
|
3246
3243
|
sar.status,
|
|
3247
3244
|
sar.reason,
|
|
3248
3245
|
sar.submitted_at AS "submittedAt",
|
|
@@ -3255,11 +3252,22 @@ let OperationsService = OperationsService_1 = class OperationsService {
|
|
|
3255
3252
|
ON approval.target_type = 'schedule_adjustment_request'
|
|
3256
3253
|
AND approval.target_id = sar.id
|
|
3257
3254
|
AND approval.deleted_at IS NULL
|
|
3258
|
-
WHERE
|
|
3259
|
-
ORDER BY
|
|
3255
|
+
WHERE ${whereClause}
|
|
3256
|
+
ORDER BY ${sortColumn} ${(_d = (_c = pagination === null || pagination === void 0 ? void 0 : pagination.sortOrder) === null || _c === void 0 ? void 0 : _c.toUpperCase()) !== null && _d !== void 0 ? _d : 'DESC'}, sar.id DESC
|
|
3257
|
+
${limitSql}`, queryParams);
|
|
3260
3258
|
if (!requests.length) {
|
|
3259
|
+
if (pagination) {
|
|
3260
|
+
return this.buildPaginationResult([], 0, pagination.page, pagination.pageSize);
|
|
3261
|
+
}
|
|
3261
3262
|
return requests;
|
|
3262
3263
|
}
|
|
3264
|
+
const total = pagination
|
|
3265
|
+
? Number((_f = (_e = (await this.querySingle(`SELECT COUNT(*)::text AS total
|
|
3266
|
+
FROM operations_schedule_adjustment_request sar
|
|
3267
|
+
JOIN operations_collaborator c ON c.id = sar.collaborator_id
|
|
3268
|
+
LEFT JOIN operations_collaborator a ON a.id = sar.approver_collaborator_id
|
|
3269
|
+
WHERE ${whereClause}`, params))) === null || _e === void 0 ? void 0 : _e.total) !== null && _f !== void 0 ? _f : 0)
|
|
3270
|
+
: 0;
|
|
3263
3271
|
const days = await this.queryRows(`SELECT schedule_adjustment_request_id AS "requestId",
|
|
3264
3272
|
weekday,
|
|
3265
3273
|
is_working_day AS "isWorkingDay",
|
|
@@ -3281,10 +3289,14 @@ let OperationsService = OperationsService_1 = class OperationsService {
|
|
|
3281
3289
|
ORDER BY collaborator_id, weekday, id DESC`, [this.uniqueNumbers(requests.map((item) => item.collaboratorId))]);
|
|
3282
3290
|
const grouped = this.groupBy(days, 'requestId');
|
|
3283
3291
|
const currentScheduleByCollaborator = this.groupBy(currentSchedule, 'collaboratorId');
|
|
3284
|
-
|
|
3292
|
+
const data = requests.map((request) => {
|
|
3285
3293
|
var _a, _b;
|
|
3286
3294
|
return (Object.assign(Object.assign({}, request), { days: (_a = grouped[request.id]) !== null && _a !== void 0 ? _a : [], currentSchedule: (_b = currentScheduleByCollaborator[request.collaboratorId]) !== null && _b !== void 0 ? _b : [] }));
|
|
3287
3295
|
});
|
|
3296
|
+
if (!pagination) {
|
|
3297
|
+
return data;
|
|
3298
|
+
}
|
|
3299
|
+
return this.buildPaginationResult(data, total, pagination.page, pagination.pageSize);
|
|
3288
3300
|
}
|
|
3289
3301
|
async createScheduleAdjustmentRequest(userId, data) {
|
|
3290
3302
|
const actor = await this.getActorContext(userId);
|
|
@@ -3356,8 +3368,8 @@ let OperationsService = OperationsService_1 = class OperationsService {
|
|
|
3356
3368
|
collaborator_id AS "collaboratorId",
|
|
3357
3369
|
approver_collaborator_id AS "approverCollaboratorId",
|
|
3358
3370
|
request_scope AS "requestScope",
|
|
3359
|
-
effective_start_date AS "effectiveStartDate",
|
|
3360
|
-
effective_end_date AS "effectiveEndDate",
|
|
3371
|
+
effective_start_date::text AS "effectiveStartDate",
|
|
3372
|
+
effective_end_date::text AS "effectiveEndDate",
|
|
3361
3373
|
status,
|
|
3362
3374
|
reason,
|
|
3363
3375
|
submitted_at AS "submittedAt",
|
|
@@ -3365,14 +3377,40 @@ let OperationsService = OperationsService_1 = class OperationsService {
|
|
|
3365
3377
|
FROM operations_schedule_adjustment_request
|
|
3366
3378
|
WHERE id = $1`, [created]);
|
|
3367
3379
|
}
|
|
3368
|
-
async listApprovals(userId) {
|
|
3380
|
+
async listApprovals(userId, filters = {}) {
|
|
3381
|
+
var _a, _b;
|
|
3369
3382
|
const actor = await this.getActorContext(userId);
|
|
3370
3383
|
this.ensureSupervisor(actor);
|
|
3371
3384
|
const params = [];
|
|
3372
3385
|
const clause = actor.isDirector
|
|
3373
3386
|
? 'a.deleted_at IS NULL'
|
|
3374
3387
|
: `a.deleted_at IS NULL AND a.approver_collaborator_id = ${this.param(params, actor.collaboratorId)}`;
|
|
3375
|
-
|
|
3388
|
+
const pagination = this.shouldPaginate(filters)
|
|
3389
|
+
? this.normalizePaginationParams(filters, {
|
|
3390
|
+
defaultSortField: 'submittedAt',
|
|
3391
|
+
defaultSortOrder: 'desc',
|
|
3392
|
+
allowedSortFields: ['submittedAt', 'decidedAt', 'requesterName', 'status'],
|
|
3393
|
+
})
|
|
3394
|
+
: null;
|
|
3395
|
+
const where = [clause];
|
|
3396
|
+
if (filters.status && filters.status !== 'all') {
|
|
3397
|
+
where.push(`a.status::text = ${this.param(params, filters.status)}`);
|
|
3398
|
+
}
|
|
3399
|
+
if (filters.targetType && filters.targetType !== 'all') {
|
|
3400
|
+
where.push(`a.target_type = ${this.param(params, filters.targetType)}::text::operations_approval_target_type_32d3f04385_enum`);
|
|
3401
|
+
}
|
|
3402
|
+
if (pagination === null || pagination === void 0 ? void 0 : pagination.search) {
|
|
3403
|
+
const searchPlaceholder = this.param(params, `%${pagination.search}%`);
|
|
3404
|
+
where.push(`(
|
|
3405
|
+
COALESCE(requester.display_name, '') ILIKE ${searchPlaceholder}
|
|
3406
|
+
OR COALESCE(approver.display_name, '') ILIKE ${searchPlaceholder}
|
|
3407
|
+
OR COALESCE(a.decision_note, '') ILIKE ${searchPlaceholder}
|
|
3408
|
+
OR COALESCE(tor.reason, '') ILIKE ${searchPlaceholder}
|
|
3409
|
+
OR COALESCE(sar.reason, '') ILIKE ${searchPlaceholder}
|
|
3410
|
+
)`);
|
|
3411
|
+
}
|
|
3412
|
+
const whereClause = where.join(' AND ');
|
|
3413
|
+
const baseQuery = `SELECT a.id,
|
|
3376
3414
|
a.target_type AS "targetType",
|
|
3377
3415
|
a.target_id AS "targetId",
|
|
3378
3416
|
a.requester_collaborator_id AS "requesterCollaboratorId",
|
|
@@ -3391,12 +3429,12 @@ let OperationsService = OperationsService_1 = class OperationsService {
|
|
|
3391
3429
|
''
|
|
3392
3430
|
) AS "timesheetProjectNames",
|
|
3393
3431
|
tor.request_type AS "timeOffType",
|
|
3394
|
-
tor.start_date AS "timeOffStartDate",
|
|
3395
|
-
tor.end_date AS "timeOffEndDate",
|
|
3432
|
+
tor.start_date::text AS "timeOffStartDate",
|
|
3433
|
+
tor.end_date::text AS "timeOffEndDate",
|
|
3396
3434
|
tor.reason AS "timeOffReason",
|
|
3397
3435
|
sar.request_scope AS "scheduleRequestScope",
|
|
3398
|
-
sar.effective_start_date AS "scheduleStartDate",
|
|
3399
|
-
sar.effective_end_date AS "scheduleEndDate",
|
|
3436
|
+
sar.effective_start_date::text AS "scheduleStartDate",
|
|
3437
|
+
sar.effective_end_date::text AS "scheduleEndDate",
|
|
3400
3438
|
sar.reason AS "scheduleReason"
|
|
3401
3439
|
FROM operations_approval a
|
|
3402
3440
|
JOIN operations_collaborator requester
|
|
@@ -3419,9 +3457,42 @@ let OperationsService = OperationsService_1 = class OperationsService {
|
|
|
3419
3457
|
LEFT JOIN operations_schedule_adjustment_request sar
|
|
3420
3458
|
ON a.target_type = 'schedule_adjustment_request'
|
|
3421
3459
|
AND sar.id = a.target_id
|
|
3422
|
-
WHERE ${
|
|
3423
|
-
GROUP BY a.id, requester.id, approver.id, t.id, tor.id, sar.id
|
|
3424
|
-
|
|
3460
|
+
WHERE ${whereClause}
|
|
3461
|
+
GROUP BY a.id, requester.id, approver.id, t.id, tor.id, sar.id`;
|
|
3462
|
+
if (!pagination) {
|
|
3463
|
+
return this.queryRows(`${baseQuery}
|
|
3464
|
+
ORDER BY a.submitted_at DESC, a.id DESC`, params);
|
|
3465
|
+
}
|
|
3466
|
+
const totalRow = await this.querySingle(`SELECT COUNT(*)::text AS total
|
|
3467
|
+
FROM operations_approval a
|
|
3468
|
+
JOIN operations_collaborator requester
|
|
3469
|
+
ON requester.id = a.requester_collaborator_id
|
|
3470
|
+
LEFT JOIN operations_collaborator approver
|
|
3471
|
+
ON approver.id = a.approver_collaborator_id
|
|
3472
|
+
LEFT JOIN operations_timesheet t
|
|
3473
|
+
ON a.target_type = 'timesheet'
|
|
3474
|
+
AND t.id = a.target_id
|
|
3475
|
+
LEFT JOIN operations_time_off_request tor
|
|
3476
|
+
ON a.target_type = 'time_off_request'
|
|
3477
|
+
AND tor.id = a.target_id
|
|
3478
|
+
LEFT JOIN operations_schedule_adjustment_request sar
|
|
3479
|
+
ON a.target_type = 'schedule_adjustment_request'
|
|
3480
|
+
AND sar.id = a.target_id
|
|
3481
|
+
WHERE ${whereClause}`, params);
|
|
3482
|
+
const sortColumn = (_a = {
|
|
3483
|
+
submittedAt: 'a.submitted_at',
|
|
3484
|
+
decidedAt: 'a.decided_at',
|
|
3485
|
+
requesterName: 'requester.display_name',
|
|
3486
|
+
status: 'a.status',
|
|
3487
|
+
}[pagination.sortField]) !== null && _a !== void 0 ? _a : 'a.submitted_at';
|
|
3488
|
+
const queryParams = [...params];
|
|
3489
|
+
const limitPlaceholder = this.param(queryParams, pagination.pageSize);
|
|
3490
|
+
const offsetPlaceholder = this.param(queryParams, pagination.offset);
|
|
3491
|
+
const rows = await this.queryRows(`${baseQuery}
|
|
3492
|
+
ORDER BY ${sortColumn} ${pagination.sortOrder.toUpperCase()}, a.id DESC
|
|
3493
|
+
LIMIT ${limitPlaceholder}
|
|
3494
|
+
OFFSET ${offsetPlaceholder}`, queryParams);
|
|
3495
|
+
return this.buildPaginationResult(rows, Number((_b = totalRow === null || totalRow === void 0 ? void 0 : totalRow.total) !== null && _b !== void 0 ? _b : 0), pagination.page, pagination.pageSize);
|
|
3425
3496
|
}
|
|
3426
3497
|
async approve(userId, approvalId, data) {
|
|
3427
3498
|
return this.decideApproval(userId, approvalId, 'approve', data);
|
|
@@ -3429,6 +3500,120 @@ let OperationsService = OperationsService_1 = class OperationsService {
|
|
|
3429
3500
|
async reject(userId, approvalId, data) {
|
|
3430
3501
|
return this.decideApproval(userId, approvalId, 'reject', data);
|
|
3431
3502
|
}
|
|
3503
|
+
async getApprovalDetail(userId, approvalId) {
|
|
3504
|
+
const actor = await this.getActorContext(userId);
|
|
3505
|
+
this.ensureSupervisor(actor);
|
|
3506
|
+
const params = [];
|
|
3507
|
+
const actorClause = actor.isDirector
|
|
3508
|
+
? 'a.deleted_at IS NULL'
|
|
3509
|
+
: `a.deleted_at IS NULL AND a.approver_collaborator_id = ${this.param(params, actor.collaboratorId)}`;
|
|
3510
|
+
const idPlaceholder = this.param(params, approvalId);
|
|
3511
|
+
const row = await this.querySingle(`SELECT a.id,
|
|
3512
|
+
a.target_type AS "targetType",
|
|
3513
|
+
a.target_id AS "targetId",
|
|
3514
|
+
a.requester_collaborator_id AS "requesterCollaboratorId",
|
|
3515
|
+
requester.display_name AS "requesterName",
|
|
3516
|
+
a.approver_collaborator_id AS "approverCollaboratorId",
|
|
3517
|
+
approver.display_name AS "approverName",
|
|
3518
|
+
a.status,
|
|
3519
|
+
a.submitted_at AS "submittedAt",
|
|
3520
|
+
a.decided_at AS "decidedAt",
|
|
3521
|
+
a.decision_note AS "decisionNote",
|
|
3522
|
+
t.week_start_date AS "timesheetWeekStartDate",
|
|
3523
|
+
t.week_end_date AS "timesheetWeekEndDate",
|
|
3524
|
+
t.total_hours AS "timesheetTotalHours",
|
|
3525
|
+
COALESCE(
|
|
3526
|
+
STRING_AGG(DISTINCT p.name, ', ') FILTER (WHERE p.name IS NOT NULL),
|
|
3527
|
+
''
|
|
3528
|
+
) AS "timesheetProjectNames",
|
|
3529
|
+
tor.request_type AS "timeOffType",
|
|
3530
|
+
tor.start_date::text AS "timeOffStartDate",
|
|
3531
|
+
tor.end_date::text AS "timeOffEndDate",
|
|
3532
|
+
tor.reason AS "timeOffReason",
|
|
3533
|
+
sar.request_scope AS "scheduleRequestScope",
|
|
3534
|
+
sar.effective_start_date::text AS "scheduleStartDate",
|
|
3535
|
+
sar.effective_end_date::text AS "scheduleEndDate",
|
|
3536
|
+
sar.reason AS "scheduleReason"
|
|
3537
|
+
FROM operations_approval a
|
|
3538
|
+
JOIN operations_collaborator requester
|
|
3539
|
+
ON requester.id = a.requester_collaborator_id
|
|
3540
|
+
LEFT JOIN operations_collaborator approver
|
|
3541
|
+
ON approver.id = a.approver_collaborator_id
|
|
3542
|
+
LEFT JOIN operations_timesheet t
|
|
3543
|
+
ON a.target_type = 'timesheet'
|
|
3544
|
+
AND t.id = a.target_id
|
|
3545
|
+
LEFT JOIN operations_timesheet_entry te
|
|
3546
|
+
ON te.timesheet_id = t.id
|
|
3547
|
+
AND te.deleted_at IS NULL
|
|
3548
|
+
LEFT JOIN operations_project_assignment pa
|
|
3549
|
+
ON pa.id = te.project_assignment_id
|
|
3550
|
+
LEFT JOIN operations_project p
|
|
3551
|
+
ON p.id = pa.project_id
|
|
3552
|
+
LEFT JOIN operations_time_off_request tor
|
|
3553
|
+
ON a.target_type = 'time_off_request'
|
|
3554
|
+
AND tor.id = a.target_id
|
|
3555
|
+
LEFT JOIN operations_schedule_adjustment_request sar
|
|
3556
|
+
ON a.target_type = 'schedule_adjustment_request'
|
|
3557
|
+
AND sar.id = a.target_id
|
|
3558
|
+
WHERE ${actorClause}
|
|
3559
|
+
AND a.id = ${idPlaceholder}
|
|
3560
|
+
GROUP BY a.id, requester.id, approver.id, t.id, tor.id, sar.id`, params);
|
|
3561
|
+
if (!row) {
|
|
3562
|
+
throw new Error('Approval not found or access denied');
|
|
3563
|
+
}
|
|
3564
|
+
if (row.targetType === 'timesheet') {
|
|
3565
|
+
const entries = await this.queryRows(`SELECT e.id,
|
|
3566
|
+
e.timesheet_id AS "timesheetId",
|
|
3567
|
+
e.project_assignment_id AS "projectAssignmentId",
|
|
3568
|
+
pa.project_id AS "projectId",
|
|
3569
|
+
p.name AS "projectName",
|
|
3570
|
+
pa.role_label AS "roleLabel",
|
|
3571
|
+
e.task_id AS "taskId",
|
|
3572
|
+
task_record.name AS "taskName",
|
|
3573
|
+
COALESCE(task_record.name, e.activity_label) AS "activityLabel",
|
|
3574
|
+
e.work_date AS "workDate",
|
|
3575
|
+
COALESCE(NULLIF(e.duration_minutes, 0), ROUND(COALESCE(e.hours, 0)::numeric * 60))::int AS "durationMinutes",
|
|
3576
|
+
COALESCE(
|
|
3577
|
+
e.hours,
|
|
3578
|
+
ROUND((COALESCE(NULLIF(e.duration_minutes, 0), 0)::numeric / 60), 2)
|
|
3579
|
+
) AS hours,
|
|
3580
|
+
e.description
|
|
3581
|
+
FROM operations_timesheet_entry e
|
|
3582
|
+
LEFT JOIN operations_project_assignment pa ON pa.id = e.project_assignment_id
|
|
3583
|
+
LEFT JOIN operations_project p ON p.id = pa.project_id
|
|
3584
|
+
LEFT JOIN operations_task task_record
|
|
3585
|
+
ON task_record.id = e.task_id
|
|
3586
|
+
AND task_record.deleted_at IS NULL
|
|
3587
|
+
WHERE e.deleted_at IS NULL
|
|
3588
|
+
AND e.timesheet_id = $1
|
|
3589
|
+
ORDER BY e.work_date ASC, e.id ASC`, [row.targetId]);
|
|
3590
|
+
return Object.assign(Object.assign({}, row), { entries });
|
|
3591
|
+
}
|
|
3592
|
+
if (row.targetType === 'schedule_adjustment_request') {
|
|
3593
|
+
const days = await this.queryRows(`SELECT schedule_adjustment_request_id AS "requestId",
|
|
3594
|
+
weekday,
|
|
3595
|
+
is_working_day AS "isWorkingDay",
|
|
3596
|
+
start_time AS "startTime",
|
|
3597
|
+
end_time AS "endTime",
|
|
3598
|
+
break_minutes AS "breakMinutes"
|
|
3599
|
+
FROM operations_schedule_adjustment_day
|
|
3600
|
+
WHERE schedule_adjustment_request_id = $1
|
|
3601
|
+
ORDER BY id ASC`, [row.targetId]);
|
|
3602
|
+
const collaboratorIdParam = [row.requesterCollaboratorId];
|
|
3603
|
+
const currentSchedule = await this.queryRows(`SELECT DISTINCT ON (collaborator_id, weekday)
|
|
3604
|
+
collaborator_id AS "collaboratorId",
|
|
3605
|
+
weekday,
|
|
3606
|
+
is_working_day AS "isWorkingDay",
|
|
3607
|
+
start_time AS "startTime",
|
|
3608
|
+
end_time AS "endTime",
|
|
3609
|
+
break_minutes AS "breakMinutes"
|
|
3610
|
+
FROM operations_collaborator_schedule_day
|
|
3611
|
+
WHERE collaborator_id = $1
|
|
3612
|
+
ORDER BY collaborator_id, weekday, id DESC`, collaboratorIdParam);
|
|
3613
|
+
return Object.assign(Object.assign({}, row), { days, currentSchedule });
|
|
3614
|
+
}
|
|
3615
|
+
return row;
|
|
3616
|
+
}
|
|
3432
3617
|
async publishAccountsPayableReference(userId, data) {
|
|
3433
3618
|
var _a, _b, _c, _d;
|
|
3434
3619
|
const actor = await this.getActorContext(userId);
|
|
@@ -4021,73 +4206,6 @@ let OperationsService = OperationsService_1 = class OperationsService {
|
|
|
4021
4206
|
LIMIT 1`, normalizedLookup));
|
|
4022
4207
|
return (_b = collaboratorTypes[0]) !== null && _b !== void 0 ? _b : null;
|
|
4023
4208
|
}
|
|
4024
|
-
async getContractTemplateRecord(client, templateId, includeInactive = false) {
|
|
4025
|
-
const template = (await client.$queryRawUnsafe(`SELECT t.id,
|
|
4026
|
-
t.slug,
|
|
4027
|
-
t.code,
|
|
4028
|
-
t.name,
|
|
4029
|
-
t.description,
|
|
4030
|
-
t.contract_category AS "contractCategory",
|
|
4031
|
-
t.contract_type AS "contractType",
|
|
4032
|
-
t.billing_model AS "billingModel",
|
|
4033
|
-
t.signature_status AS "signatureStatus",
|
|
4034
|
-
t.is_active AS "isActive",
|
|
4035
|
-
t.status,
|
|
4036
|
-
t.content_html AS "contentHtml",
|
|
4037
|
-
COUNT(DISTINCT c.id)::int AS "usageCount",
|
|
4038
|
-
t.created_at AS "createdAt",
|
|
4039
|
-
t.updated_at AS "updatedAt"
|
|
4040
|
-
FROM operations_contract_template t
|
|
4041
|
-
LEFT JOIN operations_contract c
|
|
4042
|
-
ON c.contract_template_id = t.id
|
|
4043
|
-
AND c.deleted_at IS NULL
|
|
4044
|
-
WHERE t.id = $1
|
|
4045
|
-
AND ($2::boolean = true OR t.deleted_at IS NULL)
|
|
4046
|
-
GROUP BY t.id
|
|
4047
|
-
LIMIT 1`, templateId, includeInactive));
|
|
4048
|
-
const record = template[0];
|
|
4049
|
-
if (!record) {
|
|
4050
|
-
throw new common_1.NotFoundException('Contract template not found.');
|
|
4051
|
-
}
|
|
4052
|
-
return record;
|
|
4053
|
-
}
|
|
4054
|
-
async assertContractTemplateNameAvailable(client, name, excludeTemplateId) {
|
|
4055
|
-
const existing = (await client.$queryRawUnsafe(`SELECT id
|
|
4056
|
-
FROM operations_contract_template
|
|
4057
|
-
WHERE LOWER(name) = LOWER($1)
|
|
4058
|
-
AND deleted_at IS NULL
|
|
4059
|
-
AND ($2::int IS NULL OR id <> $2)
|
|
4060
|
-
LIMIT 1`, name, excludeTemplateId !== null && excludeTemplateId !== void 0 ? excludeTemplateId : null));
|
|
4061
|
-
if (existing[0]) {
|
|
4062
|
-
throw new common_1.BadRequestException('A contract template with this name already exists.');
|
|
4063
|
-
}
|
|
4064
|
-
}
|
|
4065
|
-
async assertContractTemplateCodeAvailable(client, code, excludeTemplateId) {
|
|
4066
|
-
const existing = (await client.$queryRawUnsafe(`SELECT id
|
|
4067
|
-
FROM operations_contract_template
|
|
4068
|
-
WHERE UPPER(COALESCE(code, '')) = UPPER($1)
|
|
4069
|
-
AND deleted_at IS NULL
|
|
4070
|
-
AND ($2::int IS NULL OR id <> $2)
|
|
4071
|
-
LIMIT 1`, code, excludeTemplateId !== null && excludeTemplateId !== void 0 ? excludeTemplateId : null));
|
|
4072
|
-
if (existing[0]) {
|
|
4073
|
-
throw new common_1.BadRequestException('A contract template with this code already exists.');
|
|
4074
|
-
}
|
|
4075
|
-
}
|
|
4076
|
-
async generateUniqueContractTemplateSlug(client, label, excludeTemplateId) {
|
|
4077
|
-
const baseSlug = this.slugifyValue(label) || `contract-template-${Date.now().toString(36)}`;
|
|
4078
|
-
for (let attempt = 0; attempt < 25; attempt += 1) {
|
|
4079
|
-
const candidate = attempt === 0 ? baseSlug : `${baseSlug}-${attempt + 1}`;
|
|
4080
|
-
const existing = (await client.$queryRawUnsafe(`SELECT id
|
|
4081
|
-
FROM operations_contract_template
|
|
4082
|
-
WHERE slug = $1
|
|
4083
|
-
AND ($2::int IS NULL OR id <> $2)
|
|
4084
|
-
LIMIT 1`, candidate, excludeTemplateId !== null && excludeTemplateId !== void 0 ? excludeTemplateId : null));
|
|
4085
|
-
if (!existing.length) {
|
|
4086
|
-
return candidate;
|
|
4087
|
-
}
|
|
4088
|
-
}
|
|
4089
|
-
return `${baseSlug}-${Date.now().toString(36)}`;
|
|
4090
|
-
}
|
|
4091
4209
|
slugifyValue(value) {
|
|
4092
4210
|
return (value !== null && value !== void 0 ? value : '')
|
|
4093
4211
|
.normalize('NFKD')
|
|
@@ -4213,7 +4331,7 @@ let OperationsService = OperationsService_1 = class OperationsService {
|
|
|
4213
4331
|
WHERE pa.project_id = $1
|
|
4214
4332
|
AND pa.deleted_at IS NULL`, [projectId]),
|
|
4215
4333
|
this.querySingle(`SELECT COUNT(*) FILTER (WHERE status IN ('planned', 'active'))::text AS "activeAssignments",
|
|
4216
|
-
COUNT(*) FILTER (WHERE
|
|
4334
|
+
COUNT(*) FILTER (WHERE status = 'completed')::text AS "completedAssignments",
|
|
4217
4335
|
COALESCE(AVG(allocation_percent), 0)::text AS "averageAllocation",
|
|
4218
4336
|
COALESCE(SUM(weekly_hours), 0)::text AS "totalWeeklyHours"
|
|
4219
4337
|
FROM operations_project_assignment
|
|
@@ -4227,11 +4345,70 @@ let OperationsService = OperationsService_1 = class OperationsService {
|
|
|
4227
4345
|
totalHours: Number((_c = timesheetSummary === null || timesheetSummary === void 0 ? void 0 : timesheetSummary.totalHours) !== null && _c !== void 0 ? _c : 0),
|
|
4228
4346
|
}, operationalIndicators: {
|
|
4229
4347
|
activeAssignments: Number((_d = operationalIndicators === null || operationalIndicators === void 0 ? void 0 : operationalIndicators.activeAssignments) !== null && _d !== void 0 ? _d : 0),
|
|
4230
|
-
|
|
4348
|
+
completedAssignments: Number((_e = operationalIndicators === null || operationalIndicators === void 0 ? void 0 : operationalIndicators.completedAssignments) !== null && _e !== void 0 ? _e : 0),
|
|
4231
4349
|
averageAllocation: Number((_f = operationalIndicators === null || operationalIndicators === void 0 ? void 0 : operationalIndicators.averageAllocation) !== null && _f !== void 0 ? _f : 0),
|
|
4232
4350
|
totalWeeklyHours: Number((_g = operationalIndicators === null || operationalIndicators === void 0 ? void 0 : operationalIndicators.totalWeeklyHours) !== null && _g !== void 0 ? _g : 0),
|
|
4233
4351
|
} });
|
|
4234
4352
|
}
|
|
4353
|
+
async getProjectStats(userId, projectId) {
|
|
4354
|
+
var _a, _b, _c;
|
|
4355
|
+
const [weeklyVelocityRows, allocationRows, quickRadarRow] = await Promise.all([
|
|
4356
|
+
this.prisma.$queryRawUnsafe(`SELECT TO_CHAR(DATE_TRUNC('week', e.work_date), 'DD/MM') AS "weekStart",
|
|
4357
|
+
COALESCE(SUM(e.hours), 0)::text AS "loggedHours"
|
|
4358
|
+
FROM operations_project_assignment pa
|
|
4359
|
+
JOIN operations_timesheet_entry e ON e.project_assignment_id = pa.id AND e.deleted_at IS NULL
|
|
4360
|
+
WHERE pa.project_id = $1
|
|
4361
|
+
AND pa.deleted_at IS NULL
|
|
4362
|
+
AND e.work_date >= NOW() - INTERVAL '7 weeks'
|
|
4363
|
+
GROUP BY DATE_TRUNC('week', e.work_date)
|
|
4364
|
+
ORDER BY DATE_TRUNC('week', e.work_date) ASC
|
|
4365
|
+
LIMIT 7`, projectId),
|
|
4366
|
+
this.prisma.$queryRawUnsafe(`SELECT c.display_name AS "name",
|
|
4367
|
+
COALESCE(pa.allocation_percent, 0)::text AS "allocation"
|
|
4368
|
+
FROM operations_project_assignment pa
|
|
4369
|
+
JOIN operations_collaborator c ON c.id = pa.collaborator_id AND c.deleted_at IS NULL
|
|
4370
|
+
WHERE pa.project_id = $1
|
|
4371
|
+
AND pa.deleted_at IS NULL
|
|
4372
|
+
AND pa.status IN ('planned', 'active')
|
|
4373
|
+
ORDER BY c.display_name ASC
|
|
4374
|
+
LIMIT 6`, projectId),
|
|
4375
|
+
this.prisma.$queryRawUnsafe(`SELECT
|
|
4376
|
+
(SELECT COUNT(*)::text
|
|
4377
|
+
FROM operations_task tk
|
|
4378
|
+
WHERE tk.project_id = $1
|
|
4379
|
+
AND tk.deleted_at IS NULL
|
|
4380
|
+
AND tk.assignee_collaborator_id IS NOT NULL
|
|
4381
|
+
AND tk.status IN ('todo', 'doing', 'review')
|
|
4382
|
+
) AS "activeAssignments",
|
|
4383
|
+
COUNT(DISTINCT ts.id) FILTER (WHERE ts.status = 'submitted')::text AS "pendingTimesheets",
|
|
4384
|
+
COALESCE(SUM(pa.weekly_hours) FILTER (WHERE pa.status IN ('planned', 'active')), 0)::text AS "totalWeeklyHours"
|
|
4385
|
+
FROM operations_project_assignment pa
|
|
4386
|
+
LEFT JOIN operations_timesheet_entry e ON e.project_assignment_id = pa.id AND e.deleted_at IS NULL
|
|
4387
|
+
LEFT JOIN operations_timesheet ts ON ts.id = e.timesheet_id AND ts.deleted_at IS NULL
|
|
4388
|
+
WHERE pa.project_id = $1 AND pa.deleted_at IS NULL`, projectId).then(rows => Array.isArray(rows) ? rows[0] : rows),
|
|
4389
|
+
]);
|
|
4390
|
+
const getInitials = (name) => name
|
|
4391
|
+
.split(' ')
|
|
4392
|
+
.map((part) => part[0])
|
|
4393
|
+
.slice(0, 2)
|
|
4394
|
+
.join('')
|
|
4395
|
+
.toUpperCase();
|
|
4396
|
+
return {
|
|
4397
|
+
weeklyVelocity: weeklyVelocityRows.map((row) => ({
|
|
4398
|
+
weekLabel: row.weekStart,
|
|
4399
|
+
loggedHours: Number(row.loggedHours),
|
|
4400
|
+
})),
|
|
4401
|
+
allocationByCollaborator: allocationRows.map((row) => ({
|
|
4402
|
+
name: getInitials(row.name),
|
|
4403
|
+
allocation: Math.round(Number(row.allocation)),
|
|
4404
|
+
})),
|
|
4405
|
+
quickRadar: {
|
|
4406
|
+
activeAssignments: Number((_a = quickRadarRow === null || quickRadarRow === void 0 ? void 0 : quickRadarRow.activeAssignments) !== null && _a !== void 0 ? _a : 0),
|
|
4407
|
+
pendingTimesheets: Number((_b = quickRadarRow === null || quickRadarRow === void 0 ? void 0 : quickRadarRow.pendingTimesheets) !== null && _b !== void 0 ? _b : 0),
|
|
4408
|
+
totalWeeklyHours: Number((_c = quickRadarRow === null || quickRadarRow === void 0 ? void 0 : quickRadarRow.totalWeeklyHours) !== null && _c !== void 0 ? _c : 0),
|
|
4409
|
+
},
|
|
4410
|
+
};
|
|
4411
|
+
}
|
|
4235
4412
|
async getCollaboratorDetails(collaboratorId) {
|
|
4236
4413
|
var _a, _b, _c, _d, _e, _f;
|
|
4237
4414
|
const collaborator = await this.querySingle(`SELECT c.id,
|
|
@@ -4373,8 +4550,8 @@ let OperationsService = OperationsService_1 = class OperationsService {
|
|
|
4373
4550
|
AND deleted_at IS NULL`, [collaboratorId]),
|
|
4374
4551
|
this.queryRows(`SELECT id,
|
|
4375
4552
|
request_scope AS "requestScope",
|
|
4376
|
-
effective_start_date AS "effectiveStartDate",
|
|
4377
|
-
effective_end_date AS "effectiveEndDate",
|
|
4553
|
+
effective_start_date::text AS "effectiveStartDate",
|
|
4554
|
+
effective_end_date::text AS "effectiveEndDate",
|
|
4378
4555
|
status,
|
|
4379
4556
|
reason
|
|
4380
4557
|
FROM operations_schedule_adjustment_request
|
|
@@ -4977,7 +5154,7 @@ let OperationsService = OperationsService_1 = class OperationsService {
|
|
|
4977
5154
|
}
|
|
4978
5155
|
}
|
|
4979
5156
|
async replaceProjectAssignments(client, projectId, teamAssignments) {
|
|
4980
|
-
var _a, _b, _c, _d, _e, _f, _g, _h
|
|
5157
|
+
var _a, _b, _c, _d, _e, _f, _g, _h;
|
|
4981
5158
|
await client.$executeRawUnsafe(`UPDATE operations_project_assignment
|
|
4982
5159
|
SET deleted_at = NOW(),
|
|
4983
5160
|
updated_at = NOW()
|
|
@@ -4996,17 +5173,16 @@ let OperationsService = OperationsService_1 = class OperationsService {
|
|
|
4996
5173
|
role_label,
|
|
4997
5174
|
allocation_percent,
|
|
4998
5175
|
weekly_hours,
|
|
4999
|
-
is_billable,
|
|
5000
5176
|
start_date,
|
|
5001
5177
|
end_date,
|
|
5002
5178
|
status,
|
|
5003
5179
|
created_at,
|
|
5004
5180
|
updated_at
|
|
5005
5181
|
) VALUES (
|
|
5006
|
-
$1, $2, $3, $4, $5, $6, $7
|
|
5007
|
-
$
|
|
5182
|
+
$1, $2, $3, $4, $5, $6, $7::date, $8::date,
|
|
5183
|
+
$9::operations_project_assignment_status_155b459bbf_enum,
|
|
5008
5184
|
NOW(), NOW()
|
|
5009
|
-
)`, projectId, assignment.collaboratorId, (_a = projectRole === null || projectRole === void 0 ? void 0 : projectRole.id) !== null && _a !== void 0 ? _a : null, (_c = (_b = this.normalizeOptionalText(assignment.roleLabel)) !== null && _b !== void 0 ? _b : projectRole === null || projectRole === void 0 ? void 0 : projectRole.name) !== null && _c !== void 0 ? _c : 'Team Member', (_d = assignment.allocationPercent) !== null && _d !== void 0 ? _d : null, (_e = assignment.weeklyHours) !== null && _e !== void 0 ? _e : null, (_f = assignment.
|
|
5185
|
+
)`, projectId, assignment.collaboratorId, (_a = projectRole === null || projectRole === void 0 ? void 0 : projectRole.id) !== null && _a !== void 0 ? _a : null, (_c = (_b = this.normalizeOptionalText(assignment.roleLabel)) !== null && _b !== void 0 ? _b : projectRole === null || projectRole === void 0 ? void 0 : projectRole.name) !== null && _c !== void 0 ? _c : 'Team Member', (_d = assignment.allocationPercent) !== null && _d !== void 0 ? _d : null, (_e = assignment.weeklyHours) !== null && _e !== void 0 ? _e : null, (_f = assignment.startDate) !== null && _f !== void 0 ? _f : null, (_g = assignment.endDate) !== null && _g !== void 0 ? _g : null, (_h = assignment.status) !== null && _h !== void 0 ? _h : 'active');
|
|
5010
5186
|
}
|
|
5011
5187
|
}
|
|
5012
5188
|
async replaceCollaboratorEquityParticipation(client, collaboratorId, equityParticipation) {
|
|
@@ -5258,106 +5434,6 @@ let OperationsService = OperationsService_1 = class OperationsService {
|
|
|
5258
5434
|
updated_at = NOW()
|
|
5259
5435
|
WHERE id = $13`, `HIR-${collaboratorCode}`, this.buildHiringContractName(displayName, collaboratorTypeSlug), this.mapContractCategoryForCollaboratorType(collaboratorTypeSlug), this.mapContractTypeForCollaboratorType(collaboratorTypeSlug), displayName, this.mapBillingModelForCollaboratorType(collaboratorTypeSlug), supervisorCollaboratorId, startDate !== null && startDate !== void 0 ? startDate : new Date().toISOString().slice(0, 10), compensationAmount, weeklyCapacityHours ? Math.round(Number(weeklyCapacityHours) * 4) : null, description, updatedByUserId, hiringContract.id);
|
|
5260
5436
|
}
|
|
5261
|
-
async createProjectContractDraft(client, createdByUserId, input) {
|
|
5262
|
-
var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o, _p, _q, _r, _s, _t;
|
|
5263
|
-
const templateRows = input.contractTemplateId
|
|
5264
|
-
? (await client.$queryRawUnsafe(`SELECT id,
|
|
5265
|
-
code,
|
|
5266
|
-
name,
|
|
5267
|
-
description,
|
|
5268
|
-
contract_category AS "contractCategory",
|
|
5269
|
-
contract_type AS "contractType",
|
|
5270
|
-
billing_model AS "billingModel",
|
|
5271
|
-
signature_status AS "signatureStatus",
|
|
5272
|
-
content_html AS "contentHtml"
|
|
5273
|
-
FROM operations_contract_template
|
|
5274
|
-
WHERE id = $1
|
|
5275
|
-
AND deleted_at IS NULL
|
|
5276
|
-
LIMIT 1`, input.contractTemplateId))
|
|
5277
|
-
: [];
|
|
5278
|
-
const selectedTemplate = (_a = templateRows[0]) !== null && _a !== void 0 ? _a : null;
|
|
5279
|
-
const templateContext = {
|
|
5280
|
-
project_code: input.projectCode,
|
|
5281
|
-
project_name: input.projectName,
|
|
5282
|
-
client_name: input.clientName,
|
|
5283
|
-
start_date: (_b = input.startDate) !== null && _b !== void 0 ? _b : '',
|
|
5284
|
-
end_date: (_c = input.endDate) !== null && _c !== void 0 ? _c : '',
|
|
5285
|
-
budget_amount: input.budgetAmount !== null && input.budgetAmount !== undefined
|
|
5286
|
-
? String(input.budgetAmount)
|
|
5287
|
-
: '',
|
|
5288
|
-
monthly_hour_cap: input.monthlyHourCap !== null && input.monthlyHourCap !== undefined
|
|
5289
|
-
? String(input.monthlyHourCap)
|
|
5290
|
-
: '',
|
|
5291
|
-
};
|
|
5292
|
-
const applyTemplateVariables = (value) => {
|
|
5293
|
-
const source = value !== null && value !== void 0 ? value : '';
|
|
5294
|
-
return Object.entries(templateContext).reduce((result, [key, replacement]) => result.split(`{{${key}}}`).join(replacement || ''), source);
|
|
5295
|
-
};
|
|
5296
|
-
const templateCodePrefix = this.normalizeOptionalText(selectedTemplate === null || selectedTemplate === void 0 ? void 0 : selectedTemplate.code);
|
|
5297
|
-
const generatedContractCode = ((_e = (_d = this.normalizeOptionalText(input.contractCode)) !== null && _d !== void 0 ? _d : (templateCodePrefix
|
|
5298
|
-
? `${templateCodePrefix}-${input.projectCode}`
|
|
5299
|
-
: null)) !== null && _e !== void 0 ? _e : `PRJ-${input.projectCode}`).slice(0, 40);
|
|
5300
|
-
const generatedContractName = (_g = (_f = this.normalizeOptionalText(input.contractName)) !== null && _f !== void 0 ? _f : this.normalizeOptionalText(applyTemplateVariables(selectedTemplate === null || selectedTemplate === void 0 ? void 0 : selectedTemplate.name))) !== null && _g !== void 0 ? _g : `${input.projectName} Service Agreement`;
|
|
5301
|
-
const generatedDescription = this.normalizeOptionalText(applyTemplateVariables((_h = input.description) !== null && _h !== void 0 ? _h : selectedTemplate === null || selectedTemplate === void 0 ? void 0 : selectedTemplate.description));
|
|
5302
|
-
const generatedContentHtml = this.normalizeOptionalText(applyTemplateVariables(selectedTemplate === null || selectedTemplate === void 0 ? void 0 : selectedTemplate.contentHtml));
|
|
5303
|
-
const created = await client.$queryRawUnsafe(`INSERT INTO operations_contract (
|
|
5304
|
-
code,
|
|
5305
|
-
name,
|
|
5306
|
-
contract_category,
|
|
5307
|
-
contract_type,
|
|
5308
|
-
client_name,
|
|
5309
|
-
signature_status,
|
|
5310
|
-
is_active,
|
|
5311
|
-
billing_model,
|
|
5312
|
-
account_manager_collaborator_id,
|
|
5313
|
-
related_collaborator_id,
|
|
5314
|
-
contract_template_id,
|
|
5315
|
-
origin_type,
|
|
5316
|
-
origin_id,
|
|
5317
|
-
start_date,
|
|
5318
|
-
end_date,
|
|
5319
|
-
signed_at,
|
|
5320
|
-
effective_date,
|
|
5321
|
-
budget_amount,
|
|
5322
|
-
monthly_hour_cap,
|
|
5323
|
-
status,
|
|
5324
|
-
description,
|
|
5325
|
-
content_html,
|
|
5326
|
-
created_by_user_id,
|
|
5327
|
-
updated_by_user_id,
|
|
5328
|
-
created_at,
|
|
5329
|
-
updated_at
|
|
5330
|
-
) VALUES (
|
|
5331
|
-
$1,
|
|
5332
|
-
$2,
|
|
5333
|
-
$3::operations_contract_contract_category_70d553ea09_enum,
|
|
5334
|
-
$4::operations_contract_contract_type_48331e2ebf_enum,
|
|
5335
|
-
$5,
|
|
5336
|
-
$6::operations_contract_signature_status_2cb7282a7b_enum,
|
|
5337
|
-
true,
|
|
5338
|
-
$7::operations_contract_billing_model_409dc7fea2_enum,
|
|
5339
|
-
$8,
|
|
5340
|
-
NULL,
|
|
5341
|
-
$9,
|
|
5342
|
-
'client_project',
|
|
5343
|
-
$10,
|
|
5344
|
-
$11::date,
|
|
5345
|
-
$12::date,
|
|
5346
|
-
NULL,
|
|
5347
|
-
$11::date,
|
|
5348
|
-
$13,
|
|
5349
|
-
$14,
|
|
5350
|
-
'draft',
|
|
5351
|
-
$15,
|
|
5352
|
-
$16,
|
|
5353
|
-
$17,
|
|
5354
|
-
$17,
|
|
5355
|
-
NOW(),
|
|
5356
|
-
NOW()
|
|
5357
|
-
)
|
|
5358
|
-
RETURNING id`, generatedContractCode, generatedContractName, (_j = selectedTemplate === null || selectedTemplate === void 0 ? void 0 : selectedTemplate.contractCategory) !== null && _j !== void 0 ? _j : 'client', (_k = selectedTemplate === null || selectedTemplate === void 0 ? void 0 : selectedTemplate.contractType) !== null && _k !== void 0 ? _k : 'service_agreement', input.clientName, (_l = selectedTemplate === null || selectedTemplate === void 0 ? void 0 : selectedTemplate.signatureStatus) !== null && _l !== void 0 ? _l : 'not_started', (_m = selectedTemplate === null || selectedTemplate === void 0 ? void 0 : selectedTemplate.billingModel) !== null && _m !== void 0 ? _m : input.billingModel, input.managerCollaboratorId, (_o = selectedTemplate === null || selectedTemplate === void 0 ? void 0 : selectedTemplate.id) !== null && _o !== void 0 ? _o : null, input.projectId, (_p = input.startDate) !== null && _p !== void 0 ? _p : new Date().toISOString().slice(0, 10), (_q = input.endDate) !== null && _q !== void 0 ? _q : null, (_r = input.budgetAmount) !== null && _r !== void 0 ? _r : null, (_s = input.monthlyHourCap) !== null && _s !== void 0 ? _s : null, generatedDescription, generatedContentHtml, createdByUserId);
|
|
5359
|
-
return (_t = created[0]) === null || _t === void 0 ? void 0 : _t.id;
|
|
5360
|
-
}
|
|
5361
5437
|
async replaceContractParties(client, contractId, parties) {
|
|
5362
5438
|
var _a, _b, _c, _d, _e, _f;
|
|
5363
5439
|
await client.$executeRawUnsafe(`UPDATE operations_contract_party
|
|
@@ -5385,88 +5461,6 @@ let OperationsService = OperationsService_1 = class OperationsService {
|
|
|
5385
5461
|
)`, 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);
|
|
5386
5462
|
}
|
|
5387
5463
|
}
|
|
5388
|
-
async replaceContractSignatures(client, contractId, signatures) {
|
|
5389
|
-
var _a, _b, _c, _d;
|
|
5390
|
-
await client.$executeRawUnsafe(`UPDATE operations_contract_signature
|
|
5391
|
-
SET deleted_at = NOW(),
|
|
5392
|
-
updated_at = NOW()
|
|
5393
|
-
WHERE contract_id = $1
|
|
5394
|
-
AND deleted_at IS NULL`, contractId);
|
|
5395
|
-
for (const signature of signatures !== null && signatures !== void 0 ? signatures : []) {
|
|
5396
|
-
await client.$executeRawUnsafe(`INSERT INTO operations_contract_signature (
|
|
5397
|
-
contract_id,
|
|
5398
|
-
signer_name,
|
|
5399
|
-
signer_role,
|
|
5400
|
-
signer_email,
|
|
5401
|
-
signer_status,
|
|
5402
|
-
signed_at,
|
|
5403
|
-
created_at,
|
|
5404
|
-
updated_at
|
|
5405
|
-
) VALUES (
|
|
5406
|
-
$1, $2, $3, $4,
|
|
5407
|
-
$5::operations_contract_signature_signer_status_1e6fbe2519_enum,
|
|
5408
|
-
$6::timestamp, NOW(), NOW()
|
|
5409
|
-
)`, 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);
|
|
5410
|
-
}
|
|
5411
|
-
}
|
|
5412
|
-
async replaceContractFinancialTerms(client, contractId, financialTerms) {
|
|
5413
|
-
var _a, _b, _c, _d;
|
|
5414
|
-
await client.$executeRawUnsafe(`UPDATE operations_contract_financial_term
|
|
5415
|
-
SET deleted_at = NOW(),
|
|
5416
|
-
updated_at = NOW()
|
|
5417
|
-
WHERE contract_id = $1
|
|
5418
|
-
AND deleted_at IS NULL`, contractId);
|
|
5419
|
-
for (const term of financialTerms !== null && financialTerms !== void 0 ? financialTerms : []) {
|
|
5420
|
-
await client.$executeRawUnsafe(`INSERT INTO operations_contract_financial_term (
|
|
5421
|
-
contract_id,
|
|
5422
|
-
term_type,
|
|
5423
|
-
label,
|
|
5424
|
-
amount,
|
|
5425
|
-
recurrence,
|
|
5426
|
-
due_day,
|
|
5427
|
-
notes,
|
|
5428
|
-
created_at,
|
|
5429
|
-
updated_at
|
|
5430
|
-
) VALUES (
|
|
5431
|
-
$1,
|
|
5432
|
-
$2::operations_contract_financial_term_term_type_700635c06a_enum,
|
|
5433
|
-
$3,
|
|
5434
|
-
$4,
|
|
5435
|
-
$5::operations_contract_financial_term_recurrence_ba90bbe3bf_enum,
|
|
5436
|
-
$6,
|
|
5437
|
-
$7,
|
|
5438
|
-
NOW(), NOW()
|
|
5439
|
-
)`, 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);
|
|
5440
|
-
}
|
|
5441
|
-
}
|
|
5442
|
-
async replaceContractRevisions(client, contractId, revisions) {
|
|
5443
|
-
var _a, _b, _c, _d;
|
|
5444
|
-
await client.$executeRawUnsafe(`UPDATE operations_contract_revision
|
|
5445
|
-
SET deleted_at = NOW(),
|
|
5446
|
-
updated_at = NOW()
|
|
5447
|
-
WHERE contract_id = $1
|
|
5448
|
-
AND deleted_at IS NULL`, contractId);
|
|
5449
|
-
for (const revision of revisions !== null && revisions !== void 0 ? revisions : []) {
|
|
5450
|
-
await client.$executeRawUnsafe(`INSERT INTO operations_contract_revision (
|
|
5451
|
-
contract_id,
|
|
5452
|
-
revision_type,
|
|
5453
|
-
title,
|
|
5454
|
-
effective_date,
|
|
5455
|
-
status,
|
|
5456
|
-
summary,
|
|
5457
|
-
created_at,
|
|
5458
|
-
updated_at
|
|
5459
|
-
) VALUES (
|
|
5460
|
-
$1,
|
|
5461
|
-
$2::operations_contract_revision_revision_type_cf5ba1a538_enum,
|
|
5462
|
-
$3,
|
|
5463
|
-
$4::date,
|
|
5464
|
-
$5::operations_contract_revision_status_f44f35bb66_enum,
|
|
5465
|
-
$6,
|
|
5466
|
-
NOW(), NOW()
|
|
5467
|
-
)`, 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);
|
|
5468
|
-
}
|
|
5469
|
-
}
|
|
5470
5464
|
async replaceContractDocument(client, contractId, documentType, document) {
|
|
5471
5465
|
var _a, _b, _c, _d, _e;
|
|
5472
5466
|
await client.$executeRawUnsafe(`UPDATE operations_contract_document
|
|
@@ -5474,7 +5468,7 @@ let OperationsService = OperationsService_1 = class OperationsService {
|
|
|
5474
5468
|
updated_at = NOW()
|
|
5475
5469
|
WHERE contract_id = $1
|
|
5476
5470
|
AND deleted_at IS NULL
|
|
5477
|
-
AND document_type = $2`, contractId, documentType);
|
|
5471
|
+
AND document_type::text = $2`, contractId, documentType);
|
|
5478
5472
|
await client.$executeRawUnsafe(`INSERT INTO operations_contract_document (
|
|
5479
5473
|
contract_id,
|
|
5480
5474
|
document_type,
|
|
@@ -5489,7 +5483,7 @@ let OperationsService = OperationsService_1 = class OperationsService {
|
|
|
5489
5483
|
created_at,
|
|
5490
5484
|
updated_at
|
|
5491
5485
|
) VALUES (
|
|
5492
|
-
$1, $2, $3, $4, $5, $6, true, $7, $8, $9, NOW(), NOW()
|
|
5486
|
+
$1, $2::operations_contract_document_document_type_15ebaff0c9_enum, $3, $4, $5, $6, true, $7::operations_contract_document_extraction_status_6d94c231f3_enum, $8, $9, NOW(), NOW()
|
|
5493
5487
|
)`, contractId, documentType, (_a = document.fileId) !== null && _a !== void 0 ? _a : null, document.fileName, document.mimeType, (_b = document.fileContentBase64) !== null && _b !== void 0 ? _b : null, (_c = document.extractionStatus) !== null && _c !== void 0 ? _c : 'skipped', (_d = document.extractionSummary) !== null && _d !== void 0 ? _d : null, (_e = document.notes) !== null && _e !== void 0 ? _e : null);
|
|
5494
5488
|
}
|
|
5495
5489
|
async resolveContractExtractionFile(userId, data) {
|
|
@@ -5574,7 +5568,7 @@ let OperationsService = OperationsService_1 = class OperationsService {
|
|
|
5574
5568
|
}
|
|
5575
5569
|
}
|
|
5576
5570
|
async buildContractPdfHtml(contract) {
|
|
5577
|
-
var _a, _b, _c, _d
|
|
5571
|
+
var _a, _b, _c, _d;
|
|
5578
5572
|
const logoUrl = await this.resolveContractPdfLogoUrl();
|
|
5579
5573
|
const contentHtml = (_c = (_a = this.normalizeOptionalText(contract.contentHtml)) !== null && _a !== void 0 ? _a : (_b = this.normalizeOptionalText(contract.description)) === null || _b === void 0 ? void 0 : _b.split(/\n{2,}/).map((paragraph) => `<p>${this.escapeHtml(paragraph)}</p>`).join('')) !== null && _c !== void 0 ? _c : '<p>No contract body was provided yet.</p>';
|
|
5580
5574
|
const partiesHtml = ((_d = contract.parties) !== null && _d !== void 0 ? _d : []).length
|
|
@@ -5586,17 +5580,6 @@ let OperationsService = OperationsService_1 = class OperationsService {
|
|
|
5586
5580
|
</li>`)
|
|
5587
5581
|
.join('')
|
|
5588
5582
|
: '<li><strong>No parties registered yet.</strong><span>Complete this contract later if needed.</span></li>';
|
|
5589
|
-
const financialTermsHtml = ((_e = contract.financialTerms) !== null && _e !== void 0 ? _e : []).length
|
|
5590
|
-
? contract.financialTerms
|
|
5591
|
-
.map((term) => `
|
|
5592
|
-
<li>
|
|
5593
|
-
<strong>${this.escapeHtml(term.label || 'Term')}</strong>
|
|
5594
|
-
<span>${this.escapeHtml([term.termType, term.amount, term.recurrence]
|
|
5595
|
-
.filter((item) => item !== null && item !== undefined && String(item).trim())
|
|
5596
|
-
.join(' • '))}</span>
|
|
5597
|
-
</li>`)
|
|
5598
|
-
.join('')
|
|
5599
|
-
: '<li><strong>No financial terms registered yet.</strong><span>The draft is intentionally lightweight.</span></li>';
|
|
5600
5583
|
return `<!DOCTYPE html>
|
|
5601
5584
|
<html lang="en">
|
|
5602
5585
|
<head>
|
|
@@ -5741,11 +5724,6 @@ let OperationsService = OperationsService_1 = class OperationsService {
|
|
|
5741
5724
|
<ul>${partiesHtml}</ul>
|
|
5742
5725
|
</section>
|
|
5743
5726
|
|
|
5744
|
-
<section>
|
|
5745
|
-
<h2>Financial Terms</h2>
|
|
5746
|
-
<ul>${financialTermsHtml}</ul>
|
|
5747
|
-
</section>
|
|
5748
|
-
|
|
5749
5727
|
<section>
|
|
5750
5728
|
<h2>Contract Body</h2>
|
|
5751
5729
|
<div class="content">${contentHtml}</div>
|
|
@@ -5986,7 +5964,6 @@ let OperationsService = OperationsService_1 = class OperationsService {
|
|
|
5986
5964
|
effectiveDate: contract.effectiveDate,
|
|
5987
5965
|
signatureStatus: contract.signatureStatus,
|
|
5988
5966
|
parties: contract.parties,
|
|
5989
|
-
financialTerms: contract.financialTerms,
|
|
5990
5967
|
}, null, 2)}`,
|
|
5991
5968
|
`Contract HTML:\n${(_b = this.normalizeOptionalText(contract.contentHtml)) !== null && _b !== void 0 ? _b : ''}`,
|
|
5992
5969
|
].join('\n\n'),
|
|
@@ -6026,7 +6003,7 @@ let OperationsService = OperationsService_1 = class OperationsService {
|
|
|
6026
6003
|
}
|
|
6027
6004
|
}
|
|
6028
6005
|
buildHeuristicContractLegalReview(contract) {
|
|
6029
|
-
var _a, _b, _c, _d, _e, _f
|
|
6006
|
+
var _a, _b, _c, _d, _e, _f;
|
|
6030
6007
|
const contentText = ((_a = this.normalizeOptionalText(contract.contentHtml)) !== null && _a !== void 0 ? _a : '')
|
|
6031
6008
|
.replace(/<[^>]+>/g, ' ')
|
|
6032
6009
|
.replace(/\s+/g, ' ')
|
|
@@ -6064,12 +6041,12 @@ let OperationsService = OperationsService_1 = class OperationsService {
|
|
|
6064
6041
|
if (!this.normalizeOptionalText(primaryParty === null || primaryParty === void 0 ? void 0 : primaryParty.documentNumber)) {
|
|
6065
6042
|
warnings.push('Consider confirming the primary party document number.');
|
|
6066
6043
|
}
|
|
6067
|
-
if (
|
|
6068
|
-
warnings.push('Commercial conditions are still generic; define
|
|
6069
|
-
checklist.push('Attention: validate billing
|
|
6044
|
+
if (contract.budgetAmount == null) {
|
|
6045
|
+
warnings.push('Commercial conditions are still generic; define a budget amount before signature.');
|
|
6046
|
+
checklist.push('Attention: validate billing and penalties.');
|
|
6070
6047
|
}
|
|
6071
6048
|
else {
|
|
6072
|
-
checklist.push('OK: there is
|
|
6049
|
+
checklist.push('OK: there is a budget reference to review.');
|
|
6073
6050
|
}
|
|
6074
6051
|
if (!contentText) {
|
|
6075
6052
|
missingFields.push('Contract body content');
|
|
@@ -6235,34 +6212,6 @@ let OperationsService = OperationsService_1 = class OperationsService {
|
|
|
6235
6212
|
isPrimary: this.normalizeExtractionBoolean(party.isPrimary),
|
|
6236
6213
|
}))
|
|
6237
6214
|
.filter((party) => party.displayName),
|
|
6238
|
-
signatures: this.normalizeObjectList(raw.signatures)
|
|
6239
|
-
.map((signature) => ({
|
|
6240
|
-
signerName: this.normalizeExtractionString(signature.signerName),
|
|
6241
|
-
signerRole: this.normalizeExtractionString(signature.signerRole),
|
|
6242
|
-
signerEmail: this.normalizeExtractionString(signature.signerEmail),
|
|
6243
|
-
status: this.normalizeEnumValue(signature.status, SIGNATURE_ITEM_STATUS_VALUES, 'pending'),
|
|
6244
|
-
signedAt: this.normalizeExtractionDate(signature.signedAt),
|
|
6245
|
-
}))
|
|
6246
|
-
.filter((signature) => signature.signerName),
|
|
6247
|
-
financialTerms: this.normalizeObjectList(raw.financialTerms)
|
|
6248
|
-
.map((term) => ({
|
|
6249
|
-
label: this.normalizeExtractionString(term.label),
|
|
6250
|
-
termType: this.normalizeEnumValue(term.termType, FINANCIAL_TERM_TYPE_VALUES, 'value'),
|
|
6251
|
-
amount: this.normalizeExtractionNumber(term.amount),
|
|
6252
|
-
recurrence: this.normalizeEnumValue(term.recurrence, RECURRENCE_VALUES, 'one_time'),
|
|
6253
|
-
dueDay: this.normalizeExtractionNumber(term.dueDay),
|
|
6254
|
-
notes: this.normalizeExtractionString(term.notes),
|
|
6255
|
-
}))
|
|
6256
|
-
.filter((term) => term.label),
|
|
6257
|
-
revisions: this.normalizeObjectList(raw.revisions)
|
|
6258
|
-
.map((revision) => ({
|
|
6259
|
-
title: this.normalizeExtractionString(revision.title),
|
|
6260
|
-
revisionType: this.normalizeEnumValue(revision.revisionType, REVISION_TYPE_VALUES, 'revision'),
|
|
6261
|
-
effectiveDate: this.normalizeExtractionDate(revision.effectiveDate),
|
|
6262
|
-
status: this.normalizeEnumValue(revision.status, REVISION_STATUS_VALUES, 'draft'),
|
|
6263
|
-
summary: this.normalizeExtractionString(revision.summary),
|
|
6264
|
-
}))
|
|
6265
|
-
.filter((revision) => revision.title),
|
|
6266
6215
|
};
|
|
6267
6216
|
if (!draft.name)
|
|
6268
6217
|
missingFields.push('Contract title');
|
|
@@ -6364,6 +6313,15 @@ let OperationsService = OperationsService_1 = class OperationsService {
|
|
|
6364
6313
|
offset: (page - 1) * pageSize,
|
|
6365
6314
|
};
|
|
6366
6315
|
}
|
|
6316
|
+
shouldPaginate(input) {
|
|
6317
|
+
return [
|
|
6318
|
+
input.page,
|
|
6319
|
+
input.pageSize,
|
|
6320
|
+
input.search,
|
|
6321
|
+
input.sortField,
|
|
6322
|
+
input.sortOrder,
|
|
6323
|
+
].some((value) => value !== undefined && value !== null && value !== '');
|
|
6324
|
+
}
|
|
6367
6325
|
buildPaginationResult(data, total, page, pageSize) {
|
|
6368
6326
|
const lastPage = Math.max(1, Math.ceil(total / Math.max(pageSize, 1)));
|
|
6369
6327
|
return {
|
|
@@ -6508,6 +6466,12 @@ let OperationsService = OperationsService_1 = class OperationsService {
|
|
|
6508
6466
|
async execute(sql, params = []) {
|
|
6509
6467
|
return this.prisma.$executeRawUnsafe(sql, ...params);
|
|
6510
6468
|
}
|
|
6469
|
+
async getNextCollaboratorTypeSortOrder(client = this.prisma) {
|
|
6470
|
+
var _a, _b;
|
|
6471
|
+
const row = (await client.$queryRawUnsafe(`SELECT COALESCE(MAX(sort_order), 0) + 1 AS "nextSortOrder"
|
|
6472
|
+
FROM operations_collaborator_type`));
|
|
6473
|
+
return Number((_b = (_a = row === null || row === void 0 ? void 0 : row[0]) === null || _a === void 0 ? void 0 : _a.nextSortOrder) !== null && _b !== void 0 ? _b : 1);
|
|
6474
|
+
}
|
|
6511
6475
|
};
|
|
6512
6476
|
exports.OperationsService = OperationsService;
|
|
6513
6477
|
exports.OperationsService = OperationsService = OperationsService_1 = __decorate([
|