From 34377c8e5373408c2738032c35efc2739d18ca27 Mon Sep 17 00:00:00 2001 From: "a.bouhuolia" Date: Fri, 6 Aug 2021 14:03:55 +0200 Subject: [PATCH] feat: activate/inactive contacts. --- .../src/api/controllers/Contacts/Contacts.ts | 93 ++++++++++++++++++- .../src/services/Contacts/ContactsService.ts | 35 ++++++- server/src/services/Contacts/constants.ts | 7 ++ 3 files changed, 130 insertions(+), 5 deletions(-) diff --git a/server/src/api/controllers/Contacts/Contacts.ts b/server/src/api/controllers/Contacts/Contacts.ts index bc8354e3b..26749902f 100644 --- a/server/src/api/controllers/Contacts/Contacts.ts +++ b/server/src/api/controllers/Contacts/Contacts.ts @@ -1,7 +1,7 @@ import { check, param, query, body, ValidationChain } from 'express-validator'; import { Router, Request, Response, NextFunction } from 'express'; import { Inject, Service } from 'typedi'; -import * as R from 'ramda'; +import { ServiceError } from 'exceptions'; import BaseController from 'api/controllers/BaseController'; import ContactsService from 'services/Contacts/ContactsService'; import DynamicListingService from 'services/DynamicListing/DynamicListService'; @@ -34,6 +34,20 @@ export default class ContactsController extends BaseController { this.validationResult, this.asyncMiddleware(this.getContact.bind(this)) ); + router.post( + '/:id/inactivate', + [param('id').exists().isNumeric().toInt()], + this.validationResult, + this.asyncMiddleware(this.inactivateContact.bind(this)), + this.handlerServiceErrors + ); + router.post( + '/:id/activate', + [param('id').exists().isNumeric().toInt()], + this.validationResult, + this.asyncMiddleware(this.activateContact.bind(this)), + this.handlerServiceErrors + ); return router; } @@ -302,4 +316,81 @@ export default class ContactsController extends BaseController { get specificContactSchema(): ValidationChain[] { return [param('id').exists().isNumeric().toInt()]; } + + /** + * Activates the given contact. + * @param {Request} req + * @param {Response} res + * @param {NextFunction} next + */ + async activateContact(req: Request, res: Response, next: NextFunction) { + const { tenantId } = req; + const { id: contactId } = req.params; + + try { + await this.contactsService.activateContact(tenantId, contactId); + + return res.status(200).send({ + id: contactId, + message: 'The given contact activated successfully.', + }); + } catch (error) { + next(error); + } + } + + /** + * Inactivate the given contact. + * @param {Request} req + * @param {Response} res + * @param {NextFunction} next + */ + async inactivateContact(req: Request, res: Response, next: NextFunction) { + const { tenantId } = req; + const { id: contactId } = req.params; + + try { + await this.contactsService.inactivateContact(tenantId, contactId); + + return res.status(200).send({ + id: contactId, + message: 'The given contact inactivated successfully.', + }); + } catch (error) { + next(error); + } + } + + /** + * Handles service errors. + * @param {Error} error + * @param {Request} req + * @param {Response} res + * @param {NextFunction} next + */ + private handlerServiceErrors( + error: Error, + req: Request, + res: Response, + next: NextFunction + ) { + if (error instanceof ServiceError) { + if (error.errorType === 'contact_not_found') { + return res.boom.badRequest(null, { + errors: [{ type: 'CONTACT.NOT.FOUND', code: 100 }], + }); + } + if (error.errorType === 'CONTACT_ALREADY_ACTIVE') { + return res.boom.badRequest(null, { + errors: [{ type: 'CONTACT_ALREADY_ACTIVE', code: 700 }], + }); + } + if (error.errorType === 'CONTACT_ALREADY_INACTIVE') { + return res.boom.badRequest(null, { + errors: [{ type: 'CONTACT_ALREADY_INACTIVE', code: 800 }], + }); + } + } + next(error); + } } diff --git a/server/src/services/Contacts/ContactsService.ts b/server/src/services/Contacts/ContactsService.ts index 718692fed..f7a19d3ac 100644 --- a/server/src/services/Contacts/ContactsService.ts +++ b/server/src/services/Contacts/ContactsService.ts @@ -12,13 +12,10 @@ import { IContactsAutoCompleteFilter, } from 'interfaces'; import JournalPoster from '../Accounting/JournalPoster'; +import { ERRORS } from './constants'; type TContactService = 'customer' | 'vendor'; -const ERRORS = { - OPENING_BALANCE_DATE_REQUIRED: 'OPENING_BALANCE_DATE_REQUIRED', -}; - @Service() export default class ContactsService { @Inject() @@ -361,4 +358,34 @@ export default class ContactsService { } ); } + + /** + * Inactive the given contact. + * @param {number} tenantId - Tenant id. + * @param {number} contactId - Contact id. + */ + async inactivateContact(tenantId: number, contactId: number): Promise { + const { Contact } = this.tenancy.models(tenantId); + const contact = await this.getContactByIdOrThrowError(tenantId, contactId); + + if(!contact.active) { + throw new ServiceError(ERRORS.CONTACT_ALREADY_INACTIVE); + } + await Contact.query().findById(contactId).update({ active: false }); + } + + /** + * Inactive the given contact. + * @param {number} tenantId - Tenant id. + * @param {number} contactId - Contact id. + */ + async activateContact(tenantId: number, contactId: number): Promise { + const { Contact } = this.tenancy.models(tenantId); + const contact = await this.getContactByIdOrThrowError(tenantId, contactId); + + if(contact.active) { + throw new ServiceError(ERRORS.CONTACT_ALREADY_ACTIVE); + } + await Contact.query().findById(contactId).update({ active: true }); + } } diff --git a/server/src/services/Contacts/constants.ts b/server/src/services/Contacts/constants.ts index a40f96a00..3bfb8771e 100644 --- a/server/src/services/Contacts/constants.ts +++ b/server/src/services/Contacts/constants.ts @@ -20,3 +20,10 @@ export const DEFAULT_VIEWS = [ columns: DEFAULT_VIEW_COLUMNS, }, ]; + + +export const ERRORS = { + OPENING_BALANCE_DATE_REQUIRED: 'OPENING_BALANCE_DATE_REQUIRED', + CONTACT_ALREADY_INACTIVE: 'CONTACT_ALREADY_INACTIVE', + CONTACT_ALREADY_ACTIVE: 'CONTACT_ALREADY_ACTIVE' +};