Skip to content

Commit b1e9737

Browse files
authored
Merge pull request #1697 from Northeastern-Electric-Racing/1523-bom-delete-manufacturer-endpoint
#1523 : Delete manufacturer endpoint
2 parents da6d5b9 + 4cb9ef3 commit b1e9737

8 files changed

Lines changed: 96 additions & 3 deletions

File tree

src/backend/src/controllers/projects.controllers.ts

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -193,6 +193,17 @@ export default class ProjectsController {
193193
}
194194
}
195195

196+
static async deleteManufacturer(req: Request, res: Response, next: NextFunction) {
197+
try {
198+
const user: User = await getCurrentUser(res);
199+
const { manufacturerName } = req.params;
200+
const deletedManufacturer: Manufacturer = await ProjectsService.deleteManufacturer(user, manufacturerName);
201+
res.status(200).json(deletedManufacturer);
202+
} catch (error: unknown) {
203+
next(error);
204+
}
205+
}
206+
196207
static async getAllManufacturers(req: Request, res: Response, next: NextFunction) {
197208
try {
198209
const user = await getCurrentUser(res);

src/backend/src/prisma/migrations/20231119054311_add_bom/migration.sql renamed to src/backend/src/prisma/migrations/20231119081759_add_bom/migration.sql

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,7 @@ CREATE TABLE "Manufacturer" (
6262
"name" TEXT NOT NULL,
6363
"dateCreated" TIMESTAMP(3) NOT NULL,
6464
"creatorId" INTEGER NOT NULL,
65+
"dateDeleted" TIMESTAMP(3),
6566

6667
CONSTRAINT "Manufacturer_pkey" PRIMARY KEY ("name")
6768
);

src/backend/src/prisma/schema.prisma

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -528,5 +528,6 @@ model Manufacturer {
528528
name String @id
529529
dateCreated DateTime
530530
creatorId Int
531+
dateDeleted DateTime?
531532
materials Material[]
532533
}

src/backend/src/routes/projects.routes.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,7 @@ projectRouter.post(
5656
validateInputs,
5757
ProjectsController.createManufacturer
5858
);
59+
projectRouter.delete('/bom/manufacturer/:manufacturerName/delete', ProjectsController.deleteManufacturer);
5960
projectRouter.get('/bom/manufacturer', ProjectsController.getAllManufacturers);
6061
projectRouter.post('/bom/material-type/create', nonEmptyString(body('name')), ProjectsController.createMaterialType);
6162
projectRouter.post(

src/backend/src/services/projects.services.ts

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -798,6 +798,42 @@ export default class ProjectsService {
798798
return newManufacturer;
799799
}
800800

801+
/**
802+
* Deletes a manufacturer
803+
* @param user the user who's deleting the manufacturer
804+
* @param name the name of the manufacturer
805+
* @throws if the user is not at least a head, or if the provided name isn't a manufacturer, or if the manufacturer has already been soft-deleted
806+
* @returns the deleted manufacturer
807+
*/
808+
static async deleteManufacturer(user: User, name: string) {
809+
if (!isHead(user.role)) {
810+
throw new AccessDeniedException('Only heads and above can delete a manufacturer');
811+
}
812+
813+
const manufacturer = await prisma.manufacturer.findFirst({
814+
where: {
815+
name
816+
}
817+
});
818+
819+
if (!manufacturer) {
820+
throw new NotFoundException('Manufacturer', name);
821+
}
822+
823+
if (manufacturer.dateDeleted) throw new DeletedException('Manufacturer', manufacturer.name);
824+
825+
const dateDeleted: Date = new Date();
826+
const deletedManufacturer = await prisma.manufacturer.update({
827+
where: {
828+
name: manufacturer.name
829+
},
830+
data: {
831+
dateDeleted
832+
}
833+
});
834+
835+
return deletedManufacturer;
836+
}
801837
/**
802838
* Get all the manufacturers in the database.
803839
* @returns all the manufacturers

src/backend/src/transformers/manufacturer.transformer.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ export const manufacturerTransformer = (
1212
return {
1313
name: manufacturer.name,
1414
dateCreated: manufacturer.dateCreated,
15-
creatorId: manufacturer.creatorId
15+
creatorId: manufacturer.creatorId,
16+
dateDeleted: manufacturer.dateDeleted
1617
};
1718
};

src/backend/tests/projects.test.ts

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -642,6 +642,46 @@ describe('Projects', () => {
642642
expect(manufacturer.creatorId).toBe(prismaManufacturer1.creatorId);
643643
});
644644

645+
test('deleteManufacturer works', async () => {
646+
vi.spyOn(prisma.manufacturer, 'findFirst').mockResolvedValue(prismaManufacturer1);
647+
vi.spyOn(prisma.manufacturer, 'update').mockResolvedValue(prismaManufacturer1);
648+
649+
const manufacturer = await ProjectsService.deleteManufacturer(batman, prismaManufacturer1.name);
650+
651+
expect(manufacturer).toStrictEqual(prismaManufacturer1);
652+
expect(prisma.manufacturer.findFirst).toHaveBeenCalledTimes(1);
653+
expect(prisma.manufacturer.update).toHaveBeenCalledTimes(1);
654+
});
655+
656+
test('deleteManufacturer fails when user is not at least Head', async () => {
657+
vi.spyOn(prisma.manufacturer, 'findFirst').mockResolvedValue(prismaManufacturer1);
658+
vi.spyOn(prisma.manufacturer, 'update').mockResolvedValue(prismaManufacturer1);
659+
660+
await expect(
661+
async () => await ProjectsService.deleteManufacturer(wonderwoman, prismaManufacturer1.name)
662+
).rejects.toThrow(new AccessDeniedException('Only heads and above can delete a manufacturer'));
663+
664+
expect(prisma.project.findFirst).toHaveBeenCalledTimes(0);
665+
expect(prisma.project.update).toHaveBeenCalledTimes(0);
666+
});
667+
668+
test('deleteManufacturer fails when manufacturer is not found', async () => {
669+
vi.spyOn(prisma.manufacturer, 'findFirst').mockResolvedValue(null);
670+
671+
await expect(async () => await ProjectsService.deleteManufacturer(batman, prismaManufacturer1.name)).rejects.toThrow(
672+
new NotFoundException('Manufacturer', prismaManufacturer1.name)
673+
);
674+
675+
expect(prisma.project.findFirst).toHaveBeenCalledTimes(0);
676+
expect(prisma.project.update).toHaveBeenCalledTimes(0);
677+
});
678+
679+
test('deleteManufacturer fails when manufacturer has been deleted', async () => {
680+
vi.spyOn(prisma.manufacturer, 'findFirst').mockResolvedValue(prismaManufacturer2);
681+
await expect(async () => await ProjectsService.deleteManufacturer(batman, prismaManufacturer2.name)).rejects.toThrow(
682+
new DeletedException('Manufacturer', prismaManufacturer2.name)
683+
);
684+
});
645685
test('Get all Manufacturer works', async () => {
646686
vi.spyOn(prisma.manufacturer, 'findMany').mockResolvedValue([]);
647687

src/backend/tests/test-data/projects.test-data.ts

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -153,13 +153,15 @@ export const prismaMaterial: Material = {
153153
export const prismaManufacturer1: Manufacturer = {
154154
name: 'Manufacturer1',
155155
dateCreated: new Date('10-1-2023'),
156-
creatorId: 1
156+
creatorId: 1,
157+
dateDeleted: null
157158
};
158159

159160
export const prismaManufacturer2: Manufacturer = {
160161
name: 'name',
161162
dateCreated: new Date('10-18-2023'),
162-
creatorId: 1
163+
creatorId: 1,
164+
dateDeleted: new Date('10-18-2023')
163165
};
164166

165167
export const toolMaterial: PrismaMaterialType = {

0 commit comments

Comments
 (0)