diff --git a/server/src/api/controllers/Purchases/Bills.ts b/server/src/api/controllers/Purchases/Bills.ts index 10b48df6a..26af691c2 100644 --- a/server/src/api/controllers/Purchases/Bills.ts +++ b/server/src/api/controllers/Purchases/Bills.ts @@ -47,6 +47,14 @@ export default class BillsController extends BaseController { asyncMiddleware(this.editBill.bind(this)), this.handleServiceError, ); + router.get( + '/due', [ + ...this.dueBillsListingValidationSchema + ], + this.validationResult, + asyncMiddleware(this.getDueBills.bind(this)), + this.handleServiceError, + ) router.get( '/:id', [ ...this.specificBillValidationSchema, @@ -139,6 +147,12 @@ export default class BillsController extends BaseController { query('sort_order').optional().isIn(['desc', 'asc']), ]; } + + get dueBillsListingValidationSchema() { + return [ + query('vendor_id').optional().trim().escape(), + ] + } /** * Creates a new bill and records journal transactions. @@ -255,6 +269,24 @@ export default class BillsController extends BaseController { } } + /** + * Listing all due bills of the given vendor. + * @param {Request} req + * @param {Response} res + * @param {NextFunction} next + */ + public async getDueBills(req: Request, res: Response, next: NextFunction) { + const { tenantId } = req; + const { vendorId } = this.matchedQueryData(req); + + try { + const bills = await this.billsService.getDueBills(tenantId, vendorId); + return res.status(200).send({ bills }); + } catch (error) { + next(error); + } + } + /** * Handles service errors. * @param {Error} error diff --git a/server/src/api/controllers/Sales/SalesInvoices.ts b/server/src/api/controllers/Sales/SalesInvoices.ts index 0f5e1dcf0..a4b07bd97 100644 --- a/server/src/api/controllers/Sales/SalesInvoices.ts +++ b/server/src/api/controllers/Sales/SalesInvoices.ts @@ -52,9 +52,11 @@ export default class SaleInvoicesController extends BaseController{ this.handleServiceErrors, ); router.get( - '/due_invoices', - this.dueSalesInvoicesListValidationSchema, - asyncMiddleware(this.getDueSalesInvoice.bind(this)), + '/due', [ + ...this.dueSalesInvoicesListValidationSchema, + ], + this.validationResult, + asyncMiddleware(this.getDueInvoices.bind(this)), this.handleServiceErrors, ); router.get( @@ -210,40 +212,6 @@ export default class SaleInvoicesController extends BaseController{ next(error); } } - - /** - * Retrieve the due sales invoices for the given customer. - * @param {Request} req - * @param {Response} res - */ - async getDueSalesInvoice(req: Request, res: Response) { - const { Customer, SaleInvoice } = req.models; - const { tenantId } = req; - - const filter = { - customer_id: null, - ...req.query, - }; - if (filter.customer_id) { - const foundCustomer = await Customer.query().findById(filter.customer_id); - - if (!foundCustomer) { - return res.status(200).send({ - errors: [{ type: 'CUSTOMER.NOT.FOUND', code: 200 }], - }); - } - } - const dueSalesInvoices = await SaleInvoice.query().onBuild((query) => { - query.where(raw('BALANCE - PAYMENT_AMOUNT > 0')); - if (filter.customer_id) { - query.where('customer_id', filter.customer_id); - } - }); - return res.status(200).send({ - due_sales_invoices: dueSalesInvoices, - }); - } - /** * Retrieve paginated sales invoices with custom view metadata. * @param {Request} req @@ -276,6 +244,28 @@ export default class SaleInvoicesController extends BaseController{ } } + /** + * Retrieve due sales invoices. + * @param {Request} req - + * @param {Response} res - + * @param {NextFunction} next - + * @return {Response|void} + */ + public async getDueInvoices(req: Request, res: Response, next: NextFunction) { + const { tenantId } = req; + const { customerId } = this.matchedQueryData(req); + + try { + const salesInvoices = await this.saleInvoiceService.getDueInvoices(tenantId, customerId); + + return res.status(200).send({ + sales_invoices: this.transfromToResponse(salesInvoices), + }); + } catch (error) { + next(error); + } + } + /** * Handles service errors. * @param {Error} error diff --git a/server/src/models/Bill.js b/server/src/models/Bill.js index c7bbfa032..26c0b88f2 100644 --- a/server/src/models/Bill.js +++ b/server/src/models/Bill.js @@ -1,4 +1,4 @@ -import { Model } from 'objection'; +import { Model, raw } from 'objection'; import { difference } from 'lodash'; import TenantModel from 'models/TenantModel'; @@ -21,6 +21,14 @@ export default class Bill extends TenantModel { return true; } + static get modifiers() { + return { + dueBills(query) { + query.where(raw('AMOUNT - PAYMENT_AMOUNT > 0')); + } + } + } + /** * Timestamps columns. */ diff --git a/server/src/models/SaleInvoice.js b/server/src/models/SaleInvoice.js index b8ab76fdc..e05da70e0 100644 --- a/server/src/models/SaleInvoice.js +++ b/server/src/models/SaleInvoice.js @@ -1,4 +1,4 @@ -import { Model, mixin } from 'objection'; +import { Model, raw } from 'objection'; import moment from 'moment'; import TenantModel from 'models/TenantModel'; @@ -33,6 +33,10 @@ export default class SaleInvoice extends TenantModel { */ static get modifiers() { return { + dueInvoices(query) { + query.where(raw('BALANCE - PAYMENT_AMOUNT > 0')); + }, + filterDateRange(query, startDate, endDate, type = 'day') { const dateFormat = 'YYYY-MM-DD HH:mm:ss'; const fromDate = moment(startDate).startOf(type).format(dateFormat); diff --git a/server/src/services/Purchases/Bills.ts b/server/src/services/Purchases/Bills.ts index 1ed75445f..6aebb2a02 100644 --- a/server/src/services/Purchases/Bills.ts +++ b/server/src/services/Purchases/Bills.ts @@ -27,6 +27,7 @@ import { import { ServiceError } from 'exceptions'; import ItemsService from 'services/Items/ItemsService'; import ItemsEntriesService from 'services/Items/ItemsEntriesService'; +import { Bill } from 'models'; const ERRORS = { BILL_NOT_FOUND: 'BILL_NOT_FOUND', @@ -135,7 +136,7 @@ export default class BillsService extends SalesInvoicesCost { * * @returns {IBill} */ - private async billDTOToModel(tenantId: number, billDTO: IBillDTO|IBillEditDTO, oldBill?: IBill) { + private async billDTOToModel(tenantId: number, billDTO: IBillDTO | IBillEditDTO, oldBill?: IBill) { const { ItemEntry } = this.tenancy.models(tenantId); let invLotNumber = oldBill?.invLotNumber; @@ -415,6 +416,27 @@ export default class BillsService extends SalesInvoicesCost { }; } + /** + * Retrieve all due bills or for specific given vendor id. + * @param {number} tenantId - + * @param {number} vendorId - + */ + public async getDueBills( + tenantId: number, + vendorId?: number + ): Promise { + const { Bill } = this.tenancy.models(tenantId); + + const dueBills = await Bill.query().onBuild((query) => { + query.modify('dueBills'); + + if (vendorId) { + query.where('vendor_id', vendorId); + } + }); + return dueBills; + } + /** * Retrieve the given bill details with associated items entries. * @param {Integer} billId - Specific bill. diff --git a/server/src/services/Sales/SalesInvoices.ts b/server/src/services/Sales/SalesInvoices.ts index e2560b1b6..99267a2df 100644 --- a/server/src/services/Sales/SalesInvoices.ts +++ b/server/src/services/Sales/SalesInvoices.ts @@ -407,4 +407,25 @@ export default class SaleInvoicesService extends SalesInvoicesCost { filterMeta: dynamicFilter.getResponseMeta(), }; } + + /** + * Retrieve due sales invoices. + * @param {number} tenantId + * @param {number} customerId + */ + public async getDueInvoices( + tenantId: number, + customerId?: number, + ): Promise { + const { SaleInvoice } = this.tenancy.models(tenantId); + + const salesInvoices = await SaleInvoice.query().onBuild((query) => { + query.modify('dueInvoices'); + + if (customerId) { + query.where('customer_id', customerId); + } + }); + return salesInvoices; + } }