Merge pull request #962 from bigcapitalhq/feature/ahmedbouhuolia/add-permission-guards-to-credit-controllers

fix(server): add permission guards to credit note and vendor credit controllers
This commit is contained in:
Ahmed Bouhuolia
2026-02-16 20:07:36 +02:00
committed by GitHub
5 changed files with 80 additions and 6 deletions

View File

@@ -1,20 +1,35 @@
import { ApiOperation, ApiTags } from '@nestjs/swagger'; import { ApiOperation, ApiTags } from '@nestjs/swagger';
import { Body, Controller, Delete, Get, Param, Post } from '@nestjs/common'; import {
Body,
Controller,
Delete,
Get,
Param,
Post,
UseGuards,
} from '@nestjs/common';
import { ICreditNoteRefundDTO } from '../CreditNotes/types/CreditNotes.types'; import { ICreditNoteRefundDTO } from '../CreditNotes/types/CreditNotes.types';
import { CreditNotesRefundsApplication } from './CreditNotesRefundsApplication.service'; import { CreditNotesRefundsApplication } from './CreditNotesRefundsApplication.service';
import { RefundCreditNote } from './models/RefundCreditNote'; import { RefundCreditNote } from './models/RefundCreditNote';
import { CreditNoteRefundDto } from './dto/CreditNoteRefund.dto'; import { CreditNoteRefundDto } from './dto/CreditNoteRefund.dto';
import { ApiCommonHeaders } from '@/common/decorators/ApiCommonHeaders'; import { ApiCommonHeaders } from '@/common/decorators/ApiCommonHeaders';
import { RequirePermission } from '@/modules/Roles/RequirePermission.decorator';
import { PermissionGuard } from '@/modules/Roles/Permission.guard';
import { AuthorizationGuard } from '@/modules/Roles/Authorization.guard';
import { AbilitySubject } from '@/modules/Roles/Roles.types';
import { CreditNoteAction } from '../CreditNotes/types/CreditNotes.types';
@Controller('credit-notes') @Controller('credit-notes')
@ApiTags('Credit Note Refunds') @ApiTags('Credit Note Refunds')
@ApiCommonHeaders() @ApiCommonHeaders()
@UseGuards(AuthorizationGuard, PermissionGuard)
export class CreditNoteRefundsController { export class CreditNoteRefundsController {
constructor( constructor(
private readonly creditNotesRefundsApplication: CreditNotesRefundsApplication, private readonly creditNotesRefundsApplication: CreditNotesRefundsApplication,
) {} ) {}
@Get(':creditNoteId/refunds') @Get(':creditNoteId/refunds')
@RequirePermission(CreditNoteAction.View, AbilitySubject.CreditNote)
@ApiOperation({ summary: 'Retrieve the credit note graph.' }) @ApiOperation({ summary: 'Retrieve the credit note graph.' })
getCreditNoteRefunds(@Param('creditNoteId') creditNoteId: number) { getCreditNoteRefunds(@Param('creditNoteId') creditNoteId: number) {
return this.creditNotesRefundsApplication.getCreditNoteRefunds( return this.creditNotesRefundsApplication.getCreditNoteRefunds(
@@ -29,6 +44,7 @@ export class CreditNoteRefundsController {
* @returns {Promise<RefundCreditNote>} * @returns {Promise<RefundCreditNote>}
*/ */
@Post(':creditNoteId/refunds') @Post(':creditNoteId/refunds')
@RequirePermission(CreditNoteAction.Refund, AbilitySubject.CreditNote)
@ApiOperation({ summary: 'Create a refund for the given credit note.' }) @ApiOperation({ summary: 'Create a refund for the given credit note.' })
createRefundCreditNote( createRefundCreditNote(
@Param('creditNoteId') creditNoteId: number, @Param('creditNoteId') creditNoteId: number,
@@ -46,6 +62,7 @@ export class CreditNoteRefundsController {
* @returns {Promise<void>} * @returns {Promise<void>}
*/ */
@Delete('refunds/:refundCreditId') @Delete('refunds/:refundCreditId')
@RequirePermission(CreditNoteAction.Refund, AbilitySubject.CreditNote)
@ApiOperation({ summary: 'Delete a refund for the given credit note.' }) @ApiOperation({ summary: 'Delete a refund for the given credit note.' })
deleteRefundCreditNote( deleteRefundCreditNote(
@Param('refundCreditId') refundCreditId: number, @Param('refundCreditId') refundCreditId: number,

View File

@@ -1,15 +1,31 @@
import { Body, Controller, Get, Param, Post } from '@nestjs/common'; import {
Body,
Controller,
Get,
Param,
Post,
UseGuards,
} from '@nestjs/common';
import { ApiOperation, ApiResponse, ApiTags } from '@nestjs/swagger'; import { ApiOperation, ApiResponse, ApiTags } from '@nestjs/swagger';
import { GetCreditNoteAssociatedAppliedInvoices } from './queries/GetCreditNoteAssociatedAppliedInvoices.service'; import { GetCreditNoteAssociatedAppliedInvoices } from './queries/GetCreditNoteAssociatedAppliedInvoices.service';
import { ApiCommonHeaders } from '@/common/decorators/ApiCommonHeaders';
import { RequirePermission } from '@/modules/Roles/RequirePermission.decorator';
import { PermissionGuard } from '@/modules/Roles/Permission.guard';
import { AuthorizationGuard } from '@/modules/Roles/Authorization.guard';
import { AbilitySubject } from '@/modules/Roles/Roles.types';
import { CreditNoteAction } from '../CreditNotes/types/CreditNotes.types';
@Controller('credit-notes') @Controller('credit-notes')
@ApiTags('Credit Notes Apply Invoice') @ApiTags('Credit Notes Apply Invoice')
@ApiCommonHeaders()
@UseGuards(AuthorizationGuard, PermissionGuard)
export class CreditNotesApplyInvoiceController { export class CreditNotesApplyInvoiceController {
constructor( constructor(
private readonly getCreditNoteAssociatedAppliedInvoicesService: GetCreditNoteAssociatedAppliedInvoices, private readonly getCreditNoteAssociatedAppliedInvoicesService: GetCreditNoteAssociatedAppliedInvoices,
) {} ) {}
@Get(':creditNoteId/applied-invoices') @Get(':creditNoteId/applied-invoices')
@RequirePermission(CreditNoteAction.View, AbilitySubject.CreditNote)
@ApiOperation({ summary: 'Applied credit note to invoices' }) @ApiOperation({ summary: 'Applied credit note to invoices' })
@ApiResponse({ @ApiResponse({
status: 200, status: 200,
@@ -24,6 +40,7 @@ export class CreditNotesApplyInvoiceController {
} }
@Post(':creditNoteId/apply-invoices') @Post(':creditNoteId/apply-invoices')
@RequirePermission(CreditNoteAction.Edit, AbilitySubject.CreditNote)
@ApiOperation({ summary: 'Apply credit note to invoices' }) @ApiOperation({ summary: 'Apply credit note to invoices' })
@ApiResponse({ @ApiResponse({
status: 200, status: 200,

View File

@@ -31,9 +31,10 @@ export class AuthorizationGuard implements CanActivate {
async canActivate(context: ExecutionContext): Promise<boolean> { async canActivate(context: ExecutionContext): Promise<boolean> {
const request = context.switchToHttp().getRequest<Request>(); const request = context.switchToHttp().getRequest<Request>();
const { user } = request as any; const { user } = request as any;
const userId = this.clsService.get('userId');
if (ABILITIES_CACHE.has(user.id)) { if (ABILITIES_CACHE.has(userId)) {
(request as any).ability = ABILITIES_CACHE.get(user.id); (request as any).ability = ABILITIES_CACHE.get(userId);
} else { } else {
const ability = await this.getAbilityForUser(); const ability = await this.getAbilityForUser();
(request as any).ability = ability; (request as any).ability = ability;

View File

@@ -1,16 +1,33 @@
import { Body, Controller, Delete, Get, Param, Post } from '@nestjs/common'; import {
Body,
Controller,
Delete,
Get,
Param,
Post,
UseGuards,
} from '@nestjs/common';
import { VendorCreditApplyBillsApplicationService } from './VendorCreditApplyBillsApplication.service'; import { VendorCreditApplyBillsApplicationService } from './VendorCreditApplyBillsApplication.service';
import { IVendorCreditApplyToInvoicesDTO } from './types/VendorCreditApplyBills.types'; import { IVendorCreditApplyToInvoicesDTO } from './types/VendorCreditApplyBills.types';
import { ApiTags } from '@nestjs/swagger'; import { ApiTags } from '@nestjs/swagger';
import { ApiCommonHeaders } from '@/common/decorators/ApiCommonHeaders';
import { RequirePermission } from '@/modules/Roles/RequirePermission.decorator';
import { PermissionGuard } from '@/modules/Roles/Permission.guard';
import { AuthorizationGuard } from '@/modules/Roles/Authorization.guard';
import { AbilitySubject } from '@/modules/Roles/Roles.types';
import { VendorCreditAction } from '../VendorCredit/types/VendorCredit.types';
@Controller('vendor-credits') @Controller('vendor-credits')
@ApiTags('Vendor Credits Apply Bills') @ApiTags('Vendor Credits Apply Bills')
@ApiCommonHeaders()
@UseGuards(AuthorizationGuard, PermissionGuard)
export class VendorCreditApplyBillsController { export class VendorCreditApplyBillsController {
constructor( constructor(
private readonly vendorCreditApplyBillsApplication: VendorCreditApplyBillsApplicationService, private readonly vendorCreditApplyBillsApplication: VendorCreditApplyBillsApplicationService,
) {} ) {}
@Get(':vendorCreditId/bills-to-apply') @Get(':vendorCreditId/bills-to-apply')
@RequirePermission(VendorCreditAction.View, AbilitySubject.VendorCredit)
async getVendorCreditToApplyBills( async getVendorCreditToApplyBills(
@Param('vendorCreditId') vendorCreditId: number, @Param('vendorCreditId') vendorCreditId: number,
) { ) {
@@ -20,6 +37,7 @@ export class VendorCreditApplyBillsController {
} }
@Post(':vendorCreditId/apply-to-bills') @Post(':vendorCreditId/apply-to-bills')
@RequirePermission(VendorCreditAction.Edit, AbilitySubject.VendorCredit)
async applyVendorCreditToBills( async applyVendorCreditToBills(
@Param('vendorCreditId') vendorCreditId: number, @Param('vendorCreditId') vendorCreditId: number,
@Body() applyCreditToBillsDTO: IVendorCreditApplyToInvoicesDTO, @Body() applyCreditToBillsDTO: IVendorCreditApplyToInvoicesDTO,
@@ -31,6 +49,7 @@ export class VendorCreditApplyBillsController {
} }
@Delete('applied-bills/:vendorCreditAppliedBillId') @Delete('applied-bills/:vendorCreditAppliedBillId')
@RequirePermission(VendorCreditAction.Edit, AbilitySubject.VendorCredit)
async deleteAppliedBillToVendorCredit( async deleteAppliedBillToVendorCredit(
@Param('vendorCreditAppliedBillId') vendorCreditAppliedBillId: number, @Param('vendorCreditAppliedBillId') vendorCreditAppliedBillId: number,
) { ) {
@@ -40,6 +59,7 @@ export class VendorCreditApplyBillsController {
} }
@Get(':vendorCreditId/applied-bills') @Get(':vendorCreditId/applied-bills')
@RequirePermission(VendorCreditAction.View, AbilitySubject.VendorCredit)
async getAppliedBillsToVendorCredit( async getAppliedBillsToVendorCredit(
@Param('vendorCreditId') vendorCreditId: number, @Param('vendorCreditId') vendorCreditId: number,
) { ) {

View File

@@ -1,11 +1,27 @@
import { Body, Controller, Delete, Get, Param, Post } from '@nestjs/common'; import {
Body,
Controller,
Delete,
Get,
Param,
Post,
UseGuards,
} from '@nestjs/common';
import { VendorCreditsRefundApplication } from './VendorCreditsRefund.application'; import { VendorCreditsRefundApplication } from './VendorCreditsRefund.application';
import { RefundVendorCredit } from './models/RefundVendorCredit'; import { RefundVendorCredit } from './models/RefundVendorCredit';
import { ApiOperation, ApiTags } from '@nestjs/swagger'; import { ApiOperation, ApiTags } from '@nestjs/swagger';
import { RefundVendorCreditDto } from './dtos/RefundVendorCredit.dto'; import { RefundVendorCreditDto } from './dtos/RefundVendorCredit.dto';
import { ApiCommonHeaders } from '@/common/decorators/ApiCommonHeaders';
import { RequirePermission } from '@/modules/Roles/RequirePermission.decorator';
import { PermissionGuard } from '@/modules/Roles/Permission.guard';
import { AuthorizationGuard } from '@/modules/Roles/Authorization.guard';
import { AbilitySubject } from '@/modules/Roles/Roles.types';
import { VendorCreditAction } from '../VendorCredit/types/VendorCredit.types';
@Controller('vendor-credits') @Controller('vendor-credits')
@ApiTags('Vendor Credits Refunds') @ApiTags('Vendor Credits Refunds')
@ApiCommonHeaders()
@UseGuards(AuthorizationGuard, PermissionGuard)
export class VendorCreditsRefundController { export class VendorCreditsRefundController {
constructor( constructor(
private readonly vendorCreditsRefundApplication: VendorCreditsRefundApplication, private readonly vendorCreditsRefundApplication: VendorCreditsRefundApplication,
@@ -17,6 +33,7 @@ export class VendorCreditsRefundController {
* @returns {Promise<IRefundVendorCreditPOJO[]>} * @returns {Promise<IRefundVendorCreditPOJO[]>}
*/ */
@Get(':vendorCreditId/refund') @Get(':vendorCreditId/refund')
@RequirePermission(VendorCreditAction.View, AbilitySubject.VendorCredit)
@ApiOperation({ summary: 'Retrieve the vendor credit refunds graph.' }) @ApiOperation({ summary: 'Retrieve the vendor credit refunds graph.' })
public getVendorCreditRefunds( public getVendorCreditRefunds(
@Param('vendorCreditId') vendorCreditId: string, @Param('vendorCreditId') vendorCreditId: string,
@@ -33,6 +50,7 @@ export class VendorCreditsRefundController {
* @returns {Promise<RefundVendorCredit>} * @returns {Promise<RefundVendorCredit>}
*/ */
@Post(':vendorCreditId/refund') @Post(':vendorCreditId/refund')
@RequirePermission(VendorCreditAction.Refund, AbilitySubject.VendorCredit)
@ApiOperation({ summary: 'Create a refund for the given vendor credit.' }) @ApiOperation({ summary: 'Create a refund for the given vendor credit.' })
public async createRefundVendorCredit( public async createRefundVendorCredit(
@Param('vendorCreditId') vendorCreditId: string, @Param('vendorCreditId') vendorCreditId: string,
@@ -50,6 +68,7 @@ export class VendorCreditsRefundController {
* @returns {Promise<void>} * @returns {Promise<void>}
*/ */
@Delete('refunds/:refundCreditId') @Delete('refunds/:refundCreditId')
@RequirePermission(VendorCreditAction.Refund, AbilitySubject.VendorCredit)
@ApiOperation({ summary: 'Delete a refund for the given vendor credit.' }) @ApiOperation({ summary: 'Delete a refund for the given vendor credit.' })
public async deleteRefundVendorCredit( public async deleteRefundVendorCredit(
@Param('refundCreditId') refundCreditId: string, @Param('refundCreditId') refundCreditId: string,