From b91c4521018fa2ae945ac6dea7bc65823d6ef978 Mon Sep 17 00:00:00 2001 From: Ahmed Bouhuolia Date: Sat, 24 Oct 2020 14:49:32 +0200 Subject: [PATCH] feat: issues in bills and payments made --- server/src/api/controllers/Purchases/Bills.ts | 14 ++- server/src/interfaces/Bill.ts | 8 +- server/src/interfaces/ItemEntry.ts | 2 + server/src/models/Bill.js | 2 +- server/src/services/Purchases/BillPayments.ts | 2 + server/src/services/Purchases/Bills.ts | 86 ++++++++++--------- 6 files changed, 67 insertions(+), 47 deletions(-) diff --git a/server/src/api/controllers/Purchases/Bills.ts b/server/src/api/controllers/Purchases/Bills.ts index 12229475c..0b5950944 100644 --- a/server/src/api/controllers/Purchases/Bills.ts +++ b/server/src/api/controllers/Purchases/Bills.ts @@ -44,7 +44,8 @@ export default class BillsController extends BaseController { ...this.specificBillValidationSchema, ], this.validationResult, - asyncMiddleware(this.editBill.bind(this)) + asyncMiddleware(this.editBill.bind(this)), + this.handleServiceError, ); router.get( '/:id', [ @@ -101,10 +102,10 @@ export default class BillsController extends BaseController { */ get billEditValidationSchema() { return [ - // check('bill_number').exists().trim().escape(), + check('bill_number').exists().trim().escape(), check('bill_date').exists().isISO8601(), check('due_date').optional().isISO8601(), - // check('vendor_id').exists().isNumeric().toInt(), + check('vendor_id').exists().isNumeric().toInt(), check('note').optional().trim().escape(), check('entries').isArray({ min: 1 }), @@ -186,7 +187,7 @@ export default class BillsController extends BaseController { const { id: billId } = req.params; try { - const bill = await this.billsService.getBillWithMetadata(tenantId, billId); + const bill = await this.billsService.getBill(tenantId, billId); return res.status(200).send({ bill }); } catch (error) { @@ -286,6 +287,11 @@ export default class BillsController extends BaseController { errors: [{ type: 'ITEMS.IDS.NOT.FOUND', code: 400 }], }); } + if (error.errorType === 'BILL_ENTRIES_IDS_NOT_FOUND') { + return res.status(400).send({ + errors: [{ type: 'BILL_ENTRIES_IDS_NOT_FOUND', code: 900 }], + }); + } } next(error); } diff --git a/server/src/interfaces/Bill.ts b/server/src/interfaces/Bill.ts index 2b73a8295..4c47c97dc 100644 --- a/server/src/interfaces/Bill.ts +++ b/server/src/interfaces/Bill.ts @@ -1,3 +1,4 @@ +import { IDynamicListFilterDTO } from "./DynamicFilter"; import { IItemEntry, IItemEntryDTO } from "./ItemEntry"; export interface IBillDTO { @@ -14,6 +15,8 @@ export interface IBillDTO { }; export interface IBillEditDTO { + vendorId: number, + billNumber: string, billDate: Date, dueDate: Date, referenceNo: string, @@ -42,7 +45,6 @@ export interface IBill { entries: IItemEntry[], }; -export interface IBillsFilter { - page: number, - pageSize: number, +export interface IBillsFilter extends IDynamicListFilterDTO { + stringifiedFilterRoles?: string, } \ No newline at end of file diff --git a/server/src/interfaces/ItemEntry.ts b/server/src/interfaces/ItemEntry.ts index eed0cb7fd..1cd7d6959 100644 --- a/server/src/interfaces/ItemEntry.ts +++ b/server/src/interfaces/ItemEntry.ts @@ -1,6 +1,8 @@ export interface IItemEntry { + id?: number, + referenceType: string, referenceId: number, diff --git a/server/src/models/Bill.js b/server/src/models/Bill.js index 82bbd3524..5520aadec 100644 --- a/server/src/models/Bill.js +++ b/server/src/models/Bill.js @@ -64,7 +64,7 @@ export default class Bill extends TenantModel { to: 'items_entries.referenceId', }, filter(builder) { - builder.where('reference_type', 'SaleReceipt'); + builder.where('reference_type', 'Bill'); }, }, }; diff --git a/server/src/services/Purchases/BillPayments.ts b/server/src/services/Purchases/BillPayments.ts index 9d230efbf..59ee8b162 100644 --- a/server/src/services/Purchases/BillPayments.ts +++ b/server/src/services/Purchases/BillPayments.ts @@ -284,6 +284,7 @@ export default class BillPaymentsService { * - Re-insert the journal transactions and update the diff accounts balance. * - Update the diff vendor balance. * - Update the diff bill payment amount. + * ------ * @param {number} tenantId - Tenant id * @param {Integer} billPaymentId * @param {BillPaymentDTO} billPayment @@ -313,6 +314,7 @@ export default class BillPaymentsService { .upsertGraph({ id: billPaymentId, ...omit(billPaymentObj, ['entries']), + entries: billPaymentDTO.entries, }); await this.eventDispatcher.dispatch(events.billPayments.onEdited); this.logger.info('[bill_payment] edited successfully.', { tenantId, billPaymentId, billPayment, oldPaymentMade }); diff --git a/server/src/services/Purchases/Bills.ts b/server/src/services/Purchases/Bills.ts index 923ad754e..eb3be857c 100644 --- a/server/src/services/Purchases/Bills.ts +++ b/server/src/services/Purchases/Bills.ts @@ -133,9 +133,13 @@ export default class BillsService extends SalesInvoicesCost { * @param {Response} res * @param {Function} next */ - private async validateBillNumberExists(tenantId: number, billNumber: string) { + private async validateBillNumberExists(tenantId: number, billNumber: string, notBillId?: number) { const { Bill } = this.tenancy.models(tenantId); - const foundBills = await Bill.query().where('bill_number', billNumber); + const foundBills = await Bill.query().where('bill_number', billNumber).onBuild((builder) => { + if (notBillId) { + builder.whereNot('id', notBillId); + } + }); if (foundBills.length > 0) { throw new ServiceError(ERRORS.BILL_NUMBER_EXISTS); @@ -144,13 +148,15 @@ export default class BillsService extends SalesInvoicesCost { /** * Validates the entries ids existance on the storage. - * @param {Request} req - * @param {Response} res - * @param {Function} next + * @param {number} tenantId - + * @param {number} billId - + * @param {IItemEntry[]} billEntries - */ - async validateEntriesIdsExistance(tenantId: number, billId: number, billEntries: any) { + private async validateEntriesIdsExistance(tenantId: number, billId: number, billEntries: IItemEntryDTO[]) { const { ItemEntry } = this.tenancy.models(tenantId); - const entriesIds = billEntries.filter((e) => e.id).map((e) => e.id); + const entriesIds = billEntries + .filter((e: IItemEntry) => e.id) + .map((e: IItemEntry) => e.id); const storedEntries = await ItemEntry.query() .whereIn('reference_id', [billId]) @@ -170,9 +176,9 @@ export default class BillsService extends SalesInvoicesCost { * @param {Response} res * @param {Function} next */ - private async validateNonPurchasableEntriesItems(tenantId: number, billEntries: any) { + private async validateNonPurchasableEntriesItems(tenantId: number, billEntries: IItemEntryDTO[]) { const { Item } = this.tenancy.models(tenantId); - const itemsIds = billEntries.map((e: IItemEntry) => e.itemId); + const itemsIds = billEntries.map((e: IItemEntryDTO) => e.itemId); const purchasbleItems = await Item.query() .where('purchasable', true) @@ -194,7 +200,7 @@ export default class BillsService extends SalesInvoicesCost { * * @returns {IBill} */ - private async billDTOToModel(tenantId: number, billDTO: IBillDTO, oldBill?: IBill) { + private async billDTOToModel(tenantId: number, billDTO: IBillDTO|IBillEditDTO, oldBill?: IBill) { const { ItemEntry } = this.tenancy.models(tenantId); let invLotNumber = oldBill?.invLotNumber; @@ -293,18 +299,26 @@ export default class BillsService extends SalesInvoicesCost { const oldBill = await this.getBillOrThrowError(tenantId, billId); const billObj = this.billDTOToModel(tenantId, billDTO, oldBill); + await this.getVendorOrThrowError(tenantId, billDTO.vendorId); + await this.validateBillNumberExists(tenantId, billDTO.billNumber, billId); + + await this.validateEntriesIdsExistance(tenantId, billId, billDTO.entries); + await this.validateItemsIdsExistance(tenantId, billDTO.entries); + await this.validateNonPurchasableEntriesItems(tenantId, billDTO.entries); + // Update the bill transaction. - const bill = await Bill.query() - .upsertGraph({ - id: billId, - ...omit(billObj, ['entries', 'invLotNumber']), - entries: billDTO.entries.map((entry) => ({ - reference_type: 'Bill', - ...omit(entry, ['amount']), - })) - }); + const bill = await Bill.query().upsertGraph({ + id: billId, + ...omit(billObj, ['entries', 'invLotNumber']), + + entries: billDTO.entries.map((entry) => ({ + reference_type: 'Bill', + ...omit(entry, ['amount']), + })) + }); // Triggers event `onBillEdited`. await this.eventDispatcher.dispatch(events.bills.onEdited, { tenantId, billId, oldBill, bill }); + this.logger.info('[bill] bill upserted successfully.', { tenantId, billId }); return bill; } @@ -339,7 +353,7 @@ export default class BillsService extends SalesInvoicesCost { * @param {Bill} bill * @param {number} billId */ - recordInventoryTransactions( + public recordInventoryTransactions( tenantId: number, bill: any, billId: number, @@ -367,7 +381,7 @@ export default class BillsService extends SalesInvoicesCost { * @param {IBill} bill * @param {Integer} billId */ - async recordJournalTransactions(tenantId: number, bill: IBill, billId?: number) { + public async recordJournalTransactions(tenantId: number, bill: IBill, billId?: number) { const { AccountTransaction, Item, ItemEntry } = this.tenancy.models(tenantId); const { accountRepository } = this.tenancy.repositories(tenantId); @@ -457,27 +471,21 @@ export default class BillsService extends SalesInvoicesCost { /** * Retrieve the given bill details with associated items entries. - * @param {Integer} billId - - * @returns {Promise} + * @param {Integer} billId - Specific bill. + * @returns {Promise} */ - getBill(tenantId: number, billId: number) { - const { Bill } = this.tenancy.models(tenantId); - return Bill.query().findById(billId).withGraphFetched('entries'); - } - - /** - * Retrieve the given bill details with associated items entries. - * @param {Integer} billId - - * @returns {Promise} - */ - getBillWithMetadata(tenantId: number, billId: number) { + public async getBill(tenantId: number, billId: number): Promise { const { Bill } = this.tenancy.models(tenantId); - return Bill.query() - .where('id', billId) + this.logger.info('[bills] trying to fetch specific bill with metadata.', { tenantId, billId }); + const bill = await Bill.query().findById(billId) .withGraphFetched('vendor') - .withGraphFetched('entries') - .first(); + .withGraphFetched('entries'); + + if (!bill) { + throw new ServiceError(ERRORS.BILL_NOT_FOUND); + } + return bill; } /** @@ -486,7 +494,7 @@ export default class BillsService extends SalesInvoicesCost { * @param {IBill} bill - * @return {Promise} */ - async scheduleComputeBillItemsCost(tenantId: number, bill) { + public async scheduleComputeBillItemsCost(tenantId: number, bill) { const { Item } = this.tenancy.models(tenantId); const billItemsIds = bill.entries.map((entry) => entry.item_id);