From cdee2e5314fbfe5f5de82a47b324d3d2da33101f Mon Sep 17 00:00:00 2001 From: "a.bouhuolia" Date: Sat, 2 Jan 2021 11:32:15 +0200 Subject: [PATCH] fix: delete sale invoice with associated payment entries. --- .../api/controllers/Sales/SalesInvoices.ts | 23 ++++++++------ server/src/services/Sales/SalesInvoices.ts | 31 ++++++++++++++++++- 2 files changed, 44 insertions(+), 10 deletions(-) diff --git a/server/src/api/controllers/Sales/SalesInvoices.ts b/server/src/api/controllers/Sales/SalesInvoices.ts index b601dd48b..bcda9317a 100644 --- a/server/src/api/controllers/Sales/SalesInvoices.ts +++ b/server/src/api/controllers/Sales/SalesInvoices.ts @@ -338,7 +338,7 @@ export default class SaleInvoicesController extends BaseController { if (error instanceof ServiceError) { if (error.errorType === 'INVOICE_NUMBER_NOT_UNIQUE') { 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') { @@ -348,42 +348,47 @@ export default class SaleInvoicesController extends BaseController { } if (error.errorType === 'ENTRIES_ITEMS_IDS_NOT_EXISTS') { 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') { 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') { 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') { 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') { 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') { 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') { 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') { 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 }], }); } } diff --git a/server/src/services/Sales/SalesInvoices.ts b/server/src/services/Sales/SalesInvoices.ts index 1323c6f35..1a74d94e9 100644 --- a/server/src/services/Sales/SalesInvoices.ts +++ b/server/src/services/Sales/SalesInvoices.ts @@ -24,6 +24,7 @@ import ItemsService from 'services/Items/ItemsService'; import ItemsEntriesService from 'services/Items/ItemsEntriesService'; import CustomersService from 'services/Contacts/CustomersService'; import SaleEstimateService from 'services/Sales/SalesEstimate'; +import { PaymentReceiveEntry } from 'models'; const ERRORS = { INVOICE_NUMBER_NOT_UNIQUE: 'INVOICE_NUMBER_NOT_UNIQUE', @@ -32,6 +33,7 @@ const ERRORS = { ENTRIES_ITEMS_IDS_NOT_EXISTS: 'ENTRIES_ITEMS_IDS_NOT_EXISTS', NOT_SELLABLE_ITEMS: 'NOT_SELLABLE_ITEMS', 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 * and journal transactions. @@ -329,6 +353,9 @@ export default class SaleInvoicesService extends SalesInvoicesCost { tenantId, saleInvoiceId ); + // Validate the sale invoice has no associated payment entries. + await this.validateInvoiceHasNoPaymentEntries(tenantId, saleInvoiceId); + // Triggers `onSaleInvoiceDelete` event. await this.eventDispatcher.dispatch(events.saleInvoice.onDelete, { tenantId, @@ -454,7 +481,9 @@ export default class SaleInvoicesService extends SalesInvoicesCost { tenantId: number, saleInvoiceId: number ): Promise { - const { inventoryTransactionRepository } = this.tenancy.repositories(tenantId); + const { inventoryTransactionRepository } = this.tenancy.repositories( + tenantId + ); // Retrieve the inventory transactions of the given sale invoice. const oldInventoryTransactions = await inventoryTransactionRepository.find({