mirror of
https://github.com/bigcapitalhq/bigcapital.git
synced 2026-02-18 13:50:31 +00:00
fix: delete sale invoice with associated payment entries.
This commit is contained in:
@@ -338,7 +338,7 @@ export default class SaleInvoicesController extends BaseController {
|
|||||||
if (error instanceof ServiceError) {
|
if (error instanceof ServiceError) {
|
||||||
if (error.errorType === 'INVOICE_NUMBER_NOT_UNIQUE') {
|
if (error.errorType === 'INVOICE_NUMBER_NOT_UNIQUE') {
|
||||||
return res.boom.badRequest(null, {
|
return res.boom.badRequest(null, {
|
||||||
errors: [{ type: 'SALE.INVOICE.NUMBER.IS.EXISTS', code: 200 }],
|
errors: [{ type: 'SALE.INVOICE.NUMBER.IS.EXISTS', code: 100 }],
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
if (error.errorType === 'SALE_INVOICE_NOT_FOUND') {
|
if (error.errorType === 'SALE_INVOICE_NOT_FOUND') {
|
||||||
@@ -348,42 +348,47 @@ export default class SaleInvoicesController extends BaseController {
|
|||||||
}
|
}
|
||||||
if (error.errorType === 'ENTRIES_ITEMS_IDS_NOT_EXISTS') {
|
if (error.errorType === 'ENTRIES_ITEMS_IDS_NOT_EXISTS') {
|
||||||
return res.boom.badRequest(null, {
|
return res.boom.badRequest(null, {
|
||||||
errors: [{ type: 'ENTRIES_ITEMS_IDS_NOT_EXISTS', code: 200 }],
|
errors: [{ type: 'ENTRIES_ITEMS_IDS_NOT_EXISTS', code: 300 }],
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
if (error.errorType === 'NOT_SELLABLE_ITEMS') {
|
if (error.errorType === 'NOT_SELLABLE_ITEMS') {
|
||||||
return res.boom.badRequest(null, {
|
return res.boom.badRequest(null, {
|
||||||
errors: [{ type: 'NOT_SELLABLE_ITEMS', code: 200 }],
|
errors: [{ type: 'NOT_SELLABLE_ITEMS', code: 400 }],
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
if (error.errorType === 'SALE_INVOICE_NO_NOT_UNIQUE') {
|
if (error.errorType === 'SALE_INVOICE_NO_NOT_UNIQUE') {
|
||||||
return res.boom.badRequest(null, {
|
return res.boom.badRequest(null, {
|
||||||
errors: [{ type: 'SALE_INVOICE_NO_NOT_UNIQUE', code: 200 }],
|
errors: [{ type: 'SALE_INVOICE_NO_NOT_UNIQUE', code: 500 }],
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
if (error.errorType === 'ITEMS_NOT_FOUND') {
|
if (error.errorType === 'ITEMS_NOT_FOUND') {
|
||||||
return res.boom.badRequest(null, {
|
return res.boom.badRequest(null, {
|
||||||
errors: [{ type: 'ITEMS_NOT_FOUND', code: 200 }],
|
errors: [{ type: 'ITEMS_NOT_FOUND', code: 600 }],
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
if (error.errorType === 'ENTRIES_IDS_NOT_FOUND') {
|
if (error.errorType === 'ENTRIES_IDS_NOT_FOUND') {
|
||||||
return res.boom.badRequest(null, {
|
return res.boom.badRequest(null, {
|
||||||
errors: [{ type: 'ENTRIES_IDS_NOT_FOUND', code: 200 }],
|
errors: [{ type: 'ENTRIES_IDS_NOT_FOUND', code: 700 }],
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
if (error.errorType === 'NOT_SELL_ABLE_ITEMS') {
|
if (error.errorType === 'NOT_SELL_ABLE_ITEMS') {
|
||||||
return res.boom.badRequest(null, {
|
return res.boom.badRequest(null, {
|
||||||
errors: [{ type: 'NOT_SELL_ABLE_ITEMS', code: 200 }],
|
errors: [{ type: 'NOT_SELL_ABLE_ITEMS', code: 800 }],
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
if (error.errorType === 'contact_not_found') {
|
if (error.errorType === 'contact_not_found') {
|
||||||
return res.boom.badRequest(null, {
|
return res.boom.badRequest(null, {
|
||||||
errors: [{ type: 'CUSTOMER_NOT_FOUND', code: 200 }],
|
errors: [{ type: 'CUSTOMER_NOT_FOUND', code: 900 }],
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
if (error.errorType === 'SALE_INVOICE_ALREADY_DELIVERED') {
|
if (error.errorType === 'SALE_INVOICE_ALREADY_DELIVERED') {
|
||||||
return res.boom.badRequest(null, {
|
return res.boom.badRequest(null, {
|
||||||
errors: [{ type: 'SALE_INVOICE_ALREADY_DELIVERED', code: 200 }],
|
errors: [{ type: 'SALE_INVOICE_ALREADY_DELIVERED', code: 1000 }],
|
||||||
|
});
|
||||||
|
}
|
||||||
|
if (error.errorType === 'INVOICE_HAS_ASSOCIATED_PAYMENT_ENTRIES') {
|
||||||
|
return res.boom.badRequest(null, {
|
||||||
|
errors: [{ type: 'INVOICE_HAS_ASSOCIATED_PAYMENT_ENTRIES', code: 1100 }],
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -24,6 +24,7 @@ import ItemsService from 'services/Items/ItemsService';
|
|||||||
import ItemsEntriesService from 'services/Items/ItemsEntriesService';
|
import ItemsEntriesService from 'services/Items/ItemsEntriesService';
|
||||||
import CustomersService from 'services/Contacts/CustomersService';
|
import CustomersService from 'services/Contacts/CustomersService';
|
||||||
import SaleEstimateService from 'services/Sales/SalesEstimate';
|
import SaleEstimateService from 'services/Sales/SalesEstimate';
|
||||||
|
import { PaymentReceiveEntry } from 'models';
|
||||||
|
|
||||||
const ERRORS = {
|
const ERRORS = {
|
||||||
INVOICE_NUMBER_NOT_UNIQUE: 'INVOICE_NUMBER_NOT_UNIQUE',
|
INVOICE_NUMBER_NOT_UNIQUE: 'INVOICE_NUMBER_NOT_UNIQUE',
|
||||||
@@ -32,6 +33,7 @@ const ERRORS = {
|
|||||||
ENTRIES_ITEMS_IDS_NOT_EXISTS: 'ENTRIES_ITEMS_IDS_NOT_EXISTS',
|
ENTRIES_ITEMS_IDS_NOT_EXISTS: 'ENTRIES_ITEMS_IDS_NOT_EXISTS',
|
||||||
NOT_SELLABLE_ITEMS: 'NOT_SELLABLE_ITEMS',
|
NOT_SELLABLE_ITEMS: 'NOT_SELLABLE_ITEMS',
|
||||||
SALE_INVOICE_NO_NOT_UNIQUE: 'SALE_INVOICE_NO_NOT_UNIQUE',
|
SALE_INVOICE_NO_NOT_UNIQUE: 'SALE_INVOICE_NO_NOT_UNIQUE',
|
||||||
|
INVOICE_HAS_ASSOCIATED_PAYMENT_ENTRIES: 'INVOICE_HAS_ASSOCIATED_PAYMENT_ENTRIES',
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -312,6 +314,28 @@ export default class SaleInvoicesService extends SalesInvoicesCost {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Validate the sale invoice has no payment entries.
|
||||||
|
* @param {number} tenantId
|
||||||
|
* @param {number} saleInvoiceId
|
||||||
|
*/
|
||||||
|
async validateInvoiceHasNoPaymentEntries(
|
||||||
|
tenantId: number,
|
||||||
|
saleInvoiceId: number
|
||||||
|
) {
|
||||||
|
const { PaymentReceiveEntry } = this.tenancy.models(tenantId);
|
||||||
|
|
||||||
|
// Retrieve the sale invoice associated payment receive entries.
|
||||||
|
const entries = await PaymentReceiveEntry.query().where(
|
||||||
|
'invoice_id',
|
||||||
|
saleInvoiceId,
|
||||||
|
);
|
||||||
|
if (entries.length > 0) {
|
||||||
|
throw new ServiceError(ERRORS.INVOICE_HAS_ASSOCIATED_PAYMENT_ENTRIES);
|
||||||
|
}
|
||||||
|
return entries;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Deletes the given sale invoice with associated entries
|
* Deletes the given sale invoice with associated entries
|
||||||
* and journal transactions.
|
* and journal transactions.
|
||||||
@@ -329,6 +353,9 @@ export default class SaleInvoicesService extends SalesInvoicesCost {
|
|||||||
tenantId,
|
tenantId,
|
||||||
saleInvoiceId
|
saleInvoiceId
|
||||||
);
|
);
|
||||||
|
// Validate the sale invoice has no associated payment entries.
|
||||||
|
await this.validateInvoiceHasNoPaymentEntries(tenantId, saleInvoiceId);
|
||||||
|
|
||||||
// Triggers `onSaleInvoiceDelete` event.
|
// Triggers `onSaleInvoiceDelete` event.
|
||||||
await this.eventDispatcher.dispatch(events.saleInvoice.onDelete, {
|
await this.eventDispatcher.dispatch(events.saleInvoice.onDelete, {
|
||||||
tenantId,
|
tenantId,
|
||||||
@@ -454,7 +481,9 @@ export default class SaleInvoicesService extends SalesInvoicesCost {
|
|||||||
tenantId: number,
|
tenantId: number,
|
||||||
saleInvoiceId: number
|
saleInvoiceId: number
|
||||||
): Promise<void> {
|
): Promise<void> {
|
||||||
const { inventoryTransactionRepository } = this.tenancy.repositories(tenantId);
|
const { inventoryTransactionRepository } = this.tenancy.repositories(
|
||||||
|
tenantId
|
||||||
|
);
|
||||||
|
|
||||||
// Retrieve the inventory transactions of the given sale invoice.
|
// Retrieve the inventory transactions of the given sale invoice.
|
||||||
const oldInventoryTransactions = await inventoryTransactionRepository.find({
|
const oldInventoryTransactions = await inventoryTransactionRepository.find({
|
||||||
|
|||||||
Reference in New Issue
Block a user