@hed-hog/operations 0.0.299 → 0.0.301

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (97) hide show
  1. package/dist/operations.controller.d.ts +713 -31
  2. package/dist/operations.controller.d.ts.map +1 -1
  3. package/dist/operations.controller.js +157 -0
  4. package/dist/operations.controller.js.map +1 -1
  5. package/dist/operations.module.d.ts.map +1 -1
  6. package/dist/operations.module.js +5 -1
  7. package/dist/operations.module.js.map +1 -1
  8. package/dist/operations.proposal.subscriber.d.ts +11 -0
  9. package/dist/operations.proposal.subscriber.d.ts.map +1 -0
  10. package/dist/operations.proposal.subscriber.js +80 -0
  11. package/dist/operations.proposal.subscriber.js.map +1 -0
  12. package/dist/operations.proposal.subscriber.spec.d.ts +2 -0
  13. package/dist/operations.proposal.subscriber.spec.d.ts.map +1 -0
  14. package/dist/operations.proposal.subscriber.spec.js +88 -0
  15. package/dist/operations.proposal.subscriber.spec.js.map +1 -0
  16. package/dist/operations.service.d.ts +490 -46
  17. package/dist/operations.service.d.ts.map +1 -1
  18. package/dist/operations.service.js +3590 -1267
  19. package/dist/operations.service.js.map +1 -1
  20. package/dist/operations.service.spec.d.ts +2 -0
  21. package/dist/operations.service.spec.d.ts.map +1 -0
  22. package/dist/operations.service.spec.js +159 -0
  23. package/dist/operations.service.spec.js.map +1 -0
  24. package/hedhog/data/menu.yaml +232 -198
  25. package/hedhog/data/role.yaml +23 -23
  26. package/hedhog/data/role_route.yaml +39 -0
  27. package/hedhog/data/route.yaml +447 -317
  28. package/hedhog/frontend/app/_components/collaborator-details-screen.tsx.ejs +8 -6
  29. package/hedhog/frontend/app/_components/collaborator-form-screen.tsx.ejs +1163 -327
  30. package/hedhog/frontend/app/_components/collaborator-select-with-create.tsx.ejs +256 -0
  31. package/hedhog/frontend/app/_components/contract-content-editor.tsx.ejs +258 -0
  32. package/hedhog/frontend/app/_components/contract-creation-wizard.tsx.ejs +631 -0
  33. package/hedhog/frontend/app/_components/contract-details-screen.tsx.ejs +353 -27
  34. package/hedhog/frontend/app/_components/contract-form-screen.tsx.ejs +1926 -87
  35. package/hedhog/frontend/app/_components/contract-template-form-screen.tsx.ejs +526 -0
  36. package/hedhog/frontend/app/_components/contract-template-select-with-create.tsx.ejs +247 -0
  37. package/hedhog/frontend/app/_components/contract-wizard-sheet.tsx.ejs +3520 -0
  38. package/hedhog/frontend/app/_components/department-select-with-create.tsx.ejs +370 -0
  39. package/hedhog/frontend/app/_components/person-select-with-create.tsx.ejs +826 -0
  40. package/hedhog/frontend/app/_components/project-form-screen.tsx.ejs +1251 -364
  41. package/hedhog/frontend/app/_components/section-card.tsx.ejs +48 -13
  42. package/hedhog/frontend/app/_lib/api.ts.ejs +2 -5
  43. package/hedhog/frontend/app/_lib/types.ts.ejs +76 -33
  44. package/hedhog/frontend/app/_lib/utils/format.ts.ejs +85 -8
  45. package/hedhog/frontend/app/approvals/page.tsx.ejs +90 -54
  46. package/hedhog/frontend/app/collaborators/[id]/edit/page.tsx.ejs +2 -2
  47. package/hedhog/frontend/app/collaborators/[id]/page.tsx.ejs +2 -2
  48. package/hedhog/frontend/app/collaborators/page.tsx.ejs +597 -140
  49. package/hedhog/frontend/app/contracts/[id]/edit/page.tsx.ejs +2 -2
  50. package/hedhog/frontend/app/contracts/[id]/page.tsx.ejs +2 -2
  51. package/hedhog/frontend/app/contracts/page.tsx.ejs +941 -262
  52. package/hedhog/frontend/app/contracts/templates/page.tsx.ejs +384 -0
  53. package/hedhog/frontend/app/departments/page.tsx.ejs +442 -0
  54. package/hedhog/frontend/app/page.tsx.ejs +36 -12
  55. package/hedhog/frontend/app/projects/[id]/edit/page.tsx.ejs +2 -2
  56. package/hedhog/frontend/app/projects/new/page.tsx.ejs +2 -2
  57. package/hedhog/frontend/app/projects/page.tsx.ejs +264 -102
  58. package/hedhog/frontend/app/schedule-adjustments/page.tsx.ejs +50 -28
  59. package/hedhog/frontend/app/time-off/page.tsx.ejs +57 -31
  60. package/hedhog/frontend/app/timesheets/page.tsx.ejs +85 -42
  61. package/hedhog/frontend/messages/en.json +473 -12
  62. package/hedhog/frontend/messages/pt.json +528 -66
  63. package/hedhog/table/operations_approval.yaml +49 -49
  64. package/hedhog/table/operations_approval_history.yaml +29 -29
  65. package/hedhog/table/operations_collaborator.yaml +87 -67
  66. package/hedhog/table/operations_collaborator_schedule_day.yaml +34 -34
  67. package/hedhog/table/operations_contract.yaml +121 -100
  68. package/hedhog/table/operations_contract_document.yaml +40 -23
  69. package/hedhog/table/operations_contract_financial_term.yaml +40 -40
  70. package/hedhog/table/operations_contract_history.yaml +27 -27
  71. package/hedhog/table/operations_contract_party.yaml +46 -46
  72. package/hedhog/table/operations_contract_revision.yaml +38 -38
  73. package/hedhog/table/operations_contract_signature.yaml +38 -38
  74. package/hedhog/table/operations_contract_template.yaml +58 -0
  75. package/hedhog/table/operations_department.yaml +24 -0
  76. package/hedhog/table/operations_project.yaml +54 -54
  77. package/hedhog/table/operations_project_assignment.yaml +55 -55
  78. package/hedhog/table/operations_schedule_adjustment_day.yaml +34 -34
  79. package/hedhog/table/operations_schedule_adjustment_request.yaml +53 -53
  80. package/hedhog/table/operations_time_off_request.yaml +57 -57
  81. package/hedhog/table/operations_timesheet.yaml +41 -41
  82. package/hedhog/table/operations_timesheet_entry.yaml +40 -40
  83. package/package.json +5 -3
  84. package/src/operations.controller.ts +304 -182
  85. package/src/operations.module.ts +26 -22
  86. package/src/operations.proposal.subscriber.spec.ts +121 -0
  87. package/src/operations.proposal.subscriber.ts +86 -0
  88. package/src/operations.service.spec.ts +210 -0
  89. package/src/operations.service.ts +7317 -3595
  90. package/dist/operations-data.controller.d.ts +0 -139
  91. package/dist/operations-data.controller.d.ts.map +0 -1
  92. package/dist/operations-data.controller.js +0 -113
  93. package/dist/operations-data.controller.js.map +0 -1
  94. package/dist/operations-growth.controller.d.ts +0 -48
  95. package/dist/operations-growth.controller.d.ts.map +0 -1
  96. package/dist/operations-growth.controller.js +0 -90
  97. package/dist/operations-growth.controller.js.map +0 -1
@@ -1,182 +1,304 @@
1
- import { Role, User } from '@hed-hog/api';
2
- import {
3
- Body,
4
- Controller,
5
- Get,
6
- Param,
7
- ParseIntPipe,
8
- Patch,
9
- Post,
10
- } from '@nestjs/common';
11
- import { OperationsService } from './operations.service';
12
-
13
- @Role()
14
- @Controller('operations')
15
- export class OperationsController {
16
- constructor(private readonly operationsService: OperationsService) {}
17
-
18
- @Get('dashboard')
19
- getDashboard(@User() user) {
20
- return this.operationsService.getDashboard(Number(user?.id || 0));
21
- }
22
-
23
- @Get('collaborators')
24
- listCollaborators(@User() user) {
25
- return this.operationsService.listCollaborators(Number(user?.id || 0));
26
- }
27
-
28
- @Get('collaborators/me')
29
- getMyCollaborator(@User() user) {
30
- return this.operationsService.getMyCollaborator(Number(user?.id || 0));
31
- }
32
-
33
- @Get('collaborators/:id')
34
- getCollaborator(@User() user, @Param('id', ParseIntPipe) id: number) {
35
- return this.operationsService.getCollaboratorByIdForUser(
36
- Number(user?.id || 0),
37
- id
38
- );
39
- }
40
-
41
- @Get('collaborators/team')
42
- getTeam(@User() user) {
43
- return this.operationsService.getTeam(Number(user?.id || 0));
44
- }
45
-
46
- @Post('collaborators')
47
- createCollaborator(@User() user, @Body() data) {
48
- return this.operationsService.createCollaborator(Number(user?.id || 0), data);
49
- }
50
-
51
- @Patch('collaborators/:id')
52
- updateCollaborator(
53
- @User() user,
54
- @Param('id', ParseIntPipe) id: number,
55
- @Body() data
56
- ) {
57
- return this.operationsService.updateCollaborator(
58
- Number(user?.id || 0),
59
- id,
60
- data
61
- );
62
- }
63
-
64
- @Get('projects')
65
- listProjects(@User() user) {
66
- return this.operationsService.listProjects(Number(user?.id || 0));
67
- }
68
-
69
- @Get('projects/:id')
70
- getProject(@User() user, @Param('id', ParseIntPipe) id: number) {
71
- return this.operationsService.getProjectById(Number(user?.id || 0), id);
72
- }
73
-
74
- @Post('projects')
75
- createProject(@User() user, @Body() data) {
76
- return this.operationsService.createProject(Number(user?.id || 0), data);
77
- }
78
-
79
- @Patch('projects/:id')
80
- updateProject(@User() user, @Param('id', ParseIntPipe) id: number, @Body() data) {
81
- return this.operationsService.updateProject(Number(user?.id || 0), id, data);
82
- }
83
-
84
- @Get('contracts')
85
- listContracts(@User() user) {
86
- return this.operationsService.listContracts(Number(user?.id || 0));
87
- }
88
-
89
- @Get('contracts/:id')
90
- getContract(@User() user, @Param('id', ParseIntPipe) id: number) {
91
- return this.operationsService.getContractById(Number(user?.id || 0), id);
92
- }
93
-
94
- @Post('contracts')
95
- createContract(@User() user, @Body() data) {
96
- return this.operationsService.createContract(Number(user?.id || 0), data);
97
- }
98
-
99
- @Patch('contracts/:id')
100
- updateContract(
101
- @User() user,
102
- @Param('id', ParseIntPipe) id: number,
103
- @Body() data
104
- ) {
105
- return this.operationsService.updateContract(Number(user?.id || 0), id, data);
106
- }
107
-
108
- @Get('timesheets')
109
- listTimesheets(@User() user) {
110
- return this.operationsService.listTimesheets(Number(user?.id || 0));
111
- }
112
-
113
- @Post('timesheets')
114
- createTimesheet(@User() user, @Body() data) {
115
- return this.operationsService.createTimesheet(Number(user?.id || 0), data);
116
- }
117
-
118
- @Patch('timesheets/:id')
119
- updateTimesheet(
120
- @User() user,
121
- @Param('id', ParseIntPipe) id: number,
122
- @Body() data
123
- ) {
124
- return this.operationsService.updateTimesheet(Number(user?.id || 0), id, data);
125
- }
126
-
127
- @Post('timesheets/:id/submit')
128
- submitTimesheet(@User() user, @Param('id', ParseIntPipe) id: number) {
129
- return this.operationsService.submitTimesheet(Number(user?.id || 0), id);
130
- }
131
-
132
- @Get('time-off')
133
- listTimeOffRequests(@User() user) {
134
- return this.operationsService.listTimeOffRequests(Number(user?.id || 0));
135
- }
136
-
137
- @Post('time-off')
138
- createTimeOffRequest(@User() user, @Body() data) {
139
- return this.operationsService.createTimeOffRequest(Number(user?.id || 0), data);
140
- }
141
-
142
- @Get('schedule-adjustments')
143
- listScheduleAdjustments(@User() user) {
144
- return this.operationsService.listScheduleAdjustments(Number(user?.id || 0));
145
- }
146
-
147
- @Post('schedule-adjustments')
148
- createScheduleAdjustmentRequest(@User() user, @Body() data) {
149
- return this.operationsService.createScheduleAdjustmentRequest(
150
- Number(user?.id || 0),
151
- data
152
- );
153
- }
154
-
155
- @Get('approvals')
156
- listApprovals(@User() user) {
157
- return this.operationsService.listApprovals(Number(user?.id || 0));
158
- }
159
-
160
- @Post('approvals/:id/approve')
161
- approve(@User() user, @Param('id', ParseIntPipe) id: number, @Body() data) {
162
- return this.operationsService.approve(Number(user?.id || 0), id, data);
163
- }
164
-
165
- @Post('approvals/:id/reject')
166
- reject(@User() user, @Param('id', ParseIntPipe) id: number, @Body() data) {
167
- return this.operationsService.reject(Number(user?.id || 0), id, data);
168
- }
169
-
170
- @Post('integration/examples/accounts-payable')
171
- publishAccountsPayableReference(@User() user, @Body() data) {
172
- return this.operationsService.publishAccountsPayableReference(
173
- Number(user?.id || 0),
174
- data,
175
- );
176
- }
177
-
178
- @Get('team')
179
- getSupervisorTeam(@User() user) {
180
- return this.operationsService.getTeam(Number(user?.id || 0));
181
- }
182
- }
1
+ import { Role, User } from '@hed-hog/api';
2
+ import {
3
+ Body,
4
+ Controller,
5
+ Delete,
6
+ Get,
7
+ Param,
8
+ ParseIntPipe,
9
+ Patch,
10
+ Post,
11
+ } from '@nestjs/common';
12
+ import { OperationsService } from './operations.service';
13
+
14
+ @Role()
15
+ @Controller('operations')
16
+ export class OperationsController {
17
+ constructor(private readonly operationsService: OperationsService) {}
18
+
19
+ @Get('dashboard')
20
+ getDashboard(@User() user) {
21
+ return this.operationsService.getDashboard(Number(user?.id || 0));
22
+ }
23
+
24
+ @Get('collaborators')
25
+ listCollaborators(@User() user) {
26
+ return this.operationsService.listCollaborators(Number(user?.id || 0));
27
+ }
28
+
29
+ @Get('collaborators/me')
30
+ getMyCollaborator(@User() user) {
31
+ return this.operationsService.getMyCollaborator(Number(user?.id || 0));
32
+ }
33
+
34
+ @Get('collaborators/:id')
35
+ getCollaborator(@User() user, @Param('id', ParseIntPipe) id: number) {
36
+ return this.operationsService.getCollaboratorByIdForUser(
37
+ Number(user?.id || 0),
38
+ id
39
+ );
40
+ }
41
+
42
+ @Get('collaborators/team')
43
+ getTeam(@User() user) {
44
+ return this.operationsService.getTeam(Number(user?.id || 0));
45
+ }
46
+
47
+ @Post('collaborators')
48
+ createCollaborator(@User() user, @Body() data) {
49
+ return this.operationsService.createCollaborator(Number(user?.id || 0), data);
50
+ }
51
+
52
+ @Patch('collaborators/:id')
53
+ updateCollaborator(
54
+ @User() user,
55
+ @Param('id', ParseIntPipe) id: number,
56
+ @Body() data
57
+ ) {
58
+ return this.operationsService.updateCollaborator(
59
+ Number(user?.id || 0),
60
+ id,
61
+ data
62
+ );
63
+ }
64
+
65
+ @Get('departments')
66
+ listDepartments(@User() user) {
67
+ return this.operationsService.listDepartments(Number(user?.id || 0));
68
+ }
69
+
70
+ @Post('departments')
71
+ createDepartment(@User() user, @Body() data) {
72
+ return this.operationsService.createDepartment(Number(user?.id || 0), data);
73
+ }
74
+
75
+ @Patch('departments/:id')
76
+ updateDepartment(
77
+ @User() user,
78
+ @Param('id', ParseIntPipe) id: number,
79
+ @Body() data
80
+ ) {
81
+ return this.operationsService.updateDepartment(Number(user?.id || 0), id, data);
82
+ }
83
+
84
+ @Get('projects')
85
+ listProjects(@User() user) {
86
+ return this.operationsService.listProjects(Number(user?.id || 0));
87
+ }
88
+
89
+ @Get('projects/:id')
90
+ getProject(@User() user, @Param('id', ParseIntPipe) id: number) {
91
+ return this.operationsService.getProjectById(Number(user?.id || 0), id);
92
+ }
93
+
94
+ @Post('projects')
95
+ createProject(@User() user, @Body() data) {
96
+ return this.operationsService.createProject(Number(user?.id || 0), data);
97
+ }
98
+
99
+ @Patch('projects/:id')
100
+ updateProject(@User() user, @Param('id', ParseIntPipe) id: number, @Body() data) {
101
+ return this.operationsService.updateProject(Number(user?.id || 0), id, data);
102
+ }
103
+
104
+ @Get('contract-templates')
105
+ listContractTemplates(@User() user) {
106
+ return this.operationsService.listContractTemplates(Number(user?.id || 0));
107
+ }
108
+
109
+ @Get('contract-templates/:id')
110
+ getContractTemplate(@User() user, @Param('id', ParseIntPipe) id: number) {
111
+ return this.operationsService.getContractTemplateById(
112
+ Number(user?.id || 0),
113
+ id
114
+ );
115
+ }
116
+
117
+ @Post('contract-templates')
118
+ createContractTemplate(@User() user, @Body() data) {
119
+ return this.operationsService.createContractTemplate(
120
+ Number(user?.id || 0),
121
+ data
122
+ );
123
+ }
124
+
125
+ @Patch('contract-templates/:id')
126
+ updateContractTemplate(
127
+ @User() user,
128
+ @Param('id', ParseIntPipe) id: number,
129
+ @Body() data
130
+ ) {
131
+ return this.operationsService.updateContractTemplate(
132
+ Number(user?.id || 0),
133
+ id,
134
+ data
135
+ );
136
+ }
137
+
138
+ @Get('contracts')
139
+ listContracts(@User() user) {
140
+ return this.operationsService.listContracts(Number(user?.id || 0));
141
+ }
142
+
143
+ @Get('contracts/:id')
144
+ getContract(@User() user, @Param('id', ParseIntPipe) id: number) {
145
+ return this.operationsService.getContractById(Number(user?.id || 0), id);
146
+ }
147
+
148
+ @Post('contracts/drafts')
149
+ createContractDraft(@User() user, @Body() data) {
150
+ return this.operationsService.createContractDraft(Number(user?.id || 0), data);
151
+ }
152
+
153
+ @Post('contracts')
154
+ createContract(@User() user, @Body() data) {
155
+ return this.operationsService.createContract(Number(user?.id || 0), data);
156
+ }
157
+
158
+ @Post('contracts/extract-draft')
159
+ extractContractDraft(@User() user, @Body() data) {
160
+ return this.operationsService.extractContractDraft(
161
+ Number(user?.id || 0),
162
+ data
163
+ );
164
+ }
165
+
166
+ @Post('contracts/:id/extract-source')
167
+ extractContractSource(
168
+ @User() user,
169
+ @Param('id', ParseIntPipe) id: number,
170
+ @Body() data
171
+ ) {
172
+ return this.operationsService.extractContractSource(
173
+ Number(user?.id || 0),
174
+ id,
175
+ data
176
+ );
177
+ }
178
+
179
+ @Post('contracts/:id/generate-content')
180
+ generateContractContent(
181
+ @User() user,
182
+ @Param('id', ParseIntPipe) id: number,
183
+ @Body() data
184
+ ) {
185
+ return this.operationsService.generateContractContent(
186
+ Number(user?.id || 0),
187
+ id,
188
+ data
189
+ );
190
+ }
191
+
192
+ @Post('contracts/:id/legal-review')
193
+ reviewContractLegally(
194
+ @User() user,
195
+ @Param('id', ParseIntPipe) id: number,
196
+ @Body() data
197
+ ) {
198
+ return this.operationsService.reviewContractLegally(
199
+ Number(user?.id || 0),
200
+ id,
201
+ data
202
+ );
203
+ }
204
+
205
+ @Patch('contracts/:id')
206
+ updateContract(
207
+ @User() user,
208
+ @Param('id', ParseIntPipe) id: number,
209
+ @Body() data
210
+ ) {
211
+ return this.operationsService.updateContract(Number(user?.id || 0), id, data);
212
+ }
213
+
214
+ @Delete('contracts/:id')
215
+ removeContract(@User() user, @Param('id', ParseIntPipe) id: number) {
216
+ return this.operationsService.removeContract(Number(user?.id || 0), id);
217
+ }
218
+
219
+ @Post('contracts/:id/generate-pdf')
220
+ generateContractPdf(
221
+ @User() user,
222
+ @Param('id', ParseIntPipe) id: number
223
+ ) {
224
+ return this.operationsService.generateContractPdf(
225
+ Number(user?.id || 0),
226
+ id
227
+ );
228
+ }
229
+
230
+ @Get('timesheets')
231
+ listTimesheets(@User() user) {
232
+ return this.operationsService.listTimesheets(Number(user?.id || 0));
233
+ }
234
+
235
+ @Post('timesheets')
236
+ createTimesheet(@User() user, @Body() data) {
237
+ return this.operationsService.createTimesheet(Number(user?.id || 0), data);
238
+ }
239
+
240
+ @Patch('timesheets/:id')
241
+ updateTimesheet(
242
+ @User() user,
243
+ @Param('id', ParseIntPipe) id: number,
244
+ @Body() data
245
+ ) {
246
+ return this.operationsService.updateTimesheet(Number(user?.id || 0), id, data);
247
+ }
248
+
249
+ @Post('timesheets/:id/submit')
250
+ submitTimesheet(@User() user, @Param('id', ParseIntPipe) id: number) {
251
+ return this.operationsService.submitTimesheet(Number(user?.id || 0), id);
252
+ }
253
+
254
+ @Get('time-off')
255
+ listTimeOffRequests(@User() user) {
256
+ return this.operationsService.listTimeOffRequests(Number(user?.id || 0));
257
+ }
258
+
259
+ @Post('time-off')
260
+ createTimeOffRequest(@User() user, @Body() data) {
261
+ return this.operationsService.createTimeOffRequest(Number(user?.id || 0), data);
262
+ }
263
+
264
+ @Get('schedule-adjustments')
265
+ listScheduleAdjustments(@User() user) {
266
+ return this.operationsService.listScheduleAdjustments(Number(user?.id || 0));
267
+ }
268
+
269
+ @Post('schedule-adjustments')
270
+ createScheduleAdjustmentRequest(@User() user, @Body() data) {
271
+ return this.operationsService.createScheduleAdjustmentRequest(
272
+ Number(user?.id || 0),
273
+ data
274
+ );
275
+ }
276
+
277
+ @Get('approvals')
278
+ listApprovals(@User() user) {
279
+ return this.operationsService.listApprovals(Number(user?.id || 0));
280
+ }
281
+
282
+ @Post('approvals/:id/approve')
283
+ approve(@User() user, @Param('id', ParseIntPipe) id: number, @Body() data) {
284
+ return this.operationsService.approve(Number(user?.id || 0), id, data);
285
+ }
286
+
287
+ @Post('approvals/:id/reject')
288
+ reject(@User() user, @Param('id', ParseIntPipe) id: number, @Body() data) {
289
+ return this.operationsService.reject(Number(user?.id || 0), id, data);
290
+ }
291
+
292
+ @Post('integration/examples/accounts-payable')
293
+ publishAccountsPayableReference(@User() user, @Body() data) {
294
+ return this.operationsService.publishAccountsPayableReference(
295
+ Number(user?.id || 0),
296
+ data,
297
+ );
298
+ }
299
+
300
+ @Get('team')
301
+ getSupervisorTeam(@User() user) {
302
+ return this.operationsService.getTeam(Number(user?.id || 0));
303
+ }
304
+ }
@@ -1,22 +1,26 @@
1
- import { LocaleModule } from '@hed-hog/api-locale';
2
- import { PaginationModule } from '@hed-hog/api-pagination';
3
- import { PrismaModule } from '@hed-hog/api-prisma';
4
- import { IntegrationModule } from '@hed-hog/core';
5
- import { forwardRef, Module } from '@nestjs/common';
6
- import { ConfigModule } from '@nestjs/config';
7
- import { OperationsController } from './operations.controller';
8
- import { OperationsService } from './operations.service';
9
-
10
- @Module({
11
- imports: [
12
- ConfigModule.forRoot(),
13
- forwardRef(() => PaginationModule),
14
- forwardRef(() => PrismaModule),
15
- forwardRef(() => LocaleModule),
16
- forwardRef(() => IntegrationModule),
17
- ],
18
- controllers: [OperationsController],
19
- providers: [OperationsService],
20
- exports: [OperationsService],
21
- })
22
- export class OperationsModule {}
1
+ import { LocaleModule } from '@hed-hog/api-locale';
2
+ import { PaginationModule } from '@hed-hog/api-pagination';
3
+ import { PrismaModule } from '@hed-hog/api-prisma';
4
+ import { AiModule, FileModule, IntegrationModule, SettingModule } from '@hed-hog/core';
5
+ import { forwardRef, Module } from '@nestjs/common';
6
+ import { ConfigModule } from '@nestjs/config';
7
+ import { OperationsController } from './operations.controller';
8
+ import { OperationsProposalSubscriber } from './operations.proposal.subscriber';
9
+ import { OperationsService } from './operations.service';
10
+
11
+ @Module({
12
+ imports: [
13
+ ConfigModule.forRoot(),
14
+ forwardRef(() => PaginationModule),
15
+ forwardRef(() => PrismaModule),
16
+ forwardRef(() => LocaleModule),
17
+ forwardRef(() => AiModule),
18
+ forwardRef(() => FileModule),
19
+ forwardRef(() => IntegrationModule),
20
+ forwardRef(() => SettingModule),
21
+ ],
22
+ controllers: [OperationsController],
23
+ providers: [OperationsService, OperationsProposalSubscriber],
24
+ exports: [OperationsService],
25
+ })
26
+ export class OperationsModule {}
@@ -0,0 +1,121 @@
1
+ /// <reference types="jest" />
2
+
3
+ import { OperationsProposalSubscriber } from './operations.proposal.subscriber';
4
+
5
+ describe('OperationsProposalSubscriber', () => {
6
+ let integrationApi: {
7
+ subscribeMany: jest.Mock;
8
+ findLinksBySource: jest.Mock;
9
+ createLink: jest.Mock;
10
+ };
11
+ let operationsService: {
12
+ createContractFromProposalIntegration: jest.Mock;
13
+ };
14
+ let subscriber: OperationsProposalSubscriber;
15
+
16
+ beforeEach(() => {
17
+ integrationApi = {
18
+ subscribeMany: jest.fn(),
19
+ findLinksBySource: jest.fn(),
20
+ createLink: jest.fn().mockResolvedValue(undefined),
21
+ };
22
+
23
+ operationsService = {
24
+ createContractFromProposalIntegration: jest
25
+ .fn()
26
+ .mockResolvedValue({ id: 88, code: 'CTR-088' }),
27
+ };
28
+
29
+ subscriber = new OperationsProposalSubscriber(
30
+ integrationApi as any,
31
+ operationsService as any,
32
+ );
33
+ });
34
+
35
+ afterEach(() => {
36
+ jest.clearAllMocks();
37
+ });
38
+
39
+ it('registers handlers for the proposal approval and conversion flow', () => {
40
+ subscriber.onModuleInit();
41
+
42
+ const subscriptions = integrationApi.subscribeMany.mock.calls[0][0];
43
+
44
+ expect(subscriptions).toHaveLength(2);
45
+ expect(subscriptions.map((entry: { eventName: string }) => entry.eventName)).toEqual(
46
+ expect.arrayContaining([
47
+ 'contact.proposal.convert_requested',
48
+ 'contact.proposal.approved',
49
+ ]),
50
+ );
51
+ });
52
+
53
+ it('skips duplicate contract generation when the integration link already exists', async () => {
54
+ subscriber.onModuleInit();
55
+
56
+ const subscriptions = integrationApi.subscribeMany.mock.calls[0][0];
57
+ const convertRequested = subscriptions.find(
58
+ (entry: { eventName: string }) => entry.eventName === 'contact.proposal.convert_requested',
59
+ );
60
+
61
+ integrationApi.findLinksBySource.mockResolvedValue([
62
+ {
63
+ targetModule: 'operations',
64
+ targetEntityType: 'contract',
65
+ targetEntityId: '88',
66
+ },
67
+ ]);
68
+
69
+ await convertRequested.handler({
70
+ eventName: 'contact.proposal.convert_requested',
71
+ sourceModule: 'contact',
72
+ aggregateType: 'proposal',
73
+ aggregateId: '1001',
74
+ payload: {
75
+ proposalId: 1001,
76
+ },
77
+ });
78
+
79
+ expect(operationsService.createContractFromProposalIntegration).not.toHaveBeenCalled();
80
+ expect(integrationApi.createLink).not.toHaveBeenCalled();
81
+ });
82
+
83
+ it('creates the integration link after generating a contract draft', async () => {
84
+ subscriber.onModuleInit();
85
+
86
+ const subscriptions = integrationApi.subscribeMany.mock.calls[0][0];
87
+ const approved = subscriptions.find(
88
+ (entry: { eventName: string }) => entry.eventName === 'contact.proposal.approved',
89
+ );
90
+
91
+ integrationApi.findLinksBySource.mockResolvedValue([]);
92
+
93
+ await approved.handler({
94
+ eventName: 'contact.proposal.approved',
95
+ sourceModule: 'contact',
96
+ aggregateType: 'proposal',
97
+ aggregateId: '1002',
98
+ payload: {
99
+ proposalId: 1002,
100
+ },
101
+ });
102
+
103
+ expect(operationsService.createContractFromProposalIntegration).toHaveBeenCalledWith({
104
+ proposalId: 1002,
105
+ });
106
+ expect(integrationApi.createLink).toHaveBeenCalledWith(
107
+ expect.objectContaining({
108
+ sourceModule: 'contact',
109
+ sourceEntityType: 'proposal',
110
+ sourceEntityId: '1002',
111
+ targetModule: 'operations',
112
+ targetEntityType: 'contract',
113
+ targetEntityId: '88',
114
+ metadata: expect.objectContaining({
115
+ eventName: 'contact.proposal.approved',
116
+ contractCode: 'CTR-088',
117
+ }),
118
+ }),
119
+ );
120
+ });
121
+ });