Skip to content

Commit dd46fcd

Browse files
authored
Add option to disable project (#432)
1 parent 6b542fb commit dd46fcd

31 files changed

+167
-33
lines changed
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
import { MigrationInterface, QueryRunner } from "typeorm";
2+
3+
export class ProjectActive1716653153304 implements MigrationInterface {
4+
name = 'ProjectActive1716653153304'
5+
6+
public async up(queryRunner: QueryRunner): Promise<void> {
7+
await queryRunner.query(`ALTER TABLE "project" ADD "active" boolean NOT NULL DEFAULT true`);
8+
}
9+
10+
public async down(queryRunner: QueryRunner): Promise<void> {
11+
await queryRunner.query(`ALTER TABLE "project" DROP COLUMN "active"`);
12+
}
13+
14+
}

src/Application/Project/Command/CreateProjectCommand.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ export class CreateProjectCommand implements ICommand {
55
constructor(
66
public readonly name: string,
77
public readonly invoiceUnit: InvoiceUnits,
8+
public readonly active: boolean,
89
public readonly customerId: string
910
) {}
1011
}

src/Application/Project/Command/CreateProjectCommandHandler.spec.ts

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ describe('CreateProjectCommandHandler', () => {
1818
const command = new CreateProjectCommand(
1919
'Project',
2020
InvoiceUnits.DAY,
21+
true,
2122
'b5e8dc18-ca67-4323-bdae-654afe09499f'
2223
);
2324

@@ -83,7 +84,9 @@ describe('CreateProjectCommandHandler', () => {
8384
).thenResolve(instance(customer));
8485
when(
8586
projectRepository.save(
86-
deepEqual(new Project('Project', InvoiceUnits.DAY, instance(customer)))
87+
deepEqual(
88+
new Project('Project', InvoiceUnits.DAY, true, instance(customer))
89+
)
8790
)
8891
).thenResolve(instance(createdProject));
8992

@@ -97,7 +100,9 @@ describe('CreateProjectCommandHandler', () => {
97100
verify(isProjectAlreadyExist.isSatisfiedBy('Project')).once();
98101
verify(
99102
projectRepository.save(
100-
deepEqual(new Project('Project', InvoiceUnits.DAY, instance(customer)))
103+
deepEqual(
104+
new Project('Project', InvoiceUnits.DAY, true, instance(customer))
105+
)
101106
)
102107
).once();
103108
verify(createdProject.getId()).once();

src/Application/Project/Command/CreateProjectCommandHandler.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ export class CreateProjectCommandHandler {
1919
) {}
2020

2121
public async execute(command: CreateProjectCommand): Promise<string> {
22-
const { name, customerId, invoiceUnit } = command;
22+
const { name, customerId, active, invoiceUnit } = command;
2323

2424
const customer = await this.customerRepository.findOneById(customerId);
2525
if (!customer) {
@@ -31,7 +31,7 @@ export class CreateProjectCommandHandler {
3131
}
3232

3333
const project = await this.projectRepository.save(
34-
new Project(name, invoiceUnit, customer)
34+
new Project(name, invoiceUnit, active, customer)
3535
);
3636

3737
return project.getId();

src/Application/Project/Command/UpdateProjectCommand.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ export class UpdateProjectCommand implements ICommand {
66
public readonly id: string,
77
public readonly name: string,
88
public readonly invoiceUnit: InvoiceUnits,
9+
public readonly active: boolean,
910
public readonly customerId: string
1011
) {}
1112
}

src/Application/Project/Command/UpdateProjectCommandHandler.spec.ts

Lines changed: 22 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ describe('UpdateProjectCommandHandler', () => {
2222
'afda00b1-bf49-4102-9bc2-bce17f3acd48',
2323
'Project',
2424
InvoiceUnits.HOUR,
25+
true,
2526
'd4aa560e-d2f7-422e-ae8d-6af5d0455eeb'
2627
);
2728

@@ -64,10 +65,20 @@ describe('UpdateProjectCommandHandler', () => {
6465
).once();
6566
verify(projectRepository.save(instance(updatedProject))).once();
6667
verify(
67-
updatedProject.update(instance(customer), InvoiceUnits.HOUR, 'Project')
68+
updatedProject.update(
69+
instance(customer),
70+
InvoiceUnits.HOUR,
71+
'Project',
72+
true
73+
)
6874
).once();
6975
verify(
70-
updatedProject.update(instance(customer), InvoiceUnits.HOUR, 'Project')
76+
updatedProject.update(
77+
instance(customer),
78+
InvoiceUnits.HOUR,
79+
'Project',
80+
true
81+
)
7182
).calledBefore(projectRepository.save(instance(updatedProject)));
7283
verify(updatedProject.getName()).once();
7384
});
@@ -88,7 +99,9 @@ describe('UpdateProjectCommandHandler', () => {
8899
projectRepository.findOneById('afda00b1-bf49-4102-9bc2-bce17f3acd48')
89100
).once();
90101
verify(projectRepository.save(anything())).never();
91-
verify(updatedProject.update(anything(), anything(), anything())).never();
102+
verify(
103+
updatedProject.update(anything(), anything(), anything(), anything())
104+
).never();
92105
verify(updatedProject.getName()).never();
93106
}
94107
});
@@ -114,7 +127,9 @@ describe('UpdateProjectCommandHandler', () => {
114127
customerRepository.findOneById('d4aa560e-d2f7-422e-ae8d-6af5d0455eeb')
115128
).once();
116129
verify(projectRepository.save(anything())).never();
117-
verify(updatedProject.update(anything(), anything(), anything())).never();
130+
verify(
131+
updatedProject.update(anything(), anything(), anything(), anything())
132+
).never();
118133
verify(updatedProject.getName()).never();
119134
}
120135
});
@@ -141,7 +156,9 @@ describe('UpdateProjectCommandHandler', () => {
141156
customerRepository.findOneById('d4aa560e-d2f7-422e-ae8d-6af5d0455eeb')
142157
).once();
143158
verify(projectRepository.save(anything())).never();
144-
verify(updatedProject.update(anything(), anything(), anything())).never();
159+
verify(
160+
updatedProject.update(anything(), anything(), anything(), anything())
161+
).never();
145162
verify(updatedProject.getName()).once();
146163
}
147164
});

src/Application/Project/Command/UpdateProjectCommandHandler.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ export class UpdateProjectCommandHandler {
1919
) {}
2020

2121
public async execute(command: UpdateProjectCommand): Promise<void> {
22-
const { id, name, customerId, invoiceUnit } = command;
22+
const { id, name, customerId, invoiceUnit, active } = command;
2323

2424
const project = await this.projectRepository.findOneById(id);
2525
if (!project) {
@@ -38,7 +38,7 @@ export class UpdateProjectCommandHandler {
3838
throw new ProjectAlreadyExistException();
3939
}
4040

41-
project.update(customer, invoiceUnit, name);
41+
project.update(customer, invoiceUnit, name, active);
4242
await this.projectRepository.save(project);
4343
}
4444
}

src/Application/Project/Query/GetProjectByIdQueryHandler.spec.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ describe('GetProjectByIdQueryHandler', () => {
2424

2525
when(project.getId()).thenReturn('eb9e1d9b-dce2-48a9-b64f-f0872f3157d2');
2626
when(project.getName()).thenReturn('Project');
27+
when(project.isActive()).thenReturn(true);
2728
when(project.getInvoiceUnit()).thenReturn(InvoiceUnits.DAY);
2829
when(project.getCustomer()).thenReturn(instance(customer));
2930
when(
@@ -34,6 +35,7 @@ describe('GetProjectByIdQueryHandler', () => {
3435
new ProjectView(
3536
'eb9e1d9b-dce2-48a9-b64f-f0872f3157d2',
3637
'Project',
38+
true,
3739
InvoiceUnits.DAY,
3840
new CustomerView('aeb50974-0dcd-4ef4-af43-d656250e43bc', 'Customer')
3941
)
@@ -44,6 +46,7 @@ describe('GetProjectByIdQueryHandler', () => {
4446
).once();
4547
verify(project.getId()).once();
4648
verify(project.getName()).once();
49+
verify(project.isActive()).once();
4750
verify(project.getInvoiceUnit()).once();
4851
verify(project.getCustomer()).once();
4952
verify(customer.getId()).once();

src/Application/Project/Query/GetProjectByIdQueryHandler.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ export class GetProjectByIdQueryHandler {
2424
return new ProjectView(
2525
project.getId(),
2626
project.getName(),
27+
project.isActive(),
2728
project.getInvoiceUnit(),
2829
new CustomerView(customer.getId(), customer.getName())
2930
);

src/Application/Project/Query/GetProjectsQuery.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ import { IQuery } from 'src/Application/IQuery';
33
export class GetProjectsQuery implements IQuery {
44
constructor(
55
public readonly page: number | null,
6+
public readonly activeOnly = true,
67
public readonly customerId?: string
78
) {}
89
}

src/Application/Project/Query/GetProjectsQueryHandler.spec.ts

Lines changed: 18 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -23,22 +23,25 @@ describe('GetProjectsQueryHandler', () => {
2323
const project1 = mock(Project);
2424
when(project1.getId()).thenReturn('eb9e1d9b-dce2-48a9-b64f-f0872f3157d2');
2525
when(project1.getName()).thenReturn('z51');
26+
when(project1.isActive()).thenReturn(false);
2627
when(project1.getInvoiceUnit()).thenReturn(InvoiceUnits.DAY);
2728
when(project1.getCustomer()).thenReturn(instance(customer1));
2829

2930
const project2 = mock(Project);
3031
when(project2.getId()).thenReturn('d54f15d6-1a1d-47e8-8672-9f46018f9960');
3132
when(project2.getName()).thenReturn('BO cruiser');
33+
when(project2.isActive()).thenReturn(true);
3234
when(project2.getInvoiceUnit()).thenReturn(InvoiceUnits.HOUR);
3335
when(project2.getCustomer()).thenReturn(instance(customer1));
3436

3537
const project3 = mock(Project);
3638
when(project3.getId()).thenReturn('992eb372-cc02-4ffe-86e0-7b955b7f1a6e');
3739
when(project3.getInvoiceUnit()).thenReturn(InvoiceUnits.HOUR);
40+
when(project3.isActive()).thenReturn(true);
3841
when(project3.getName()).thenReturn('Vimeet');
3942
when(project3.getCustomer()).thenReturn(instance(customer2));
4043

41-
when(projectRepository.findProjects(1, undefined)).thenResolve([
44+
when(projectRepository.findProjects(1, false, undefined)).thenResolve([
4245
[instance(project3), instance(project2), instance(project1)],
4346
3
4447
]);
@@ -52,12 +55,14 @@ describe('GetProjectsQueryHandler', () => {
5255
new ProjectView(
5356
'992eb372-cc02-4ffe-86e0-7b955b7f1a6e',
5457
'Vimeet',
58+
true,
5559
InvoiceUnits.HOUR,
5660
new CustomerView('b9a9b094-5bb2-4d0b-b01e-231b6cb50039', 'Proximum')
5761
),
5862
new ProjectView(
5963
'd54f15d6-1a1d-47e8-8672-9f46018f9960',
6064
'BO cruiser',
65+
true,
6166
InvoiceUnits.HOUR,
6267
new CustomerView(
6368
'58958f69-d104-471b-b780-bbb0ec6c52da',
@@ -67,6 +72,7 @@ describe('GetProjectsQueryHandler', () => {
6772
new ProjectView(
6873
'eb9e1d9b-dce2-48a9-b64f-f0872f3157d2',
6974
'z51',
75+
false,
7076
InvoiceUnits.DAY,
7177
new CustomerView(
7278
'58958f69-d104-471b-b780-bbb0ec6c52da',
@@ -77,10 +83,10 @@ describe('GetProjectsQueryHandler', () => {
7783
3
7884
);
7985

80-
expect(await queryHandler.execute(new GetProjectsQuery(1))).toMatchObject(
81-
expectedResult
82-
);
83-
verify(projectRepository.findProjects(1, undefined)).once();
86+
expect(
87+
await queryHandler.execute(new GetProjectsQuery(1, false))
88+
).toMatchObject(expectedResult);
89+
verify(projectRepository.findProjects(1, false, undefined)).once();
8490
});
8591

8692
it('testGetAllProjects', async () => {
@@ -93,16 +99,18 @@ describe('GetProjectsQueryHandler', () => {
9399
const project1 = mock(Project);
94100
when(project1.getId()).thenReturn('eb9e1d9b-dce2-48a9-b64f-f0872f3157d2');
95101
when(project1.getName()).thenReturn('z51');
102+
when(project1.isActive()).thenReturn(true);
96103
when(project1.getInvoiceUnit()).thenReturn(InvoiceUnits.DAY);
97104
when(project1.getCustomer()).thenReturn(instance(customer1));
98105

99106
const project2 = mock(Project);
100107
when(project2.getId()).thenReturn('d54f15d6-1a1d-47e8-8672-9f46018f9960');
101108
when(project2.getName()).thenReturn('BO cruiser');
109+
when(project2.isActive()).thenReturn(true);
102110
when(project2.getInvoiceUnit()).thenReturn(InvoiceUnits.HOUR);
103111
when(project2.getCustomer()).thenReturn(instance(customer1));
104112

105-
when(projectRepository.findProjects(null, undefined)).thenResolve([
113+
when(projectRepository.findProjects(null, true, undefined)).thenResolve([
106114
[instance(project2), instance(project1)],
107115
2
108116
]);
@@ -116,6 +124,7 @@ describe('GetProjectsQueryHandler', () => {
116124
new ProjectView(
117125
'd54f15d6-1a1d-47e8-8672-9f46018f9960',
118126
'BO cruiser',
127+
true,
119128
InvoiceUnits.HOUR,
120129
new CustomerView(
121130
'58958f69-d104-471b-b780-bbb0ec6c52da',
@@ -125,6 +134,7 @@ describe('GetProjectsQueryHandler', () => {
125134
new ProjectView(
126135
'eb9e1d9b-dce2-48a9-b64f-f0872f3157d2',
127136
'z51',
137+
true,
128138
InvoiceUnits.DAY,
129139
new CustomerView(
130140
'58958f69-d104-471b-b780-bbb0ec6c52da',
@@ -136,8 +146,8 @@ describe('GetProjectsQueryHandler', () => {
136146
);
137147

138148
expect(
139-
await queryHandler.execute(new GetProjectsQuery(null))
149+
await queryHandler.execute(new GetProjectsQuery(null, true))
140150
).toMatchObject(expectedResult);
141-
verify(projectRepository.findProjects(null, undefined)).once();
151+
verify(projectRepository.findProjects(null, true, undefined)).once();
142152
});
143153
});

src/Application/Project/Query/GetProjectsQueryHandler.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,12 +16,13 @@ export class GetProjectsQueryHandler {
1616
public async execute(
1717
query: GetProjectsQuery
1818
): Promise<Pagination<ProjectView>> {
19-
const { customerId, page } = query;
19+
const { customerId, activeOnly, page } = query;
2020

2121
const projectViews: ProjectView[] = [];
2222

2323
const [projects, total] = await this.projectRepository.findProjects(
2424
page,
25+
activeOnly,
2526
customerId
2627
);
2728

@@ -32,6 +33,7 @@ export class GetProjectsQueryHandler {
3233
new ProjectView(
3334
project.getId(),
3435
project.getName(),
36+
project.isActive(),
3537
project.getInvoiceUnit(),
3638
new CustomerView(customer.getId(), customer.getName())
3739
)

src/Application/Project/View/ProjectView.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ export class ProjectView {
44
constructor(
55
public readonly id: string,
66
public readonly name: string,
7+
public readonly active?: boolean,
78
public readonly invoiceUnit?: string,
89
public readonly customer?: CustomerView
910
) {}

src/Domain/Project/Project.entity.spec.ts

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,13 +10,15 @@ describe('Project.entity', () => {
1010
const project = new Project(
1111
'Project name',
1212
InvoiceUnits.DAY,
13+
true,
1314
instance(customer)
1415
);
1516

1617
expect(project.getId()).toBe(undefined);
1718
expect(project.getFullName()).toBe('[Radio France] Project name');
1819
expect(project.getName()).toBe('Project name');
1920
expect(project.getInvoiceUnit()).toBe(InvoiceUnits.DAY);
21+
expect(project.isActive()).toBe(true);
2022
expect(project.getCustomer()).toBe(instance(customer));
2123
});
2224

@@ -29,13 +31,15 @@ describe('Project.entity', () => {
2931
const project = new Project(
3032
'Project name',
3133
InvoiceUnits.DAY,
34+
false,
3235
instance(customer)
3336
);
34-
project.update(instance(customer2), InvoiceUnits.HOUR, 'project');
37+
project.update(instance(customer2), InvoiceUnits.HOUR, 'project', true);
3538

3639
expect(project.getId()).toBe(undefined);
3740
expect(project.getFullName()).toBe('[RF] project');
3841
expect(project.getName()).toBe('project');
42+
expect(project.isActive()).toBe(true);
3943
expect(project.getInvoiceUnit()).toBe(InvoiceUnits.HOUR);
4044
expect(project.getCustomer()).toBe(instance(customer2));
4145
});

0 commit comments

Comments
 (0)