diff --git a/server/src/api/controllers/Purchases/Bills.ts b/server/src/api/controllers/Purchases/Bills.ts index e190d7d84..c119bcfce 100644 --- a/server/src/api/controllers/Purchases/Bills.ts +++ b/server/src/api/controllers/Purchases/Bills.ts @@ -446,7 +446,9 @@ export default class BillsController extends BaseController { ], }); } - if (error.errorType === 'LOCATED_COST_ENTRIES_SHOULD_BIGGE_THAN_NEW_ENTRIES') { + if ( + error.errorType === 'LOCATED_COST_ENTRIES_SHOULD_BIGGE_THAN_NEW_ENTRIES' + ) { return res.status(400).send({ errors: [ { @@ -456,6 +458,18 @@ export default class BillsController extends BaseController { ], }); } + if (error.errorType === 'LANDED_COST_ENTRIES_SHOULD_BE_INVENTORY_ITEMS') { + return res.status(400).send({ + errors: [ + { + type: 'LANDED_COST_ENTRIES_SHOULD_BE_INVENTORY_ITEMS', + message: + 'Landed cost entries should be only with inventory items.', + code: 1600, + }, + ], + }); + } } next(error); } diff --git a/server/src/interfaces/ItemEntry.ts b/server/src/interfaces/ItemEntry.ts index 3cb07e4a7..348e5875d 100644 --- a/server/src/interfaces/ItemEntry.ts +++ b/server/src/interfaces/ItemEntry.ts @@ -25,5 +25,6 @@ export interface IItemEntry { export interface IItemEntryDTO { id?: number, + itemId: number; landedCost?: boolean; } diff --git a/server/src/services/Entries/index.ts b/server/src/services/Entries/index.ts index b4277dabb..482fffa5a 100644 --- a/server/src/services/Entries/index.ts +++ b/server/src/services/Entries/index.ts @@ -17,16 +17,16 @@ const ERRORS = { export default class EntriesService { /** * Validates bill entries that has allocated landed cost amount not deleted. - * @param {IItemEntry[]} oldBillEntries - + * @param {IItemEntry[]} oldCommonEntries - * @param {IItemEntry[]} newBillEntries - */ public getLandedCostEntriesDeleted( - oldBillEntries: ICommonLandedCostEntry[], - newBillEntriesDTO: ICommonLandedCostEntryDTO[] + oldCommonEntries: ICommonLandedCostEntry[], + newCommonEntriesDTO: ICommonLandedCostEntryDTO[] ): ICommonLandedCostEntry[] { - const newBillEntriesById = transformToMap(newBillEntriesDTO, 'id'); + const newBillEntriesById = transformToMap(newCommonEntriesDTO, 'id'); - return oldBillEntries.filter((entry) => { + return oldCommonEntries.filter((entry) => { const newEntry = newBillEntriesById.get(entry.id); if (entry.allocatedCostAmount > 0 && typeof newEntry === 'undefined') { @@ -38,16 +38,16 @@ export default class EntriesService { /** * Validates the bill entries that have located cost amount should not be deleted. - * @param {IItemEntry[]} oldBillEntries - Old bill entries. + * @param {IItemEntry[]} oldCommonEntries - Old bill entries. * @param {IItemEntryDTO[]} newBillEntries - New DTO bill entries. */ public validateLandedCostEntriesNotDeleted( - oldBillEntries: ICommonLandedCostEntry[], - newBillEntriesDTO: ICommonLandedCostEntryDTO[] + oldCommonEntries: ICommonLandedCostEntry[], + newCommonEntriesDTO: ICommonLandedCostEntryDTO[] ): void { const entriesDeleted = this.getLandedCostEntriesDeleted( - oldBillEntries, - newBillEntriesDTO + oldCommonEntries, + newCommonEntriesDTO ); if (entriesDeleted.length > 0) { throw new ServiceError(ERRORS.ENTRIES_ALLOCATED_COST_COULD_NOT_DELETED); @@ -56,16 +56,16 @@ export default class EntriesService { /** * Validate allocated cost amount entries should be smaller than new entries amount. - * @param {IItemEntry[]} oldBillEntries - Old bill entries. + * @param {IItemEntry[]} oldCommonEntries - Old bill entries. * @param {IItemEntryDTO[]} newBillEntries - New DTO bill entries. */ public validateLocatedCostEntriesSmallerThanNewEntries( - oldBillEntries: ICommonLandedCostEntry[], - newBillEntriesDTO: ICommonLandedCostEntryDTO[] + oldCommonEntries: ICommonLandedCostEntry[], + newCommonEntriesDTO: ICommonLandedCostEntryDTO[] ): void { - const oldBillEntriesById = transformToMap(oldBillEntries, 'id'); + const oldBillEntriesById = transformToMap(oldCommonEntries, 'id'); - newBillEntriesDTO.forEach((entry) => { + newCommonEntriesDTO.forEach((entry) => { const oldEntry = oldBillEntriesById.get(entry.id); if (oldEntry && oldEntry.allocatedCostAmount > entry.amount) { diff --git a/server/src/services/Purchases/Bills.ts b/server/src/services/Purchases/Bills.ts index 7cd4dfe34..439cdfb74 100644 --- a/server/src/services/Purchases/Bills.ts +++ b/server/src/services/Purchases/Bills.ts @@ -13,7 +13,7 @@ import InventoryService from 'services/Inventory/Inventory'; import SalesInvoicesCost from 'services/Sales/SalesInvoicesCost'; import TenancyService from 'services/Tenancy/TenancyService'; import DynamicListingService from 'services/DynamicListing/DynamicListService'; -import { formatDateFields } from 'utils'; +import { formatDateFields, transformToMap } from 'utils'; import { IBillDTO, IBill, @@ -194,6 +194,36 @@ export default class BillsService } } + /** + * Validate transaction entries that have landed cost type should not be + * inventory items. + * @param {number} tenantId - + * @param {IItemEntryDTO[]} newEntriesDTO - + */ + public async validateCostEntriesShouldBeInventoryItems( + tenantId: number, + newEntriesDTO: IItemEntryDTO[] + ) { + const { Item } = this.tenancy.models(tenantId); + + const entriesItemsIds = newEntriesDTO.map((e) => e.itemId); + const entriesItems = await Item.query().whereIn('id', entriesItemsIds); + + const entriesItemsById = transformToMap(entriesItems, 'id'); + + // Filter the landed cost entries that not associated with inventory item. + const nonInventoryHasCost = newEntriesDTO.filter((entry) => { + const item = entriesItemsById.get(entry.itemId); + + return entry.landedCost && item.type !== 'inventory'; + }); + if (nonInventoryHasCost.length > 0) { + throw new ServiceError( + ERRORS.LANDED_COST_ENTRIES_SHOULD_BE_INVENTORY_ITEMS + ); + } + } + /** * Sets the default cost account to the bill entries. */ @@ -334,6 +364,10 @@ export default class BillsService tenantId, billDTO.entries ); + await this.validateCostEntriesShouldBeInventoryItems( + tenantId, + billDTO.entries, + ); this.logger.info('[bill] trying to create a new bill', { tenantId, billDTO, @@ -423,7 +457,7 @@ export default class BillsService // Validate landed cost entries that have allocated cost could not be deleted. await this.entriesService.validateLandedCostEntriesNotDeleted( oldBill.entries, - billObj.entries, + billObj.entries ); // Validate new landed cost entries should be bigger than new entries. await this.entriesService.validateLocatedCostEntriesSmallerThanNewEntries( diff --git a/server/src/services/Purchases/constants.ts b/server/src/services/Purchases/constants.ts index 251598385..be1874a86 100644 --- a/server/src/services/Purchases/constants.ts +++ b/server/src/services/Purchases/constants.ts @@ -12,5 +12,6 @@ export const ERRORS = { VENDOR_HAS_BILLS: 'VENDOR_HAS_BILLS', BILL_HAS_ASSOCIATED_LANDED_COSTS: 'BILL_HAS_ASSOCIATED_LANDED_COSTS', BILL_ENTRIES_ALLOCATED_COST_COULD_DELETED: 'BILL_ENTRIES_ALLOCATED_COST_COULD_DELETED', - LOCATED_COST_ENTRIES_SHOULD_BIGGE_THAN_NEW_ENTRIES: 'LOCATED_COST_ENTRIES_SHOULD_BIGGE_THAN_NEW_ENTRIES' + LOCATED_COST_ENTRIES_SHOULD_BIGGE_THAN_NEW_ENTRIES: 'LOCATED_COST_ENTRIES_SHOULD_BIGGE_THAN_NEW_ENTRIES', + LANDED_COST_ENTRIES_SHOULD_BE_INVENTORY_ITEMS: 'LANDED_COST_ENTRIES_SHOULD_BE_INVENTORY_ITEMS' };