mirror of
https://github.com/bigcapitalhq/bigcapital.git
synced 2026-02-16 12:50:38 +00:00
feat: Currencies CRUD.
This commit is contained in:
@@ -243,6 +243,13 @@ factory.define('option', 'options', async () => {
|
||||
};
|
||||
});
|
||||
|
||||
factory.define('currency', 'currencies', async () => {
|
||||
return {
|
||||
currency_name: faker.lorem.slug(),
|
||||
currency_code: 'USD',
|
||||
};
|
||||
});
|
||||
|
||||
factory.define('budget', 'budgets', async () => {
|
||||
return {
|
||||
name: faker.lorem.slug(),
|
||||
|
||||
@@ -0,0 +1,12 @@
|
||||
|
||||
exports.up = function(knex) {
|
||||
return knex.schema.createTable('currencies', table => {
|
||||
table.increments();
|
||||
table.string('currency_name');
|
||||
table.string('currency_code', 4);
|
||||
})
|
||||
};
|
||||
|
||||
exports.down = function(knex) {
|
||||
return knex.schema.dropTableIfExists('currencies');
|
||||
};
|
||||
@@ -1,45 +1,136 @@
|
||||
import express from 'express';
|
||||
import { check, validationResult } from 'express-validator';
|
||||
import { check, param, validationResult } from 'express-validator';
|
||||
import asyncMiddleware from '@/http/middleware/asyncMiddleware';
|
||||
import Currency from '@/models/Currency';
|
||||
import jwtAuth from '@/http/middleware/jwtAuth';
|
||||
|
||||
export default {
|
||||
|
||||
router() {
|
||||
const router = express.Router();
|
||||
router.use(jwtAuth);
|
||||
|
||||
router.get('/all',
|
||||
router.get('/',
|
||||
this.all.validation,
|
||||
asyncMiddleware(this.all.handler));
|
||||
|
||||
router.get('/registered',
|
||||
this.registered.validation,
|
||||
asyncMiddleware(this.registered.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 currencies = await Currency.query();
|
||||
|
||||
return res.status(200).send({
|
||||
currencies: [
|
||||
{ currency_code: 'USD', currency_sign: '$' },
|
||||
{ currency_code: 'LYD', currency_sign: '' },
|
||||
...currencies,
|
||||
],
|
||||
});
|
||||
},
|
||||
},
|
||||
|
||||
registered: {
|
||||
validation: [],
|
||||
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 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({
|
||||
currencies: [
|
||||
{ currency_code: 'USD', currency_sign: '$' },
|
||||
{ currency_code: 'LYD', currency_sign: '' },
|
||||
],
|
||||
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_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 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 },
|
||||
});
|
||||
},
|
||||
},
|
||||
|
||||
10
server/src/models/Currency.js
Normal file
10
server/src/models/Currency.js
Normal file
@@ -0,0 +1,10 @@
|
||||
import BaseModel from '@/models/Model';
|
||||
|
||||
export default class Currency extends BaseModel {
|
||||
/**
|
||||
* Table name
|
||||
*/
|
||||
static get tableName() {
|
||||
return 'currencies';
|
||||
}
|
||||
}
|
||||
188
server/tests/routes/currencies.test.js
Normal file
188
server/tests/routes/currencies.test.js
Normal file
@@ -0,0 +1,188 @@
|
||||
import {
|
||||
request,
|
||||
create,
|
||||
expect,
|
||||
login,
|
||||
} from '~/testInit';
|
||||
import Currency from '@/models/Currency';
|
||||
|
||||
let loginRes;
|
||||
|
||||
describe('route: /currencies/', () => {
|
||||
beforeEach(async () => {
|
||||
loginRes = await login();
|
||||
});
|
||||
afterEach(() => {
|
||||
loginRes = null;
|
||||
});
|
||||
|
||||
describe('POST: `/api/currencies`', () => {
|
||||
|
||||
it('Should response unauthorized in case user was not logged in.', async () => {
|
||||
const res = await request()
|
||||
.post('/api/currencies')
|
||||
.send();
|
||||
|
||||
expect(res.status).equals(401);
|
||||
expect(res.body.message).equals('unauthorized');
|
||||
});
|
||||
|
||||
it('Should `currency_name` be required.', async () => {
|
||||
const res = await request()
|
||||
.post('/api/currencies')
|
||||
.set('x-access-token', loginRes.body.token)
|
||||
.send();
|
||||
|
||||
expect(res.status).equals(422);
|
||||
expect(res.body.code).equals('validation_error');
|
||||
expect(res.body.errors).include.something.deep.equals({
|
||||
msg: 'Invalid value', param: 'currency_name', location: 'body',
|
||||
});
|
||||
});
|
||||
|
||||
it('Should `currency_code` be required.', async () => {
|
||||
const res = await request()
|
||||
.post('/api/currencies')
|
||||
.set('x-access-token', loginRes.body.token)
|
||||
.send();
|
||||
|
||||
expect(res.status).equals(422);
|
||||
expect(res.body.code).equals('validation_error');
|
||||
expect(res.body.errors).include.something.deep.equals({
|
||||
msg: 'Invalid value', param: 'currency_code', location: 'body',
|
||||
});
|
||||
});
|
||||
|
||||
it('Should response currency code is duplicated.', async () => {
|
||||
create('currency', { currency_code: 'USD' });
|
||||
|
||||
const res = await request()
|
||||
.post('/api/currencies')
|
||||
.set('x-access-token', loginRes.body.token)
|
||||
.send({
|
||||
currency_code: 'USD',
|
||||
currency_name: 'Dollar',
|
||||
});
|
||||
|
||||
expect(res.status).equals(400);
|
||||
expect(res.body.errors).include.something.deep.equals({
|
||||
type: 'CURRENCY.CODE.ALREADY.EXISTS', code: 100,
|
||||
});
|
||||
});
|
||||
|
||||
it('Should insert currency details to the storage.', async () => {
|
||||
const res = await request()
|
||||
.post('/api/currencies')
|
||||
.set('x-access-token', loginRes.body.token)
|
||||
.send({
|
||||
currency_code: 'USD',
|
||||
currency_name: 'Dollar',
|
||||
});
|
||||
|
||||
const foundCurrency = await Currency.query().where('currency_code', 'USD');
|
||||
|
||||
expect(foundCurrency.length).equals(1);
|
||||
expect(foundCurrency[0].currencyCode).equals('USD');
|
||||
expect(foundCurrency[0].currencyName).equals('Dollar');
|
||||
});
|
||||
|
||||
it('Should response success with correct data.', async () => {
|
||||
const res = await request()
|
||||
.post('/api/currencies')
|
||||
.set('x-access-token', loginRes.body.token)
|
||||
.send({
|
||||
currency_code: 'USD',
|
||||
currency_name: 'Dollar',
|
||||
});
|
||||
|
||||
expect(res.status).equals(200);
|
||||
});
|
||||
});
|
||||
|
||||
describe('DELETE: `/api/currencies/:currency_code`', () => {
|
||||
|
||||
it('Should delete the given currency code from the storage.', async () => {
|
||||
const currency = await create('currency');
|
||||
const res = await request()
|
||||
.delete(`/api/currencies/${currency.currencyCode}`)
|
||||
.set('x-access-token', loginRes.body.token)
|
||||
.send();
|
||||
|
||||
expect(res.status).equals(200);
|
||||
|
||||
const foundCurrency = await Currency.query().where('currency_code', 'USD');
|
||||
expect(foundCurrency.length).equals(0);
|
||||
});
|
||||
});
|
||||
|
||||
describe('POST: `/api/currencies/:id`', () => {
|
||||
it('Should `currency_name` be required.', async () => {
|
||||
const currency = await create('currency');
|
||||
const res = await request()
|
||||
.post(`/api/currencies/${currency.code}`)
|
||||
.set('x-access-token', loginRes.body.token)
|
||||
.send();
|
||||
|
||||
expect(res.status).equals(422);
|
||||
expect(res.body.code).equals('validation_error');
|
||||
expect(res.body.errors).include.something.deep.equals({
|
||||
msg: 'Invalid value', param: 'currency_name', location: 'body',
|
||||
});
|
||||
});
|
||||
|
||||
it('Should `currency_code` be required.', async () => {
|
||||
const currency = await create('currency');
|
||||
const res = await request()
|
||||
.post(`/api/currencies/${currency.code}`)
|
||||
.set('x-access-token', loginRes.body.token)
|
||||
.send();
|
||||
|
||||
expect(res.status).equals(422);
|
||||
expect(res.body.code).equals('validation_error');
|
||||
expect(res.body.errors).include.something.deep.equals({
|
||||
msg: 'Invalid value', param: 'currency_code', location: 'body',
|
||||
});
|
||||
});
|
||||
|
||||
it('Should response currency code is duplicated.', async () => {
|
||||
const currency1 = await create('currency');
|
||||
const currency2 = await create('currency');
|
||||
|
||||
const res = await request()
|
||||
.post(`/api/currencies/${currency2.id}`)
|
||||
.set('x-access-token', loginRes.body.token)
|
||||
.send({
|
||||
currency_code: currency1.currencyCode,
|
||||
currency_name: 'Dollar',
|
||||
});
|
||||
|
||||
expect(res.status).equals(400);
|
||||
expect(res.body.errors).include.something.deep.equals({
|
||||
type: 'CURRENCY.CODE.ALREADY.EXISTS', code: 100,
|
||||
});
|
||||
});
|
||||
|
||||
it('Should update currency details of the given currency on the storage.', async () => {
|
||||
const currency1 = await create('currency');
|
||||
const currency2 = await create('currency');
|
||||
|
||||
const res = await request()
|
||||
.post(`/api/currencies/${currency2.id}`)
|
||||
.set('x-access-token', loginRes.body.token)
|
||||
.send({
|
||||
currency_code: 'ABC',
|
||||
currency_name: 'Name',
|
||||
});
|
||||
|
||||
const foundCurrency = await Currency.query().where('currency_code', 'ABC');
|
||||
|
||||
expect(foundCurrency.length).equals(1);
|
||||
expect(foundCurrency[0].currencyCode).equals('ABC');
|
||||
expect(foundCurrency[0].currencyName).equals('Name');
|
||||
});
|
||||
|
||||
it('Should response success with correct data.', () => {
|
||||
|
||||
});
|
||||
})
|
||||
});
|
||||
Reference in New Issue
Block a user