@hed-hog/operations 0.0.325 → 0.0.327
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-collaborators.controller.d.ts +5 -0
- package/dist/controllers/operations-collaborators.controller.d.ts.map +1 -1
- package/dist/operations.service.d.ts +9 -1
- package/dist/operations.service.d.ts.map +1 -1
- package/dist/operations.service.js +140 -26
- package/dist/operations.service.js.map +1 -1
- package/hedhog/data/integration_event_catalog.yaml +313 -0
- package/hedhog/data/setting_group.yaml +21 -0
- package/hedhog/frontend/app/_components/collaborator-form-screen.tsx.ejs +410 -23
- package/hedhog/frontend/app/_components/my-project-summary-screen.tsx.ejs +504 -375
- package/hedhog/frontend/app/_components/project-details-screen.tsx.ejs +258 -230
- package/hedhog/frontend/app/_components/task-detail-sheet.tsx.ejs +225 -162
- package/hedhog/frontend/app/_components/task-form-sheet.tsx.ejs +484 -230
- package/hedhog/frontend/app/_lib/api.ts.ejs +13 -4
- package/hedhog/frontend/app/_lib/hooks/use-mention-items.ts.ejs +28 -0
- package/hedhog/frontend/app/_lib/types.ts.ejs +30 -29
- package/hedhog/frontend/app/my-tasks/page.tsx.ejs +347 -236
- package/hedhog/frontend/app/reports/projects/page.tsx.ejs +31 -7
- package/hedhog/frontend/messages/en.json +38 -55
- package/hedhog/frontend/messages/en.json.ejs +21 -4
- package/hedhog/frontend/messages/pt.json +36 -55
- package/hedhog/frontend/messages/pt.json.ejs +14 -3
- package/hedhog/frontend/src/app/(app)/(libraries)/operations/_lib/types.d.ts +1 -0
- package/hedhog/frontend/src/app/(app)/(libraries)/operations/_lib/types.d.ts.map +1 -1
- package/hedhog/frontend/src/app/(app)/(libraries)/operations/_lib/types.ts +1 -0
- package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/_lib/types.d.ts +1 -0
- package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/_lib/types.d.ts.map +1 -1
- package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/_lib/types.ts +1 -0
- package/hedhog/table/operations_collaborator.yaml +5 -0
- package/hedhog/table/operations_collaborator_compensation_history.yaml +4 -0
- package/package.json +5 -5
- package/src/operations.service.ts +202 -26
|
@@ -997,7 +997,7 @@ let OperationsService = OperationsService_1 = class OperationsService {
|
|
|
997
997
|
throw new common_1.BadRequestException('Field "personId" is required.');
|
|
998
998
|
}
|
|
999
999
|
const collaboratorId = await this.prisma.$transaction(async (tx) => {
|
|
1000
|
-
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;
|
|
1000
|
+
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;
|
|
1001
1001
|
const normalizedCode = String((_a = data.code) !== null && _a !== void 0 ? _a : '').trim() ||
|
|
1002
1002
|
(await this.generateCollaboratorCode(tx));
|
|
1003
1003
|
const resolvedDepartment = await this.resolveDepartmentReference(tx, {
|
|
@@ -1053,11 +1053,23 @@ let OperationsService = OperationsService_1 = class OperationsService {
|
|
|
1053
1053
|
});
|
|
1054
1054
|
}
|
|
1055
1055
|
if (data.compensationAmount != null) {
|
|
1056
|
-
await this.insertCollaboratorCompensationHistory(tx, createdCollaboratorId, Number(data.compensationAmount), actor.userId, null);
|
|
1056
|
+
await this.insertCollaboratorCompensationHistory(tx, createdCollaboratorId, Number(data.compensationAmount), actor.userId, (_3 = data.compensationNotes) !== null && _3 !== void 0 ? _3 : null, (_4 = data.compensationEffectiveDate) !== null && _4 !== void 0 ? _4 : null);
|
|
1057
|
+
}
|
|
1058
|
+
if (data.hourlyRate != null) {
|
|
1059
|
+
await tx.$executeRawUnsafe(`UPDATE operations_collaborator SET hourly_rate = $1 WHERE id = $2`, Number(data.hourlyRate), createdCollaboratorId);
|
|
1060
|
+
await this.insertCollaboratorCompensationHistory(tx, createdCollaboratorId, Number(data.hourlyRate), actor.userId, (_5 = data.compensationNotes) !== null && _5 !== void 0 ? _5 : null, (_6 = data.compensationEffectiveDate) !== null && _6 !== void 0 ? _6 : null, 'hourly_rate');
|
|
1057
1061
|
}
|
|
1058
1062
|
return createdCollaboratorId;
|
|
1059
1063
|
});
|
|
1060
|
-
|
|
1064
|
+
const result = await this.getCollaboratorByIdForUser(userId, collaboratorId);
|
|
1065
|
+
await this.integrationApi.publishEvent({
|
|
1066
|
+
eventName: 'operations.collaborator.created',
|
|
1067
|
+
sourceModule: 'operations',
|
|
1068
|
+
aggregateType: 'collaborator',
|
|
1069
|
+
aggregateId: String(collaboratorId),
|
|
1070
|
+
payload: { id: collaboratorId, displayName: resolvedDisplayName, status: normalizedStatus },
|
|
1071
|
+
}).catch(() => null);
|
|
1072
|
+
return result;
|
|
1061
1073
|
}
|
|
1062
1074
|
async updateCollaborator(userId, collaboratorId, data) {
|
|
1063
1075
|
var _a, _b, _c, _d, _e;
|
|
@@ -1080,34 +1092,41 @@ let OperationsService = OperationsService_1 = class OperationsService {
|
|
|
1080
1092
|
}
|
|
1081
1093
|
this.pushUpdate(updates, params, 'level_label', data.levelLabel);
|
|
1082
1094
|
this.pushUpdate(updates, params, 'weekly_capacity_hours', data.weeklyCapacityHours);
|
|
1095
|
+
this.pushUpdate(updates, params, 'hourly_rate', data.hourlyRate);
|
|
1083
1096
|
this.pushUpdate(updates, params, 'status', normalizedStatus, 'operations_collaborator_status_ef779877d4_enum');
|
|
1084
1097
|
this.pushUpdate(updates, params, 'joined_at', data.joinedAt, 'date');
|
|
1085
1098
|
this.pushUpdate(updates, params, 'left_at', data.leftAt, 'date');
|
|
1086
1099
|
this.pushUpdate(updates, params, 'notes', data.notes);
|
|
1100
|
+
let currentHourlyRate = null;
|
|
1087
1101
|
await this.prisma.$transaction(async (tx) => {
|
|
1088
|
-
var _a, _b, _c, _d, _e, _f, _g, _h, _j;
|
|
1102
|
+
var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o, _p, _q;
|
|
1103
|
+
if (data.hourlyRate !== undefined && data.hourlyRate !== null) {
|
|
1104
|
+
const curr = (await tx.$queryRawUnsafe(`SELECT hourly_rate AS "hourlyRate" FROM operations_collaborator WHERE id = $1`, collaboratorId));
|
|
1105
|
+
currentHourlyRate =
|
|
1106
|
+
((_a = curr[0]) === null || _a === void 0 ? void 0 : _a.hourlyRate) != null ? Number(curr[0].hourlyRate) : null;
|
|
1107
|
+
}
|
|
1089
1108
|
if (data.collaboratorType !== undefined ||
|
|
1090
1109
|
data.collaboratorTypeId !== undefined ||
|
|
1091
1110
|
data.collaboratorTypeSlug !== undefined) {
|
|
1092
1111
|
const resolvedCollaboratorType = await this.resolveCollaboratorTypeReference(tx, {
|
|
1093
|
-
collaboratorTypeId: (
|
|
1094
|
-
collaboratorTypeSlug: (
|
|
1112
|
+
collaboratorTypeId: (_b = data.collaboratorTypeId) !== null && _b !== void 0 ? _b : null,
|
|
1113
|
+
collaboratorTypeSlug: (_d = (_c = data.collaboratorTypeSlug) !== null && _c !== void 0 ? _c : data.collaboratorType) !== null && _d !== void 0 ? _d : null,
|
|
1095
1114
|
});
|
|
1096
|
-
this.pushUpdate(updates, params, 'collaborator_type_id', (
|
|
1115
|
+
this.pushUpdate(updates, params, 'collaborator_type_id', (_e = resolvedCollaboratorType === null || resolvedCollaboratorType === void 0 ? void 0 : resolvedCollaboratorType.id) !== null && _e !== void 0 ? _e : null);
|
|
1097
1116
|
}
|
|
1098
1117
|
if (data.departmentId !== undefined) {
|
|
1099
1118
|
const resolvedDepartment = await this.resolveDepartmentReference(tx, {
|
|
1100
|
-
departmentId: (
|
|
1119
|
+
departmentId: (_f = data.departmentId) !== null && _f !== void 0 ? _f : null,
|
|
1101
1120
|
});
|
|
1102
|
-
this.pushUpdate(updates, params, 'department_id', (
|
|
1121
|
+
this.pushUpdate(updates, params, 'department_id', (_g = resolvedDepartment === null || resolvedDepartment === void 0 ? void 0 : resolvedDepartment.id) !== null && _g !== void 0 ? _g : null);
|
|
1103
1122
|
}
|
|
1104
1123
|
if (data.title !== undefined || data.jobTitleId !== undefined) {
|
|
1105
1124
|
const resolvedJobTitle = await this.resolveJobTitleReference(tx, {
|
|
1106
|
-
jobTitleId: (
|
|
1125
|
+
jobTitleId: (_h = data.jobTitleId) !== null && _h !== void 0 ? _h : null,
|
|
1107
1126
|
jobTitleName: data.title,
|
|
1108
1127
|
});
|
|
1109
|
-
this.pushUpdate(updates, params, 'job_title_id', (
|
|
1110
|
-
this.pushUpdate(updates, params, 'title', (
|
|
1128
|
+
this.pushUpdate(updates, params, 'job_title_id', (_j = resolvedJobTitle === null || resolvedJobTitle === void 0 ? void 0 : resolvedJobTitle.id) !== null && _j !== void 0 ? _j : null);
|
|
1129
|
+
this.pushUpdate(updates, params, 'title', (_k = resolvedJobTitle === null || resolvedJobTitle === void 0 ? void 0 : resolvedJobTitle.name) !== null && _k !== void 0 ? _k : this.normalizeOptionalText(data.title));
|
|
1111
1130
|
}
|
|
1112
1131
|
if (updates.length) {
|
|
1113
1132
|
params.push(collaboratorId);
|
|
@@ -1125,6 +1144,7 @@ let OperationsService = OperationsService_1 = class OperationsService {
|
|
|
1125
1144
|
if (data.compensationAmount !== undefined ||
|
|
1126
1145
|
data.contractDescription !== undefined ||
|
|
1127
1146
|
data.autoGenerateContractDraft !== undefined ||
|
|
1147
|
+
data.hourlyRate !== undefined ||
|
|
1128
1148
|
data.joinedAt !== undefined ||
|
|
1129
1149
|
data.weeklyCapacityHours !== undefined ||
|
|
1130
1150
|
data.supervisorCollaboratorId !== undefined ||
|
|
@@ -1134,14 +1154,47 @@ let OperationsService = OperationsService_1 = class OperationsService {
|
|
|
1134
1154
|
data.code !== undefined ||
|
|
1135
1155
|
data.personId !== undefined ||
|
|
1136
1156
|
data.displayName !== undefined) {
|
|
1157
|
+
let currentBudgetAmount = null;
|
|
1158
|
+
if (data.compensationAmount !== undefined &&
|
|
1159
|
+
data.compensationAmount !== null) {
|
|
1160
|
+
const hiringContracts = (await tx.$queryRawUnsafe(`SELECT budget_amount AS "budgetAmount"
|
|
1161
|
+
FROM operations_contract
|
|
1162
|
+
WHERE related_collaborator_id = $1
|
|
1163
|
+
AND origin_type = 'employee_hiring'
|
|
1164
|
+
AND deleted_at IS NULL
|
|
1165
|
+
ORDER BY created_at DESC
|
|
1166
|
+
LIMIT 1`, collaboratorId));
|
|
1167
|
+
currentBudgetAmount =
|
|
1168
|
+
((_l = hiringContracts[0]) === null || _l === void 0 ? void 0 : _l.budgetAmount) != null
|
|
1169
|
+
? Number(hiringContracts[0].budgetAmount)
|
|
1170
|
+
: null;
|
|
1171
|
+
}
|
|
1137
1172
|
await this.syncHiringContractDraft(tx, actor.userId, collaboratorId, data);
|
|
1138
1173
|
if (data.compensationAmount !== undefined &&
|
|
1139
1174
|
data.compensationAmount !== null) {
|
|
1140
|
-
|
|
1175
|
+
const newAmount = Number(data.compensationAmount);
|
|
1176
|
+
if (currentBudgetAmount === null ||
|
|
1177
|
+
newAmount !== currentBudgetAmount) {
|
|
1178
|
+
await this.insertCollaboratorCompensationHistory(tx, collaboratorId, newAmount, actor.userId, (_m = data.compensationNotes) !== null && _m !== void 0 ? _m : null, (_o = data.compensationEffectiveDate) !== null && _o !== void 0 ? _o : null);
|
|
1179
|
+
}
|
|
1180
|
+
}
|
|
1181
|
+
if (data.hourlyRate !== undefined && data.hourlyRate !== null) {
|
|
1182
|
+
const newRate = Number(data.hourlyRate);
|
|
1183
|
+
if (currentHourlyRate === null || newRate !== currentHourlyRate) {
|
|
1184
|
+
await this.insertCollaboratorCompensationHistory(tx, collaboratorId, newRate, actor.userId, (_p = data.compensationNotes) !== null && _p !== void 0 ? _p : null, (_q = data.compensationEffectiveDate) !== null && _q !== void 0 ? _q : null, 'hourly_rate');
|
|
1185
|
+
}
|
|
1141
1186
|
}
|
|
1142
1187
|
}
|
|
1143
1188
|
});
|
|
1144
|
-
|
|
1189
|
+
const collaboratorResult = await this.getCollaboratorByIdForUser(userId, collaboratorId);
|
|
1190
|
+
await this.integrationApi.publishEvent({
|
|
1191
|
+
eventName: 'operations.collaborator.updated',
|
|
1192
|
+
sourceModule: 'operations',
|
|
1193
|
+
aggregateType: 'collaborator',
|
|
1194
|
+
aggregateId: String(collaboratorId),
|
|
1195
|
+
payload: { id: collaboratorId, displayName: data.displayName, status: data.status },
|
|
1196
|
+
}).catch(() => null);
|
|
1197
|
+
return collaboratorResult;
|
|
1145
1198
|
}
|
|
1146
1199
|
async updateCollaboratorProjectAssignment(collaboratorId, projectId, data) {
|
|
1147
1200
|
var _a, _b, _c, _d, _e, _f;
|
|
@@ -1210,6 +1263,7 @@ let OperationsService = OperationsService_1 = class OperationsService {
|
|
|
1210
1263
|
h.actor_user_id AS "actorUserId",
|
|
1211
1264
|
u.name AS "actorName",
|
|
1212
1265
|
h.notes,
|
|
1266
|
+
h.amount_type AS "amountType",
|
|
1213
1267
|
h.created_at AS "createdAt"
|
|
1214
1268
|
FROM operations_collaborator_compensation_history h
|
|
1215
1269
|
LEFT JOIN "user" u ON u.id = h.actor_user_id
|
|
@@ -1714,7 +1768,7 @@ let OperationsService = OperationsService_1 = class OperationsService {
|
|
|
1714
1768
|
return this.buildPaginationResult(rows.map((row) => (Object.assign(Object.assign({}, row), { label: [row.name, row.projectName].filter(Boolean).join(' • ') }))), Number((_b = totalRow === null || totalRow === void 0 ? void 0 : totalRow.total) !== null && _b !== void 0 ? _b : 0), pagination.page, pagination.pageSize);
|
|
1715
1769
|
}
|
|
1716
1770
|
async createTask(userId, data) {
|
|
1717
|
-
var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o, _p;
|
|
1771
|
+
var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o, _p, _q, _r, _s;
|
|
1718
1772
|
const actor = await this.getActorContext(userId);
|
|
1719
1773
|
if (!actor.isCollaborator && !actor.isDirector && !actor.isSupervisor) {
|
|
1720
1774
|
throw new common_1.ForbiddenException('Operations collaborator access is required.');
|
|
@@ -1790,7 +1844,15 @@ let OperationsService = OperationsService_1 = class OperationsService {
|
|
|
1790
1844
|
(_m = data.position) !== null && _m !== void 0 ? _m : nextPosition,
|
|
1791
1845
|
(_o = data.tags) !== null && _o !== void 0 ? _o : null,
|
|
1792
1846
|
]);
|
|
1793
|
-
|
|
1847
|
+
const task = await this.getProjectBoardTask((_p = created === null || created === void 0 ? void 0 : created.id) !== null && _p !== void 0 ? _p : 0);
|
|
1848
|
+
await this.integrationApi.publishEvent({
|
|
1849
|
+
eventName: 'operations.task.created',
|
|
1850
|
+
sourceModule: 'operations',
|
|
1851
|
+
aggregateType: 'task',
|
|
1852
|
+
aggregateId: String((_q = created === null || created === void 0 ? void 0 : created.id) !== null && _q !== void 0 ? _q : 0),
|
|
1853
|
+
payload: { id: created === null || created === void 0 ? void 0 : created.id, projectId, name, status: (_r = data.status) !== null && _r !== void 0 ? _r : 'todo', priority: (_s = data.priority) !== null && _s !== void 0 ? _s : 'medium' },
|
|
1854
|
+
}).catch(() => null);
|
|
1855
|
+
return task;
|
|
1794
1856
|
}
|
|
1795
1857
|
async updateTask(userId, taskId, data) {
|
|
1796
1858
|
const actor = await this.getActorContext(userId);
|
|
@@ -1848,7 +1910,15 @@ let OperationsService = OperationsService_1 = class OperationsService {
|
|
|
1848
1910
|
? this.normalizeOptionalText(data.description)
|
|
1849
1911
|
: ((_d = current.description) !== null && _d !== void 0 ? _d : null), (_e = data.priority) !== null && _e !== void 0 ? _e : current.priority, nextStatus, data.dueDate !== undefined ? ((_f = data.dueDate) !== null && _f !== void 0 ? _f : null) : current.dueDate, data.estimateHours !== undefined ? ((_g = data.estimateHours) !== null && _g !== void 0 ? _g : null) : current.estimateHours, data.position !== undefined ? data.position : current.position, data.tags !== undefined ? ((_h = data.tags) !== null && _h !== void 0 ? _h : null) : current.tags, nextArchived, taskId, Boolean(current.deletedAt));
|
|
1850
1912
|
});
|
|
1851
|
-
|
|
1913
|
+
const taskResult = await this.getProjectBoardTask(taskId);
|
|
1914
|
+
await this.integrationApi.publishEvent({
|
|
1915
|
+
eventName: 'operations.task.updated',
|
|
1916
|
+
sourceModule: 'operations',
|
|
1917
|
+
aggregateType: 'task',
|
|
1918
|
+
aggregateId: String(taskId),
|
|
1919
|
+
payload: { id: taskId, name: data.name, status: data.status },
|
|
1920
|
+
}).catch(() => null);
|
|
1921
|
+
return taskResult;
|
|
1852
1922
|
}
|
|
1853
1923
|
async removeTask(userId, taskId, permanent = false) {
|
|
1854
1924
|
const actor = await this.getActorContext(userId);
|
|
@@ -1869,6 +1939,13 @@ let OperationsService = OperationsService_1 = class OperationsService {
|
|
|
1869
1939
|
WHERE id = $1
|
|
1870
1940
|
AND deleted_at IS NULL`, taskId);
|
|
1871
1941
|
});
|
|
1942
|
+
await this.integrationApi.publishEvent({
|
|
1943
|
+
eventName: 'operations.task.deleted',
|
|
1944
|
+
sourceModule: 'operations',
|
|
1945
|
+
aggregateType: 'task',
|
|
1946
|
+
aggregateId: String(taskId),
|
|
1947
|
+
payload: { id: taskId, projectId: current.projectId, permanent },
|
|
1948
|
+
}).catch(() => null);
|
|
1872
1949
|
return { success: true };
|
|
1873
1950
|
}
|
|
1874
1951
|
async listTaskFiles(userId, taskId) {
|
|
@@ -1972,7 +2049,7 @@ let OperationsService = OperationsService_1 = class OperationsService {
|
|
|
1972
2049
|
return createdComment;
|
|
1973
2050
|
}
|
|
1974
2051
|
async updateTaskComment(userId, taskId, commentId, content) {
|
|
1975
|
-
var _a;
|
|
2052
|
+
var _a, _b;
|
|
1976
2053
|
const actor = await this.getActorContext(userId);
|
|
1977
2054
|
if (!actor.isCollaborator && !actor.isDirector && !actor.isSupervisor) {
|
|
1978
2055
|
throw new common_1.ForbiddenException('Operations collaborator access is required.');
|
|
@@ -1983,7 +2060,7 @@ let OperationsService = OperationsService_1 = class OperationsService {
|
|
|
1983
2060
|
if (!normalizedContent) {
|
|
1984
2061
|
throw new common_1.BadRequestException('Comment content is required.');
|
|
1985
2062
|
}
|
|
1986
|
-
const rows = await this.queryRows(`SELECT id, actor_collaborator_id AS "actorCollaboratorId"
|
|
2063
|
+
const rows = await this.queryRows(`SELECT id, actor_collaborator_id AS "actorCollaboratorId", created_at AS "createdAt"
|
|
1987
2064
|
FROM operations_task_comment
|
|
1988
2065
|
WHERE id = $1 AND task_id = $2`, [commentId, taskId]);
|
|
1989
2066
|
const row = rows[0];
|
|
@@ -1993,20 +2070,29 @@ let OperationsService = OperationsService_1 = class OperationsService {
|
|
|
1993
2070
|
if (row.actorCollaboratorId !== actor.collaboratorId) {
|
|
1994
2071
|
throw new common_1.ForbiddenException('You can only edit your own comments.');
|
|
1995
2072
|
}
|
|
2073
|
+
const editSettings = await this.settingService.getSettingValues(['operations.comment-edit-window']);
|
|
2074
|
+
const editWindowMinutes = Number((_a = editSettings['operations.comment-edit-window']) !== null && _a !== void 0 ? _a : 5);
|
|
2075
|
+
if (editWindowMinutes > 0) {
|
|
2076
|
+
const diffMinutes = (Date.now() - new Date(row.createdAt).getTime()) / 60000;
|
|
2077
|
+
if (diffMinutes > editWindowMinutes) {
|
|
2078
|
+
throw new common_1.ForbiddenException(`Comments can only be edited within ${editWindowMinutes} minute(s) of posting.`);
|
|
2079
|
+
}
|
|
2080
|
+
}
|
|
1996
2081
|
await this.queryRows(`UPDATE operations_task_comment
|
|
1997
2082
|
SET content = $1, updated_at = NOW()
|
|
1998
2083
|
WHERE id = $2`, [normalizedContent, commentId]);
|
|
1999
2084
|
const comments = await this.listTaskComments(userId, taskId);
|
|
2000
|
-
return (
|
|
2085
|
+
return (_b = comments.find((c) => c.id === commentId)) !== null && _b !== void 0 ? _b : null;
|
|
2001
2086
|
}
|
|
2002
2087
|
async removeTaskComment(userId, taskId, commentId) {
|
|
2088
|
+
var _a;
|
|
2003
2089
|
const actor = await this.getActorContext(userId);
|
|
2004
2090
|
if (!actor.isCollaborator && !actor.isDirector && !actor.isSupervisor) {
|
|
2005
2091
|
throw new common_1.ForbiddenException('Operations collaborator access is required.');
|
|
2006
2092
|
}
|
|
2007
2093
|
const current = await this.getTaskRecordForActor(this.prisma, actor, taskId);
|
|
2008
2094
|
await this.assertProjectAccess(actor, current.projectId);
|
|
2009
|
-
const rows = await this.queryRows(`SELECT id, actor_collaborator_id AS "actorCollaboratorId"
|
|
2095
|
+
const rows = await this.queryRows(`SELECT id, actor_collaborator_id AS "actorCollaboratorId", created_at AS "createdAt"
|
|
2010
2096
|
FROM operations_task_comment
|
|
2011
2097
|
WHERE id = $1 AND task_id = $2`, [commentId, taskId]);
|
|
2012
2098
|
const row = rows[0];
|
|
@@ -2016,6 +2102,14 @@ let OperationsService = OperationsService_1 = class OperationsService {
|
|
|
2016
2102
|
if (row.actorCollaboratorId !== actor.collaboratorId) {
|
|
2017
2103
|
throw new common_1.ForbiddenException('You can only delete your own comments.');
|
|
2018
2104
|
}
|
|
2105
|
+
const deleteSettings = await this.settingService.getSettingValues(['operations.comment-edit-window']);
|
|
2106
|
+
const deleteWindowMinutes = Number((_a = deleteSettings['operations.comment-edit-window']) !== null && _a !== void 0 ? _a : 5);
|
|
2107
|
+
if (deleteWindowMinutes > 0) {
|
|
2108
|
+
const diffMinutes = (Date.now() - new Date(row.createdAt).getTime()) / 60000;
|
|
2109
|
+
if (diffMinutes > deleteWindowMinutes) {
|
|
2110
|
+
throw new common_1.ForbiddenException(`Comments can only be deleted within ${deleteWindowMinutes} minute(s) of posting.`);
|
|
2111
|
+
}
|
|
2112
|
+
}
|
|
2019
2113
|
await this.queryRows(`DELETE FROM operations_task_comment WHERE id = $1`, [commentId]);
|
|
2020
2114
|
return { success: true };
|
|
2021
2115
|
}
|
|
@@ -2285,6 +2379,7 @@ let OperationsService = OperationsService_1 = class OperationsService {
|
|
|
2285
2379
|
return this.getProjectDetails(projectId, actor.collaboratorId);
|
|
2286
2380
|
}
|
|
2287
2381
|
async createProject(userId, data) {
|
|
2382
|
+
var _a;
|
|
2288
2383
|
const actor = await this.getActorContext(userId);
|
|
2289
2384
|
this.ensureDirector(actor);
|
|
2290
2385
|
this.requireFields(data, ['code', 'name']);
|
|
@@ -2320,7 +2415,15 @@ let OperationsService = OperationsService_1 = class OperationsService {
|
|
|
2320
2415
|
}
|
|
2321
2416
|
return projectId;
|
|
2322
2417
|
});
|
|
2323
|
-
|
|
2418
|
+
const result = await this.getProjectById(userId, createdProjectId);
|
|
2419
|
+
await this.integrationApi.publishEvent({
|
|
2420
|
+
eventName: 'operations.project.created',
|
|
2421
|
+
sourceModule: 'operations',
|
|
2422
|
+
aggregateType: 'project',
|
|
2423
|
+
aggregateId: String(createdProjectId),
|
|
2424
|
+
payload: { id: createdProjectId, code: data.code, name: data.name, status: (_a = data.status) !== null && _a !== void 0 ? _a : 'planning' },
|
|
2425
|
+
}).catch(() => null);
|
|
2426
|
+
return result;
|
|
2324
2427
|
}
|
|
2325
2428
|
async updateProject(userId, projectId, data) {
|
|
2326
2429
|
const actor = await this.getActorContext(userId);
|
|
@@ -2373,7 +2476,15 @@ let OperationsService = OperationsService_1 = class OperationsService {
|
|
|
2373
2476
|
}
|
|
2374
2477
|
}
|
|
2375
2478
|
});
|
|
2376
|
-
|
|
2479
|
+
const projectResult = await this.getProjectById(userId, projectId);
|
|
2480
|
+
await this.integrationApi.publishEvent({
|
|
2481
|
+
eventName: 'operations.project.updated',
|
|
2482
|
+
sourceModule: 'operations',
|
|
2483
|
+
aggregateType: 'project',
|
|
2484
|
+
aggregateId: String(projectId),
|
|
2485
|
+
payload: { id: projectId, name: data.name, status: data.status },
|
|
2486
|
+
}).catch(() => null);
|
|
2487
|
+
return projectResult;
|
|
2377
2488
|
}
|
|
2378
2489
|
async listContracts(userId, filters = {}) {
|
|
2379
2490
|
var _a, _b;
|
|
@@ -4766,6 +4877,7 @@ let OperationsService = OperationsService_1 = class OperationsService {
|
|
|
4766
4877
|
COALESCE(NULLIF(job_title_record.name, ''), NULLIF(c.title, '')) AS "title",
|
|
4767
4878
|
c.level_label AS "levelLabel",
|
|
4768
4879
|
c.weekly_capacity_hours AS "weeklyCapacityHours",
|
|
4880
|
+
c.hourly_rate AS "hourlyRate",
|
|
4769
4881
|
c.status,
|
|
4770
4882
|
c.joined_at AS "joinedAt",
|
|
4771
4883
|
c.left_at AS "leftAt",
|
|
@@ -6222,16 +6334,18 @@ let OperationsService = OperationsService_1 = class OperationsService {
|
|
|
6222
6334
|
$1, $2, $3, $4, $5, NOW()
|
|
6223
6335
|
)`, contractId, actorUserId, action, note, metadataJson !== null && metadataJson !== void 0 ? metadataJson : null);
|
|
6224
6336
|
}
|
|
6225
|
-
async insertCollaboratorCompensationHistory(client, collaboratorId, amount, actorUserId, notes) {
|
|
6337
|
+
async insertCollaboratorCompensationHistory(client, collaboratorId, amount, actorUserId, notes, effectiveDate, amountType = 'salary') {
|
|
6226
6338
|
await client.$executeRawUnsafe(`INSERT INTO operations_collaborator_compensation_history (
|
|
6227
6339
|
collaborator_id,
|
|
6228
6340
|
amount,
|
|
6229
6341
|
actor_user_id,
|
|
6230
6342
|
notes,
|
|
6343
|
+
effective_date,
|
|
6344
|
+
amount_type,
|
|
6231
6345
|
created_at
|
|
6232
6346
|
) VALUES (
|
|
6233
|
-
$1, $2, $3, $4, NOW()
|
|
6234
|
-
)`, collaboratorId, amount, actorUserId, notes !== null && notes !== void 0 ? notes : null);
|
|
6347
|
+
$1, $2, $3, $4, $5::date, $6::operations_collaborator_compensation_history_am_f803c4196e_enum, NOW()
|
|
6348
|
+
)`, collaboratorId, amount, actorUserId, notes !== null && notes !== void 0 ? notes : null, effectiveDate !== null && effectiveDate !== void 0 ? effectiveDate : null, amountType);
|
|
6235
6349
|
}
|
|
6236
6350
|
async generateCollaboratorCode(client) {
|
|
6237
6351
|
for (let attempt = 0; attempt < 5; attempt += 1) {
|