refactor: currencies service.

refactor: exchange rates service.
This commit is contained in:
Ahmed Bouhuolia
2020-09-26 16:23:57 +02:00
parent 986cd6b7a0
commit 933afb37bf
25 changed files with 878 additions and 401 deletions

View File

@@ -85,6 +85,7 @@ export default class AccountsController extends BaseController{
router.delete(
'/',
this.bulkDeleteSchema,
this.validationResult,
asyncMiddleware(this.deleteBulkAccounts.bind(this)),
this.catchServiceErrors,
);
@@ -144,6 +145,9 @@ export default class AccountsController extends BaseController{
];
}
/**
*
*/
get bulkDeleteSchema() {
return [
query('ids').isArray({ min: 2 }),

View File

@@ -5,10 +5,19 @@ import { mapKeysDeep } from 'utils'
export default class BaseController {
/**
* Converts plain object keys to cameCase style.
* @param {Object} data
*/
private dataToCamelCase(data) {
return mapKeysDeep(data, (v, k) => camelCase(k));
}
/**
* Matches the body data from validation schema.
* @param {Request} req
* @param options
*/
matchedBodyData(req: Request, options: any = {}) {
const data = matchedData(req, {
locations: ['body'],
@@ -18,6 +27,10 @@ export default class BaseController {
return this.dataToCamelCase(data);
}
/**
* Matches the query data from validation schema.
* @param {Request} req
*/
matchedQueryData(req: Request) {
const data = matchedData(req, {
locations: ['query'],
@@ -25,6 +38,12 @@ export default class BaseController {
return this.dataToCamelCase(data);
}
/**
* Validate validation schema middleware.
* @param {Request} req
* @param {Response} res
* @param {NextFunction} next
*/
validationResult(req: Request, res: Response, next: NextFunction) {
const validationErrors = validationResult(req);

View File

@@ -1,12 +1,11 @@
import { check, param, query } from 'express-validator';
import { check, param, query, ValidationChain } from 'express-validator';
import BaseController from "api/controllers/BaseController";
export default class ContactsController extends BaseController {
/**
* Contact DTO schema.
* @returns {ValidationChain[]}
*/
get contactDTOSchema() {
get contactDTOSchema(): ValidationChain[] {
return [
check('first_name').optional().trim().escape(),
check('last_name').optional().trim().escape(),
@@ -39,8 +38,9 @@ export default class ContactsController extends BaseController {
/**
* Contact new DTO schema.
* @returns {ValidationChain[]}
*/
get contactNewDTOSchema() {
get contactNewDTOSchema(): ValidationChain[] {
return [
check('balance').optional().isNumeric().toInt(),
];
@@ -48,20 +48,27 @@ export default class ContactsController extends BaseController {
/**
* Contact edit DTO schema.
* @returns {ValidationChain[]}
*/
get contactEditDTOSchema() {
get contactEditDTOSchema(): ValidationChain[] {
return [
]
}
get specificContactSchema() {
/**
* @returns {ValidationChain[]}
*/
get specificContactSchema(): ValidationChain[] {
return [
param('id').exists().isNumeric().toInt(),
];
}
get bulkContactsSchema() {
/**
* @returns {ValidationChain[]}
*/
get bulkContactsSchema(): ValidationChain[] {
return [
query('ids').isArray({ min: 2 }),
query('ids.*').isNumeric().toInt(),

View File

@@ -19,36 +19,36 @@ export default class CustomersController extends ContactsController {
const router = Router();
router.post('/', [
...this.contactDTOSchema,
...this.contactNewDTOSchema,
...this.customerDTOSchema,
],
...this.contactDTOSchema,
...this.contactNewDTOSchema,
...this.customerDTOSchema,
],
this.validationResult,
asyncMiddleware(this.newCustomer.bind(this))
);
router.post('/:id', [
...this.contactDTOSchema,
...this.contactEditDTOSchema,
...this.customerDTOSchema,
],
...this.contactDTOSchema,
...this.contactEditDTOSchema,
...this.customerDTOSchema,
],
this.validationResult,
asyncMiddleware(this.editCustomer.bind(this))
);
router.delete('/:id', [
...this.specificContactSchema,
],
...this.specificContactSchema,
],
this.validationResult,
asyncMiddleware(this.deleteCustomer.bind(this))
);
router.delete('/', [
...this.bulkContactsSchema,
],
...this.bulkContactsSchema,
],
this.validationResult,
asyncMiddleware(this.deleteBulkCustomers.bind(this))
);
router.get('/:id', [
...this.specificContactSchema,
],
...this.specificContactSchema,
],
this.validationResult,
asyncMiddleware(this.getCustomer.bind(this))
);

View File

@@ -1,6 +1,6 @@
import { Request, Response, Router, NextFunction } from 'express';
import { Service, Inject } from 'typedi';
import { check, query } from 'express-validator';
import { check, query, ValidationChain } from 'express-validator';
import ContactsController from 'api/controllers/Contacts/Contacts';
import VendorsService from 'services/Contacts/VendorsService';
import { ServiceError } from 'exceptions';
@@ -19,42 +19,42 @@ export default class VendorsController extends ContactsController {
const router = Router();
router.post('/', [
...this.contactDTOSchema,
...this.contactNewDTOSchema,
...this.vendorDTOSchema,
],
...this.contactDTOSchema,
...this.contactNewDTOSchema,
...this.vendorDTOSchema,
],
this.validationResult,
asyncMiddleware(this.newVendor.bind(this))
);
router.post('/:id', [
...this.contactDTOSchema,
...this.contactEditDTOSchema,
...this.vendorDTOSchema,
],
...this.contactDTOSchema,
...this.contactEditDTOSchema,
...this.vendorDTOSchema,
],
this.validationResult,
asyncMiddleware(this.editVendor.bind(this))
);
router.delete('/:id', [
...this.specificContactSchema,
],
...this.specificContactSchema,
],
this.validationResult,
asyncMiddleware(this.deleteVendor.bind(this))
);
router.delete('/', [
...this.bulkContactsSchema,
],
...this.bulkContactsSchema,
],
this.validationResult,
asyncMiddleware(this.deleteBulkVendors.bind(this))
);
router.get('/:id', [
...this.specificContactSchema,
],
...this.specificContactSchema,
],
this.validationResult,
asyncMiddleware(this.getVendor.bind(this))
);
router.get('/', [
...this.vendorsListSchema,
],
...this.vendorsListSchema,
],
this.validationResult,
asyncMiddleware(this.getVendorsList.bind(this)),
);
@@ -63,8 +63,9 @@ export default class VendorsController extends ContactsController {
/**
* Vendor DTO schema.
* @returns {ValidationChain[]}
*/
get vendorDTOSchema() {
get vendorDTOSchema(): ValidationChain[] {
return [
check('opening_balance').optional().isNumeric().toInt(),
];
@@ -72,6 +73,7 @@ export default class VendorsController extends ContactsController {
/**
* Vendors datatable list validation schema.
* @returns {ValidationChain[]}
*/
get vendorsListSchema() {
return [
@@ -231,7 +233,7 @@ export default class VendorsController extends ContactsController {
const vendors = await this.vendorsService.getVendorsList(tenantId, vendorsFilter);
return res.status(200).send({ vendors });
} catch (error) {
next(error);
}
}
}

View File

@@ -1,135 +0,0 @@
import express from 'express';
import { check, param, validationResult } from 'express-validator';
import asyncMiddleware from 'api/middleware/asyncMiddleware';
export default {
/**
* Router constructor.
*/
router() {
const router = express.Router();
router.get('/',
this.all.validation,
asyncMiddleware(this.all.handler));
router.post('/',
this.newCurrency.validation,
asyncMiddleware(this.newCurrency.handler));
router.post('/:id',
this.editCurrency.validation,
asyncMiddleware(this.editCurrency.handler));
router.delete('/:currency_code',
this.deleteCurrecy.validation,
asyncMiddleware(this.deleteCurrecy.handler));
return router;
},
/**
* Retrieve all registered currency details.
*/
all: {
validation: [],
async handler(req, res) {
const { Currency } = req.models;
const currencies = await Currency.query();
return res.status(200).send({
currencies: [
...currencies,
],
});
},
},
newCurrency: {
validation: [
check('currency_name').exists().trim().escape(),
check('currency_code').exists().trim().escape(),
],
async handler(req, res) {
const validationErrors = validationResult(req);
if (!validationErrors.isEmpty()) {
return res.boom.badData(null, {
code: 'validation_error', ...validationErrors,
});
}
const form = { ...req.body };
const { Currency } = req.models;
const foundCurrency = await Currency.query()
.where('currency_code', form.currency_code);
if (foundCurrency.length > 0) {
return res.status(400).send({
errors: [{ type: 'CURRENCY.CODE.ALREADY.EXISTS', code: 100 }],
});
}
await Currency.query()
.insert({ ...form });
return res.status(200).send({
currency: { ...form },
});
},
},
deleteCurrecy: {
validation: [
param('currency_code').exists().trim().escape(),
],
async handler(req, res) {
const validationErrors = validationResult(req);
if (!validationErrors.isEmpty()) {
return res.boom.badData(null, {
code: 'validation_error', ...validationErrors,
});
}
const { Currency } = req.models;
const { currency_code: currencyCode } = req.params;
await Currency.query()
.where('currency_code', currencyCode)
.delete();
return res.status(200).send({ currency_code: currencyCode });
},
},
editCurrency: {
validation: [
param('id').exists().isNumeric().toInt(),
check('currency_name').exists().trim().escape(),
check('currency_code').exists().trim().escape(),
],
async handler(req, res) {
const validationErrors = validationResult(req);
if (!validationErrors.isEmpty()) {
return res.boom.badData(null, {
code: 'validation_error', ...validationErrors,
});
}
const form = { ...req.body };
const { id } = req.params;
const { Currency } = req.models;
const foundCurrency = await Currency.query()
.where('currency_code', form.currency_code).whereNot('id', id);
if (foundCurrency.length > 0) {
return res.status(400).send({
errors: [{ type: 'CURRENCY.CODE.ALREADY.EXISTS', code: 100 }],
});
}
await Currency.query().where('id', id).update({ ...form });
return res.status(200).send({ currency: { ...form } });
},
},
};

View File

@@ -0,0 +1,180 @@
import { Router, Request, Response, NextFunction } from 'express';
import { check, param, query, ValidationChain } from 'express-validator';
import asyncMiddleware from 'api/middleware/asyncMiddleware';
import BaseController from './BaseController';
import CurrenciesService from 'services/Currencies/CurrenciesService';
import { Inject, Service } from 'typedi';
import { ServiceError } from 'exceptions';
@Service()
export default class CurrenciesController extends BaseController {
@Inject()
currenciesService: CurrenciesService;
/**
* Router constructor.
*/
router() {
const router = Router();
router.get('/', [
...this.listSchema,
],
this.validationResult,
asyncMiddleware(this.all.bind(this))
);
router.post('/', [
...this.currencyDTOSchemaValidation,
],
this.validationResult,
asyncMiddleware(this.newCurrency.bind(this)),
this.handlerServiceError,
);
router.post('/:id', [
...this.currencyIdParamSchema,
...this.currencyEditDTOSchemaValidation
],
this.validationResult,
asyncMiddleware(this.editCurrency.bind(this)),
this.handlerServiceError,
);
router.delete('/:currency_code', [
...this.currencyParamSchema,
],
this.validationResult,
asyncMiddleware(this.deleteCurrency.bind(this)),
this.handlerServiceError,
);
return router;
}
get currencyDTOSchemaValidation(): ValidationChain[] {
return [
check('currency_name').exists().trim().escape(),
check('currency_code').exists().trim().escape(),
];
}
get currencyEditDTOSchemaValidation(): ValidationChain[] {
return [
check('currency_name').exists().trim().escape(),
];
}
get currencyIdParamSchema(): ValidationChain[] {
return [
param('id').exists().isNumeric().toInt(),
];
}
get currencyParamSchema(): ValidationChain[] {
return [
param('currency_code').exists().trim().escape(),
];
}
get listSchema(): ValidationChain[] {
return [
query('page').optional().isNumeric().toInt(),
query('page_size').optional().isNumeric().toInt(),
];
}
/**
* Retrieve all registered currency details.
* @param {Request} req
* @param {Response} res
* @param {NextFunction} next
*/
async all(req: Request, res: Response, next: NextFunction) {
const { tenantId } = req;
try {
const currencies = await this.currenciesService.listCurrencies(tenantId);
return res.status(200).send({ currencies: [ ...currencies, ] });
} catch (error) {
next(error);
}
}
/**
* Creates a new currency on the storage.
* @param {Request} req
* @param {Response} res
* @param {NextFunction} next
*/
async newCurrency(req: Request, res: Response, next: Function) {
const { tenantId } = req;
const currencyDTO = this.matchedBodyData(req);
try {
await this.currenciesService.newCurrency(tenantId, currencyDTO);
return res.status(200).send({
currency_code: currencyDTO.currencyCode,
});
} catch (error) {
next(error);
}
}
/**
* Edits details of the given currency.
* @param {Request} req
* @param {Response} res
* @param {NextFunction} next
*/
async deleteCurrency(req: Request, res: Response, next: Function) {
const { tenantId } = req;
const { currency_code: currencyCode } = req.params;
try {
await this.currenciesService.deleteCurrency(tenantId, currencyCode);
return res.status(200).send({ currency_code: currencyCode });
} catch (error) {
next(error);
}
}
/**
* Deletes the currency.
* @param {Request} req
* @param {Response} res
* @param {NextFunction} next
*/
async editCurrency(req: Request, res: Response, next: Function) {
const { tenantId } = req;
const { id: currencyId } = req.params;
const { body: editCurrencyDTO } = req;
try {
const currency = await this.currenciesService.editCurrency(tenantId, currencyId, editCurrencyDTO);
return res.status(200).send({ currency_code: currency.currencyCode });
} catch (error) {
next(error);
}
}
/**
* Handles currencies service error.
* @param {Error} error
* @param {Request} req
* @param {Response} res
* @param {NextFunction} next
*/
handlerServiceError(error, req, res, next) {
if (error instanceof ServiceError) {
if (error.errorType === 'currency_not_found') {
return res.boom.badRequest(null, {
errors: [{ type: 'CURRENCY_NOT_FOUND', code: 100, }],
});
}
if (error.errorType === 'currency_code_exists') {
return res.boom.badRequest(null, {
errors: [{ type: 'CURRENCY_CODE_EXISTS', code: 200, }],
});
}
}
next(error);
}
};

View File

@@ -1,209 +0,0 @@
import express from 'express';
import {
check,
param,
query,
validationResult,
} from 'express-validator';
import moment from 'moment';
import { difference } from 'lodash';
import asyncMiddleware from 'api/middleware/asyncMiddleware';
export default {
/**
* Constructor method.
*/
router() {
const router = express.Router();
router.get('/',
this.exchangeRates.validation,
asyncMiddleware(this.exchangeRates.handler));
router.post('/',
this.addExchangeRate.validation,
asyncMiddleware(this.addExchangeRate.handler));
router.post('/:id',
this.editExchangeRate.validation,
asyncMiddleware(this.editExchangeRate.handler));
router.delete('/bulk',
this.bulkDeleteExchangeRates.validation,
asyncMiddleware(this.bulkDeleteExchangeRates.handler));
router.delete('/:id',
this.deleteExchangeRate.validation,
asyncMiddleware(this.deleteExchangeRate.handler));
return router;
},
/**
* Retrieve exchange rates.
*/
exchangeRates: {
validation: [
query('page').optional().isNumeric().toInt(),
query('page_size').optional().isNumeric().toInt(),
],
async handler(req, res) {
const validationErrors = validationResult(req);
if (!validationErrors.isEmpty()) {
return res.boom.badData(null, {
code: 'validation_error', ...validationErrors,
});
}
const filter = {
page: 1,
page_size: 10,
...req.query,
};
const { ExchangeRate } = req.models;
const exchangeRates = await ExchangeRate.query()
.pagination(filter.page - 1, filter.page_size);
return res.status(200).send({ exchange_rates: exchangeRates });
},
},
/**
* Adds a new exchange rate on the given date.
*/
addExchangeRate: {
validation: [
check('exchange_rate').exists().isNumeric().toFloat(),
check('currency_code').exists().trim().escape(),
check('date').exists().isISO8601(),
],
async handler(req, res) {
const validationErrors = validationResult(req);
if (!validationErrors.isEmpty()) {
return res.boom.badData(null, {
code: 'validation_error', ...validationErrors,
});
}
const { ExchangeRate } = req.models;
const form = { ...req.body };
const foundExchangeRate = await ExchangeRate.query()
.where('currency_code', form.currency_code)
.where('date', form.date);
if (foundExchangeRate.length > 0) {
return res.status(400).send({
errors: [{ type: 'EXCHANGE.RATE.DATE.PERIOD.DEFINED', code: 200 }],
});
}
await ExchangeRate.query().insert({
...form,
date: moment(form.date).format('YYYY-MM-DD'),
});
return res.status(200).send();
},
},
/**
* Edit the given exchange rate.
*/
editExchangeRate: {
validation: [
param('id').exists().isNumeric().toInt(),
check('exchange_rate').exists().isNumeric().toFloat(),
],
async handler(req, res) {
const validationErrors = validationResult(req);
if (!validationErrors.isEmpty()) {
return res.boom.badData(null, {
code: 'validation_error', ...validationErrors,
});
}
const { id } = req.params;
const form = { ...req.body };
const { ExchangeRate } = req.models;
const foundExchangeRate = await ExchangeRate.query()
.where('id', id);
if (!foundExchangeRate.length) {
return res.status(400).send({
errors: [{ type: 'EXCHANGE.RATE.NOT.FOUND', code: 200 }],
});
}
await ExchangeRate.query()
.where('id', id)
.update({ ...form });
return res.status(200).send({ id });
},
},
/**
* Delete the given exchange rate from the storage.
*/
deleteExchangeRate: {
validation: [
param('id').isNumeric().toInt(),
],
async handler(req, res) {
const validationErrors = validationResult(req);
if (!validationErrors.isEmpty()) {
return res.boom.badData(null, {
code: 'validation_error', ...validationErrors,
});
}
const { id } = req.params;
const { ExchangeRate } = req.models;
const foundExchangeRate = await ExchangeRate.query().where('id', id);
if (!foundExchangeRate.length) {
return res.status(404).send({
errors: [{ type: 'EXCHANGE.RATE.NOT.FOUND', code: 200 }],
});
}
await ExchangeRate.query().where('id', id).delete();
return res.status(200).send({ id });
},
},
bulkDeleteExchangeRates: {
validation: [
query('ids').isArray({ min: 2 }),
query('ids.*').isNumeric().toInt(),
],
async handler(req, res) {
const validationErrors = validationResult(req);
if (!validationErrors.isEmpty()) {
return res.boom.badData(null, {
code: 'validation_error', ...validationErrors,
});
}
const filter = {
ids: [],
...req.query,
};
const { ExchangeRate } = req.models;
const exchangeRates = await ExchangeRate.query().whereIn('id', filter.ids);
const exchangeRatesIds = exchangeRates.map((category) => category.id);
const notFoundExRates = difference(filter.ids, exchangeRatesIds);
if (notFoundExRates.length > 0) {
return res.status(400).send({
errors: [{ type: 'EXCHANGE.RATES.IS.NOT.FOUND', code: 200, ids: notFoundExRates }],
});
}
await ExchangeRate.query().whereIn('id', exchangeRatesIds).delete();
return res.status(200).send({ ids: exchangeRatesIds });
},
},
}

View File

@@ -0,0 +1,217 @@
import { Service, Inject } from 'typedi';
import { Router, Request, Response, NextFunction } from 'express';
import {
check,
param,
query,
} from 'express-validator';
import asyncMiddleware from 'api/middleware/asyncMiddleware';
import BaseController from './BaseController';
import { ServiceError } from 'exceptions';
import ExchangeRatesService from 'services/ExchangeRates/ExchangeRatesService';
@Service()
export default class ExchangeRatesController extends BaseController {
@Inject()
exchangeRatesService: ExchangeRatesService;
/**
* Constructor method.
*/
router() {
const router = Router();
router.get('/', [
...this.exchangeRatesListSchema,
],
this.validationResult,
asyncMiddleware(this.exchangeRates.bind(this)),
this.handleServiceError,
);
router.post('/', [
...this.exchangeRateDTOSchema
],
this.validationResult,
asyncMiddleware(this.addExchangeRate.bind(this)),
this.handleServiceError,
);
router.post('/:id', [
...this.exchangeRateEditDTOSchema,
...this.exchangeRateIdSchema,
],
this.validationResult,
asyncMiddleware(this.editExchangeRate.bind(this)),
this.handleServiceError,
);
router.delete('/bulk', [
...this.exchangeRatesIdsSchema,
],
this.validationResult,
asyncMiddleware(this.bulkDeleteExchangeRates.bind(this)),
this.handleServiceError,
);
router.delete('/:id', [
...this.exchangeRateIdSchema,
],
this.validationResult,
asyncMiddleware(this.deleteExchangeRate.bind(this)),
this.handleServiceError,
);
return router;
}
get exchangeRatesListSchema() {
return [
query('page').optional().isNumeric().toInt(),
query('page_size').optional().isNumeric().toInt(),
];
}
get exchangeRateDTOSchema() {
return [
check('exchange_rate').exists().isNumeric().toFloat(),
check('currency_code').exists().trim().escape(),
check('date').exists().isISO8601(),
];
}
get exchangeRateEditDTOSchema() {
return [
check('exchange_rate').exists().isNumeric().toFloat(),
];
}
get exchangeRateIdSchema() {
return [
param('id').isNumeric().toInt(),
];
}
get exchangeRatesIdsSchema() {
return [
query('ids').isArray({ min: 2 }),
query('ids.*').isNumeric().toInt(),
];
}
/**
* Retrieve exchange rates.
* @param {Request} req
* @param {Response} res
* @param {NextFunction} next
*/
async exchangeRates(req: Request, res: Response, next: NextFunction) {
const { tenantId } = req;
const filter = {
page: 1,
pageSize: 100,
...req.query,
};
try {
const exchangeRates = await this.exchangeRatesService.listExchangeRates(tenantId, filter);
return res.status(200).send({ exchange_rates: exchangeRates });
} catch (error) {
next(error);
}
}
/**
* Adds a new exchange rate on the given date.
* @param {Request} req
* @param {Response} res
* @param {NextFunction} next
*/
async addExchangeRate(req: Request, res: Response, next: NextFunction) {
const { tenantId } = req;
const exchangeRateDTO = this.matchedBodyData(req);
try {
const exchangeRate = await this.exchangeRatesService.newExchangeRate(tenantId, exchangeRateDTO)
return res.status(200).send({ id: exchangeRate.id });
} catch (error) {
next(error);
}
}
/**
* Edit the given exchange rate.
* @param {Request} req
* @param {Response} res
* @param {NextFunction} next
*/
async editExchangeRate(req: Request, res: Response, next: NextFunction) {
const { tenantId } = req;
const exchangeRateDTO = this.matchedBodyData(req);
try {
const exchangeRate = await this.exchangeRatesService.newExchangeRate(tenantId, exchangeRateDTO)
return res.status(200).send({ id: exchangeRate.id });
} catch (error) {
next(error);
}
}
/**
* Delete the given exchange rate from the storage.
* @param {Request} req
* @param {Response} res
* @param {NextFunction} next
*/
async deleteExchangeRate(req: Request, res: Response, next: NextFunction) {
const { tenantId } = req;
const { id: exchangeRateId } = req.params;
try {
await this.exchangeRatesService.deleteExchangeRate(tenantId, exchangeRateId);
return res.status(200).send({ id: exchangeRateId });
} catch (error) {
next(error);
}
}
/**
* Deletes the given exchange rates in bulk.
* @param {Request} req
* @param {Response} res
* @param {NextFunction} next
*/
async bulkDeleteExchangeRates(req: Request, res: Response, next: NextFunction) {
const { tenantId } = req;
const { ids: exchangeRateIds } = req.query;
try {
await this.exchangeRatesService.deleteBulkExchangeRates(tenantId, exchangeRateIds);
return res.status(200).send();
} catch (error) {
next(error);
}
}
/**
* Handle service errors.
* @param {Error} error
* @param {Request} req
* @param {Response} res
* @param {NextFunction} next
*/
handleServiceError(error: Error, req: Request, res: Response, next: NextFunction) {
if (error instanceof ServiceError) {
if (error.errorType === 'EXCHANGE_RATE_NOT_FOUND') {
return res.status(404).send({
errors: [{ type: 'EXCHANGE.RATE.NOT.FOUND', code: 200 }],
});
}
if (error.errorType === 'NOT_FOUND_EXCHANGE_RATES') {
return res.status(400).send({
errors: [{ type: 'EXCHANGE.RATES.IS.NOT.FOUND', code: 100 }],
});
}
if (error.errorType === 'EXCHANGE_RATE_PERIOD_EXISTS') {
return res.status(400).send({
errors: [{ type: 'EXCHANGE.RATE.PERIOD.EXISTS', code: 300 }],
});
}
}
}
}

View File

@@ -211,7 +211,12 @@ export default class ExpensesController extends BaseController {
}
}
/**
* Publishes the given expenses in bulk.
* @param {Request} req
* @param {Response} res
* @param {NextFunction} next
*/
async bulkPublishExpenses(req: Request, res: Response, next: NextFunction) {
const { tenantId } = req;

View File

@@ -22,8 +22,8 @@ export default class InviteUsersController extends BaseController {
const router = Router();
router.post('/send', [
body('email').exists().trim().escape(),
],
body('email').exists().trim().escape(),
],
this.validationResult,
asyncMiddleware(this.sendInvite.bind(this)),
);
@@ -117,9 +117,7 @@ export default class InviteUsersController extends BaseController {
message: 'User invite has been accepted successfully.',
});
} catch (error) {
if (error instanceof ServiceError) {
if (error.errorType === 'phone_number_exists') {
return res.status(400).send({
errors: [{ type: 'PHONE_NUMBER.EXISTS' }],

View File

@@ -60,10 +60,9 @@ export default () => {
dashboard.use('/users', Container.get(Users).router());
dashboard.use('/invite', Container.get(InviteUsers).authRouter());
dashboard.use('/currencies', Currencies.router());
dashboard.use('/currencies', Container.get(Currencies).router());
dashboard.use('/accounts', Container.get(Accounts).router());
dashboard.use('/account_types', Container.get(AccountTypes).router());
// dashboard.use('/accounting', Accounting.router());
dashboard.use('/manual-journals', Container.get(ManualJournals).router());
dashboard.use('/views', Views.router());
dashboard.use('/items', Container.get(Items).router());
@@ -76,7 +75,7 @@ export default () => {
dashboard.use('/vendors', Container.get(Vendors).router());
dashboard.use('/purchases', Purchases.router());
dashboard.use('/resources', Resources.router());
dashboard.use('/exchange_rates', ExchangeRates.router());
dashboard.use('/exchange_rates', Container.get(ExchangeRates).router());
dashboard.use('/media', Media.router())
app.use('/', dashboard);