import { Router, Request, Response, NextFunction } from 'express'; import { check, param, query, ValidationChain } from 'express-validator'; import { Inject, Service } from 'typedi'; import { IPaymentReceiveDTO } from 'interfaces'; import BaseController from 'api/controllers/BaseController'; import asyncMiddleware from 'api/middleware/asyncMiddleware'; import PaymentReceiveService from 'services/Sales/PaymentReceives/PaymentsReceives'; import PaymentReceivesPages from 'services/Sales/PaymentReceives/PaymentReceivesPages'; import DynamicListingService from 'services/DynamicListing/DynamicListService'; import { ServiceError } from 'exceptions'; /** * Payments receives controller. * @service */ @Service() export default class PaymentReceivesController extends BaseController { @Inject() paymentReceiveService: PaymentReceiveService; @Inject() PaymentReceivesPages: PaymentReceivesPages; @Inject() dynamicListService: DynamicListingService; /** * Router constructor. */ router() { const router = Router(); router.post( '/:id', this.editPaymentReceiveValidation, this.validationResult, asyncMiddleware(this.editPaymentReceive.bind(this)), this.handleServiceErrors ); router.post( '/', [...this.newPaymentReceiveValidation], this.validationResult, asyncMiddleware(this.newPaymentReceive.bind(this)), this.handleServiceErrors ); router.get( '/:id/edit-page', this.paymentReceiveValidation, this.validationResult, asyncMiddleware(this.getPaymentReceiveEditPage.bind(this)), this.handleServiceErrors ); router.get( '/new-page/entries', [query('customer_id').exists().isNumeric().toInt()], this.validationResult, asyncMiddleware(this.getPaymentReceiveNewPageEntries.bind(this)), this.getPaymentReceiveNewPageEntries.bind(this) ); router.get( '/:id/invoices', this.paymentReceiveValidation, this.validationResult, asyncMiddleware(this.getPaymentReceiveInvoices.bind(this)), this.handleServiceErrors ); router.get( '/:id', this.paymentReceiveValidation, this.asyncMiddleware(this.getPaymentReceive.bind(this)), this.handleServiceErrors ); router.get( '/', this.validatePaymentReceiveList, this.validationResult, asyncMiddleware(this.getPaymentReceiveList.bind(this)), this.handleServiceErrors, this.dynamicListService.handlerErrorsToResponse ); router.delete( '/:id', this.paymentReceiveValidation, this.validationResult, asyncMiddleware(this.deletePaymentReceive.bind(this)), this.handleServiceErrors ); return router; } /** * Payment receive schema. * @return {Array} */ get paymentReceiveSchema(): ValidationChain[] { return [ check('customer_id').exists().isNumeric().toInt(), check('payment_date').exists(), check('reference_no').optional(), check('deposit_account_id').exists().isNumeric().toInt(), check('payment_receive_no').optional({ nullable: true }).trim().escape(), check('statement').optional().trim().escape(), check('entries').isArray({ min: 1 }), check('entries.*.id').optional({ nullable: true }).isNumeric().toInt(), check('entries.*.invoice_id').exists().isNumeric().toInt(), check('entries.*.payment_amount').exists().isNumeric().toInt(), ]; } /** * Payment receive list validation schema. */ get validatePaymentReceiveList(): ValidationChain[] { return [ query('custom_view_id').optional().isNumeric().toInt(), query('stringified_filter_roles').optional().isJSON(), query('column_sort_by').optional(), query('sort_order').optional().isIn(['desc', 'asc']), query('page').optional().isNumeric().toInt(), query('page_size').optional().isNumeric().toInt(), ]; } /** * Validate payment receive parameters. */ get paymentReceiveValidation() { return [param('id').exists().isNumeric().toInt()]; } /** * New payment receive validation schema. * @return {Array} */ get newPaymentReceiveValidation() { return [...this.paymentReceiveSchema]; } /** * Edit payment receive validation. */ get editPaymentReceiveValidation() { return [ param('id').exists().isNumeric().toInt(), ...this.paymentReceiveSchema, ]; } /** * Records payment receive to the given customer with associated invoices. * @param {Request} req * @param {Response} res * @return {Response} */ async newPaymentReceive(req: Request, res: Response, next: NextFunction) { const { tenantId, user } = req; const paymentReceive: IPaymentReceiveDTO = this.matchedBodyData(req); try { const storedPaymentReceive = await this.paymentReceiveService.createPaymentReceive( tenantId, paymentReceive, user ); return res.status(200).send({ id: storedPaymentReceive.id, message: 'The payment receive has been created successfully.', }); } catch (error) { console.log(error); next(error); } } /** * Edit the given payment receive. * @param {Request} req * @param {Response} res * @return {Response} */ async editPaymentReceive(req: Request, res: Response, next: NextFunction) { const { tenantId, user } = req; const { id: paymentReceiveId } = req.params; const paymentReceive: IPaymentReceiveDTO = this.matchedBodyData(req); try { await this.paymentReceiveService.editPaymentReceive( tenantId, paymentReceiveId, paymentReceive, user ); return res.status(200).send({ id: paymentReceiveId, message: 'The payment receive has been edited successfully.', }); } catch (error) { next(error); } } /** * Delets the given payment receive id. * @param {Request} req * @param {Response} res */ async deletePaymentReceive(req: Request, res: Response, next: NextFunction) { const { tenantId, user } = req; const { id: paymentReceiveId } = req.params; try { await this.paymentReceiveService.deletePaymentReceive( tenantId, paymentReceiveId, user ); return res.status(200).send({ id: paymentReceiveId, message: 'The payment receive has been deleted successfully', }); } catch (error) { next(error); } } /** * Retrieve sale invoices that associated with the given payment receive. * @param {Request} req * @param {Response} res * @param {NextFunction} next */ async getPaymentReceiveInvoices( req: Request, res: Response, next: NextFunction ) { const { tenantId } = req; const { id: paymentReceiveId } = req.params; try { const invoices = await this.paymentReceiveService.getPaymentReceiveInvoices( tenantId, paymentReceiveId ); return res.status(200).send({ sale_invoices: invoices }); } catch (error) { next(error); } } /** * Retrieve payment receive list with pagination metadata. * @param {Request} req * @param {Response} res * @return {Response} */ async getPaymentReceiveList(req: Request, res: Response, next: NextFunction) { const { tenantId } = req; const filter = { filterRoles: [], sortOrder: 'asc', columnSortBy: 'created_at', page: 1, pageSize: 12, ...this.matchedQueryData(req), }; if (filter.stringifiedFilterRoles) { filter.filterRoles = JSON.parse(filter.stringifiedFilterRoles); } try { const { paymentReceives, pagination, filterMeta, } = await this.paymentReceiveService.listPaymentReceives( tenantId, filter ); return res.status(200).send({ payment_receives: paymentReceives, pagination: this.transfromToResponse(pagination), filter_meta: this.transfromToResponse(filterMeta), }); } catch (error) { next(error); } } /** * Retrieve payment receive new page receivable entries. * @param {Request} req - Request. * @param {Response} res - Response. */ async getPaymentReceiveNewPageEntries( req: Request, res: Response, next: NextFunction ) { const { tenantId } = req; const { customerId } = this.matchedQueryData(req); try { const entries = await this.PaymentReceivesPages.getNewPageEntries( tenantId, customerId ); return res.status(200).send({ entries: this.transfromToResponse(entries), }); } catch (error) { next(error); } } /** * Retrieve the given payment receive details. * @asycn * @param {Request} req - * @param {Response} res - */ async getPaymentReceiveEditPage( req: Request, res: Response, next: NextFunction ) { const { tenantId, user } = req; const { id: paymentReceiveId } = req.params; try { const { paymentReceive, entries, } = await this.PaymentReceivesPages.getPaymentReceiveEditPage( tenantId, paymentReceiveId, user ); return res.status(200).send({ payment_receive: this.transfromToResponse({ ...paymentReceive }), entries: this.transfromToResponse([...entries]), }); } catch (error) { next(error); } } /** * Retrieve the payment receive details. * @param {Request} req * @param {Response} res * @param {NextFunction} next */ async getPaymentReceive(req: Request, res: Response, next: NextFunction) { const { tenantId } = req; const { id: paymentReceiveId } = req.params; try { const paymentReceive = await this.paymentReceiveService.getPaymentReceive( tenantId, paymentReceiveId ); return res .status(200) .send({ payment_receive: this.transfromToResponse(paymentReceive) }); } catch (error) { next(error); } } /** * Handles service errors. * @param error * @param req * @param res * @param next */ handleServiceErrors( error: Error, req: Request, res: Response, next: NextFunction ) { if (error instanceof ServiceError) { if (error.errorType === 'DEPOSIT_ACCOUNT_NOT_FOUND') { return res.boom.badRequest(null, { errors: [{ type: 'DEPOSIT.ACCOUNT.NOT.EXISTS', code: 300 }], }); } if (error.errorType === 'PAYMENT_RECEIVE_NO_EXISTS') { return res.boom.badRequest(null, { errors: [{ type: 'PAYMENT_RECEIVE_NO_EXISTS', code: 300 }], }); } if (error.errorType === 'PAYMENT_RECEIVE_NOT_EXISTS') { return res.boom.badRequest(null, { errors: [{ type: 'PAYMENT_RECEIVE_NOT_EXISTS', code: 300 }], }); } if (error.errorType === 'DEPOSIT_ACCOUNT_INVALID_TYPE') { return res.boom.badRequest(null, { errors: [{ type: 'DEPOSIT_ACCOUNT_INVALID_TYPE', code: 300 }], }); } if (error.errorType === 'INVALID_PAYMENT_AMOUNT_INVALID') { return res.boom.badRequest(null, { errors: [{ type: 'INVALID_PAYMENT_AMOUNT', code: 300 }], }); } if (error.errorType === 'INVOICES_IDS_NOT_FOUND') { return res.boom.badRequest(null, { errors: [{ type: 'INVOICES_IDS_NOT_FOUND', code: 300 }], }); } if (error.errorType === 'ENTRIES_IDS_NOT_EXISTS') { return res.boom.badRequest(null, { errors: [{ type: 'ENTRIES_IDS_NOT_FOUND', code: 300 }], }); } if (error.errorType === 'contact_not_found') { return res.boom.badRequest(null, { errors: [{ type: 'CUSTOMER_NOT_FOUND', code: 300 }], }); } if (error.errorType === 'INVALID_PAYMENT_AMOUNT') { return res.boom.badRequest(null, { errors: [{ type: 'INVALID_PAYMENT_AMOUNT', code: 1000 }], }); } if (error.errorType === 'INVOICES_NOT_DELIVERED_YET') { return res.boom.badRequest(null, { errors: [ { type: 'INVOICES_NOT_DELIVERED_YET', code: 200, data: { not_delivered_invoices_ids: error.payload.notDeliveredInvoices.map( (invoice) => invoice.id ), }, }, ], }); } if (error.errorType === 'PAYMENT_RECEIVE_NO_IS_REQUIRED') { return res.boom.badRequest(null, { errors: [{ type: 'PAYMENT_RECEIVE_NO_IS_REQUIRED', code: 1100 }], }); } if (error.errorType === 'PAYMENT_CUSTOMER_SHOULD_NOT_UPDATE') { return res.boom.badRequest(null, { errors: [{ type: 'PAYMENT_CUSTOMER_SHOULD_NOT_UPDATE', code: 1200 }], }); } if (error.errorType === 'PAYMENT_RECEIVE_NO_REQUIRED') { return res.boom.badRequest(null, { errors: [{ type: 'PAYMENT_RECEIVE_NO_REQUIRED', code: 1300 }], }); } } next(error); } }