@hed-hog/operations 0.0.304 → 0.0.306
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-projects.controller.d.ts +15 -0
- package/dist/controllers/operations-projects.controller.d.ts.map +1 -1
- package/dist/controllers/operations-tasks.controller.d.ts +41 -10
- package/dist/controllers/operations-tasks.controller.d.ts.map +1 -1
- package/dist/controllers/operations-tasks.controller.js +11 -0
- package/dist/controllers/operations-tasks.controller.js.map +1 -1
- package/dist/controllers/operations-timesheets.controller.d.ts +21 -0
- package/dist/controllers/operations-timesheets.controller.d.ts.map +1 -1
- package/dist/controllers/operations-timesheets.controller.js +12 -0
- package/dist/controllers/operations-timesheets.controller.js.map +1 -1
- package/dist/dto/create-task.dto.d.ts +7 -1
- package/dist/dto/create-task.dto.d.ts.map +1 -1
- package/dist/dto/create-task.dto.js +38 -5
- package/dist/dto/create-task.dto.js.map +1 -1
- package/dist/dto/list-tasks.dto.d.ts +1 -1
- package/dist/dto/list-tasks.dto.d.ts.map +1 -1
- package/dist/dto/list-tasks.dto.js +2 -2
- package/dist/dto/list-tasks.dto.js.map +1 -1
- package/dist/dto/update-collaborator-type.dto.d.ts +3 -1
- package/dist/dto/update-collaborator-type.dto.d.ts.map +1 -1
- package/dist/dto/update-collaborator-type.dto.js +2 -1
- package/dist/dto/update-collaborator-type.dto.js.map +1 -1
- package/dist/dto/update-task.dto.d.ts +7 -1
- package/dist/dto/update-task.dto.d.ts.map +1 -1
- package/dist/dto/update-task.dto.js +38 -5
- package/dist/dto/update-task.dto.js.map +1 -1
- package/dist/operations.service.d.ts +90 -12
- package/dist/operations.service.d.ts.map +1 -1
- package/dist/operations.service.js +560 -148
- package/dist/operations.service.js.map +1 -1
- package/dist/operations.service.spec.js +73 -0
- package/dist/operations.service.spec.js.map +1 -1
- package/hedhog/data/menu.yaml +26 -26
- package/hedhog/data/operations_collaborator_type.yaml +76 -76
- package/hedhog/data/route.yaml +26 -0
- package/hedhog/frontend/app/_components/async-options-combobox.tsx.ejs +5 -3
- package/hedhog/frontend/app/_components/collaborator-details-screen.tsx.ejs +44 -44
- package/hedhog/frontend/app/_components/collaborator-form-screen.tsx.ejs +168 -213
- package/hedhog/frontend/app/_components/collaborator-select-with-create.tsx.ejs +256 -256
- package/hedhog/frontend/app/_components/contract-form-screen.tsx.ejs +7 -7
- package/hedhog/frontend/app/_components/contract-template-form-screen.tsx.ejs +306 -306
- package/hedhog/frontend/app/_components/contract-template-select-with-create.tsx.ejs +247 -247
- package/hedhog/frontend/app/_components/contract-wizard-sheet.tsx.ejs +3520 -3520
- package/hedhog/frontend/app/_components/project-details-screen.tsx.ejs +1504 -52
- package/hedhog/frontend/app/_components/project-form-screen.tsx.ejs +528 -403
- package/hedhog/frontend/app/_components/section-card.tsx.ejs +25 -18
- package/hedhog/frontend/app/_components/system-user-select-with-create.tsx.ejs +609 -0
- package/hedhog/frontend/app/_components/timesheet-task-create-sheet.tsx.ejs +1 -0
- package/hedhog/frontend/app/_lib/types.ts.ejs +5 -0
- package/hedhog/frontend/app/_lib/utils/format.ts.ejs +7 -7
- package/hedhog/frontend/app/_lib/utils/forms.ts.ejs +48 -1
- package/hedhog/frontend/app/approvals/page.tsx.ejs +2 -2
- package/hedhog/frontend/app/collaborator-types/page.tsx.ejs +513 -502
- package/hedhog/frontend/app/collaborators/page.tsx.ejs +10 -7
- package/hedhog/frontend/app/contracts/page.tsx.ejs +938 -938
- package/hedhog/frontend/app/projects/[id]/edit/page.tsx.ejs +1 -1
- package/hedhog/frontend/app/projects/page.tsx.ejs +360 -133
- package/hedhog/frontend/app/schedule-adjustments/page.tsx.ejs +235 -72
- package/hedhog/frontend/app/timesheets/page.tsx.ejs +344 -134
- package/hedhog/frontend/messages/en.json +32 -4
- package/hedhog/frontend/messages/pt.json +34 -6
- package/hedhog/table/operations_collaborator.yaml +18 -18
- package/hedhog/table/operations_collaborator_equity_participation.yaml +43 -43
- package/hedhog/table/operations_collaborator_type.yaml +33 -33
- package/hedhog/table/operations_contract_document.yaml +33 -33
- package/hedhog/table/operations_project.yaml +9 -0
- package/hedhog/table/operations_task.yaml +43 -4
- package/package.json +6 -6
- package/src/controllers/operations-tasks.controller.ts +11 -0
- package/src/controllers/operations-timesheets.controller.ts +13 -0
- package/src/dto/create-collaborator-type.dto.ts +43 -43
- package/src/dto/create-collaborator.dto.ts +223 -223
- package/src/dto/create-task.dto.ts +47 -7
- package/src/dto/list-collaborator-types.dto.ts +15 -15
- package/src/dto/list-collaborators.dto.ts +30 -30
- package/src/dto/list-tasks.dto.ts +3 -3
- package/src/dto/update-collaborator-type.dto.ts +4 -3
- package/src/dto/update-collaborator.dto.ts +3 -3
- package/src/dto/update-task.dto.ts +47 -7
- package/src/operations.service.spec.ts +96 -0
- package/src/operations.service.ts +813 -135
|
@@ -1,30 +1,30 @@
|
|
|
1
|
-
import { PaginationDTO } from '@hed-hog/api-pagination';
|
|
2
|
-
import { Transform } from 'class-transformer';
|
|
3
|
-
import { IsInt, IsOptional, IsString } from 'class-validator';
|
|
4
|
-
|
|
5
|
-
export class ListCollaboratorsDto extends PaginationDTO {
|
|
6
|
-
@IsOptional()
|
|
7
|
-
@IsString()
|
|
8
|
-
status?: string;
|
|
9
|
-
|
|
10
|
-
@IsOptional()
|
|
11
|
-
@Transform(({ value }) =>
|
|
12
|
-
value === '' || value === undefined || value === null ? undefined : Number(value)
|
|
13
|
-
)
|
|
14
|
-
@IsInt()
|
|
15
|
-
collaboratorTypeId?: number;
|
|
16
|
-
|
|
17
|
-
@IsOptional()
|
|
18
|
-
@Transform(({ value }) =>
|
|
19
|
-
value === '' || value === undefined || value === null ? undefined : Number(value)
|
|
20
|
-
)
|
|
21
|
-
@IsInt()
|
|
22
|
-
departmentId?: number;
|
|
23
|
-
|
|
24
|
-
@IsOptional()
|
|
25
|
-
@Transform(({ value }) =>
|
|
26
|
-
value === '' || value === undefined || value === null ? undefined : Number(value)
|
|
27
|
-
)
|
|
28
|
-
@IsInt()
|
|
29
|
-
jobTitleId?: number;
|
|
30
|
-
}
|
|
1
|
+
import { PaginationDTO } from '@hed-hog/api-pagination';
|
|
2
|
+
import { Transform } from 'class-transformer';
|
|
3
|
+
import { IsInt, IsOptional, IsString } from 'class-validator';
|
|
4
|
+
|
|
5
|
+
export class ListCollaboratorsDto extends PaginationDTO {
|
|
6
|
+
@IsOptional()
|
|
7
|
+
@IsString()
|
|
8
|
+
status?: string;
|
|
9
|
+
|
|
10
|
+
@IsOptional()
|
|
11
|
+
@Transform(({ value }) =>
|
|
12
|
+
value === '' || value === undefined || value === null ? undefined : Number(value)
|
|
13
|
+
)
|
|
14
|
+
@IsInt()
|
|
15
|
+
collaboratorTypeId?: number;
|
|
16
|
+
|
|
17
|
+
@IsOptional()
|
|
18
|
+
@Transform(({ value }) =>
|
|
19
|
+
value === '' || value === undefined || value === null ? undefined : Number(value)
|
|
20
|
+
)
|
|
21
|
+
@IsInt()
|
|
22
|
+
departmentId?: number;
|
|
23
|
+
|
|
24
|
+
@IsOptional()
|
|
25
|
+
@Transform(({ value }) =>
|
|
26
|
+
value === '' || value === undefined || value === null ? undefined : Number(value)
|
|
27
|
+
)
|
|
28
|
+
@IsInt()
|
|
29
|
+
jobTitleId?: number;
|
|
30
|
+
}
|
|
@@ -18,8 +18,8 @@ export class ListOperationsTasksDto extends PaginationDTO {
|
|
|
18
18
|
projectAssignmentId?: number;
|
|
19
19
|
|
|
20
20
|
@IsOptional()
|
|
21
|
-
@IsIn(['
|
|
22
|
-
message: 'status must be
|
|
21
|
+
@IsIn(['todo', 'doing', 'review', 'done'], {
|
|
22
|
+
message: 'status must be todo, doing, review, or done',
|
|
23
23
|
})
|
|
24
|
-
status?: '
|
|
24
|
+
status?: 'todo' | 'doing' | 'review' | 'done';
|
|
25
25
|
}
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
-
import {
|
|
2
|
-
|
|
3
|
-
|
|
1
|
+
import { PartialType } from '@nestjs/mapped-types';
|
|
2
|
+
import { CreateCollaboratorTypeDto } from './create-collaborator-type.dto';
|
|
3
|
+
|
|
4
|
+
export class UpdateCollaboratorTypeDto extends PartialType(CreateCollaboratorTypeDto) {}
|
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
import { CreateCollaboratorDto } from './create-collaborator.dto';
|
|
2
|
-
|
|
3
|
-
export class UpdateCollaboratorDto extends CreateCollaboratorDto {}
|
|
1
|
+
import { CreateCollaboratorDto } from './create-collaborator.dto';
|
|
2
|
+
|
|
3
|
+
export class UpdateCollaboratorDto extends CreateCollaboratorDto {}
|
|
@@ -1,5 +1,12 @@
|
|
|
1
1
|
import { Transform } from 'class-transformer';
|
|
2
|
-
import {
|
|
2
|
+
import {
|
|
3
|
+
IsIn,
|
|
4
|
+
IsInt,
|
|
5
|
+
IsNumber,
|
|
6
|
+
IsOptional,
|
|
7
|
+
IsString,
|
|
8
|
+
MaxLength,
|
|
9
|
+
} from 'class-validator';
|
|
3
10
|
|
|
4
11
|
export class UpdateOperationsTaskDto {
|
|
5
12
|
@IsOptional()
|
|
@@ -16,6 +23,13 @@ export class UpdateOperationsTaskDto {
|
|
|
16
23
|
@IsInt({ message: 'projectAssignmentId must be an integer' })
|
|
17
24
|
projectAssignmentId?: number;
|
|
18
25
|
|
|
26
|
+
@IsOptional()
|
|
27
|
+
@Transform(({ value }) =>
|
|
28
|
+
value === '' || value === undefined || value === null ? undefined : Number(value)
|
|
29
|
+
)
|
|
30
|
+
@IsInt({ message: 'assigneeCollaboratorId must be an integer' })
|
|
31
|
+
assigneeCollaboratorId?: number;
|
|
32
|
+
|
|
19
33
|
@IsOptional()
|
|
20
34
|
@IsString({ message: 'name must be a string' })
|
|
21
35
|
@MaxLength(180, { message: 'name must have at most 180 characters' })
|
|
@@ -23,14 +37,40 @@ export class UpdateOperationsTaskDto {
|
|
|
23
37
|
|
|
24
38
|
@IsOptional()
|
|
25
39
|
@IsString({ message: 'description must be a string' })
|
|
26
|
-
@MaxLength(
|
|
27
|
-
message: 'description must have at most 500 characters',
|
|
28
|
-
})
|
|
40
|
+
@MaxLength(2000, { message: 'description must have at most 2000 characters' })
|
|
29
41
|
description?: string;
|
|
30
42
|
|
|
31
43
|
@IsOptional()
|
|
32
|
-
@IsIn(['
|
|
33
|
-
message: '
|
|
44
|
+
@IsIn(['low', 'medium', 'high'], {
|
|
45
|
+
message: 'priority must be low, medium, or high',
|
|
34
46
|
})
|
|
35
|
-
|
|
47
|
+
priority?: 'low' | 'medium' | 'high';
|
|
48
|
+
|
|
49
|
+
@IsOptional()
|
|
50
|
+
@IsIn(['todo', 'doing', 'review', 'done'], {
|
|
51
|
+
message: 'status must be todo, doing, review, or done',
|
|
52
|
+
})
|
|
53
|
+
status?: 'todo' | 'doing' | 'review' | 'done';
|
|
54
|
+
|
|
55
|
+
@IsOptional()
|
|
56
|
+
@IsString({ message: 'dueDate must be a string' })
|
|
57
|
+
dueDate?: string;
|
|
58
|
+
|
|
59
|
+
@IsOptional()
|
|
60
|
+
@Transform(({ value }) =>
|
|
61
|
+
value === '' || value === undefined || value === null ? undefined : Number(value)
|
|
62
|
+
)
|
|
63
|
+
@IsNumber({}, { message: 'estimateHours must be a number' })
|
|
64
|
+
estimateHours?: number;
|
|
65
|
+
|
|
66
|
+
@IsOptional()
|
|
67
|
+
@Transform(({ value }) =>
|
|
68
|
+
value === '' || value === undefined || value === null ? undefined : Number(value)
|
|
69
|
+
)
|
|
70
|
+
@IsInt({ message: 'position must be an integer' })
|
|
71
|
+
position?: number;
|
|
72
|
+
|
|
73
|
+
@IsOptional()
|
|
74
|
+
@IsString({ message: 'tags must be a string' })
|
|
75
|
+
tags?: string;
|
|
36
76
|
}
|
|
@@ -472,6 +472,102 @@ describe('OperationsService quick-entry timesheets', () => {
|
|
|
472
472
|
expect((service as any).refreshTimesheetTotal).toHaveBeenCalledWith(tx, 55);
|
|
473
473
|
});
|
|
474
474
|
|
|
475
|
+
it('updates quick entries and moves them to the correct weekly timesheet', async () => {
|
|
476
|
+
const tx = {
|
|
477
|
+
$executeRawUnsafe: jest.fn().mockResolvedValue(undefined),
|
|
478
|
+
$queryRawUnsafe: jest.fn().mockResolvedValue([]),
|
|
479
|
+
};
|
|
480
|
+
|
|
481
|
+
(service as any).prisma.$transaction.mockImplementation(
|
|
482
|
+
async (callback: (client: unknown) => unknown) => callback(tx),
|
|
483
|
+
);
|
|
484
|
+
|
|
485
|
+
jest
|
|
486
|
+
.spyOn(service as any, 'getTimesheetEntryByIdForActor')
|
|
487
|
+
.mockResolvedValueOnce({
|
|
488
|
+
id: 93,
|
|
489
|
+
timesheetId: 55,
|
|
490
|
+
collaboratorId: 7,
|
|
491
|
+
projectId: 11,
|
|
492
|
+
projectAssignmentId: 33,
|
|
493
|
+
taskId: 44,
|
|
494
|
+
status: 'draft',
|
|
495
|
+
weekStartDate: '2026-04-06',
|
|
496
|
+
weekEndDate: '2026-04-12',
|
|
497
|
+
workDate: '2026-04-09',
|
|
498
|
+
hours: 1,
|
|
499
|
+
durationMinutes: 60,
|
|
500
|
+
})
|
|
501
|
+
.mockResolvedValueOnce({
|
|
502
|
+
id: 93,
|
|
503
|
+
timesheetId: 77,
|
|
504
|
+
collaboratorId: 7,
|
|
505
|
+
projectId: 12,
|
|
506
|
+
projectAssignmentId: 34,
|
|
507
|
+
taskId: 45,
|
|
508
|
+
status: 'draft',
|
|
509
|
+
weekStartDate: '2026-04-13',
|
|
510
|
+
weekEndDate: '2026-04-19',
|
|
511
|
+
workDate: '2026-04-14',
|
|
512
|
+
hours: 2,
|
|
513
|
+
durationMinutes: 120,
|
|
514
|
+
taskName: 'Review backlog',
|
|
515
|
+
});
|
|
516
|
+
jest.spyOn(service as any, 'resolveOwnedProjectAssignment').mockResolvedValue({
|
|
517
|
+
id: 34,
|
|
518
|
+
projectId: 12,
|
|
519
|
+
projectName: 'Project Boreal',
|
|
520
|
+
projectCode: 'OPS-12',
|
|
521
|
+
roleLabel: 'Engineer',
|
|
522
|
+
});
|
|
523
|
+
jest.spyOn(service as any, 'getOwnedTaskRecord').mockResolvedValue({
|
|
524
|
+
id: 45,
|
|
525
|
+
name: 'Review backlog',
|
|
526
|
+
projectAssignmentId: 34,
|
|
527
|
+
projectId: 12,
|
|
528
|
+
projectName: 'Project Boreal',
|
|
529
|
+
projectCode: 'OPS-12',
|
|
530
|
+
});
|
|
531
|
+
jest.spyOn(service as any, 'getOrCreateTimesheetForWorkDate').mockResolvedValue(77);
|
|
532
|
+
jest.spyOn(service as any, 'refreshTimesheetTotal').mockResolvedValue(undefined);
|
|
533
|
+
jest.spyOn(service as any, 'cleanupEmptyEditableTimesheet').mockResolvedValue(undefined);
|
|
534
|
+
|
|
535
|
+
const result = await service.updateTimesheetEntry(15, 93, {
|
|
536
|
+
projectId: 12,
|
|
537
|
+
projectAssignmentId: 34,
|
|
538
|
+
taskId: 45,
|
|
539
|
+
workDate: '2026-04-14',
|
|
540
|
+
duration: 2,
|
|
541
|
+
unit: 'hours',
|
|
542
|
+
description: 'Backlog refinement',
|
|
543
|
+
} as any);
|
|
544
|
+
|
|
545
|
+
expect(result).toEqual(
|
|
546
|
+
expect.objectContaining({
|
|
547
|
+
id: 93,
|
|
548
|
+
timesheetId: 77,
|
|
549
|
+
}),
|
|
550
|
+
);
|
|
551
|
+
expect(tx.$executeRawUnsafe).toHaveBeenCalledWith(
|
|
552
|
+
expect.stringContaining('UPDATE operations_timesheet_entry'),
|
|
553
|
+
77,
|
|
554
|
+
34,
|
|
555
|
+
45,
|
|
556
|
+
'Review backlog',
|
|
557
|
+
'2026-04-14',
|
|
558
|
+
120,
|
|
559
|
+
2,
|
|
560
|
+
'Backlog refinement',
|
|
561
|
+
93,
|
|
562
|
+
);
|
|
563
|
+
expect((service as any).refreshTimesheetTotal).toHaveBeenCalledWith(tx, 55);
|
|
564
|
+
expect((service as any).refreshTimesheetTotal).toHaveBeenCalledWith(tx, 77);
|
|
565
|
+
expect((service as any).cleanupEmptyEditableTimesheet).toHaveBeenCalledWith(
|
|
566
|
+
tx,
|
|
567
|
+
55,
|
|
568
|
+
);
|
|
569
|
+
});
|
|
570
|
+
|
|
475
571
|
it('rejects deleting entries from submitted timesheets', async () => {
|
|
476
572
|
jest.spyOn(service as any, 'getTimesheetEntryByIdForActor').mockResolvedValue({
|
|
477
573
|
id: 92,
|