Skip to content

Commit 63599e2

Browse files
committed
#1330: redesigned the create wp endpoint
1 parent 8ab7e13 commit 63599e2

7 files changed

Lines changed: 125 additions & 74 deletions

File tree

src/backend/src/controllers/work-packages.controllers.ts

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ export default class WorkPackagesController {
3232
// Create a work package with the given details
3333
static async createWorkPackage(req: Request, res: Response, next: NextFunction) {
3434
try {
35-
const { projectWbsNum, name, crId, startDate, duration, blockedBy, expectedActivities, deliverables } = req.body;
35+
const { name, crId, startDate, duration, blockedBy, expectedActivities, deliverables } = req.body;
3636

3737
let { stage } = req.body;
3838
if (stage === 'NONE') {
@@ -43,7 +43,6 @@ export default class WorkPackagesController {
4343

4444
const wbsString: string = await WorkPackagesService.createWorkPackage(
4545
user,
46-
projectWbsNum,
4746
name,
4847
crId,
4948
stage,

src/backend/src/prisma/seed-data/work-packages.seed.ts

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,6 @@ import { descBulletConverter } from '../../utils/description-bullets.utils';
1818
*/
1919
export const seedWorkPackage = async (
2020
creator: User,
21-
projectWbsNumber: WbsNumber,
2221
name: string,
2322
changeRequestId: number,
2423
stage: WorkPackageStage | null,
@@ -37,7 +36,6 @@ export const seedWorkPackage = async (
3736
}> => {
3837
const workPackage1WbsString = await WorkPackagesService.createWorkPackage(
3938
creator,
40-
projectWbsNumber,
4139
name,
4240
changeRequestId,
4341
stage,

src/backend/src/prisma/seed.ts

Lines changed: 53 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -316,15 +316,60 @@ const performSeed: () => Promise<void> = async () => {
316316
joeBlow.userId
317317
);
318318

319+
/**
320+
* Make approved change requests that has project 1 and 5 as wbs element
321+
*/
322+
323+
const changeRequest2Id = await ChangeRequestsService.createStandardChangeRequest(
324+
thomasEmrax,
325+
project1WbsNumber.carNumber,
326+
project1WbsNumber.projectNumber,
327+
project1WbsNumber.workPackageNumber,
328+
CR_Type.DEFINITION_CHANGE,
329+
'Remove the uncessary rule',
330+
[{ type: Scope_CR_Why_Type.DESIGN, explain: 'The rule has changed' }]
331+
);
332+
333+
const proposedSolution2Id = await ChangeRequestsService.addProposedSolution(
334+
thomasEmrax,
335+
changeRequest2Id,
336+
50,
337+
'Remove the rule',
338+
1,
339+
'n/a'
340+
);
341+
342+
await ChangeRequestsService.reviewChangeRequest(joeShmoe, changeRequest2Id, 'LGTM', true, proposedSolution2Id);
343+
344+
const changeRequest3Id = await ChangeRequestsService.createStandardChangeRequest(
345+
thomasEmrax,
346+
project5WbsNumber.carNumber,
347+
project5WbsNumber.projectNumber,
348+
project5WbsNumber.workPackageNumber,
349+
CR_Type.ISSUE,
350+
'Change the wire material',
351+
[{ type: Scope_CR_Why_Type.MAINTENANCE, explain: 'It would be better to maintain' }]
352+
);
353+
354+
const proposedSolution3Id = await ChangeRequestsService.addProposedSolution(
355+
thomasEmrax,
356+
changeRequest3Id,
357+
50,
358+
'Change to better wire material',
359+
1,
360+
'n/a'
361+
);
362+
363+
await ChangeRequestsService.reviewChangeRequest(joeShmoe, changeRequest3Id, 'LGTM', true, proposedSolution3Id);
364+
319365
/**
320366
* Work Packages
321367
*/
322368
/** Work Package 1 */
323369
const { workPackageWbsNumber: workPackage1WbsNumber, workPackage: workPackage1 } = await seedWorkPackage(
324370
joeShmoe,
325-
project1WbsNumber,
326371
'Bodywork Concept of Design',
327-
changeRequest1Id,
372+
changeRequest2Id,
328373
WorkPackageStage.Design,
329374
'01/01/2023',
330375
3,
@@ -363,9 +408,8 @@ const performSeed: () => Promise<void> = async () => {
363408
/** Work Package 2 */
364409
const { workPackageWbsNumber: workPackage2WbsNumber, workPackage: workPackage2 } = await seedWorkPackage(
365410
thomasEmrax,
366-
project1WbsNumber,
367411
'Adhesive Shear Strength Test',
368-
changeRequest1Id,
412+
changeRequest2Id,
369413
WorkPackageStage.Research,
370414
'01/22/2023',
371415
5,
@@ -387,9 +431,8 @@ const performSeed: () => Promise<void> = async () => {
387431
/** Work Package 3 */
388432
const workPackage3WbsString = await WorkPackagesService.createWorkPackage(
389433
thomasEmrax,
390-
project5WbsNumber,
391434
'Manufacture Wiring Harness',
392-
changeRequest1Id,
435+
changeRequest3Id,
393436
WorkPackageStage.Manufacturing,
394437
'02/01/2023',
395438
3,
@@ -416,7 +459,7 @@ const performSeed: () => Promise<void> = async () => {
416459
true
417460
);
418461

419-
const changeRequest2Id = await ChangeRequestsService.createStandardChangeRequest(
462+
const changeRequest4Id = await ChangeRequestsService.createStandardChangeRequest(
420463
thomasEmrax,
421464
project2WbsNumber.carNumber,
422465
project2WbsNumber.projectNumber,
@@ -428,16 +471,16 @@ const performSeed: () => Promise<void> = async () => {
428471
{ type: Scope_CR_Why_Type.ESTIMATION, explain: 'I estimate that it would be really pretty' }
429472
]
430473
);
431-
await ChangeRequestsService.addProposedSolution(thomasEmrax, changeRequest2Id, 50, 'Buy hot pink paint', 1, 'n/a');
474+
await ChangeRequestsService.addProposedSolution(thomasEmrax, changeRequest4Id, 50, 'Buy hot pink paint', 1, 'n/a');
432475
await ChangeRequestsService.addProposedSolution(
433476
thomasEmrax,
434-
changeRequest2Id,
477+
changeRequest4Id,
435478
40,
436479
'Buy slightly cheaper but lower quality hot pink paint',
437480
1,
438481
'n/a'
439482
);
440-
await ChangeRequestsService.reviewChangeRequest(joeShmoe, changeRequest2Id, 'What the hell Thomas', false, null);
483+
await ChangeRequestsService.reviewChangeRequest(joeShmoe, changeRequest4Id, 'What the hell Thomas', false, null);
441484

442485
await ChangeRequestsService.createActivationChangeRequest(
443486
thomasEmrax,

src/backend/src/routes/work-packages.routes.ts

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -11,9 +11,6 @@ workPackagesRouter.post(
1111
'/create',
1212
intMinZero(body('crId')),
1313
nonEmptyString(body('name')),
14-
intMinZero(body('projectWbsNum.carNumber')),
15-
intMinZero(body('projectWbsNum.projectNumber')),
16-
intMinZero(body('projectWbsNum.workPackageNumber')),
1714
isWorkPackageStageOrNone(body('stage')),
1815
isDate(body('startDate')),
1916
intMinZero(body('duration')),

src/backend/src/services/work-packages.services.ts

Lines changed: 25 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -111,7 +111,6 @@ export default class WorkPackagesService {
111111
/**
112112
* Creates a Work_Package in the database
113113
* @param user the user creating the work package
114-
* @param projectWbsNum the WBS number of the attached project
115114
* @param name the name of the new work package
116115
* @param crId the id of the change request creating this work package
117116
* @param stage the stage of the work package
@@ -125,7 +124,6 @@ export default class WorkPackagesService {
125124
*/
126125
static async createWorkPackage(
127126
user: User,
128-
projectWbsNum: WbsNumber,
129127
name: string,
130128
crId: number,
131129
stage: WorkPackageStage | null,
@@ -137,30 +135,11 @@ export default class WorkPackagesService {
137135
): Promise<string> {
138136
if (isGuest(user.role)) throw new AccessDeniedGuestException('create work packages');
139137

140-
await validateChangeRequestAccepted(crId);
141-
142-
// get the corresponding project so we can find the next wbs number
143-
// and what number work package this should be
144-
const { carNumber, projectNumber, workPackageNumber } = projectWbsNum;
145-
146-
if (workPackageNumber !== 0) {
147-
throw new HttpException(
148-
400,
149-
`Given WBS Number ${carNumber}.${projectNumber}.${workPackageNumber} is not for a project.`
150-
);
151-
}
152-
153-
if (blockedBy.find((dep: WbsNumber) => equalsWbsNumber(dep, projectWbsNum))) {
154-
throw new HttpException(400, 'A Work Package cannot have its own project as a blocker');
155-
}
138+
const changeRequest = await validateChangeRequestAccepted(crId);
156139

157140
const wbsElem = await prisma.wBS_Element.findUnique({
158141
where: {
159-
wbsNumber: {
160-
carNumber,
161-
projectNumber,
162-
workPackageNumber
163-
}
142+
wbsElementId: changeRequest.wbsElementId
164143
},
165144
include: {
166145
project: {
@@ -171,10 +150,32 @@ export default class WorkPackagesService {
171150
}
172151
});
173152

174-
if (!wbsElem) throw new NotFoundException('WBS Element', `${carNumber}.${projectNumber}.${workPackageNumber}`);
153+
if (!wbsElem) throw new NotFoundException('WBS Element', changeRequest.wbsElementId);
154+
155+
// get the corresponding project so we can find the next wbs number
156+
// and what number work package this should be
157+
const { carNumber, projectNumber, workPackageNumber } = wbsElem;
158+
159+
const projectWbsNum: WbsNumber = {
160+
carNumber,
161+
projectNumber,
162+
workPackageNumber
163+
};
164+
175165
if (wbsElem.dateDeleted)
176166
throw new DeletedException('WBS Element', wbsPipe({ carNumber, projectNumber, workPackageNumber }));
177167

168+
if (workPackageNumber !== 0) {
169+
throw new HttpException(
170+
400,
171+
`Given WBS Number ${carNumber}.${projectNumber}.${workPackageNumber} is not for a project.`
172+
);
173+
}
174+
175+
if (blockedBy.find((dep: WbsNumber) => equalsWbsNumber(dep, projectWbsNum))) {
176+
throw new HttpException(400, 'A Work Package cannot have its own project as a blocker');
177+
}
178+
178179
const { project } = wbsElem;
179180

180181
if (!project) throw new NotFoundException('Project', `${carNumber}.${projectNumber}.${workPackageNumber}`);

src/backend/tests/test-data/wbs-element.test-data.ts

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,3 +13,17 @@ export const prismaWbsElement1: PrismaWbsElement = {
1313
projectLeadId: 4,
1414
projectManagerId: 5
1515
};
16+
17+
export const prismaWbsElement2: PrismaWbsElement = {
18+
wbsElementId: 1,
19+
status: PrismaWBSElementStatus.ACTIVE,
20+
carNumber: 1,
21+
projectNumber: 2,
22+
workPackageNumber: 2,
23+
dateCreated: new Date(),
24+
dateDeleted: null,
25+
name: 'car',
26+
deletedByUserId: null,
27+
projectLeadId: 4,
28+
projectManagerId: 5
29+
};

src/backend/tests/work-packages.test.ts

Lines changed: 32 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import prisma from '../src/prisma/prisma';
22
import { batman, wonderwoman } from './test-data/users.test-data';
3-
import { prismaWbsElement1 } from './test-data/wbs-element.test-data';
3+
import { prismaWbsElement1, prismaWbsElement2 } from './test-data/wbs-element.test-data';
44
import { prismaChangeRequest1 } from './test-data/change-requests.test-data';
55
import { calculateWorkPackageProgress } from '../src/utils/work-packages.utils';
66
import {
@@ -41,18 +41,17 @@ describe('Work Packages', () => {
4141
const expectedActivities = ['ayo'];
4242
const deliverables = ['ajdhjakfjafja'];
4343
const stage = WorkPackageStage.Design;
44-
const createWorkPackageArgs: [
45-
User,
46-
WbsNumber,
47-
string,
48-
number,
49-
WorkPackageStage,
50-
string,
51-
number,
52-
WbsNumber[],
53-
string[],
54-
string[]
55-
] = [batman, projectWbsNum, name, crId, stage, startDate, duration, blockedBy, expectedActivities, deliverables];
44+
const createWorkPackageArgs: [User, string, number, WorkPackageStage, string, number, WbsNumber[], string[], string[]] = [
45+
batman,
46+
name,
47+
crId,
48+
stage,
49+
startDate,
50+
duration,
51+
blockedBy,
52+
expectedActivities,
53+
deliverables
54+
];
5655
/*********************************************************/
5756

5857
afterEach(() => {
@@ -73,16 +72,12 @@ describe('Work Packages', () => {
7372

7473
describe('createWorkPackage', () => {
7574
test('createWorkPackage fails if WBS number does not represent a project', async () => {
75+
vi.spyOn(prisma.wBS_Element, 'findUnique').mockResolvedValue(prismaWbsElement2);
7676
vi.spyOn(prisma.change_Request, 'findUnique').mockResolvedValue(prismaChangeRequest1);
7777

7878
const callCreateWP = async () => {
7979
return await WorkPackageService.createWorkPackage(
8080
batman,
81-
{
82-
carNumber: 1,
83-
projectNumber: 2,
84-
workPackageNumber: 2
85-
},
8681
name,
8782
crId,
8883
stage,
@@ -115,12 +110,12 @@ describe('Work Packages', () => {
115110
});
116111

117112
test('createWorkPackage fails if user does not have access', async () => {
113+
vi.spyOn(prisma.wBS_Element, 'findUnique').mockResolvedValue(prismaWbsElement2);
118114
vi.spyOn(prisma.change_Request, 'findUnique').mockResolvedValue(prismaChangeRequest1);
119115

120116
const callCreateWP = async () => {
121117
return await WorkPackageService.createWorkPackage(
122118
wonderwoman,
123-
projectWbsNum,
124119
name,
125120
crId,
126121
stage,
@@ -156,7 +151,9 @@ describe('Work Packages', () => {
156151
return await WorkPackageService.createWorkPackage.apply(null, createWorkPackageArgs);
157152
};
158153

159-
await expect(callCreateWP).rejects.toThrowError(new NotFoundException('WBS Element', '1.2.0'));
154+
await expect(callCreateWP).rejects.toThrowError(
155+
new NotFoundException('WBS Element', prismaChangeRequest1.wbsElementId.toString())
156+
);
160157
});
161158

162159
test('createWorkPackage fails if the associated wbsElem does not have a project object', async () => {
@@ -167,22 +164,24 @@ describe('Work Packages', () => {
167164
return await WorkPackageService.createWorkPackage.apply(null, createWorkPackageArgs);
168165
};
169166

170-
await expect(callCreateWP).rejects.toThrowError(new NotFoundException('WBS Element', '1.2.0'));
167+
await expect(callCreateWP).rejects.toThrowError(
168+
new NotFoundException('WBS Element', prismaChangeRequest1.wbsElementId.toString())
169+
);
171170
});
172171

173172
test("fails if the blocked by include the work package's own project", async () => {
174-
const argsToTest: [
175-
User,
176-
WbsNumber,
177-
string,
178-
number,
179-
WorkPackageStage,
180-
string,
181-
number,
182-
WbsNumber[],
183-
string[],
184-
string[]
185-
] = [batman, projectWbsNum, name, crId, stage, startDate, duration, [projectWbsNum], expectedActivities, deliverables];
173+
vi.spyOn(prisma.wBS_Element, 'findUnique').mockResolvedValueOnce(prismaWbsElement1);
174+
const argsToTest: [User, string, number, WorkPackageStage, string, number, WbsNumber[], string[], string[]] = [
175+
batman,
176+
name,
177+
crId,
178+
stage,
179+
startDate,
180+
duration,
181+
[projectWbsNum],
182+
expectedActivities,
183+
deliverables
184+
];
186185

187186
const callCreateWP = async () => {
188187
return await WorkPackageService.createWorkPackage.apply(null, argsToTest);

0 commit comments

Comments
 (0)