Skip to content

Commit 5ccf484

Browse files
authored
Merge pull request #1688 from Northeastern-Electric-Racing/#1448-BenjaminZhu-AddAbilityToEditVendors
#1448 benjamin zhu add ability to edit vendors
2 parents 40c0560 + 0ab44a2 commit 5ccf484

6 files changed

Lines changed: 89 additions & 1 deletion

File tree

src/backend/src/controllers/reimbursement-requests.controllers.ts

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -319,4 +319,16 @@ export default class ReimbursementRequestsController {
319319
next(error);
320320
}
321321
}
322+
323+
static async editVendor(req: Request, res: Response, next: NextFunction) {
324+
try {
325+
const { vendorId } = req.params;
326+
const { name } = req.body;
327+
const submitter = await getCurrentUser(res);
328+
const editVendors = await ReimbursementRequestService.editVendors(name, vendorId, submitter);
329+
res.status(200).json(editVendors);
330+
} catch (error: unknown) {
331+
next(error);
332+
}
333+
}
322334
}

src/backend/src/routes/reimbursement-requests.routes.ts

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,13 @@ reimbursementRequestsRouter.get('/reimbursements/current-user', ReimbursementReq
2424

2525
reimbursementRequestsRouter.get('/reimbursements', ReimbursementRequestController.getAllReimbursements);
2626

27+
reimbursementRequestsRouter.post(
28+
'/:vendorId/vendors/edit',
29+
nonEmptyString(body('name')),
30+
validateInputs,
31+
ReimbursementRequestController.editVendor
32+
);
33+
2734
reimbursementRequestsRouter.post(
2835
'/create',
2936
isDate(body('dateOfExpense')),

src/backend/src/services/reimbursement-requests.services.ts

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ import {
2222
} from 'shared';
2323
import prisma from '../prisma/prisma';
2424
import {
25+
isUserAdminOrOnFinance,
2526
createReimbursementProducts,
2627
isUserLeadOrHeadOfFinanceTeam,
2728
removeDeletedReceiptPictures,
@@ -767,4 +768,29 @@ export default class ReimbursementRequestService {
767768
if (!fileData) throw new NotFoundException('Image File', fileId);
768769
return fileData;
769770
}
771+
772+
/**
773+
* Edits the vendor name
774+
*
775+
* @param name the new vendor name
776+
* @param vendorId the requested vendor to be edited
777+
* @param submitter the user editing the vendor name
778+
* @returns the updated vendor
779+
*/
780+
static async editVendors(name: string, vendorId: string, submitter: User) {
781+
await isUserAdminOrOnFinance(submitter);
782+
783+
const vendorUniqueName = await prisma.vendor.findUnique({
784+
where: { name }
785+
});
786+
787+
if (!!vendorUniqueName) throw new HttpException(400, 'vendor name already exists');
788+
789+
const vendor = await prisma.vendor.update({
790+
where: { vendorId },
791+
data: { name }
792+
});
793+
794+
return vendorTransformer(vendor);
795+
}
770796
}

src/backend/src/utils/reimbursement-requests.utils.ts

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ import {
99
ReimbursementProductCreateArgs,
1010
ReimbursementReceiptCreateArgs,
1111
ValidatedWbsReimbursementProductCreateArgs,
12+
isAdmin,
1213
wbsPipe,
1314
WbsReimbursementProductCreateArgs
1415
} from 'shared';
@@ -366,6 +367,16 @@ export const isAuthUserHeadOfFinance = (user: Prisma.UserGetPayload<typeof authU
366367
return user.teamAsHead?.teamId === process.env.FINANCE_TEAM_ID;
367368
};
368369

370+
export const isUserAdminOrOnFinance = async (submitter: User) => {
371+
try {
372+
await validateUserIsPartOfFinanceTeam(submitter);
373+
} catch (error) {
374+
if (!isAdmin(submitter.role)) {
375+
throw new AccessDeniedException('Only Admins, Finance Team Leads, or Heads can edit vendors');
376+
}
377+
}
378+
};
379+
369380
const isTeamIdInList = (teamId: string, teamsList: Team[]) => {
370381
return teamsList.map((team) => team.teamId).includes(teamId);
371382
};

src/backend/tests/reimbursement-requests.test.ts

Lines changed: 27 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,8 @@ import {
2222
prismaGiveMeMyMoney4,
2323
prismaGiveMeMyMoney5,
2424
prismaReimbursementStatus,
25-
sharedGiveMeMyMoney
25+
sharedGiveMeMyMoney,
26+
KFC
2627
} from './test-data/reimbursement-requests.test-data';
2728
import {
2829
alfred,
@@ -758,4 +759,29 @@ describe('Reimbursement Requests', () => {
758759
expect(newReimbursement).toStrictEqual(reimbursementTransformer(reimbursementMock));
759760
});
760761
});
762+
763+
describe('Edit Vendor Tests', () => {
764+
test('Throws error if user isnt an admin or lead/head of the finance', async () => {
765+
await expect(
766+
ReimbursementRequestService.editVendors('I Love Benny', GiveMeMyMoney.vendorId, wonderwoman)
767+
).rejects.toThrow(new AccessDeniedException('Only Admins, Finance Team Leads, or Heads can edit vendors'));
768+
});
769+
770+
test('Throws error if the vendor name already exists', async () => {
771+
vi.spyOn(prisma.vendor, 'findUnique').mockResolvedValue(PopEyes);
772+
await expect(ReimbursementRequestService.editVendors('CHICKEN', GiveMeMyMoney.vendorId, batman)).rejects.toThrow(
773+
new HttpException(400, 'vendor name already exists')
774+
);
775+
});
776+
777+
test('Successfuly changes Vendors name', async () => {
778+
vi.spyOn(prisma.vendor, 'update').mockResolvedValue(KFC);
779+
vi.spyOn(prisma.vendor, 'findUnique').mockResolvedValue(null);
780+
781+
const vendor = await ReimbursementRequestService.editVendors('kfc', PopEyes.vendorId, batman);
782+
783+
expect(vendor.name).toBe('kfc');
784+
expect(prisma.vendor.update).toBeCalledTimes(1);
785+
});
786+
});
761787
});

src/backend/tests/test-data/reimbursement-requests.test-data.ts

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,12 @@ export const PopEyes: PrismaVendor = {
2323
name: 'Pop Eyes'
2424
};
2525

26+
export const KFC: PrismaVendor = {
27+
vendorId: 'CHICKEN',
28+
dateCreated: new Date('12/22/203'),
29+
name: 'kfc'
30+
};
31+
2632
export const Parts: PrismaExpenseType = {
2733
expenseTypeId: 'PARTS',
2834
name: 'hammer',

0 commit comments

Comments
 (0)