mirror of
https://github.com/bigcapitalhq/bigcapital.git
synced 2026-02-24 08:39:49 +00:00
fix: Add DELETE endpoint for credit notes applied invoices
- Add missing DELETE /credit-notes/applied-invoices/:id endpoint - Fix CreditNotesApplyInvoice controller to use correct service methods - Add missing GetCreditNoteAssociatedInvoicesToApply endpoint - Add proper DTO for ApplyCreditNoteToInvoices - Update frontend creditNote hook to use correct API paths Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -1,5 +1,5 @@
|
||||
import { ModuleRef } from '@nestjs/core';
|
||||
import bluebird from 'bluebird';
|
||||
import * as bluebird from 'bluebird';
|
||||
import { Knex } from 'knex';
|
||||
import {
|
||||
validateLinkModelEntryExists,
|
||||
@@ -53,7 +53,8 @@ export class LinkAttachment {
|
||||
const foundLinkModel = await LinkModel().query(trx).findById(modelId);
|
||||
validateLinkModelEntryExists(foundLinkModel);
|
||||
|
||||
const foundLinks = await this.documentLinkModel().query(trx)
|
||||
const foundLinks = await this.documentLinkModel()
|
||||
.query(trx)
|
||||
.where('modelRef', modelRef)
|
||||
.where('modelId', modelId)
|
||||
.where('documentId', foundFile.id);
|
||||
@@ -70,7 +71,7 @@ export class LinkAttachment {
|
||||
|
||||
/**
|
||||
* Links the given file keys to the given model type and id.
|
||||
* @param {string[]} filekeys - File keys.
|
||||
* @param {string[]} filekeys - File keys.
|
||||
* @param {string} modelRef - Model reference.
|
||||
* @param {number} modelId - Model id.
|
||||
* @param {Knex.Transaction} trx - Knex transaction.
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import {
|
||||
Body,
|
||||
Controller,
|
||||
Delete,
|
||||
Get,
|
||||
Param,
|
||||
Post,
|
||||
@@ -14,6 +15,10 @@ 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';
|
||||
import { GetCreditNoteAssociatedInvoicesToApply } from './queries/GetCreditNoteAssociatedInvoicesToApply.service';
|
||||
import { CreditNoteApplyToInvoices } from './commands/CreditNoteApplyToInvoices.service';
|
||||
import { DeleteCreditNoteApplyToInvoices } from './commands/DeleteCreditNoteApplyToInvoices.service';
|
||||
import { ApplyCreditNoteToInvoicesDto } from './dtos/ApplyCreditNoteToInvoices.dto';
|
||||
|
||||
@Controller('credit-notes')
|
||||
@ApiTags('Credit Notes Apply Invoice')
|
||||
@@ -22,6 +27,9 @@ import { CreditNoteAction } from '../CreditNotes/types/CreditNotes.types';
|
||||
export class CreditNotesApplyInvoiceController {
|
||||
constructor(
|
||||
private readonly getCreditNoteAssociatedAppliedInvoicesService: GetCreditNoteAssociatedAppliedInvoices,
|
||||
private readonly getCreditNoteAssociatedInvoicesToApplyService: GetCreditNoteAssociatedInvoicesToApply,
|
||||
private readonly creditNoteApplyToInvoicesService: CreditNoteApplyToInvoices,
|
||||
private readonly deleteCreditNoteApplyToInvoicesService: DeleteCreditNoteApplyToInvoices,
|
||||
) {}
|
||||
|
||||
@Get(':creditNoteId/applied-invoices')
|
||||
@@ -39,6 +47,23 @@ export class CreditNotesApplyInvoiceController {
|
||||
);
|
||||
}
|
||||
|
||||
@Get(':creditNoteId/apply-invoices')
|
||||
@RequirePermission(CreditNoteAction.View, AbilitySubject.CreditNote)
|
||||
@ApiOperation({ summary: 'Get credit note associated invoices to apply' })
|
||||
@ApiResponse({
|
||||
status: 200,
|
||||
description: 'Credit note associated invoices to apply',
|
||||
})
|
||||
@ApiResponse({ status: 404, description: 'Credit note not found' })
|
||||
@ApiResponse({ status: 400, description: 'Invalid input data' })
|
||||
getCreditNoteAssociatedInvoicesToApply(
|
||||
@Param('creditNoteId') creditNoteId: number,
|
||||
) {
|
||||
return this.getCreditNoteAssociatedInvoicesToApplyService.getCreditAssociatedInvoicesToApply(
|
||||
creditNoteId,
|
||||
);
|
||||
}
|
||||
|
||||
@Post(':creditNoteId/apply-invoices')
|
||||
@RequirePermission(CreditNoteAction.Edit, AbilitySubject.CreditNote)
|
||||
@ApiOperation({ summary: 'Apply credit note to invoices' })
|
||||
@@ -48,9 +73,32 @@ export class CreditNotesApplyInvoiceController {
|
||||
})
|
||||
@ApiResponse({ status: 404, description: 'Credit note not found' })
|
||||
@ApiResponse({ status: 400, description: 'Invalid input data' })
|
||||
applyCreditNoteToInvoices(@Param('creditNoteId') creditNoteId: number) {
|
||||
return this.getCreditNoteAssociatedAppliedInvoicesService.getCreditAssociatedAppliedInvoices(
|
||||
applyCreditNoteToInvoices(
|
||||
@Param('creditNoteId') creditNoteId: number,
|
||||
@Body() applyDto: ApplyCreditNoteToInvoicesDto,
|
||||
) {
|
||||
return this.creditNoteApplyToInvoicesService.applyCreditNoteToInvoices(
|
||||
creditNoteId,
|
||||
applyDto,
|
||||
);
|
||||
}
|
||||
|
||||
@Delete('applied-invoices/:applyCreditToInvoicesId')
|
||||
@RequirePermission(CreditNoteAction.Edit, AbilitySubject.CreditNote)
|
||||
@ApiOperation({ summary: 'Delete applied credit note to invoice' })
|
||||
@ApiResponse({
|
||||
status: 200,
|
||||
description: 'Credit note application successfully deleted',
|
||||
})
|
||||
@ApiResponse({
|
||||
status: 404,
|
||||
description: 'Credit note application not found',
|
||||
})
|
||||
deleteApplyCreditNoteToInvoices(
|
||||
@Param('applyCreditToInvoicesId') applyCreditToInvoicesId: number,
|
||||
) {
|
||||
return this.deleteCreditNoteApplyToInvoicesService.deleteApplyCreditNoteToInvoices(
|
||||
applyCreditToInvoicesId,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -9,6 +9,8 @@ import { CreditNotesModule } from '../CreditNotes/CreditNotes.module';
|
||||
import { GetCreditNoteAssociatedAppliedInvoices } from './queries/GetCreditNoteAssociatedAppliedInvoices.service';
|
||||
import { GetCreditNoteAssociatedInvoicesToApply } from './queries/GetCreditNoteAssociatedInvoicesToApply.service';
|
||||
import { CreditNotesApplyInvoiceController } from './CreditNotesApplyInvoice.controller';
|
||||
import { CreditNoteApplySyncCreditSubscriber } from './subscribers/CreditNoteApplySyncCreditSubscriber';
|
||||
import { CreditNoteApplySyncInvoicesCreditedAmountSubscriber } from './subscribers/CreditNoteApplySyncInvoicesSubscriber';
|
||||
|
||||
@Module({
|
||||
providers: [
|
||||
@@ -19,6 +21,8 @@ import { CreditNotesApplyInvoiceController } from './CreditNotesApplyInvoice.con
|
||||
CreditNoteApplySyncCredit,
|
||||
GetCreditNoteAssociatedAppliedInvoices,
|
||||
GetCreditNoteAssociatedInvoicesToApply,
|
||||
CreditNoteApplySyncCreditSubscriber,
|
||||
CreditNoteApplySyncInvoicesCreditedAmountSubscriber,
|
||||
],
|
||||
exports: [DeleteCustomerLinkedCreditNoteService],
|
||||
imports: [PaymentsReceivedModule, forwardRef(() => CreditNotesModule)],
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { Knex } from 'knex';
|
||||
import { Injectable, Inject } from '@nestjs/common';
|
||||
import Bluebird from 'bluebird';
|
||||
import * as Bluebird from 'bluebird';
|
||||
import { ICreditNoteAppliedToInvoice } from '../types/CreditNoteApplyInvoice.types';
|
||||
import { SaleInvoice } from '@/modules/SaleInvoices/models/SaleInvoice';
|
||||
import { CreditNoteAppliedInvoice } from '../models/CreditNoteAppliedInvoice';
|
||||
|
||||
@@ -0,0 +1,38 @@
|
||||
import { ApiProperty } from '@nestjs/swagger';
|
||||
import { Type } from 'class-transformer';
|
||||
import {
|
||||
ArrayMinSize,
|
||||
IsArray,
|
||||
IsInt,
|
||||
IsNotEmpty,
|
||||
IsNumber,
|
||||
ValidateNested,
|
||||
} from 'class-validator';
|
||||
|
||||
export class ApplyCreditNoteInvoiceEntryDto {
|
||||
@IsNotEmpty()
|
||||
@IsInt()
|
||||
@ApiProperty({ description: 'Invoice ID to apply credit to', example: 1 })
|
||||
invoiceId: number;
|
||||
|
||||
@IsNotEmpty()
|
||||
@IsNumber()
|
||||
@ApiProperty({ description: 'Amount to apply', example: 100.5 })
|
||||
amount: number;
|
||||
}
|
||||
|
||||
export class ApplyCreditNoteToInvoicesDto {
|
||||
@IsArray()
|
||||
@ArrayMinSize(1)
|
||||
@ValidateNested({ each: true })
|
||||
@Type(() => ApplyCreditNoteInvoiceEntryDto)
|
||||
@ApiProperty({
|
||||
description: 'Entries of invoice ID and amount to apply',
|
||||
type: [ApplyCreditNoteInvoiceEntryDto],
|
||||
example: [
|
||||
{ invoice_id: 1, amount: 100.5 },
|
||||
{ invoice_id: 2, amount: 50 },
|
||||
],
|
||||
})
|
||||
entries: ApplyCreditNoteInvoiceEntryDto[];
|
||||
}
|
||||
@@ -8,7 +8,7 @@ import { CreditNoteApplySyncInvoicesCreditedAmount } from '../commands/CreditNot
|
||||
import { events } from '@/common/events/events';
|
||||
|
||||
@Injectable()
|
||||
export default class CreditNoteApplySyncInvoicesCreditedAmountSubscriber {
|
||||
export class CreditNoteApplySyncInvoicesCreditedAmountSubscriber {
|
||||
constructor(
|
||||
private readonly syncInvoicesWithCreditNote: CreditNoteApplySyncInvoicesCreditedAmount,
|
||||
) {}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import Bluebird from 'bluebird';
|
||||
import * as Bluebird from 'bluebird';
|
||||
import { Inject, Injectable } from '@nestjs/common';
|
||||
import { Knex } from 'knex';
|
||||
import { IVendorCreditAppliedBill } from '../types/VendorCreditApplyBills.types';
|
||||
|
||||
@@ -58,16 +58,13 @@ export function useCreateCreditNote(props) {
|
||||
const queryClient = useQueryClient();
|
||||
const apiRequest = useApiRequest();
|
||||
|
||||
return useMutation(
|
||||
(values) => apiRequest.post('credit-notes', values),
|
||||
{
|
||||
onSuccess: (res, values) => {
|
||||
// Common invalidate queries.
|
||||
commonInvalidateQueries(queryClient);
|
||||
},
|
||||
...props,
|
||||
return useMutation((values) => apiRequest.post('credit-notes', values), {
|
||||
onSuccess: (res, values) => {
|
||||
// Common invalidate queries.
|
||||
commonInvalidateQueries(queryClient);
|
||||
},
|
||||
);
|
||||
...props,
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -218,8 +215,7 @@ export function useCreateRefundCreditNote(props) {
|
||||
const apiRequest = useApiRequest();
|
||||
|
||||
return useMutation(
|
||||
([id, values]) =>
|
||||
apiRequest.post(`credit-notes/${id}/refunds`, values),
|
||||
([id, values]) => apiRequest.post(`credit-notes/${id}/refunds`, values),
|
||||
{
|
||||
onSuccess: (res, [id, values]) => {
|
||||
// Common invalidate queries.
|
||||
@@ -240,19 +236,16 @@ export function useDeleteRefundCreditNote(props) {
|
||||
const queryClient = useQueryClient();
|
||||
const apiRequest = useApiRequest();
|
||||
|
||||
return useMutation(
|
||||
(id) => apiRequest.delete(`credit-notes/refunds/${id}`),
|
||||
{
|
||||
onSuccess: (res, id) => {
|
||||
// Common invalidate queries.
|
||||
commonInvalidateQueries(queryClient);
|
||||
return useMutation((id) => apiRequest.delete(`credit-notes/refunds/${id}`), {
|
||||
onSuccess: (res, id) => {
|
||||
// Common invalidate queries.
|
||||
commonInvalidateQueries(queryClient);
|
||||
|
||||
// Invalidate vendor credit query.
|
||||
queryClient.invalidateQueries([t.CREDIT_NOTE, id]);
|
||||
},
|
||||
...props,
|
||||
// Invalidate vendor credit query.
|
||||
queryClient.invalidateQueries([t.CREDIT_NOTE, id]);
|
||||
},
|
||||
);
|
||||
...props,
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -301,7 +294,7 @@ export function useReconcileCreditNote(id, props, requestProps) {
|
||||
[t.RECONCILE_CREDIT_NOTE, id],
|
||||
{
|
||||
method: 'get',
|
||||
url: `credit-notes/${id}/applied-invoices`,
|
||||
url: `credit-notes/${id}/apply-invoices`,
|
||||
...requestProps,
|
||||
},
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user