mirror of
https://github.com/bigcapitalhq/bigcapital.git
synced 2026-02-19 14:20:31 +00:00
fix item categories API.
This commit is contained in:
@@ -2,7 +2,7 @@
|
|||||||
exports.up = function (knex) {
|
exports.up = function (knex) {
|
||||||
return knex.schema.createTable('items_categories', (table) => {
|
return knex.schema.createTable('items_categories', (table) => {
|
||||||
table.increments();
|
table.increments();
|
||||||
table.string('label');
|
table.string('name');
|
||||||
table.integer('parent_category_id').unsigned();
|
table.integer('parent_category_id').unsigned();
|
||||||
table.text('description');
|
table.text('description');
|
||||||
table.integer('user_id').unsigned();
|
table.integer('user_id').unsigned();
|
||||||
|
|||||||
@@ -11,34 +11,34 @@ export default {
|
|||||||
*/
|
*/
|
||||||
router() {
|
router() {
|
||||||
const router = express.Router();
|
const router = express.Router();
|
||||||
const permit = Authorization('items_categories');
|
// const permit = Authorization('items_categories');
|
||||||
|
|
||||||
router.use(JWTAuth);
|
router.use(JWTAuth);
|
||||||
|
|
||||||
router.post('/:id',
|
router.post('/:id',
|
||||||
permit('create', 'edit'),
|
// permit('create', 'edit'),
|
||||||
this.editCategory.validation,
|
this.editCategory.validation,
|
||||||
asyncMiddleware(this.editCategory.handler));
|
asyncMiddleware(this.editCategory.handler));
|
||||||
|
|
||||||
router.post('/',
|
router.post('/',
|
||||||
permit('create'),
|
// permit('create'),
|
||||||
this.newCategory.validation,
|
this.newCategory.validation,
|
||||||
asyncMiddleware(this.newCategory.handler));
|
asyncMiddleware(this.newCategory.handler));
|
||||||
|
|
||||||
router.delete('/:id',
|
router.delete('/:id',
|
||||||
permit('create', 'edit', 'delete'),
|
// permit('create', 'edit', 'delete'),
|
||||||
this.deleteItem.validation,
|
this.deleteItem.validation,
|
||||||
asyncMiddleware(this.deleteItem.handler));
|
asyncMiddleware(this.deleteItem.handler));
|
||||||
|
|
||||||
router.get('/:id',
|
router.get('/:id',
|
||||||
permit('view'),
|
// permit('view'),
|
||||||
this.getCategory.validation,
|
this.getCategory.validation,
|
||||||
asyncMiddleware(this.getCategory.handler));
|
asyncMiddleware(this.getCategory.handler));
|
||||||
|
|
||||||
router.get('/',
|
router.get('/',
|
||||||
permit('view'),
|
// permit('view'),
|
||||||
this.getList.validation,
|
this.getList.validation,
|
||||||
asyncMiddleware(this.getList.validation));
|
asyncMiddleware(this.getList.handler));
|
||||||
|
|
||||||
return router;
|
return router;
|
||||||
},
|
},
|
||||||
@@ -48,7 +48,7 @@ export default {
|
|||||||
*/
|
*/
|
||||||
newCategory: {
|
newCategory: {
|
||||||
validation: [
|
validation: [
|
||||||
check('name').exists({ checkFalsy: true }).trim().escape(),
|
check('name').exists().trim().escape(),
|
||||||
check('parent_category_id').optional().isNumeric().toInt(),
|
check('parent_category_id').optional().isNumeric().toInt(),
|
||||||
check('description').optional().trim().escape(),
|
check('description').optional().trim().escape(),
|
||||||
],
|
],
|
||||||
@@ -61,10 +61,12 @@ export default {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
const { name, parent_category_id: parentCategoryId, description } = req.body;
|
const { user } = req;
|
||||||
|
const form = { ...req.body };
|
||||||
|
|
||||||
if (parentCategoryId) {
|
if (form.parent_category_id) {
|
||||||
const foundParentCategory = await ItemCategory.where('id', parentCategoryId).fetch();
|
const foundParentCategory = await ItemCategory.query()
|
||||||
|
.where('id', form.parent_category_id).first();
|
||||||
|
|
||||||
if (!foundParentCategory) {
|
if (!foundParentCategory) {
|
||||||
return res.boom.notFound('The parent category ID is not found.', {
|
return res.boom.notFound('The parent category ID is not found.', {
|
||||||
@@ -72,14 +74,11 @@ export default {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
const category = await ItemCategory.forge({
|
const category = await ItemCategory.query().insert({
|
||||||
label: name,
|
...form,
|
||||||
parent_category_id: parentCategoryId,
|
user_id: user.id,
|
||||||
description,
|
|
||||||
});
|
});
|
||||||
|
return res.status(200).send({ category });
|
||||||
await category.save();
|
|
||||||
return res.status(200).send({ id: category.get('id') });
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|
||||||
@@ -89,7 +88,7 @@ export default {
|
|||||||
editCategory: {
|
editCategory: {
|
||||||
validation: [
|
validation: [
|
||||||
param('id').toInt(),
|
param('id').toInt(),
|
||||||
check('name').exists({ checkFalsy: true }).trim().escape(),
|
check('name').exists().trim().escape(),
|
||||||
check('parent_category_id').optional().isNumeric().toInt(),
|
check('parent_category_id').optional().isNumeric().toInt(),
|
||||||
check('description').optional().trim().escape(),
|
check('description').optional().trim().escape(),
|
||||||
],
|
],
|
||||||
@@ -102,14 +101,19 @@ export default {
|
|||||||
code: 'validation_error', ...validationErrors,
|
code: 'validation_error', ...validationErrors,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
const { name, parent_category_id: parentCategoryId, description } = req.body;
|
|
||||||
const itemCategory = await ItemCategory.where('id', id).fetch();
|
const form = { ...req.body };
|
||||||
|
const itemCategory = await ItemCategory.query().where('id', id).first()
|
||||||
|
|
||||||
if (!itemCategory) {
|
if (!itemCategory) {
|
||||||
return res.boom.notFound();
|
return res.boom.notFound({
|
||||||
|
errors: [{ type: 'ITEM_CATEGORY.NOT.FOUND', code: 100 }],
|
||||||
|
});
|
||||||
}
|
}
|
||||||
if (parentCategoryId && parentCategoryId !== itemCategory.attributes.parent_category_id) {
|
if (form.parent_category_id
|
||||||
const foundParentCategory = await ItemCategory.where('id', parentCategoryId).fetch();
|
&& form.parent_category_id !== itemCategory.parent_category_id) {
|
||||||
|
const foundParentCategory = await ItemCategory.query()
|
||||||
|
.where('id', form.parent_category_id).first();
|
||||||
|
|
||||||
if (!foundParentCategory) {
|
if (!foundParentCategory) {
|
||||||
return res.boom.notFound('The parent category ID is not found.', {
|
return res.boom.notFound('The parent category ID is not found.', {
|
||||||
@@ -117,13 +121,9 @@ export default {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
await itemCategory.save({
|
const updateItemCategory = await ItemCategory.query().where('id', id).update({ ...form });
|
||||||
label: name,
|
|
||||||
description,
|
|
||||||
parent_category_id: parentCategoryId,
|
|
||||||
});
|
|
||||||
|
|
||||||
return res.status(200).send({ id: itemCategory.id });
|
return res.status(200).send({ id: updateItemCategory });
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|
||||||
@@ -132,16 +132,18 @@ export default {
|
|||||||
*/
|
*/
|
||||||
deleteItem: {
|
deleteItem: {
|
||||||
validation: [
|
validation: [
|
||||||
param('id').toInt(),
|
param('id').exists().toInt(),
|
||||||
],
|
],
|
||||||
async handler(req, res) {
|
async handler(req, res) {
|
||||||
const { id } = req.params;
|
const { id } = req.params;
|
||||||
const itemCategory = await ItemCategory.where('id', id).fetch();
|
const itemCategory = await ItemCategory.query().where('id', id).first();
|
||||||
|
|
||||||
if (!itemCategory) {
|
if (!itemCategory) {
|
||||||
return res.boom.notFound();
|
return res.boom.notFound();
|
||||||
}
|
}
|
||||||
await itemCategory.destroy();
|
|
||||||
|
await ItemCategory.query().where('id', itemCategory.id).delete();
|
||||||
|
|
||||||
return res.status(200).send();
|
return res.status(200).send();
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@@ -152,12 +154,9 @@ export default {
|
|||||||
getList: {
|
getList: {
|
||||||
validation: [],
|
validation: [],
|
||||||
async handler(req, res) {
|
async handler(req, res) {
|
||||||
const items = await ItemCategory.fetch();
|
const categories = await ItemCategory.query();
|
||||||
|
|
||||||
if (!items) {
|
return res.status(200).send({ categories });
|
||||||
return res.boom.notFound();
|
|
||||||
}
|
|
||||||
return res.status(200).send({ items: items.toJSON() });
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|
||||||
|
|||||||
@@ -14,15 +14,17 @@ export default class ItemCategory extends BaseModel {
|
|||||||
* Relationship mapping.
|
* Relationship mapping.
|
||||||
*/
|
*/
|
||||||
static get relationMappings() {
|
static get relationMappings() {
|
||||||
|
const Item = require('@/models/Item');
|
||||||
|
|
||||||
return {
|
return {
|
||||||
/**
|
/**
|
||||||
* Item category may has many items.
|
* Item category may has many items.
|
||||||
*/
|
*/
|
||||||
items: {
|
items: {
|
||||||
relation: Model.HasManyRelation,
|
relation: Model.HasManyRelation,
|
||||||
modelBase: path.join(__dirname, 'Item'),
|
modelClass: Item.default,
|
||||||
join: {
|
join: {
|
||||||
from: 'items_categories.item_id',
|
from: 'items_categories.itemId',
|
||||||
to: 'items.id',
|
to: 'items.id',
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -1,24 +1,47 @@
|
|||||||
import { request, expect, create } from '~/testInit';
|
import {
|
||||||
|
request,
|
||||||
|
expect,
|
||||||
|
create,
|
||||||
|
login,
|
||||||
|
} from '~/testInit';
|
||||||
import knex from '@/database/knex';
|
import knex from '@/database/knex';
|
||||||
|
|
||||||
describe('routes: /item_categories/', () => {
|
let loginRes;
|
||||||
describe('POST `/items_categories``', async () => {
|
|
||||||
it('Should not create a item category if the user was not authorized.', () => {
|
|
||||||
|
|
||||||
|
describe.only('routes: /item_categories/', () => {
|
||||||
|
beforeEach(async () => {
|
||||||
|
loginRes = await login();
|
||||||
|
});
|
||||||
|
afterEach(() => {
|
||||||
|
loginRes = null;
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('POST `/items_categories``', async () => {
|
||||||
|
it('Should not create a item category if the user was not authorized.', async () => {
|
||||||
|
const res = await request().post('/api/item_categories').send();
|
||||||
|
|
||||||
|
expect(res.status).equals(401);
|
||||||
|
expect(res.body.message).equals('unauthorized');
|
||||||
});
|
});
|
||||||
|
|
||||||
it('Should `name` be required.', async () => {
|
it('Should `name` be required.', async () => {
|
||||||
const res = await request().post('/api/item_categories').send();
|
const res = await request()
|
||||||
|
.post('/api/item_categories')
|
||||||
|
.set('x-access-token', loginRes.body.token)
|
||||||
|
.send();
|
||||||
|
|
||||||
expect(res.status).equals(422);
|
expect(res.status).equals(422);
|
||||||
expect(res.body.code).equals('validation_error');
|
expect(res.body.code).equals('validation_error');
|
||||||
});
|
});
|
||||||
|
|
||||||
it('Should `parent_category_id` be exist in the storage.', async () => {
|
it('Should `parent_category_id` be exist in the storage.', async () => {
|
||||||
const res = await request().posjt('/api/item_categories').send({
|
const res = await request()
|
||||||
name: 'Clothes',
|
.post('/api/item_categories')
|
||||||
parent_category_id: 10,
|
.set('x-access-token', loginRes.body.token)
|
||||||
});
|
.send({
|
||||||
|
name: 'Clothes',
|
||||||
|
parent_category_id: 10,
|
||||||
|
});
|
||||||
|
|
||||||
expect(res.status).equals(404);
|
expect(res.status).equals(404);
|
||||||
expect(res.body.errors).include.something.that.deep.equals({
|
expect(res.body.errors).include.something.that.deep.equals({
|
||||||
@@ -27,55 +50,76 @@ describe('routes: /item_categories/', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it('Should response success with correct form data.', async () => {
|
it('Should response success with correct form data.', async () => {
|
||||||
const res = await request().post('/api/item_categories').send({
|
const res = await request()
|
||||||
name: 'Clothes',
|
.post('/api/item_categories')
|
||||||
description: 'Here is description',
|
.set('x-access-token', loginRes.body.token)
|
||||||
});
|
.send({
|
||||||
|
name: 'Clothes',
|
||||||
|
description: 'Here is description',
|
||||||
|
});
|
||||||
|
|
||||||
// eslint-disable-next-line no-unused-expressions
|
|
||||||
expect(res.body.id).to.exist;
|
|
||||||
expect(res.status).equals(200);
|
expect(res.status).equals(200);
|
||||||
|
expect(res.body.category).to.be.a('object');
|
||||||
|
expect(res.body.category.id).to.be.a('number');
|
||||||
|
expect(res.body.category.name).to.be.a('string');
|
||||||
|
expect(res.body.category.description).to.be.a('string');
|
||||||
});
|
});
|
||||||
|
|
||||||
it('Should item category data be saved to the storage.', async () => {
|
it('Should item category data be saved to the storage.', async () => {
|
||||||
const category = await create('item_category');
|
const category = await create('item_category');
|
||||||
const res = await request().post('/api/item_categories').send({
|
const res = await request()
|
||||||
name: 'Clothes',
|
.post('/api/item_categories')
|
||||||
description: 'Here is description',
|
.set('x-access-token', loginRes.body.token)
|
||||||
parent_category_id: category.id,
|
.send({
|
||||||
});
|
name: 'Clothes',
|
||||||
|
description: 'Here is description',
|
||||||
|
parent_category_id: category.id,
|
||||||
|
});
|
||||||
|
|
||||||
// eslint-disable-next-line no-unused-expressions
|
expect(res.status).equals(200);
|
||||||
expect(res.body.id).to.exist;
|
|
||||||
|
|
||||||
const storedCategory = await knex('items_categories').where('id', res.body.id).first();
|
const storedCategory = await knex('items_categories')
|
||||||
|
.where('id', res.body.category.id).first();
|
||||||
|
|
||||||
expect(storedCategory.label).equals('Clothes');
|
expect(storedCategory.name).equals('Clothes');
|
||||||
expect(storedCategory.description).equals('Here is description');
|
expect(storedCategory.description).equals('Here is description');
|
||||||
expect(storedCategory.parent_category_id).equals(category.id);
|
expect(storedCategory.parentCategoryId).equals(category.id);
|
||||||
|
expect(storedCategory.userId).to.be.a('number');
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('POST `/items_category/{id}`', () => {
|
describe('POST `/items_category/{id}`', () => {
|
||||||
it('Should not update a item category if the user was not authorized.', () => {
|
it('Should not update a item category if the user was not authorized.', async () => {
|
||||||
|
const category = await create('item_category');
|
||||||
|
const res = await request()
|
||||||
|
.post(`/api/item_categories/${category.id}`)
|
||||||
|
.send();
|
||||||
|
|
||||||
|
expect(res.status).equals(401);
|
||||||
|
expect(res.body.message).equals('unauthorized');
|
||||||
});
|
});
|
||||||
|
|
||||||
it('Should `name` be required.', async () => {
|
it('Should `name` be required.', async () => {
|
||||||
const category = await create('item_category');
|
const category = await create('item_category');
|
||||||
const res = await request().post(`/api/item_categories/${category.id}`).send({
|
const res = await request()
|
||||||
name: '',
|
.post(`/api/item_categories/${category.id}`)
|
||||||
});
|
.set('x-access-token', loginRes.body.token)
|
||||||
|
.send({
|
||||||
|
name: '',
|
||||||
|
});
|
||||||
expect(res.status).equals(422);
|
expect(res.status).equals(422);
|
||||||
expect(res.body.code).equals('validation_error');
|
expect(res.body.code).equals('validation_error');
|
||||||
});
|
});
|
||||||
|
|
||||||
it('Should `parent_category_id` be exist in the storage.', async () => {
|
it('Should `parent_category_id` be exist in the storage.', async () => {
|
||||||
const category = await create('item_category');
|
const category = await create('item_category');
|
||||||
const res = await request().post(`/api/item_categories/${category.id}`).send({
|
const res = await request()
|
||||||
name: 'Name',
|
.post(`/api/item_categories/${category.id}`)
|
||||||
parent_category_id: 10,
|
.set('x-access-token', loginRes.body.token)
|
||||||
});
|
.send({
|
||||||
|
name: 'Name',
|
||||||
|
parent_category_id: 10,
|
||||||
|
});
|
||||||
|
|
||||||
expect(res.status).equals(404);
|
expect(res.status).equals(404);
|
||||||
expect(res.body.errors).include.something.that.deep.equals({
|
expect(res.body.errors).include.something.that.deep.equals({
|
||||||
@@ -87,11 +131,14 @@ describe('routes: /item_categories/', () => {
|
|||||||
const category = await create('item_category');
|
const category = await create('item_category');
|
||||||
const anotherCategory = await create('item_category');
|
const anotherCategory = await create('item_category');
|
||||||
|
|
||||||
const res = await request().post(`/api/item_categories/${category.id}`).send({
|
const res = await request()
|
||||||
name: 'Name',
|
.post(`/api/item_categories/${category.id}`)
|
||||||
parent_category_id: anotherCategory.id,
|
.set('x-access-token', loginRes.body.token)
|
||||||
description: 'updated description',
|
.send({
|
||||||
});
|
name: 'Name',
|
||||||
|
parent_category_id: anotherCategory.id,
|
||||||
|
description: 'updated description',
|
||||||
|
});
|
||||||
|
|
||||||
expect(res.status).equals(200);
|
expect(res.status).equals(200);
|
||||||
});
|
});
|
||||||
@@ -100,42 +147,61 @@ describe('routes: /item_categories/', () => {
|
|||||||
const category = await create('item_category');
|
const category = await create('item_category');
|
||||||
const anotherCategory = await create('item_category');
|
const anotherCategory = await create('item_category');
|
||||||
|
|
||||||
const res = await request().post(`/api/item_categories/${category.id}`).send({
|
const res = await request()
|
||||||
name: 'Name',
|
.post(`/api/item_categories/${category.id}`)
|
||||||
parent_category_id: anotherCategory.id,
|
.set('x-access-token', loginRes.body.token)
|
||||||
description: 'updated description',
|
.send({
|
||||||
});
|
name: 'Name',
|
||||||
|
parent_category_id: anotherCategory.id,
|
||||||
|
description: 'updated description',
|
||||||
|
});
|
||||||
|
|
||||||
const storedCategory = await knex('items_categories').where('id', res.body.id).first();
|
const storedCategory = await knex('items_categories')
|
||||||
|
.where('id', res.body.id).first();
|
||||||
|
|
||||||
expect(storedCategory.label).equals('Name');
|
expect(storedCategory.name).equals('Name');
|
||||||
expect(storedCategory.description).equals('updated description');
|
expect(storedCategory.description).equals('updated description');
|
||||||
expect(storedCategory.parent_category_id).equals(anotherCategory.id);
|
expect(storedCategory.parentCategoryId).equals(anotherCategory.id);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('DELETE: `/items_categories`', async () => {
|
describe('DELETE: `/items_categories`', async () => {
|
||||||
it('Should not delete the give item category if the user was not authorized.', () => {
|
it('Should not delete the give item category if the user was not authorized.', async () => {
|
||||||
|
const category = await create('item_category');
|
||||||
|
|
||||||
|
const res = await request()
|
||||||
|
.delete(`/api/item_categories/${category.id}`)
|
||||||
|
.send();
|
||||||
|
|
||||||
|
expect(res.status).equals(401);
|
||||||
|
expect(res.body.message).equals('unauthorized');
|
||||||
});
|
});
|
||||||
|
|
||||||
it('Should not delete if the item category was not found.', async () => {
|
it('Should not delete if the item category was not found.', async () => {
|
||||||
const res = await request().delete('/api/item_categories/10');
|
const res = await request()
|
||||||
|
.delete('/api/item_categories/10')
|
||||||
|
.set('x-access-token', loginRes.body.token)
|
||||||
|
.send();
|
||||||
|
|
||||||
expect(res.status).equals(404);
|
expect(res.status).equals(404);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('Should response success after delete the given item category.', async () => {
|
it('Should response success after delete the given item category.', async () => {
|
||||||
const category = await create('item_category');
|
const category = await create('item_category');
|
||||||
|
const res = await request()
|
||||||
const res = await request().delete(`/api/item_categories/${category.id}`);
|
.delete(`/api/item_categories/${category.id}`)
|
||||||
|
.set('x-access-token', loginRes.body.token)
|
||||||
|
.send();
|
||||||
|
|
||||||
expect(res.status).equals(200);
|
expect(res.status).equals(200);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('Should delete the give item category from the storage.', async () => {
|
it('Should delete the give item category from the storage.', async () => {
|
||||||
const category = await create('item_category');
|
const category = await create('item_category');
|
||||||
await request().delete(`/api/item_categories/${category.id}`);
|
const res = await request()
|
||||||
|
.delete(`/api/item_categories/${category.id}`)
|
||||||
|
.set('x-access-token', loginRes.body.token)
|
||||||
|
.send();
|
||||||
|
|
||||||
const categories = await knex('items_categories').where('id', category.id);
|
const categories = await knex('items_categories').where('id', category.id);
|
||||||
|
|
||||||
@@ -143,6 +209,28 @@ describe('routes: /item_categories/', () => {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
describe('GET: `/item_categories`', () => {
|
||||||
|
|
||||||
|
it('Should retrieve list of item categories.', async () => {
|
||||||
|
const category1 = await create('item_category');
|
||||||
|
const category2 = await create('item_category', { parent_category_id: category1.id });
|
||||||
|
|
||||||
|
const res = await request()
|
||||||
|
.get('/api/item_categories')
|
||||||
|
.set('x-access-token', loginRes.body.token)
|
||||||
|
.send();
|
||||||
|
|
||||||
|
expect(res.body.categories).to.be.a('array');
|
||||||
|
expect(res.body.categories.length).equals(2);
|
||||||
|
|
||||||
|
expect(res.body.categories[0].id).to.be.a('number');
|
||||||
|
expect(res.body.categories[0].name).to.be.a('string');
|
||||||
|
expect(res.body.categories[0].parent_category_id).to.be.a('null');
|
||||||
|
expect(res.body.categories[0].description).to.be.a('string');
|
||||||
|
|
||||||
|
expect(res.body.categories[1].parent_category_id).to.be.a('number');
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
describe('GET `/items_category/{id}', () => {
|
describe('GET `/items_category/{id}', () => {
|
||||||
it('Should response not found with incorrect item category ID.', () => {
|
it('Should response not found with incorrect item category ID.', () => {
|
||||||
|
|||||||
Reference in New Issue
Block a user