diff --git a/server/src/api/controllers/Sales/SalesEstimates.ts b/server/src/api/controllers/Sales/SalesEstimates.ts index f1cbef385..15ce01f3a 100644 --- a/server/src/api/controllers/Sales/SalesEstimates.ts +++ b/server/src/api/controllers/Sales/SalesEstimates.ts @@ -230,37 +230,47 @@ export default class SalesEstimatesController extends BaseController { if (error instanceof ServiceError) { if (error.errorType === 'ITEMS_NOT_FOUND') { return res.boom.badRequest(null, { - errors: [{ type: 'ITEMS.IDS.NOT.EXISTS', code: 400 }], + errors: [{ type: 'ITEMS.IDS.NOT.EXISTS', code: 100 }], }); } if (error.errorType === 'ENTRIES_IDS_NOT_FOUND') { return res.boom.badRequest(null, { - errors: [{ type: 'ENTRIES.IDS.NOT.EXISTS', code: 300 }], + errors: [{ type: 'ENTRIES.IDS.NOT.EXISTS', code: 200 }], }); } if (error.errorType === 'ITEMS_IDS_NOT_EXISTS') { return res.boom.badRequest(null, { - errors: [{ type: 'ITEMS.IDS.NOT.EXISTS', code: 200 }], + errors: [{ type: 'ITEMS.IDS.NOT.EXISTS', code: 300 }], }); } if (error.errorType === 'NOT_PURCHASE_ABLE_ITEMS') { return res.boom.badRequest(null, { - errors: [{ type: 'NOT_PURCHASABLE_ITEMS', code: 200 }], + errors: [{ type: 'NOT_PURCHASABLE_ITEMS', code: 400 }], }); } if (error.errorType === 'SALE_ESTIMATE_NOT_FOUND') { return res.boom.badRequest(null, { - errors: [{ type: 'SALE_ESTIMATE_NOT_FOUND', code: 200 }], + errors: [{ type: 'SALE_ESTIMATE_NOT_FOUND', code: 500 }], }); } if (error.errorType === 'CUSTOMER_NOT_FOUND') { return res.boom.badRequest(null, { - errors: [{ type: 'CUSTOMER_NOT_FOUND', code: 200 }], + errors: [{ type: 'CUSTOMER_NOT_FOUND', code: 600 }], }); } if (error.errorType === 'SALE_ESTIMATE_NUMBER_EXISTANCE') { return res.boom.badRequest(null, { - errors: [{ type: 'ESTIMATE.NUMBER.IS.NOT.UNQIUE', code: 300 }], + errors: [{ type: 'ESTIMATE.NUMBER.IS.NOT.UNQIUE', code: 700 }], + }); + } + if (error.errorType === 'NOT_SELL_ABLE_ITEMS') { + return res.boom.badRequest(null, { + 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: 900 }], }); } } diff --git a/server/src/services/Sales/SalesEstimate.ts b/server/src/services/Sales/SalesEstimate.ts index b2c4f03bd..f79d41ca1 100644 --- a/server/src/services/Sales/SalesEstimate.ts +++ b/server/src/services/Sales/SalesEstimate.ts @@ -19,7 +19,7 @@ const ERRORS = { CUSTOMER_NOT_FOUND: 'CUSTOMER_NOT_FOUND', SALE_ESTIMATE_NUMBER_EXISTANCE: 'SALE_ESTIMATE_NUMBER_EXISTANCE', ITEMS_IDS_NOT_EXISTS: 'ITEMS_IDS_NOT_EXISTS', -} +}; /** * Sale estimate service. * @Service @@ -97,14 +97,21 @@ export default class SaleEstimateService { amount, ...formatDateFields(estimateDTO, ['estimate_date', 'expiration_date']), }; + + // Validate estimate number uniquiness on the storage. await this.validateEstimateNumberExistance(tenantId, estimateDTO.estimateNumber); + + // Retrieve the given customer or throw not found service error. await this.customersService.getCustomer(tenantId, estimateDTO.customerId); + // Validate items IDs existance on the storage. await this.itemsEntriesService.validateItemsIdsExistance(tenantId, estimateDTO.entries); + + // Validate non-sellable items. await this.itemsEntriesService.validateNonSellableEntriesItems(tenantId, estimateDTO.entries); const saleEstimate = await SaleEstimate.query() - .upsertGraph({ + .upsertGraphAndFetch({ ...omit(estimateObj, ['entries']), entries: estimateObj.entries.map((entry) => ({ reference_type: 'SaleEstimate', @@ -135,19 +142,29 @@ export default class SaleEstimateService { amount, ...formatDateFields(estimateDTO, ['estimate_date', 'expiration_date']), }; + + // Validate estimate number uniquiness on the storage. await this.validateEstimateNumberExistance(tenantId, estimateDTO.estimateNumber, estimateId); + + // Retrieve the given customer or throw not found service error. await this.customersService.getCustomer(tenantId, estimateDTO.customerId); + // Validate sale estimate entries existance. await this.itemsEntriesService.validateEntriesIdsExistance(tenantId, estimateId, 'SaleEstiamte', estimateDTO.entries); + + // Validate items IDs existance on the storage. await this.itemsEntriesService.validateItemsIdsExistance(tenantId, estimateDTO.entries); + + // Validate non-sellable items. await this.itemsEntriesService.validateNonSellableEntriesItems(tenantId, estimateDTO.entries); this.logger.info('[sale_estimate] editing sale estimate on the storage.'); const saleEstimate = await SaleEstimate.query() - .upsertGraph({ + .upsertGraphAndFetch({ id: estimateId, ...omit(estimateObj, ['entries']), entries: estimateObj.entries.map((entry) => ({ + reference_type: 'SaleEstimate', ...omit(entry, ['total', 'amount']), })), }); @@ -155,6 +172,8 @@ export default class SaleEstimateService { await this.eventDispatcher.dispatch(events.saleEstimates.onEdited, { tenantId, estimateId, saleEstimate, oldSaleEstimate, }); + this.logger.info('[sale_estiamte] edited successfully', { tenantId, estimateId }); + return saleEstimate; } @@ -168,6 +187,7 @@ export default class SaleEstimateService { public async deleteEstimate(tenantId: number, estimateId: number): Promise { const { SaleEstimate, ItemEntry } = this.tenancy.models(tenantId); + // Retrieve sale estimate or throw not found service error. const oldSaleEstimate = await this.getSaleEstimateOrThrowError(tenantId, estimateId); this.logger.info('[sale_estimate] delete sale estimate and associated entries from the storage.');