mirror of
https://github.com/bigcapitalhq/bigcapital.git
synced 2026-02-17 05:10:31 +00:00
add server to monorepo.
This commit is contained in:
130
packages/server/tests/collection/NestedSet.test.js
Normal file
130
packages/server/tests/collection/NestedSet.test.js
Normal file
@@ -0,0 +1,130 @@
|
||||
import { expect } from '~/testInit';
|
||||
import NestedSet from '@/collection/NestedSet';
|
||||
|
||||
describe('NestedSet', () => {
|
||||
describe('linkChildren()', () => {
|
||||
it('Should link parent and children nodes.', () => {
|
||||
const flattenArray = [
|
||||
{ id: 10 },
|
||||
{ id: 1 },
|
||||
{
|
||||
id: 3,
|
||||
parent_id: 1,
|
||||
},
|
||||
{
|
||||
id: 2,
|
||||
parent_id: 1,
|
||||
},
|
||||
{
|
||||
id: 4,
|
||||
parent_id: 3,
|
||||
},
|
||||
];
|
||||
const nestSet = new NestedSet(flattenArray);
|
||||
const treeGroups = nestSet.linkChildren();
|
||||
|
||||
expect(treeGroups['1']).deep.equals({
|
||||
id: 1,
|
||||
children: {
|
||||
'2': { id: 2, parent_id: 1, children: {} },
|
||||
'3': {
|
||||
id: 3, parent_id: 1, children: {
|
||||
'4': { id: 4, parent_id: 3, children: {} }
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
expect(treeGroups['2']).deep.equals({
|
||||
id: 2, parent_id: 1, children: {},
|
||||
});
|
||||
expect(treeGroups['3']).deep.equals({
|
||||
id: 3,
|
||||
parent_id: 1,
|
||||
children: { '4': { id: 4, parent_id: 3, children: {} } }
|
||||
});
|
||||
expect(treeGroups['4']).deep.equals({
|
||||
id: 4, parent_id: 3, children: {},
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('toArray()', () => {
|
||||
it('Should retrieve nested sets as array.', () => {
|
||||
const flattenArray = [
|
||||
{ id: 10 },
|
||||
{ id: 1 },
|
||||
{
|
||||
id: 3,
|
||||
parent_id: 1,
|
||||
},
|
||||
{
|
||||
id: 2,
|
||||
parent_id: 1,
|
||||
},
|
||||
{
|
||||
id: 4,
|
||||
parent_id: 3,
|
||||
},
|
||||
];
|
||||
const nestSet = new NestedSet(flattenArray);
|
||||
const treeArray = nestSet.toArray();
|
||||
|
||||
expect(treeArray[0]).deep.equals({
|
||||
id: 10, children: [],
|
||||
});
|
||||
expect(treeArray[1]).deep.equals({
|
||||
id: 1,
|
||||
children: [
|
||||
{ id: 2, parent_id: 1, children: [] },
|
||||
{ id: 3, parent_id: 1, children: [{
|
||||
id: 4, parent_id: 3, children: []
|
||||
}] }
|
||||
]
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('getParents(id)', () => {
|
||||
it('Should retrieve parent nodes of the given node id.', () => {
|
||||
const flattenArray = [
|
||||
{ id: 10 },
|
||||
{ id: 1 },
|
||||
{
|
||||
id: 3,
|
||||
parent_id: 1,
|
||||
},
|
||||
{
|
||||
id: 2,
|
||||
parent_id: 1,
|
||||
},
|
||||
{
|
||||
id: 4,
|
||||
parent_id: 3,
|
||||
},
|
||||
];
|
||||
const nestSet = new NestedSet(flattenArray);
|
||||
const parentNodes = nestSet.getParents(4);
|
||||
|
||||
expect(parentNodes).deep.equals([
|
||||
{ id: 4, parent_id: 3, children: {} },
|
||||
{
|
||||
id: 3,
|
||||
parent_id: 1,
|
||||
children: { '4': { id: 4, parent_id: 3, children: {} } }
|
||||
},
|
||||
{
|
||||
id: 1,
|
||||
children: {
|
||||
'2': { id: 2, parent_id: 1, children: {} },
|
||||
'3': {
|
||||
id: 3, parent_id: 1, children: {
|
||||
'4': { id: 4, parent_id: 3, children: {} }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
]);
|
||||
});
|
||||
})
|
||||
|
||||
});
|
||||
40
packages/server/tests/dbInit.js
Normal file
40
packages/server/tests/dbInit.js
Normal file
@@ -0,0 +1,40 @@
|
||||
import {
|
||||
request,
|
||||
expect,
|
||||
createTenantFactory,
|
||||
createTenant,
|
||||
bindTenantModel,
|
||||
login,
|
||||
systemFactory,
|
||||
dropTenant,
|
||||
} from '~/testInit';
|
||||
import CacheService from '@/services/Cache';
|
||||
|
||||
let tenantWebsite;
|
||||
let tenantFactory;
|
||||
let loginRes;
|
||||
|
||||
beforeEach(async () => {
|
||||
tenantWebsite = await createTenant();
|
||||
tenantFactory = createTenantFactory(tenantWebsite.tenantDb);
|
||||
|
||||
bindTenantModel(tenantWebsite.tenantDb);
|
||||
loginRes = await login(tenantWebsite);
|
||||
|
||||
CacheService.flush();
|
||||
});
|
||||
|
||||
afterEach(async () => {
|
||||
await dropTenant(tenantWebsite);
|
||||
|
||||
loginRes = null;
|
||||
tenantFactory = null;
|
||||
tenantWebsite = null;
|
||||
});
|
||||
|
||||
export {
|
||||
tenantWebsite,
|
||||
tenantFactory,
|
||||
systemFactory,
|
||||
loginRes,
|
||||
};
|
||||
14
packages/server/tests/docker-compose.yml
Normal file
14
packages/server/tests/docker-compose.yml
Normal file
@@ -0,0 +1,14 @@
|
||||
|
||||
services:
|
||||
mysql:
|
||||
image: mysql/mysql-server:5.7
|
||||
ports:
|
||||
- "3306:3306"
|
||||
environment:
|
||||
- MYSQL_ROOT_PASSWORD=root
|
||||
- MYSQL_DATABASE=moosher_test
|
||||
- MYSQL_USER=moosher
|
||||
- MYSQL_PASSWORD=moosher
|
||||
tmpfs:
|
||||
- /var/lib/mysql/:rw,noexec,nosuid,size=600m
|
||||
- /tmp/:rw,noexec,nosuid,size=50m
|
||||
32
packages/server/tests/lib/CachableModel.test.js
Normal file
32
packages/server/tests/lib/CachableModel.test.js
Normal file
@@ -0,0 +1,32 @@
|
||||
import {
|
||||
request,
|
||||
expect,
|
||||
} from '~/testInit';
|
||||
import Account from 'models/Account';
|
||||
import {
|
||||
tenantWebsite,
|
||||
tenantFactory,
|
||||
loginRes
|
||||
} from '~/dbInit';
|
||||
import { times } from 'lodash';
|
||||
|
||||
describe('CachableModel', () => {
|
||||
describe('remember()', () => {
|
||||
it('Should retrieve the data from the storage.', async () => {
|
||||
|
||||
for (let i = 0; i < 1; i++) {
|
||||
const account = await Account.tenant().query()
|
||||
.remember()
|
||||
.where('id', 1);
|
||||
|
||||
const account2 = await Account.tenant().query()
|
||||
.remember()
|
||||
.withGraphFetched('balance');
|
||||
|
||||
console.log(account2);
|
||||
// \\\
|
||||
}
|
||||
// Account.flushCache();
|
||||
});
|
||||
});
|
||||
});
|
||||
39
packages/server/tests/lib/MetableStore.test.ts
Normal file
39
packages/server/tests/lib/MetableStore.test.ts
Normal file
@@ -0,0 +1,39 @@
|
||||
import { expect } from '~/testInit';
|
||||
import MetableStore from '@/lib/MetableStore';
|
||||
|
||||
describe('MetableStore()', () => {
|
||||
|
||||
describe('find', () => {
|
||||
it('Find metadata by the given key.', () => {
|
||||
const store = new MetableStore();
|
||||
store.metadata = [{ key: 'first-key', value: 'first-value' }];
|
||||
|
||||
const meta = store.find('first-key');
|
||||
|
||||
expect(meta.value).equals('first-value');
|
||||
expect(meta.key).equals('first-key');
|
||||
});
|
||||
|
||||
it('Find metadata by the key as payload.', () => {
|
||||
|
||||
});
|
||||
|
||||
it('Find metadata by the given key and extra columns.', () => {
|
||||
|
||||
});
|
||||
});
|
||||
|
||||
describe('all()', () => {
|
||||
it('Should retrieve all metadata in the store.', () => {
|
||||
|
||||
});
|
||||
});
|
||||
|
||||
describe('get()', () => {
|
||||
it('Should retrieve data of the given metadata query.', () => {
|
||||
|
||||
});
|
||||
});
|
||||
|
||||
describe('removeMeta')
|
||||
});
|
||||
50
packages/server/tests/models/Account.test.js
Normal file
50
packages/server/tests/models/Account.test.js
Normal file
@@ -0,0 +1,50 @@
|
||||
import {
|
||||
expect,
|
||||
} from '~/testInit';
|
||||
import Account from 'models/Account';
|
||||
import AccountType from 'models/AccountType';
|
||||
import {
|
||||
tenantFactory,
|
||||
tenantWebsite
|
||||
} from '~/dbInit';
|
||||
import DependencyGraph from '@/lib/DependencyGraph';
|
||||
|
||||
describe('Model: Account', () => {
|
||||
it('Should account model belongs to the associated account type model.', async () => {
|
||||
const accountType = await tenantFactory.create('account_type');
|
||||
const account = await tenantFactory.create('account', { account_type_id: accountType.id });
|
||||
|
||||
const accountModel = await Account.tenant().query()
|
||||
.where('id', account.id)
|
||||
.withGraphFetched('type')
|
||||
.first();
|
||||
|
||||
expect(accountModel.type.id).equals(accountType.id);
|
||||
});
|
||||
|
||||
it('Should account model has one balance model that associated to the account model.', async () => {
|
||||
const accountBalance = await tenantFactory.create('account_balance');
|
||||
|
||||
const accountModel = await Account.tenant().query()
|
||||
.where('id', accountBalance.accountId)
|
||||
.withGraphFetched('balance')
|
||||
.first();
|
||||
|
||||
expect(accountModel.balance.amount).equals(accountBalance.amount);
|
||||
});
|
||||
|
||||
it('Should account model has many transactions models that associated to the account model.', async () => {
|
||||
const account = await tenantFactory.create('account');
|
||||
const accountTransaction = await tenantFactory.create('account_transaction', { account_id: account.id });
|
||||
|
||||
const accountModel = await Account.tenant().query().where('id', account.id).first();
|
||||
const transactionsModels = await accountModel.$relatedQuery('transactions');
|
||||
|
||||
expect(transactionsModels.length).equals(1);
|
||||
});
|
||||
|
||||
it('Should retrieve dependency graph.', async () => {
|
||||
const accountsDepGraph = await Account.tenant().depGraph().query();
|
||||
expect(accountsDepGraph).to.be.an.instanceOf(DependencyGraph);
|
||||
});
|
||||
});
|
||||
22
packages/server/tests/models/AccountType.test.js
Normal file
22
packages/server/tests/models/AccountType.test.js
Normal file
@@ -0,0 +1,22 @@
|
||||
import { create, expect } from '~/testInit';
|
||||
import 'models/Account';
|
||||
import AccountType from 'models/AccountType';
|
||||
import {
|
||||
tenantWebsite,
|
||||
tenantFactory,
|
||||
loginRes
|
||||
} from '~/dbInit';
|
||||
|
||||
|
||||
describe('Model: AccountType', () => {
|
||||
it('Shoud account type model has many associated accounts.', async () => {
|
||||
const accountType = await tenantFactory.create('account_type');
|
||||
await tenantFactory.create('account', { account_type_id: accountType.id });
|
||||
await tenantFactory.create('account', { account_type_id: accountType.id });
|
||||
|
||||
const accountTypeModel = await AccountType.tenant().query().where('id', accountType.id).first();
|
||||
const typeAccounts = await accountTypeModel.$relatedQuery('accounts');
|
||||
|
||||
expect(typeAccounts.length).equals(2);
|
||||
});
|
||||
});
|
||||
39
packages/server/tests/models/Expense.test.js
Normal file
39
packages/server/tests/models/Expense.test.js
Normal file
@@ -0,0 +1,39 @@
|
||||
import { create, expect } from '~/testInit';
|
||||
import Expense from 'models/Expense';
|
||||
import ExpenseCategory from 'models/ExpenseCategory';
|
||||
import {
|
||||
tenantFactory,
|
||||
tenantWebsite
|
||||
} from '~/dbInit';
|
||||
|
||||
describe('Model: Expense', () => {
|
||||
describe('relations', () => {
|
||||
it('Expense model may belongs to associated payment account.', async () => {
|
||||
const expense = await tenantFactory.create('expense');
|
||||
|
||||
const expenseModel = await Expense.tenant().query().findById(expense.id);
|
||||
const paymentAccountModel = await expenseModel.$relatedQuery('paymentAccount');
|
||||
|
||||
expect(paymentAccountModel.id).equals(expense.paymentAccountId);
|
||||
});
|
||||
|
||||
it('Expense model may has many associated expense categories.', async () => {
|
||||
const expenseCategory = await tenantFactory.create('expense_category');
|
||||
|
||||
const expenseModel = await Expense.tenant().query().findById(expenseCategory.expenseId);
|
||||
const expenseCategories = await expenseModel.$relatedQuery('categories');
|
||||
|
||||
expect(expenseCategories.length).equals(1);
|
||||
expect(expenseCategories[0].expenseId).equals(expenseModel.id);
|
||||
});
|
||||
|
||||
it('Expense model may belongs to associated user model.', async () => {
|
||||
const expense = await tenantFactory.create('expense');
|
||||
|
||||
const expenseModel = await Expense.tenant().query().findById(expense.id);
|
||||
const expenseUserModel = await expenseModel.$relatedQuery('user');
|
||||
|
||||
expect(expenseUserModel.id).equals(expense.userId);
|
||||
});
|
||||
});
|
||||
});
|
||||
5
packages/server/tests/models/ExpenseCategory.test.js
Normal file
5
packages/server/tests/models/ExpenseCategory.test.js
Normal file
@@ -0,0 +1,5 @@
|
||||
|
||||
|
||||
describe('ExpenseCategory', () => {
|
||||
|
||||
});
|
||||
22
packages/server/tests/models/Item.test.js
Normal file
22
packages/server/tests/models/Item.test.js
Normal file
@@ -0,0 +1,22 @@
|
||||
import { create, expect } from '~/testInit';
|
||||
import Item from 'models/Item';
|
||||
// eslint-disable-next-line no-unused-vars
|
||||
import itemCategory from 'models/ItemCategory';
|
||||
import {
|
||||
tenantWebsite,
|
||||
tenantFactory,
|
||||
loginRes
|
||||
} from '~/dbInit';
|
||||
|
||||
|
||||
describe('Model: Item', () => {
|
||||
it('Should item model belongs to the associated category model.', async () => {
|
||||
const category = await tenantFactory.create('item_category');
|
||||
const item = await tenantFactory.create('item', { category_id: category.id });
|
||||
|
||||
const itemModel = await Item.tenant().query().where('id', item.id).first();
|
||||
const itemCategoryModel = await itemModel.$relatedQuery('category');
|
||||
|
||||
expect(itemCategoryModel.id).equals(category.id);
|
||||
});
|
||||
});
|
||||
24
packages/server/tests/models/ItemCategories.test.js
Normal file
24
packages/server/tests/models/ItemCategories.test.js
Normal file
@@ -0,0 +1,24 @@
|
||||
import { create, expect } from '~/testInit';
|
||||
import 'models/Item';
|
||||
import ItemCategory from 'models/ItemCategory';
|
||||
import {
|
||||
tenantWebsite,
|
||||
tenantFactory,
|
||||
loginRes
|
||||
} from '~/dbInit';
|
||||
|
||||
|
||||
describe('Model: ItemCategories', () => {
|
||||
it('Shoud item category model has many associated items.', async () => {
|
||||
const category = await tenantFactory.create('item_category');
|
||||
await tenantFactory.create('item', { category_id: category.id });
|
||||
await tenantFactory.create('item', { category_id: category.id });
|
||||
|
||||
const categoryModel = await ItemCategory.tenant().query()
|
||||
.where('id', category.id).first();
|
||||
|
||||
const categoryItems = await categoryModel.$relatedQuery('items');
|
||||
|
||||
expect(categoryItems.length).equals(2);
|
||||
});
|
||||
});
|
||||
31
packages/server/tests/models/Resource.test.js
Normal file
31
packages/server/tests/models/Resource.test.js
Normal file
@@ -0,0 +1,31 @@
|
||||
import { create, expect } from '~/testInit';
|
||||
import Resource from 'models/Resource';
|
||||
import 'models/View';
|
||||
import 'models/ResourceField';
|
||||
import {
|
||||
tenantWebsite,
|
||||
tenantFactory,
|
||||
loginRes
|
||||
} from '~/dbInit';
|
||||
|
||||
|
||||
describe('Model: Resource', () => {
|
||||
it('Resource model may has many associated views.', async () => {
|
||||
const view = await tenantFactory.create('view');
|
||||
await tenantFactory.create('view', { resource_id: view.resourceId });
|
||||
|
||||
const resourceModel = await Resource.tenant().query().findById(view.resourceId);
|
||||
const resourceViews = await resourceModel.$relatedQuery('views');
|
||||
|
||||
expect(resourceViews).to.have.lengthOf(2);
|
||||
});
|
||||
|
||||
it('Resource model may has many fields.', async () => {
|
||||
const resourceField = await tenantFactory.create('resource_field');
|
||||
|
||||
const resourceModel = await Resource.tenant().query().findById(resourceField.resourceId);
|
||||
const resourceFields = await resourceModel.$relatedQuery('fields');
|
||||
|
||||
expect(resourceFields).to.have.lengthOf(1);
|
||||
});
|
||||
});
|
||||
23
packages/server/tests/models/User.test.js
Normal file
23
packages/server/tests/models/User.test.js
Normal file
@@ -0,0 +1,23 @@
|
||||
import { create, expect } from '~/testInit';
|
||||
import User from 'models/TenantUser';
|
||||
import 'models/Role';
|
||||
import {
|
||||
tenantWebsite,
|
||||
tenantFactory,
|
||||
loginRes
|
||||
} from '~/dbInit';
|
||||
|
||||
|
||||
describe('Model: User', () => {
|
||||
describe('relations', () => {
|
||||
it('User model may has many associated roles.', async () => {
|
||||
const userHasRole = await tenantFactory.create('user_has_role');
|
||||
await tenantFactory.create('user_has_role', { user_id: userHasRole.user_id });
|
||||
|
||||
const userModel = await User.tenant().query().where('id', userHasRole.userId).first();
|
||||
const userRoles = await userModel.$relatedQuery('roles');
|
||||
|
||||
expect(userRoles).to.have.lengthOf(1);
|
||||
});
|
||||
});
|
||||
});
|
||||
47
packages/server/tests/models/View.test.js
Normal file
47
packages/server/tests/models/View.test.js
Normal file
@@ -0,0 +1,47 @@
|
||||
import { create, expect } from '~/testInit';
|
||||
import View from 'models/View';
|
||||
import Resource from 'models/Resource';
|
||||
import ResourceField from 'models/ResourceField';
|
||||
import ViewRole from 'models/ViewRole';
|
||||
import {
|
||||
tenantWebsite,
|
||||
tenantFactory,
|
||||
loginRes
|
||||
} from '~/dbInit';
|
||||
|
||||
|
||||
describe('Model: View', () => {
|
||||
it('View model may has many associated resource.', async () => {
|
||||
const view = await tenantFactory.create('view');
|
||||
|
||||
const viewModel = await View.tenant().query().findById(view.id);
|
||||
const viewResource = await viewModel.$relatedQuery('resource');
|
||||
|
||||
const foundResource = await Resource.tenant().query().findById(view.resourceId);
|
||||
|
||||
expect(viewResource.id).equals(foundResource.id);
|
||||
expect(viewResource.name).equals(foundResource.name);
|
||||
});
|
||||
|
||||
it('View model may has many associated view roles.', async () => {
|
||||
const view = await tenantFactory.create('view');
|
||||
await tenantFactory.create('view_role', { view_id: view.id });
|
||||
await tenantFactory.create('view_role', { view_id: view.id });
|
||||
|
||||
const viewModel = await View.tenant().query().findById(view.id);
|
||||
const viewRoles = await viewModel.$relatedQuery('roles');
|
||||
|
||||
expect(viewRoles).to.have.lengthOf(2);
|
||||
});
|
||||
|
||||
it('View model may has many associated view columns', async () => {
|
||||
const view = await tenantFactory.create('view');
|
||||
await tenantFactory.create('view_column', { view_id: view.id });
|
||||
await tenantFactory.create('view_column', { view_id: view.id });
|
||||
|
||||
const viewModel = await View.tenant().query().findById(view.id);
|
||||
const viewColumns = await viewModel.$relatedQuery('columns');
|
||||
|
||||
expect(viewColumns).to.have.lengthOf(2);
|
||||
});
|
||||
});
|
||||
31
packages/server/tests/mysql-tmpfs.sh
Normal file
31
packages/server/tests/mysql-tmpfs.sh
Normal file
@@ -0,0 +1,31 @@
|
||||
MYSQL_USER="database_test"
|
||||
MYSQL_DATABASE="database_test"
|
||||
MYSQL_CONTAINER_NAME="database_test"
|
||||
|
||||
MYSQL_ROOT_PASSWORD="root"
|
||||
MYSQL_PASSWORD="root"
|
||||
|
||||
echo "Start the testing MySql database..."
|
||||
|
||||
docker \
|
||||
run \
|
||||
--detach \
|
||||
--env MYSQL_ROOT_PASSWORD=${MYSQL_ROOT_PASSWORD} \
|
||||
--env MYSQL_USER=${MYSQL_USER} \
|
||||
--env MYSQL_PASSWORD=${MYSQL_PASSWORD} \
|
||||
--env MYSQL_DATABASE=${MYSQL_DATABASE} \
|
||||
--name ${MYSQL_CONTAINER_NAME} \
|
||||
--publish 3306:3306 \
|
||||
--tmpfs /var/lib/mysql:rw,noexec,nosuid,size=600m \
|
||||
mysql:5.7;
|
||||
|
||||
echo "Sleeping for 10 seconds to allow time for the DB to be provisioned:"
|
||||
for i in `seq 1 10`;
|
||||
do
|
||||
echo "."
|
||||
sleep 1
|
||||
done
|
||||
|
||||
echo "Database '${MYSQL_DATABASE}' running."
|
||||
echo " Username: ${MYSQL_USER}"
|
||||
echo " Password: ${MYSQL_PASSWORD}"
|
||||
887
packages/server/tests/routes/accounting.test.js
Normal file
887
packages/server/tests/routes/accounting.test.js
Normal file
@@ -0,0 +1,887 @@
|
||||
import {
|
||||
request,
|
||||
expect,
|
||||
} from '~/testInit';
|
||||
import moment from 'moment';
|
||||
import ManualJournal from 'models/ManualJournal';
|
||||
import AccountTransaction from 'models/AccountTransaction';
|
||||
import AccountBalance from 'models/AccountBalance';
|
||||
import {
|
||||
tenantWebsite,
|
||||
tenantFactory,
|
||||
loginRes
|
||||
} from '~/dbInit';
|
||||
|
||||
|
||||
describe('routes: `/accounting`', () => {
|
||||
describe('route: `/accounting/make-journal-entries`', async () => {
|
||||
it('Should sumation of credit or debit does not equal zero.', async () => {
|
||||
const account = await tenantFactory.create('account');
|
||||
const res = await request()
|
||||
.post('/api/accounting/make-journal-entries')
|
||||
.set('x-access-token', loginRes.body.token)
|
||||
.set('organization-id', tenantWebsite.organizationId)
|
||||
.send({
|
||||
date: new Date().toISOString(),
|
||||
journal_number: '123',
|
||||
reference: 'ASC',
|
||||
entries: [
|
||||
{
|
||||
index: 1,
|
||||
credit: 0,
|
||||
debit: 0,
|
||||
account_id: account.id,
|
||||
},
|
||||
{
|
||||
index: 2,
|
||||
credit: 0,
|
||||
debit: 0,
|
||||
account_id: account.id,
|
||||
},
|
||||
],
|
||||
});
|
||||
expect(res.status).equals(400);
|
||||
expect(res.body.errors).include.something.that.deep.equal({
|
||||
type: 'CREDIT.DEBIT.SUMATION.SHOULD.NOT.EQUAL.ZERO',
|
||||
code: 400,
|
||||
});
|
||||
});
|
||||
|
||||
it('Should all credit entries equal debit.', async () => {
|
||||
const account = await tenantFactory.create('account');
|
||||
const res = await request()
|
||||
.post('/api/accounting/make-journal-entries')
|
||||
.set('x-access-token', loginRes.body.token)
|
||||
.set('organization-id', tenantWebsite.organizationId)
|
||||
.send({
|
||||
date: new Date().toISOString(),
|
||||
journal_number: '123',
|
||||
entries: [
|
||||
{
|
||||
index: 1,
|
||||
credit: 1000,
|
||||
debit: 0,
|
||||
account_id: account.id,
|
||||
},
|
||||
{
|
||||
index: 2,
|
||||
credit: 0,
|
||||
debit: 500,
|
||||
account_id: account.id,
|
||||
},
|
||||
],
|
||||
});
|
||||
|
||||
expect(res.status).equals(400);
|
||||
expect(res.body.errors).include.something.that.deep.equal({
|
||||
type: 'CREDIT.DEBIT.NOT.EQUALS',
|
||||
code: 100,
|
||||
});
|
||||
});
|
||||
|
||||
it('Should journal reference be not exists.', async () => {
|
||||
const manualJournal = await tenantFactory.create('manual_journal');
|
||||
const account = await tenantFactory.create('account');
|
||||
|
||||
const res = await request()
|
||||
.post('/api/accounting/make-journal-entries')
|
||||
.set('x-access-token', loginRes.body.token)
|
||||
.set('organization-id', tenantWebsite.organizationId)
|
||||
.send({
|
||||
date: new Date().toISOString(),
|
||||
journal_number: manualJournal.journalNumber,
|
||||
entries: [
|
||||
{
|
||||
index: 1,
|
||||
credit: 1000,
|
||||
debit: 0,
|
||||
account_id: account.id,
|
||||
},
|
||||
{
|
||||
index: 2,
|
||||
credit: 0,
|
||||
debit: 1000,
|
||||
account_id: account.id,
|
||||
},
|
||||
],
|
||||
});
|
||||
|
||||
expect(res.status).equals(400);
|
||||
expect(res.body.errors).include.something.that.deep.equal({
|
||||
type: 'JOURNAL.NUMBER.ALREADY.EXISTS',
|
||||
code: 300,
|
||||
});
|
||||
});
|
||||
|
||||
it('Should response error in case account id not exists in one of the given entries.', async () => {
|
||||
const res = await request()
|
||||
.post('/api/accounting/make-journal-entries')
|
||||
.set('x-access-token', loginRes.body.token)
|
||||
.set('organization-id', tenantWebsite.organizationId)
|
||||
.send({
|
||||
date: new Date().toISOString(),
|
||||
journal_number: '123',
|
||||
entries: [
|
||||
{
|
||||
index: 1,
|
||||
credit: 1000,
|
||||
debit: 0,
|
||||
account_id: 12,
|
||||
},
|
||||
{
|
||||
index: 2,
|
||||
credit: 0,
|
||||
debit: 1000,
|
||||
account_id: 12,
|
||||
},
|
||||
],
|
||||
});
|
||||
|
||||
expect(res.status).equals(400);
|
||||
expect(res.body.errors).include.something.that.deep.equal({
|
||||
type: 'ACCOUNTS.IDS.NOT.FOUND',
|
||||
code: 200,
|
||||
});
|
||||
});
|
||||
|
||||
it('Should discard journal entries that has null credit and debit amount.', async () => {
|
||||
const account1 = await tenantFactory.create('account');
|
||||
const account2 = await tenantFactory.create('account');
|
||||
|
||||
const res = await request()
|
||||
.post('/api/accounting/make-journal-entries')
|
||||
.set('x-access-token', loginRes.body.token)
|
||||
.set('organization-id', tenantWebsite.organizationId)
|
||||
.send({
|
||||
date: new Date().toISOString(),
|
||||
journal_number: '1000',
|
||||
entries: [
|
||||
{
|
||||
index: 1,
|
||||
credit: null,
|
||||
debit: 0,
|
||||
account_id: account1.id,
|
||||
},
|
||||
{
|
||||
index: 2,
|
||||
credit: null,
|
||||
debit: 0,
|
||||
account_id: account2.id,
|
||||
},
|
||||
],
|
||||
});
|
||||
|
||||
expect(res.status).equals(400);
|
||||
expect(res.body.errors).include.something.that.deep.equal({
|
||||
type: 'CREDIT.DEBIT.SUMATION.SHOULD.NOT.EQUAL.ZERO',
|
||||
|
||||
code: 400,
|
||||
});
|
||||
});
|
||||
|
||||
it('Should validate the customers and vendors contact if were not found on the storage.', async () => {
|
||||
const account1 = await tenantFactory.create('account');
|
||||
const account2 = await tenantFactory.create('account');
|
||||
|
||||
const res = await request()
|
||||
.post('/api/accounting/make-journal-entries')
|
||||
.set('x-access-token', loginRes.body.token)
|
||||
.set('organization-id', tenantWebsite.organizationId)
|
||||
.send({
|
||||
date: new Date().toISOString(),
|
||||
journal_number: '1000',
|
||||
entries: [
|
||||
{
|
||||
index: 1,
|
||||
credit: null,
|
||||
debit: 1000,
|
||||
account_id: account1.id,
|
||||
contact_type: 'customer',
|
||||
contact_id: 100,
|
||||
},
|
||||
{
|
||||
index: 2,
|
||||
credit: 1000,
|
||||
debit: 0,
|
||||
account_id: account1.id,
|
||||
contact_type: 'vendor',
|
||||
contact_id: 300,
|
||||
},
|
||||
],
|
||||
});
|
||||
|
||||
expect(res.body.errors).include.something.deep.equals({
|
||||
type: 'CUSTOMERS.CONTACTS.NOT.FOUND', code: 500, ids: [100],
|
||||
});
|
||||
expect(res.body.errors).include.something.deep.equals({
|
||||
type: 'VENDORS.CONTACTS.NOT.FOUND', code: 600, ids: [300],
|
||||
})
|
||||
});
|
||||
|
||||
it('Should customer contact_type with receivable accounts type.', async () => {
|
||||
const account1 = await tenantFactory.create('account');
|
||||
const account2 = await tenantFactory.create('account');
|
||||
const customer = await tenantFactory.create('customer');
|
||||
|
||||
const res = await request()
|
||||
.post('/api/accounting/make-journal-entries')
|
||||
.set('x-access-token', loginRes.body.token)
|
||||
.set('organization-id', tenantWebsite.organizationId)
|
||||
.send({
|
||||
date: new Date().toISOString(),
|
||||
journal_number: '1000',
|
||||
entries: [
|
||||
{
|
||||
index: 1,
|
||||
credit: null,
|
||||
debit: 1000,
|
||||
account_id: account1.id,
|
||||
contact_type: 'customer',
|
||||
contact_id: 100,
|
||||
},
|
||||
{
|
||||
index: 2,
|
||||
credit: 1000,
|
||||
debit: 0,
|
||||
account_id: account1.id,
|
||||
},
|
||||
],
|
||||
});
|
||||
|
||||
expect(res.status).equals(400);
|
||||
expect(res.body.errors).include.something.deep.equals({
|
||||
type: 'CUSTOMERS.NOT.WITH.RECEIVABLE.ACCOUNT',
|
||||
code: 700,
|
||||
indexes: [1]
|
||||
});
|
||||
});
|
||||
|
||||
it('Should account receivable entries has contact_id and contact_type customer.', async () => {
|
||||
const res = await request()
|
||||
.post('/api/accounting/make-journal-entries')
|
||||
.set('x-access-token', loginRes.body.token)
|
||||
.set('organization-id', tenantWebsite.organizationId)
|
||||
.send({
|
||||
date: new Date().toISOString(),
|
||||
journal_number: '1000',
|
||||
entries: [
|
||||
{
|
||||
index: 1,
|
||||
credit: null,
|
||||
debit: 1000,
|
||||
account_id: 10,
|
||||
},
|
||||
{
|
||||
index: 2,
|
||||
credit: 1000,
|
||||
debit: 0,
|
||||
account_id: 1,
|
||||
},
|
||||
],
|
||||
});
|
||||
|
||||
expect(res.status).equals(400);
|
||||
expect(res.body.errors).include.something.deep.equals({
|
||||
type: 'RECEIVABLE.ENTRIES.HAS.NO.CUSTOMERS', code: 900, indexes: [1],
|
||||
});
|
||||
});
|
||||
|
||||
it('Should account payable entries has contact_id and contact_type vendor.', async () => {
|
||||
const res = await request()
|
||||
.post('/api/accounting/make-journal-entries')
|
||||
.set('x-access-token', loginRes.body.token)
|
||||
.set('organization-id', tenantWebsite.organizationId)
|
||||
.send({
|
||||
date: new Date().toISOString(),
|
||||
journal_number: '1000',
|
||||
entries: [
|
||||
{
|
||||
index: 1,
|
||||
credit: null,
|
||||
debit: 1000,
|
||||
account_id: 10,
|
||||
},
|
||||
{
|
||||
index: 2,
|
||||
credit: 1000,
|
||||
debit: 0,
|
||||
account_id: 11,
|
||||
},
|
||||
],
|
||||
});
|
||||
|
||||
expect(res.status).equals(400);
|
||||
expect(res.body.errors).include.something.deep.equals({
|
||||
type: 'PAYABLE.ENTRIES.HAS.NO.VENDORS', code: 1000, indexes: [2]
|
||||
});
|
||||
});
|
||||
|
||||
it('Should retrieve account_id is not receivable in case contact_type equals customer.', async () => {
|
||||
const customer = await tenantFactory.create('customer');
|
||||
|
||||
const res = await request()
|
||||
.post('/api/accounting/make-journal-entries')
|
||||
.set('x-access-token', loginRes.body.token)
|
||||
.set('organization-id', tenantWebsite.organizationId)
|
||||
.send({
|
||||
date: new Date().toISOString(),
|
||||
journal_number: '1000',
|
||||
entries: [
|
||||
{
|
||||
index: 1,
|
||||
credit: null,
|
||||
debit: 1000,
|
||||
account_id: 2,
|
||||
contact_id: customer.id,
|
||||
contact_type: 'customer',
|
||||
},
|
||||
{
|
||||
index: 2,
|
||||
credit: 1000,
|
||||
debit: 0,
|
||||
account_id: 11,
|
||||
},
|
||||
],
|
||||
});
|
||||
|
||||
expect(res.status).equals(400);
|
||||
expect(res.body.errors).include.something.deep.equals({
|
||||
type: 'CUSTOMERS.NOT.WITH.RECEIVABLE.ACCOUNT', code: 700, indexes: [1],
|
||||
});
|
||||
});
|
||||
|
||||
it('Should store manual journal transaction to the storage.', async () => {
|
||||
const account1 = await tenantFactory.create('account');
|
||||
const account2 = await tenantFactory.create('account');
|
||||
|
||||
const res = await request()
|
||||
.post('/api/accounting/make-journal-entries')
|
||||
.set('x-access-token', loginRes.body.token)
|
||||
.set('organization-id', tenantWebsite.organizationId)
|
||||
.send({
|
||||
date: new Date('2020-2-2').toISOString(),
|
||||
journal_number: '1000',
|
||||
reference: '2000',
|
||||
description: 'Description here.',
|
||||
entries: [
|
||||
{
|
||||
index: 1,
|
||||
credit: 1000,
|
||||
account_id: account1.id,
|
||||
},
|
||||
{
|
||||
index: 2,
|
||||
debit: 1000,
|
||||
account_id: account2.id,
|
||||
},
|
||||
],
|
||||
});
|
||||
|
||||
const foundManualJournal = await ManualJournal.tenant().query();
|
||||
expect(foundManualJournal.length).equals(1);
|
||||
|
||||
expect(foundManualJournal[0].reference).equals('2000');
|
||||
expect(foundManualJournal[0].journalNumber).equals('1000');
|
||||
expect(foundManualJournal[0].transactionType).equals('Journal');
|
||||
expect(foundManualJournal[0].amount).equals(1000);
|
||||
expect(moment(foundManualJournal[0].date).format('YYYY-MM-DD')).equals('2020-02-02');
|
||||
expect(foundManualJournal[0].description).equals('Description here.');
|
||||
expect(foundManualJournal[0].userId).to.be.a('number');
|
||||
});
|
||||
|
||||
it('Should store journal transactions to the storage.', async () => {
|
||||
const account1 = await tenantFactory.create('account');
|
||||
const account2 = await tenantFactory.create('account');
|
||||
|
||||
const res = await request()
|
||||
.post('/api/accounting/make-journal-entries')
|
||||
.set('x-access-token', loginRes.body.token)
|
||||
.set('organization-id', tenantWebsite.organizationId)
|
||||
.send({
|
||||
journal_number: '1',
|
||||
date: new Date('2020-1-1').toISOString(),
|
||||
reference: '1000',
|
||||
memo: 'Description here.',
|
||||
entries: [
|
||||
{
|
||||
index: 1,
|
||||
credit: 1000,
|
||||
account_id: account1.id,
|
||||
note: 'First note',
|
||||
},
|
||||
{
|
||||
index: 2,
|
||||
debit: 1000,
|
||||
account_id: account2.id,
|
||||
note: 'Second note',
|
||||
},
|
||||
],
|
||||
});
|
||||
|
||||
const foundAccountsTransactions = await AccountTransaction.tenant().query();
|
||||
|
||||
expect(foundAccountsTransactions.length).equals(2);
|
||||
|
||||
expect(foundAccountsTransactions[0].credit).equals(1000);
|
||||
expect(foundAccountsTransactions[0].debit).equals(null);
|
||||
expect(foundAccountsTransactions[0].accountId).equals(account1.id);
|
||||
expect(foundAccountsTransactions[0].note).equals('First note');
|
||||
expect(foundAccountsTransactions[0].referenceType).equals('Journal');
|
||||
expect(foundAccountsTransactions[0].userId).equals(1);
|
||||
|
||||
expect(foundAccountsTransactions[1].credit).equals(null);
|
||||
expect(foundAccountsTransactions[1].debit).equals(1000);
|
||||
expect(foundAccountsTransactions[1].accountId).equals(account2.id);
|
||||
expect(foundAccountsTransactions[1].note).equals('Second note');
|
||||
expect(foundAccountsTransactions[1].referenceType).equals('Journal');
|
||||
expect(foundAccountsTransactions[1].userId).equals(1);
|
||||
});
|
||||
});
|
||||
|
||||
describe('route: POST: `/accounting/manual-journal/:id`', () => {
|
||||
it('Should response not found in case manual journal transaction was not exists.', async () => {
|
||||
const res = await request()
|
||||
.post('/api/manual-journal/1000')
|
||||
.set('x-access-token', loginRes.body.token)
|
||||
.set('organization-id', tenantWebsite.organizationId)
|
||||
.send();
|
||||
|
||||
expect(res.status).equals(404);
|
||||
});
|
||||
|
||||
it('Should sumation of credit or debit be equal zero.', async () => {
|
||||
const manualJournal = await tenantFactory.create('manual_journal');
|
||||
|
||||
const res = await request()
|
||||
.post(`/api/accounting/manual-journals/${manualJournal.id}`)
|
||||
.set('x-access-token', loginRes.body.token)
|
||||
.set('organization-id', tenantWebsite.organizationId)
|
||||
.send({
|
||||
date: new Date().toISOString(),
|
||||
journal_number: '123',
|
||||
reference: 'ASC',
|
||||
entries: [
|
||||
{
|
||||
credit: 0,
|
||||
debit: 0,
|
||||
account_id: 2000,
|
||||
},
|
||||
{
|
||||
credit: 0,
|
||||
debit: 0,
|
||||
account_id: 2000,
|
||||
},
|
||||
],
|
||||
});
|
||||
|
||||
expect(res.status).equals(400);
|
||||
expect(res.body.errors).include.something.that.deep.equal({
|
||||
type: 'CREDIT.DEBIT.SUMATION.SHOULD.NOT.EQUAL.ZERO',
|
||||
code: 400,
|
||||
});
|
||||
});
|
||||
|
||||
it('Should all credit and debit sumation be equal.', async () => {
|
||||
const manualJournal = await tenantFactory.create('manual_journal');
|
||||
|
||||
const res = await request()
|
||||
.post(`/api/accounting/manual-journals/${manualJournal.id}`)
|
||||
.set('x-access-token', loginRes.body.token)
|
||||
.set('organization-id', tenantWebsite.organizationId)
|
||||
.send({
|
||||
date: new Date().toISOString(),
|
||||
journal_number: '123',
|
||||
reference: 'ASC',
|
||||
entries: [
|
||||
{
|
||||
credit: 0,
|
||||
debit: 2000,
|
||||
account_id: 2000,
|
||||
},
|
||||
{
|
||||
credit: 1000,
|
||||
debit: 0,
|
||||
account_id: 2000,
|
||||
},
|
||||
],
|
||||
});
|
||||
|
||||
expect(res.status).equals(400);
|
||||
expect(res.body.errors).include.something.that.deep.equal({
|
||||
type: 'CREDIT.DEBIT.NOT.EQUALS', code: 100,
|
||||
});
|
||||
});
|
||||
|
||||
it('Should response journal number already exists in case another one on the storage.', async () => {
|
||||
const manualJournal = await tenantFactory.create('manual_journal');
|
||||
const manualJournal2 = await tenantFactory.create('manual_journal');
|
||||
|
||||
const jsonBody = {
|
||||
date: new Date().toISOString(),
|
||||
reference: 'ASC',
|
||||
entries: [
|
||||
{
|
||||
credit: 0,
|
||||
debit: 2000,
|
||||
account_id: 2000,
|
||||
},
|
||||
{
|
||||
credit: 1000,
|
||||
debit: 0,
|
||||
account_id: 2000,
|
||||
},
|
||||
],
|
||||
};
|
||||
|
||||
const res = await request()
|
||||
.post(`/api/accounting/manual-journals/${manualJournal.id}`)
|
||||
.set('x-access-token', loginRes.body.token)
|
||||
.set('organization-id', tenantWebsite.organizationId)
|
||||
.send({
|
||||
...jsonBody,
|
||||
journal_number: manualJournal2.journalNumber,
|
||||
});
|
||||
expect(res.status).equals(400);
|
||||
expect(res.body.errors).include.something.that.deep.equal({
|
||||
type: 'JOURNAL.NUMBER.ALREADY.EXISTS', code: 300,
|
||||
});
|
||||
});
|
||||
|
||||
it('Should not response journal number exists in case was unique number.', async () => {
|
||||
const manualJournal = await tenantFactory.create('manual_journal');
|
||||
const manualJournal2 = await tenantFactory.create('manual_journal');
|
||||
|
||||
const jsonBody = {
|
||||
date: new Date().toISOString(),
|
||||
reference: 'ASC',
|
||||
entries: [
|
||||
{
|
||||
credit: 0,
|
||||
debit: 2000,
|
||||
account_id: 2000,
|
||||
},
|
||||
{
|
||||
credit: 1000,
|
||||
debit: 0,
|
||||
account_id: 2000,
|
||||
},
|
||||
],
|
||||
};
|
||||
const res = await request()
|
||||
.post(`/api/accounting/manual-journals/${manualJournal.id}`)
|
||||
.set('x-access-token', loginRes.body.token)
|
||||
.set('organization-id', tenantWebsite.organizationId)
|
||||
.send({
|
||||
...jsonBody,
|
||||
journal_number: manualJournal.journalNumber,
|
||||
});
|
||||
|
||||
expect(res.status).equals(400);
|
||||
expect(res.body.errors).not.include.something.that.deep.equal({
|
||||
type: 'JOURNAL.NUMBER.ALREADY.EXISTS', code: 300,
|
||||
});
|
||||
})
|
||||
|
||||
it('Should response error in case account id not exists in one of the given entries.', async () => {
|
||||
const manualJournal = await tenantFactory.create('manual_journal');
|
||||
const manualJournal2 = await tenantFactory.create('manual_journal');
|
||||
|
||||
const jsonBody = {
|
||||
date: new Date().toISOString(),
|
||||
reference: 'ASC',
|
||||
entries: [
|
||||
{
|
||||
credit: 0,
|
||||
debit: 1000,
|
||||
account_id: 2000,
|
||||
},
|
||||
{
|
||||
credit: 1000,
|
||||
debit: 0,
|
||||
account_id: 2000,
|
||||
},
|
||||
],
|
||||
};
|
||||
const res = await request()
|
||||
.post(`/api/accounting/manual-journals/${manualJournal.id}`)
|
||||
.set('x-access-token', loginRes.body.token)
|
||||
.set('organization-id', tenantWebsite.organizationId)
|
||||
.send({
|
||||
...jsonBody,
|
||||
journal_number: manualJournal.journalNumber,
|
||||
});
|
||||
|
||||
expect(res.status).equals(400);
|
||||
expect(res.body.errors).include.something.that.deep.equal({
|
||||
type: 'ACCOUNTS.IDS.NOT.FOUND', code: 200,
|
||||
});
|
||||
});
|
||||
|
||||
it('Should update the given manual journal transaction in the storage.', async () => {
|
||||
const manualJournal = await tenantFactory.create('manual_journal');
|
||||
const account1 = await tenantFactory.create('account');
|
||||
const account2 = await tenantFactory.create('account');
|
||||
|
||||
const res = await request()
|
||||
.post(`/api/accounting/manual-journals/${manualJournal.id}`)
|
||||
.set('x-access-token', loginRes.body.token)
|
||||
.set('organization-id', tenantWebsite.organizationId)
|
||||
.send({
|
||||
journal_number: '123',
|
||||
date: new Date().toISOString(),
|
||||
reference: 'ABC',
|
||||
description: 'hello world',
|
||||
entries: [
|
||||
{
|
||||
credit: 0,
|
||||
debit: 1000,
|
||||
account_id: account1.id,
|
||||
},
|
||||
{
|
||||
credit: 1000,
|
||||
debit: 0,
|
||||
account_id: account2.id,
|
||||
},
|
||||
],
|
||||
});
|
||||
|
||||
const foundManualJournal = await ManualJournal.tenant().query()
|
||||
.where('id', manualJournal.id);
|
||||
|
||||
expect(foundManualJournal.length).equals(1);
|
||||
expect(foundManualJournal[0].journalNumber).equals('123');
|
||||
expect(foundManualJournal[0].reference).equals('ABC');
|
||||
expect(foundManualJournal[0].description).equals('hello world');
|
||||
});
|
||||
|
||||
it('Should update account transactions that associated to the manual journal transaction.', async () => {
|
||||
const manualJournal = await tenantFactory.create('manual_journal');
|
||||
const account1 = await tenantFactory.create('account');
|
||||
const account2 = await tenantFactory.create('account');
|
||||
const transaction = await tenantFactory.create('account_transaction', {
|
||||
reference_type: 'Journal',
|
||||
reference_id: manualJournal.id,
|
||||
});
|
||||
const transaction2 = await tenantFactory.create('account_transaction', {
|
||||
reference_type: 'Journal',
|
||||
reference_id: manualJournal.id,
|
||||
});
|
||||
|
||||
const res = await request()
|
||||
.post(`/api/accounting/manual-journals/${manualJournal.id}`)
|
||||
.set('x-access-token', loginRes.body.token)
|
||||
.set('organization-id', tenantWebsite.organizationId)
|
||||
.send({
|
||||
journal_number: '123',
|
||||
date: new Date().toISOString(),
|
||||
reference: 'ABC',
|
||||
description: 'hello world',
|
||||
entries: [
|
||||
{
|
||||
credit: 0,
|
||||
debit: 1000,
|
||||
account_id: account1.id,
|
||||
note: 'hello 1',
|
||||
},
|
||||
{
|
||||
credit: 1000,
|
||||
debit: 0,
|
||||
account_id: account2.id,
|
||||
note: 'hello 2',
|
||||
},
|
||||
],
|
||||
});
|
||||
|
||||
const foundTransactions = await AccountTransaction.tenant().query();
|
||||
|
||||
expect(foundTransactions.length).equals(2);
|
||||
expect(foundTransactions[0].credit).equals(0);
|
||||
expect(foundTransactions[0].debit).equals(1000);
|
||||
expect(foundTransactions[0].accountId).equals(account1.id);
|
||||
expect(foundTransactions[0].note).equals('hello 1');
|
||||
|
||||
expect(foundTransactions[1].credit).equals(1000);
|
||||
expect(foundTransactions[1].debit).equals(0);
|
||||
expect(foundTransactions[1].accountId).equals(account2.id);
|
||||
expect(foundTransactions[1].note).equals('hello 2');
|
||||
});
|
||||
});
|
||||
|
||||
describe('route: DELETE `accounting/manual-journals/:id`', () => {
|
||||
it('Should response not found in case the manual journal transaction was not found.', async() => {
|
||||
const res = await request()
|
||||
.delete('/api/accounting/manual-journals/1000')
|
||||
.set('x-access-token', loginRes.body.token)
|
||||
.set('organization-id', tenantWebsite.organizationId)
|
||||
.send();
|
||||
|
||||
expect(res.status).equals(404);
|
||||
expect(res.body.errors).include.something.that.deep.equal({
|
||||
type: 'MANUAL.JOURNAL.NOT.FOUND', code: 100,
|
||||
});
|
||||
});
|
||||
|
||||
it('Should delete manual journal transactions from storage.', async () => {
|
||||
const manualJournal = await tenantFactory.create('manual_journal');
|
||||
|
||||
const res = await request()
|
||||
.delete(`/api/accounting/manual-journals/${manualJournal.id}`)
|
||||
.set('x-access-token', loginRes.body.token)
|
||||
.set('organization-id', tenantWebsite.organizationId)
|
||||
.send();
|
||||
|
||||
const foundManualTransaction = await ManualJournal.tenant().query()
|
||||
.where('id', manualJournal.id).first();
|
||||
|
||||
expect(foundManualTransaction).equals(undefined);
|
||||
});
|
||||
|
||||
it('Should delete associated transactions of journal transaction.', async () => {
|
||||
const manualJournal = await tenantFactory.create('manual_journal');
|
||||
const transaction1 = await tenantFactory.create('account_transaction', {
|
||||
reference_type: 'Journal', reference_id: manualJournal.id,
|
||||
});
|
||||
const transaction2 = await tenantFactory.create('account_transaction', {
|
||||
reference_type: 'Journal', reference_id: manualJournal.id,
|
||||
});
|
||||
|
||||
const res = await request()
|
||||
.delete(`/api/accounting/manual-journals/${manualJournal.id}`)
|
||||
.set('x-access-token', loginRes.body.token)
|
||||
.set('organization-id', tenantWebsite.organizationId)
|
||||
.send();
|
||||
|
||||
const foundTransactions = await AccountTransaction.tenant().query();
|
||||
expect(foundTransactions.length).equals(0);
|
||||
});
|
||||
|
||||
it('Should revert accounts balance after delete account transactions.', () => {
|
||||
|
||||
});
|
||||
});
|
||||
|
||||
describe('route: GET `accounting/manual-journals/:id`', () => {
|
||||
it('Should response not found in case manual transaction id was not exists.', async () => {
|
||||
const res = await request()
|
||||
.delete('/api/accounting/manual-journals/100')
|
||||
.set('x-access-token', loginRes.body.token)
|
||||
.set('organization-id', tenantWebsite.organizationId)
|
||||
.send();
|
||||
|
||||
expect(res.status).equals(404);
|
||||
expect(res.body.errors).include.something.that.deep.equals({
|
||||
type: 'MANUAL.JOURNAL.NOT.FOUND', code: 100,
|
||||
});
|
||||
});
|
||||
|
||||
it('Should response manual transaction and transactions metadata.', async () => {
|
||||
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
describe('route: `accounting/manual-journals`', async () => {
|
||||
|
||||
it('Should retrieve all manual journals with pagination meta.', async () => {
|
||||
const manualJournal1 = await tenantFactory.create('manual_journal');
|
||||
const manualJournal2 = await tenantFactory.create('manual_journal');
|
||||
|
||||
const res = await request()
|
||||
.get('/api/accounting/manual-journals')
|
||||
.set('x-access-token', loginRes.body.token)
|
||||
.set('organization-id', tenantWebsite.organizationId)
|
||||
.send();
|
||||
|
||||
expect(res.status).equals(200);
|
||||
expect(res.body.manualJournals.results).to.be.a('array');
|
||||
expect(res.body.manualJournals.results.length).equals(2);
|
||||
});
|
||||
});
|
||||
|
||||
describe('route: POST `accounting/manual-journals/:id/publish`', () => {
|
||||
|
||||
it('Should response not found in case the manual journal id was not exists.', async () => {
|
||||
const manualJournal = await tenantFactory.create('manual_journal');
|
||||
|
||||
const res = await request()
|
||||
.post('/api/accounting/manual-journals/123/publish')
|
||||
.set('x-access-token', loginRes.body.token)
|
||||
.set('organization-id', tenantWebsite.organizationId)
|
||||
.send();
|
||||
|
||||
expect(res.status).equals(404);
|
||||
expect(res.body.errors).include.something.that.deep.equals({
|
||||
type: 'MANUAL.JOURNAL.NOT.FOUND', code: 100,
|
||||
});
|
||||
});
|
||||
|
||||
it('Should response published ready.', async () => {
|
||||
const manualJournal = await tenantFactory.create('manual_journal', { status: 1 });
|
||||
|
||||
const res = await request()
|
||||
.post(`/api/accounting/manual-journals/${manualJournal.id}/publish`)
|
||||
.set('x-access-token', loginRes.body.token)
|
||||
.set('organization-id', tenantWebsite.organizationId)
|
||||
.send();
|
||||
|
||||
expect(res.status).equals(400);
|
||||
expect(res.body.errors).include.something.that.deep.equals({
|
||||
type: 'MANUAL.JOURNAL.PUBLISHED.ALREADY', code: 200,
|
||||
});
|
||||
});
|
||||
|
||||
it('Should update all accounts transactions to not draft.', async () => {
|
||||
const manualJournal = await tenantFactory.create('manual_journal', { status: 0 });
|
||||
const transaction = await tenantFactory.create('account_transaction', {
|
||||
reference_type: 'Journal',
|
||||
reference_id: manualJournal.id,
|
||||
draft: 1,
|
||||
});
|
||||
const transaction2 = await tenantFactory.create('account_transaction', {
|
||||
reference_type: 'Journal',
|
||||
reference_id: manualJournal.id,
|
||||
draft: 1,
|
||||
});
|
||||
const res = await request()
|
||||
.post(`/api/accounting/manual-journals/${manualJournal.id}/publish`)
|
||||
.set('x-access-token', loginRes.body.token)
|
||||
.set('organization-id', tenantWebsite.organizationId)
|
||||
.send();
|
||||
|
||||
const foundTransactions = await AccountTransaction.tenant().query()
|
||||
.whereIn('id', [transaction.id, transaction2.id]);
|
||||
|
||||
expect(foundTransactions[0].draft).equals(0);
|
||||
expect(foundTransactions[1].draft).equals(0);
|
||||
});
|
||||
|
||||
it('Should increment/decrement accounts balance.', () => {
|
||||
|
||||
});
|
||||
});
|
||||
|
||||
describe('route: `/accounting/quick-journal-entries`', async () => {
|
||||
it('Shoud `credit_account_id` be required', () => {
|
||||
|
||||
});
|
||||
it('Should `debit_account_id` be required.', () => {
|
||||
|
||||
});
|
||||
|
||||
it('Should `amount` be required.', () => {
|
||||
|
||||
});
|
||||
|
||||
it('Should credit account id be exists.', () => {
|
||||
|
||||
});
|
||||
|
||||
it('Should debit account id be exists.', () => {
|
||||
|
||||
});
|
||||
|
||||
it('Should store the quick journal entry to the storage.', () => {
|
||||
|
||||
});
|
||||
});
|
||||
});
|
||||
758
packages/server/tests/routes/accounts.test.js
Normal file
758
packages/server/tests/routes/accounts.test.js
Normal file
@@ -0,0 +1,758 @@
|
||||
import {
|
||||
request,
|
||||
expect,
|
||||
} from '~/testInit';
|
||||
import Account from 'models/Account';
|
||||
import {
|
||||
tenantWebsite,
|
||||
tenantFactory,
|
||||
loginRes
|
||||
} from '~/dbInit';
|
||||
|
||||
|
||||
describe('routes: /accounts/', () => {
|
||||
describe('POST `/accounts`', () => {
|
||||
it('Should `name` be required.', async () => {
|
||||
const res = await request()
|
||||
.post('/api/accounts')
|
||||
.set('x-access-token', loginRes.body.token)
|
||||
.set('organization-id', tenantWebsite.organizationId)
|
||||
.send();
|
||||
|
||||
expect(res.status).equals(422);
|
||||
expect(res.body.code).equals('validation_error');
|
||||
});
|
||||
|
||||
it('Should `account_type_id` be required.', async () => {
|
||||
const res = await request()
|
||||
.post('/api/accounts')
|
||||
.set('x-access-token', loginRes.body.token)
|
||||
.set('organization-id', tenantWebsite.organizationId)
|
||||
.send();
|
||||
|
||||
expect(res.status).equals(422);
|
||||
expect(res.body.code).equals('validation_error');
|
||||
});
|
||||
|
||||
it('Should max length of `code` be limited.', async () => {
|
||||
const res = await request()
|
||||
.post('/api/accounts')
|
||||
.set('x-access-token', loginRes.body.token)
|
||||
.set('organization-id', tenantWebsite.organizationId)
|
||||
.send();
|
||||
|
||||
expect(res.status).equals(422);
|
||||
expect(res.body.code).equals('validation_error');
|
||||
});
|
||||
|
||||
it('Should response type not found in case `account_type_id` was not exist.', async () => {
|
||||
const account = await tenantFactory.create('account');
|
||||
const res = await request()
|
||||
.post('/api/accounts')
|
||||
.set('x-access-token', loginRes.body.token)
|
||||
.set('organization-id', tenantWebsite.organizationId)
|
||||
.send({
|
||||
name: 'Account Name',
|
||||
description: account.description,
|
||||
account_type_id: 22, // not found.
|
||||
code: 123,
|
||||
});
|
||||
|
||||
expect(res.status).equals(400);
|
||||
expect(res.body.errors).include.something.that.deep.equals({
|
||||
type: 'NOT_EXIST_ACCOUNT_TYPE', code: 200,
|
||||
});
|
||||
});
|
||||
|
||||
it('Should account code be unique in the storage.', async () => {
|
||||
const account = await tenantFactory.create('account');
|
||||
const res = await request()
|
||||
.post('/api/accounts')
|
||||
.set('x-access-token', loginRes.body.token)
|
||||
.set('organization-id', tenantWebsite.organizationId)
|
||||
.send({
|
||||
name: account.name,
|
||||
description: account.description,
|
||||
account_type_id: account.accountTypeId,
|
||||
code: account.code,
|
||||
});
|
||||
|
||||
expect(res.status).equals(400);
|
||||
expect(res.body.errors).include.something.that.deep.equals({
|
||||
type: 'NOT_UNIQUE_CODE', code: 100,
|
||||
});
|
||||
});
|
||||
|
||||
it('Should response success with correct data form.', async () => {
|
||||
const account = await tenantFactory.create('account');
|
||||
const res = await request()
|
||||
.post('/api/accounts')
|
||||
.set('x-access-token', loginRes.body.token)
|
||||
.set('organization-id', tenantWebsite.organizationId)
|
||||
.send({
|
||||
name: 'Name',
|
||||
description: 'description here',
|
||||
code: 100,
|
||||
account_type_id: account.accountTypeId,
|
||||
parent_account_id: account.id,
|
||||
});
|
||||
|
||||
expect(res.status).equals(200);
|
||||
});
|
||||
|
||||
it('Should store account data in the storage.', async () => {
|
||||
const account = await tenantFactory.create('account');
|
||||
|
||||
const res = await request().post('/api/accounts')
|
||||
.set('x-access-token', loginRes.body.token)
|
||||
.set('organization-id', tenantWebsite.organizationId)
|
||||
.send({
|
||||
name: 'Account Name',
|
||||
description: 'desc here',
|
||||
account_type_id: account.accountTypeId,
|
||||
parent_account_id: account.id,
|
||||
});
|
||||
|
||||
const accountModel = await Account.tenant().query()
|
||||
.where('name', 'Account Name')
|
||||
.first();
|
||||
|
||||
expect(accountModel).a.an('object');
|
||||
expect(accountModel.description).equals('desc here');
|
||||
expect(accountModel.accountTypeId).equals(account.accountTypeId);
|
||||
expect(accountModel.parentAccountId).equals(account.id);
|
||||
});
|
||||
});
|
||||
|
||||
describe('POST `/accounts/:id`', () => {
|
||||
it('Should `name` be required.', async () => {
|
||||
const account = await tenantFactory.create('account');
|
||||
const res = await request()
|
||||
.post(`/api/accounts/${account.id}`)
|
||||
.set('x-access-token', loginRes.body.token)
|
||||
.set('organization-id', tenantWebsite.organizationId)
|
||||
.send();
|
||||
|
||||
expect(res.status).equals(422);
|
||||
expect(res.body.code).equals('validation_error');
|
||||
});
|
||||
|
||||
it('Should `account_type_id` be required.', async () => {
|
||||
const account = await tenantFactory.create('account');
|
||||
const res = await request()
|
||||
.post(`/api/accounts/${account.id}`)
|
||||
.set('x-access-token', loginRes.body.token)
|
||||
.set('organization-id', tenantWebsite.organizationId)
|
||||
.send();
|
||||
|
||||
expect(res.status).equals(422);
|
||||
expect(res.body.code).equals('validation_error');
|
||||
});
|
||||
|
||||
it('Should max length of `code` be limited.', async () => {
|
||||
const account = await tenantFactory.create('account');
|
||||
const res = await request()
|
||||
.post(`/api/accounts/${account.id}`)
|
||||
.set('x-access-token', loginRes.body.token)
|
||||
.set('organization-id', tenantWebsite.organizationId)
|
||||
.send();
|
||||
|
||||
expect(res.status).equals(422);
|
||||
expect(res.body.code).equals('validation_error');
|
||||
});
|
||||
|
||||
it('Should response type not found in case `account_type_id` was not exist.', async () => {
|
||||
const res = await request()
|
||||
.post('/api/accounts')
|
||||
.set('x-access-token', loginRes.body.token)
|
||||
.set('organization-id', tenantWebsite.organizationId)
|
||||
.send();
|
||||
|
||||
expect(res.status).equals(422);
|
||||
});
|
||||
|
||||
it('Should account code be unique in the storage.', async () => {
|
||||
await tenantFactory.create('account', { code: 'ABCD' });
|
||||
const account = await tenantFactory.create('account');
|
||||
const res = await request()
|
||||
.post(`/api/accounts/${account.id}`)
|
||||
.set('x-access-token', loginRes.body.token)
|
||||
.set('organization-id', tenantWebsite.organizationId)
|
||||
.send({
|
||||
name: 'name',
|
||||
code: 'ABCD',
|
||||
account_type_id: account.accountTypeId,
|
||||
});
|
||||
|
||||
expect(res.status).equals(400);
|
||||
expect(res.body.errors).include.something.that.deep.equals({
|
||||
type: 'NOT_UNIQUE_CODE', code: 100,
|
||||
});
|
||||
});
|
||||
|
||||
it('Should response success with correct data form.', async () => {
|
||||
const account = await tenantFactory.create('account');
|
||||
const res = await request()
|
||||
.post('/api/accounts')
|
||||
.set('x-access-token', loginRes.body.token)
|
||||
.set('organization-id', tenantWebsite.organizationId)
|
||||
.send({
|
||||
name: 'Name',
|
||||
description: 'description here',
|
||||
account_type_id: account.accountTypeId,
|
||||
parent_account_id: account.id,
|
||||
code: '123',
|
||||
});
|
||||
|
||||
expect(res.status).equals(200);
|
||||
});
|
||||
});
|
||||
|
||||
describe('GET: `/accounts`', () => {
|
||||
it('Should retrieve chart of accounts', async () => {
|
||||
await tenantFactory.create('resource', { name: 'accounts' });
|
||||
const account = await tenantFactory.create('account');
|
||||
await tenantFactory.create('account', { parent_account_id: account.id });
|
||||
|
||||
const res = await request()
|
||||
.get('/api/accounts')
|
||||
.set('x-access-token', loginRes.body.token)
|
||||
.set('organization-id', tenantWebsite.organizationId)
|
||||
.send();
|
||||
|
||||
expect(res.status).equals(200);
|
||||
expect(res.body.accounts.length).above(0);
|
||||
});
|
||||
|
||||
it('Should retrieve accounts based on view roles conditionals of the custom view.', async () => {
|
||||
const resource = await tenantFactory.create('resource', { name: 'accounts' });
|
||||
|
||||
const accountTypeField = await tenantFactory.create('resource_field', {
|
||||
label_name: 'Account type',
|
||||
key: 'type',
|
||||
resource_id: resource.id,
|
||||
active: true,
|
||||
predefined: true,
|
||||
});
|
||||
|
||||
const accountNameField = await tenantFactory.create('resource_field', {
|
||||
label_name: 'Account Name',
|
||||
key: 'name',
|
||||
resource_id: resource.id,
|
||||
active: true,
|
||||
predefined: true,
|
||||
});
|
||||
const accountsView = await tenantFactory.create('view', {
|
||||
name: 'Accounts View',
|
||||
resource_id: resource.id,
|
||||
roles_logic_expression: '1 AND 2',
|
||||
});
|
||||
const accountType = await tenantFactory.create('account_type');
|
||||
|
||||
await tenantFactory.create('view_role', {
|
||||
view_id: accountsView.id,
|
||||
index: 1,
|
||||
field_id: accountTypeField.id,
|
||||
value: accountType.name,
|
||||
comparator: 'equals',
|
||||
});
|
||||
await tenantFactory.create('view_role', {
|
||||
view_id: accountsView.id,
|
||||
index: 2,
|
||||
field_id: accountNameField.id,
|
||||
value: 'account',
|
||||
comparator: 'contains',
|
||||
});
|
||||
|
||||
await tenantFactory.create('account', { name: 'account-1', account_type_id: accountType.id });
|
||||
await tenantFactory.create('account', { name: 'account-2', account_type_id: accountType.id });
|
||||
await tenantFactory.create('account', { name: 'account-3' });
|
||||
|
||||
const res = await request()
|
||||
.get('/api/accounts')
|
||||
.set('x-access-token', loginRes.body.token)
|
||||
.set('organization-id', tenantWebsite.organizationId)
|
||||
.query({
|
||||
custom_view_id: accountsView.id
|
||||
})
|
||||
.send();
|
||||
|
||||
expect(res.body.accounts.length).equals(2);
|
||||
expect(res.body.accounts[0].name).equals('account-1');
|
||||
expect(res.body.accounts[1].name).equals('account-2');
|
||||
expect(res.body.accounts[0].account_type_id).equals(accountType.id);
|
||||
expect(res.body.accounts[1].account_type_id).equals(accountType.id);
|
||||
});
|
||||
|
||||
it('Should retrieve accounts based on view roles conditionals with relation join column.', async () => {
|
||||
const resource = await tenantFactory.create('resource', { name: 'accounts' });
|
||||
|
||||
const accountTypeField = await tenantFactory.create('resource_field', {
|
||||
label_name: 'Account type',
|
||||
key: 'type',
|
||||
resource_id: resource.id,
|
||||
active: true,
|
||||
predefined: true,
|
||||
});
|
||||
const accountsView = await tenantFactory.create('view', {
|
||||
name: 'Accounts View',
|
||||
resource_id: resource.id,
|
||||
roles_logic_expression: '1',
|
||||
});
|
||||
|
||||
const accountType = await tenantFactory.create('account_type');
|
||||
const accountsViewRole = await tenantFactory.create('view_role', {
|
||||
view_id: accountsView.id,
|
||||
index: 1,
|
||||
field_id: accountTypeField.id,
|
||||
value: accountType.name,
|
||||
comparator: 'equals',
|
||||
});
|
||||
|
||||
await tenantFactory.create('account', { account_type_id: accountType.id });
|
||||
await tenantFactory.create('account');
|
||||
await tenantFactory.create('account');
|
||||
|
||||
const res = await request()
|
||||
.get('/api/accounts')
|
||||
.set('x-access-token', loginRes.body.token)
|
||||
.set('organization-id', tenantWebsite.organizationId)
|
||||
.query({
|
||||
custom_view_id: accountsView.id
|
||||
})
|
||||
.send();
|
||||
|
||||
expect(res.body.accounts.length).equals(1);
|
||||
expect(res.body.accounts[0].account_type_id).equals(accountType.id);
|
||||
});
|
||||
|
||||
it('Should retrieve accounts and child accounts in nested set graph.', async () => {
|
||||
const resource = await tenantFactory.create('resource', { name: 'accounts' });
|
||||
|
||||
const account1 = await tenantFactory.create('account');
|
||||
const account2 = await tenantFactory.create('account', { parent_account_id: account1.id });
|
||||
const account3 = await tenantFactory.create('account', { parent_account_id: account2.id });
|
||||
|
||||
const res = await request()
|
||||
.get('/api/accounts')
|
||||
.set('x-access-token', loginRes.body.token)
|
||||
.set('organization-id', tenantWebsite.organizationId)
|
||||
.send();
|
||||
|
||||
expect(res.status).equals(200);
|
||||
|
||||
const foundAccount = res.body.accounts.find(a => a.id === account1.id);
|
||||
|
||||
expect(foundAccount.id).equals(account1.id);
|
||||
expect(foundAccount.children[0].id).equals(account2.id);
|
||||
expect(foundAccount.children[0].children[0].id).equals(account3.id);
|
||||
});
|
||||
|
||||
it('Should retrieve bad request when `filter_roles.*.comparator` not associated to `field_key`.', () => {
|
||||
|
||||
});
|
||||
|
||||
it('Should retrieve bad request when `filter_roles.*.field_key` not found in accounts resource.', async () => {
|
||||
const resource = await tenantFactory.create('resource', { name: 'accounts' });
|
||||
|
||||
const account1 = await tenantFactory.create('account', { name: 'ahmed' });
|
||||
const account2 = await tenantFactory.create('account');
|
||||
const account3 = await tenantFactory.create('account');
|
||||
|
||||
const res = await request()
|
||||
.get('/api/accounts')
|
||||
.set('x-access-token', loginRes.body.token)
|
||||
.set('organization-id', tenantWebsite.organizationId)
|
||||
.query({
|
||||
stringified_filter_roles: JSON.stringify([{
|
||||
condition: 'AND',
|
||||
field_key: 'not_found',
|
||||
comparator: 'equals',
|
||||
value: 'ahmed',
|
||||
}, {
|
||||
condition: 'AND',
|
||||
field_key: 'mybe_found',
|
||||
comparator: 'equals',
|
||||
value: 'ahmed',
|
||||
}]),
|
||||
});
|
||||
|
||||
expect(res.body.errors).include.something.that.deep.equals({
|
||||
type: 'ACCOUNTS.RESOURCE.HAS.NO.GIVEN.FIELDS', code: 500,
|
||||
});
|
||||
});
|
||||
|
||||
it('Should retrieve bad request when `filter_roles.*.condition` is invalid.', async () => {
|
||||
|
||||
});
|
||||
|
||||
it('Should retrieve filtered accounts according to the given account type filter condition.', async () => {
|
||||
const resource = await tenantFactory.create('resource', { name: 'accounts' });
|
||||
const keyField = await tenantFactory.create('resource_field', {
|
||||
key: 'type',
|
||||
resource_id: resource.id,
|
||||
});
|
||||
const nameFiled = await tenantFactory.create('resource_field', {
|
||||
key: 'name',
|
||||
resource_id: resource.id,
|
||||
});
|
||||
const accountType = await tenantFactory.create('account_type');
|
||||
|
||||
const account1 = await tenantFactory.create('account', {
|
||||
name: 'ahmed',
|
||||
account_type_id: accountType.id
|
||||
});
|
||||
const account2 = await tenantFactory.create('account');
|
||||
const account3 = await tenantFactory.create('account');
|
||||
|
||||
const res = await request()
|
||||
.get('/api/accounts')
|
||||
.set('x-access-token', loginRes.body.token)
|
||||
.set('organization-id', tenantWebsite.organizationId)
|
||||
.query({
|
||||
stringified_filter_roles: JSON.stringify([{
|
||||
condition: '&&',
|
||||
field_key: 'type',
|
||||
comparator: 'equals',
|
||||
value: accountType.name,
|
||||
}, {
|
||||
condition: '&&',
|
||||
field_key: 'name',
|
||||
comparator: 'equals',
|
||||
value: 'ahmed',
|
||||
}]),
|
||||
});
|
||||
|
||||
expect(res.body.accounts.length).equals(1);
|
||||
});
|
||||
|
||||
it('Shoud retrieve filtered accounts according to the given account description filter condition.', async () => {
|
||||
const resource = await tenantFactory.create('resource', { name: 'accounts' });
|
||||
const resourceField = await tenantFactory.create('resource_field', {
|
||||
key: 'description',
|
||||
resource_id: resource.id,
|
||||
});
|
||||
|
||||
const account1 = await tenantFactory.create('account', { name: 'ahmed', description: 'here' });
|
||||
const account2 = await tenantFactory.create('account');
|
||||
const account3 = await tenantFactory.create('account');
|
||||
|
||||
const res = await request()
|
||||
.get('/api/accounts')
|
||||
.set('x-access-token', loginRes.body.token)
|
||||
.set('organization-id', tenantWebsite.organizationId)
|
||||
.query({
|
||||
stringified_filter_roles: JSON.stringify([{
|
||||
condition: 'AND',
|
||||
field_key: resourceField.key,
|
||||
comparator: 'contain',
|
||||
value: 'here',
|
||||
}]),
|
||||
});
|
||||
|
||||
expect(res.body.accounts.length).equals(1);
|
||||
expect(res.body.accounts[0].description).equals('here');
|
||||
});
|
||||
|
||||
it('Should retrieve filtered accounts based on given filter roles between OR conditions.', async () => {
|
||||
const resource = await tenantFactory.create('resource', { name: 'accounts' });
|
||||
const resourceField = await tenantFactory.create('resource_field', {
|
||||
key: 'description',
|
||||
resource_id: resource.id,
|
||||
});
|
||||
|
||||
const resourceCodeField = await tenantFactory.create('resource_field', {
|
||||
key: 'code',
|
||||
resource_id: resource.id,
|
||||
});
|
||||
|
||||
const account1 = await tenantFactory.create('account', { name: 'ahmed', description: 'target' });
|
||||
const account2 = await tenantFactory.create('account', { description: 'target' });
|
||||
const account3 = await tenantFactory.create('account');
|
||||
|
||||
const res = await request()
|
||||
.get('/api/accounts')
|
||||
.set('x-access-token', loginRes.body.token)
|
||||
.set('organization-id', tenantWebsite.organizationId)
|
||||
.query({
|
||||
stringified_filter_roles: JSON.stringify([{
|
||||
condition: '&&',
|
||||
field_key: resourceField.key,
|
||||
comparator: 'contain',
|
||||
value: 'target',
|
||||
}, {
|
||||
condition: '||',
|
||||
field_key: resourceCodeField.key,
|
||||
comparator: 'equals',
|
||||
value: 'ahmed',
|
||||
}]),
|
||||
});
|
||||
|
||||
expect(res.body.accounts.length).equals(2);
|
||||
expect(res.body.accounts[0].description).equals('target');
|
||||
expect(res.body.accounts[1].description).equals('target');
|
||||
expect(res.body.accounts[0].name).equals('ahmed');
|
||||
});
|
||||
|
||||
it('Should retrieve filtered accounts from custom view and filter roles.', async () => {
|
||||
const resource = await tenantFactory.create('resource', { name: 'accounts' });
|
||||
const accountTypeField = await tenantFactory.create('resource_field', {
|
||||
key: 'type', resource_id: resource.id,
|
||||
});
|
||||
const accountDescriptionField = await tenantFactory.create('resource_field', {
|
||||
key: 'description', resource_id: resource.id,
|
||||
});
|
||||
|
||||
const accountType = await tenantFactory.create('account_type', { name: 'type-name' });
|
||||
|
||||
const account1 = await tenantFactory.create('account', { name: 'ahmed-1' });
|
||||
const account2 = await tenantFactory.create('account', { name: 'ahmed-2', account_type_id: accountType.id, description: 'target' });
|
||||
const account3 = await tenantFactory.create('account', { name: 'ahmed-3' });
|
||||
|
||||
const accountsView = await tenantFactory.create('view', {
|
||||
name: 'Accounts View',
|
||||
resource_id: resource.id,
|
||||
roles_logic_expression: '1',
|
||||
});
|
||||
const accountsViewRole = await tenantFactory.create('view_role', {
|
||||
view_id: accountsView.id,
|
||||
field_id: accountTypeField.id,
|
||||
index: 1,
|
||||
value: 'type-name',
|
||||
comparator: 'equals',
|
||||
});
|
||||
|
||||
const res = await request()
|
||||
.get('/api/accounts')
|
||||
.set('x-access-token', loginRes.body.token)
|
||||
.set('organization-id', tenantWebsite.organizationId)
|
||||
.query({
|
||||
custom_view_id: accountsView.id,
|
||||
stringified_filter_roles: JSON.stringify([{
|
||||
condition: 'AND',
|
||||
field_key: 'description',
|
||||
comparator: 'contain',
|
||||
value: 'target',
|
||||
}]),
|
||||
});
|
||||
|
||||
expect(res.body.accounts.length).equals(1);
|
||||
expect(res.body.accounts[0].name).equals('ahmed-2');
|
||||
expect(res.body.accounts[0].description).equals('target');
|
||||
});
|
||||
|
||||
it('Should validate the given `column_sort_order` column on the accounts resource.', async () => {
|
||||
const resource = await tenantFactory.create('resource', { name: 'accounts' });
|
||||
const res = await request()
|
||||
.get('/api/accounts')
|
||||
.set('x-access-token', loginRes.body.token)
|
||||
.set('organization-id', tenantWebsite.organizationId)
|
||||
.query({
|
||||
column_sort_by: 'not_found',
|
||||
sort_order: 'desc',
|
||||
});
|
||||
|
||||
expect(res.body.errors).include.something.that.deep.equals({
|
||||
type: 'COLUMN.SORT.ORDER.NOT.FOUND', code: 300,
|
||||
});
|
||||
});
|
||||
|
||||
it('Should sorting the given `column_sort_order` column on asc direction,', async () => {
|
||||
const resource = await tenantFactory.create('resource', { name: 'accounts' });
|
||||
const resourceField = await tenantFactory.create('resource_field', {
|
||||
key: 'name', resource_id: resource.id,
|
||||
});
|
||||
const accounts1 = await tenantFactory.create('account', { name: 'A' });
|
||||
const accounts2 = await tenantFactory.create('account', { name: 'B' });
|
||||
|
||||
const res = await request()
|
||||
.get('/api/accounts')
|
||||
.set('x-access-token', loginRes.body.token)
|
||||
.set('organization-id', tenantWebsite.organizationId)
|
||||
.query({
|
||||
column_sort_by: 'name',
|
||||
sort_order: 'asc',
|
||||
});
|
||||
|
||||
const AAccountIndex = res.body.accounts.findIndex(a => a.name === 'B');
|
||||
const BAccountIndex = res.body.accounts.findIndex(a => a.name === 'A');
|
||||
|
||||
expect(AAccountIndex).above(BAccountIndex);
|
||||
});
|
||||
|
||||
it('Should sorting the given `column_sort_order` columnw with relation on another table on asc direction.', async () => {
|
||||
const resource = await tenantFactory.create('resource', { name: 'accounts' });
|
||||
const resourceField = await tenantFactory.create('resource_field', {
|
||||
key: 'type', resource_id: resource.id,
|
||||
});
|
||||
const accounts1 = await tenantFactory.create('account', { name: 'A' });
|
||||
const accounts2 = await tenantFactory.create('account', { name: 'B' });
|
||||
|
||||
const res = await request()
|
||||
.get('/api/accounts')
|
||||
.set('x-access-token', loginRes.body.token)
|
||||
.set('organization-id', tenantWebsite.organizationId)
|
||||
.query({
|
||||
column_sort_by: 'name',
|
||||
sort_order: 'asc',
|
||||
});
|
||||
|
||||
expect(res.body.accounts[0].name).equals('A');
|
||||
expect(res.body.accounts[1].name).equals('B');
|
||||
});
|
||||
});
|
||||
|
||||
describe('DELETE: `/accounts`', () => {
|
||||
it('Should response not found in case account was not exist.', async () => {
|
||||
const res = await request()
|
||||
.delete('/api/accounts/10')
|
||||
.set('x-access-token', loginRes.body.token)
|
||||
.set('organization-id', tenantWebsite.organizationId)
|
||||
.send();
|
||||
|
||||
expect(res.status).equals(404);
|
||||
});
|
||||
|
||||
it('Should delete the give account from the storage.', async () => {
|
||||
const account = await tenantFactory.create('account');
|
||||
await request()
|
||||
.delete(`/api/accounts/${account.id}`)
|
||||
.set('x-access-token', loginRes.body.token)
|
||||
.set('organization-id', tenantWebsite.organizationId)
|
||||
.send();
|
||||
|
||||
const foundAccounts = await Account.tenant().query().where('id', account.id);
|
||||
expect(foundAccounts).to.have.lengthOf(0);
|
||||
});
|
||||
|
||||
it('Should not delete the given account in case account has associated transactions.', async () => {
|
||||
const accountTransaction = await tenantFactory.create('account_transaction');
|
||||
|
||||
const res = await request()
|
||||
.delete(`/api/accounts/${accountTransaction.accountId}`)
|
||||
.set('x-access-token', loginRes.body.token)
|
||||
.set('organization-id', tenantWebsite.organizationId)
|
||||
.send();
|
||||
|
||||
expect(res.status).equals(400);
|
||||
expect(res.body.errors).include.something.that.deep.equals({
|
||||
type: 'ACCOUNT.HAS.ASSOCIATED.TRANSACTIONS', code: 100,
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('DELETE: `/accounts?ids=`', () => {
|
||||
it('Should response in case on of accounts ids was not exists.', async () => {
|
||||
const res = await request()
|
||||
.delete('/api/accounts')
|
||||
.set('x-access-token', loginRes.body.token)
|
||||
.set('organization-id', tenantWebsite.organizationId)
|
||||
.query({
|
||||
ids: [100, 200],
|
||||
})
|
||||
.send();
|
||||
|
||||
expect(res.status).equals(404);
|
||||
expect(res.body.errors).include.something.that.deep.equals({
|
||||
type: 'ACCOUNTS.IDS.NOT.FOUND', code: 200, ids: [100, 200],
|
||||
});
|
||||
});
|
||||
|
||||
it('Should response bad request in case one of accounts has transactions.', async () => {
|
||||
const accountTransaction = await tenantFactory.create('account_transaction');
|
||||
const accountTransaction2 = await tenantFactory.create('account_transaction');
|
||||
|
||||
const res = await request()
|
||||
.delete('/api/accounts')
|
||||
.set('x-access-token', loginRes.body.token)
|
||||
.set('organization-id', tenantWebsite.organizationId)
|
||||
.query({
|
||||
ids: [accountTransaction.accountId, accountTransaction2.accountId],
|
||||
})
|
||||
.send();
|
||||
|
||||
expect(res.body.errors).include.something.that.deep.equals({
|
||||
type: 'ACCOUNT.HAS.ASSOCIATED.TRANSACTIONS',
|
||||
code: 300,
|
||||
ids: [accountTransaction.accountId, accountTransaction2.accountId],
|
||||
});
|
||||
});
|
||||
|
||||
it('Should delete the given accounts from the storage.', async () => {
|
||||
const account1 = await tenantFactory.create('account');
|
||||
const account2 = await tenantFactory.create('account');
|
||||
|
||||
const res = await request()
|
||||
.delete('/api/accounts')
|
||||
.set('x-access-token', loginRes.body.token)
|
||||
.set('organization-id', tenantWebsite.organizationId)
|
||||
.query({
|
||||
ids: [account1.id, account2.id],
|
||||
})
|
||||
.send();
|
||||
|
||||
expect(res.status).equals(200);
|
||||
|
||||
const foundAccounts = await Account.tenant().query()
|
||||
.whereIn('id', [account1.id, account2.id]);
|
||||
|
||||
expect(foundAccounts.length).equals(0);
|
||||
});
|
||||
});
|
||||
|
||||
describe('POST: `/api/accounts/bulk/activate|inactivate', () => {
|
||||
it('Should response if there one of accounts ids were not found.', async () => {
|
||||
const res = await request()
|
||||
.post('/api/accounts/bulk/activate')
|
||||
.set('x-access-token', loginRes.body.token)
|
||||
.set('organization-id', tenantWebsite.organizationId)
|
||||
.query({
|
||||
ids: [123123, 321321],
|
||||
})
|
||||
.send();
|
||||
|
||||
expect(res.status).equals(400);
|
||||
expect(res.body.errors).include.something.that.deep.equals({
|
||||
type: 'ACCOUNTS.NOT.FOUND', code: 200,
|
||||
});
|
||||
});
|
||||
|
||||
it('Should activate all the given accounts.', async () => {
|
||||
const accountA = await tenantFactory.create('account', { active: 1 });
|
||||
const accountB = await tenantFactory.create('account', { active: 1 });
|
||||
|
||||
const res = await request()
|
||||
.post('/api/accounts/bulk/inactivate')
|
||||
.set('x-access-token', loginRes.body.token)
|
||||
.set('organization-id', tenantWebsite.organizationId)
|
||||
.query({
|
||||
ids: [accountA.id, accountB.id],
|
||||
})
|
||||
.send();
|
||||
|
||||
const updatedAccounts = await Account.tenant().query().whereIn('id', [accountA.id, accountB.id]);
|
||||
|
||||
expect(updatedAccounts[0].active).equals(0);
|
||||
expect(updatedAccounts[1].active).equals(0);
|
||||
});
|
||||
|
||||
it('Should inactivate all the given accounts.', async () => {
|
||||
const accountA = await tenantFactory.create('account', { active: 0 });
|
||||
const accountB = await tenantFactory.create('account', { active: 0 });
|
||||
|
||||
const res = await request()
|
||||
.post('/api/accounts/bulk/activate')
|
||||
.set('x-access-token', loginRes.body.token)
|
||||
.set('organization-id', tenantWebsite.organizationId)
|
||||
.query({
|
||||
ids: [accountA.id, accountB.id],
|
||||
})
|
||||
.send();
|
||||
|
||||
const updatedAccounts = await Account.tenant().query().whereIn('id', [accountA.id, accountB.id]);
|
||||
|
||||
expect(updatedAccounts[0].active).equals(1);
|
||||
expect(updatedAccounts[1].active).equals(1);
|
||||
});
|
||||
});
|
||||
});
|
||||
288
packages/server/tests/routes/auth.test.js
Normal file
288
packages/server/tests/routes/auth.test.js
Normal file
@@ -0,0 +1,288 @@
|
||||
import { request, expect, createUser } from '~/testInit';
|
||||
import { hashPassword } from 'utils';
|
||||
import knex from '@/database/knex';
|
||||
import {
|
||||
tenantWebsite,
|
||||
tenantFactory,
|
||||
systemFactory,
|
||||
loginRes
|
||||
} from '~/dbInit';
|
||||
import TenantUser from 'models/TenantUser';
|
||||
import PasswordReset from '@/system/models/PasswordReset';
|
||||
import SystemUser from '@/system/models/SystemUser';
|
||||
|
||||
|
||||
describe('routes: /auth/', () => {
|
||||
describe('POST `/api/auth/login`', () => {
|
||||
it('Should `crediential` be required.', async () => {
|
||||
const res = await request().post('/api/auth/login').send({});
|
||||
expect(res.status).equals(422);
|
||||
expect(res.body.code).equals('validation_error');
|
||||
|
||||
const paramsErrors = res.body.errors.map((error) => error.param);
|
||||
expect(paramsErrors).to.include('crediential');
|
||||
});
|
||||
|
||||
it('Should `password` be required.', async () => {
|
||||
const res = await request().post('/api/auth/login').send();
|
||||
expect(res.status).equals(422);
|
||||
expect(res.body.code).equals('validation_error');
|
||||
|
||||
const paramsErrors = res.body.errors.map((error) => error.param);
|
||||
expect(paramsErrors).to.include('password');
|
||||
});
|
||||
|
||||
it('Should the min length of the `password` be 5 ch.', async () => {
|
||||
const res = await request().post('/api/auth/login').send({
|
||||
crediential: 'admin@admin.com',
|
||||
password: 'test',
|
||||
});
|
||||
|
||||
expect(res.status).equals(422);
|
||||
expect(res.body.code).equals('validation_error');
|
||||
|
||||
const paramsErrors = res.body.errors.map((error) => error.param);
|
||||
expect(paramsErrors).to.include('password');
|
||||
});
|
||||
|
||||
it('Should be a valid email format in crediential attribute.', async () => {
|
||||
const res = await request().post('/api/auth/login').send({
|
||||
crediential: 'admin',
|
||||
password: 'test',
|
||||
});
|
||||
|
||||
expect(res.status).equals(422);
|
||||
expect(res.body.code).equals('validation_error');
|
||||
|
||||
const paramsErrors = res.body.errors.map((error) => error.param);
|
||||
expect(paramsErrors).to.include('password');
|
||||
});
|
||||
|
||||
it('Should not authenticate with wrong user email and password.', async () => {
|
||||
const res = await request().post('/api/auth/login').send({
|
||||
crediential: 'admin@admin.com',
|
||||
password: 'admin',
|
||||
});
|
||||
expect(res.body.errors).include.something.that.deep.equals({
|
||||
type: 'INVALID_DETAILS', code: 100,
|
||||
});
|
||||
});
|
||||
|
||||
it('Should not authenticate in case user was not active.', async () => {
|
||||
const user = await createUser(tenantWebsite, {
|
||||
active: false,
|
||||
email: 'admin@admin.com',
|
||||
});
|
||||
|
||||
const res = await request().post('/api/auth/login').send({
|
||||
crediential: 'admin@admin.com',
|
||||
password: 'admin',
|
||||
});
|
||||
expect(res.status).equals(400);
|
||||
expect(res.body.errors).include.something.that.deep.equals({
|
||||
type: 'USER_INACTIVE', code: 110,
|
||||
});
|
||||
});
|
||||
|
||||
it('Should authenticate with correct email and password and active user.', async () => {
|
||||
const user = await createUser(tenantWebsite, {
|
||||
email: 'admin@admin.com',
|
||||
});
|
||||
const res = await request().post('/api/auth/login').send({
|
||||
crediential: user.email,
|
||||
password: 'admin',
|
||||
});
|
||||
expect(res.status).equals(200);
|
||||
});
|
||||
|
||||
it('Should autheticate success with correct phone number and password.', async () => {
|
||||
const password = await hashPassword('admin');
|
||||
const user = await createUser(tenantWebsite, {
|
||||
phone_number: '0920000000',
|
||||
password,
|
||||
});
|
||||
const res = await request().post('/api/auth/login').send({
|
||||
crediential: user.email,
|
||||
password: 'admin',
|
||||
});
|
||||
|
||||
expect(res.status).equals(200);
|
||||
});
|
||||
|
||||
it('Should last login date be saved after success login.', async () => {
|
||||
const user = await createUser(tenantWebsite, {
|
||||
email: 'admin@admin.com',
|
||||
});
|
||||
const res = await request().post('/api/auth/login').send({
|
||||
crediential: user.email,
|
||||
password: 'admin',
|
||||
});
|
||||
const foundUserAfterUpdate = await TenantUser.tenant().query()
|
||||
.where('email', user.email)
|
||||
.where('first_name', user.first_name)
|
||||
.first();
|
||||
|
||||
expect(res.status).equals(200);
|
||||
expect(foundUserAfterUpdate.lastLoginAt).to.not.be.null;
|
||||
});
|
||||
});
|
||||
|
||||
describe('POST: `/auth/send_reset_password`', () => {
|
||||
it('Should `email` be required.', async () => {
|
||||
const res = await request().post('/api/auth/send_reset_password').send();
|
||||
|
||||
expect(res.status).equals(422);
|
||||
expect(res.body.code).equals('validation_error');
|
||||
});
|
||||
|
||||
it('Should response unproccessable if the email address was invalid.', async () => {
|
||||
const res = await request().post('/api/auth/send_reset_password').send({
|
||||
email: 'invalid_email',
|
||||
});
|
||||
|
||||
expect(res.status).equals(422);
|
||||
expect(res.body.code).equals('validation_error');
|
||||
});
|
||||
|
||||
it('Should response unproccessable if the email address was not exist.', async () => {
|
||||
const res = await request().post('/api/auth/send_reset_password').send({
|
||||
email: 'admin@admin.com',
|
||||
});
|
||||
|
||||
expect(res.status).equals(400);
|
||||
expect(res.body.errors).include.something.that.deep.equals({
|
||||
type: 'EMAIL.NOT.REGISTERED', code: 200,
|
||||
});
|
||||
});
|
||||
|
||||
it('Should delete all already tokens that associate to the given email.', async () => {
|
||||
const user = await createUser(tenantWebsite);
|
||||
const token = '123123';
|
||||
|
||||
await knex('password_resets').insert({ email: user.email, token });
|
||||
|
||||
await request().post('/api/auth/send_reset_password').send({
|
||||
email: user.email,
|
||||
});
|
||||
|
||||
const oldPasswordToken = await knex('password_resets').where('token', token);
|
||||
|
||||
expect(oldPasswordToken).to.have.lengthOf(0);
|
||||
});
|
||||
|
||||
it('Should store new token associate with the given email.', async () => {
|
||||
const user = await createUser(tenantWebsite);
|
||||
await request().post('/api/auth/send_reset_password').send({
|
||||
email: user.email,
|
||||
});
|
||||
|
||||
const token = await knex('password_resets').where('email', user.email);
|
||||
|
||||
expect(token).to.have.lengthOf(1);
|
||||
});
|
||||
|
||||
it('Should response success if the email was exist.', async () => {
|
||||
const user = await createUser(tenantWebsite);
|
||||
const res = await request().post('/api/auth/send_reset_password').send({
|
||||
email: user.email,
|
||||
});
|
||||
|
||||
expect(res.status).equals(200);
|
||||
});
|
||||
});
|
||||
|
||||
describe('POST: `/auth/reset/:token`', () => {
|
||||
// it('Should response forbidden if the token was invalid.', () => {
|
||||
|
||||
// });
|
||||
|
||||
it('Should response forbidden if the token was expired.', () => {
|
||||
|
||||
});
|
||||
|
||||
it('Should `password` be required.', async () => {
|
||||
const user = await createUser(tenantWebsite);
|
||||
const passwordReset = await systemFactory.create('password_reset', {
|
||||
email: user.email,
|
||||
});
|
||||
|
||||
const res = await request()
|
||||
.post(`/api/auth/reset/${passwordReset.token}`)
|
||||
.send();
|
||||
|
||||
expect(res.status).equals(422);
|
||||
expect(res.body.code).equals('validation_error');
|
||||
|
||||
const paramsErrors = res.body.errors.map((error) => error.param);
|
||||
expect(paramsErrors).to.include('password');
|
||||
});
|
||||
|
||||
it('Should password and confirm_password be equal.', async () => {
|
||||
const user = await createUser(tenantWebsite);
|
||||
const passwordReset = await systemFactory.create('password_reset', {
|
||||
email: user.email,
|
||||
});
|
||||
|
||||
const res = await request()
|
||||
.post(`/api/auth/reset/${passwordReset.token}`)
|
||||
.send({
|
||||
password: '123123',
|
||||
});
|
||||
|
||||
expect(res.status).equals(422);
|
||||
expect(res.body.code).equals('validation_error');
|
||||
|
||||
const paramsErrors = res.body.errors.map((error) => error.param);
|
||||
expect(paramsErrors).to.include('password');
|
||||
});
|
||||
|
||||
it('Should response success with correct data form.', async () => {
|
||||
const user = await createUser(tenantWebsite);
|
||||
const passwordReset = await systemFactory.create('password_reset', {
|
||||
email: user.email,
|
||||
});
|
||||
|
||||
const res = await request()
|
||||
.post(`/api/auth/reset/${passwordReset.token}`)
|
||||
.send({
|
||||
password: '123123',
|
||||
confirm_password: '123123',
|
||||
});
|
||||
expect(res.status).equals(200);
|
||||
});
|
||||
|
||||
it('Should token be deleted after success response.', async () => {
|
||||
const user = await createUser(tenantWebsite);
|
||||
const passwordReset = await systemFactory.create('password_reset', {
|
||||
email: user.email,
|
||||
});
|
||||
await request()
|
||||
.post(`/api/auth/reset/${passwordReset.token}`)
|
||||
.send({
|
||||
password: '123123',
|
||||
confirm_password: '123123',
|
||||
});
|
||||
|
||||
const foundTokens = await PasswordReset.query().where('email', passwordReset.email);
|
||||
|
||||
expect(foundTokens).to.have.lengthOf(0);
|
||||
});
|
||||
|
||||
it('Should password be updated after success response.', async () => {
|
||||
const user = await createUser(tenantWebsite);
|
||||
const passwordReset = await systemFactory.create('password_reset', {
|
||||
email: user.email,
|
||||
});
|
||||
|
||||
const res = await request().post(`/api/auth/reset/${passwordReset.token}`).send({
|
||||
password: '123123',
|
||||
confirm_password: '123123',
|
||||
});
|
||||
const systemUserPasswordUpdated = await SystemUser.query()
|
||||
.where('id', user.id).first();
|
||||
|
||||
expect(systemUserPasswordUpdated.id).equals(user.id);
|
||||
expect(systemUserPasswordUpdated.password).not.equals(user.password);
|
||||
});
|
||||
});
|
||||
});
|
||||
541
packages/server/tests/routes/balance_sheet.test.js
Normal file
541
packages/server/tests/routes/balance_sheet.test.js
Normal file
@@ -0,0 +1,541 @@
|
||||
import moment from 'moment';
|
||||
import {
|
||||
request,
|
||||
expect,
|
||||
} from '~/testInit';
|
||||
import {
|
||||
tenantWebsite,
|
||||
tenantFactory,
|
||||
loginRes
|
||||
} from '~/dbInit';
|
||||
import { iteratee } from 'lodash';
|
||||
|
||||
let creditAccount;
|
||||
let debitAccount;
|
||||
let incomeAccount;
|
||||
let incomeType;
|
||||
|
||||
describe('routes: `/financial_statements`', () => {
|
||||
beforeEach(async () => {
|
||||
const accountTransactionMixied = { date: '2020-1-10' };
|
||||
|
||||
// Expense --
|
||||
// 1000 Credit - Cash account
|
||||
// 1000 Debit - Bank account.
|
||||
await tenantFactory.create('account_transaction', {
|
||||
credit: 1000, debit: 0, account_id: 2, referenceType: 'Expense',
|
||||
referenceId: 1, ...accountTransactionMixied,
|
||||
});
|
||||
await tenantFactory.create('account_transaction', {
|
||||
credit: 0, debit: 1000, account_id: 7, referenceType: 'Expense',
|
||||
referenceId: 1, ...accountTransactionMixied,
|
||||
});
|
||||
|
||||
// Jounral
|
||||
// 4000 Credit - Opening balance account.
|
||||
// 2000 Debit - Bank account
|
||||
// 2000 Debit - Bank account
|
||||
await tenantFactory.create('account_transaction', {
|
||||
credit: 4000, debit: 0, account_id: 5, ...accountTransactionMixied,
|
||||
});
|
||||
await tenantFactory.create('account_transaction', {
|
||||
debit: 2000, credit: 0, account_id: 2, ...accountTransactionMixied,
|
||||
});
|
||||
await tenantFactory.create('account_transaction', {
|
||||
debit: 2000, credit: 0, account_id: 2, ...accountTransactionMixied,
|
||||
});
|
||||
|
||||
// Income Journal.
|
||||
// 2000 Credit - Income account.
|
||||
// 2000 Debit - Bank account.
|
||||
await tenantFactory.create('account_transaction', {
|
||||
credit: 2000, account_id: 4, ...accountTransactionMixied
|
||||
});
|
||||
await tenantFactory.create('account_transaction', {
|
||||
debit: 2000, credit: 0, account_id: 2, ...accountTransactionMixied,
|
||||
});
|
||||
|
||||
// -----------------------------------------
|
||||
// Bank account balance = 5000 | Opening balance account balance = 4000
|
||||
// Expense account balance = 1000 | Income account balance = 2000
|
||||
});
|
||||
|
||||
describe('routes: `financial_statements/balance_sheet`', () => {
|
||||
it('Should response unauthorzied in case the user was not authorized.', async () => {
|
||||
const res = await request()
|
||||
.get('/api/financial_statements/balance_sheet')
|
||||
.send();
|
||||
|
||||
expect(res.status).equals(401);
|
||||
});
|
||||
|
||||
it('Should retrieve query of the balance sheet with default values.', async () => {
|
||||
const res = await request()
|
||||
.get('/api/financial_statements/balance_sheet')
|
||||
.set('x-access-token', loginRes.body.token)
|
||||
.set('organization-id', tenantWebsite.organizationId)
|
||||
.query({
|
||||
display_columns_by: 'year',
|
||||
from_date: '2020-01-01',
|
||||
to_date: '2020-02-01',
|
||||
})
|
||||
.send();
|
||||
|
||||
expect(res.body.query.display_columns_by).equals('year');
|
||||
expect(res.body.query.from_date).equals('2020-01-01');
|
||||
expect(res.body.query.to_date).equals('2020-02-01');
|
||||
|
||||
expect(res.body.query.number_format.no_cents).equals(false);
|
||||
expect(res.body.query.number_format.divide_1000).equals(false);
|
||||
|
||||
expect(res.body.query.none_zero).equals(false);
|
||||
});
|
||||
|
||||
it('Should retrieve assets and liabilities/equity section.', async () => {
|
||||
const res = await request()
|
||||
.get('/api/financial_statements/balance_sheet')
|
||||
.set('x-access-token', loginRes.body.token)
|
||||
.set('organization-id', tenantWebsite.organizationId)
|
||||
.query({
|
||||
display_columns_by: 'year',
|
||||
})
|
||||
.send();
|
||||
|
||||
expect(res.body.balance_sheet[0].name).equals('Assets');
|
||||
expect(res.body.balance_sheet[1].name).equals('Liabilities and Equity');
|
||||
|
||||
expect(res.body.balance_sheet[0].section_type).equals('assets');
|
||||
expect(res.body.balance_sheet[1].section_type).equals('liabilities_equity');
|
||||
|
||||
expect(res.body.balance_sheet[0].type).equals('section');
|
||||
expect(res.body.balance_sheet[1].type).equals('section');
|
||||
});
|
||||
|
||||
it('Should retrieve assets and liabilities/equity total of each section.', async () => {
|
||||
const res = await request()
|
||||
.get('/api/financial_statements/balance_sheet')
|
||||
.set('x-access-token', loginRes.body.token)
|
||||
.set('organization-id', tenantWebsite.organizationId)
|
||||
.query({
|
||||
to_date: '2020-12-10',
|
||||
})
|
||||
.send();
|
||||
|
||||
expect(res.body.balance_sheet[0].total.amount).equals(5000);
|
||||
expect(res.body.balance_sheet[1].total.amount).equals(4000);
|
||||
});
|
||||
|
||||
it('Should retrieve the asset and liabilities/equity accounts.', async () => {
|
||||
const res = await request()
|
||||
.get('/api/financial_statements/balance_sheet')
|
||||
.set('x-access-token', loginRes.body.token)
|
||||
.set('organization-id', tenantWebsite.organizationId)
|
||||
.query({
|
||||
display_columns_type: 'total',
|
||||
from_date: '2012-01-01',
|
||||
to_date: '2032-02-02',
|
||||
})
|
||||
.send();
|
||||
|
||||
expect(res.body.balance_sheet[0].children).to.be.a('array');
|
||||
expect(res.body.balance_sheet[0].children).to.be.a('array');
|
||||
|
||||
expect(res.body.balance_sheet[0].children.length).is.not.equals(0);
|
||||
expect(res.body.balance_sheet[1].children.length).is.not.equals(0);
|
||||
|
||||
expect(res.body.balance_sheet[1].children[0].children.length).is.not.equals(0);
|
||||
expect(res.body.balance_sheet[1].children[1].children.length).is.not.equals(0);
|
||||
});
|
||||
|
||||
it('Should retrieve assets/liabilities total balance between the given date range.', async () => {
|
||||
const res = await request()
|
||||
.get('/api/financial_statements/balance_sheet')
|
||||
.set('x-access-token', loginRes.body.token)
|
||||
.set('organization-id', tenantWebsite.organizationId)
|
||||
.query({
|
||||
display_columns_type: 'total',
|
||||
from_date: '2012-01-01',
|
||||
to_date: '2032-02-02',
|
||||
})
|
||||
.send();
|
||||
|
||||
expect(res.body.accounts[0].children).include.something.deep.equals({
|
||||
id: 1001,
|
||||
index: null,
|
||||
name: debitAccount.name,
|
||||
code: debitAccount.code,
|
||||
parentAccountId: null,
|
||||
children: [],
|
||||
total: { formatted_amount: 5000, amount: 5000, date: '2032-02-02' }
|
||||
});
|
||||
|
||||
expect(res.body.accounts[1].children).include.something.deep.equals({
|
||||
id: 1000,
|
||||
index: null,
|
||||
name: creditAccount.name,
|
||||
code: creditAccount.code,
|
||||
parentAccountId: null,
|
||||
children: [],
|
||||
total: { formatted_amount: 4000, amount: 4000, date: '2032-02-02' }
|
||||
});
|
||||
});
|
||||
|
||||
it('Should retrieve asset/liabilities balance sheet with display columns by `year`.', async () => {
|
||||
const res = await request()
|
||||
.get('/api/financial_statements/balance_sheet')
|
||||
.set('x-access-token', loginRes.body.token)
|
||||
.set('organization-id', tenantWebsite.organizationId)
|
||||
.query({
|
||||
display_columns_by: 'year',
|
||||
display_columns_type: 'date_periods',
|
||||
from_date: '2012-01-01',
|
||||
to_date: '2018-02-02',
|
||||
})
|
||||
.send();
|
||||
|
||||
expect(res.body.accounts[0].children[0].total_periods.length).equals(7);
|
||||
expect(res.body.accounts[1].children[0].total_periods.length).equals(7);
|
||||
|
||||
expect(res.body.accounts[0].children[0].total_periods).deep.equals([
|
||||
{
|
||||
amount: 0,
|
||||
formatted_amount: 0,
|
||||
date: '2012',
|
||||
},
|
||||
{
|
||||
amount: 0,
|
||||
formatted_amount: 0,
|
||||
date: '2013',
|
||||
},
|
||||
{
|
||||
amount: 0,
|
||||
formatted_amount: 0,
|
||||
date: '2014',
|
||||
},
|
||||
{
|
||||
amount: 0,
|
||||
formatted_amount: 0,
|
||||
date: '2015',
|
||||
},
|
||||
{
|
||||
amount: 0,
|
||||
formatted_amount: 0,
|
||||
date: '2016',
|
||||
},
|
||||
{
|
||||
amount: 0,
|
||||
formatted_amount: 0,
|
||||
date: '2017',
|
||||
},
|
||||
{
|
||||
amount: 0,
|
||||
formatted_amount: 0,
|
||||
date: '2018',
|
||||
},
|
||||
]);
|
||||
});
|
||||
|
||||
it('Should retrieve balance sheet with display columns by `day`.', async () => {
|
||||
const res = await request()
|
||||
.get('/api/financial_statements/balance_sheet')
|
||||
.set('x-access-token', loginRes.body.token)
|
||||
.set('organization-id', tenantWebsite.organizationId)
|
||||
.query({
|
||||
display_columns_by: 'day',
|
||||
display_columns_type: 'date_periods',
|
||||
from_date: '2020-01-08',
|
||||
to_date: '2020-01-12',
|
||||
})
|
||||
.send();
|
||||
|
||||
expect(res.body.accounts[0].children).include.something.deep.equals({
|
||||
id: debitAccount.id,
|
||||
index: debitAccount.index,
|
||||
name: debitAccount.name,
|
||||
code: debitAccount.code,
|
||||
parentAccountId: null,
|
||||
children: [],
|
||||
total_periods: [
|
||||
{ date: '2020-01-08', formatted_amount: 0, amount: 0 },
|
||||
{ date: '2020-01-09', formatted_amount: 0, amount: 0 },
|
||||
{ date: '2020-01-10', formatted_amount: 5000, amount: 5000 },
|
||||
{ date: '2020-01-11', formatted_amount: 5000, amount: 5000 },
|
||||
{ date: '2020-01-12', formatted_amount: 5000, amount: 5000 },
|
||||
],
|
||||
total: { formatted_amount: 5000, amount: 5000, date: '2020-01-12' }
|
||||
});
|
||||
expect(res.body.accounts[1].children).include.something.deep.equals({
|
||||
id: creditAccount.id,
|
||||
index: creditAccount.index,
|
||||
name: creditAccount.name,
|
||||
code: creditAccount.code,
|
||||
parentAccountId: null,
|
||||
children: [],
|
||||
total_periods: [
|
||||
{ date: '2020-01-08', formatted_amount: 0, amount: 0 },
|
||||
{ date: '2020-01-09', formatted_amount: 0, amount: 0 },
|
||||
{ date: '2020-01-10', formatted_amount: 4000, amount: 4000 },
|
||||
{ date: '2020-01-11', formatted_amount: 4000, amount: 4000 },
|
||||
{ date: '2020-01-12', formatted_amount: 4000, amount: 4000 }
|
||||
],
|
||||
total: { formatted_amount: 4000, amount: 4000, date: '2020-01-12' }
|
||||
});
|
||||
});
|
||||
|
||||
it('Should retrieve the balance sheet with display columns by `month`.', async () => {
|
||||
const res = await request()
|
||||
.get('/api/financial_statements/balance_sheet')
|
||||
.set('x-access-token', loginRes.body.token)
|
||||
.set('organization-id', tenantWebsite.organizationId)
|
||||
.query({
|
||||
display_columns_by: 'month',
|
||||
display_columns_type: 'date_periods',
|
||||
from_date: '2019-07-01',
|
||||
to_date: '2020-06-30',
|
||||
})
|
||||
.send();
|
||||
|
||||
expect(res.body.accounts[0].children).include.something.deep.equals({
|
||||
id: debitAccount.id,
|
||||
index: debitAccount.index,
|
||||
name: debitAccount.name,
|
||||
code: debitAccount.code,
|
||||
parentAccountId: null,
|
||||
children: [],
|
||||
total_periods: [
|
||||
{ date: '2019-07', formatted_amount: 0, amount: 0 },
|
||||
{ date: '2019-08', formatted_amount: 0, amount: 0 },
|
||||
{ date: '2019-09', formatted_amount: 0, amount: 0 },
|
||||
{ date: '2019-10', formatted_amount: 0, amount: 0 },
|
||||
{ date: '2019-11', formatted_amount: 0, amount: 0 },
|
||||
{ date: '2019-12', formatted_amount: 0, amount: 0 },
|
||||
{ date: '2020-01', formatted_amount: 5000, amount: 5000 },
|
||||
{ date: '2020-02', formatted_amount: 5000, amount: 5000 },
|
||||
{ date: '2020-03', formatted_amount: 5000, amount: 5000 },
|
||||
{ date: '2020-04', formatted_amount: 5000, amount: 5000 },
|
||||
{ date: '2020-05', formatted_amount: 5000, amount: 5000 },
|
||||
{ date: '2020-06', formatted_amount: 5000, amount: 5000 },
|
||||
],
|
||||
total: { formatted_amount: 5000, amount: 5000, date: '2020-06-30' }
|
||||
});
|
||||
});
|
||||
|
||||
it('Should retrieve the balance sheet with display columns `quarter`.', async () => {
|
||||
const res = await request()
|
||||
.get('/api/financial_statements/balance_sheet')
|
||||
.set('x-access-token', loginRes.body.token)
|
||||
.set('organization-id', tenantWebsite.organizationId)
|
||||
.query({
|
||||
display_columns_by: 'quarter',
|
||||
display_columns_type: 'date_periods',
|
||||
from_date: '2020-01-01',
|
||||
to_date: '2020-12-31',
|
||||
})
|
||||
.send();
|
||||
|
||||
expect(res.body.accounts[0].children).include.something.deep.equals({
|
||||
id: debitAccount.id,
|
||||
index: debitAccount.index,
|
||||
name: debitAccount.name,
|
||||
code: debitAccount.code,
|
||||
parentAccountId: null,
|
||||
children: [],
|
||||
total_periods: [
|
||||
{ date: '2020-03', formatted_amount: 5000, amount: 5000 },
|
||||
{ date: '2020-06', formatted_amount: 5000, amount: 5000 },
|
||||
{ date: '2020-09', formatted_amount: 5000, amount: 5000 },
|
||||
{ date: '2020-12', formatted_amount: 5000, amount: 5000 },
|
||||
],
|
||||
total: { formatted_amount: 5000, amount: 5000, date: '2020-12-31' },
|
||||
});
|
||||
});
|
||||
|
||||
it('Should retrieve the balance sheet amounts without cents.', async () => {
|
||||
await tenantFactory.create('account_transaction', {
|
||||
debit: 0.25, credit: 0, account_id: debitAccount.id, date: '2020-1-10',
|
||||
});
|
||||
const res = await request()
|
||||
.get('/api/financial_statements/balance_sheet')
|
||||
.set('x-access-token', loginRes.body.token)
|
||||
.set('organization-id', tenantWebsite.organizationId)
|
||||
.query({
|
||||
display_columns_by: 'quarter',
|
||||
display_columns_type: 'date_periods',
|
||||
from_date: '2020-01-01',
|
||||
to_date: '2020-12-31',
|
||||
number_format: {
|
||||
no_cents: true,
|
||||
},
|
||||
})
|
||||
.send();
|
||||
|
||||
expect(res.body.accounts[0].children).include.something.deep.equals({
|
||||
id: debitAccount.id,
|
||||
index: debitAccount.index,
|
||||
name: debitAccount.name,
|
||||
code: debitAccount.code,
|
||||
parentAccountId: null,
|
||||
children: [],
|
||||
total_periods: [
|
||||
{ date: '2020-03', formatted_amount: 5000, amount: 5000.25 },
|
||||
{ date: '2020-06', formatted_amount: 5000, amount: 5000.25 },
|
||||
{ date: '2020-09', formatted_amount: 5000, amount: 5000.25 },
|
||||
{ date: '2020-12', formatted_amount: 5000, amount: 5000.25 },
|
||||
],
|
||||
total: { formatted_amount: 5000, amount: 5000.25, date: '2020-12-31' },
|
||||
});
|
||||
});
|
||||
|
||||
it('Should retrieve the balance sheet amounts divided on 1000.', async () => {
|
||||
const res = await request()
|
||||
.get('/api/financial_statements/balance_sheet')
|
||||
.set('x-access-token', loginRes.body.token)
|
||||
.set('organization-id', tenantWebsite.organizationId)
|
||||
.query({
|
||||
display_columns_by: 'quarter',
|
||||
display_columns_type: 'date_periods',
|
||||
from_date: '2020',
|
||||
to_date: '2021',
|
||||
number_format: {
|
||||
divide_1000: true,
|
||||
},
|
||||
})
|
||||
.send();
|
||||
|
||||
expect(res.body.accounts[0].children).include.something.deep.equals({
|
||||
id: debitAccount.id,
|
||||
index: debitAccount.index,
|
||||
name: debitAccount.name,
|
||||
code: debitAccount.code,
|
||||
parentAccountId: null,
|
||||
children: [],
|
||||
total_periods: [
|
||||
{ date: '2020-03', formatted_amount: 5, amount: 5000 },
|
||||
{ date: '2020-06', formatted_amount: 5, amount: 5000 },
|
||||
{ date: '2020-09', formatted_amount: 5, amount: 5000 },
|
||||
{ date: '2020-12', formatted_amount: 5, amount: 5000 },
|
||||
{ date: '2021-03', formatted_amount: 5, amount: 5000 },
|
||||
],
|
||||
total: { formatted_amount: 5, amount: 5000, date: '2021' },
|
||||
});
|
||||
});
|
||||
|
||||
it('Should not retrieve accounts has no transactions between the given date range in case query none_zero is true.', async () => {
|
||||
const res = await request()
|
||||
.get('/api/financial_statements/balance_sheet')
|
||||
.set('x-access-token', loginRes.body.token)
|
||||
.set('organization-id', tenantWebsite.organizationId)
|
||||
.query({
|
||||
display_columns_by: 'quarter',
|
||||
from_date: '2002',
|
||||
to_date: '2003',
|
||||
number_format: {
|
||||
divide_1000: true,
|
||||
},
|
||||
none_zero: true,
|
||||
})
|
||||
.send();
|
||||
|
||||
expect(res.body.accounts[0].children.length).equals(0);
|
||||
expect(res.body.accounts[1].children.length).equals(0);
|
||||
});
|
||||
|
||||
it('Should retrieve accounts in nested structure parent and children accounts.', async () => {
|
||||
const childAccount = await tenantFactory.create('account', {
|
||||
parent_account_id: debitAccount.id,
|
||||
account_type_id: 1
|
||||
});
|
||||
const res = await request()
|
||||
.get('/api/financial_statements/balance_sheet')
|
||||
.set('x-access-token', loginRes.body.token)
|
||||
.set('organization-id', tenantWebsite.organizationId)
|
||||
.query({
|
||||
none_zero: false,
|
||||
account_ids: [childAccount.id, debitAccount.id]
|
||||
})
|
||||
.send();
|
||||
|
||||
expect(res.body.accounts[0].children).include.something.deep.equals({
|
||||
id: debitAccount.id,
|
||||
index: null,
|
||||
name: debitAccount.name,
|
||||
code: debitAccount.code,
|
||||
parentAccountId: null,
|
||||
total: { formatted_amount: 5000, amount: 5000, date: '2020-12-31' },
|
||||
children: [
|
||||
{
|
||||
id: childAccount.id,
|
||||
index: null,
|
||||
name: childAccount.name,
|
||||
code: childAccount.code,
|
||||
parentAccountId: debitAccount.id,
|
||||
total: { formatted_amount: 0, amount: 0, date: '2020-12-31' },
|
||||
children: [],
|
||||
}
|
||||
]
|
||||
});
|
||||
});
|
||||
|
||||
it('Should parent account balance sumation of total balane all children accounts.', async () => {
|
||||
const childAccount = await tenantFactory.create('account', {
|
||||
parent_account_id: debitAccount.id,
|
||||
account_type_id: 1
|
||||
});
|
||||
await tenantFactory.create('account_transaction', {
|
||||
credit: 0, debit: 1000, account_id: childAccount.id, date: '2020-1-10'
|
||||
});
|
||||
|
||||
const res = await request()
|
||||
.get('/api/financial_statements/balance_sheet')
|
||||
.set('x-access-token', loginRes.body.token)
|
||||
.set('organization-id', tenantWebsite.organizationId)
|
||||
.query({
|
||||
none_zero: false,
|
||||
account_ids: [childAccount.id, debitAccount.id]
|
||||
})
|
||||
.send();
|
||||
|
||||
expect(res.body.accounts[0].children[0].total.amount).equals(6000);
|
||||
expect(res.body.accounts[0].children[0].total.formatted_amount).equals(6000);
|
||||
});
|
||||
|
||||
it('Should parent account balance sumation of total periods amounts all children accounts.', async () => {
|
||||
const childAccount = await tenantFactory.create('account', {
|
||||
parent_account_id: debitAccount.id,
|
||||
account_type_id: 1
|
||||
});
|
||||
await tenantFactory.create('account_transaction', {
|
||||
credit: 0, debit: 1000, account_id: childAccount.id, date: '2020-2-10'
|
||||
});
|
||||
|
||||
const res = await request()
|
||||
.get('/api/financial_statements/balance_sheet')
|
||||
.set('x-access-token', loginRes.body.token)
|
||||
.set('organization-id', tenantWebsite.organizationId)
|
||||
.query({
|
||||
none_zero: false,
|
||||
account_ids: [childAccount.id, debitAccount.id],
|
||||
display_columns_type: 'date_periods',
|
||||
display_columns_by: 'month',
|
||||
from_date: '2020-01-01',
|
||||
to_date: '2020-12-12',
|
||||
})
|
||||
.send();
|
||||
|
||||
expect(res.body.accounts[0].children[0].total_periods).deep.equals([
|
||||
{ amount: 5000, formatted_amount: 5000, date: '2020-01' },
|
||||
{ amount: 6000, formatted_amount: 6000, date: '2020-02' },
|
||||
{ amount: 6000, formatted_amount: 6000, date: '2020-03' },
|
||||
{ amount: 6000, formatted_amount: 6000, date: '2020-04' },
|
||||
{ amount: 6000, formatted_amount: 6000, date: '2020-05' },
|
||||
{ amount: 6000, formatted_amount: 6000, date: '2020-06' },
|
||||
{ amount: 6000, formatted_amount: 6000, date: '2020-07' },
|
||||
{ amount: 6000, formatted_amount: 6000, date: '2020-08' },
|
||||
{ amount: 6000, formatted_amount: 6000, date: '2020-09' },
|
||||
{ amount: 6000, formatted_amount: 6000, date: '2020-10' },
|
||||
{ amount: 6000, formatted_amount: 6000, date: '2020-11' },
|
||||
{ amount: 6000, formatted_amount: 6000, date: '2020-12' }
|
||||
])
|
||||
});
|
||||
});
|
||||
});
|
||||
113
packages/server/tests/routes/bill_payments.test.js
Normal file
113
packages/server/tests/routes/bill_payments.test.js
Normal file
@@ -0,0 +1,113 @@
|
||||
import {
|
||||
request,
|
||||
expect,
|
||||
} from '~/testInit';
|
||||
import {
|
||||
tenantWebsite,
|
||||
tenantFactory,
|
||||
loginRes
|
||||
} from '~/dbInit';
|
||||
|
||||
describe('route: `/api/purchases/bill_payments`', () => {
|
||||
describe('POST: `/api/purchases/bill_payments`', () => {
|
||||
it('Should `payment_date` be required.', async () => {
|
||||
const res = await request()
|
||||
.post('/api/purchases/bills')
|
||||
.set('x-access-token', loginRes.body.token)
|
||||
.set('organization-id', tenantWebsite.organizationId)
|
||||
.send();
|
||||
|
||||
expect(res.status).equals(422);
|
||||
expect(res.body.errors).include.something.deep.equals({
|
||||
msg: 'Invalid value',
|
||||
param: 'payment_date',
|
||||
location: 'body',
|
||||
});
|
||||
});
|
||||
|
||||
it('Should `payment_account_id` be required.', async () => {
|
||||
const res = await request()
|
||||
.post('/api/purchases/bills')
|
||||
.set('x-access-token', loginRes.body.token)
|
||||
.set('organization-id', tenantWebsite.organizationId)
|
||||
.send();
|
||||
|
||||
expect(res.status).equals(422);
|
||||
expect(res.body.errors).include.something.deep.equals({
|
||||
msg: 'Invalid value',
|
||||
param: 'payment_account_id',
|
||||
location: 'body',
|
||||
});
|
||||
});
|
||||
|
||||
it('Should `payment_number` be required.', async () => {
|
||||
const res = await request()
|
||||
.post('/api/purchases/bills')
|
||||
.set('x-access-token', loginRes.body.token)
|
||||
.set('organization-id', tenantWebsite.organizationId)
|
||||
.send();
|
||||
|
||||
expect(res.status).equals(422);
|
||||
expect(res.body.errors).include.something.deep.equals({
|
||||
msg: 'Invalid value',
|
||||
param: 'payment_number',
|
||||
location: 'body',
|
||||
});
|
||||
});
|
||||
|
||||
it('Should `entries.*.item_id` be required.', async () => {
|
||||
const res = await request()
|
||||
.post('/api/purchases/bills')
|
||||
.set('x-access-token', loginRes.body.token)
|
||||
.set('organization-id', tenantWebsite.organizationId)
|
||||
.send({
|
||||
entries: [{}],
|
||||
});
|
||||
|
||||
expect(res.status).equals(422);
|
||||
expect(res.body.errors).include.something.deep.equals({
|
||||
msg: 'Invalid value',
|
||||
param: 'entries[0].item_id',
|
||||
location: 'body',
|
||||
});
|
||||
});
|
||||
|
||||
it('Should `payment_number` be unique on the storage.', () => {
|
||||
|
||||
});
|
||||
|
||||
it('Should `payment_account_id` be exists on the storage.', () => {
|
||||
|
||||
});
|
||||
|
||||
it('Should `entries.*.item_id` be exists on the storage.', () => {
|
||||
|
||||
});
|
||||
|
||||
it('Should store the given bill payment to the storage.', () => {
|
||||
|
||||
});
|
||||
});
|
||||
|
||||
describe('POST: `/api/purchases/bill_payments/:id`', () => {
|
||||
it('Should bill payment be exists on the storage.', () => {
|
||||
|
||||
});
|
||||
});
|
||||
|
||||
describe('DELETE: `/api/purchases/bill_payments/:id`', () => {
|
||||
it('Should bill payment be exists on the storage.', () => {
|
||||
|
||||
});
|
||||
|
||||
it('Should delete the given bill payment from the storage.', () => {
|
||||
|
||||
});
|
||||
});
|
||||
|
||||
describe('GET: `/api/purchases/bill_payments/:id`', () => {
|
||||
it('Should bill payment be exists on the storage.', () => {
|
||||
|
||||
});
|
||||
});
|
||||
});
|
||||
217
packages/server/tests/routes/bills.test.js
Normal file
217
packages/server/tests/routes/bills.test.js
Normal file
@@ -0,0 +1,217 @@
|
||||
import {
|
||||
request,
|
||||
expect,
|
||||
} from '~/testInit';
|
||||
import {
|
||||
tenantWebsite,
|
||||
tenantFactory,
|
||||
loginRes
|
||||
} from '~/dbInit';
|
||||
|
||||
describe('route: `/api/purchases/bills`', () => {
|
||||
describe('POST: `/api/purchases/bills`', () => {
|
||||
it('Should `bill_number` be required.', async () => {
|
||||
const res = await request()
|
||||
.post('/api/purchases/bills')
|
||||
.set('x-access-token', loginRes.body.token)
|
||||
.set('organization-id', tenantWebsite.organizationId)
|
||||
.send();
|
||||
|
||||
expect(res.status).equals(422);
|
||||
expect(res.body.errors).include.something.deep.equals({
|
||||
msg: 'Invalid value',
|
||||
param: 'bill_number',
|
||||
location: 'body',
|
||||
});
|
||||
});
|
||||
|
||||
it('Should `vendor_id` be required.', async () => {
|
||||
const res = await request()
|
||||
.post('/api/purchases/bills')
|
||||
.set('x-access-token', loginRes.body.token)
|
||||
.set('organization-id', tenantWebsite.organizationId)
|
||||
.send();
|
||||
|
||||
expect(res.status).equals(422);
|
||||
expect(res.body.errors).include.something.deep.equals({
|
||||
msg: 'Invalid value',
|
||||
param: 'vendor_id',
|
||||
location: 'body',
|
||||
});
|
||||
});
|
||||
|
||||
it('Should `bill_date` be required.', async () => {
|
||||
const res = await request()
|
||||
.post('/api/purchases/bills')
|
||||
.set('x-access-token', loginRes.body.token)
|
||||
.set('organization-id', tenantWebsite.organizationId)
|
||||
.send();
|
||||
|
||||
expect(res.status).equals(422);
|
||||
expect(res.body.errors).include.something.deep.equals({
|
||||
msg: 'Invalid value',
|
||||
param: 'bill_date',
|
||||
location: 'body',
|
||||
});
|
||||
});
|
||||
|
||||
it('Should `entries` be minimum one', async () => {
|
||||
const res = await request()
|
||||
.post('/api/purchases/bills')
|
||||
.set('x-access-token', loginRes.body.token)
|
||||
.set('organization-id', tenantWebsite.organizationId)
|
||||
.send();
|
||||
|
||||
expect(res.status).equals(422);
|
||||
expect(res.body.errors).include.something.deep.equals({
|
||||
msg: 'Invalid value',
|
||||
param: 'entries',
|
||||
location: 'body',
|
||||
});
|
||||
});
|
||||
|
||||
it('Should `entries.*.item_id be required.', async () => {
|
||||
const res = await request()
|
||||
.post('/api/purchases/bills')
|
||||
.set('x-access-token', loginRes.body.token)
|
||||
.set('organization-id', tenantWebsite.organizationId)
|
||||
.send({
|
||||
entries: [{
|
||||
|
||||
}]
|
||||
});
|
||||
expect(res.status).equals(422);
|
||||
expecvt(res.body.errors).include.something.deep.equals({
|
||||
msg: 'Invalid value',
|
||||
param: 'entries[0].item_id',
|
||||
location: 'body'
|
||||
});
|
||||
});
|
||||
|
||||
it('Should `entries.*.rate` be required.', async () => {
|
||||
const res = await request()
|
||||
.post('/api/purchases/bills')
|
||||
.set('x-access-token', loginRes.body.token)
|
||||
.set('organization-id', tenantWebsite.organizationId)
|
||||
.send({
|
||||
entries: [{
|
||||
|
||||
}]
|
||||
});
|
||||
expect(res.status).equals(422);
|
||||
expecvt(res.body.errors).include.something.deep.equals({
|
||||
msg: 'Invalid value',
|
||||
param: 'entries[0].rate',
|
||||
location: 'body'
|
||||
});
|
||||
});
|
||||
|
||||
it('Should `entries.*.discount` be required.', () => {
|
||||
|
||||
});
|
||||
|
||||
it('Should entries.*.quantity be required.', () => {
|
||||
|
||||
});
|
||||
|
||||
|
||||
it('Should vendor_id be exists on the storage.', async () => {
|
||||
const vendor = await tenantFactory.create('vendor');
|
||||
const res = await request()
|
||||
.post('/api/purchases/bills')
|
||||
.set('x-access-token', loginRes.body.token)
|
||||
.set('organization-id', tenantWebsite.organizationId)
|
||||
.send({
|
||||
vendor_id: vendor.id,
|
||||
bill_number: '123',
|
||||
bill_date: '2020-02-02',
|
||||
entries: [{
|
||||
item_id: 1,
|
||||
rate: 1,
|
||||
quantity: 1,
|
||||
}]
|
||||
});
|
||||
|
||||
expect(res.status).equals(400);
|
||||
expect(res.body.errors).include.something.deep.equals({
|
||||
type: 'VENDOR.ID.NOT.FOUND', code: 300,
|
||||
})
|
||||
});
|
||||
|
||||
it('Should entries.*.item_id be exists on the storage.', async () => {
|
||||
const item = await tenantFactory.create('item');
|
||||
const vendor = await tenantFactory.create('vendor');
|
||||
const res = await request()
|
||||
.post('/api/purchases/bills')
|
||||
.set('x-access-token', loginRes.body.token)
|
||||
.set('organization-id', tenantWebsite.organizationId)
|
||||
.send({
|
||||
vendor_id: vendor.id,
|
||||
bill_number: '123',
|
||||
bill_date: '2020-02-02',
|
||||
entries: [{
|
||||
item_id: 123123,
|
||||
rate: 1,
|
||||
quantity: 1,
|
||||
}]
|
||||
});
|
||||
expect(res.status).equals(400);
|
||||
expect(res.body.errors).include.something.deep.equals({
|
||||
type: 'ITEMS.IDS.NOT.FOUND', code: 400,
|
||||
});
|
||||
});
|
||||
|
||||
it('Should validate the bill number is not exists on the storage.', async () => {
|
||||
const item = await tenantFactory.create('item');
|
||||
const vendor = await tenantFactory.create('vendor');
|
||||
const bill = await tenantFactory.create('bill', { bill_number: '123' });
|
||||
|
||||
const res = await request()
|
||||
.post('/api/purchases/bills')
|
||||
.set('x-access-token', loginRes.body.token)
|
||||
.set('organization-id', tenantWebsite.organizationId)
|
||||
.send({
|
||||
vendor_id: vendor.id,
|
||||
bill_number: '123',
|
||||
bill_date: '2020-02-02',
|
||||
entries: [{
|
||||
item_id: item.id,
|
||||
rate: 1,
|
||||
quantity: 1,
|
||||
}]
|
||||
});
|
||||
|
||||
expect(res.status).equals(400);
|
||||
expect(res.body.errors).include.something.deep.equals({
|
||||
type: 'BILL.NUMBER.EXISTS', code: 500,
|
||||
})
|
||||
})
|
||||
|
||||
it('Should store the given bill details with associated entries to the storage.', async () => {
|
||||
const item = await tenantFactory.create('item');
|
||||
const vendor = await tenantFactory.create('vendor');
|
||||
const res = await request()
|
||||
.post('/api/purchases/bills')
|
||||
.set('x-access-token', loginRes.body.token)
|
||||
.set('organization-id', tenantWebsite.organizationId)
|
||||
.send({
|
||||
vendor_id: vendor.id,
|
||||
bill_number: '123',
|
||||
bill_date: '2020-02-02',
|
||||
entries: [{
|
||||
item_id: item.id,
|
||||
rate: 1,
|
||||
quantity: 1,
|
||||
}]
|
||||
});
|
||||
|
||||
expect(res.status).equals(200);
|
||||
});
|
||||
|
||||
|
||||
});
|
||||
|
||||
describe('DELETE: `/api/purchases/bills/:id`', () => {
|
||||
|
||||
});
|
||||
});
|
||||
191
packages/server/tests/routes/currencies.test.js
Normal file
191
packages/server/tests/routes/currencies.test.js
Normal file
@@ -0,0 +1,191 @@
|
||||
import {
|
||||
request,
|
||||
expect,
|
||||
} from '~/testInit';
|
||||
import Currency from 'models/Currency';
|
||||
import {
|
||||
tenantWebsite,
|
||||
tenantFactory,
|
||||
loginRes
|
||||
} from '~/dbInit';
|
||||
|
||||
|
||||
describe('route: /currencies/', () => {
|
||||
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)
|
||||
.set('organization-id', tenantWebsite.organizationId)
|
||||
.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)
|
||||
.set('organization-id', tenantWebsite.organizationId)
|
||||
.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 () => {
|
||||
tenantFactory.create('currency', { currency_code: 'USD' });
|
||||
|
||||
const res = await request()
|
||||
.post('/api/currencies')
|
||||
.set('x-access-token', loginRes.body.token)
|
||||
.set('organization-id', tenantWebsite.organizationId)
|
||||
.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)
|
||||
.set('organization-id', tenantWebsite.organizationId)
|
||||
.send({
|
||||
currency_code: 'USD',
|
||||
currency_name: 'Dollar',
|
||||
});
|
||||
|
||||
const foundCurrency = await Currency.tenant().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)
|
||||
.set('organization-id', tenantWebsite.organizationId)
|
||||
.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 tenantFactory.create('currency');
|
||||
const res = await request()
|
||||
.delete(`/api/currencies/${currency.currencyCode}`)
|
||||
.set('x-access-token', loginRes.body.token)
|
||||
.set('organization-id', tenantWebsite.organizationId)
|
||||
.send();
|
||||
|
||||
expect(res.status).equals(200);
|
||||
|
||||
const foundCurrency = await Currency.tenant().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 tenantFactory.create('currency');
|
||||
const res = await request()
|
||||
.post(`/api/currencies/${currency.code}`)
|
||||
.set('x-access-token', loginRes.body.token)
|
||||
.set('organization-id', tenantWebsite.organizationId)
|
||||
.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 tenantFactory.create('currency');
|
||||
const res = await request()
|
||||
.post(`/api/currencies/${currency.code}`)
|
||||
.set('x-access-token', loginRes.body.token)
|
||||
.set('organization-id', tenantWebsite.organizationId)
|
||||
.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 tenantFactory.create('currency');
|
||||
const currency2 = await tenantFactory.create('currency');
|
||||
|
||||
const res = await request()
|
||||
.post(`/api/currencies/${currency2.id}`)
|
||||
.set('x-access-token', loginRes.body.token)
|
||||
.set('organization-id', tenantWebsite.organizationId)
|
||||
.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 tenantFactory.create('currency');
|
||||
const currency2 = await tenantFactory.create('currency');
|
||||
|
||||
const res = await request()
|
||||
.post(`/api/currencies/${currency2.id}`)
|
||||
.set('x-access-token', loginRes.body.token)
|
||||
.set('organization-id', tenantWebsite.organizationId)
|
||||
.send({
|
||||
currency_code: 'ABC',
|
||||
currency_name: 'Name',
|
||||
});
|
||||
|
||||
const foundCurrency = await Currency.tenant().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.', () => {
|
||||
|
||||
});
|
||||
})
|
||||
});
|
||||
250
packages/server/tests/routes/customers.test.js
Normal file
250
packages/server/tests/routes/customers.test.js
Normal file
@@ -0,0 +1,250 @@
|
||||
import {
|
||||
request,
|
||||
expect,
|
||||
} from '~/testInit';
|
||||
import Currency from 'models/Currency';
|
||||
import {
|
||||
tenantWebsite,
|
||||
tenantFactory,
|
||||
loginRes
|
||||
} from '~/dbInit';
|
||||
import Customer from '../../src/models/Customer';
|
||||
|
||||
describe('route: `/customers`', () => {
|
||||
describe('POST: `/customers`', () => {
|
||||
it('Should response unauthorized in case the user was not logged in.', async () => {
|
||||
const res = await request()
|
||||
.post('/api/customers')
|
||||
.send({});
|
||||
|
||||
expect(res.status).equals(401);
|
||||
expect(res.body.message).equals('Unauthorized');
|
||||
});
|
||||
|
||||
it('Should `display_name` be required field.', async () => {
|
||||
const res = await request()
|
||||
.post('/api/customers')
|
||||
.set('x-access-token', loginRes.body.token)
|
||||
.set('organization-id', tenantWebsite.organizationId)
|
||||
.send({
|
||||
|
||||
});
|
||||
|
||||
expect(res.status).equals(422);
|
||||
expect(res.body.errors).include.something.deep.equals({
|
||||
msg: 'Invalid value', param: 'display_name', location: 'body',
|
||||
})
|
||||
});
|
||||
|
||||
it('Should `customer_type` be required field', async () => {
|
||||
const res = await request()
|
||||
.post('/api/customers')
|
||||
.set('x-access-token', loginRes.body.token)
|
||||
.set('organization-id', tenantWebsite.organizationId)
|
||||
.send();
|
||||
|
||||
expect(res.status).equals(422);
|
||||
expect(res.body.errors).include.something.deep.equals({
|
||||
msg: 'Invalid value', param: 'customer_type', location: 'body',
|
||||
});
|
||||
});
|
||||
|
||||
it('Should store the customer data to the storage.', async () => {
|
||||
const res = await request()
|
||||
.post('/api/customers')
|
||||
.set('x-access-token', loginRes.body.token)
|
||||
.set('organization-id', tenantWebsite.organizationId)
|
||||
.send({
|
||||
customer_type: 'business',
|
||||
|
||||
first_name: 'Ahmed',
|
||||
last_name: 'Bouhuolia',
|
||||
|
||||
company_name: 'Bigcapital',
|
||||
|
||||
display_name: 'Ahmed Bouhuolia, Bigcapital',
|
||||
|
||||
email: 'a.bouhuolia@live.com',
|
||||
work_phone: '0927918381',
|
||||
personal_phone: '0925173379',
|
||||
|
||||
billing_address_city: 'Tripoli',
|
||||
billing_address_country: 'Libya',
|
||||
billing_address_email: 'a.bouhuolia@live.com',
|
||||
billing_address_state: 'State Tripoli',
|
||||
billing_address_zipcode: '21892',
|
||||
|
||||
shipping_address_city: 'Tripoli',
|
||||
shipping_address_country: 'Libya',
|
||||
shipping_address_email: 'a.bouhuolia@live.com',
|
||||
shipping_address_state: 'State Tripoli',
|
||||
shipping_address_zipcode: '21892',
|
||||
|
||||
note: '__desc__',
|
||||
|
||||
active: true,
|
||||
});
|
||||
|
||||
expect(res.status).equals(200);
|
||||
|
||||
const foundCustomer = await Customer.tenant().query().where('id', res.body.id);
|
||||
|
||||
expect(foundCustomer[0].customerType).equals('business');
|
||||
expect(foundCustomer[0].firstName).equals('Ahmed');
|
||||
expect(foundCustomer[0].lastName).equals('Bouhuolia');
|
||||
expect(foundCustomer[0].companyName).equals('Bigcapital');
|
||||
expect(foundCustomer[0].displayName).equals('Ahmed Bouhuolia, Bigcapital');
|
||||
|
||||
expect(foundCustomer[0].email).equals('a.bouhuolia@live.com');
|
||||
|
||||
expect(foundCustomer[0].workPhone).equals('0927918381');
|
||||
expect(foundCustomer[0].personalPhone).equals('0925173379');
|
||||
|
||||
expect(foundCustomer[0].billingAddressCity).equals('Tripoli');
|
||||
expect(foundCustomer[0].billingAddressCountry).equals('Libya');
|
||||
expect(foundCustomer[0].billingAddressEmail).equals('a.bouhuolia@live.com');
|
||||
expect(foundCustomer[0].billingAddressState).equals('State Tripoli');
|
||||
expect(foundCustomer[0].billingAddressZipcode).equals('21892');
|
||||
|
||||
expect(foundCustomer[0].shippingAddressCity).equals('Tripoli');
|
||||
expect(foundCustomer[0].shippingAddressCountry).equals('Libya');
|
||||
expect(foundCustomer[0].shippingAddressEmail).equals('a.bouhuolia@live.com');
|
||||
expect(foundCustomer[0].shippingAddressState).equals('State Tripoli');
|
||||
expect(foundCustomer[0].shippingAddressZipcode).equals('21892');
|
||||
});
|
||||
});
|
||||
|
||||
describe('GET: `/customers/:id`', () => {
|
||||
it('Should response not found in case the given customer id was not exists on the storage.', async () => {
|
||||
const res = await request()
|
||||
.get('/api/customers/123')
|
||||
.set('x-access-token', loginRes.body.token)
|
||||
.set('organization-id', tenantWebsite.organizationId)
|
||||
.send();
|
||||
|
||||
expect(res.status).equals(404);
|
||||
expect(res.body.errors).include.something.deep.equals({
|
||||
type: 'CUSTOMER.NOT.FOUND', code: 200,
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('GET: `customers`', () => {
|
||||
it('Should response customers items', async () => {
|
||||
await tenantFactory.create('customer');
|
||||
await tenantFactory.create('customer');
|
||||
|
||||
const res = await request()
|
||||
.get('/api/customers')
|
||||
.set('x-access-token', loginRes.body.token)
|
||||
.set('organization-id', tenantWebsite.organizationId)
|
||||
.send();
|
||||
|
||||
expect(res.body.customers.results.length).equals(2);
|
||||
});
|
||||
});
|
||||
|
||||
describe('DELETE: `/customers/:id`', () => {
|
||||
it('Should response not found in case the given customer id was not exists on the storage.', async () => {
|
||||
const res = await request()
|
||||
.delete('/api/customers/123')
|
||||
.set('x-access-token', loginRes.body.token)
|
||||
.set('organization-id', tenantWebsite.organizationId)
|
||||
.send();
|
||||
|
||||
expect(res.status).equals(404);
|
||||
expect(res.body.errors).include.something.deep.equals({
|
||||
type: 'CUSTOMER.NOT.FOUND', code: 200,
|
||||
});
|
||||
});
|
||||
|
||||
it('Should delete the given customer from the storage.', async () => {
|
||||
const customer = await tenantFactory.create('customer');
|
||||
const res = await request()
|
||||
.delete(`/api/customers/${customer.id}`)
|
||||
.set('x-access-token', loginRes.body.token)
|
||||
.set('organization-id', tenantWebsite.organizationId)
|
||||
.send();
|
||||
|
||||
expect(res.status).equals(200);
|
||||
|
||||
const foundCustomer = await Customer.tenant().query().where('id', customer.id);
|
||||
expect(foundCustomer.length).equals(0);
|
||||
})
|
||||
});
|
||||
|
||||
describe('POST: `/customers/:id`', () => {
|
||||
it('Should response customer not found', async () => {
|
||||
const res = await request()
|
||||
.post('/api/customers/123')
|
||||
.set('x-access-token', loginRes.body.token)
|
||||
.set('organization-id', tenantWebsite.organizationId)
|
||||
.send({
|
||||
customer_type: 'business',
|
||||
display_name: 'Ahmed Bouhuolia, Bigcapital',
|
||||
});
|
||||
|
||||
expect(res.status).equals(404);
|
||||
expect(res.body.errors).include.something.deep.equals({
|
||||
type: 'CUSTOMER.NOT.FOUND', code: 200,
|
||||
});
|
||||
});
|
||||
|
||||
it('Should update details of the given customer.', async () => {
|
||||
const customer = await tenantFactory.create('customer');
|
||||
const res = await request()
|
||||
.post(`/api/customers/${customer.id}`)
|
||||
.set('x-access-token', loginRes.body.token)
|
||||
.set('organization-id', tenantWebsite.organizationId)
|
||||
.send({
|
||||
customer_type: 'business',
|
||||
display_name: 'Ahmed Bouhuolia, Bigcapital',
|
||||
});
|
||||
|
||||
expect(res.status).equals(200);
|
||||
const foundCustomer = await Customer.tenant().query().where('id', res.body.id);
|
||||
|
||||
expect(foundCustomer.length).equals(1);
|
||||
expect(foundCustomer[0].customerType).equals('business');
|
||||
expect(foundCustomer[0].displayName).equals('Ahmed Bouhuolia, Bigcapital');
|
||||
})
|
||||
});
|
||||
|
||||
describe('DELETE: `customers`', () => {
|
||||
it('Should response customers ids not found.', async () => {
|
||||
const res = await request()
|
||||
.delete('/api/customers')
|
||||
.set('x-access-token', loginRes.body.token)
|
||||
.set('organization-id', tenantWebsite.organizationId)
|
||||
.query({
|
||||
ids: [100, 200],
|
||||
})
|
||||
.send();
|
||||
|
||||
expect(res.status).equals(404);
|
||||
expect(res.body.errors).include.something.deep.equals({
|
||||
type: 'CUSTOMERS.NOT.FOUND', code: 200,
|
||||
});
|
||||
});
|
||||
|
||||
it('Should delete the given customers.', async () => {
|
||||
const customer1 = await tenantFactory.create('customer');
|
||||
const customer2 = await tenantFactory.create('customer');
|
||||
|
||||
const res = await request()
|
||||
.delete('/api/customers')
|
||||
.set('x-access-token', loginRes.body.token)
|
||||
.set('organization-id', tenantWebsite.organizationId)
|
||||
.query({
|
||||
ids: [customer1.id, customer2.id],
|
||||
})
|
||||
.send();
|
||||
|
||||
const foundCustomers = await Customer.tenant().query()
|
||||
.whereIn('id', [customer1.id, customer2.id]);
|
||||
|
||||
expect(res.status).equals(200);
|
||||
expect(foundCustomers.length).equals(0);
|
||||
});
|
||||
})
|
||||
});
|
||||
230
packages/server/tests/routes/exchange_rates.test.js
Normal file
230
packages/server/tests/routes/exchange_rates.test.js
Normal file
@@ -0,0 +1,230 @@
|
||||
import moment from 'moment';
|
||||
import {
|
||||
request,
|
||||
expect,
|
||||
} from '~/testInit';
|
||||
import ExchangeRate from '../../src/models/ExchangeRate';
|
||||
import {
|
||||
tenantWebsite,
|
||||
tenantFactory,
|
||||
loginRes
|
||||
} from '~/dbInit';
|
||||
|
||||
|
||||
describe('route: /exchange_rates/', () => {
|
||||
describe('POST: `/api/exchange_rates`', () => {
|
||||
it('Should response unauthorized in case the user was not logged in.', async () => {
|
||||
const res = await request()
|
||||
.post('/api/exchange_rates')
|
||||
.send();
|
||||
|
||||
expect(res.status).equals(401);
|
||||
expect(res.body.message).equals('Unauthorized');
|
||||
});
|
||||
|
||||
it('Should `currency_code` be required.', async () => {
|
||||
const res = await request()
|
||||
.post('/api/exchange_rates')
|
||||
.set('x-access-token', loginRes.body.token)
|
||||
.set('organization-id', tenantWebsite.organizationId)
|
||||
.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 `exchange_rate` be required.', async () => {
|
||||
const res = await request()
|
||||
.post('/api/exchange_rates')
|
||||
.set('x-access-token', loginRes.body.token)
|
||||
.set('organization-id', tenantWebsite.organizationId)
|
||||
.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: 'exchange_rate', location: 'body',
|
||||
});
|
||||
});
|
||||
|
||||
it('Should date be required', async () => {
|
||||
const res = await request()
|
||||
.post('/api/exchange_rates')
|
||||
.set('x-access-token', loginRes.body.token)
|
||||
.set('organization-id', tenantWebsite.organizationId)
|
||||
.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: 'date', location: 'body',
|
||||
});
|
||||
});
|
||||
|
||||
it('Should response date and currency code is already exists.', async () => {
|
||||
await tenantFactory.create('exchange_rate', {
|
||||
date: '2020-02-02',
|
||||
currency_code: 'USD',
|
||||
exchange_rate: 4.4,
|
||||
});
|
||||
const res = await request()
|
||||
.post('/api/exchange_rates')
|
||||
.set('x-access-token', loginRes.body.token)
|
||||
.set('organization-id', tenantWebsite.organizationId)
|
||||
.send({
|
||||
date: '2020-02-02',
|
||||
currency_code: 'USD',
|
||||
exchange_rate: 4.4,
|
||||
});
|
||||
|
||||
expect(res.status).equals(400);
|
||||
expect(res.body.errors).include.something.deep.equals({
|
||||
type: 'EXCHANGE.RATE.DATE.PERIOD.DEFINED', code: 200,
|
||||
});
|
||||
});
|
||||
|
||||
it('Should save the given exchange rate to the storage.', async () => {
|
||||
const res = await request()
|
||||
.post('/api/exchange_rates')
|
||||
.set('x-access-token', loginRes.body.token)
|
||||
.set('organization-id', tenantWebsite.organizationId)
|
||||
.send({
|
||||
date: '2020-02-02',
|
||||
currency_code: 'USD',
|
||||
exchange_rate: 4.4,
|
||||
});
|
||||
expect(res.status).equals(200);
|
||||
|
||||
const foundExchangeRate = await ExchangeRate.tenant().query()
|
||||
.where('currency_code', 'USD');
|
||||
|
||||
expect(foundExchangeRate.length).equals(1);
|
||||
expect(
|
||||
moment(foundExchangeRate[0].date).format('YYYY-MM-DD'),
|
||||
).equals('2020-02-02');
|
||||
expect(foundExchangeRate[0].currencyCode).equals('USD');
|
||||
expect(foundExchangeRate[0].exchangeRate).equals(4.4);
|
||||
});
|
||||
});
|
||||
|
||||
describe('GET: `/api/exchange_rates', () => {
|
||||
it('Should retrieve all exchange rates with pagination meta.', async () => {
|
||||
await tenantFactory.create('exchange_rate');
|
||||
await tenantFactory.create('exchange_rate');
|
||||
await tenantFactory.create('exchange_rate');
|
||||
|
||||
const res = await request()
|
||||
.get('/api/exchange_rates')
|
||||
.set('x-access-token', loginRes.body.token)
|
||||
.set('organization-id', tenantWebsite.organizationId)
|
||||
.send();
|
||||
|
||||
expect(res.status).equals(200);
|
||||
expect(res.body.exchange_rates.results.length).equals(3);
|
||||
});
|
||||
});
|
||||
|
||||
describe('POST: `/api/exchange_rates/:id`', () => {
|
||||
it('Should response the given exchange rate not found.', async () => {
|
||||
const res = await request()
|
||||
.post('/api/exchange_rates/100')
|
||||
.set('x-access-token', loginRes.body.token)
|
||||
.set('organization-id', tenantWebsite.organizationId)
|
||||
.send({
|
||||
date: '2020-02-02',
|
||||
currency_code: 'USD',
|
||||
exchange_rate: 4.4,
|
||||
});
|
||||
|
||||
expect(res.status).equals(400);
|
||||
expect(res.body.errors).include.something.deep.equals({
|
||||
type: 'EXCHANGE.RATE.NOT.FOUND', code: 200,
|
||||
});
|
||||
});
|
||||
|
||||
it('Should update exchange rate of the given id on the storage.', async () => {
|
||||
const exRate = await tenantFactory.create('exchange_rate');
|
||||
const res = await request()
|
||||
.post(`/api/exchange_rates/${exRate.id}`)
|
||||
.set('x-access-token', loginRes.body.token)
|
||||
.set('organization-id', tenantWebsite.organizationId)
|
||||
.send({
|
||||
exchange_rate: 4.4,
|
||||
});
|
||||
expect(res.status).equals(200);
|
||||
|
||||
const foundExchangeRate = await ExchangeRate.tenant().query()
|
||||
.where('id', exRate.id);
|
||||
|
||||
expect(foundExchangeRate.length).equals(1);
|
||||
expect(foundExchangeRate[0].exchangeRate).equals(4.4);
|
||||
});
|
||||
});
|
||||
|
||||
describe('DELETE: `/api/exchange_rates/:id`', () => {
|
||||
it('Should response the given exchange rate id not found.', async () => {
|
||||
const res = await request()
|
||||
.delete('/api/exchange_rates/100')
|
||||
.set('x-access-token', loginRes.body.token)
|
||||
.set('organization-id', tenantWebsite.organizationId)
|
||||
.send();
|
||||
|
||||
expect(res.status).equals(404);
|
||||
expect(res.body.errors).include.something.deep.equals({
|
||||
type: 'EXCHANGE.RATE.NOT.FOUND', code: 200,
|
||||
});
|
||||
});
|
||||
|
||||
it('Should delete the given exchange rate id from the storage.', async () => {
|
||||
const exRate = await tenantFactory.create('exchange_rate');
|
||||
const res = await request()
|
||||
.delete(`/api/exchange_rates/${exRate.id}`)
|
||||
.set('x-access-token', loginRes.body.token)
|
||||
.set('organization-id', tenantWebsite.organizationId)
|
||||
.send();
|
||||
|
||||
const foundRates = await ExchangeRate.tenant().query();
|
||||
expect(foundRates.length).equals(0);
|
||||
});
|
||||
});
|
||||
|
||||
describe('DELETE: `/api/exchange_rates/bulk`', () => {
|
||||
it('Should response the given exchange rates ids where not found.', async () => {
|
||||
const res = await request()
|
||||
.delete('/api/exchange_rates/bulk')
|
||||
.set('x-access-token', loginRes.body.token)
|
||||
.set('organization-id', tenantWebsite.organizationId)
|
||||
.query({
|
||||
ids: [12332, 32432],
|
||||
})
|
||||
.send();
|
||||
|
||||
expect(res.status).equals(400);
|
||||
expect(res.body.errors).include.something.deep.equals({
|
||||
type: 'EXCHANGE.RATES.IS.NOT.FOUND', code: 200, ids: [12332, 32432],
|
||||
})
|
||||
});
|
||||
|
||||
it('Should delete the given excahnge rates ids.', async () => {
|
||||
const exRate = await tenantFactory.create('exchange_rate');
|
||||
const exRate2 = await tenantFactory.create('exchange_rate');
|
||||
|
||||
const res = await request()
|
||||
.delete('/api/exchange_rates/bulk')
|
||||
.set('x-access-token', loginRes.body.token)
|
||||
.set('organization-id', tenantWebsite.organizationId)
|
||||
.query({
|
||||
ids: [exRate.id, exRate2.id],
|
||||
})
|
||||
.send();
|
||||
|
||||
const foundExchangeRate = await ExchangeRate.tenant().query()
|
||||
.whereIn('id', [exRate.id, exRate2.id]);
|
||||
|
||||
expect(foundExchangeRate.length).equals(0);
|
||||
})
|
||||
});
|
||||
});
|
||||
739
packages/server/tests/routes/expenses.test.js
Normal file
739
packages/server/tests/routes/expenses.test.js
Normal file
@@ -0,0 +1,739 @@
|
||||
import moment from 'moment';
|
||||
import { pick } from 'lodash';
|
||||
import {
|
||||
request,
|
||||
expect,
|
||||
} from '~/testInit';
|
||||
import Expense from 'models/Expense';
|
||||
import ExpenseCategory from 'models/ExpenseCategory';
|
||||
import AccountTransaction from 'models/AccountTransaction';
|
||||
import {
|
||||
tenantWebsite,
|
||||
tenantFactory,
|
||||
loginRes,
|
||||
} from '~/dbInit';
|
||||
|
||||
describe('routes: /expenses/', () => {
|
||||
describe('POST `/expenses`', () => {
|
||||
it('Should retrieve unauthorized access if the user was not authorized.', async () => {
|
||||
const res = await request()
|
||||
.post('/api/expenses')
|
||||
.set('organization-id', tenantWebsite.organizationId)
|
||||
.send();
|
||||
|
||||
expect(res.status).equals(401);
|
||||
expect(res.body.message).equals('Unauthorized');
|
||||
});
|
||||
|
||||
it('Should categories total not be equals zero.', async () => {
|
||||
const res = await request()
|
||||
.post('/api/expenses')
|
||||
.set('x-access-token', loginRes.body.token)
|
||||
.set('organization-id', tenantWebsite.organizationId)
|
||||
.send({
|
||||
payment_date: moment().format('YYYY-MM-DD'),
|
||||
reference_no: '',
|
||||
payment_account_id: 0,
|
||||
description: '',
|
||||
publish: 1,
|
||||
categories: [
|
||||
{
|
||||
index: 1,
|
||||
expense_account_id: 33,
|
||||
amount: 1000,
|
||||
description: '',
|
||||
}
|
||||
],
|
||||
});
|
||||
|
||||
expect(res.status).equals(400);
|
||||
expect(res.body.errors).include.something.deep.equals({
|
||||
type: 'EXPENSE.ACCOUNTS.IDS.NOT.STORED', code: 400, ids: [33]
|
||||
});
|
||||
});
|
||||
|
||||
it('Should expense accounts ids be stored in the storage.', async () => {
|
||||
const res = await request()
|
||||
.post('/api/expenses')
|
||||
.set('x-access-token', loginRes.body.token)
|
||||
.set('organization-id', tenantWebsite.organizationId)
|
||||
.send({
|
||||
payment_date: moment().format('YYYY-MM-DD'),
|
||||
reference_no: '',
|
||||
payment_account_id: 0,
|
||||
description: '',
|
||||
publish: 1,
|
||||
categories: [
|
||||
{
|
||||
index: 1,
|
||||
expense_account_id: 22,
|
||||
amount: 1000,
|
||||
description: '',
|
||||
},
|
||||
],
|
||||
});
|
||||
|
||||
expect(res.status).equals(400);
|
||||
expect(res.body.errors).include.something.deep.equals({
|
||||
type: 'EXPENSE.ACCOUNTS.IDS.NOT.STORED', code: 400, ids: [22],
|
||||
});
|
||||
});
|
||||
|
||||
it('Should `payment_account_id` be in the storage.', async () => {
|
||||
const res = await request()
|
||||
.post('/api/expenses')
|
||||
.set('x-access-token', loginRes.body.token)
|
||||
.set('organization-id', tenantWebsite.organizationId)
|
||||
.send({
|
||||
payment_date: moment().format('YYYY-MM-DD'),
|
||||
reference_no: '',
|
||||
payment_account_id: 22,
|
||||
description: '',
|
||||
publish: 1,
|
||||
categories: [
|
||||
{
|
||||
index: 1,
|
||||
expense_account_id: 22,
|
||||
amount: 1000,
|
||||
description: '',
|
||||
},
|
||||
],
|
||||
});
|
||||
|
||||
expect(res.status).equals(400);
|
||||
expect(res.body.errors).include.something.deep.equals({
|
||||
type: 'PAYMENT.ACCOUNT.NOT.FOUND', code: 500,
|
||||
});
|
||||
});
|
||||
|
||||
it('Should payment_account be required.', async () => {
|
||||
const res = await request()
|
||||
.post('/api/expenses')
|
||||
.set('x-access-token', loginRes.body.token)
|
||||
.set('organization-id', tenantWebsite.organizationId)
|
||||
.send();
|
||||
|
||||
expect(res.status).equals(422);
|
||||
});
|
||||
|
||||
it('Should `categories.*.expense_account_id` be required.', async () => {
|
||||
const res = await request()
|
||||
.post('/api/expenses')
|
||||
.set('x-access-token', loginRes.body.token)
|
||||
.set('organization-id', tenantWebsite.organizationId)
|
||||
.send({
|
||||
|
||||
});
|
||||
expect(res.body.errors).include.something.deep.equals({
|
||||
msg: 'Invalid value', param: 'payment_account_id', location: 'body'
|
||||
});
|
||||
});
|
||||
|
||||
it('Should expense transactions be stored on the storage.', async () => {
|
||||
const paymentAccount = await tenantFactory.create('account');
|
||||
const expenseAccount = await tenantFactory.create('account');
|
||||
|
||||
const res = await request()
|
||||
.post('/api/expenses')
|
||||
.set('x-access-token', loginRes.body.token)
|
||||
.set('organization-id', tenantWebsite.organizationId)
|
||||
.send({
|
||||
payment_date: moment().format('YYYY-MM-DD'),
|
||||
reference_no: 'ABC',
|
||||
payment_account_id: paymentAccount.id,
|
||||
description: 'desc',
|
||||
publish: 1,
|
||||
categories: [
|
||||
{
|
||||
index: 1,
|
||||
expense_account_id: expenseAccount.id,
|
||||
amount: 1000,
|
||||
description: '',
|
||||
},
|
||||
],
|
||||
});
|
||||
|
||||
const foundExpense = await Expense.tenant().query().where('id', res.body.id);
|
||||
|
||||
expect(foundExpense.length).equals(1);
|
||||
expect(foundExpense[0].referenceNo).equals('ABC');
|
||||
expect(foundExpense[0].paymentAccountId).equals(paymentAccount.id);
|
||||
expect(foundExpense[0].description).equals('desc');
|
||||
expect(foundExpense[0].totalAmount).equals(1000);
|
||||
});
|
||||
|
||||
it('Should expense categories transactions be stored on the storage.', async () => {
|
||||
const paymentAccount = await tenantFactory.create('account');
|
||||
const expenseAccount = await tenantFactory.create('account');
|
||||
|
||||
const res = await request()
|
||||
.post('/api/expenses')
|
||||
.set('x-access-token', loginRes.body.token)
|
||||
.set('organization-id', tenantWebsite.organizationId)
|
||||
.send({
|
||||
payment_date: moment().format('YYYY-MM-DD'),
|
||||
reference_no: 'ABC',
|
||||
payment_account_id: paymentAccount.id,
|
||||
description: 'desc',
|
||||
publish: 1,
|
||||
categories: [
|
||||
{
|
||||
index: 1,
|
||||
expense_account_id: expenseAccount.id,
|
||||
amount: 1000,
|
||||
description: 'category desc',
|
||||
},
|
||||
],
|
||||
});
|
||||
|
||||
const foundCategories = await ExpenseCategory.tenant().query().where('id', res.body.id);
|
||||
|
||||
expect(foundCategories.length).equals(1);
|
||||
expect(foundCategories[0].index).equals(1);
|
||||
expect(foundCategories[0].expenseAccountId).equals(expenseAccount.id);
|
||||
expect(foundCategories[0].amount).equals(1000);
|
||||
expect(foundCategories[0].description).equals('category desc');
|
||||
});
|
||||
|
||||
it('Should save journal entries that associate to the expense transaction.', async () => {
|
||||
const paymentAccount = await tenantFactory.create('account');
|
||||
const expenseAccount = await tenantFactory.create('account');
|
||||
|
||||
const res = await request()
|
||||
.post('/api/expenses')
|
||||
.set('x-access-token', loginRes.body.token)
|
||||
.set('organization-id', tenantWebsite.organizationId)
|
||||
.send({
|
||||
payment_date: moment().format('YYYY-MM-DD'),
|
||||
reference_no: 'ABC',
|
||||
payment_account_id: paymentAccount.id,
|
||||
description: 'desc',
|
||||
publish: 1,
|
||||
categories: [
|
||||
{
|
||||
index: 1,
|
||||
expense_account_id: expenseAccount.id,
|
||||
amount: 1000,
|
||||
description: 'category desc',
|
||||
},
|
||||
],
|
||||
});
|
||||
|
||||
const transactions = await AccountTransaction.tenant().query()
|
||||
.where('reference_id', res.body.id)
|
||||
.where('reference_type', 'Expense');
|
||||
|
||||
const mappedTransactions = transactions.map(tr => ({
|
||||
...pick(tr, ['credit', 'debit', 'referenceId', 'referenceType']),
|
||||
}));
|
||||
|
||||
expect(mappedTransactions[0]).deep.equals({
|
||||
credit: 1000,
|
||||
debit: 0,
|
||||
referenceType: 'Expense',
|
||||
referenceId: res.body.id,
|
||||
});
|
||||
expect(mappedTransactions[1]).deep.equals({
|
||||
credit: 0,
|
||||
debit: 1000,
|
||||
referenceType: 'Expense',
|
||||
referenceId: res.body.id,
|
||||
});
|
||||
expect(transactions.length).equals(2);
|
||||
})
|
||||
});
|
||||
|
||||
describe('GET: `/expenses`', () => {
|
||||
it('Should response unauthorized if the user was not logged in.', async () => {
|
||||
const res = await request()
|
||||
.post('/api/expenses')
|
||||
.set('organization-id', tenantWebsite.organizationId)
|
||||
.send();
|
||||
|
||||
expect(res.status).equals(401);
|
||||
expect(res.body.message).equals('Unauthorized');
|
||||
});
|
||||
|
||||
it('Should retrieve expenses with pagination meta.', async () => {
|
||||
await tenantFactory.create('expense');
|
||||
await tenantFactory.create('expense');
|
||||
|
||||
const res = await request()
|
||||
.get('/api/expenses')
|
||||
.set('x-access-token', loginRes.body.token)
|
||||
.set('organization-id', tenantWebsite.organizationId)
|
||||
.send();
|
||||
|
||||
expect(res.body.expenses).that.is.an('object');
|
||||
expect(res.body.expenses.results).that.is.an('array');
|
||||
});
|
||||
|
||||
it('Should retrieve expenses based on view roles conditions of the custom view.', () => {
|
||||
|
||||
});
|
||||
|
||||
it('Should sort expenses based on the given `column_sort_order` column on ASC direction.', () => {
|
||||
|
||||
});
|
||||
});
|
||||
|
||||
describe('DELETE: `/expenses/:id`', () => {
|
||||
it('Should response unauthorized if the user was not logged in.', async () => {
|
||||
const res = await request()
|
||||
.delete('/api/expenses')
|
||||
.set('organization-id', tenantWebsite.organizationId)
|
||||
.send();
|
||||
|
||||
expect(res.status).equals(401);
|
||||
expect(res.body.message).equals('Unauthorized');
|
||||
});
|
||||
|
||||
it('Should response not found in case expense id was not exists on the storage.', async () => {
|
||||
const res = await request()
|
||||
.delete('/api/expenses/123321')
|
||||
.set('organization-id', tenantWebsite.organizationId)
|
||||
.set('x-access-token', loginRes.body.token)
|
||||
.send();
|
||||
|
||||
expect(res.status).equals(404);
|
||||
expect(res.body.errors).include.something.deep.equals({
|
||||
type: 'EXPENSE.NOT.FOUND', code: 200,
|
||||
});
|
||||
});
|
||||
|
||||
it('Should delete the given expense transactions with associated categories.', async () => {
|
||||
const expense = await tenantFactory.create('expense');
|
||||
|
||||
const res = await request()
|
||||
.delete(`/api/expenses/${expense.id}`)
|
||||
.set('organization-id', tenantWebsite.organizationId)
|
||||
.set('x-access-token', loginRes.body.token)
|
||||
.send();
|
||||
|
||||
expect(res.status).equals(200);
|
||||
|
||||
const storedExpense = await Expense.tenant().query().where('id', expense.id);
|
||||
const storedExpenseCategories = await ExpenseCategory.tenant().query().where('expense_id', expense.id);
|
||||
|
||||
expect(storedExpense.length).equals(0);
|
||||
expect(storedExpenseCategories.length).equals(0);
|
||||
});
|
||||
|
||||
it('Should delete all journal entries that associated to the given expense.', async () => {
|
||||
const expense = await tenantFactory.create('expense');
|
||||
|
||||
const trans = { reference_id: expense.id, reference_type: 'Expense' };
|
||||
await tenantFactory.create('account_transaction', trans);
|
||||
await tenantFactory.create('account_transaction', trans);
|
||||
|
||||
const res = await request()
|
||||
.delete(`/api/expenses/${expense.id}`)
|
||||
.set('organization-id', tenantWebsite.organizationId)
|
||||
.set('x-access-token', loginRes.body.token)
|
||||
.send();
|
||||
|
||||
const foundTransactions = await AccountTransaction.tenant().query()
|
||||
.where('reference_type', 'Expense')
|
||||
.where('reference_id', expense.id);
|
||||
|
||||
expect(foundTransactions.length).equals(0);
|
||||
});
|
||||
});
|
||||
|
||||
describe('GET: `/expenses/:id`', () => {
|
||||
it('Should response unauthorized if the user was not logged in.', async () => {
|
||||
const res = await request()
|
||||
.get('/api/expenses/123')
|
||||
.set('organization-id', tenantWebsite.organizationId)
|
||||
.send();
|
||||
|
||||
expect(res.status).equals(401);
|
||||
expect(res.body.message).equals('Unauthorized');
|
||||
});
|
||||
|
||||
it('Should response not found in case the given expense id was not exists in the storage.', async () => {
|
||||
const res = await request()
|
||||
.get(`/api/expenses/321`)
|
||||
.set('organization-id', tenantWebsite.organizationId)
|
||||
.set('x-access-token', loginRes.body.token)
|
||||
.send();
|
||||
|
||||
expect(res.status).equals(404);
|
||||
});
|
||||
|
||||
it('Should retrieve expense metadata and associated expense categories.', async () => {
|
||||
const expense = await tenantFactory.create('expense');
|
||||
const expenseCategory = await tenantFactory.create('expense_category', {
|
||||
expense_id: expense.id,
|
||||
})
|
||||
const res = await request()
|
||||
.get(`/api/expenses/${expense.id}`)
|
||||
.set('organization-id', tenantWebsite.organizationId)
|
||||
.set('x-access-token', loginRes.body.token)
|
||||
.send();
|
||||
|
||||
expect(res.status).equals(200);
|
||||
|
||||
expect(res.body.expense.id).is.a('number');
|
||||
expect(res.body.expense.paymentAccountId).is.a('number');
|
||||
expect(res.body.expense.totalAmount).is.a('number');
|
||||
expect(res.body.expense.userId).is.a('number');
|
||||
expect(res.body.expense.referenceNo).is.a('string');
|
||||
expect(res.body.expense.description).is.a('string');
|
||||
expect(res.body.expense.categories).is.a('array');
|
||||
|
||||
expect(res.body.expense.categories[0].id).is.a('number');
|
||||
expect(res.body.expense.categories[0].description).is.a('string');
|
||||
expect(res.body.expense.categories[0].expenseAccountId).is.a('number');
|
||||
});
|
||||
|
||||
it('Should retrieve journal entries with expense metadata.', async () => {
|
||||
const expense = await tenantFactory.create('expense');
|
||||
const expenseCategory = await tenantFactory.create('expense_category', {
|
||||
expense_id: expense.id,
|
||||
});
|
||||
const trans = { reference_id: expense.id, reference_type: 'Expense' };
|
||||
await tenantFactory.create('account_transaction', trans);
|
||||
await tenantFactory.create('account_transaction', trans);
|
||||
|
||||
const res = await request()
|
||||
.get(`/api/expenses/${expense.id}`)
|
||||
.set('organization-id', tenantWebsite.organizationId)
|
||||
.set('x-access-token', loginRes.body.token)
|
||||
.send();
|
||||
|
||||
expect(res.body.expense.journalEntries).is.an('array');
|
||||
expect(res.body.expense.journalEntries.length).equals(2);
|
||||
});
|
||||
});
|
||||
|
||||
describe('POST: `expenses/:id`', () => {
|
||||
it('Should response unauthorized in case the user was not logged in.', async () => {
|
||||
const expense = await tenantFactory.create('expense');
|
||||
const res = await request()
|
||||
.post(`/api/expenses/${expense.id}`)
|
||||
.set('organization-id', tenantWebsite.organizationId)
|
||||
.send();
|
||||
|
||||
expect(res.status).equals(401);
|
||||
expect(res.body.message).equals('Unauthorized');
|
||||
});
|
||||
|
||||
it('Should response the given expense id not exists on the storage.', async () => {
|
||||
const expenseAccount = await tenantFactory.create('account');
|
||||
|
||||
const res = await request()
|
||||
.post('/api/expenses/1233')
|
||||
.set('x-access-token', loginRes.body.token)
|
||||
.set('organization-id', tenantWebsite.organizationId)
|
||||
.send({
|
||||
reference_no: '123',
|
||||
payment_date: moment().format('YYYY-MM-DD'),
|
||||
payment_account_id: 321,
|
||||
publish: true,
|
||||
categories: [
|
||||
{
|
||||
expense_account_id: expenseAccount.id,
|
||||
index: 1,
|
||||
amount: 1000,
|
||||
description: '',
|
||||
},
|
||||
],
|
||||
});
|
||||
expect(res.status).equals(404);
|
||||
expect(res.body.errors).include.something.deep.equals({
|
||||
type: 'EXPENSE.NOT.FOUND', code: 200,
|
||||
});
|
||||
});
|
||||
|
||||
it('Should response the given `payment_account_id` not exists.', async () => {
|
||||
const expense = await tenantFactory.create('expense');
|
||||
const expenseAccount = await tenantFactory.create('account');
|
||||
|
||||
const res = await request()
|
||||
.post(`/api/expenses/${expense.id}`)
|
||||
.set('x-access-token', loginRes.body.token)
|
||||
.set('organization-id', tenantWebsite.organizationId)
|
||||
.send({
|
||||
reference_no: '123',
|
||||
payment_date: moment().format('YYYY-MM-DD'),
|
||||
payment_account_id: 321,
|
||||
publish: true,
|
||||
categories: [
|
||||
{
|
||||
expense_account_id: expenseAccount.id,
|
||||
index: 1,
|
||||
amount: 1000,
|
||||
description: '',
|
||||
},
|
||||
],
|
||||
});
|
||||
|
||||
expect(res.status).equals(400);
|
||||
expect(res.body.errors).include.something.deep.equals({
|
||||
type: 'PAYMENT.ACCOUNT.NOT.FOUND', code: 400,
|
||||
});
|
||||
});
|
||||
|
||||
it('Should response the given `categories.*.expense_account_id` not exists.', async () => {
|
||||
const paymentAccount = await tenantFactory.create('account');
|
||||
const expense = await tenantFactory.create('expense');
|
||||
|
||||
const res = await request()
|
||||
.post(`/api/expenses/${expense.id}`)
|
||||
.set('x-access-token', loginRes.body.token)
|
||||
.set('organization-id', tenantWebsite.organizationId)
|
||||
.send({
|
||||
reference_no: '123',
|
||||
payment_date: moment().format('YYYY-MM-DD'),
|
||||
payment_account_id: paymentAccount.id,
|
||||
publish: true,
|
||||
categories: [
|
||||
{
|
||||
index: 1,
|
||||
expense_account_id: 100,
|
||||
amount: 1000,
|
||||
description: '',
|
||||
},
|
||||
],
|
||||
});
|
||||
|
||||
expect(res.status).equals(400);
|
||||
expect(res.body.errors).include.something.deep.equals({
|
||||
type: 'EXPENSE.ACCOUNTS.IDS.NOT.FOUND', code: 600, ids: [100],
|
||||
});
|
||||
});
|
||||
|
||||
it('Should response the total amount equals zero.', async () => {
|
||||
const expense = await tenantFactory.create('expense');
|
||||
const expenseAccount = await tenantFactory.create('account');
|
||||
const paymentAccount = await tenantFactory.create('account');
|
||||
|
||||
const res = await request()
|
||||
.post(`/api/expenses/${expense.id}`)
|
||||
.set('x-access-token', loginRes.body.token)
|
||||
.set('organization-id', tenantWebsite.organizationId)
|
||||
.send({
|
||||
reference_no: '123',
|
||||
payment_date: moment().format('YYYY-MM-DD'),
|
||||
payment_account_id: paymentAccount.id,
|
||||
publish: true,
|
||||
categories: [
|
||||
{
|
||||
index: 1,
|
||||
expense_account_id: expenseAccount.id,
|
||||
amount: 0,
|
||||
description: '',
|
||||
},
|
||||
],
|
||||
});
|
||||
|
||||
expect(res.status).equals(400);
|
||||
expect(res.body.errors).include.something.deep.equals({
|
||||
type: 'TOTAL.AMOUNT.EQUALS.ZERO', code: 500,
|
||||
});
|
||||
});
|
||||
|
||||
it('Should update the expense transaction.', async () => {
|
||||
const expense = await tenantFactory.create('expense');
|
||||
const paymentAccount = await tenantFactory.create('account');
|
||||
const expenseAccount = await tenantFactory.create('account');
|
||||
|
||||
const res = await request()
|
||||
.post(`/api/expenses/${expense.id}`)
|
||||
.set('x-access-token', loginRes.body.token)
|
||||
.set('organization-id', tenantWebsite.organizationId)
|
||||
.send({
|
||||
reference_no: '123',
|
||||
payment_date: moment('2009-01-02').format('YYYY-MM-DD'),
|
||||
payment_account_id: paymentAccount.id,
|
||||
publish: true,
|
||||
description: 'Updated description',
|
||||
categories: [
|
||||
{
|
||||
index: 1,
|
||||
expense_account_id: expenseAccount.id,
|
||||
amount: 3000,
|
||||
description: '',
|
||||
},
|
||||
],
|
||||
});
|
||||
expect(res.status).equals(200);
|
||||
|
||||
const updatedExpense = await Expense.tenant().query()
|
||||
.where('id', expense.id).first();
|
||||
|
||||
expect(updatedExpense.id).equals(expense.id);
|
||||
expect(updatedExpense.referenceNo).equals('123');
|
||||
expect(updatedExpense.description).equals('Updated description');
|
||||
expect(updatedExpense.totalAmount).equals(3000);
|
||||
expect(updatedExpense.paymentAccountId).equals(paymentAccount.id);
|
||||
});
|
||||
|
||||
it('Should delete the expense categories that associated to the expense transaction.', async () => {
|
||||
const expense = await tenantFactory.create('expense');
|
||||
const expenseCategory = await tenantFactory.create('expense_category', {
|
||||
expense_id: expense.id,
|
||||
});
|
||||
const paymentAccount = await tenantFactory.create('account');
|
||||
const expenseAccount = await tenantFactory.create('account');
|
||||
|
||||
const res = await request()
|
||||
.post(`/api/expenses/${expense.id}`)
|
||||
.set('x-access-token', loginRes.body.token)
|
||||
.set('organization-id', tenantWebsite.organizationId)
|
||||
.send({
|
||||
reference_no: '123',
|
||||
payment_date: moment('2009-01-02').format('YYYY-MM-DD'),
|
||||
payment_account_id: paymentAccount.id,
|
||||
publish: true,
|
||||
description: 'Updated description',
|
||||
categories: [
|
||||
{
|
||||
index: 1,
|
||||
expense_account_id: expenseAccount.id,
|
||||
amount: 3000,
|
||||
description: '',
|
||||
},
|
||||
],
|
||||
});
|
||||
|
||||
const foundExpenseCategories = await ExpenseCategory.tenant()
|
||||
.query().where('id', expenseCategory.id)
|
||||
|
||||
expect(foundExpenseCategories.length).equals(0);
|
||||
});
|
||||
|
||||
it('Should insert the expense categories to associated to the expense transaction.', async () => {
|
||||
const expense = await tenantFactory.create('expense');
|
||||
const expenseCategory = await tenantFactory.create('expense_category', {
|
||||
expense_id: expense.id,
|
||||
});
|
||||
const paymentAccount = await tenantFactory.create('account');
|
||||
const expenseAccount = await tenantFactory.create('account');
|
||||
|
||||
const res = await request()
|
||||
.post(`/api/expenses/${expense.id}`)
|
||||
.set('x-access-token', loginRes.body.token)
|
||||
.set('organization-id', tenantWebsite.organizationId)
|
||||
.send({
|
||||
reference_no: '123',
|
||||
payment_date: moment('2009-01-02').format('YYYY-MM-DD'),
|
||||
payment_account_id: paymentAccount.id,
|
||||
publish: true,
|
||||
description: 'Updated description',
|
||||
categories: [
|
||||
{
|
||||
index: 1,
|
||||
expense_account_id: expenseAccount.id,
|
||||
amount: 3000,
|
||||
description: '__desc__',
|
||||
},
|
||||
],
|
||||
});
|
||||
|
||||
const foundExpenseCategories = await ExpenseCategory.tenant()
|
||||
.query()
|
||||
.where('expense_id', expense.id)
|
||||
|
||||
expect(foundExpenseCategories.length).equals(1);
|
||||
expect(foundExpenseCategories[0].id).not.equals(expenseCategory.id);
|
||||
});
|
||||
|
||||
it('Should update the expense categories that associated to the expense transactions.', async () => {
|
||||
const expense = await tenantFactory.create('expense');
|
||||
const expenseCategory = await tenantFactory.create('expense_category', {
|
||||
expense_id: expense.id,
|
||||
});
|
||||
const paymentAccount = await tenantFactory.create('account');
|
||||
const expenseAccount = await tenantFactory.create('account');
|
||||
|
||||
const res = await request()
|
||||
.post(`/api/expenses/${expense.id}`)
|
||||
.set('x-access-token', loginRes.body.token)
|
||||
.set('organization-id', tenantWebsite.organizationId)
|
||||
.send({
|
||||
reference_no: '123',
|
||||
payment_date: moment('2009-01-02').format('YYYY-MM-DD'),
|
||||
payment_account_id: paymentAccount.id,
|
||||
publish: true,
|
||||
description: 'Updated description',
|
||||
categories: [
|
||||
{
|
||||
id: expenseCategory.id,
|
||||
index: 1,
|
||||
expense_account_id: expenseAccount.id,
|
||||
amount: 3000,
|
||||
description: '__desc__',
|
||||
},
|
||||
],
|
||||
});
|
||||
|
||||
const foundExpenseCategory = await ExpenseCategory.tenant().query()
|
||||
.where('id', expenseCategory.id);
|
||||
|
||||
expect(foundExpenseCategory.length).equals(1);
|
||||
expect(foundExpenseCategory[0].expenseAccountId).equals(expenseAccount.id);
|
||||
expect(foundExpenseCategory[0].description).equals('__desc__');
|
||||
expect(foundExpenseCategory[0].amount).equals(3000);
|
||||
});
|
||||
});
|
||||
|
||||
describe('DELETE: `/api/expenses`', () => {
|
||||
it('Should response not found expenses ids.', async () => {
|
||||
const res = await request()
|
||||
.delete('/api/expenses')
|
||||
.set('x-access-token', loginRes.body.token)
|
||||
.set('organization-id', tenantWebsite.organizationId)
|
||||
.query({
|
||||
ids: [100, 200],
|
||||
})
|
||||
.send({});
|
||||
|
||||
expect(res.status).equals(404);
|
||||
expect(res.body.errors).include.something.deep.equals({
|
||||
type: 'EXPENSES.NOT.FOUND', code: 200,
|
||||
});
|
||||
});
|
||||
|
||||
it('Should delete the given expenses ids.', async () => {
|
||||
const expense1 = await tenantFactory.create('expense');
|
||||
const expense2 = await tenantFactory.create('expense');
|
||||
|
||||
const res = await request()
|
||||
.delete('/api/expenses')
|
||||
.set('x-access-token', loginRes.body.token)
|
||||
.set('organization-id', tenantWebsite.organizationId)
|
||||
.query({
|
||||
ids: [expense1.id, expense2.id],
|
||||
})
|
||||
.send({});
|
||||
|
||||
const foundExpenses = await Expense.tenant().query()
|
||||
.whereIn('id', [expense1.id, expense2.id]);
|
||||
|
||||
expect(res.status).equals(200);
|
||||
expect(foundExpenses.length).equals(0);
|
||||
})
|
||||
});
|
||||
|
||||
describe('POST: `/api/expenses/:id/publish`', () => {
|
||||
it('Should publish the given expense.', async () => {
|
||||
const expense = await tenantFactory.create('expense', {
|
||||
published: 0,
|
||||
});
|
||||
|
||||
const res = await request()
|
||||
.post(`/api/expenses/${expense.id}/publish`)
|
||||
.set('x-access-token', loginRes.body.token)
|
||||
.set('organization-id', tenantWebsite.organizationId)
|
||||
.send();
|
||||
|
||||
const foundExpense = await Expense.tenant().query()
|
||||
.where('id', expense.id).first();
|
||||
|
||||
expect(res.status).equals(200);
|
||||
expect(foundExpense.published).equals(1);
|
||||
});
|
||||
});
|
||||
});
|
||||
956
packages/server/tests/routes/financial_statements.test.js
Normal file
956
packages/server/tests/routes/financial_statements.test.js
Normal file
@@ -0,0 +1,956 @@
|
||||
import moment from 'moment';
|
||||
import {
|
||||
request,
|
||||
expect,
|
||||
} from '~/testInit';
|
||||
import {
|
||||
tenantWebsite,
|
||||
tenantFactory,
|
||||
loginRes
|
||||
} from '~/dbInit';
|
||||
import { iteratee } from 'lodash';
|
||||
|
||||
let creditAccount;
|
||||
let debitAccount;
|
||||
let incomeAccount;
|
||||
let incomeType;
|
||||
|
||||
describe('routes: `/financial_statements`', () => {
|
||||
beforeEach(async () => {
|
||||
// Balance sheet types.
|
||||
const assetType = await tenantFactory.create('account_type', { normal: 'debit', balance_sheet: true });
|
||||
const liabilityType = await tenantFactory.create('account_type', { normal: 'credit', balance_sheet: true });
|
||||
|
||||
// Income statement types.
|
||||
incomeType = await tenantFactory.create('account_type', { normal: 'credit', income_sheet: true });
|
||||
const expenseType = await tenantFactory.create('account_type', { normal: 'debit', income_sheet: true });
|
||||
|
||||
// Assets & liabilites accounts.
|
||||
creditAccount = await tenantFactory.create('account', { account_type_id: liabilityType.id });
|
||||
debitAccount = await tenantFactory.create('account', { account_type_id: assetType.id });
|
||||
|
||||
// Income && expenses accounts.
|
||||
incomeAccount = await tenantFactory.create('account', { account_type_id: incomeType.id });
|
||||
const expenseAccount = await tenantFactory.create('account', { account_type_id: expenseType.id });
|
||||
// const income2Account = await tenantFactory.create('account', { account_type_id: incomeType.id });
|
||||
|
||||
const accountTransactionMixied = { date: '2020-1-10' };
|
||||
|
||||
// Expense --
|
||||
// 1000 Credit - Credit account
|
||||
// 1000 Debit - expense account.
|
||||
await tenantFactory.create('account_transaction', {
|
||||
credit: 1000, debit: 0, account_id: debitAccount.id, referenceType: 'Expense',
|
||||
referenceId: 1, ...accountTransactionMixied,
|
||||
});
|
||||
await tenantFactory.create('account_transaction', {
|
||||
credit: 0, debit: 1000, account_id: expenseAccount.id, referenceType: 'Expense',
|
||||
referenceId: 1, ...accountTransactionMixied,
|
||||
});
|
||||
|
||||
// Jounral
|
||||
// 4000 Credit - liability account.
|
||||
// 2000 Debit - Asset account
|
||||
// 2000 Debit - Asset account
|
||||
await tenantFactory.create('account_transaction', {
|
||||
credit: 4000, debit: 0, account_id: creditAccount.id, ...accountTransactionMixied,
|
||||
});
|
||||
await tenantFactory.create('account_transaction', {
|
||||
debit: 2000, credit: 0, account_id: debitAccount.id, ...accountTransactionMixied,
|
||||
});
|
||||
await tenantFactory.create('account_transaction', {
|
||||
debit: 2000, credit: 0, account_id: debitAccount.id, ...accountTransactionMixied,
|
||||
});
|
||||
|
||||
// Income Journal.
|
||||
// 2000 Credit - Income account.
|
||||
// 2000 Debit - Asset account.
|
||||
await tenantFactory.create('account_transaction', {
|
||||
credit: 2000, account_id: incomeAccount.id, ...accountTransactionMixied
|
||||
});
|
||||
await tenantFactory.create('account_transaction', {
|
||||
debit: 2000, credit: 0, account_id: debitAccount.id, ...accountTransactionMixied,
|
||||
});
|
||||
|
||||
// -----------------------------------------
|
||||
// Assets account balance = 5000 | Libility account balance = 4000
|
||||
// Expense account balance = 1000 | Income account balance = 2000
|
||||
});
|
||||
|
||||
|
||||
describe('routes: `/financial_statements/journal`', () => {
|
||||
it('Should response unauthorized in case the user was not authorized.', async () => {
|
||||
const res = await request()
|
||||
.get('/api/financial_statements/journal')
|
||||
.send();
|
||||
|
||||
expect(res.status).equals(401);
|
||||
});
|
||||
|
||||
it('Should retrieve ledger sheet transactions grouped by reference type and id.', async () => {
|
||||
const res = await request()
|
||||
.get('/api/financial_statements/journal')
|
||||
.set('x-access-token', loginRes.body.token)
|
||||
.set('organization-id', tenantWebsite.organizationId)
|
||||
.send();
|
||||
|
||||
expect(res.status).equals(200);
|
||||
expect(res.body.journal.length).to.be.at.least(1);
|
||||
|
||||
expect(res.body.journal[0].credit).to.be.a('number');
|
||||
expect(res.body.journal[0].debit).to.be.a('number');
|
||||
expect(res.body.journal[0].entries).to.be.a('array');
|
||||
expect(res.body.journal[0].id).to.be.a('string');
|
||||
|
||||
expect(res.body.journal[0].entries[0].credit).to.be.a('number');
|
||||
expect(res.body.journal[0].entries[0].debit).to.be.a('number');
|
||||
});
|
||||
|
||||
it('Should retrieve transactions between date range.', async () => {
|
||||
const res = await request()
|
||||
.get('/api/financial_statements/journal')
|
||||
.set('x-access-token', loginRes.body.token)
|
||||
.set('organization-id', tenantWebsite.organizationId)
|
||||
.query({
|
||||
from_date: '2018-01-01',
|
||||
to_date: '2019-01-01',
|
||||
})
|
||||
.send();
|
||||
|
||||
expect(res.body.journal.length).equals(0);
|
||||
});
|
||||
|
||||
it('Should retrieve transactions that associated to the queried accounts.', async () => {
|
||||
const res = await request()
|
||||
.get('/api/financial_statements/journal')
|
||||
.set('x-access-token', loginRes.body.token)
|
||||
.set('organization-id', tenantWebsite.organizationId)
|
||||
.query({
|
||||
account_ids: [creditAccount.id],
|
||||
})
|
||||
.send();
|
||||
|
||||
expect(res.body.journal[0].entries.length).equals(1);
|
||||
expect(res.body.journal[0].entries[0].account_id).equals(creditAccount.id);
|
||||
|
||||
expect(res.body.journal.length).equals(1);
|
||||
});
|
||||
|
||||
it('Should retrieve tranasactions with the given types.', async () => {
|
||||
const res = await request()
|
||||
.get('/api/financial_statements/journal')
|
||||
.set('x-access-token', loginRes.body.token)
|
||||
.set('organization-id', tenantWebsite.organizationId)
|
||||
.query({
|
||||
transaction_types: ['Expense'],
|
||||
});
|
||||
|
||||
expect(res.body.journal.length).equals(1);
|
||||
});
|
||||
|
||||
it('Should retrieve transactions with range amount.', async () => {
|
||||
const res = await request()
|
||||
.get('/api/financial_statements/journal')
|
||||
.set('x-access-token', loginRes.body.token)
|
||||
.set('organization-id', tenantWebsite.organizationId)
|
||||
.query({
|
||||
from_range: 2000,
|
||||
to_range: 2000,
|
||||
})
|
||||
.send();
|
||||
|
||||
expect(res.body.journal[0].credit).satisfy((credit) => {
|
||||
return credit === 0 || credit >= 2000;
|
||||
});
|
||||
expect(res.body.journal[0].debit).satisfy((debit) => {
|
||||
return debit === 0 || debit >= 2000;
|
||||
});
|
||||
});
|
||||
|
||||
it('Should format credit and debit to no cents of retrieved transactions.', async () => {
|
||||
|
||||
});
|
||||
|
||||
it('Should divide credit/debit amount on 1000', async () => {
|
||||
const res = await request()
|
||||
.get('/api/financial_statements/journal')
|
||||
.set('x-access-token', loginRes.body.token)
|
||||
.set('organization-id', tenantWebsite.organizationId)
|
||||
.query({
|
||||
number_format: {
|
||||
divide_1000: true,
|
||||
},
|
||||
})
|
||||
.send();
|
||||
|
||||
const journal = res.body.journal.find((j) => j.id === '1-Expense');
|
||||
|
||||
expect(journal.formatted_credit).equals(1);
|
||||
expect(journal.formatted_debit).equals(1);
|
||||
});
|
||||
});
|
||||
|
||||
describe('routes: `/financial_statements/general_ledger`', () => {
|
||||
it('Should response unauthorized in case the user was not authorized.', async () => {
|
||||
const res = await request()
|
||||
.get('/api/financial_statements/general_ledger')
|
||||
.send();
|
||||
|
||||
expect(res.status).equals(401);
|
||||
});
|
||||
|
||||
it('Should retrieve request query meta on response schema.', async () => {
|
||||
const res = await request()
|
||||
.get('/api/financial_statements/general_ledger')
|
||||
.set('x-access-token', loginRes.body.token)
|
||||
.set('organization-id', tenantWebsite.organizationId)
|
||||
.send();
|
||||
|
||||
expect(res.body.query.from_date).equals(moment().startOf('year').format('YYYY-MM-DD'));
|
||||
expect(res.body.query.to_date).equals(moment().endOf('year').format('YYYY-MM-DD'));
|
||||
expect(res.body.query.basis).equals('cash');
|
||||
expect(res.body.query.number_format.no_cents).equals(false);
|
||||
expect(res.body.query.number_format.divide_1000).equals(false);
|
||||
expect(res.body.query.none_zero).equals(false);
|
||||
expect(res.body.query.accounts_ids).to.be.an('array');
|
||||
});
|
||||
|
||||
it('Should retrieve the general ledger accounts with associated transactions and opening/closing balance.', async () => {
|
||||
const res = await request()
|
||||
.get('/api/financial_statements/general_ledger')
|
||||
.set('x-access-token', loginRes.body.token)
|
||||
.set('organization-id', tenantWebsite.organizationId)
|
||||
.send();
|
||||
|
||||
expect(res.body.accounts).is.an('array');
|
||||
expect(res.body.accounts[0].id).to.be.an('number');
|
||||
expect(res.body.accounts[0].name).to.be.a('string');
|
||||
expect(res.body.accounts[0].code).to.be.a('string');
|
||||
expect(res.body.accounts[0].transactions).to.be.a('array');
|
||||
expect(res.body.accounts[0].opening).to.be.a('object');
|
||||
expect(res.body.accounts[0].opening.amount).to.be.a('number');
|
||||
expect(res.body.accounts[0].opening.date).to.be.a('string');
|
||||
expect(res.body.accounts[0].closing).to.be.a('object');
|
||||
expect(res.body.accounts[0].closing.amount).to.be.a('number');
|
||||
expect(res.body.accounts[0].closing.date).to.be.a('string');
|
||||
});
|
||||
|
||||
it('Should retrieve opening and closing balance.', async () => {
|
||||
const res = await request()
|
||||
.get('/api/financial_statements/general_ledger')
|
||||
.set('x-access-token', loginRes.body.token)
|
||||
.set('organization-id', tenantWebsite.organizationId)
|
||||
.send();
|
||||
|
||||
const targetAccount = res.body.accounts.find((a) => a.id === creditAccount.id);
|
||||
|
||||
expect(targetAccount).to.be.an('object');
|
||||
expect(targetAccount.opening).to.deep.equal({
|
||||
amount: 0, formatted_amount: 0, date: '2020-01-01',
|
||||
});
|
||||
expect(targetAccount.closing).to.deep.equal({
|
||||
amount: 4000, formatted_amount: 4000, date: '2020-12-31',
|
||||
});
|
||||
});
|
||||
|
||||
it('Should retrieve opening and closing balance between the given date range.', async () => {
|
||||
const res = await request()
|
||||
.get('/api/financial_statements/general_ledger')
|
||||
.set('x-access-token', loginRes.body.token)
|
||||
.set('organization-id', tenantWebsite.organizationId)
|
||||
.query({
|
||||
from_date: '2018-01-01',
|
||||
to_date: '2020-03-30',
|
||||
// none_zero: true,
|
||||
})
|
||||
.send();
|
||||
|
||||
const targetAccount = res.body.accounts.find((a) => a.id === creditAccount.id);
|
||||
|
||||
expect(targetAccount).to.be.an('object');
|
||||
expect(targetAccount.opening).to.deep.equal({
|
||||
amount: 0, formatted_amount: 0, date: '2018-01-01',
|
||||
});
|
||||
expect(targetAccount.closing).to.deep.equal({
|
||||
amount: 4000, formatted_amount: 4000, date: '2020-03-30',
|
||||
});
|
||||
});
|
||||
|
||||
it('Should retrieve accounts with associated transactions.', async () => {
|
||||
const res = await request()
|
||||
.get('/api/financial_statements/general_ledger')
|
||||
.set('x-access-token', loginRes.body.token)
|
||||
.set('organization-id', tenantWebsite.organizationId)
|
||||
.query({
|
||||
none_zero: true,
|
||||
})
|
||||
.send();
|
||||
|
||||
})
|
||||
|
||||
it('Should retrieve accounts transactions only that between date range.', async () => {
|
||||
const res = await request()
|
||||
.get('/api/financial_statements/general_ledger')
|
||||
.set('x-access-token', loginRes.body.token)
|
||||
.set('organization-id', tenantWebsite.organizationId)
|
||||
.query({
|
||||
from_date: '2020-01-01',
|
||||
to_date: '2020-03-30',
|
||||
none_zero: true,
|
||||
})
|
||||
.send();
|
||||
|
||||
|
||||
// console.log(res.body.accounts);
|
||||
});
|
||||
|
||||
it('Should retrieve no accounts with given date period has not transactions.', async () => {
|
||||
const res = await request()
|
||||
.get('/api/financial_statements/general_ledger')
|
||||
.set('x-access-token', loginRes.body.token)
|
||||
.set('organization-id', tenantWebsite.organizationId)
|
||||
.query({
|
||||
from_date: '2020-01-20',
|
||||
to_date: '2020-03-30',
|
||||
none_zero: true,
|
||||
})
|
||||
.send();
|
||||
|
||||
expect(res.body.accounts.length).equals(0);
|
||||
});
|
||||
|
||||
it('Should retrieve all accounts even it have no transactions in the given date range when `none_zero` is `true`', async () => {
|
||||
const res = await request()
|
||||
.get('/api/financial_statements/general_ledger')
|
||||
.set('x-access-token', loginRes.body.token)
|
||||
.set('organization-id', tenantWebsite.organizationId)
|
||||
.query({
|
||||
from_date: '2020-01-01',
|
||||
to_date: '2020-03-30',
|
||||
none_zero: true,
|
||||
})
|
||||
.send();
|
||||
|
||||
const accountsNoTransactions = res.body.accounts.filter(a => a.transactions.length === 0);
|
||||
const accountsWithTransactions = res.body.accounts.filter(a => a.transactions.length > 0);
|
||||
|
||||
expect(accountsNoTransactions.length).equals(0);
|
||||
expect(accountsWithTransactions.length).not.equals(0);
|
||||
});
|
||||
|
||||
it('Should amount transactions divided on `1000` when `number_format.none_zero` is `true`.', async () => {
|
||||
const res = await request()
|
||||
.get('/api/financial_statements/general_ledger')
|
||||
.set('x-access-token', loginRes.body.token)
|
||||
.set('organization-id', tenantWebsite.organizationId)
|
||||
.query({
|
||||
from_date: '2020-01-01',
|
||||
to_date: '2020-03-30',
|
||||
accounts_ids: [creditAccount.id],
|
||||
number_format: {
|
||||
divide_1000: true,
|
||||
},
|
||||
})
|
||||
.send();
|
||||
|
||||
expect(res.body.accounts).include.something.deep.equals({
|
||||
id: creditAccount.id,
|
||||
name: creditAccount.name,
|
||||
code: creditAccount.code,
|
||||
index: null,
|
||||
parentAccountId: null,
|
||||
children: [],
|
||||
transactions: [
|
||||
{
|
||||
id: 1002,
|
||||
note: null,
|
||||
transactionType: null,
|
||||
referenceType: null,
|
||||
referenceId: null,
|
||||
date: '2020-01-09T22:00:00.000Z',
|
||||
createdAt: null,
|
||||
formatted_amount: 4,
|
||||
amount: 4000,
|
||||
}
|
||||
],
|
||||
opening: { date: '2020-01-01', formatted_amount: 0, amount: 0 },
|
||||
closing: { date: '2020-03-30', formatted_amount: 4, amount: 4000 }
|
||||
});
|
||||
});
|
||||
|
||||
it('Should amount transactions rounded with no decimals when `number_format.no_cents` is `true`.', async () => {
|
||||
await tenantFactory.create('account_transaction', {
|
||||
debit: 0.25, credit: 0, account_id: debitAccount.id, date: '2020-1-10',
|
||||
});
|
||||
|
||||
const res = await request()
|
||||
.get('/api/financial_statements/general_ledger')
|
||||
.set('x-access-token', loginRes.body.token)
|
||||
.set('organization-id', tenantWebsite.organizationId)
|
||||
.query({
|
||||
from_date: '2020-01-01',
|
||||
to_date: '2020-03-30',
|
||||
number_format: {
|
||||
divide_1000: true,
|
||||
no_cents: true,
|
||||
},
|
||||
accounts_ids: [debitAccount.id]
|
||||
})
|
||||
.send();
|
||||
|
||||
expect(res.body.accounts[0].transactions[2].formatted_amount).equal(2);
|
||||
});
|
||||
|
||||
it('Should retrieve only accounts that given in the query.', async () => {
|
||||
const res = await request()
|
||||
.get('/api/financial_statements/general_ledger')
|
||||
.set('x-access-token', loginRes.body.token)
|
||||
.set('organization-id', tenantWebsite.organizationId)
|
||||
.query({
|
||||
from_date: '2020-01-01',
|
||||
to_date: '2020-03-30',
|
||||
none_zero: true,
|
||||
accounts_ids: [creditAccount.id],
|
||||
})
|
||||
.send();
|
||||
|
||||
expect(res.body.accounts.length).equals(1);
|
||||
});
|
||||
|
||||
it('Should retrieve accounts in nested array structure as parent/children accounts.', async () => {
|
||||
const childAccount = await tenantFactory.create('account', {
|
||||
parent_account_id: debitAccount.id,
|
||||
account_type_id: 1
|
||||
});
|
||||
|
||||
const res = await request()
|
||||
.get('/api/financial_statements/general_ledger')
|
||||
.set('x-access-token', loginRes.body.token)
|
||||
.set('organization-id', tenantWebsite.organizationId)
|
||||
.query({
|
||||
accounts_ids: [childAccount.id, debitAccount.id],
|
||||
})
|
||||
.send();
|
||||
|
||||
expect(res.body.accounts[0].children.length).equals(1);
|
||||
expect(res.body.accounts[0].children[0].id).equals(childAccount.id);
|
||||
});
|
||||
});
|
||||
|
||||
describe('routes: `/financial_statements/trial_balance`', () => {
|
||||
it('Should response unauthorized in case the user was not authorized.', async () => {
|
||||
const res = await request()
|
||||
.get('/api/financial_statements/trial_balance_sheet')
|
||||
.send();
|
||||
|
||||
expect(res.status).equals(401);
|
||||
});
|
||||
|
||||
it('Should retrieve the trial balance of accounts.', async () => {
|
||||
const res = await request()
|
||||
.get('/api/financial_statements/trial_balance_sheet')
|
||||
.set('x-access-token', loginRes.body.token)
|
||||
.set('organization-id', tenantWebsite.organizationId)
|
||||
.send();
|
||||
|
||||
expect(res.body.accounts).include.something.deep.equals({
|
||||
id: debitAccount.id,
|
||||
name: debitAccount.name,
|
||||
code: debitAccount.code,
|
||||
parentAccountId: null,
|
||||
accountNormal: 'debit',
|
||||
credit: 1000,
|
||||
debit: 6000,
|
||||
balance: 5000,
|
||||
|
||||
formatted_credit: 1000,
|
||||
formatted_debit: 6000,
|
||||
formatted_balance: 5000,
|
||||
|
||||
children: [],
|
||||
});
|
||||
expect(res.body.accounts).include.something.deep.equals({
|
||||
id: creditAccount.id,
|
||||
name: creditAccount.name,
|
||||
code: creditAccount.code,
|
||||
accountNormal: 'credit',
|
||||
parentAccountId: null,
|
||||
|
||||
credit: 4000,
|
||||
debit: 0,
|
||||
balance: 4000,
|
||||
|
||||
formatted_credit: 4000,
|
||||
formatted_debit: 0,
|
||||
formatted_balance: 4000,
|
||||
|
||||
children: [],
|
||||
});
|
||||
});
|
||||
|
||||
it('Should not retrieve accounts has no transactions between the given date range.', async () => {
|
||||
const res = await request()
|
||||
.get('/api/financial_statements/trial_balance_sheet')
|
||||
.set('x-access-token', loginRes.body.token)
|
||||
.set('organization-id', tenantWebsite.organizationId)
|
||||
.query({
|
||||
// There is no transactions between these dates.
|
||||
from_date: '2002-01-01',
|
||||
to_date: '2003-01-01',
|
||||
none_zero: true,
|
||||
})
|
||||
.send();
|
||||
|
||||
expect(res.body.accounts.length).equals(0);
|
||||
});
|
||||
|
||||
it('Should retrieve trial balance of accounts between the given date range.', async () => {
|
||||
const res = await request()
|
||||
.get('/api/financial_statements/trial_balance_sheet')
|
||||
.set('x-access-token', loginRes.body.token)
|
||||
.set('organization-id', tenantWebsite.organizationId)
|
||||
.query({
|
||||
// There is no transactions between these dates.
|
||||
from_date: '2020-01-05',
|
||||
to_date: '2020-01-10',
|
||||
none_zero: true,
|
||||
})
|
||||
.send();
|
||||
|
||||
expect(res.body.accounts).include.something.deep.equals({
|
||||
id: creditAccount.id,
|
||||
name: creditAccount.name,
|
||||
code: creditAccount.code,
|
||||
accountNormal: 'credit',
|
||||
parentAccountId: null,
|
||||
credit: 4000,
|
||||
debit: 0,
|
||||
balance: 4000,
|
||||
|
||||
formatted_credit: 4000,
|
||||
formatted_debit: 0,
|
||||
formatted_balance: 4000,
|
||||
|
||||
children: []
|
||||
});
|
||||
});
|
||||
|
||||
it('Should credit, debit and balance amount be divided on 1000.', async () => {
|
||||
const res = await request()
|
||||
.get('/api/financial_statements/trial_balance_sheet')
|
||||
.set('x-access-token', loginRes.body.token)
|
||||
.set('organization-id', tenantWebsite.organizationId)
|
||||
.query({
|
||||
// There is no transactions between these dates.
|
||||
from_date: '2020-01-05',
|
||||
to_date: '2020-01-10',
|
||||
number_format: {
|
||||
divide_1000: true,
|
||||
},
|
||||
})
|
||||
.send();
|
||||
|
||||
expect(res.body.accounts).include.something.deep.equals({
|
||||
id: creditAccount.id,
|
||||
name: creditAccount.name,
|
||||
code: creditAccount.code,
|
||||
accountNormal: 'credit',
|
||||
parentAccountId: null,
|
||||
|
||||
credit: 4000,
|
||||
debit: 0,
|
||||
balance: 4000,
|
||||
|
||||
formatted_credit: 4,
|
||||
formatted_debit: 0,
|
||||
formatted_balance: 4,
|
||||
|
||||
children: [],
|
||||
});
|
||||
});
|
||||
|
||||
it('Should credit, debit and balance amount rounded without cents.', async () => {
|
||||
const res = await request()
|
||||
.get('/api/financial_statements/trial_balance_sheet')
|
||||
.set('x-access-token', loginRes.body.token)
|
||||
.set('organization-id', tenantWebsite.organizationId)
|
||||
.query({
|
||||
// There is no transactions between these dates.
|
||||
from_date: '2020-01-05',
|
||||
to_date: '2020-01-10',
|
||||
number_format: {
|
||||
no_cents: true,
|
||||
},
|
||||
})
|
||||
.send();
|
||||
});
|
||||
|
||||
it('Should retrieve associated account details in accounts list.', async () => {
|
||||
|
||||
});
|
||||
|
||||
it('Should retrieve account with nested array structure as parent/children accounts.', async () => {
|
||||
const childAccount = await tenantFactory.create('account', {
|
||||
parent_account_id: debitAccount.id,
|
||||
account_type_id: 1
|
||||
});
|
||||
|
||||
const res = await request()
|
||||
.get('/api/financial_statements/trial_balance_sheet')
|
||||
.set('x-access-token', loginRes.body.token)
|
||||
.set('organization-id', tenantWebsite.organizationId)
|
||||
.query({
|
||||
account_ids: [debitAccount.id, childAccount.id],
|
||||
})
|
||||
.send();
|
||||
|
||||
expect(res.body.accounts[0].children.length).equals(1);
|
||||
expect(res.body.accounts[0].children[0].id).equals(childAccount.id);
|
||||
});
|
||||
});
|
||||
|
||||
describe('routes: `/api/financial_statements/profit_loss_sheet`', () => {
|
||||
it('Should response unauthorized in case the user was not authorized.', async () => {
|
||||
const res = await request()
|
||||
.get('/api/financial_statements/profit_loos_sheet')
|
||||
.send();
|
||||
|
||||
expect(res.status).equals(401);
|
||||
expect(res.body.message).equals('Unauthorized');
|
||||
});
|
||||
|
||||
it('Should retrieve columns when display type `date_periods` and columns by `month` between date range.', async () => {
|
||||
const res = await request()
|
||||
.get('/api/financial_statements/profit_loss_sheet')
|
||||
.set('x-access-token', loginRes.body.token)
|
||||
.set('organization-id', tenantWebsite.organizationId)
|
||||
.query({
|
||||
from_date: '2020-01-01',
|
||||
to_date: '2020-12-12',
|
||||
display_columns_type: 'date_periods',
|
||||
display_columns_by: 'month',
|
||||
})
|
||||
.send();
|
||||
|
||||
expect(res.body.columns.length).equals(12);
|
||||
expect(res.body.columns).deep.equals([
|
||||
'2020-01', '2020-02',
|
||||
'2020-03', '2020-04',
|
||||
'2020-05', '2020-06',
|
||||
'2020-07', '2020-08',
|
||||
'2020-09', '2020-10',
|
||||
'2020-11', '2020-12',
|
||||
]);
|
||||
});
|
||||
|
||||
it('Should retrieve columns when display type `date_periods` and columns by `quarter`.', async () => {
|
||||
const res = await request()
|
||||
.get('/api/financial_statements/profit_loss_sheet')
|
||||
.set('x-access-token', loginRes.body.token)
|
||||
.set('organization-id', tenantWebsite.organizationId)
|
||||
.query({
|
||||
from_date: moment().startOf('year').format('YYYY-MM-DD'),
|
||||
to_date: moment().endOf('year').format('YYYY-MM-DD'),
|
||||
display_columns_type: 'date_periods',
|
||||
display_columns_by: 'quarter',
|
||||
})
|
||||
.send();
|
||||
|
||||
expect(res.body.columns.length).equals(4);
|
||||
expect(res.body.columns).deep.equals([
|
||||
'2020-03', '2020-06', '2020-09', '2020-12',
|
||||
]);
|
||||
});
|
||||
|
||||
it('Should retrieve columns when display type `date_periods` and columns by `day` between date range.', async () => {
|
||||
const res = await request()
|
||||
.get('/api/financial_statements/profit_loss_sheet')
|
||||
.set('x-access-token', loginRes.body.token)
|
||||
.set('organization-id', tenantWebsite.organizationId)
|
||||
.query({
|
||||
from_date: moment('2020-01-01').startOf('month').format('YYYY-MM-DD'),
|
||||
to_date: moment('2020-01-01').endOf('month').format('YYYY-MM-DD'),
|
||||
display_columns_type: 'date_periods',
|
||||
display_columns_by: 'day',
|
||||
})
|
||||
.send();
|
||||
|
||||
expect(res.body.columns.length).equals(31);
|
||||
expect(res.body.columns).deep.equals([
|
||||
'2020-01-01', '2020-01-02', '2020-01-03',
|
||||
'2020-01-04', '2020-01-05', '2020-01-06',
|
||||
'2020-01-07', '2020-01-08', '2020-01-09',
|
||||
'2020-01-10', '2020-01-11', '2020-01-12',
|
||||
'2020-01-13', '2020-01-14', '2020-01-15',
|
||||
'2020-01-16', '2020-01-17', '2020-01-18',
|
||||
'2020-01-19', '2020-01-20', '2020-01-21',
|
||||
'2020-01-22', '2020-01-23', '2020-01-24',
|
||||
'2020-01-25', '2020-01-26', '2020-01-27',
|
||||
'2020-01-28', '2020-01-29', '2020-01-30',
|
||||
'2020-01-31',
|
||||
]);
|
||||
});
|
||||
|
||||
it('Should retrieve all income accounts even it has no transactions.', async () => {
|
||||
const zeroAccount = await tenantFactory.create('account', { account_type_id: incomeType.id });
|
||||
|
||||
const res = await request()
|
||||
.get('/api/financial_statements/profit_loss_sheet')
|
||||
.set('x-access-token', loginRes.body.token)
|
||||
.set('organization-id', tenantWebsite.organizationId)
|
||||
.query({
|
||||
from_date: moment('2020-01-01').startOf('month').format('YYYY-MM-DD'),
|
||||
to_date: moment('2020-01-31').endOf('month').format('YYYY-MM-DD'),
|
||||
display_columns_type: 'total',
|
||||
display_columns_by: 'month',
|
||||
none_zero: false,
|
||||
})
|
||||
.send();
|
||||
|
||||
expect(res.body.profitLoss.income.accounts).include.something.deep.equals({
|
||||
id: zeroAccount.id,
|
||||
index: zeroAccount.index,
|
||||
name: zeroAccount.name,
|
||||
code: zeroAccount.code,
|
||||
parentAccountId: null,
|
||||
children: [],
|
||||
total: { amount: 0, date: '2020-01-31', formatted_amount: 0 },
|
||||
});
|
||||
});
|
||||
|
||||
it('Should retrieve total of each income account when display columns by `total`.', async () => {
|
||||
const toDate = moment('2020-01-01').endOf('month').format('YYYY-MM-DD');
|
||||
const res = await request()
|
||||
.get('/api/financial_statements/profit_loss_sheet')
|
||||
.set('x-access-token', loginRes.body.token)
|
||||
.set('organization-id', tenantWebsite.organizationId)
|
||||
.query({
|
||||
from_date: moment('2020-01-01').startOf('month').format('YYYY-MM-DD'),
|
||||
to_date: toDate,
|
||||
})
|
||||
.send();
|
||||
|
||||
expect(res.body.profitLoss.income.accounts).to.be.an('array');
|
||||
expect(res.body.profitLoss.income.accounts.length).not.equals(0);
|
||||
expect(res.body.profitLoss.income.accounts[0].id).to.be.an('number');
|
||||
expect(res.body.profitLoss.income.accounts[0].name).to.be.an('string');
|
||||
expect(res.body.profitLoss.income.accounts[0].total).to.be.an('object');
|
||||
expect(res.body.profitLoss.income.accounts[0].total.amount).to.be.an('number');
|
||||
expect(res.body.profitLoss.income.accounts[0].total.formatted_amount).to.be.an('number');
|
||||
expect(res.body.profitLoss.income.accounts[0].total.date).equals(toDate);
|
||||
});
|
||||
|
||||
it('Should retrieve credit sumation of income accounts.', async () => {
|
||||
const res = await request()
|
||||
.get('/api/financial_statements/profit_loss_sheet')
|
||||
.set('x-access-token', loginRes.body.token)
|
||||
.set('organization-id', tenantWebsite.organizationId)
|
||||
.query({
|
||||
from_date: '2020-01-01',
|
||||
to_date: '2021-01-01',
|
||||
})
|
||||
.send();
|
||||
|
||||
expect(res.body.profitLoss.income.total).to.be.an('object');
|
||||
expect(res.body.profitLoss.income.total.amount).equals(2000);
|
||||
expect(res.body.profitLoss.income.total.formatted_amount).equals(2000);
|
||||
expect(res.body.profitLoss.income.total.date).equals('2021-01-01');
|
||||
});
|
||||
|
||||
it('Should retrieve debit sumation of expenses accounts.', async () => {
|
||||
const res = await request()
|
||||
.get('/api/financial_statements/profit_loss_sheet')
|
||||
.set('x-access-token', loginRes.body.token)
|
||||
.set('organization-id', tenantWebsite.organizationId)
|
||||
.query({
|
||||
from_date: '2020-01-01',
|
||||
to_date: '2021-01-01',
|
||||
})
|
||||
.send();
|
||||
|
||||
expect(res.body.profitLoss.expenses.total).to.be.an('object');
|
||||
expect(res.body.profitLoss.expenses.total.amount).equals(1000);
|
||||
expect(res.body.profitLoss.expenses.total.formatted_amount).equals(1000);
|
||||
expect(res.body.profitLoss.expenses.total.date).equals('2021-01-01');
|
||||
});
|
||||
|
||||
it('Should retrieve credit total of income accounts with `date_periods` columns between the given date range.', async () => {
|
||||
const res = await request()
|
||||
.get('/api/financial_statements/profit_loss_sheet')
|
||||
.set('x-access-token', loginRes.body.token)
|
||||
.set('organization-id', tenantWebsite.organizationId)
|
||||
.query({
|
||||
from_date: '2019-12-01',
|
||||
to_date: '2020-12-01',
|
||||
display_columns_type: 'date_periods',
|
||||
display_columns_by: 'month',
|
||||
})
|
||||
.send();
|
||||
|
||||
expect(res.body.profitLoss.income.total_periods[0].amount).equals(0);
|
||||
expect(res.body.profitLoss.income.total_periods[1].amount).equals(2000);
|
||||
expect(res.body.profitLoss.income.total_periods[2].amount).equals(2000);
|
||||
});
|
||||
|
||||
it('Should retrieve debit total of expenses accounts with `date_periods` columns between the given date range.', async () => {
|
||||
const res = await request()
|
||||
.get('/api/financial_statements/profit_loss_sheet')
|
||||
.set('x-access-token', loginRes.body.token)
|
||||
.set('organization-id', tenantWebsite.organizationId)
|
||||
.query({
|
||||
from_date: '2019-12-01',
|
||||
to_date: '2020-12-01',
|
||||
display_columns_type: 'date_periods',
|
||||
display_columns_by: 'month',
|
||||
})
|
||||
.send();
|
||||
|
||||
expect(res.body.profitLoss.expenses.total_periods[0].amount).equals(0);
|
||||
expect(res.body.profitLoss.expenses.total_periods[1].amount).equals(1000);
|
||||
expect(res.body.profitLoss.expenses.total_periods[2].amount).equals(1000);
|
||||
});
|
||||
|
||||
it('Should retrieve total net income with `total column display between the given date range.', async () => {
|
||||
const res = await request()
|
||||
.get('/api/financial_statements/profit_loss_sheet')
|
||||
.set('x-access-token', loginRes.body.token)
|
||||
.set('organization-id', tenantWebsite.organizationId)
|
||||
.query({
|
||||
from_date: '2019-12-01',
|
||||
to_date: '2020-12-01',
|
||||
display_columns_type: 'total',
|
||||
})
|
||||
.send();
|
||||
|
||||
expect(res.body.profitLoss.net_income.total.amount).equals(1000);
|
||||
expect(res.body.profitLoss.net_income.total.formatted_amount).equals(1000);
|
||||
expect(res.body.profitLoss.net_income.total.date).equals('2020-12-01');
|
||||
});
|
||||
|
||||
it('Should retrieve total net income with `date_periods` columns between the given date range.', async () => {
|
||||
const res = await request()
|
||||
.get('/api/financial_statements/profit_loss_sheet')
|
||||
.set('x-access-token', loginRes.body.token)
|
||||
.set('organization-id', tenantWebsite.organizationId)
|
||||
.query({
|
||||
from_date: '2019-12-01',
|
||||
to_date: '2020-12-01',
|
||||
display_columns_type: 'date_periods',
|
||||
display_columns_by: 'quarter',
|
||||
})
|
||||
.send();
|
||||
|
||||
expect(res.body.profitLoss.net_income).deep.equals({
|
||||
total_periods: [
|
||||
{ date: '2019-12', amount: 0, formatted_amount: 0 },
|
||||
{ date: '2020-03', amount: 1000, formatted_amount: 1000 },
|
||||
{ date: '2020-06', amount: 1000, formatted_amount: 1000 },
|
||||
{ date: '2020-09', amount: 1000, formatted_amount: 1000 },
|
||||
{ date: '2020-12', amount: 1000, formatted_amount: 1000 }
|
||||
],
|
||||
});
|
||||
});
|
||||
|
||||
it('Should not retrieve income or expenses accounts that has no transactions between the given date range in case none_zero equals true.', async () => {
|
||||
const res = await request()
|
||||
.get('/api/financial_statements/profit_loss_sheet')
|
||||
.set('x-access-token', loginRes.body.token)
|
||||
.set('organization-id', tenantWebsite.organizationId)
|
||||
.query({
|
||||
from_date: '2020-01-01',
|
||||
to_date: '2021-01-01',
|
||||
display_columns_by: 'month',
|
||||
display_columns_type: 'date_periods',
|
||||
none_zero: true,
|
||||
})
|
||||
.send();
|
||||
|
||||
expect(res.body.profitLoss.income.accounts.length).equals(1);
|
||||
});
|
||||
|
||||
it('Should retrieve accounts in nested array structure as parent/children accounts.', async () => {
|
||||
const childAccount = await tenantFactory.create('account', {
|
||||
parent_account_id: incomeAccount.id,
|
||||
account_type_id: 7
|
||||
});
|
||||
|
||||
const res = await request()
|
||||
.get('/api/financial_statements/profit_loss_sheet')
|
||||
.set('x-access-token', loginRes.body.token)
|
||||
.set('organization-id', tenantWebsite.organizationId)
|
||||
.query({
|
||||
account_ids: [childAccount.id, incomeAccount.id],
|
||||
})
|
||||
.send();
|
||||
|
||||
expect(res.body.profitLoss.income.accounts.length).equals(1);
|
||||
expect(res.body.profitLoss.income.accounts[0].children.length).equals(1);
|
||||
expect(res.body.profitLoss.income.accounts[0].children[0].id).equals(childAccount.id);
|
||||
});
|
||||
|
||||
it('Should parent account credit/debit sumation of total periods amounts all children accounts.', async () => {
|
||||
const childAccount = await tenantFactory.create('account', {
|
||||
parent_account_id: incomeAccount.id,
|
||||
account_type_id: 7,
|
||||
});
|
||||
await tenantFactory.create('account_transaction', {
|
||||
credit: 1000, debit: 0, account_id: childAccount.id, date: '2020-2-10'
|
||||
});
|
||||
|
||||
const res = await request()
|
||||
.get('/api/financial_statements/profit_loss_sheet')
|
||||
.set('x-access-token', loginRes.body.token)
|
||||
.set('organization-id', tenantWebsite.organizationId)
|
||||
.query({
|
||||
account_ids: [childAccount.id, incomeAccount.id],
|
||||
from_date: '2020-01-01',
|
||||
to_date: '2020-12-12',
|
||||
})
|
||||
.send();
|
||||
|
||||
expect(res.body.profitLoss.income.accounts[0].total).deep.equals({
|
||||
amount: 3000, date: '2020-12-12', formatted_amount: 3000
|
||||
});
|
||||
});
|
||||
|
||||
it('Should parent account credit/debit sumation of total date periods.', async () => {
|
||||
const childAccount = await tenantFactory.create('account', {
|
||||
parent_account_id: incomeAccount.id,
|
||||
account_type_id: 7,
|
||||
});
|
||||
await tenantFactory.create('account_transaction', {
|
||||
credit: 1000, debit: 0, account_id: childAccount.id, date: '2020-2-10'
|
||||
});
|
||||
|
||||
const res = await request()
|
||||
.get('/api/financial_statements/profit_loss_sheet')
|
||||
.set('x-access-token', loginRes.body.token)
|
||||
.set('organization-id', tenantWebsite.organizationId)
|
||||
.query({
|
||||
account_ids: [childAccount.id, incomeAccount.id],
|
||||
display_columns_type: 'date_periods',
|
||||
display_columns_by: 'month',
|
||||
from_date: '2020-01-01',
|
||||
to_date: '2020-12-12',
|
||||
})
|
||||
.send();
|
||||
|
||||
const periods = [
|
||||
{ date: '2020-01', amount: 2000, formatted_amount: 2000 },
|
||||
{ date: '2020-02', amount: 3000, formatted_amount: 3000 },
|
||||
{ date: '2020-03', amount: 3000, formatted_amount: 3000 },
|
||||
{ date: '2020-04', amount: 3000, formatted_amount: 3000 },
|
||||
{ date: '2020-05', amount: 3000, formatted_amount: 3000 },
|
||||
{ date: '2020-06', amount: 3000, formatted_amount: 3000 },
|
||||
{ date: '2020-07', amount: 3000, formatted_amount: 3000 },
|
||||
{ date: '2020-08', amount: 3000, formatted_amount: 3000 },
|
||||
{ date: '2020-09', amount: 3000, formatted_amount: 3000 },
|
||||
{ date: '2020-10', amount: 3000, formatted_amount: 3000 },
|
||||
{ date: '2020-11', amount: 3000, formatted_amount: 3000 },
|
||||
{ date: '2020-12', amount: 3000, formatted_amount: 3000 }
|
||||
];
|
||||
expect(res.body.profitLoss.income.accounts[0].periods).deep.equals(periods);
|
||||
expect(res.body.profitLoss.income.total_periods).deep.equals(periods);
|
||||
});
|
||||
});
|
||||
});
|
||||
259
packages/server/tests/routes/inviteUsers.test.js
Normal file
259
packages/server/tests/routes/inviteUsers.test.js
Normal file
@@ -0,0 +1,259 @@
|
||||
import knex from '@/database/knex';
|
||||
import {
|
||||
request,
|
||||
expect,
|
||||
createUser,
|
||||
} from '~/testInit';
|
||||
import {
|
||||
tenantWebsite,
|
||||
tenantFactory,
|
||||
loginRes
|
||||
} from '~/dbInit';
|
||||
import Invite from '@/system/models/Invite'
|
||||
import TenantUser from 'models/TenantUser';
|
||||
import SystemUser from '@/system/models/SystemUser';
|
||||
|
||||
describe('routes: `/api/invite_users`', () => {
|
||||
describe('POST: `/api/invite_users/send`', () => {
|
||||
it('Should response unauthorized if the user was not authorized.', async () => {
|
||||
const res = await request().get('/api/invite_users/send');
|
||||
|
||||
expect(res.status).equals(401);
|
||||
expect(res.body.message).equals('Unauthorized');
|
||||
});
|
||||
|
||||
it('Should email be required.', async () => {
|
||||
const res = await request()
|
||||
.post('/api/invite/send')
|
||||
.set('x-access-token', loginRes.body.token)
|
||||
.set('organization-id', tenantWebsite.organizationId)
|
||||
.send();
|
||||
|
||||
expect(res.status).equals(422);
|
||||
expect(res.body.errors).include.something.deep.equals({
|
||||
msg: 'Invalid value', param: 'email', location: 'body',
|
||||
});
|
||||
});
|
||||
|
||||
it('Should email not be already registered in the system database.', async () => {
|
||||
const user = await createUser(tenantWebsite, {
|
||||
active: false,
|
||||
email: 'admin@admin.com',
|
||||
});
|
||||
|
||||
const res = await request()
|
||||
.post('/api/invite/send')
|
||||
.set('x-access-token', loginRes.body.token)
|
||||
.set('organization-id', tenantWebsite.organizationId)
|
||||
.send({
|
||||
email: 'admin@admin.com',
|
||||
});
|
||||
|
||||
expect(res.status).equals(400);
|
||||
expect(res.body.errors).include.something.deep.equals({
|
||||
type: 'USER.EMAIL.ALREADY.REGISTERED', code: 100,
|
||||
});
|
||||
});
|
||||
|
||||
it('Should invite token be inserted to the master database.', async () => {
|
||||
const res = await request()
|
||||
.post('/api/invite/send')
|
||||
.set('x-access-token', loginRes.body.token)
|
||||
.set('organization-id', tenantWebsite.organizationId)
|
||||
.send({
|
||||
email: 'admin@admin.com'
|
||||
});
|
||||
|
||||
const foundInviteToken = await Invite.query()
|
||||
.where('email', 'admin@admin.com').first();
|
||||
|
||||
expect(foundInviteToken).is.not.null;
|
||||
expect(foundInviteToken.token).is.not.null;
|
||||
});
|
||||
|
||||
it('Should invite email be insereted to users tenant database.', async () => {
|
||||
const res = await request()
|
||||
.post('/api/invite/send')
|
||||
.set('x-access-token', loginRes.body.token)
|
||||
.set('organization-id', tenantWebsite.organizationId)
|
||||
.send({
|
||||
email: 'admin@admin.com'
|
||||
});
|
||||
|
||||
const foundTenantUser = await TenantUser.tenant().query()
|
||||
.where('email', 'admin@admin.com').first();
|
||||
|
||||
expect(foundTenantUser).is.not.null;
|
||||
expect(foundTenantUser.email).equals('admin@admin.com');
|
||||
expect(foundTenantUser.firstName).equals('admin@admin.com');
|
||||
expect(foundTenantUser.createdAt).is.not.null;
|
||||
});
|
||||
});
|
||||
|
||||
describe('POST: `/api/invite/accept/:token`', () => {
|
||||
let sendInviteRes;
|
||||
let inviteUser;
|
||||
|
||||
beforeEach(async () => {
|
||||
sendInviteRes = await request()
|
||||
.post('/api/invite/send')
|
||||
.set('x-access-token', loginRes.body.token)
|
||||
.set('organization-id', tenantWebsite.organizationId)
|
||||
.send({
|
||||
email: 'admin@admin.com'
|
||||
});
|
||||
|
||||
inviteUser = await Invite.query()
|
||||
.where('email', 'admin@admin.com')
|
||||
.first();
|
||||
});
|
||||
|
||||
it('Should the given token be valid.', async () => {
|
||||
const res = await request()
|
||||
.post('/api/invite/accept/invalid_token')
|
||||
.send({
|
||||
first_name: 'Ahmed',
|
||||
last_name: 'Bouhuolia',
|
||||
password: 'hard-password',
|
||||
phone_number: '0927918381',
|
||||
});
|
||||
|
||||
expect(res.status).equals(404);
|
||||
expect(res.body.errors).include.something.deep.equals({
|
||||
type: 'INVITE.TOKEN.NOT.FOUND', code: 300,
|
||||
});
|
||||
});
|
||||
|
||||
it('Should first_name be required.', async () => {
|
||||
const res = await request()
|
||||
.post(`/api/invite/accept/${inviteUser.token}`)
|
||||
.send();
|
||||
|
||||
expect(res.status).equals(422);
|
||||
expect(res.body.errors).include.something.deep.equals({
|
||||
msg: 'Invalid value', param: 'first_name', location: 'body'
|
||||
});
|
||||
});
|
||||
|
||||
it('Should last_name be required.', async () => {
|
||||
const res = await request()
|
||||
.post(`/api/invite/accept/${inviteUser.token}`)
|
||||
.send();
|
||||
|
||||
expect(res.status).equals(422);
|
||||
expect(res.body.errors).include.something.deep.equals({
|
||||
msg: 'Invalid value', param: 'last_name', location: 'body'
|
||||
});
|
||||
});
|
||||
|
||||
it('Should phone_number be required.', async () => {
|
||||
const res = await request()
|
||||
.post(`/api/invite/accept/${inviteUser.token}`)
|
||||
.send();
|
||||
|
||||
expect(res.status).equals(422);
|
||||
expect(res.body.errors).include.something.deep.equals({
|
||||
msg: 'Invalid value', param: 'phone_number', location: 'body'
|
||||
});
|
||||
});
|
||||
|
||||
it('Should password be required.', async () => {
|
||||
const res = await request()
|
||||
.post(`/api/invite/accept/${inviteUser.token}`)
|
||||
.send();
|
||||
|
||||
expect(res.status).equals(422);
|
||||
expect(res.body.errors).include.something.deep.equals({
|
||||
msg: 'Invalid value', param: 'password', location: 'body'
|
||||
});
|
||||
});
|
||||
|
||||
it('Should phone number not be already registered.', async () => {
|
||||
const user = await createUser(tenantWebsite);
|
||||
const res = await request()
|
||||
.post(`/api/invite/accept/${inviteUser.token}`)
|
||||
.send({
|
||||
first_name: 'Ahmed',
|
||||
last_name: 'Bouhuolia',
|
||||
password: 'hard-password',
|
||||
phone_number: user.phone_number,
|
||||
})
|
||||
|
||||
expect(res.status).equals(400);
|
||||
expect(res.body.errors).include.something.deep.equals({
|
||||
type: 'PHONE_MUMNER.ALREADY.EXISTS', code: 400,
|
||||
});
|
||||
});
|
||||
|
||||
it('Should tenant user details updated after invite accept.', async () => {
|
||||
const user = await createUser(tenantWebsite);
|
||||
const res = await request()
|
||||
.post(`/api/invite/accept/${inviteUser.token}`)
|
||||
.send({
|
||||
first_name: 'Ahmed',
|
||||
last_name: 'Bouhuolia',
|
||||
password: 'hard-password',
|
||||
phone_number: '0927918381',
|
||||
});
|
||||
|
||||
const foundTenantUser = await TenantUser.tenant().query()
|
||||
.where('email', 'admin@admin.com').first();
|
||||
|
||||
expect(foundTenantUser).is.not.null;
|
||||
expect(foundTenantUser.id).is.not.null;
|
||||
expect(foundTenantUser.email).equals('admin@admin.com');
|
||||
expect(foundTenantUser.firstName).equals('Ahmed');
|
||||
expect(foundTenantUser.lastName).equals('Bouhuolia');
|
||||
expect(foundTenantUser.active).equals(1);
|
||||
expect(foundTenantUser.inviteAcceptedAt).is.not.null;
|
||||
expect(foundTenantUser.createdAt).is.not.null;
|
||||
expect(foundTenantUser.updatedAt).is.not.null;
|
||||
});
|
||||
|
||||
it('Should user details be insereted to the system database', async () => {
|
||||
const user = await createUser(tenantWebsite);
|
||||
const res = await request()
|
||||
.post(`/api/invite/accept/${inviteUser.token}`)
|
||||
.send({
|
||||
first_name: 'Ahmed',
|
||||
last_name: 'Bouhuolia',
|
||||
password: 'hard-password',
|
||||
phone_number: '0927918381',
|
||||
});
|
||||
|
||||
const foundSystemUser = await SystemUser.query()
|
||||
.where('email', 'admin@admin.com').first();
|
||||
|
||||
expect(foundSystemUser).is.not.null;
|
||||
expect(foundSystemUser.id).is.not.null;
|
||||
expect(foundSystemUser.tenantId).equals(inviteUser.tenantId);
|
||||
expect(foundSystemUser.email).equals('admin@admin.com');
|
||||
expect(foundSystemUser.firstName).equals('Ahmed');
|
||||
expect(foundSystemUser.lastName).equals('Bouhuolia');
|
||||
expect(foundSystemUser.active).equals(1);
|
||||
expect(foundSystemUser.lastLoginAt).is.null;
|
||||
expect(foundSystemUser.createdAt).is.not.null;
|
||||
expect(foundSystemUser.updatedAt).is.null;
|
||||
});
|
||||
|
||||
it('Should invite token be deleted after invite accept.', async () => {
|
||||
const res = await request()
|
||||
.post(`/api/invite/accept/${inviteUser.token}`)
|
||||
.send({
|
||||
first_name: 'Ahmed',
|
||||
last_name: 'Bouhuolia',
|
||||
password: 'hard-password',
|
||||
phone_number: '0927918381',
|
||||
});
|
||||
|
||||
const foundInviteToken = await Invite.query().where('token', inviteUser.token);
|
||||
expect(foundInviteToken.length).equals(0);
|
||||
});
|
||||
});
|
||||
|
||||
describe('GET: `/api/invite_users/:token`', () => {
|
||||
it('Should response token invalid.', () => {
|
||||
|
||||
});
|
||||
});
|
||||
});
|
||||
729
packages/server/tests/routes/items.test.js
Normal file
729
packages/server/tests/routes/items.test.js
Normal file
@@ -0,0 +1,729 @@
|
||||
import {
|
||||
request,
|
||||
expect,
|
||||
} from '~/testInit';
|
||||
import Item from 'models/Item';
|
||||
import {
|
||||
tenantWebsite,
|
||||
tenantFactory,
|
||||
loginRes
|
||||
} from '~/dbInit';
|
||||
|
||||
|
||||
describe('routes: `/items`', () => {
|
||||
describe('POST: `/items`', () => {
|
||||
it('Should not create a new item if the user was not authorized.', async () => {
|
||||
const res = await request()
|
||||
.post('/api/items')
|
||||
.send();
|
||||
|
||||
expect(res.status).equals(401);
|
||||
expect(res.body.message).equals('Unauthorized');
|
||||
});
|
||||
|
||||
it('Should `name` be required.', async () => {
|
||||
const res = await request()
|
||||
.post('/api/items')
|
||||
.set('x-access-token', loginRes.body.token)
|
||||
.set('organization-id', tenantWebsite.organizationId)
|
||||
.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: 'name', location: 'body',
|
||||
});
|
||||
});
|
||||
|
||||
it('Should `type` be required.', async () => {
|
||||
const res = await request()
|
||||
.post('/api/items')
|
||||
.set('x-access-token', loginRes.body.token)
|
||||
.set('organization-id', tenantWebsite.organizationId)
|
||||
.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: 'type', location: 'body',
|
||||
});
|
||||
});
|
||||
|
||||
it('Should `type` be one of defined words.', async () => {
|
||||
const res = await request()
|
||||
.post('/api/items')
|
||||
.set('x-access-token', loginRes.body.token)
|
||||
.set('organization-id', tenantWebsite.organizationId)
|
||||
.send({
|
||||
type: 'not-defined',
|
||||
});
|
||||
|
||||
expect(res.body.errors).include.something.deep.equals({
|
||||
value: 'not-defined',
|
||||
msg: 'Invalid value',
|
||||
param: 'type',
|
||||
location: 'body',
|
||||
});
|
||||
});
|
||||
|
||||
it('Should `buy_price` be numeric.', async () => {
|
||||
const res = await request()
|
||||
.post('/api/items')
|
||||
.set('x-access-token', loginRes.body.token)
|
||||
.set('organization-id', tenantWebsite.organizationId)
|
||||
.send({
|
||||
cost_price: 'not_numeric',
|
||||
});
|
||||
|
||||
expect(res.status).equals(422);
|
||||
expect(res.body.code).equals('validation_error');
|
||||
expect(res.body.errors).include.something.deep.equals({
|
||||
value: 'not_numeric',
|
||||
msg: 'Invalid value',
|
||||
param: 'cost_price',
|
||||
location: 'body',
|
||||
});
|
||||
});
|
||||
|
||||
it('Should `sell_price` be numeric.', async () => {
|
||||
const res = await request()
|
||||
.post('/api/items')
|
||||
.set('x-access-token', loginRes.body.token)
|
||||
.set('organization-id', tenantWebsite.organizationId)
|
||||
.send({
|
||||
sell_price: 'not_numeric',
|
||||
});
|
||||
|
||||
expect(res.status).equals(422);
|
||||
expect(res.body.code).equals('validation_error');
|
||||
expect(res.body.errors).include.something.deep.equals({
|
||||
value: 'not_numeric',
|
||||
msg: 'Invalid value',
|
||||
param: 'sell_price',
|
||||
location: 'body',
|
||||
});
|
||||
});
|
||||
|
||||
it('Should `sell_account_id` be integer.', async () => {
|
||||
const res = await request()
|
||||
.post('/api/items')
|
||||
.set('x-access-token', loginRes.body.token)
|
||||
.set('organization-id', tenantWebsite.organizationId)
|
||||
.send({
|
||||
cost_account_id: 'not_numeric',
|
||||
});
|
||||
|
||||
expect(res.status).equals(422);
|
||||
expect(res.body.code).equals('validation_error');
|
||||
expect(res.body.errors).include.something.deep.equals({
|
||||
value: 'not_numeric',
|
||||
msg: 'Invalid value',
|
||||
param: 'cost_account_id',
|
||||
location: 'body',
|
||||
});
|
||||
});
|
||||
|
||||
it('Should `cost_account_id` be integer.', async () => {
|
||||
const res = await request()
|
||||
.post('/api/items')
|
||||
.set('x-access-token', loginRes.body.token)
|
||||
.set('organization-id', tenantWebsite.organizationId)
|
||||
.send({
|
||||
sell_account_id: 'not_numeric',
|
||||
});
|
||||
|
||||
expect(res.status).equals(422);
|
||||
expect(res.body.code).equals('validation_error');
|
||||
expect(res.body.errors).include.something.deep.equals({
|
||||
value: 'not_numeric',
|
||||
msg: 'Invalid value',
|
||||
param: 'sell_account_id',
|
||||
location: 'body',
|
||||
});
|
||||
});
|
||||
|
||||
it('Should `cost_account_id` be required if `cost_price` was presented.', async () => {
|
||||
|
||||
});
|
||||
|
||||
it('Should `buy_account_id` be required if `buy_price` was presented.', async () => {
|
||||
|
||||
});
|
||||
|
||||
it('Should `inventory_account_id` be required if type was `inventory` item.', async () => {
|
||||
const res = await request()
|
||||
.post('/api/items')
|
||||
.set('x-access-token', loginRes.body.token)
|
||||
.set('organization-id', tenantWebsite.organizationId)
|
||||
.send({
|
||||
name: 'Item Name',
|
||||
type: 'inventory',
|
||||
sell_price: 10.2,
|
||||
cost_price: 20.2,
|
||||
sell_account_id: 10,
|
||||
cost_account_id: 20,
|
||||
});
|
||||
|
||||
expect(res.body.errors).include.something.deep.equals({
|
||||
msg: 'Invalid value',
|
||||
param: 'inventory_account_id',
|
||||
location: 'body',
|
||||
});
|
||||
});
|
||||
|
||||
it('Should `inventory_account_id` be not required if type was not `inventory`.', async () => {
|
||||
const res = await request()
|
||||
.post('/api/items')
|
||||
.set('x-access-token', loginRes.body.token)
|
||||
.set('organization-id', tenantWebsite.organizationId)
|
||||
.send({
|
||||
name: 'Item Name',
|
||||
type: 'service',
|
||||
sell_price: 10.2,
|
||||
cost_price: 20.2,
|
||||
sell_account_id: 10,
|
||||
cost_account_id: 20,
|
||||
});
|
||||
|
||||
expect(res.body.errors).include.something.deep.not.equals({
|
||||
msg: 'Invalid value',
|
||||
param: 'inventory_account_id',
|
||||
location: 'body',
|
||||
});
|
||||
});
|
||||
|
||||
it('Should response bad request in case `cost account` was not exist.', async () => {
|
||||
const res = await request()
|
||||
.post('/api/items')
|
||||
.set('x-access-token', loginRes.body.token)
|
||||
.set('organization-id', tenantWebsite.organizationId)
|
||||
.send({
|
||||
name: 'Item Name',
|
||||
type: 'service',
|
||||
sell_price: 10.2,
|
||||
cost_price: 20.2,
|
||||
sell_account_id: 10,
|
||||
cost_account_id: 20,
|
||||
});
|
||||
|
||||
expect(res.status).equals(400);
|
||||
expect(res.body.errors).include.something.that.deep.equals({
|
||||
type: 'COST_ACCOUNT_NOT_FOUND', code: 100,
|
||||
});
|
||||
});
|
||||
|
||||
it('Should response bad request in case sell account was not exist.', async () => {
|
||||
const res = await request()
|
||||
.post('/api/items')
|
||||
.set('x-access-token', loginRes.body.token)
|
||||
.set('organization-id', tenantWebsite.organizationId)
|
||||
.send({
|
||||
name: 'Item Name',
|
||||
type: 'service',
|
||||
sell_price: 10.2,
|
||||
cost_price: 20.2,
|
||||
sell_account_id: 10,
|
||||
cost_account_id: 20,
|
||||
});
|
||||
|
||||
expect(res.status).equals(400);
|
||||
expect(res.body.errors).include.something.that.deep.equals({
|
||||
type: 'SELL_ACCOUNT_NOT_FOUND', code: 120,
|
||||
});
|
||||
});
|
||||
|
||||
it('Should response not category found in case item category was not exist.', async () => {
|
||||
const res = await request()
|
||||
.post('/api/items')
|
||||
.set('x-access-token', loginRes.body.token)
|
||||
.set('organization-id', tenantWebsite.organizationId)
|
||||
.send({
|
||||
name: 'Item Name',
|
||||
type: 'service',
|
||||
sell_price: 10.2,
|
||||
cost_price: 20.2,
|
||||
sell_account_id: 10,
|
||||
cost_account_id: 20,
|
||||
category_id: 20,
|
||||
});
|
||||
|
||||
expect(res.status).equals(400);
|
||||
expect(res.body.errors).include.something.that.deep.equals({
|
||||
type: 'ITEM_CATEGORY_NOT_FOUND', code: 140,
|
||||
});
|
||||
});
|
||||
|
||||
it('Should response success with correct data format.', async () => {
|
||||
const account = await tenantFactory.create('account');
|
||||
const anotherAccount = await tenantFactory.create('account');
|
||||
const itemCategory = await tenantFactory.create('item_category');
|
||||
|
||||
const res = await request()
|
||||
.post('/api/items')
|
||||
.set('x-access-token', loginRes.body.token)
|
||||
.set('organization-id', tenantWebsite.organizationId)
|
||||
.send({
|
||||
name: 'Item Name',
|
||||
type: 'service',
|
||||
sell_price: 10.2,
|
||||
cost_price: 20.2,
|
||||
sell_account_id: account.id,
|
||||
cost_account_id: anotherAccount.id,
|
||||
category_id: itemCategory.id,
|
||||
});
|
||||
|
||||
expect(res.status).equals(200);
|
||||
});
|
||||
|
||||
it('Should store the given item details to the storage.', async () => {
|
||||
const account = await tenantFactory.create('account');
|
||||
const anotherAccount = await tenantFactory.create('account');
|
||||
const itemCategory = await tenantFactory.create('item_category');
|
||||
|
||||
const res = await request()
|
||||
.post('/api/items')
|
||||
.set('x-access-token', loginRes.body.token)
|
||||
.set('organization-id', tenantWebsite.organizationId)
|
||||
.send({
|
||||
name: 'Item Name',
|
||||
type: 'service',
|
||||
sku: 'SKU CODE',
|
||||
sell_price: 10.2,
|
||||
cost_price: 20.2,
|
||||
sell_account_id: account.id,
|
||||
cost_account_id: anotherAccount.id,
|
||||
category_id: itemCategory.id,
|
||||
note: 'note about item'
|
||||
});
|
||||
|
||||
const storedItem = await Item.tenant().query().where('id', res.body.id).first();
|
||||
|
||||
expect(storedItem.name).equals('Item Name');
|
||||
expect(storedItem.type).equals('service');
|
||||
|
||||
expect(storedItem.sellPrice).equals(10.2);
|
||||
expect(storedItem.costPrice).equals(20.2);
|
||||
expect(storedItem.sellAccountId).equals(account.id);
|
||||
expect(storedItem.costAccountId).equals(anotherAccount.id);
|
||||
expect(storedItem.categoryId).equals(itemCategory.id);
|
||||
expect(storedItem.sku).equals('SKU CODE');
|
||||
expect(storedItem.note).equals('note about item');
|
||||
expect(storedItem.userId).is.not.null;
|
||||
});
|
||||
});
|
||||
|
||||
describe('POST: `items/:id`', () => {
|
||||
it('Should response item not found in case item id was not exist.', async () => {
|
||||
const res = await request()
|
||||
.post('/api/items/100')
|
||||
.set('x-access-token', loginRes.body.token)
|
||||
.set('organization-id', tenantWebsite.organizationId)
|
||||
.send({
|
||||
name: 'Item Name',
|
||||
type: 'product',
|
||||
cost_price: 100,
|
||||
sell_price: 200,
|
||||
sell_account_id: 1,
|
||||
cost_account_id: 2,
|
||||
category_id: 2,
|
||||
});
|
||||
|
||||
expect(res.status).equals(404);
|
||||
expect(res.body.errors).include.something.deep.equals({
|
||||
type: 'ITEM.NOT.FOUND', code: 100,
|
||||
});
|
||||
});
|
||||
|
||||
it('Should `name` be required.', async () => {
|
||||
const item = await tenantFactory.create('item');
|
||||
const res = await request()
|
||||
.post(`/api/items/${item.id}`)
|
||||
.set('x-access-token', loginRes.body.token)
|
||||
.set('organization-id', tenantWebsite.organizationId)
|
||||
.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: 'name', location: 'body',
|
||||
});
|
||||
});
|
||||
|
||||
it('Should `type` be required.', async () => {
|
||||
const item = await tenantFactory.create('item');
|
||||
const res = await request()
|
||||
.post(`/api/items/${item.id}`)
|
||||
.set('x-access-token', loginRes.body.token)
|
||||
.set('organization-id', tenantWebsite.organizationId)
|
||||
.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: 'type', location: 'body',
|
||||
});
|
||||
});
|
||||
|
||||
it('Should `sell_price` be numeric.', async () => {
|
||||
const item = await tenantFactory.create('item');
|
||||
const res = await request()
|
||||
.post(`/api/items/${item.id}`)
|
||||
.set('x-access-token', loginRes.body.token)
|
||||
.set('organization-id', tenantWebsite.organizationId)
|
||||
.send({
|
||||
sell_price: 'not_numeric',
|
||||
});
|
||||
|
||||
expect(res.status).equals(422);
|
||||
expect(res.body.code).equals('validation_error');
|
||||
expect(res.body.errors).include.something.deep.equals({
|
||||
value: 'not_numeric',
|
||||
msg: 'Invalid value',
|
||||
param: 'sell_price',
|
||||
location: 'body',
|
||||
});
|
||||
});
|
||||
|
||||
it('Should `cost_price` be numeric.', async () => {
|
||||
const item = await tenantFactory.create('item');
|
||||
const res = await request()
|
||||
.post(`/api/items/${item.id}`)
|
||||
.set('x-access-token', loginRes.body.token)
|
||||
.set('organization-id', tenantWebsite.organizationId)
|
||||
.send({
|
||||
cost_price: 'not_numeric',
|
||||
});
|
||||
|
||||
expect(res.status).equals(422);
|
||||
expect(res.body.code).equals('validation_error');
|
||||
expect(res.body.errors).include.something.deep.equals({
|
||||
value: 'not_numeric',
|
||||
msg: 'Invalid value',
|
||||
param: 'cost_price',
|
||||
location: 'body',
|
||||
});
|
||||
});
|
||||
|
||||
it('Should `sell_account_id` be integer.', async () => {
|
||||
const item = await tenantFactory.create('item');
|
||||
const res = await request()
|
||||
.post(`/api/items/${item.id}`)
|
||||
.set('x-access-token', loginRes.body.token)
|
||||
.set('organization-id', tenantWebsite.organizationId)
|
||||
.send({
|
||||
sell_account_id: 'not_numeric',
|
||||
});
|
||||
|
||||
expect(res.status).equals(422);
|
||||
expect(res.body.code).equals('validation_error');
|
||||
expect(res.body.errors).include.something.deep.equals({
|
||||
value: 'not_numeric',
|
||||
msg: 'Invalid value',
|
||||
param: 'sell_account_id',
|
||||
location: 'body',
|
||||
});
|
||||
});
|
||||
|
||||
it('Should `cost_account_id` be integer.', async () => {
|
||||
const item = await tenantFactory.create('item');
|
||||
const res = await request()
|
||||
.post(`/api/items/${item.id}`)
|
||||
.set('x-access-token', loginRes.body.token)
|
||||
.set('organization-id', tenantWebsite.organizationId)
|
||||
.send({
|
||||
cost_account_id: 'not_numeric',
|
||||
});
|
||||
|
||||
expect(res.status).equals(422);
|
||||
expect(res.body.code).equals('validation_error');
|
||||
expect(res.body.errors).include.something.deep.equals({
|
||||
value: 'not_numeric',
|
||||
msg: 'Invalid value',
|
||||
param: 'cost_account_id',
|
||||
location: 'body',
|
||||
});
|
||||
});
|
||||
|
||||
it ('Should response bad request in case cost account was not exist.', async () => {
|
||||
const item = await tenantFactory.create('item');
|
||||
const res = await request()
|
||||
.post(`/api/items/${item.id}`)
|
||||
.set('x-access-token', loginRes.body.token)
|
||||
.set('organization-id', tenantWebsite.organizationId)
|
||||
.send({
|
||||
name: 'Item Name',
|
||||
type: 'service',
|
||||
sell_price: 10.2,
|
||||
cost_price: 20.2,
|
||||
sell_account_id: 10,
|
||||
cost_account_id: 20,
|
||||
});
|
||||
|
||||
expect(res.status).equals(400);
|
||||
expect(res.body.errors).include.something.that.deep.equals({
|
||||
type: 'COST_ACCOUNT_NOT_FOUND', code: 100,
|
||||
});
|
||||
});
|
||||
|
||||
it('Should response bad request in case sell account was not exist.', async () => {
|
||||
const item = await tenantFactory.create('item');
|
||||
const res = await request()
|
||||
.post(`/api/items/${item.id}`)
|
||||
.set('x-access-token', loginRes.body.token)
|
||||
.set('organization-id', tenantWebsite.organizationId)
|
||||
.send({
|
||||
name: 'Item Name',
|
||||
type: 'product',
|
||||
sell_price: 10.2,
|
||||
cost_price: 20.2,
|
||||
sell_account_id: 1000000,
|
||||
cost_account_id: 1000000,
|
||||
});
|
||||
|
||||
expect(res.status).equals(400);
|
||||
expect(res.body.errors).include.something.that.deep.equals({
|
||||
type: 'SELL_ACCOUNT_NOT_FOUND', code: 120,
|
||||
});
|
||||
});
|
||||
|
||||
it('Should update details of the given item.', async () => {
|
||||
const account = await tenantFactory.create('account');
|
||||
const anotherAccount = await tenantFactory.create('account');
|
||||
const itemCategory = await tenantFactory.create('item_category');
|
||||
|
||||
const item = await tenantFactory.create('item');
|
||||
const res = await request()
|
||||
.post(`/api/items/${item.id}`)
|
||||
.set('x-access-token', loginRes.body.token)
|
||||
.set('organization-id', tenantWebsite.organizationId)
|
||||
.send({
|
||||
name: 'New Item Name',
|
||||
type: 'service',
|
||||
sell_price: 10.2,
|
||||
cost_price: 20.2,
|
||||
sell_account_id: account.id,
|
||||
cost_account_id: anotherAccount.id,
|
||||
category_id: itemCategory.id,
|
||||
});
|
||||
|
||||
const updatedItem = await Item.tenant().query().findById(item.id);
|
||||
|
||||
expect(updatedItem.name).equals('New Item Name');
|
||||
expect(updatedItem.type).equals('service');
|
||||
expect(updatedItem.sellPrice).equals(10.2);
|
||||
expect(updatedItem.costPrice).equals(20.2);
|
||||
expect(updatedItem.sellAccountId).equals(account.id);
|
||||
expect(updatedItem.costAccountId).equals(anotherAccount.id);
|
||||
expect(updatedItem.categoryId).equals(itemCategory.id);
|
||||
});
|
||||
});
|
||||
|
||||
describe('DELETE: `items/:id`', () => {
|
||||
it('Should response not found in case the item was not exist.', async () => {
|
||||
const res = await request()
|
||||
.delete('/api/items/10')
|
||||
.set('x-access-token', loginRes.body.token)
|
||||
.set('organization-id', tenantWebsite.organizationId)
|
||||
.send();
|
||||
|
||||
expect(res.status).equals(404);
|
||||
});
|
||||
|
||||
it('Should response success in case was exist.', async () => {
|
||||
const item = await tenantFactory.create('item');
|
||||
const res = await request()
|
||||
.delete(`/api/items/${item.id}`)
|
||||
.set('x-access-token', loginRes.body.token)
|
||||
.set('organization-id', tenantWebsite.organizationId)
|
||||
.send();
|
||||
|
||||
expect(res.status).equals(200);
|
||||
});
|
||||
|
||||
it('Should delete the given item from the storage.', async () => {
|
||||
const item = await tenantFactory.create('item');
|
||||
await request()
|
||||
.delete(`/api/items/${item.id}`)
|
||||
.set('x-access-token', loginRes.body.token)
|
||||
.set('organization-id', tenantWebsite.organizationId)
|
||||
.send();
|
||||
|
||||
const storedItems = await Item.tenant().query().where('id', item.id);
|
||||
expect(storedItems).to.have.lengthOf(0);
|
||||
});
|
||||
});
|
||||
|
||||
describe('DELETE: `items?ids=`', () => {
|
||||
it('Should response in case one of items ids where not exists.', async () => {
|
||||
const res = await request()
|
||||
.delete('/api/items')
|
||||
.set('x-access-token', loginRes.body.token)
|
||||
.set('organization-id', tenantWebsite.organizationId)
|
||||
.query({
|
||||
ids: [100, 200],
|
||||
})
|
||||
.send();
|
||||
|
||||
expect(res.status).equals(404);
|
||||
expect(res.body.errors).include.something.that.deep.equals({
|
||||
type: 'ITEMS.NOT.FOUND', code: 200, ids: [100, 200],
|
||||
});
|
||||
});
|
||||
|
||||
it('Should delete the given items from the storage.', async () => {
|
||||
const item1 = await tenantFactory.create('item');
|
||||
const item2 = await tenantFactory.create('item');
|
||||
|
||||
const res = await request()
|
||||
.delete('/api/items')
|
||||
.set('x-access-token', loginRes.body.token)
|
||||
.set('organization-id', tenantWebsite.organizationId)
|
||||
.query({
|
||||
ids: [item1.id, item2.id],
|
||||
})
|
||||
.send();
|
||||
|
||||
const foundItems = await Item.tenant().query();
|
||||
|
||||
expect(res.status).equals(200);
|
||||
expect(foundItems.length).equals(0)
|
||||
});
|
||||
});
|
||||
|
||||
describe('GET: `items`', () => {
|
||||
it('Should response unauthorized access in case the user not authenticated.', async () => {
|
||||
const res = await request()
|
||||
.get('/api/items')
|
||||
.send();
|
||||
|
||||
expect(res.status).equals(401);
|
||||
expect(res.body.message).equals('Unauthorized');
|
||||
});
|
||||
|
||||
it('Should retrieve items list with associated accounts.', async () => {
|
||||
await tenantFactory.create('resource', { name: 'items' });
|
||||
await tenantFactory.create('item');
|
||||
|
||||
const res = await request()
|
||||
.get('/api/items')
|
||||
.set('x-access-token', loginRes.body.token)
|
||||
.set('organization-id', tenantWebsite.organizationId)
|
||||
.send();
|
||||
|
||||
expect(res.status).equals(200);
|
||||
|
||||
expect(res.body.items).to.be.a('object');
|
||||
expect(res.body.items.results).to.be.a('array');
|
||||
expect(res.body.items.results.length).equals(1);
|
||||
|
||||
expect(res.body.items.results[0].cost_account).to.be.an('object');
|
||||
expect(res.body.items.results[0].sell_account).to.be.an('object');
|
||||
expect(res.body.items.results[0].inventory_account).to.be.an('object');
|
||||
expect(res.body.items.results[0].category).to.be.an('object');
|
||||
});
|
||||
|
||||
it('Should retrieve ordered items based on the given `column_sort_order` and `sort_order` query.', async () => {
|
||||
await tenantFactory.create('item', { name: 'ahmed' });
|
||||
await tenantFactory.create('item', { name: 'mohamed' });
|
||||
|
||||
const res = await request()
|
||||
.get('/api/items')
|
||||
.set('x-access-token', loginRes.body.token)
|
||||
.set('organization-id', tenantWebsite.organizationId)
|
||||
.query({
|
||||
column_sort_order: 'name',
|
||||
sort_order: 'desc',
|
||||
})
|
||||
.send();
|
||||
|
||||
expect(res.body.items.results.length).equals(2);
|
||||
expect(res.body.items.results[0].name).equals('mohamed');
|
||||
expect(res.body.items.results[1].name).equals('ahmed');
|
||||
});
|
||||
|
||||
it('Should retrieve pagination meta of items list.', async () => {
|
||||
await tenantFactory.create('resource', { name: 'items' });
|
||||
|
||||
const res = await request()
|
||||
.get('/api/items')
|
||||
.set('x-access-token', loginRes.body.token)
|
||||
.set('organization-id', tenantWebsite.organizationId)
|
||||
.send();
|
||||
|
||||
expect(res.body.items.results).to.be.a('array');
|
||||
expect(res.body.items.results.length).equals(0);
|
||||
expect(res.body.items.pagination).to.be.a('object');
|
||||
expect(res.body.items.pagination.total).to.be.a('number');
|
||||
expect(res.body.items.pagination.total).equals(0)
|
||||
});
|
||||
|
||||
it('Should retrieve filtered items based on custom view conditions.', async () => {
|
||||
const item1 = await tenantFactory.create('item', { type: 'service' });
|
||||
const item2 = await tenantFactory.create('item', { type: 'service' });
|
||||
const item3 = await tenantFactory.create('item', { type: 'inventory' });
|
||||
const item4 = await tenantFactory.create('item', { type: 'inventory' });
|
||||
|
||||
const view = await tenantFactory.create('view', {
|
||||
name: 'Items Inventory',
|
||||
resource_id: 2,
|
||||
roles_logic_expression: '1',
|
||||
});
|
||||
const viewCondition = await tenantFactory.create('view_role', {
|
||||
view_id: view.id,
|
||||
index: 1,
|
||||
field_id: 12,
|
||||
value: 'inventory',
|
||||
comparator: 'equals',
|
||||
});
|
||||
const res = await request()
|
||||
.get('/api/items')
|
||||
.set('x-access-token', loginRes.body.token)
|
||||
.set('organization-id', tenantWebsite.organizationId)
|
||||
.query({
|
||||
custom_view_id: view.id,
|
||||
})
|
||||
.send();
|
||||
|
||||
expect(res.body.customViewId).equals(view.id);
|
||||
expect(res.body.viewColumns).to.be.a('array');
|
||||
expect(res.body.viewConditions).to.be.a('array');
|
||||
expect(res.body.items.results.length).equals(2);
|
||||
expect(res.body.items.results[0].type).equals('inventory');
|
||||
expect(res.body.items.results[1].type).equals('inventory');
|
||||
});
|
||||
|
||||
it('Should retrieve filtered items based on filtering conditions.', async () => {
|
||||
const item1 = await tenantFactory.create('item', { type: 'service' });
|
||||
const item2 = await tenantFactory.create('item', { type: 'service', name: 'target' });
|
||||
const item3 = await tenantFactory.create('item', { type: 'inventory' });
|
||||
const item4 = await tenantFactory.create('item', { type: 'inventory' });
|
||||
|
||||
const res = await request()
|
||||
.get('/api/items')
|
||||
.set('x-access-token', loginRes.body.token)
|
||||
.set('organization-id', tenantWebsite.organizationId)
|
||||
.query({
|
||||
stringified_filter_roles: JSON.stringify([
|
||||
{
|
||||
condition: 'AND',
|
||||
field_key: 'type',
|
||||
comparator: 'equals',
|
||||
value: 'inventory',
|
||||
},
|
||||
{
|
||||
condition: 'OR',
|
||||
field_key: 'name',
|
||||
comparator: 'equals',
|
||||
value: 'target',
|
||||
},
|
||||
]),
|
||||
})
|
||||
.send();
|
||||
|
||||
expect(res.body.items.results.length).equals(3);
|
||||
expect(res.body.items.results[0].name).equals('target');
|
||||
expect(res.body.items.results[1].type).equals('inventory');
|
||||
expect(res.body.items.results[2].type).equals('inventory');
|
||||
});
|
||||
});
|
||||
});
|
||||
311
packages/server/tests/routes/itemsCategories.test.js
Normal file
311
packages/server/tests/routes/itemsCategories.test.js
Normal file
@@ -0,0 +1,311 @@
|
||||
import {
|
||||
request,
|
||||
expect,
|
||||
} from '~/testInit';
|
||||
import ItemCategory from 'models/ItemCategory';
|
||||
import {
|
||||
tenantWebsite,
|
||||
tenantFactory,
|
||||
loginRes
|
||||
} from '~/dbInit';
|
||||
|
||||
describe('routes: /item_categories/', () => {
|
||||
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 () => {
|
||||
const res = await request()
|
||||
.post('/api/item_categories')
|
||||
.set('x-access-token', loginRes.body.token)
|
||||
.set('organization-id', tenantWebsite.organizationId)
|
||||
.send();
|
||||
|
||||
expect(res.status).equals(422);
|
||||
expect(res.body.code).equals('validation_error');
|
||||
});
|
||||
|
||||
it('Should `parent_category_id` be exist in the storage.', async () => {
|
||||
const res = await request()
|
||||
.post('/api/item_categories')
|
||||
.set('x-access-token', loginRes.body.token)
|
||||
.set('organization-id', tenantWebsite.organizationId)
|
||||
.send({
|
||||
name: 'Clothes',
|
||||
parent_category_id: 10,
|
||||
});
|
||||
|
||||
expect(res.status).equals(404);
|
||||
expect(res.body.errors).include.something.that.deep.equals({
|
||||
type: 'PARENT_CATEGORY_NOT_FOUND', code: 100,
|
||||
});
|
||||
});
|
||||
|
||||
it('Should response success with correct form data.', async () => {
|
||||
const res = await request()
|
||||
.post('/api/item_categories')
|
||||
.set('x-access-token', loginRes.body.token)
|
||||
.set('organization-id', tenantWebsite.organizationId)
|
||||
.send({
|
||||
name: 'Clothes',
|
||||
description: 'Here is description',
|
||||
});
|
||||
|
||||
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 () => {
|
||||
const category = await tenantFactory.create('item_category');
|
||||
const res = await request()
|
||||
.post('/api/item_categories')
|
||||
.set('x-access-token', loginRes.body.token)
|
||||
.set('organization-id', tenantWebsite.organizationId)
|
||||
.send({
|
||||
name: 'Clothes',
|
||||
description: 'Here is description',
|
||||
parent_category_id: category.id,
|
||||
});
|
||||
|
||||
expect(res.status).equals(200);
|
||||
|
||||
const storedCategory = await ItemCategory.tenant().query()
|
||||
.where('id', res.body.category.id)
|
||||
.first();
|
||||
|
||||
expect(storedCategory.name).equals('Clothes');
|
||||
expect(storedCategory.description).equals('Here is description');
|
||||
expect(storedCategory.parentCategoryId).equals(category.id);
|
||||
expect(storedCategory.userId).to.be.a('number');
|
||||
});
|
||||
});
|
||||
|
||||
describe('POST `/items_category/{id}`', () => {
|
||||
it('Should not update a item category if the user was not authorized.', async () => {
|
||||
const category = await tenantFactory.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 () => {
|
||||
const category = await tenantFactory.create('item_category');
|
||||
const res = await request()
|
||||
.post(`/api/item_categories/${category.id}`)
|
||||
.set('x-access-token', loginRes.body.token)
|
||||
.set('organization-id', tenantWebsite.organizationId)
|
||||
.send();
|
||||
|
||||
expect(res.status).equals(422);
|
||||
expect(res.body.code).equals('validation_error');
|
||||
});
|
||||
|
||||
it('Should `parent_category_id` be exist in the storage.', async () => {
|
||||
const category = await tenantFactory.create('item_category');
|
||||
const res = await request()
|
||||
.post(`/api/item_categories/${category.id}`)
|
||||
.set('x-access-token', loginRes.body.token)
|
||||
.set('organization-id', tenantWebsite.organizationId)
|
||||
.send({
|
||||
name: 'Name',
|
||||
parent_category_id: 10,
|
||||
});
|
||||
|
||||
expect(res.status).equals(404);
|
||||
expect(res.body.errors).include.something.that.deep.equals({
|
||||
type: 'PARENT_CATEGORY_NOT_FOUND', code: 100,
|
||||
});
|
||||
});
|
||||
|
||||
it('Should response success with correct data format.', async () => {
|
||||
const category = await tenantFactory.create('item_category');
|
||||
const anotherCategory = await tenantFactory.create('item_category');
|
||||
|
||||
const res = await request()
|
||||
.post(`/api/item_categories/${category.id}`)
|
||||
.set('x-access-token', loginRes.body.token)
|
||||
.set('organization-id', tenantWebsite.organizationId)
|
||||
.send({
|
||||
name: 'Name',
|
||||
parent_category_id: anotherCategory.id,
|
||||
description: 'updated description',
|
||||
});
|
||||
|
||||
expect(res.status).equals(200);
|
||||
});
|
||||
|
||||
it('Should item category data be update in the storage.', async () => {
|
||||
const category = await tenantFactory.create('item_category');
|
||||
const anotherCategory = await tenantFactory.create('item_category');
|
||||
|
||||
const res = await request()
|
||||
.post(`/api/item_categories/${category.id}`)
|
||||
.set('x-access-token', loginRes.body.token)
|
||||
.set('organization-id', tenantWebsite.organizationId)
|
||||
.send({
|
||||
name: 'Name',
|
||||
parent_category_id: anotherCategory.id,
|
||||
description: 'updated description',
|
||||
});
|
||||
|
||||
const storedCategory = await ItemCategory.tenant().query()
|
||||
.where('id', res.body.id)
|
||||
.first();
|
||||
|
||||
expect(storedCategory.name).equals('Name');
|
||||
expect(storedCategory.description).equals('updated description');
|
||||
expect(storedCategory.parentCategoryId).equals(anotherCategory.id);
|
||||
});
|
||||
});
|
||||
|
||||
describe('DELETE: `/items_categories`', async () => {
|
||||
it('Should not delete the give item category if the user was not authorized.', async () => {
|
||||
const category = await tenantFactory.create('item_category');
|
||||
|
||||
const res = await request()
|
||||
.delete(`/api/item_categories/${category.id}`)
|
||||
.set('organization-id', tenantWebsite.organizationId)
|
||||
.send();
|
||||
|
||||
expect(res.status).equals(401);
|
||||
expect(res.body.message).equals('Unauthorized');
|
||||
});
|
||||
|
||||
it('Should not delete if the item category was not found.', async () => {
|
||||
const res = await request()
|
||||
.delete('/api/item_categories/10')
|
||||
.set('x-access-token', loginRes.body.token)
|
||||
.set('organization-id', tenantWebsite.organizationId)
|
||||
.send();
|
||||
|
||||
expect(res.status).equals(404);
|
||||
});
|
||||
|
||||
it('Should response success after delete the given item category.', async () => {
|
||||
const category = await tenantFactory.create('item_category');
|
||||
const res = await request()
|
||||
.delete(`/api/item_categories/${category.id}`)
|
||||
.set('x-access-token', loginRes.body.token)
|
||||
.set('organization-id', tenantWebsite.organizationId)
|
||||
.send();
|
||||
|
||||
expect(res.status).equals(200);
|
||||
});
|
||||
|
||||
it('Should delete the give item category from the storage.', async () => {
|
||||
const category = await tenantFactory.create('item_category');
|
||||
const res = await request()
|
||||
.delete(`/api/item_categories/${category.id}`)
|
||||
.set('x-access-token', loginRes.body.token)
|
||||
.set('organization-id', tenantWebsite.organizationId)
|
||||
.send();
|
||||
|
||||
const categories = await ItemCategory.tenant().query()
|
||||
.where('id', category.id);
|
||||
|
||||
expect(categories).to.have.lengthOf(0);
|
||||
});
|
||||
});
|
||||
|
||||
describe('GET: `/item_categories`', () => {
|
||||
|
||||
it('Should retrieve list of item categories.', async () => {
|
||||
const category1 = await tenantFactory.create('item_category');
|
||||
const category2 = await tenantFactory.create('item_category', { parent_category_id: category1.id });
|
||||
|
||||
const res = await request()
|
||||
.get('/api/item_categories')
|
||||
.set('x-access-token', loginRes.body.token)
|
||||
.set('organization-id', tenantWebsite.organizationId)
|
||||
.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');
|
||||
});
|
||||
|
||||
|
||||
it('Should retrieve of related items.', async () => {
|
||||
const category1 = await tenantFactory.create('item_category');
|
||||
const category2 = await tenantFactory.create('item_category', { parent_category_id: category1.id });
|
||||
|
||||
await tenantFactory.create('item', { category_id: category1.id });
|
||||
|
||||
const res = await request()
|
||||
.get('/api/item_categories')
|
||||
.set('x-access-token', loginRes.body.token)
|
||||
.set('organization-id', tenantWebsite.organizationId)
|
||||
.send();
|
||||
|
||||
expect(res.body.categories[0].count).to.be.a('number');
|
||||
expect(res.body.categories[0].count).equals(1);
|
||||
});
|
||||
});
|
||||
|
||||
describe('GET `/items_category/{id}', () => {
|
||||
it('Should response not found with incorrect item category ID.', () => {
|
||||
|
||||
});
|
||||
|
||||
it('Should response success with exist item category.', () => {
|
||||
|
||||
});
|
||||
|
||||
it('Should response data of item category.', () => {
|
||||
|
||||
});
|
||||
});
|
||||
|
||||
describe('DELETE: `/items_cateogires`', () => {
|
||||
it('Should response bad request in case one of item categories id not exists in the storage.', async () => {
|
||||
const res = await request()
|
||||
.delete('/api/item_categories/bulk')
|
||||
.set('x-access-token', loginRes.body.token)
|
||||
.set('organization-id', tenantWebsite.organizationId)
|
||||
.query({
|
||||
ids: [1020, 2020],
|
||||
})
|
||||
.send();
|
||||
|
||||
expect(res.status).equals(400);
|
||||
expect(res.body.errors).include.something.deep.equals({
|
||||
type: 'ITEM.CATEGORIES.IDS.NOT.FOUND', code: 200
|
||||
});
|
||||
});
|
||||
|
||||
it('Should delete the given item categories.', async () => {
|
||||
const itemCategory = await tenantFactory.create('item_category');
|
||||
const itemCategory2 = await tenantFactory.create('item_category');
|
||||
|
||||
const res = await request()
|
||||
.delete('/api/item_categories/bulk')
|
||||
.set('x-access-token', loginRes.body.token)
|
||||
.set('organization-id', tenantWebsite.organizationId)
|
||||
.query({
|
||||
ids: [itemCategory.id, itemCategory2.id],
|
||||
})
|
||||
.send();
|
||||
|
||||
const deleteItemCategories = await ItemCategory.tenant().query()
|
||||
.whereIn('id', [itemCategory.id, itemCategory2.id]);
|
||||
|
||||
expect(deleteItemCategories.length).equals(0);
|
||||
});
|
||||
});
|
||||
});
|
||||
120
packages/server/tests/routes/options.test.js
Normal file
120
packages/server/tests/routes/options.test.js
Normal file
@@ -0,0 +1,120 @@
|
||||
import {
|
||||
request,
|
||||
expect,
|
||||
} from '~/testInit';
|
||||
import Option from 'models/Option';
|
||||
import {
|
||||
tenantWebsite,
|
||||
tenantFactory,
|
||||
loginRes
|
||||
} from '~/dbInit';
|
||||
|
||||
|
||||
describe('routes: `/options`', () => {
|
||||
describe('POST: `/options/`', () => {
|
||||
it('Should response unauthorized if the user was not logged in.', async () => {
|
||||
const res = await request()
|
||||
.post('/api/options')
|
||||
.send();
|
||||
|
||||
expect(res.status).equals(401);
|
||||
expect(res.body.message).equals('Unauthorized');
|
||||
});
|
||||
|
||||
it('Should response the options key and group is not defined.', async () => {
|
||||
const res = await request()
|
||||
.post('/api/options')
|
||||
.set('x-access-token', loginRes.body.token)
|
||||
.set('organization-id', tenantWebsite.organizationId)
|
||||
.send({
|
||||
options: [
|
||||
{
|
||||
key: 'key',
|
||||
value: 'hello world',
|
||||
group: 'group',
|
||||
},
|
||||
],
|
||||
});
|
||||
|
||||
expect(res.status).equals(400);
|
||||
expect(res.body.errors).include.something.that.deep.equals({
|
||||
type: 'OPTIONS.KEY.NOT.DEFINED',
|
||||
code: 200,
|
||||
keys: [
|
||||
{ key: 'key', group: 'group' },
|
||||
],
|
||||
});
|
||||
});
|
||||
|
||||
it('Should save options to the storage.', async () => {
|
||||
const res = await request()
|
||||
.post('/api/options')
|
||||
.set('x-access-token', loginRes.body.token)
|
||||
.set('organization-id', tenantWebsite.organizationId)
|
||||
.send({
|
||||
options: [{
|
||||
key: 'name',
|
||||
group: 'organization',
|
||||
value: 'hello world',
|
||||
}],
|
||||
});
|
||||
expect(res.status).equals(200);
|
||||
|
||||
const storedOptions = await Option.tenant().query()
|
||||
.where('group', 'organization')
|
||||
.where('key', 'name');
|
||||
|
||||
expect(storedOptions.metadata.length).equals(1);
|
||||
});
|
||||
});
|
||||
|
||||
describe('GET: `/options`', () => {
|
||||
it('Should response unauthorized if the user was not unauthorized.', async () => {
|
||||
const res = await request()
|
||||
.get('/api/options')
|
||||
.query({
|
||||
group: 'organization',
|
||||
})
|
||||
.send();
|
||||
|
||||
expect(res.status).equals(401);
|
||||
expect(res.body.message).equals('Unauthorized');
|
||||
});
|
||||
|
||||
it('Should retrieve options the associated to the given group.', async () => {
|
||||
await tenantFactory.create('option', { group: 'organization', key: 'name' });
|
||||
await tenantFactory.create('option', { group: 'organization', key: 'base_currency' });
|
||||
|
||||
const res = await request()
|
||||
.get('/api/options')
|
||||
.set('x-access-token', loginRes.body.token)
|
||||
.set('organization-id', tenantWebsite.organizationId)
|
||||
.query({
|
||||
group: 'organization',
|
||||
})
|
||||
.send();
|
||||
|
||||
expect(res.status).equals(200);
|
||||
expect(res.body.options).is.an('array');
|
||||
expect(res.body.options.length).equals(2);
|
||||
});
|
||||
|
||||
it('Should retrieve options that associated to the given key.', async () => {
|
||||
await tenantFactory.create('option', { group: 'organization', key: 'base_currency' });
|
||||
await tenantFactory.create('option', { group: 'organization', key: 'name' });
|
||||
|
||||
const res = await request()
|
||||
.get('/api/options')
|
||||
.set('x-access-token', loginRes.body.token)
|
||||
.set('organization-id', tenantWebsite.organizationId)
|
||||
.query({
|
||||
key: 'name',
|
||||
})
|
||||
.send();
|
||||
|
||||
expect(res.status).equals(200);
|
||||
expect(res.body.options).is.an('array');
|
||||
expect(res.body.options.length).equals(1);
|
||||
});
|
||||
});
|
||||
});
|
||||
0
packages/server/tests/routes/payable_aging.test.js
Normal file
0
packages/server/tests/routes/payable_aging.test.js
Normal file
274
packages/server/tests/routes/payment_receives.test.js
Normal file
274
packages/server/tests/routes/payment_receives.test.js
Normal file
@@ -0,0 +1,274 @@
|
||||
import {
|
||||
request,
|
||||
expect,
|
||||
} from '~/testInit';
|
||||
import {
|
||||
tenantWebsite,
|
||||
tenantFactory,
|
||||
loginRes
|
||||
} from '~/dbInit';
|
||||
import {
|
||||
PaymentReceive,
|
||||
PaymentReceiveEntry,
|
||||
} from 'models';
|
||||
|
||||
describe('route: `/sales/payment_receives`', () => {
|
||||
describe('POST: `/sales/payment_receives`', () => {
|
||||
it('Should `customer_id` be required.', async () => {
|
||||
const res = await request()
|
||||
.post('/api/sales/payment_receives')
|
||||
.set('x-access-token', loginRes.body.token)
|
||||
.set('organization-id', tenantWebsite.organizationId)
|
||||
.send();
|
||||
|
||||
expect(res.status).equals(422);
|
||||
expect(res.body.errors).include.something.deep.equals({
|
||||
msg: 'Invalid value',
|
||||
param: 'customer_id',
|
||||
location: 'body',
|
||||
});
|
||||
});
|
||||
|
||||
it('Should `payment_date` be required.', async () => {
|
||||
const res = await request()
|
||||
.post('/api/sales/payment_receives')
|
||||
.set('x-access-token', loginRes.body.token)
|
||||
.set('organization-id', tenantWebsite.organizationId)
|
||||
.send();
|
||||
|
||||
expect(res.status).equals(422);
|
||||
expect(res.body.errors).include.something.deep.equals({
|
||||
msg: 'Invalid value',
|
||||
param: 'payment_date',
|
||||
location: 'body',
|
||||
});
|
||||
});
|
||||
|
||||
it('Should `deposit_account_id` be required.', async () => {
|
||||
const res = await request()
|
||||
.post('/api/sales/payment_receives')
|
||||
.set('x-access-token', loginRes.body.token)
|
||||
.set('organization-id', tenantWebsite.organizationId)
|
||||
.send();
|
||||
|
||||
expect(res.status).equals(422);
|
||||
expect(res.body.errors).include.something.deep.equals({
|
||||
msg: 'Invalid value',
|
||||
param: 'deposit_account_id',
|
||||
location: 'body',
|
||||
});
|
||||
});
|
||||
|
||||
it('Should `payment_receive_no` be required.', async () => {
|
||||
const res = await request()
|
||||
.post('/api/sales/payment_receives')
|
||||
.set('x-access-token', loginRes.body.token)
|
||||
.set('organization-id', tenantWebsite.organizationId)
|
||||
.send();
|
||||
|
||||
expect(res.status).equals(422);
|
||||
expect(res.body.errors).include.something.deep.equals({
|
||||
msg: 'Invalid value',
|
||||
param: 'payment_receive_no',
|
||||
location: 'body',
|
||||
});
|
||||
});
|
||||
|
||||
it('Should invoices IDs be required.', async () => {
|
||||
const res = await request()
|
||||
.post('/api/sales/payment_receives')
|
||||
.set('x-access-token', loginRes.body.token)
|
||||
.set('organization-id', tenantWebsite.organizationId)
|
||||
.send();
|
||||
|
||||
expect(res.status).equals(422);
|
||||
expect(res.body.errors).include.something.deep.equals({
|
||||
msg: 'Invalid value',
|
||||
param: 'payment_receive_no',
|
||||
location: 'body',
|
||||
});
|
||||
});
|
||||
|
||||
it('Should `customer_id` be exists on the storage.', async () => {
|
||||
const res = await request()
|
||||
.post('/api/sales/payment_receives')
|
||||
.set('x-access-token', loginRes.body.token)
|
||||
.set('organization-id', tenantWebsite.organizationId)
|
||||
.send({
|
||||
customer_id: 123,
|
||||
payment_date: '2020-02-02',
|
||||
reference_no: '123',
|
||||
deposit_account_id: 100,
|
||||
payment_receive_no: '123',
|
||||
entries: [
|
||||
{
|
||||
invoice_id: 1,
|
||||
payment_amount: 1000,
|
||||
}
|
||||
],
|
||||
});
|
||||
expect(res.status).equals(400);
|
||||
expect(res.body.errors).include.something.deep.equals({
|
||||
type: 'CUSTOMER.ID.NOT.EXISTS', code: 200,
|
||||
});
|
||||
});
|
||||
|
||||
it('Should `deposit_account_id` be exists on the storage.', async () => {
|
||||
const customer = await tenantFactory.create('customer');
|
||||
const res = await request()
|
||||
.post('/api/sales/payment_receives')
|
||||
.set('x-access-token', loginRes.body.token)
|
||||
.set('organization-id', tenantWebsite.organizationId)
|
||||
.send({
|
||||
customer_id: customer.id,
|
||||
payment_date: '2020-02-02',
|
||||
reference_no: '123',
|
||||
deposit_account_id: 10000,
|
||||
payment_receive_no: '123',
|
||||
entries: [
|
||||
{
|
||||
invoice_id: 1,
|
||||
payment_amount: 1000,
|
||||
}
|
||||
],
|
||||
});
|
||||
|
||||
expect(res.status).equals(400);
|
||||
expect(res.body.errors).include.something.deep.equals({
|
||||
type: 'DEPOSIT.ACCOUNT.NOT.EXISTS', code: 300,
|
||||
});
|
||||
});
|
||||
|
||||
it('Should invoices IDs be exist on the storage.', async () => {
|
||||
const customer = await tenantFactory.create('customer');
|
||||
const account = await tenantFactory.create('account');
|
||||
|
||||
const res = await request()
|
||||
.post('/api/sales/payment_receives')
|
||||
.set('x-access-token', loginRes.body.token)
|
||||
.set('organization-id', tenantWebsite.organizationId)
|
||||
.send({
|
||||
customer_id: customer.id,
|
||||
payment_date: '2020-02-02',
|
||||
reference_no: '123',
|
||||
deposit_account_id: account.id,
|
||||
payment_receive_no: '123',
|
||||
entries: [
|
||||
{
|
||||
invoice_id: 1,
|
||||
payment_amount: 1000,
|
||||
}
|
||||
],
|
||||
});
|
||||
|
||||
expect(res.status).equals(400);
|
||||
expect(res.body.errors).include.something.deep.equals({
|
||||
type: 'DEPOSIT.ACCOUNT.NOT.EXISTS', code: 300,
|
||||
});
|
||||
});
|
||||
|
||||
it('Should payment receive number be unique on the storage.', async () => {
|
||||
const customer = await tenantFactory.create('customer');
|
||||
const account = await tenantFactory.create('account');
|
||||
const paymentReceive = await tenantFactory.create('payment_receive', {
|
||||
payment_receive_no: '123',
|
||||
});
|
||||
|
||||
const res = await request()
|
||||
.post('/api/sales/payment_receives')
|
||||
.set('x-access-token', loginRes.body.token)
|
||||
.set('organization-id', tenantWebsite.organizationId)
|
||||
.send({
|
||||
customer_id: customer.id,
|
||||
payment_date: '2020-02-02',
|
||||
reference_no: '123',
|
||||
deposit_account_id: account.id,
|
||||
payment_receive_no: '123',
|
||||
entries: [
|
||||
{
|
||||
invoice_id: 1,
|
||||
payment_amount: 1000,
|
||||
}
|
||||
],
|
||||
});
|
||||
expect(res.status).equals(400);
|
||||
expect(res.body.errors).include.something.deep.equals({
|
||||
type: 'PAYMENT.RECEIVE.NUMBER.EXISTS', code: 400,
|
||||
});
|
||||
});
|
||||
|
||||
it('Should store the payment receive details with associated entries.', async () => {
|
||||
const customer = await tenantFactory.create('customer');
|
||||
const account = await tenantFactory.create('account');
|
||||
const invoice = await tenantFactory.create('sale_invoice');
|
||||
|
||||
const res = await request()
|
||||
.post('/api/sales/payment_receives')
|
||||
.set('x-access-token', loginRes.body.token)
|
||||
.set('organization-id', tenantWebsite.organizationId)
|
||||
.send({
|
||||
customer_id: customer.id,
|
||||
payment_date: '2020-02-02',
|
||||
reference_no: '123',
|
||||
deposit_account_id: account.id,
|
||||
payment_receive_no: '123',
|
||||
entries: [
|
||||
{
|
||||
invoice_id: invoice.id,
|
||||
payment_amount: 1000,
|
||||
}
|
||||
],
|
||||
});
|
||||
|
||||
const storedPaymentReceived = await PaymentReceive.tenant().query().where('id', res.body.id).first();
|
||||
|
||||
expect(res.status).equals(200);
|
||||
expect(storedPaymentReceived.customerId).equals(customer.id)
|
||||
expect(storedPaymentReceived.referenceNo).equals('123');
|
||||
expect(storedPaymentReceived.paymentReceiveNo).equals('123');
|
||||
});
|
||||
});
|
||||
|
||||
describe('POST: `/sales/payment_receives/:id`', () => {
|
||||
it('Should update the payment receive details with associated entries.', async () => {
|
||||
const paymentReceive = await tenantFactory.create('payment_receive');
|
||||
const customer = await tenantFactory.create('customer');
|
||||
const account = await tenantFactory.create('account');
|
||||
const invoice = await tenantFactory.create('sale_invoice');
|
||||
|
||||
const res = await request()
|
||||
.post(`/api/sales/payment_receives/${paymentReceive.id}`)
|
||||
.set('x-access-token', loginRes.body.token)
|
||||
.set('organization-id', tenantWebsite.organizationId)
|
||||
.send({
|
||||
customer_id: customer.id,
|
||||
payment_date: '2020-02-02',
|
||||
reference_no: '123',
|
||||
deposit_account_id: account.id,
|
||||
payment_receive_no: '123',
|
||||
entries: [
|
||||
{
|
||||
invoice_id: invoice.id,
|
||||
payment_amount: 1000,
|
||||
}
|
||||
],
|
||||
});
|
||||
expect(res.status).equals(200);
|
||||
});
|
||||
});
|
||||
|
||||
describe('DELETE: `/sales/payment_receives/:id`', () => {
|
||||
it('Should response the given payment receive is not exists on the storage.', async () => {
|
||||
const res = await request()
|
||||
.delete(`/api/sales/payment_receives/123`)
|
||||
.set('x-access-token', loginRes.body.token)
|
||||
.set('organization-id', tenantWebsite.organizationId)
|
||||
.send();
|
||||
|
||||
expect(res.status).equals(400);
|
||||
expect(res.body.errors).include.something.deep.equals({
|
||||
type: 'PAYMENT.RECEIVE.NO.EXISTS', code: 600,
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
234
packages/server/tests/routes/receivable_aging.test.js
Normal file
234
packages/server/tests/routes/receivable_aging.test.js
Normal file
@@ -0,0 +1,234 @@
|
||||
import {
|
||||
request,
|
||||
expect,
|
||||
} from '~/testInit';
|
||||
import Item from 'models/Item';
|
||||
import {
|
||||
tenantWebsite,
|
||||
tenantFactory,
|
||||
loginRes
|
||||
} from '~/dbInit';
|
||||
|
||||
|
||||
describe('routes: `/financial_statements/receivable_aging_summary`', () => {
|
||||
|
||||
it('Should retrieve customers list.', async () => {
|
||||
const customer1 = await tenantFactory.create('customer', { display_name: 'Ahmed' });
|
||||
const customer2 = await tenantFactory.create('customer', { display_name: 'Mohamed' });
|
||||
|
||||
const res = await request()
|
||||
.get('/api/financial_statements/receivable_aging_summary')
|
||||
.set('x-access-token', loginRes.body.token)
|
||||
.set('organization-id', tenantWebsite.organizationId)
|
||||
.send();
|
||||
|
||||
expect(res.status).equals(200);
|
||||
|
||||
expect(res.body.aging.customers).is.an('array');
|
||||
expect(res.body.aging.customers.length).equals(2);
|
||||
|
||||
expect(res.body.aging.customers[0].customer_name).equals('Ahmed');
|
||||
expect(res.body.aging.customers[1].customer_name).equals('Mohamed');
|
||||
});
|
||||
|
||||
it('Should respon se the customers ids not found.', async () => {
|
||||
const res = await request()
|
||||
.get('/api/financial_statements/receivable_aging_summary')
|
||||
.set('x-access-token', loginRes.body.token)
|
||||
.set('organization-id', tenantWebsite.organizationId)
|
||||
.query({
|
||||
customer_ids: [3213, 3322],
|
||||
})
|
||||
.send();
|
||||
|
||||
expect(res.status).equals(400);
|
||||
expect(res.body.errors).include.something.deep.equals({
|
||||
type: 'CUSTOMERS.IDS.NOT.FOUND', code: 300, ids: [3213, 3322]
|
||||
})
|
||||
});
|
||||
|
||||
it('Should retrieve aging report columns.', async () => {
|
||||
const customer1 = await tenantFactory.create('customer', { display_name: 'Ahmed' });
|
||||
const customer2 = await tenantFactory.create('customer', { display_name: 'Mohamed' });
|
||||
|
||||
const res = await request()
|
||||
.get('/api/financial_statements/receivable_aging_summary')
|
||||
.set('x-access-token', loginRes.body.token)
|
||||
.set('organization-id', tenantWebsite.organizationId)
|
||||
.query({
|
||||
as_date: '2020-06-01',
|
||||
aging_days_before: 30,
|
||||
aging_periods: 6,
|
||||
})
|
||||
.send();
|
||||
|
||||
expect(res.body.columns).length(6);
|
||||
expect(res.body.columns[0].before_days).equals(0);
|
||||
expect(res.body.columns[0].to_days).equals(30);
|
||||
|
||||
expect(res.body.columns[1].before_days).equals(31);
|
||||
expect(res.body.columns[1].to_days).equals(60);
|
||||
|
||||
expect(res.body.columns[2].before_days).equals(61);
|
||||
expect(res.body.columns[2].to_days).equals(90);
|
||||
|
||||
expect(res.body.columns[3].before_days).equals(91);
|
||||
expect(res.body.columns[3].to_days).equals(120);
|
||||
|
||||
expect(res.body.columns[4].before_days).equals(121);
|
||||
expect(res.body.columns[4].to_days).equals(150);
|
||||
|
||||
expect(res.body.columns[5].before_days).equals(151);
|
||||
expect(res.body.columns[5].to_days).equals(null);
|
||||
});
|
||||
|
||||
it('Should retrieve receivable total of the customers.', async () => {
|
||||
const customer1 = await tenantFactory.create('customer', { display_name: 'Ahmed' });
|
||||
const customer2 = await tenantFactory.create('customer', { display_name: 'Mohamed' });
|
||||
|
||||
await tenantFactory.create('account_transaction', {
|
||||
contact_id: customer1.id,
|
||||
contact_type: 'customer',
|
||||
debit: 10000,
|
||||
credit: 0,
|
||||
account_id: 10,
|
||||
date: '2020-01-01',
|
||||
});
|
||||
|
||||
await tenantFactory.create('account_transaction', {
|
||||
contact_id: customer1.id,
|
||||
contact_type: 'customer',
|
||||
debit: 1000,
|
||||
credit: 0,
|
||||
account_id: 10,
|
||||
date: '2020-03-15',
|
||||
});
|
||||
|
||||
// Receive
|
||||
await tenantFactory.create('account_transaction', {
|
||||
contact_id: customer1.id,
|
||||
contact_type: 'customer',
|
||||
debit: 0,
|
||||
credit: 8000,
|
||||
account_id: 10,
|
||||
date: '2020-06-01',
|
||||
});
|
||||
|
||||
const res = await request()
|
||||
.get('/api/financial_statements/receivable_aging_summary')
|
||||
.set('x-access-token', loginRes.body.token)
|
||||
.set('organization-id', tenantWebsite.organizationId)
|
||||
.query({
|
||||
as_date: '2020-06-01',
|
||||
aging_days_before: 30,
|
||||
aging_periods: 6,
|
||||
})
|
||||
.send();
|
||||
|
||||
expect(res.body.aging.total[0].total).equals(0);
|
||||
expect(res.body.aging.total[1].total).equals(0);
|
||||
expect(res.body.aging.total[2].total).equals(1000);
|
||||
expect(res.body.aging.total[3].total).equals(0);
|
||||
expect(res.body.aging.total[4].total).equals(0);
|
||||
expect(res.body.aging.total[5].total).equals(2000);
|
||||
});
|
||||
|
||||
|
||||
it('Should retrieve customer aging.', async () => {
|
||||
const customer1 = await tenantFactory.create('customer', { display_name: 'Ahmed' });
|
||||
const customer2 = await tenantFactory.create('customer', { display_name: 'Mohamed' });
|
||||
|
||||
await tenantFactory.create('account_transaction', {
|
||||
contact_id: customer1.id,
|
||||
contact_type: 'customer',
|
||||
debit: 10000,
|
||||
credit: 0,
|
||||
account_id: 10,
|
||||
date: '2020-01-14',
|
||||
});
|
||||
|
||||
await tenantFactory.create('account_transaction', {
|
||||
contact_id: customer1.id,
|
||||
contact_type: 'customer',
|
||||
debit: 1000,
|
||||
credit: 0,
|
||||
account_id: 10,
|
||||
date: '2020-03-15',
|
||||
});
|
||||
|
||||
// Receive
|
||||
await tenantFactory.create('account_transaction', {
|
||||
contact_id: customer1.id,
|
||||
contact_type: 'customer',
|
||||
debit: 0,
|
||||
credit: 8000,
|
||||
account_id: 10,
|
||||
date: '2020-06-01',
|
||||
});
|
||||
|
||||
const res = await request()
|
||||
.get('/api/financial_statements/receivable_aging_summary')
|
||||
.set('x-access-token', loginRes.body.token)
|
||||
.set('organization-id', tenantWebsite.organizationId)
|
||||
.query({
|
||||
as_date: '2020-06-01',
|
||||
aging_days_before: 30,
|
||||
aging_periods: 6,
|
||||
})
|
||||
.send();
|
||||
|
||||
expect(res.body.aging.customers[0].aging[0].total).equals(0);
|
||||
expect(res.body.aging.customers[0].aging[1].total).equals(0);
|
||||
expect(res.body.aging.customers[0].aging[2].total).equals(1000);
|
||||
expect(res.body.aging.customers[0].aging[3].total).equals(0);
|
||||
expect(res.body.aging.customers[0].aging[4].total).equals(2000);
|
||||
expect(res.body.aging.customers[0].aging[5].total).equals(0);
|
||||
});
|
||||
|
||||
it('Should retrieve the queried customers ids only.', async () => {
|
||||
const customer1 = await tenantFactory.create('customer', { display_name: 'Ahmed' });
|
||||
const customer2 = await tenantFactory.create('customer', { display_name: 'Mohamed' });
|
||||
|
||||
await tenantFactory.create('account_transaction', {
|
||||
contact_id: customer1.id,
|
||||
contact_type: 'customer',
|
||||
debit: 10000,
|
||||
credit: 0,
|
||||
account_id: 10,
|
||||
date: '2020-01-14',
|
||||
});
|
||||
|
||||
await tenantFactory.create('account_transaction', {
|
||||
contact_id: customer1.id,
|
||||
contact_type: 'customer',
|
||||
debit: 1000,
|
||||
credit: 0,
|
||||
account_id: 10,
|
||||
date: '2020-03-15',
|
||||
});
|
||||
|
||||
// Receive
|
||||
await tenantFactory.create('account_transaction', {
|
||||
contact_id: customer1.id,
|
||||
contact_type: 'customer',
|
||||
debit: 0,
|
||||
credit: 8000,
|
||||
account_id: 10,
|
||||
date: '2020-06-01',
|
||||
});
|
||||
|
||||
const res = await request()
|
||||
.get('/api/financial_statements/receivable_aging_summary')
|
||||
.set('x-access-token', loginRes.body.token)
|
||||
.set('organization-id', tenantWebsite.organizationId)
|
||||
.query({
|
||||
as_date: '2020-06-01',
|
||||
aging_days_before: 30,
|
||||
aging_periods: 6,
|
||||
customer_ids: [customer1.id],
|
||||
})
|
||||
.send();
|
||||
|
||||
expect(res.body.aging.customers.length).equals(1);
|
||||
})
|
||||
});
|
||||
439
packages/server/tests/routes/sales_estimates.test.js
Normal file
439
packages/server/tests/routes/sales_estimates.test.js
Normal file
@@ -0,0 +1,439 @@
|
||||
const { iteratee } = require('lodash');
|
||||
import { tenantWebsite, tenantFactory, loginRes } from '~/dbInit';
|
||||
import { request, expect } from '~/testInit';
|
||||
import { SaleEstimate, SaleEstimateEntry } from '../../src/models';
|
||||
|
||||
describe('route: `/sales/estimates`', () => {
|
||||
describe('POST: `/sales/estimates`', () => {
|
||||
it('Should `customer_id` be required.', async () => {
|
||||
const res = await request()
|
||||
.post('/api/sales/estimates')
|
||||
.set('x-access-token', loginRes.body.token)
|
||||
.set('organization-id', tenantWebsite.organizationId)
|
||||
.send();
|
||||
|
||||
expect(res.status).equals(422);
|
||||
expect(res.body.errors).include.something.deep.equals({
|
||||
msg: 'Invalid value',
|
||||
param: 'customer_id',
|
||||
location: 'body',
|
||||
});
|
||||
});
|
||||
|
||||
it('Should `estimate_date` be required.', async () => {
|
||||
const res = await request()
|
||||
.post('/api/sales/estimates')
|
||||
.set('x-access-token', loginRes.body.token)
|
||||
.set('organization-id', tenantWebsite.organizationId)
|
||||
.send();
|
||||
|
||||
expect(res.status).equals(422);
|
||||
expect(res.body.errors).include.something.deep.equals({
|
||||
msg: 'Invalid value',
|
||||
param: 'estimate_date',
|
||||
location: 'body',
|
||||
});
|
||||
});
|
||||
|
||||
it('Should `estimate_number` be required.', async () => {
|
||||
const res = await request()
|
||||
.post('/api/sales/estimates')
|
||||
.set('x-access-token', loginRes.body.token)
|
||||
.set('organization-id', tenantWebsite.organizationId)
|
||||
.send();
|
||||
|
||||
expect(res.status).equals(422);
|
||||
expect(res.body.errors).include.something.deep.equals({
|
||||
msg: 'Invalid value',
|
||||
param: 'estimate_number',
|
||||
location: 'body',
|
||||
});
|
||||
});
|
||||
|
||||
it('Should `entries` be atleast one entry.', async () => {
|
||||
const res = await request()
|
||||
.post('/api/sales/estimates')
|
||||
.set('x-access-token', loginRes.body.token)
|
||||
.set('organization-id', tenantWebsite.organizationId)
|
||||
.send({
|
||||
entries: [],
|
||||
});
|
||||
|
||||
expect(res.status).equals(422);
|
||||
expect(res.body.errors).include.something.deep.equals({
|
||||
value: [],
|
||||
msg: 'Invalid value',
|
||||
param: 'entries',
|
||||
location: 'body',
|
||||
});
|
||||
});
|
||||
|
||||
it('Should `entries.*.item_id` be required.', async () => {
|
||||
const res = await request()
|
||||
.post('/api/sales/estimates')
|
||||
.set('x-access-token', loginRes.body.token)
|
||||
.set('organization-id', tenantWebsite.organizationId)
|
||||
.send({
|
||||
entries: [{}],
|
||||
});
|
||||
|
||||
expect(res.status).equals(422);
|
||||
expect(res.body.errors).include.something.deep.equals({
|
||||
msg: 'Invalid value',
|
||||
param: 'entries[0].item_id',
|
||||
location: 'body',
|
||||
});
|
||||
});
|
||||
|
||||
it('Should `entries.*.quantity` be required.', async () => {
|
||||
const res = await request()
|
||||
.post('/api/sales/estimates')
|
||||
.set('x-access-token', loginRes.body.token)
|
||||
.set('organization-id', tenantWebsite.organizationId)
|
||||
.send({
|
||||
entries: [{}],
|
||||
});
|
||||
|
||||
expect(res.status).equals(422);
|
||||
expect(res.body.errors).include.something.deep.equals({
|
||||
msg: 'Invalid value',
|
||||
param: 'entries[0].quantity',
|
||||
location: 'body',
|
||||
});
|
||||
});
|
||||
|
||||
it('Should be `entries.*.rate` be required.', async () => {
|
||||
const res = await request()
|
||||
.post('/api/sales/estimates')
|
||||
.set('x-access-token', loginRes.body.token)
|
||||
.set('organization-id', tenantWebsite.organizationId)
|
||||
.send({
|
||||
entries: [{}],
|
||||
});
|
||||
|
||||
expect(res.status).equals(422);
|
||||
expect(res.body.errors).include.something.deep.equals({
|
||||
msg: 'Invalid value',
|
||||
param: 'entries[0].rate',
|
||||
location: 'body',
|
||||
});
|
||||
});
|
||||
|
||||
it('Should `customer_id` be exists on the storage.', async () => {
|
||||
const res = await request()
|
||||
.post('/api/sales/estimates')
|
||||
.set('x-access-token', loginRes.body.token)
|
||||
.set('organization-id', tenantWebsite.organizationId)
|
||||
.send({
|
||||
customer_id: 10,
|
||||
estimate_date: '2020-02-02',
|
||||
expiration_date: '2020-03-03',
|
||||
estimate_number: '1',
|
||||
entries: [
|
||||
{
|
||||
item_id: 1,
|
||||
rate: 1,
|
||||
quantity: 2,
|
||||
}
|
||||
],
|
||||
});
|
||||
|
||||
expect(res.status).equals(404);
|
||||
expect(res.body.errors).include.something.deep.equals({
|
||||
type: 'CUSTOMER.ID.NOT.FOUND', code: 200,
|
||||
});
|
||||
});
|
||||
|
||||
it('Should `estimate_number` be unique on the storage.', async () => {
|
||||
const saleEstimate = await tenantFactory.create('sale_estimate');
|
||||
|
||||
const res = await request()
|
||||
.post('/api/sales/estimates')
|
||||
.set('x-access-token', loginRes.body.token)
|
||||
.set('organization-id', tenantWebsite.organizationId)
|
||||
.send({
|
||||
customer_id: saleEstimate.customerId,
|
||||
estimate_date: '2020-02-02',
|
||||
expiration_date: '2020-03-03',
|
||||
estimate_number: saleEstimate.estimateNumber,
|
||||
entries: [
|
||||
{
|
||||
item_id: 1,
|
||||
rate: 1,
|
||||
quantity: 2,
|
||||
}
|
||||
],
|
||||
});
|
||||
|
||||
expect(res.status).equals(400);
|
||||
expect(res.body.errors).include.something.deep.equals({
|
||||
type: 'ESTIMATE.NUMBER.IS.NOT.UNQIUE', code: 300,
|
||||
});
|
||||
});
|
||||
|
||||
it('Should `entries.*.item_id` be exists on the storage.', async () => {
|
||||
const customer = await tenantFactory.create('customer');
|
||||
const res = await request()
|
||||
.post('/api/sales/estimates')
|
||||
.set('x-access-token', loginRes.body.token)
|
||||
.set('organization-id', tenantWebsite.organizationId)
|
||||
.send({
|
||||
customer_id: customer.id,
|
||||
estimate_date: '2020-02-02',
|
||||
expiration_date: '2020-03-03',
|
||||
estimate_number: '12',
|
||||
entries: [
|
||||
{
|
||||
item_id: 1,
|
||||
rate: 1,
|
||||
quantity: 2,
|
||||
}
|
||||
],
|
||||
});
|
||||
|
||||
expect(res.status).equals(400);
|
||||
expect(res.body.errors).include.something.deep.equals({
|
||||
type: 'ITEMS.IDS.NOT.EXISTS', code: 400,
|
||||
});
|
||||
});
|
||||
|
||||
it('Should store the given details on the storage.', async () => {
|
||||
const customer = await tenantFactory.create('customer');
|
||||
const item = await tenantFactory.create('item');
|
||||
|
||||
const res = await request()
|
||||
.post('/api/sales/estimates')
|
||||
.set('x-access-token', loginRes.body.token)
|
||||
.set('organization-id', tenantWebsite.organizationId)
|
||||
.send({
|
||||
customer_id: customer.id,
|
||||
estimate_date: '2020-02-02',
|
||||
expiration_date: '2020-03-03',
|
||||
estimate_number: '12',
|
||||
reference: 'reference',
|
||||
note: 'note here',
|
||||
terms_conditions: 'terms and conditions',
|
||||
entries: [
|
||||
{
|
||||
item_id: item.id,
|
||||
rate: 1,
|
||||
quantity: 2,
|
||||
description: 'desc..'
|
||||
}
|
||||
],
|
||||
});
|
||||
|
||||
expect(res.status).equals(200);
|
||||
|
||||
const storedEstimate = await SaleEstimate.tenant().query().where('id', res.body.id).first();
|
||||
const storedEstimateEntry = await SaleEstimateEntry.tenant().query().where('estimate_id', res.body.id).first();
|
||||
|
||||
expect(storedEstimate.id).equals(res.body.id);
|
||||
expect(storedEstimate.customerId).equals(customer.id);
|
||||
expect(storedEstimate.reference).equals('reference')
|
||||
expect(storedEstimate.note).equals('note here');
|
||||
expect(storedEstimate.termsConditions).equals('terms and conditions');
|
||||
expect(storedEstimate.estimateNumber).equals('12');
|
||||
|
||||
expect(storedEstimateEntry.itemId).equals(item.id);
|
||||
expect(storedEstimateEntry.rate).equals(1);
|
||||
expect(storedEstimateEntry.quantity).equals(2);
|
||||
expect(storedEstimateEntry.description).equals('desc..');
|
||||
});
|
||||
});
|
||||
|
||||
describe('DELETE: `/sales/estimates/:id`', () => {
|
||||
it('Should estimate id be exists on the storage.', async () => {
|
||||
const estimate = await tenantFactory.create('sale_estimate');
|
||||
const res = await request()
|
||||
.delete(`/api/sales/estimates/123`)
|
||||
.set('x-access-token', loginRes.body.token)
|
||||
.set('organization-id', tenantWebsite.organizationId)
|
||||
.send();
|
||||
|
||||
expect(res.status).equals(404);
|
||||
expect(res.body.errors).include.something.deep.equals({
|
||||
type: 'SALE.ESTIMATE.ID.NOT.FOUND', code: 200
|
||||
});
|
||||
});
|
||||
|
||||
it('Should delete the given estimate with associated entries from the storage.', async () => {
|
||||
const estimate = await tenantFactory.create('sale_estimate');
|
||||
const estimateEntry = await tenantFactory.create('sale_estimate_entry', { estimate_id: estimate.id });
|
||||
|
||||
const res = await request()
|
||||
.delete(`/api/sales/estimates/${estimate.id}`)
|
||||
.set('x-access-token', loginRes.body.token)
|
||||
.set('organization-id', tenantWebsite.organizationId)
|
||||
.send();
|
||||
|
||||
const foundEstimate = await SaleEstimate.tenant().query().where('id', estimate.id);
|
||||
const foundEstimateEntry = await SaleEstimateEntry.tenant().query().where('estimate_id', estimate.id);
|
||||
|
||||
expect(res.status).equals(200);
|
||||
expect(foundEstimate.length).equals(0);
|
||||
expect(foundEstimateEntry.length).equals(0);
|
||||
});
|
||||
});
|
||||
|
||||
describe('POST: `/sales/estimates/:id`', () => {
|
||||
it('Should estimate id be exists on the storage.', async () => {
|
||||
const customer = await tenantFactory.create('customer');
|
||||
const item = await tenantFactory.create('item');
|
||||
|
||||
const res = await request()
|
||||
.post(`/api/sales/estimates/123`)
|
||||
.set('x-access-token', loginRes.body.token)
|
||||
.set('organization-id', tenantWebsite.organizationId)
|
||||
.send({
|
||||
customer_id: customer.id,
|
||||
estimate_date: '2020-02-02',
|
||||
expiration_date: '2020-03-03',
|
||||
estimate_number: '12',
|
||||
reference: 'reference',
|
||||
note: 'note here',
|
||||
terms_conditions: 'terms and conditions',
|
||||
entries: [
|
||||
{
|
||||
item_id: item.id,
|
||||
rate: 1,
|
||||
quantity: 2,
|
||||
description: 'desc..'
|
||||
}
|
||||
],
|
||||
})
|
||||
|
||||
expect(res.status).equals(404);
|
||||
expect(res.body.errors).include.something.deep.equals({
|
||||
type: 'SALE.ESTIMATE.ID.NOT.FOUND', code: 200
|
||||
});
|
||||
});
|
||||
|
||||
it('Should `entries.*.item_id` be exists on the storage.', async () => {
|
||||
const saleEstimate = await tenantFactory.create('sale_estimate');
|
||||
const customer = await tenantFactory.create('customer');
|
||||
|
||||
const res = await request()
|
||||
.post(`/api/sales/estimates/${saleEstimate.id}`)
|
||||
.set('x-access-token', loginRes.body.token)
|
||||
.set('organization-id', tenantWebsite.organizationId)
|
||||
.send({
|
||||
customer_id: customer.id,
|
||||
estimate_date: '2020-02-02',
|
||||
expiration_date: '2020-03-03',
|
||||
estimate_number: '12',
|
||||
entries: [
|
||||
{
|
||||
item_id: 1,
|
||||
rate: 1,
|
||||
quantity: 2,
|
||||
}
|
||||
],
|
||||
});
|
||||
|
||||
expect(res.status).equals(400);
|
||||
expect(res.body.errors).include.something.deep.equals({
|
||||
type: 'ITEMS.IDS.NOT.EXISTS', code: 400
|
||||
});
|
||||
});
|
||||
|
||||
it('Should sale estimate number unique on the storage.', async () => {
|
||||
const saleEstimate = await tenantFactory.create('sale_estimate');
|
||||
const saleEstimate2 = await tenantFactory.create('sale_estimate');
|
||||
|
||||
const res = await request()
|
||||
.post(`/api/sales/estimates/${saleEstimate.id}`)
|
||||
.set('x-access-token', loginRes.body.token)
|
||||
.set('organization-id', tenantWebsite.organizationId)
|
||||
.send({
|
||||
customer_id: saleEstimate.customerId,
|
||||
estimate_date: '2020-02-02',
|
||||
expiration_date: '2020-03-03',
|
||||
estimate_number: saleEstimate2.estimateNumber,
|
||||
entries: [
|
||||
{
|
||||
item_id: 1,
|
||||
rate: 1,
|
||||
quantity: 2,
|
||||
}
|
||||
],
|
||||
});
|
||||
expect(res.status).equals(400);
|
||||
expect(res.body.errors).include.something.deep.equals({
|
||||
type: 'ESTIMATE.NUMBER.IS.NOT.UNQIUE', code: 300,
|
||||
});
|
||||
});
|
||||
|
||||
it('Should sale estimate entries IDs be exists on the storage and associated to the sale estimate.', async () => {
|
||||
const item = await tenantFactory.create('item');
|
||||
const saleEstimate = await tenantFactory.create('sale_estimate');
|
||||
const saleEstimate2 = await tenantFactory.create('sale_estimate');
|
||||
|
||||
const res = await request()
|
||||
.post(`/api/sales/estimates/${saleEstimate.id}`)
|
||||
.set('x-access-token', loginRes.body.token)
|
||||
.set('organization-id', tenantWebsite.organizationId)
|
||||
.send({
|
||||
customer_id: saleEstimate.customerId,
|
||||
estimate_date: '2020-02-02',
|
||||
expiration_date: '2020-03-03',
|
||||
estimate_number: saleEstimate.estimateNumber,
|
||||
entries: [
|
||||
{
|
||||
id: 100,
|
||||
item_id: item.id,
|
||||
rate: 1,
|
||||
quantity: 2,
|
||||
}
|
||||
],
|
||||
});
|
||||
|
||||
expect(res.status).equals(400);
|
||||
expect(res.body.errors).include.something.deep.equals({
|
||||
type: 'ESTIMATE.NOT.FOUND.ENTRIES.IDS', code: 500,
|
||||
});
|
||||
});
|
||||
|
||||
it('Should update the given sale estimates with associated entries.', async () => {
|
||||
const customer = await tenantFactory.create('customer');
|
||||
const item = await tenantFactory.create('item');
|
||||
const saleEstimate = await tenantFactory.create('sale_estimate');
|
||||
const saleEstimateEntry = await tenantFactory.create('sale_estimate_entry', {
|
||||
estimate_id: saleEstimate.id,
|
||||
});
|
||||
|
||||
const res = await request()
|
||||
.post(`/api/sales/estimates/${saleEstimate.id}`)
|
||||
.set('x-access-token', loginRes.body.token)
|
||||
.set('organization-id', tenantWebsite.organizationId)
|
||||
.send({
|
||||
customer_id: customer.id,
|
||||
estimate_date: '2020-02-02',
|
||||
expiration_date: '2020-03-03',
|
||||
estimate_number: '123',
|
||||
entries: [
|
||||
{
|
||||
id: saleEstimateEntry.id,
|
||||
item_id: item.id,
|
||||
rate: 100,
|
||||
quantity: 200,
|
||||
}
|
||||
],
|
||||
});
|
||||
expect(res.status).equals(200);
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
describe('GET: `/sales/estimates`', () => {
|
||||
it('Should retrieve sales estimates.', async () => {
|
||||
const res = await request()
|
||||
.get('/api/sales/estimates')
|
||||
.set('x-access-token', loginRes.body.token)
|
||||
.set('organization-id', tenantWebsite.organizationId)
|
||||
.send();
|
||||
|
||||
console.log(res.status, res.body);
|
||||
});
|
||||
});
|
||||
});
|
||||
494
packages/server/tests/routes/sales_invoices.test.js
Normal file
494
packages/server/tests/routes/sales_invoices.test.js
Normal file
@@ -0,0 +1,494 @@
|
||||
import { tenantWebsite, tenantFactory, loginRes } from '~/dbInit';
|
||||
import { request, expect } from '~/testInit';
|
||||
import { SaleInvoice } from 'models';
|
||||
import { SaleInvoiceEntry } from '../../src/models';
|
||||
|
||||
describe('route: `/sales/invoices`', () => {
|
||||
describe('POST: `/sales/invoices`', () => {
|
||||
it('Should `customer_id` be required.', async () => {
|
||||
const res = await request()
|
||||
.post('/api/sales/invoices')
|
||||
.set('x-access-token', loginRes.body.token)
|
||||
.set('organization-id', tenantWebsite.organizationId)
|
||||
.send();
|
||||
|
||||
expect(res.status).equals(422);
|
||||
expect(res.body.errors).include.something.deep.equals({
|
||||
msg: 'Invalid value',
|
||||
param: 'customer_id',
|
||||
location: 'body',
|
||||
});
|
||||
});
|
||||
|
||||
it('Should `invoice_date` be required.', async () => {
|
||||
const res = await request()
|
||||
.post('/api/sales/invoices')
|
||||
.set('x-access-token', loginRes.body.token)
|
||||
.set('organization-id', tenantWebsite.organizationId)
|
||||
.send();
|
||||
|
||||
expect(res.status).equals(422);
|
||||
expect(res.body.errors).include.something.deep.equals({
|
||||
msg: 'Invalid value',
|
||||
param: 'invoice_date',
|
||||
location: 'body',
|
||||
});
|
||||
});
|
||||
|
||||
it('Should `due_date` be required.', async () => {
|
||||
const res = await request()
|
||||
.post('/api/sales/invoices')
|
||||
.set('x-access-token', loginRes.body.token)
|
||||
.set('organization-id', tenantWebsite.organizationId)
|
||||
.send();
|
||||
|
||||
expect(res.status).equals(422);
|
||||
expect(res.body.errors).include.something.deep.equals({
|
||||
msg: 'Invalid value',
|
||||
param: 'due_date',
|
||||
location: 'body',
|
||||
});
|
||||
});
|
||||
|
||||
it('Should `invoice_no` be required.', async () => {
|
||||
const res = await request()
|
||||
.post('/api/sales/invoices')
|
||||
.set('x-access-token', loginRes.body.token)
|
||||
.set('organization-id', tenantWebsite.organizationId)
|
||||
.send();
|
||||
|
||||
expect(res.status).equals(422);
|
||||
expect(res.body.errors).include.something.deep.equals({
|
||||
msg: 'Invalid value',
|
||||
param: 'invoice_no',
|
||||
location: 'body',
|
||||
});
|
||||
});
|
||||
|
||||
it('Should `status` be required.', async () => {
|
||||
const res = await request()
|
||||
.post('/api/sales/invoices')
|
||||
.set('x-access-token', loginRes.body.token)
|
||||
.set('organization-id', tenantWebsite.organizationId)
|
||||
.send();
|
||||
|
||||
expect(res.status).equals(422);
|
||||
expect(res.body.errors).include.something.deep.equals({
|
||||
msg: 'Invalid value',
|
||||
param: 'status',
|
||||
location: 'body',
|
||||
});
|
||||
});
|
||||
|
||||
it('Should `entries.*.item_id` be required.', async () => {
|
||||
const res = await request()
|
||||
.post('/api/sales/invoices')
|
||||
.set('x-access-token', loginRes.body.token)
|
||||
.set('organization-id', tenantWebsite.organizationId)
|
||||
.send({
|
||||
entries: [{}],
|
||||
});
|
||||
|
||||
expect(res.status).equals(422);
|
||||
expect(res.body.errors).include.something.deep.equals({
|
||||
msg: 'Invalid value',
|
||||
param: 'entries[0].item_id',
|
||||
location: 'body',
|
||||
});
|
||||
});
|
||||
|
||||
it('Should `entries.*.quantity` be required.', async () => {
|
||||
const res = await request()
|
||||
.post('/api/sales/invoices')
|
||||
.set('x-access-token', loginRes.body.token)
|
||||
.set('organization-id', tenantWebsite.organizationId)
|
||||
.send({
|
||||
entries: [{}],
|
||||
});
|
||||
|
||||
expect(res.status).equals(422);
|
||||
expect(res.body.errors).include.something.deep.equals({
|
||||
msg: 'Invalid value',
|
||||
param: 'entries[0].quantity',
|
||||
location: 'body',
|
||||
});
|
||||
});
|
||||
|
||||
it('Should `entries.*.rate` be required.', async () => {
|
||||
const res = await request()
|
||||
.post('/api/sales/invoices')
|
||||
.set('x-access-token', loginRes.body.token)
|
||||
.set('organization-id', tenantWebsite.organizationId)
|
||||
.send({
|
||||
entries: [{}],
|
||||
});
|
||||
|
||||
expect(res.status).equals(422);
|
||||
expect(res.body.errors).include.something.deep.equals({
|
||||
msg: 'Invalid value',
|
||||
param: 'entries[0].rate',
|
||||
location: 'body',
|
||||
});
|
||||
});
|
||||
|
||||
it('Should `customer_id` be exists on the storage.', async () => {
|
||||
const customer = await tenantFactory.create('customer');
|
||||
const res = await request()
|
||||
.post('/api/sales/invoices')
|
||||
.set('x-access-token', loginRes.body.token)
|
||||
.set('organization-id', tenantWebsite.organizationId)
|
||||
.send({
|
||||
customer_id: 123,
|
||||
invoice_date: '2020-02-02',
|
||||
due_date: '2020-03-03',
|
||||
invoice_no: '123',
|
||||
reference_no: '123',
|
||||
status: 'published',
|
||||
invoice_message: 'Invoice message...',
|
||||
terms_conditions: 'terms and conditions',
|
||||
entries: [
|
||||
{
|
||||
item_id: 1,
|
||||
rate: 1,
|
||||
quantity: 1,
|
||||
discount: 1,
|
||||
}
|
||||
]
|
||||
});
|
||||
|
||||
expect(res.status).equals(400);
|
||||
expect(res.body.errors).include.something.deep.equals({
|
||||
type: 'CUSTOMER.ID.NOT.EXISTS', code: 200,
|
||||
});
|
||||
});
|
||||
|
||||
it('Should `invoice_date` be bigger than `due_date`.', async () => {
|
||||
|
||||
});
|
||||
|
||||
it('Should `invoice_no` be unique on the storage.', async () => {
|
||||
const saleInvoice = await tenantFactory.create('sale_invoice', {
|
||||
invoice_no: '123',
|
||||
});
|
||||
const res = await request()
|
||||
.post('/api/sales/invoices')
|
||||
.set('x-access-token', loginRes.body.token)
|
||||
.set('organization-id', tenantWebsite.organizationId)
|
||||
.send({
|
||||
customer_id: 123,
|
||||
invoice_date: '2020-02-02',
|
||||
due_date: '2020-03-03',
|
||||
invoice_no: '123',
|
||||
reference_no: '123',
|
||||
status: 'published',
|
||||
invoice_message: 'Invoice message...',
|
||||
terms_conditions: 'terms and conditions',
|
||||
entries: [
|
||||
{
|
||||
item_id: 1,
|
||||
rate: 1,
|
||||
quantity: 1,
|
||||
discount: 1,
|
||||
}
|
||||
]
|
||||
});
|
||||
|
||||
expect(res.status).equals(400);
|
||||
expect(res.body.errors).include.something.deep.equals({
|
||||
type: 'SALE.INVOICE.NUMBER.IS.EXISTS', code: 200
|
||||
});
|
||||
});
|
||||
|
||||
it('Should `entries.*.item_id` be exists on the storage.', async () => {
|
||||
const res = await request()
|
||||
.post('/api/sales/invoices')
|
||||
.set('x-access-token', loginRes.body.token)
|
||||
.set('organization-id', tenantWebsite.organizationId)
|
||||
.send({
|
||||
customer_id: 123,
|
||||
invoice_date: '2020-02-02',
|
||||
due_date: '2020-03-03',
|
||||
invoice_no: '123',
|
||||
reference_no: '123',
|
||||
status: 'published',
|
||||
invoice_message: 'Invoice message...',
|
||||
terms_conditions: 'terms and conditions',
|
||||
entries: [
|
||||
{
|
||||
item_id: 1,
|
||||
rate: 1,
|
||||
quantity: 1,
|
||||
discount: 1,
|
||||
}
|
||||
]
|
||||
});
|
||||
|
||||
expect(res.status).equals(400);
|
||||
expect(res.body.errors).include.something.deep.equals({
|
||||
type: 'ITEMS.IDS.NOT.EXISTS', code: 300,
|
||||
});
|
||||
});
|
||||
|
||||
it('Should save the given sale invoice details with associated entries.', async () => {
|
||||
const customer = await tenantFactory.create('customer');
|
||||
const item = await tenantFactory.create('item');
|
||||
const res = await request()
|
||||
.post('/api/sales/invoices')
|
||||
.set('x-access-token', loginRes.body.token)
|
||||
.set('organization-id', tenantWebsite.organizationId)
|
||||
.send({
|
||||
customer_id: customer.id,
|
||||
invoice_date: '2020-02-02',
|
||||
due_date: '2020-03-03',
|
||||
invoice_no: '123',
|
||||
reference_no: '123',
|
||||
status: 'published',
|
||||
invoice_message: 'Invoice message...',
|
||||
terms_conditions: 'terms and conditions',
|
||||
entries: [
|
||||
{
|
||||
item_id: item.id,
|
||||
rate: 1,
|
||||
quantity: 1,
|
||||
discount: 1,
|
||||
}
|
||||
]
|
||||
});
|
||||
expect(res.status).equals(200);
|
||||
});
|
||||
});
|
||||
|
||||
describe('POST: `/api/sales/invoices/:id`', () => {
|
||||
it('Should `customer_id` be required.', async () => {
|
||||
const res = await request()
|
||||
.post('/api/sales/invoices/123')
|
||||
.set('x-access-token', loginRes.body.token)
|
||||
.set('organization-id', tenantWebsite.organizationId)
|
||||
.send();
|
||||
|
||||
expect(res.status).equals(422);
|
||||
expect(res.body.errors).include.something.deep.equals({
|
||||
msg: 'Invalid value',
|
||||
param: 'customer_id',
|
||||
location: 'body',
|
||||
});
|
||||
});
|
||||
|
||||
it('Should `invoice_date` be required.', async () => {
|
||||
const res = await request()
|
||||
.post('/api/sales/invoices/123')
|
||||
.set('x-access-token', loginRes.body.token)
|
||||
.set('organization-id', tenantWebsite.organizationId)
|
||||
.send();
|
||||
|
||||
expect(res.status).equals(422);
|
||||
expect(res.body.errors).include.something.deep.equals({
|
||||
msg: 'Invalid value',
|
||||
param: 'invoice_date',
|
||||
location: 'body',
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
it('Should `status` be required.', async () => {
|
||||
const res = await request()
|
||||
.post('/api/sales/invoices/123')
|
||||
.set('x-access-token', loginRes.body.token)
|
||||
.set('organization-id', tenantWebsite.organizationId)
|
||||
.send();
|
||||
|
||||
expect(res.status).equals(422);
|
||||
expect(res.body.errors).include.something.deep.equals({
|
||||
msg: 'Invalid value',
|
||||
param: 'status',
|
||||
location: 'body',
|
||||
});
|
||||
});
|
||||
|
||||
it('Should `entries.*.item_id` be required.', async () => {
|
||||
const res = await request()
|
||||
.post('/api/sales/invoices/123')
|
||||
.set('x-access-token', loginRes.body.token)
|
||||
.set('organization-id', tenantWebsite.organizationId)
|
||||
.send({
|
||||
entries: [{}],
|
||||
});
|
||||
|
||||
expect(res.status).equals(422);
|
||||
expect(res.body.errors).include.something.deep.equals({
|
||||
msg: 'Invalid value',
|
||||
param: 'entries[0].item_id',
|
||||
location: 'body',
|
||||
});
|
||||
});
|
||||
|
||||
it('Should `entries.*.quantity` be required.', async () => {
|
||||
const res = await request()
|
||||
.post('/api/sales/invoices/123')
|
||||
.set('x-access-token', loginRes.body.token)
|
||||
.set('organization-id', tenantWebsite.organizationId)
|
||||
.send({
|
||||
entries: [{}],
|
||||
});
|
||||
|
||||
expect(res.status).equals(422);
|
||||
expect(res.body.errors).include.something.deep.equals({
|
||||
msg: 'Invalid value',
|
||||
param: 'entries[0].quantity',
|
||||
location: 'body',
|
||||
});
|
||||
});
|
||||
|
||||
it('Should `entries.*.rate` be required.', async () => {
|
||||
const res = await request()
|
||||
.post('/api/sales/invoices/123')
|
||||
.set('x-access-token', loginRes.body.token)
|
||||
.set('organization-id', tenantWebsite.organizationId)
|
||||
.send({
|
||||
entries: [{}],
|
||||
});
|
||||
|
||||
expect(res.status).equals(422);
|
||||
expect(res.body.errors).include.something.deep.equals({
|
||||
msg: 'Invalid value',
|
||||
param: 'entries[0].rate',
|
||||
location: 'body',
|
||||
});
|
||||
});
|
||||
|
||||
it('Should `customer_id` be exists on the storage.', async () => {
|
||||
const customer = await tenantFactory.create('customer');
|
||||
const saleInvoice = await tenantFactory.create('sale_invoice');
|
||||
|
||||
const res = await request()
|
||||
.post(`/api/sales/invoices/${saleInvoice.id}`)
|
||||
.set('x-access-token', loginRes.body.token)
|
||||
.set('organization-id', tenantWebsite.organizationId)
|
||||
.send({
|
||||
customer_id: 123,
|
||||
invoice_date: '2020-02-02',
|
||||
due_date: '2020-03-03',
|
||||
invoice_no: '123',
|
||||
reference_no: '123',
|
||||
status: 'published',
|
||||
invoice_message: 'Invoice message...',
|
||||
terms_conditions: 'terms and conditions',
|
||||
entries: [
|
||||
{
|
||||
item_id: 1,
|
||||
rate: 1,
|
||||
quantity: 1,
|
||||
discount: 1,
|
||||
}
|
||||
]
|
||||
});
|
||||
|
||||
expect(res.status).equals(400);
|
||||
expect(res.body.errors).include.something.deep.equals({
|
||||
type: 'CUSTOMER.ID.NOT.EXISTS', code: 200,
|
||||
});
|
||||
});
|
||||
|
||||
it('Should `invoice_date` be bigger than `due_date`.', async () => {
|
||||
|
||||
});
|
||||
|
||||
it('Should `invoice_no` be unique on the storage.', async () => {
|
||||
const saleInvoice = await tenantFactory.create('sale_invoice', {
|
||||
invoice_no: '123',
|
||||
});
|
||||
const res = await request()
|
||||
.post('/api/sales/invoices')
|
||||
.set('x-access-token', loginRes.body.token)
|
||||
.set('organization-id', tenantWebsite.organizationId)
|
||||
.send({
|
||||
customer_id: 123,
|
||||
invoice_date: '2020-02-02',
|
||||
due_date: '2020-03-03',
|
||||
invoice_no: '123',
|
||||
reference_no: '123',
|
||||
status: 'published',
|
||||
invoice_message: 'Invoice message...',
|
||||
terms_conditions: 'terms and conditions',
|
||||
entries: [
|
||||
{
|
||||
item_id: 1,
|
||||
rate: 1,
|
||||
quantity: 1,
|
||||
discount: 1,
|
||||
}
|
||||
]
|
||||
});
|
||||
|
||||
expect(res.status).equals(400);
|
||||
expect(res.body.errors).include.something.deep.equals({
|
||||
type: 'SALE.INVOICE.NUMBER.IS.EXISTS', code: 200
|
||||
});
|
||||
});
|
||||
|
||||
it('Should update the sale invoice details with associated entries.', async () => {
|
||||
const saleInvoice = await tenantFactory.create('sale_invoice');
|
||||
const customer = await tenantFactory.create('customer');
|
||||
const item = await tenantFactory.create('item');
|
||||
|
||||
const res = await request()
|
||||
.post(`/api/sales/invoices/${saleInvoice.id}`)
|
||||
.set('x-access-token', loginRes.body.token)
|
||||
.set('organization-id', tenantWebsite.organizationId)
|
||||
.send({
|
||||
customer_id: customer.id,
|
||||
invoice_date: '2020-02-02',
|
||||
due_date: '2020-03-03',
|
||||
invoice_no: '1',
|
||||
reference_no: '123',
|
||||
status: 'published',
|
||||
invoice_message: 'Invoice message...',
|
||||
terms_conditions: 'terms and conditions',
|
||||
entries: [
|
||||
{
|
||||
item_id: item.id,
|
||||
rate: 1,
|
||||
quantity: 1,
|
||||
discount: 1,
|
||||
}
|
||||
]
|
||||
});
|
||||
expect(res.status).equals(200);
|
||||
});
|
||||
});
|
||||
|
||||
describe('DELETE: `/sales/invoices/:id`', () => {
|
||||
it('Should retrieve sale invoice not found.', async () => {
|
||||
const res = await request()
|
||||
.delete('/api/sales/invoices/123')
|
||||
.set('x-access-token', loginRes.body.token)
|
||||
.set('organization-id', tenantWebsite.organizationId)
|
||||
.send();
|
||||
|
||||
expect(res.status).equals(404);
|
||||
expect(res.body.errors).include.something.deep.equals({
|
||||
type: 'SALE.INVOICE.NOT.FOUND', code: 200,
|
||||
});
|
||||
});
|
||||
|
||||
it('Should delete the given sale invoice with assocaited entries.', async () => {
|
||||
const saleInvoice = await tenantFactory.create('sale_invoice');
|
||||
const saleInvoiceEntey = await tenantFactory.create('sale_invoice_entry', {
|
||||
sale_invoice_id: saleInvoice.id,
|
||||
});
|
||||
|
||||
const res = await request()
|
||||
.delete(`/api/sales/invoices/${saleInvoice.id}`)
|
||||
.set('x-access-token', loginRes.body.token)
|
||||
.set('organization-id', tenantWebsite.organizationId)
|
||||
.send();
|
||||
|
||||
const storedSaleInvoice = await SaleInvoice.tenant().query().where('id', saleInvoice.id);
|
||||
const storedSaleInvoiceEntry = await SaleInvoiceEntry.tenant().query().where('id', saleInvoiceEntey.id);
|
||||
|
||||
expect(res.status).equals(200);
|
||||
expect(storedSaleInvoice.length).equals(0);
|
||||
expect(storedSaleInvoiceEntry.length).equals(0);
|
||||
});
|
||||
});
|
||||
});
|
||||
294
packages/server/tests/routes/sales_receipts.test.js
Normal file
294
packages/server/tests/routes/sales_receipts.test.js
Normal file
@@ -0,0 +1,294 @@
|
||||
import { tenantWebsite, tenantFactory, loginRes } from '~/dbInit';
|
||||
import { request, expect } from '~/testInit';
|
||||
import { SaleReceipt } from 'models';
|
||||
|
||||
describe('route: `/sales/receipts`', () => {
|
||||
describe('POST: `/sales/receipts`', () => {
|
||||
it('Should `deposit_account_id` be required.', async () => {
|
||||
const res = await request()
|
||||
.post('/api/sales/receipts')
|
||||
.set('x-access-token', loginRes.body.token)
|
||||
.set('organization-id', tenantWebsite.organizationId)
|
||||
.send();
|
||||
|
||||
expect(res.status).equals(422);
|
||||
expect(res.body.errors).include.something.deep.equals({
|
||||
msg: 'Invalid value',
|
||||
param: 'deposit_account_id',
|
||||
location: 'body',
|
||||
});
|
||||
});
|
||||
|
||||
it('Should `customer_id` be required.', async () => {
|
||||
const res = await request()
|
||||
.post('/api/sales/receipts')
|
||||
.set('x-access-token', loginRes.body.token)
|
||||
.set('organization-id', tenantWebsite.organizationId)
|
||||
.send();
|
||||
|
||||
expect(res.status).equals(422);
|
||||
expect(res.body.errors).include.something.deep.equals({
|
||||
msg: 'Invalid value',
|
||||
param: 'customer_id',
|
||||
location: 'body',
|
||||
});
|
||||
});
|
||||
|
||||
it('should `receipt_date` be required.', async () => {
|
||||
const res = await request()
|
||||
.post('/api/sales/receipts')
|
||||
.set('x-access-token', loginRes.body.token)
|
||||
.set('organization-id', tenantWebsite.organizationId)
|
||||
.send();
|
||||
|
||||
expect(res.status).equals(422);
|
||||
expect(res.body.errors).include.something.deep.equals({
|
||||
msg: 'Invalid value',
|
||||
param: 'receipt_date',
|
||||
location: 'body',
|
||||
});
|
||||
});
|
||||
|
||||
it('Should `entries.*.item_id` be required.', async () => {});
|
||||
|
||||
it('Should `deposit_account_id` be exists.', async () => {
|
||||
const res = await request()
|
||||
.post('/api/sales/receipts')
|
||||
.set('x-access-token', loginRes.body.token)
|
||||
.set('organization-id', tenantWebsite.organizationId)
|
||||
.send({
|
||||
deposit_account_id: 12220,
|
||||
customer_id: 1,
|
||||
receipt_date: '2020-02-02',
|
||||
reference_no: '123',
|
||||
entries: [
|
||||
{
|
||||
item_id: 1,
|
||||
quantity: 1,
|
||||
rate: 2,
|
||||
},
|
||||
],
|
||||
});
|
||||
|
||||
expect(res.status).equals(400);
|
||||
expect(res.body.errors).include.something.deep.equals({
|
||||
type: 'DEPOSIT.ACCOUNT.NOT.EXISTS',
|
||||
code: 300,
|
||||
});
|
||||
});
|
||||
|
||||
it('Should `customer_id` be exists.', async () => {
|
||||
const res = await request()
|
||||
.post('/api/sales/receipts')
|
||||
.set('x-access-token', loginRes.body.token)
|
||||
.set('organization-id', tenantWebsite.organizationId)
|
||||
.send({
|
||||
deposit_account_id: 12220,
|
||||
customer_id: 1001,
|
||||
receipt_date: '2020-02-02',
|
||||
reference_no: '123',
|
||||
entries: [
|
||||
{
|
||||
item_id: 1,
|
||||
quantity: 1,
|
||||
rate: 2,
|
||||
},
|
||||
],
|
||||
});
|
||||
|
||||
expect(res.status).equals(400);
|
||||
expect(res.body.errors).include.something.deep.equals({
|
||||
type: 'CUSTOMER.ID.NOT.EXISTS',
|
||||
code: 200,
|
||||
});
|
||||
});
|
||||
|
||||
it('Should all `entries.*.item_id` be exists on the storage.', async () => {
|
||||
const res = await request()
|
||||
.post('/api/sales/receipts')
|
||||
.set('x-access-token', loginRes.body.token)
|
||||
.set('organization-id', tenantWebsite.organizationId)
|
||||
.send({
|
||||
deposit_account_id: 12220,
|
||||
customer_id: 1001,
|
||||
receipt_date: '2020-02-02',
|
||||
reference_no: '123',
|
||||
entries: [
|
||||
{
|
||||
item_id: 1000,
|
||||
quantity: 1,
|
||||
rate: 2,
|
||||
},
|
||||
],
|
||||
});
|
||||
|
||||
expect(res.status).equals(400);
|
||||
expect(res.body.errors).include.something.deep.equals({
|
||||
type: 'ITEMS.IDS.NOT.EXISTS',
|
||||
code: 400,
|
||||
});
|
||||
});
|
||||
|
||||
it('Should store the sale receipt details with entries to the storage.', async () => {
|
||||
const item = await tenantFactory.create('item');
|
||||
const customer = await tenantFactory.create('customer');
|
||||
const account = await tenantFactory.create('account');
|
||||
|
||||
const res = await request()
|
||||
.post('/api/sales/receipts')
|
||||
.set('x-access-token', loginRes.body.token)
|
||||
.set('organization-id', tenantWebsite.organizationId)
|
||||
.send({
|
||||
deposit_account_id: account.id,
|
||||
customer_id: customer.id,
|
||||
receipt_date: '2020-02-02',
|
||||
reference_no: '123',
|
||||
receipt_message: 'Receipt message...',
|
||||
statement: 'Receipt statement...',
|
||||
entries: [
|
||||
{
|
||||
item_id: item.id,
|
||||
quantity: 1,
|
||||
rate: 2,
|
||||
},
|
||||
],
|
||||
});
|
||||
|
||||
const storedSaleReceipt = await SaleReceipt.tenant()
|
||||
.query()
|
||||
.where('id', res.body.id)
|
||||
.first();
|
||||
|
||||
expect(res.status).equals(200);
|
||||
expect(storedSaleReceipt.depositAccountId).equals(account.id);
|
||||
expect(storedSaleReceipt.referenceNo).equals('123');
|
||||
expect(storedSaleReceipt.customerId).equals(customer.id);
|
||||
|
||||
expect(storedSaleReceipt.receiptMessage).equals('Receipt message...');
|
||||
expect(storedSaleReceipt.statement).equals('Receipt statement...');
|
||||
});
|
||||
});
|
||||
|
||||
describe('DELETE: `/sales/receipts/:id`', () => {
|
||||
it('Should the given sale receipt id be exists on the storage.', async () => {
|
||||
const res = await request()
|
||||
.delete('/api/sales/receipts/123')
|
||||
.set('x-access-token', loginRes.body.token)
|
||||
.set('organization-id', tenantWebsite.organizationId)
|
||||
.send();
|
||||
|
||||
expect(res.status).equals(404);
|
||||
expect(res.body.errors).include.something.deep.equals({
|
||||
type: 'SALE.RECEIPT.NOT.FOUND',
|
||||
code: 200,
|
||||
});
|
||||
});
|
||||
|
||||
it('Should delete the sale receipt with associated entries and journal transactions.', async () => {
|
||||
const saleReceipt = await tenantFactory.create('sale_receipt');
|
||||
const saleReceiptEntry = await tenantFactory.create(
|
||||
'sale_receipt_entry',
|
||||
{
|
||||
sale_receipt_id: saleReceipt.id,
|
||||
}
|
||||
);
|
||||
const res = await request()
|
||||
.delete(`/api/sales/receipts/${saleReceipt.id}`)
|
||||
.set('x-access-token', loginRes.body.token)
|
||||
.set('organization-id', tenantWebsite.organizationId)
|
||||
.send();
|
||||
|
||||
const storedSaleReceipt = await SaleReceipt.tenant()
|
||||
.query()
|
||||
.where('id', saleReceipt.id);
|
||||
const storedSaleReceiptEntries = await SaleReceipt.tenant()
|
||||
.query()
|
||||
.where('id', saleReceiptEntry.id);
|
||||
|
||||
expect(res.status).equals(200);
|
||||
expect(storedSaleReceipt.length).equals(0);
|
||||
expect(storedSaleReceiptEntries.length).equals(0);
|
||||
});
|
||||
});
|
||||
|
||||
describe('POST: `/sales/receipts/:id`', () => {
|
||||
it('Should the given sale receipt id be exists on the storage.', async () => {
|
||||
const res = await request()
|
||||
.post('/api/sales/receipts/123')
|
||||
.set('x-access-token', loginRes.body.token)
|
||||
.set('organization-id', tenantWebsite.organizationId)
|
||||
.send({
|
||||
deposit_account_id: 123,
|
||||
customer_id: 123,
|
||||
receipt_date: '2020-02-02',
|
||||
reference_no: '123',
|
||||
receipt_message: 'Receipt message...',
|
||||
statement: 'Receipt statement...',
|
||||
entries: [
|
||||
{
|
||||
item_id: 123,
|
||||
quantity: 1,
|
||||
rate: 2,
|
||||
},
|
||||
],
|
||||
});
|
||||
|
||||
expect(res.status).equals(404);
|
||||
expect(res.body.errors).include.something.deep.equals({
|
||||
type: 'SALE.RECEIPT.NOT.FOUND',
|
||||
code: 200,
|
||||
});
|
||||
});
|
||||
|
||||
it('Should update the sale receipt details with associated entries.', async () => {
|
||||
const saleReceipt = await tenantFactory.create('sale_receipt');
|
||||
const depositAccount = await tenantFactory.create('account');
|
||||
const customer = await tenantFactory.create('customer');
|
||||
const item = await tenantFactory.create('item');
|
||||
|
||||
const res = await request()
|
||||
.post(`/api/sales/receipts/${saleReceipt.id}`)
|
||||
.set('x-access-token', loginRes.body.token)
|
||||
.set('organization-id', tenantWebsite.organizationId)
|
||||
.send({
|
||||
deposit_account_id: depositAccount.id,
|
||||
customer_id: customer.id,
|
||||
receipt_date: '2020-02-02',
|
||||
reference_no: '123',
|
||||
receipt_message: 'Receipt message...',
|
||||
statement: 'Receipt statement...',
|
||||
entries: [
|
||||
{
|
||||
id: 100,
|
||||
item_id: item.id,
|
||||
quantity: 1,
|
||||
rate: 2,
|
||||
},
|
||||
],
|
||||
});
|
||||
|
||||
expect(res.status).equals(400);
|
||||
expect(res.body.errors).include.something.deep.equals({
|
||||
type: 'ENTRIES.IDS.NOT.FOUND', code: 500,
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('GET: `/sales/receipts`', () => {
|
||||
it('Should response the custom view id not exists on the storage.', async () => {
|
||||
const res = await request()
|
||||
.get('/api/sales/receipts')
|
||||
.set('x-access-token', loginRes.body.token)
|
||||
.set('organization-id', tenantWebsite.organizationId)
|
||||
.send({
|
||||
|
||||
});
|
||||
|
||||
console.log(res.status, res.body);
|
||||
});
|
||||
|
||||
it('Should retrieve all sales receipts on the storage with pagination meta.', () => {
|
||||
|
||||
});
|
||||
});
|
||||
});
|
||||
203
packages/server/tests/routes/users.test.js
Normal file
203
packages/server/tests/routes/users.test.js
Normal file
@@ -0,0 +1,203 @@
|
||||
import knex from '@/database/knex';
|
||||
import {
|
||||
request,
|
||||
expect,
|
||||
} from '~/testInit';
|
||||
import {
|
||||
tenantWebsite,
|
||||
tenantFactory,
|
||||
loginRes
|
||||
} from '~/dbInit';
|
||||
|
||||
|
||||
describe('routes: `/routes`', () => {
|
||||
describe('GET: `/users`', () => {
|
||||
it('Should response unauthorized if the user was not authorized.', async () => {
|
||||
const res = await request().get('/api/users');
|
||||
|
||||
expect(res.status).equals(401);
|
||||
expect(res.body.message).equals('Unauthorized');
|
||||
});
|
||||
|
||||
it('Should retrieve the stored users with pagination meta.', async () => {
|
||||
await tenantFactory.create('user');
|
||||
|
||||
const res = await request()
|
||||
.get('/api/users')
|
||||
.set('x-access-token', loginRes.body.token)
|
||||
.set('organization-id', tenantWebsite.organizationId)
|
||||
.send();
|
||||
|
||||
expect(res.body.users.results.length).equals(2);
|
||||
expect(res.body.users.total).equals(2);
|
||||
});
|
||||
});
|
||||
|
||||
describe('POST: `/users/:id`', () => {
|
||||
it('Should create a new user if the user was not authorized.', async () => {
|
||||
const user = await tenantFactory.create('user');
|
||||
const res = await request()
|
||||
.post(`/api/users/${user.id}`);
|
||||
|
||||
expect(res.status).equals(401);
|
||||
expect(res.body.message).equals('Unauthorized');
|
||||
});
|
||||
|
||||
it('Should `first_name` be required.', async () => {
|
||||
const user = await tenantFactory.create('user');
|
||||
const res = await request()
|
||||
.post(`/api/users/${user.id}`)
|
||||
.set('x-access-token', loginRes.body.token)
|
||||
.set('organization-id', tenantWebsite.organizationId)
|
||||
.send();
|
||||
|
||||
expect(res.status).equals(422);
|
||||
|
||||
const foundFirstNameParam = res.body.errors.find((error) => error.param === 'first_name');
|
||||
expect(!!foundFirstNameParam).equals(true);
|
||||
});
|
||||
|
||||
it('Should `last_name` be required.', async () => {
|
||||
const user = await tenantFactory.create('user');
|
||||
const res = await request()
|
||||
.post(`/api/users/${user.id}`)
|
||||
.set('x-access-token', loginRes.body.token)
|
||||
.set('organization-id', tenantWebsite.organizationId)
|
||||
.send();
|
||||
|
||||
expect(res.status).equals(422);
|
||||
|
||||
const foundFirstNameParam = res.body.errors.find((error) => error.param === 'last_name');
|
||||
expect(!!foundFirstNameParam).equals(true);
|
||||
});
|
||||
|
||||
it('Should `email` be required.', async () => {
|
||||
const user = await tenantFactory.create('user');
|
||||
const res = await request()
|
||||
.post(`/api/users/${user.id}`)
|
||||
.set('x-access-token', loginRes.body.token)
|
||||
.set('organization-id', tenantWebsite.organizationId)
|
||||
.send();
|
||||
|
||||
expect(res.status).equals(422);
|
||||
|
||||
const foundEmailParam = res.body.errors.find((error) => error.param === 'email');
|
||||
expect(!!foundEmailParam).equals(true);
|
||||
});
|
||||
|
||||
it('Should be `email` be valid format.', async () => {
|
||||
const user = await tenantFactory.create('user');
|
||||
const res = await request()
|
||||
.post(`/api/users/${user.id}`)
|
||||
.set('x-access-token', loginRes.body.token)
|
||||
.set('organization-id', tenantWebsite.organizationId)
|
||||
.send({
|
||||
first_name: user.first_name,
|
||||
last_name: user.last_name,
|
||||
email: 'email',
|
||||
phone_number: user.phone_number,
|
||||
status: 1,
|
||||
});
|
||||
|
||||
expect(res.status).equals(422);
|
||||
|
||||
const foundEmailParam = res.body.errors.find((error) => error.param === 'email');
|
||||
expect(!!foundEmailParam).equals(true);
|
||||
});
|
||||
|
||||
it('Should `phone_number` be valid format.', async () => {
|
||||
const user = tenantFactory.create('user');
|
||||
const res = await request()
|
||||
.post(`/api/users/${user.id}`)
|
||||
.set('x-access-token', loginRes.body.token)
|
||||
.set('organization-id', tenantWebsite.organizationId)
|
||||
.send({
|
||||
first_name: user.first_name,
|
||||
last_name: user.last_name,
|
||||
email: user.email,
|
||||
phone_number: 'phone_number',
|
||||
status: 1,
|
||||
});
|
||||
|
||||
expect(res.status).equals(422);
|
||||
|
||||
const phoneNumberParam = res.body.errors.find((error) => error.param === 'phone_number');
|
||||
expect(!!phoneNumberParam).equals(true);
|
||||
});
|
||||
});
|
||||
|
||||
describe('GET: `/users/:id`', () => {
|
||||
it('Should not success if the user was not authorized.', async () => {
|
||||
const res = await request().get('/api/users/1');
|
||||
|
||||
expect(res.status).equals(401);
|
||||
expect(res.body.message).equals('Unauthorized');
|
||||
});
|
||||
|
||||
it('Should response not found if the user was not exist.', async () => {
|
||||
const res = await request()
|
||||
.get('/api/users/10')
|
||||
.set('x-access-token', loginRes.body.token)
|
||||
.set('organization-id', tenantWebsite.organizationId)
|
||||
.send();
|
||||
|
||||
expect(res.status).equals(404);
|
||||
});
|
||||
|
||||
it('Should response success if the user was exist.', async () => {
|
||||
const user = await tenantFactory.create('user');
|
||||
const res = await request()
|
||||
.get(`/api/users/${user.id}`)
|
||||
.set('x-access-token', loginRes.body.token)
|
||||
.set('organization-id', tenantWebsite.organizationId)
|
||||
.send();
|
||||
|
||||
expect(res.status).equals(200);
|
||||
});
|
||||
});
|
||||
|
||||
describe('DELETE: `/users/:id`', () => {
|
||||
it('Should not success if the user was not authorized.', async () => {
|
||||
const res = await request().delete('/api/users/1');
|
||||
|
||||
expect(res.status).equals(401);
|
||||
expect(res.body.message).equals('Unauthorized');
|
||||
});
|
||||
|
||||
it('Should response not found if the user was not exist.', async () => {
|
||||
const res = await request()
|
||||
.delete('/api/users/10')
|
||||
.set('x-access-token', loginRes.body.token)
|
||||
.set('organization-id', tenantWebsite.organizationId)
|
||||
.send();
|
||||
|
||||
expect(res.status).equals(404);
|
||||
expect(res.body.errors).include.something.that.deep.equals({
|
||||
type: 'USER_NOT_FOUND', code: 100,
|
||||
});
|
||||
});
|
||||
|
||||
it('Should response success if the user was exist.', async () => {
|
||||
const user = await tenantFactory.create('user');
|
||||
const res = await request()
|
||||
.delete(`/api/users/${user.id}`)
|
||||
.set('x-access-token', loginRes.body.token)
|
||||
.set('organization-id', tenantWebsite.organizationId)
|
||||
.send();
|
||||
|
||||
expect(res.status).equals(200);
|
||||
});
|
||||
|
||||
it('Should delete the give user from the storage.', async () => {
|
||||
const user = await tenantFactory.create('user');
|
||||
await request()
|
||||
.delete(`/api/users/${user.id}`)
|
||||
.set('x-access-token', loginRes.body.token)
|
||||
.set('organization-id', tenantWebsite.organizationId)
|
||||
.send();
|
||||
|
||||
const storedUsers = await knex('users').where('id', user.id);
|
||||
expect(storedUsers).to.have.lengthOf(0);
|
||||
});
|
||||
});
|
||||
});
|
||||
193
packages/server/tests/routes/vendors.test.js
Normal file
193
packages/server/tests/routes/vendors.test.js
Normal file
@@ -0,0 +1,193 @@
|
||||
import {
|
||||
request,
|
||||
expect,
|
||||
} from '~/testInit';
|
||||
import Currency from 'models/Currency';
|
||||
import {
|
||||
tenantWebsite,
|
||||
tenantFactory,
|
||||
loginRes
|
||||
} from '~/dbInit';
|
||||
import Vendor from 'models/Vendor';
|
||||
|
||||
describe('route: `/vendors`', () => {
|
||||
describe('POST: `/vendors`', () => {
|
||||
it('Should response unauthorized in case the user was not logged in.', async () => {
|
||||
const res = await request()
|
||||
.post('/api/vendors')
|
||||
.send({});
|
||||
|
||||
expect(res.status).equals(401);
|
||||
expect(res.body.message).equals('Unauthorized');
|
||||
});
|
||||
|
||||
it('Should `display_name` be required field.', async () => {
|
||||
const res = await request()
|
||||
.post('/api/vendors')
|
||||
.set('x-access-token', loginRes.body.token)
|
||||
.set('organization-id', tenantWebsite.organizationId)
|
||||
.send({
|
||||
|
||||
});
|
||||
|
||||
expect(res.status).equals(422);
|
||||
expect(res.body.errors).include.something.deep.equals({
|
||||
msg: 'Invalid value', param: 'display_name', location: 'body',
|
||||
})
|
||||
});
|
||||
|
||||
it('Should store the vendor data to the storage.', async () => {
|
||||
const res = await request()
|
||||
.post('/api/vendors')
|
||||
.set('x-access-token', loginRes.body.token)
|
||||
.set('organization-id', tenantWebsite.organizationId)
|
||||
.send({
|
||||
first_name: 'Ahmed',
|
||||
last_name: 'Bouhuolia',
|
||||
|
||||
company_name: 'Bigcapital',
|
||||
|
||||
display_name: 'Ahmed Bouhuolia, Bigcapital',
|
||||
|
||||
email: 'a.bouhuolia@live.com',
|
||||
work_phone: '0927918381',
|
||||
personal_phone: '0925173379',
|
||||
|
||||
billing_address_city: 'Tripoli',
|
||||
billing_address_country: 'Libya',
|
||||
billing_address_email: 'a.bouhuolia@live.com',
|
||||
billing_address_state: 'State Tripoli',
|
||||
billing_address_zipcode: '21892',
|
||||
|
||||
shipping_address_city: 'Tripoli',
|
||||
shipping_address_country: 'Libya',
|
||||
shipping_address_email: 'a.bouhuolia@live.com',
|
||||
shipping_address_state: 'State Tripoli',
|
||||
shipping_address_zipcode: '21892',
|
||||
|
||||
note: '__desc__',
|
||||
|
||||
active: true,
|
||||
});
|
||||
|
||||
expect(res.status).equals(200);
|
||||
|
||||
const foundVendor = await Vendor.tenant().query().where('id', res.body.id);
|
||||
|
||||
expect(foundVendor[0].firstName).equals('Ahmed');
|
||||
expect(foundVendor[0].lastName).equals('Bouhuolia');
|
||||
expect(foundVendor[0].companyName).equals('Bigcapital');
|
||||
expect(foundVendor[0].displayName).equals('Ahmed Bouhuolia, Bigcapital');
|
||||
|
||||
expect(foundVendor[0].email).equals('a.bouhuolia@live.com');
|
||||
|
||||
expect(foundVendor[0].workPhone).equals('0927918381');
|
||||
expect(foundVendor[0].personalPhone).equals('0925173379');
|
||||
|
||||
expect(foundVendor[0].billingAddressCity).equals('Tripoli');
|
||||
expect(foundVendor[0].billingAddressCountry).equals('Libya');
|
||||
expect(foundVendor[0].billingAddressEmail).equals('a.bouhuolia@live.com');
|
||||
expect(foundVendor[0].billingAddressState).equals('State Tripoli');
|
||||
expect(foundVendor[0].billingAddressZipcode).equals('21892');
|
||||
|
||||
expect(foundVendor[0].shippingAddressCity).equals('Tripoli');
|
||||
expect(foundVendor[0].shippingAddressCountry).equals('Libya');
|
||||
expect(foundVendor[0].shippingAddressEmail).equals('a.bouhuolia@live.com');
|
||||
expect(foundVendor[0].shippingAddressState).equals('State Tripoli');
|
||||
expect(foundVendor[0].shippingAddressZipcode).equals('21892');
|
||||
});
|
||||
});
|
||||
|
||||
describe('GET: `/vendors/:id`', () => {
|
||||
it('Should response not found in case the given vendor id was not exists on the storage.', async () => {
|
||||
const res = await request()
|
||||
.get('/api/vendors/123')
|
||||
.set('x-access-token', loginRes.body.token)
|
||||
.set('organization-id', tenantWebsite.organizationId)
|
||||
.send();
|
||||
|
||||
expect(res.status).equals(404);
|
||||
expect(res.body.errors).include.something.deep.equals({
|
||||
type: 'VENDOR.NOT.FOUND', code: 200,
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('GET: `vendors`', () => {
|
||||
it('Should response vendors items', async () => {
|
||||
await tenantFactory.create('vendor');
|
||||
await tenantFactory.create('vendor');
|
||||
|
||||
const res = await request()
|
||||
.get('/api/vendors')
|
||||
.set('x-access-token', loginRes.body.token)
|
||||
.set('organization-id', tenantWebsite.organizationId)
|
||||
.send();
|
||||
|
||||
expect(res.body.vendors.results.length).equals(2);
|
||||
});
|
||||
});
|
||||
|
||||
describe('DELETE: `/vendors/:id`', () => {
|
||||
it('Should response not found in case the given vendor id was not exists on the storage.', async () => {
|
||||
const res = await request()
|
||||
.delete('/api/vendors/123')
|
||||
.set('x-access-token', loginRes.body.token)
|
||||
.set('organization-id', tenantWebsite.organizationId)
|
||||
.send();
|
||||
|
||||
expect(res.status).equals(404);
|
||||
expect(res.body.errors).include.something.deep.equals({
|
||||
type: 'VENDOR.NOT.FOUND', code: 200,
|
||||
});
|
||||
});
|
||||
|
||||
it('Should delete the given vendor from the storage.', async () => {
|
||||
const vendor = await tenantFactory.create('vendor');
|
||||
const res = await request()
|
||||
.delete(`/api/vendors/${vendor.id}`)
|
||||
.set('x-access-token', loginRes.body.token)
|
||||
.set('organization-id', tenantWebsite.organizationId)
|
||||
.send();
|
||||
|
||||
expect(res.status).equals(200);
|
||||
|
||||
const foundVendor = await Vendor.tenant().query().where('id', vendor.id);
|
||||
expect(foundVendor.length).equals(0);
|
||||
})
|
||||
});
|
||||
|
||||
describe('POST: `/vendors/:id`', () => {
|
||||
it('Should response vendor not found', async () => {
|
||||
const res = await request()
|
||||
.post('/api/vendors/123')
|
||||
.set('x-access-token', loginRes.body.token)
|
||||
.set('organization-id', tenantWebsite.organizationId)
|
||||
.send({
|
||||
display_name: 'Ahmed Bouhuolia, Bigcapital',
|
||||
});
|
||||
|
||||
expect(res.status).equals(404);
|
||||
expect(res.body.errors).include.something.deep.equals({
|
||||
type: 'VENDOR.NOT.FOUND', code: 200,
|
||||
});
|
||||
});
|
||||
|
||||
it('Should update details of the given vendor.', async () => {
|
||||
const vendor = await tenantFactory.create('vendor');
|
||||
const res = await request()
|
||||
.post(`/api/vendors/${vendor.id}`)
|
||||
.set('x-access-token', loginRes.body.token)
|
||||
.set('organization-id', tenantWebsite.organizationId)
|
||||
.send({
|
||||
display_name: 'Ahmed Bouhuolia, Bigcapital',
|
||||
});
|
||||
|
||||
expect(res.status).equals(200);
|
||||
const foundVendor = await Vendor.tenant().query().where('id', res.body.id);
|
||||
|
||||
expect(foundVendor.length).equals(1);
|
||||
expect(foundVendor[0].displayName).equals('Ahmed Bouhuolia, Bigcapital');
|
||||
})
|
||||
});
|
||||
});
|
||||
936
packages/server/tests/routes/views.test.js
Normal file
936
packages/server/tests/routes/views.test.js
Normal file
@@ -0,0 +1,936 @@
|
||||
import {
|
||||
request,
|
||||
expect,
|
||||
} from '~/testInit';
|
||||
import View from 'models/View';
|
||||
import ViewRole from 'models/ViewRole';
|
||||
import 'models/ResourceField';
|
||||
import ViewColumn from '../../src/models/ViewColumn';
|
||||
import {
|
||||
tenantWebsite,
|
||||
tenantFactory,
|
||||
loginRes
|
||||
} from '~/dbInit';
|
||||
|
||||
|
||||
describe('routes: `/views`', () => {
|
||||
describe('GET: `/views`', () => {
|
||||
it('Should response unauthorized in case the user was not authorized.', async () => {
|
||||
const res = await request().get('/api/views');
|
||||
|
||||
expect(res.status).equals(401);
|
||||
expect(res.body.message).equals('Unauthorized');
|
||||
});
|
||||
|
||||
it('Should retrieve all views of the given resource name.', async () => {
|
||||
const resource = await tenantFactory.create('resource', { name: 'resource_name' });
|
||||
const resourceFields = await tenantFactory.create('view', {
|
||||
name: 'Resource View',
|
||||
resource_id: resource.id,
|
||||
roles_logic_expression: '',
|
||||
});
|
||||
|
||||
const res = await request()
|
||||
.get('/api/views')
|
||||
.set('x-access-token', loginRes.body.token)
|
||||
.set('organization-id', tenantWebsite.organizationId)
|
||||
.query({ resource_name: 'resource_name' })
|
||||
.send();
|
||||
|
||||
expect(res.status).equals(200);
|
||||
expect(res.body.views.length).equals(1);
|
||||
});
|
||||
});
|
||||
|
||||
describe('GET `/views/:id`', () => {
|
||||
it('Should response unauthorized in case the user was not authorized.', async () => {
|
||||
const resource = await tenantFactory.create('resource', { name: 'resource_name' });
|
||||
const resourceView = await tenantFactory.create('view', {
|
||||
name: 'Resource View',
|
||||
resource_id: resource.id,
|
||||
roles_logic_expression: '',
|
||||
});
|
||||
|
||||
const res = await request()
|
||||
.get(`/api/views/${resourceView.id}`)
|
||||
.query({ resource_name: 'resource_name' })
|
||||
.send();
|
||||
|
||||
expect(res.status).equals(401);
|
||||
expect(res.body.message).equals('Unauthorized');
|
||||
});
|
||||
|
||||
it('Should response not found in case the given view was not found.', async () => {
|
||||
const resource = await tenantFactory.create('resource', { name: 'resource_name' });
|
||||
const resourceView = await tenantFactory.create('view', {
|
||||
name: 'Resource View',
|
||||
resource_id: resource.id,
|
||||
roles_logic_expression: '',
|
||||
});
|
||||
|
||||
const res = await request()
|
||||
.get('/api/views/123')
|
||||
.set('x-access-token', loginRes.body.token)
|
||||
.set('organization-id', tenantWebsite.organizationId)
|
||||
.send();
|
||||
|
||||
expect(res.status).equals(404);
|
||||
expect(res.body.errors[0]).deep.equals({
|
||||
type: 'VIEW_NOT_FOUND', code: 100,
|
||||
});
|
||||
});
|
||||
|
||||
it('Should retrieve details of the given view with associated graphs.', async () => {
|
||||
const resource = await tenantFactory.create('resource', { name: 'resource_name' });
|
||||
const resourceView = await tenantFactory.create('view', {
|
||||
name: 'Resource View',
|
||||
resource_id: resource.id,
|
||||
roles_logic_expression: '1 AND 2',
|
||||
});
|
||||
const resourceField = await tenantFactory.create('resource_field', {
|
||||
label_name: 'Expense Account',
|
||||
key: 'expense_account',
|
||||
data_type: 'integer',
|
||||
resource_id: resource.id,
|
||||
active: true,
|
||||
predefined: true,
|
||||
builtin: true,
|
||||
});
|
||||
const viewRole = await tenantFactory.create('view_role', {
|
||||
view_id: resourceView.id,
|
||||
index: 1,
|
||||
field_id: resourceField.id,
|
||||
value: '12',
|
||||
comparator: 'equals',
|
||||
});
|
||||
|
||||
const res = await request()
|
||||
.get(`/api/views/${resourceView.id}`)
|
||||
.set('x-access-token', loginRes.body.token)
|
||||
.set('organization-id', tenantWebsite.organizationId)
|
||||
.send();
|
||||
|
||||
expect(res.status).equals(200);
|
||||
expect(res.body.view.name).equals(resourceView.name);
|
||||
expect(res.body.view.resource_id).equals(resourceView.resourceId);
|
||||
expect(res.body.view.roles_logic_expression).equals(resourceView.rolesLogicExpression);
|
||||
|
||||
expect(res.body.view.roles.length).equals(1);
|
||||
expect(res.body.view.roles[0].view_id).equals(viewRole.viewId);
|
||||
});
|
||||
});
|
||||
|
||||
describe('POST: `/views`', () => {
|
||||
it('Should response unauthorzied in case the user was not authorized.', async () => {
|
||||
const res = await request().post('/api/views');
|
||||
|
||||
expect(res.status).equals(401);
|
||||
expect(res.body.message).equals('Unauthorized');
|
||||
});
|
||||
|
||||
it('Should `name` be required.', async () => {
|
||||
await tenantFactory.create('resource');
|
||||
const res = await request()
|
||||
.post('/api/views')
|
||||
.set('x-access-token', loginRes.body.token)
|
||||
.set('organization-id', tenantWebsite.organizationId);
|
||||
|
||||
expect(res.status).equals(422);
|
||||
expect(res.body.code).equals('validation_error');
|
||||
expect(res.body.errors).include.something.deep.equals({
|
||||
msg: 'Invalid value', param: 'name', location: 'body',
|
||||
});
|
||||
});
|
||||
|
||||
it('Should `resource_name` be required.', async () => {
|
||||
await tenantFactory.create('resource');
|
||||
const res = await request()
|
||||
.post('/api/views')
|
||||
.set('x-access-token', loginRes.body.token)
|
||||
.set('organization-id', tenantWebsite.organizationId);
|
||||
|
||||
expect(res.status).equals(422);
|
||||
expect(res.body.code).equals('validation_error');
|
||||
expect(res.body.errors).include.something.deep.equals({
|
||||
msg: 'Invalid value', param: 'resource_name', location: 'body',
|
||||
});
|
||||
});
|
||||
|
||||
it('Should `columns` be minimum limited', async () => {
|
||||
await tenantFactory.create('resource');
|
||||
const res = await request()
|
||||
.post('/api/views', {
|
||||
label: 'View Label',
|
||||
columns: [],
|
||||
})
|
||||
.set('x-access-token', loginRes.body.token)
|
||||
.set('organization-id', tenantWebsite.organizationId);
|
||||
|
||||
expect(res.status).equals(422);
|
||||
expect(res.body.code).equals('validation_error');
|
||||
expect(res.body.errors).include.something.deep.equals({
|
||||
msg: 'Invalid value', param: 'columns', location: 'body',
|
||||
});
|
||||
});
|
||||
|
||||
it('Should `columns` be array.', async () => {
|
||||
await tenantFactory.create('resource');
|
||||
const res = await request()
|
||||
.post('/api/views', {
|
||||
label: 'View Label',
|
||||
columns: 'not_array',
|
||||
})
|
||||
.set('x-access-token', loginRes.body.token)
|
||||
.set('organization-id', tenantWebsite.organizationId);
|
||||
|
||||
expect(res.status).equals(422);
|
||||
expect(res.body.code).equals('validation_error');
|
||||
expect(res.body.errors).include.something.deep.equals({
|
||||
msg: 'Invalid value', param: 'columns', location: 'body',
|
||||
});
|
||||
});
|
||||
|
||||
it('Should `roles.*.field_key` be required.', async () => {
|
||||
const resource = await tenantFactory.create('resource');
|
||||
const res = await request()
|
||||
.post('/api/views')
|
||||
.set('x-access-token', loginRes.body.token)
|
||||
.set('organization-id', tenantWebsite.organizationId)
|
||||
.send({
|
||||
resource_name: resource.name,
|
||||
label: 'View Label',
|
||||
roles: [{}],
|
||||
});
|
||||
|
||||
expect(res.status).equals(422);
|
||||
expect(res.body.code).equals('validation_error');
|
||||
expect(res.body.errors).include.something.deep.equals({
|
||||
msg: 'Invalid value', param: 'roles[0].field_key', location: 'body',
|
||||
});
|
||||
});
|
||||
|
||||
it('Should `roles.*.comparator` be valid.', async () => {
|
||||
const resource = await tenantFactory.create('resource');
|
||||
const res = await request()
|
||||
.post('/api/views')
|
||||
.set('x-access-token', loginRes.body.token)
|
||||
.set('organization-id', tenantWebsite.organizationId)
|
||||
.send({
|
||||
resource_name: resource.name,
|
||||
label: 'View Label',
|
||||
roles: [{}],
|
||||
});
|
||||
|
||||
expect(res.status).equals(422);
|
||||
expect(res.body.code).equals('validation_error');
|
||||
|
||||
const paramsErrors = res.body.errors.map((error) => error.param);
|
||||
expect(paramsErrors).to.include('roles[0].comparator');
|
||||
});
|
||||
|
||||
it('Should `roles.*.index` be number as integer.', async () => {
|
||||
const resource = await tenantFactory.create('resource');
|
||||
const res = await request()
|
||||
.post('/api/views')
|
||||
.send({
|
||||
resource_name: resource.name,
|
||||
label: 'View Label',
|
||||
roles: [
|
||||
{ index: 'not_numeric' },
|
||||
],
|
||||
})
|
||||
.set('x-access-token', loginRes.body.token)
|
||||
.set('organization-id', tenantWebsite.organizationId);
|
||||
|
||||
expect(res.status).equals(422);
|
||||
expect(res.body.code).equals('validation_error');
|
||||
expect(res.body.errors).include.something.deep.equals({
|
||||
value: 'not_numeric',
|
||||
msg: 'Invalid value',
|
||||
param: 'roles[0].index',
|
||||
location: 'body',
|
||||
});
|
||||
});
|
||||
|
||||
it('Should response not found in case resource was not exist.', async () => {
|
||||
const res = await request()
|
||||
.post('/api/views')
|
||||
.set('x-access-token', loginRes.body.token)
|
||||
.set('organization-id', tenantWebsite.organizationId)
|
||||
.send({
|
||||
resource_name: 'not_found',
|
||||
name: 'View Label',
|
||||
columns: [
|
||||
{ key: 'amount', index: 1 },
|
||||
{ key: 'thumbnail', index: 1 },
|
||||
{ key: 'status', index: 1 },
|
||||
],
|
||||
roles: [{
|
||||
index: 1,
|
||||
field_key: 'amount',
|
||||
comparator: 'equals',
|
||||
value: '100',
|
||||
}],
|
||||
logic_expression: '1',
|
||||
});
|
||||
|
||||
expect(res.status).equals(404);
|
||||
expect(res.body.errors).include.something.that.deep.equals({
|
||||
type: 'RESOURCE_NOT_FOUND', code: 100,
|
||||
});
|
||||
});
|
||||
|
||||
it('Should response invalid logic expression.', async () =>{
|
||||
const resource = await tenantFactory.create('resource');
|
||||
await tenantFactory.create('resource_field', {
|
||||
resource_id: resource.id,
|
||||
label_name: 'Amount',
|
||||
key: 'amount',
|
||||
});
|
||||
const res = await request()
|
||||
.post('/api/views')
|
||||
.set('x-access-token', loginRes.body.token)
|
||||
.set('organization-id', tenantWebsite.organizationId)
|
||||
.send({
|
||||
resource_name: resource.name,
|
||||
logic_expression: '100 && 100',
|
||||
name: 'View Label',
|
||||
columns: [
|
||||
{ key: 'amount', index: 1 },
|
||||
],
|
||||
roles: [{
|
||||
index: 1,
|
||||
field_key: 'amount',
|
||||
comparator: 'equals',
|
||||
value: '100',
|
||||
}],
|
||||
});
|
||||
|
||||
expect(res.body.errors).include.something.that.deep.equals({
|
||||
type: 'VIEW.ROLES.LOGIC.EXPRESSION.INVALID', code: 400,
|
||||
});
|
||||
});
|
||||
|
||||
it('Should response the roles fields not exist in case role field was not exist.', async () => {
|
||||
const resource = await tenantFactory.create('resource');
|
||||
await tenantFactory.create('resource_field', { resource_id: resource.id, label_name: 'Amount' });
|
||||
|
||||
const res = await request()
|
||||
.post('/api/views')
|
||||
.set('x-access-token', loginRes.body.token)
|
||||
.set('organization-id', tenantWebsite.organizationId)
|
||||
.send({
|
||||
resource_name: resource.name,
|
||||
name: 'View Label',
|
||||
logic_expression: '1',
|
||||
columns: [
|
||||
{ key: 'amount', index: 1 },
|
||||
{ key: 'thumbnail', index: 1 },
|
||||
{ key: 'status', index: 1 },
|
||||
],
|
||||
roles: [{
|
||||
index: 1,
|
||||
field_key: 'price',
|
||||
comparator: 'equals',
|
||||
value: '100',
|
||||
}],
|
||||
});
|
||||
|
||||
expect(res.body.errors).include.something.that.deep.equals({
|
||||
type: 'RESOURCE_FIELDS_NOT_EXIST', code: 100, fields: ['price'],
|
||||
});
|
||||
});
|
||||
|
||||
it('Should response the columns that not exists in case column was not exist.', async () => {
|
||||
const resource = await tenantFactory.create('resource');
|
||||
const resourceField = await tenantFactory.create('resource_field', {
|
||||
resource_id: resource.id,
|
||||
label_name: 'Amount',
|
||||
key: 'amount',
|
||||
});
|
||||
const res = await request()
|
||||
.post('/api/views')
|
||||
.set('x-access-token', loginRes.body.token)
|
||||
.set('organization-id', tenantWebsite.organizationId)
|
||||
.send({
|
||||
resource_name: resource.name,
|
||||
name: 'View Label',
|
||||
logic_expression: '1',
|
||||
columns: [
|
||||
{ key: 'amount', index: 1 },
|
||||
{ key: 'thumbnail', index: 2 },
|
||||
{ key: 'status', index: 3 },
|
||||
],
|
||||
roles: [{
|
||||
index: 1,
|
||||
field_key: 'price',
|
||||
comparator: 'equals',
|
||||
value: '100',
|
||||
}],
|
||||
});
|
||||
|
||||
expect(res.body.errors).include.something.that.deep.equals({
|
||||
type: 'COLUMNS_NOT_EXIST', code: 200, columns: ['thumbnail', 'status'],
|
||||
});
|
||||
});
|
||||
|
||||
it('Should save the given details of the view.', async () => {
|
||||
const resource = await tenantFactory.create('resource');
|
||||
await tenantFactory.create('resource_field', {
|
||||
resource_id: resource.id,
|
||||
label_name: 'Amount',
|
||||
key: 'amount',
|
||||
});
|
||||
const res = await request()
|
||||
.post('/api/views')
|
||||
.set('x-access-token', loginRes.body.token)
|
||||
.set('organization-id', tenantWebsite.organizationId)
|
||||
.send({
|
||||
resource_name: resource.name,
|
||||
name: 'View Label',
|
||||
logic_expression: '1',
|
||||
columns: [
|
||||
{ key: 'amount', index: 1 },
|
||||
],
|
||||
roles: [{
|
||||
index: 1,
|
||||
field_key: 'amount',
|
||||
comparator: 'equals',
|
||||
value: '100',
|
||||
}],
|
||||
});
|
||||
|
||||
const storedView = await View.tenant().query().where('name', 'View Label').first();
|
||||
|
||||
expect(storedView.name).equals('View Label');
|
||||
expect(storedView.predefined).equals(0);
|
||||
expect(storedView.resourceId).equals(resource.id);
|
||||
});
|
||||
|
||||
it('Should save the given details of view fields that associated to the given view id.', async () => {
|
||||
const resource = await tenantFactory.create('resource');
|
||||
const resourceField = await tenantFactory.create('resource_field', {
|
||||
resource_id: resource.id,
|
||||
label_name: 'Amount',
|
||||
key: 'amount',
|
||||
});
|
||||
|
||||
const res = await request()
|
||||
.post('/api/views')
|
||||
.set('x-access-token', loginRes.body.token)
|
||||
.set('organization-id', tenantWebsite.organizationId)
|
||||
.send({
|
||||
resource_name: resource.name,
|
||||
name: 'View Label',
|
||||
columns: [{ key: 'amount', index: 1 }],
|
||||
logic_expression: '1',
|
||||
roles: [{
|
||||
index: 1,
|
||||
field_key: 'amount',
|
||||
comparator: 'equals',
|
||||
value: '100',
|
||||
}],
|
||||
});
|
||||
|
||||
const viewRoles = await ViewRole.tenant().query().where('view_id', res.body.id);
|
||||
|
||||
expect(viewRoles.length).equals(1);
|
||||
expect(viewRoles[0].index).equals(1);
|
||||
expect(viewRoles[0].fieldId).equals(resourceField.id);
|
||||
expect(viewRoles[0].value).equals('100');
|
||||
expect(viewRoles[0].comparator).equals('equals');
|
||||
});
|
||||
|
||||
it('Should save columns that associated to the given view.', async () => {
|
||||
const resource = await tenantFactory.create('resource');
|
||||
const resourceField = await tenantFactory.create('resource_field', {
|
||||
resource_id: resource.id,
|
||||
label_name: 'Amount',
|
||||
key: 'amount',
|
||||
});
|
||||
|
||||
const res = await request()
|
||||
.post('/api/views')
|
||||
.set('x-access-token', loginRes.body.token)
|
||||
.set('organization-id', tenantWebsite.organizationId)
|
||||
.send({
|
||||
resource_name: resource.name,
|
||||
name: 'View Label',
|
||||
logic_expression: '1',
|
||||
columns: [
|
||||
{ key: 'amount', index: 1 },
|
||||
],
|
||||
roles: [{
|
||||
index: 1,
|
||||
field_key: 'amount',
|
||||
comparator: 'equals',
|
||||
value: '100',
|
||||
}],
|
||||
});
|
||||
|
||||
const viewColumns = await ViewColumn.tenant().query().where('view_id', res.body.id);
|
||||
expect(viewColumns.length).equals(1);
|
||||
});
|
||||
|
||||
|
||||
});
|
||||
|
||||
describe('POST: `/views/:view_id`', () => {
|
||||
it('Should `name` be required.', async () => {
|
||||
const view = await tenantFactory.create('view');
|
||||
const res = await request()
|
||||
.post(`/api/views/${view.id}`)
|
||||
.set('x-access-token', loginRes.body.token)
|
||||
.set('organization-id', tenantWebsite.organizationId)
|
||||
.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: 'name', location: 'body',
|
||||
});
|
||||
});
|
||||
|
||||
it('Should columns be minimum limited', async () => {
|
||||
const view = await tenantFactory.create('view');
|
||||
const res = await request()
|
||||
.post(`/api/views/${view.id}`, {
|
||||
label: 'View Label',
|
||||
columns: [],
|
||||
})
|
||||
.set('x-access-token', loginRes.body.token)
|
||||
.set('organization-id', tenantWebsite.organizationId)
|
||||
.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: 'columns', location: 'body',
|
||||
});
|
||||
});
|
||||
|
||||
it('Should columns be array.', async () => {
|
||||
const view = await tenantFactory.create('view');
|
||||
const res = await request()
|
||||
.post(`/api/views/${view.id}`, {
|
||||
label: 'View Label',
|
||||
columns: 'not_array',
|
||||
})
|
||||
.set('x-access-token', loginRes.body.token)
|
||||
.set('organization-id', tenantWebsite.organizationId)
|
||||
.send({
|
||||
columns: 'columns'
|
||||
});
|
||||
|
||||
expect(res.status).equals(422);
|
||||
expect(res.body.code).equals('validation_error');
|
||||
expect(res.body.errors).include.something.deep.equals({
|
||||
msg: 'Invalid value', param: 'columns', location: 'body', value: 'columns',
|
||||
});
|
||||
});
|
||||
|
||||
it('Should `roles.*.field_key` be required.', async () => {
|
||||
const view = await tenantFactory.create('view');
|
||||
const res = await request()
|
||||
.post(`/api/views/${view.id}`)
|
||||
.set('x-access-token', loginRes.body.token)
|
||||
.set('organization-id', tenantWebsite.organizationId)
|
||||
.send({
|
||||
label: 'View Label',
|
||||
roles: [{}],
|
||||
});
|
||||
|
||||
expect(res.status).equals(422);
|
||||
expect(res.body.code).equals('validation_error');
|
||||
expect(res.body.errors).include.something.deep.equals({
|
||||
msg: 'Invalid value', param: 'roles[0].field_key', location: 'body',
|
||||
});
|
||||
});
|
||||
|
||||
it('Should `roles.*.comparator` be required.', async () => {
|
||||
const view = await tenantFactory.create('view');
|
||||
const res = await request()
|
||||
.post(`/api/views/${view.id}`)
|
||||
.set('x-access-token', loginRes.body.token)
|
||||
.set('organization-id', tenantWebsite.organizationId)
|
||||
.send({
|
||||
label: 'View Label',
|
||||
roles: [{}],
|
||||
});
|
||||
|
||||
expect(res.status).equals(422);
|
||||
expect(res.body.code).equals('validation_error');
|
||||
expect(res.body.errors).include.something.deep.equals({
|
||||
msg: 'Invalid value', param: 'roles[0].comparator', location: 'body',
|
||||
});
|
||||
});
|
||||
|
||||
it('Should `roles.*.index` be number as integer.', async () => {
|
||||
const view = await tenantFactory.create('view');
|
||||
const res = await request()
|
||||
.post(`/api/views/${view.id}`)
|
||||
.set('x-access-token', loginRes.body.token)
|
||||
.set('organization-id', tenantWebsite.organizationId)
|
||||
.send({
|
||||
label: 'View Label',
|
||||
roles: [{ index: 'not_numeric' }],
|
||||
});
|
||||
|
||||
expect(res.status).equals(422);
|
||||
expect(res.body.code).equals('validation_error');
|
||||
expect(res.body.errors).include.something.deep.equals({
|
||||
msg: 'Invalid value',
|
||||
param: 'roles[0].index',
|
||||
location: 'body',
|
||||
value: 'not_numeric',
|
||||
});
|
||||
});
|
||||
|
||||
it('Should response the roles fields not exist in case role field was not exist.', async () => {
|
||||
const view = await tenantFactory.create('view');
|
||||
await tenantFactory.create('resource_field', {
|
||||
resource_id: view.resource_id,
|
||||
label_name: 'Amount',
|
||||
});
|
||||
const res = await request()
|
||||
.post(`/api/views/${view.id}`)
|
||||
.set('x-access-token', loginRes.body.token)
|
||||
.set('organization-id', tenantWebsite.organizationId)
|
||||
.send({
|
||||
name: 'View Label',
|
||||
logic_expression: '1',
|
||||
columns: [{
|
||||
key: 'amount',
|
||||
index: 1,
|
||||
}, {
|
||||
key: 'thumbnail',
|
||||
index: 2,
|
||||
}, {
|
||||
key: 'status',
|
||||
index: 3,
|
||||
}],
|
||||
roles: [{
|
||||
index: 1,
|
||||
field_key: 'price',
|
||||
comparator: 'equals',
|
||||
value: '100',
|
||||
}],
|
||||
});
|
||||
expect(res.body.errors).include.something.that.deep.equals({
|
||||
type: 'RESOURCE_FIELDS_NOT_EXIST', code: 100, fields: ['price'],
|
||||
});
|
||||
});
|
||||
|
||||
it('Should response the resource columns not exists in case the column keys was not exist.', async () => {
|
||||
const view = await tenantFactory.create('view');
|
||||
await tenantFactory.create('resource_field', {
|
||||
resource_id: view.resource_id,
|
||||
label_name: 'Amount',
|
||||
});
|
||||
const res = await request()
|
||||
.post(`/api/views/${view.id}`)
|
||||
.set('x-access-token', loginRes.body.token)
|
||||
.set('organization-id', tenantWebsite.organizationId)
|
||||
.send({
|
||||
name: 'View Label',
|
||||
logic_expression: '1',
|
||||
columns: [{
|
||||
key: 'amount',
|
||||
index: 1,
|
||||
}, {
|
||||
key: 'thumbnail',
|
||||
index: 2,
|
||||
}, {
|
||||
key: 'status',
|
||||
index: 3,
|
||||
}],
|
||||
roles: [{
|
||||
index: 1,
|
||||
field_key: 'price',
|
||||
comparator: 'equals',
|
||||
value: '100',
|
||||
}],
|
||||
});
|
||||
expect(res.body.errors).include.something.that.deep.equals({
|
||||
type: 'RESOURCE_COLUMNS_NOT_EXIST',
|
||||
code: 200,
|
||||
columns: ['amount', 'thumbnail', 'status'],
|
||||
});
|
||||
});
|
||||
|
||||
it('Should validate the logic expressions with the given conditions.', () => {
|
||||
|
||||
});
|
||||
|
||||
it('Should delete the view roles that not presented the post data.', async () => {
|
||||
const resource = await tenantFactory.create('resource');
|
||||
const resourceField = await tenantFactory.create('resource_field', {
|
||||
resource_id: resource.id,
|
||||
label_name: 'Amount',
|
||||
key: 'amount',
|
||||
});
|
||||
|
||||
const view = await tenantFactory.create('view', { resource_id: resource.id });
|
||||
const viewRole = await tenantFactory.create('view_role', {
|
||||
view_id: view.id,
|
||||
field_id: resourceField.id,
|
||||
});
|
||||
const res = await request()
|
||||
.post(`/api/views/${view.id}`)
|
||||
.set('x-access-token', loginRes.body.token)
|
||||
.set('organization-id', tenantWebsite.organizationId)
|
||||
.send({
|
||||
name: 'View Label',
|
||||
logic_expression: '1',
|
||||
columns: [{
|
||||
key: resourceField.key,
|
||||
index: 1,
|
||||
}],
|
||||
roles: [{
|
||||
index: 1,
|
||||
field_key: resourceField.key,
|
||||
comparator: 'equals',
|
||||
value: '100',
|
||||
}],
|
||||
});
|
||||
|
||||
const foundViewRole = await ViewRole.tenant().query().where('id', viewRole.id);
|
||||
expect(foundViewRole.length).equals(0);
|
||||
});
|
||||
|
||||
it('Should update the view roles that presented in the given data.', async () => {
|
||||
const resource = await tenantFactory.create('resource');
|
||||
const resourceField = await tenantFactory.create('resource_field', {
|
||||
resource_id: resource.id,
|
||||
label_name: 'Amount',
|
||||
key: 'amount',
|
||||
});
|
||||
|
||||
const view = await tenantFactory.create('view', { resource_id: resource.id });
|
||||
const viewRole = await tenantFactory.create('view_role', {
|
||||
view_id: view.id,
|
||||
field_id: resourceField.id,
|
||||
});
|
||||
const res = await request()
|
||||
.post(`/api/views/${view.id}`)
|
||||
.set('x-access-token', loginRes.body.token)
|
||||
.set('organization-id', tenantWebsite.organizationId)
|
||||
.send({
|
||||
name: 'View Label',
|
||||
logic_expression: '1',
|
||||
columns: [{
|
||||
key: resourceField.key,
|
||||
index: 1,
|
||||
}],
|
||||
roles: [{
|
||||
id: viewRole.id,
|
||||
index: 1,
|
||||
field_key: resourceField.key,
|
||||
comparator: 'equals',
|
||||
value: '100',
|
||||
}],
|
||||
});
|
||||
|
||||
const foundViewRole = await ViewRole.tenant().query().where('id', viewRole.id);
|
||||
|
||||
expect(foundViewRole.length).equals(1);
|
||||
expect(foundViewRole[0].id).equals(viewRole.id);
|
||||
expect(foundViewRole[0].index).equals(1);
|
||||
expect(foundViewRole[0].value).equals('100');
|
||||
expect(foundViewRole[0].comparator).equals('equals');
|
||||
});
|
||||
|
||||
it('Should response not found roles ids in case not exists in the storage.', async () => {
|
||||
const resource = await tenantFactory.create('resource');
|
||||
const resourceField = await tenantFactory.create('resource_field', {
|
||||
resource_id: resource.id,
|
||||
label_name: 'Amount',
|
||||
key: 'amount',
|
||||
});
|
||||
const view = await tenantFactory.create('view', { resource_id: resource.id });
|
||||
|
||||
const res = await request()
|
||||
.post(`/api/views/${view.id}`)
|
||||
.set('x-access-token', loginRes.body.token)
|
||||
.set('organization-id', tenantWebsite.organizationId)
|
||||
.send({
|
||||
name: 'View Label',
|
||||
logic_expression: '1',
|
||||
columns: [{
|
||||
key: resourceField.key,
|
||||
index: 1,
|
||||
}],
|
||||
roles: [{
|
||||
id: 1,
|
||||
index: 1,
|
||||
field_key: resourceField.key,
|
||||
comparator: 'equals',
|
||||
value: '100',
|
||||
}],
|
||||
});
|
||||
|
||||
expect(res.body.errors).include.something.that.deep.equals({
|
||||
type: 'VIEW.ROLES.IDS.NOT.FOUND', code: 500, ids: [1],
|
||||
});
|
||||
});
|
||||
|
||||
it('Should delete columns from storage in case view columns ids not presented.', async () => {
|
||||
const resource = await tenantFactory.create('resource');
|
||||
const resourceField = await tenantFactory.create('resource_field', {
|
||||
resource_id: resource.id,
|
||||
label_name: 'Amount',
|
||||
key: 'amount',
|
||||
});
|
||||
const view = await tenantFactory.create('view', { resource_id: resource.id });
|
||||
const viewColumn = await tenantFactory.create('view_column', { view_id: view.id });
|
||||
|
||||
const res = await request()
|
||||
.post(`/api/views/${view.id}`)
|
||||
.set('x-access-token', loginRes.body.token)
|
||||
.set('organization-id', tenantWebsite.organizationId)
|
||||
.send({
|
||||
name: 'View Label',
|
||||
logic_expression: '1',
|
||||
columns: [{
|
||||
key: resourceField.key,
|
||||
index: 1,
|
||||
}],
|
||||
roles: [{
|
||||
index: 1,
|
||||
field_key: resourceField.key,
|
||||
comparator: 'equals',
|
||||
value: '100',
|
||||
}],
|
||||
});
|
||||
const foundViewColumns = await ViewColumn.tenant().query().where('id', viewColumn.id);
|
||||
expect(foundViewColumns.length).equals(0);
|
||||
});
|
||||
|
||||
it('Should insert columns to the storage if where new columns', async () => {
|
||||
const resource = await tenantFactory.create('resource');
|
||||
const resourceField = await tenantFactory.create('resource_field', {
|
||||
resource_id: resource.id,
|
||||
label_name: 'Amount',
|
||||
key: 'amount',
|
||||
});
|
||||
const view = await tenantFactory.create('view', { resource_id: resource.id });
|
||||
|
||||
const res = await request()
|
||||
.post(`/api/views/${view.id}`)
|
||||
.set('x-access-token', loginRes.body.token)
|
||||
.set('organization-id', tenantWebsite.organizationId)
|
||||
.send({
|
||||
name: 'View Label',
|
||||
logic_expression: '1',
|
||||
columns: [{
|
||||
key: resourceField.key,
|
||||
index: 1,
|
||||
}],
|
||||
roles: [{
|
||||
index: 1,
|
||||
field_key: resourceField.key,
|
||||
comparator: 'equals',
|
||||
value: '100',
|
||||
}],
|
||||
});
|
||||
|
||||
const foundViewColumns = await ViewColumn.tenant().query().where('view_id', view.id);
|
||||
|
||||
expect(foundViewColumns.length).equals(1);
|
||||
expect(foundViewColumns[0].viewId).equals(view.id);
|
||||
expect(foundViewColumns[0].index).equals(1);
|
||||
expect(foundViewColumns[0].fieldId).equals(resourceField.id);
|
||||
});
|
||||
|
||||
|
||||
it('Should update columns on the storage.', async () => {
|
||||
const resource = await tenantFactory.create('resource');
|
||||
const resourceField = await tenantFactory.create('resource_field', {
|
||||
resource_id: resource.id,
|
||||
label_name: 'Amount',
|
||||
key: 'amount',
|
||||
});
|
||||
const view = await tenantFactory.create('view', { resource_id: resource.id });
|
||||
const viewColumn = await tenantFactory.create('view_column', { view_id: view.id });
|
||||
|
||||
const res = await request()
|
||||
.post(`/api/views/${view.id}`)
|
||||
.set('x-access-token', loginRes.body.token)
|
||||
.set('organization-id', tenantWebsite.organizationId)
|
||||
.send({
|
||||
name: 'View Label',
|
||||
logic_expression: '1',
|
||||
columns: [{
|
||||
id: viewColumn.id,
|
||||
key: resourceField.key,
|
||||
index: 10,
|
||||
}],
|
||||
roles: [{
|
||||
index: 1,
|
||||
field_key: resourceField.key,
|
||||
comparator: 'equals',
|
||||
value: '100',
|
||||
}],
|
||||
});
|
||||
|
||||
console.log(res.body)
|
||||
|
||||
const foundViewColumns = await ViewColumn.tenant().query().where('id', viewColumn.id);
|
||||
|
||||
expect(foundViewColumns.length).equals(1);
|
||||
expect(foundViewColumns[0].id).equals(viewColumn.id);
|
||||
expect(foundViewColumns[0].viewId).equals(view.id);
|
||||
expect(foundViewColumns[0].index).equals(10);
|
||||
// expect(foundViewColumns[0].fieldId).equals();
|
||||
})
|
||||
});
|
||||
|
||||
describe('DELETE: `/views/:resource_id`', () => {
|
||||
it('Should not delete predefined view.', async () => {
|
||||
const view = await tenantFactory.create('view', { predefined: true });
|
||||
const res = await request()
|
||||
.delete(`/api/views/${view.id}`)
|
||||
.set('x-access-token', loginRes.body.token)
|
||||
.set('organization-id', tenantWebsite.organizationId)
|
||||
.send();
|
||||
|
||||
expect(res.status).equals(400);
|
||||
expect(res.body.errors).include.something.that.deep.equals({
|
||||
type: 'PREDEFINED_VIEW', code: 200,
|
||||
});
|
||||
});
|
||||
|
||||
it('Should response not found in case view was not exist.', async () => {
|
||||
const res = await request()
|
||||
.delete('/api/views/100')
|
||||
.set('x-access-token', loginRes.body.token)
|
||||
.set('organization-id', tenantWebsite.organizationId)
|
||||
.send();
|
||||
|
||||
expect(res.status).equals(404);
|
||||
expect(res.body.errors).include.something.that.deep.equals({
|
||||
type: 'VIEW_NOT_FOUND', code: 100,
|
||||
});
|
||||
});
|
||||
|
||||
it('Should delete the given view and associated view columns and roles.', async () => {
|
||||
const view = await tenantFactory.create('view', { predefined: false });
|
||||
await tenantFactory.create('view_role', { view_id: view.id });
|
||||
await tenantFactory.create('view_column', { view_id: view.id });
|
||||
|
||||
const res = await request()
|
||||
.delete(`/api/views/${view.id}`)
|
||||
.set('x-access-token', loginRes.body.token)
|
||||
.set('organization-id', tenantWebsite.organizationId)
|
||||
.send();
|
||||
|
||||
expect(res.body.id).equals(view.id);
|
||||
|
||||
const foundViews = await View.tenant().query().where('id', view.id);
|
||||
const foundViewRoles = await ViewRole.tenant().query().where('view_id', view.id);
|
||||
|
||||
expect(foundViews).to.have.lengthOf(0);
|
||||
expect(foundViewRoles).to.have.lengthOf(0);
|
||||
});
|
||||
});
|
||||
});
|
||||
406
packages/server/tests/services/JournalPoster.test.js
Normal file
406
packages/server/tests/services/JournalPoster.test.js
Normal file
@@ -0,0 +1,406 @@
|
||||
import { expect } from '~/testInit';
|
||||
import JournalPoster from '@/services/Accounting/JournalPoster';
|
||||
import JournalEntry from '@/services/Accounting/JournalEntry';
|
||||
import AccountBalance from 'models/AccountBalance';
|
||||
import AccountTransaction from 'models/AccountTransaction';
|
||||
import Account from 'models/Account';
|
||||
import {
|
||||
tenantWebsite,
|
||||
tenantFactory,
|
||||
loginRes
|
||||
} from '~/dbInit';
|
||||
import { omit } from 'lodash';
|
||||
import DependencyGraph from '@/lib/DependencyGraph';
|
||||
|
||||
let accountsDepGraph;
|
||||
|
||||
describe('JournalPoster', () => {
|
||||
beforeEach(async () => {
|
||||
accountsDepGraph = await Account.tenant().depGraph().query().remember();
|
||||
});
|
||||
describe('credit()', () => {
|
||||
it('Should write credit entry to journal entries stack.', () => {
|
||||
const journalEntries = new JournalPoster(accountsDepGraph);
|
||||
const journalEntry = new JournalEntry({
|
||||
referenceId: 1,
|
||||
referenceType: 'Expense',
|
||||
credit: 100,
|
||||
account: 1,
|
||||
});
|
||||
journalEntries.credit(journalEntry);
|
||||
expect(journalEntries.entries.length).equals(1);
|
||||
});
|
||||
});
|
||||
|
||||
describe('debit()', () => {
|
||||
it('Should write debit entry to journal entries stack.', () => {
|
||||
const journalEntries = new JournalPoster(accountsDepGraph);
|
||||
const journalEntry = new JournalEntry({
|
||||
referenceId: 1,
|
||||
referenceType: 'Expense',
|
||||
debit: 100,
|
||||
account: 1,
|
||||
});
|
||||
|
||||
journalEntries.debit(journalEntry);
|
||||
expect(journalEntries.entries.length).equals(1);
|
||||
});
|
||||
});
|
||||
|
||||
describe('setBalanceChange()', () => {
|
||||
it('Should increment balance amount after credit entry with credit normal account.', () => {
|
||||
const journalEntries = new JournalPoster(accountsDepGraph);
|
||||
const journalEntry = new JournalEntry({
|
||||
referenceId: 1,
|
||||
referenceType: 'Expense',
|
||||
credit: 100,
|
||||
debit: 0,
|
||||
account: 1,
|
||||
accountNormal: 'debit',
|
||||
});
|
||||
journalEntries.credit(journalEntry);
|
||||
expect(journalEntries.balancesChange).to.have.property(1, -100);
|
||||
});
|
||||
|
||||
it('Should decrement balance amount after debit entry wiht debit normal account.', () => {
|
||||
const journalEntries = new JournalPoster(accountsDepGraph);
|
||||
const journalEntry = new JournalEntry({
|
||||
referenceId: 1,
|
||||
referenceType: 'Expense',
|
||||
debit: 100,
|
||||
account: 1,
|
||||
accountNormal: 'debit',
|
||||
});
|
||||
journalEntries.debit(journalEntry);
|
||||
expect(journalEntries.balancesChange).to.have.property(1, 100);
|
||||
});
|
||||
});
|
||||
|
||||
describe('setContactAccountBalance', () => {
|
||||
it('Should increment balance amount after credit/debit entry.', () => {
|
||||
|
||||
});
|
||||
|
||||
it('Should decrement balance amount after credit/debit customer/vendor entry.', () => {
|
||||
|
||||
});
|
||||
});
|
||||
|
||||
describe('saveEntries()', () => {
|
||||
it('Should save all stacked entries to the storage.', async () => {
|
||||
const journalEntries = new JournalPoster(accountsDepGraph);
|
||||
const journalEntry = new JournalEntry({
|
||||
referenceId: 1,
|
||||
referenceType: 'Expense',
|
||||
debit: 100,
|
||||
account: 1,
|
||||
accountNormal: 'debit',
|
||||
});
|
||||
|
||||
journalEntries.debit(journalEntry);
|
||||
await journalEntries.saveEntries();
|
||||
|
||||
const storedJournalEntries = await AccountTransaction.tenant().query();
|
||||
|
||||
expect(storedJournalEntries.length).equals(1);
|
||||
expect(storedJournalEntries[0]).to.deep.include({
|
||||
referenceType: 'Expense',
|
||||
referenceId: 1,
|
||||
debit: 100,
|
||||
credit: 0,
|
||||
accountId: 1,
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('saveBalance()', () => {
|
||||
it('Should save account balance increment.', async () => {
|
||||
const account = await tenantFactory.create('account');
|
||||
const depGraph = await Account.tenant().depGraph().query();
|
||||
|
||||
const journalEntries = new JournalPoster(depGraph);
|
||||
const journalEntry = new JournalEntry({
|
||||
referenceId: 1,
|
||||
referenceType: 'Expense',
|
||||
debit: 100,
|
||||
account: account.id,
|
||||
accountNormal: 'debit',
|
||||
});
|
||||
journalEntries.debit(journalEntry);
|
||||
|
||||
await journalEntries.saveBalance();
|
||||
|
||||
const storedAccountBalance = await AccountBalance.tenant().query();
|
||||
|
||||
expect(storedAccountBalance.length).equals(1);
|
||||
expect(storedAccountBalance[0].amount).equals(100);
|
||||
});
|
||||
|
||||
it('Should save account balance decrement.', async () => {
|
||||
const account = await tenantFactory.create('account');
|
||||
const depGraph = await Account.tenant().depGraph().query();
|
||||
|
||||
const journalEntries = new JournalPoster(depGraph);
|
||||
const journalEntry = new JournalEntry({
|
||||
referenceId: 1,
|
||||
referenceType: 'Expense',
|
||||
credit: 100,
|
||||
account: account.id,
|
||||
accountNormal: 'debit',
|
||||
});
|
||||
journalEntries.credit(journalEntry);
|
||||
|
||||
await journalEntries.saveBalance();
|
||||
|
||||
const storedAccountBalance = await AccountBalance.tenant().query();
|
||||
|
||||
expect(storedAccountBalance.length).equals(1);
|
||||
expect(storedAccountBalance[0].amount).equals(-100);
|
||||
});
|
||||
});
|
||||
|
||||
describe('getClosingBalance', () => {
|
||||
it('Should retrieve closing balance the given account id.', () => {
|
||||
const journalEntries = new JournalPoster(accountsDepGraph);
|
||||
const journalEntry = new JournalEntry({
|
||||
referenceId: 1,
|
||||
referenceType: 'Expense',
|
||||
debit: 100,
|
||||
account: 1,
|
||||
accountNormal: 'debit',
|
||||
date: '2020-1-10',
|
||||
});
|
||||
const journalEntry2 = new JournalEntry({
|
||||
referenceId: 1,
|
||||
referenceType: 'Income',
|
||||
credit: 100,
|
||||
account: 2,
|
||||
accountNormal: 'credit',
|
||||
date: '2020-1-12',
|
||||
});
|
||||
journalEntries.credit(journalEntry);
|
||||
journalEntries.credit(journalEntry2);
|
||||
|
||||
const closingBalance = journalEntries.getClosingBalance(1, '2020-1-30');
|
||||
expect(closingBalance).equals(100);
|
||||
});
|
||||
|
||||
it('Should retrieve closing balance the given closing date period.', () => {
|
||||
const journalEntries = new JournalPoster(accountsDepGraph);
|
||||
const journalEntry = new JournalEntry({
|
||||
referenceId: 1,
|
||||
referenceType: 'Expense',
|
||||
debit: 100,
|
||||
account: 1,
|
||||
accountNormal: 'debit',
|
||||
date: '2020-1-10',
|
||||
});
|
||||
const journalEntry2 = new JournalEntry({
|
||||
referenceId: 1,
|
||||
referenceType: 'Income',
|
||||
credit: 100,
|
||||
account: 2,
|
||||
accountNormal: 'credit',
|
||||
date: '2020-1-12',
|
||||
});
|
||||
journalEntries.credit(journalEntry);
|
||||
journalEntries.credit(journalEntry2);
|
||||
|
||||
const closingBalance = journalEntries.getClosingBalance(1, '2020-1-2');
|
||||
expect(closingBalance).equals(0);
|
||||
});
|
||||
});
|
||||
|
||||
describe('getTrialBalance(account, closeDate, dateType)', () => {
|
||||
it('Should retrieve the trial balance of the given account id.', () => {
|
||||
const journalEntries = new JournalPoster(accountsDepGraph);
|
||||
const journalEntry = new JournalEntry({
|
||||
referenceId: 1,
|
||||
referenceType: 'Expense',
|
||||
debit: 200,
|
||||
account: 1,
|
||||
accountNormal: 'debit',
|
||||
date: '2020-1-10',
|
||||
});
|
||||
const journalEntry2 = new JournalEntry({
|
||||
referenceId: 1,
|
||||
referenceType: 'Income',
|
||||
credit: 100,
|
||||
account: 1,
|
||||
accountNormal: 'credit',
|
||||
date: '2020-1-12',
|
||||
});
|
||||
|
||||
journalEntries.debit(journalEntry);
|
||||
journalEntries.credit(journalEntry2);
|
||||
|
||||
const trialBalance = journalEntries.getTrialBalance(1);
|
||||
|
||||
expect(trialBalance.credit).equals(100);
|
||||
expect(trialBalance.debit).equals(200);
|
||||
});
|
||||
});
|
||||
|
||||
describe('groupingEntriesByDate(accountId, dateGroupType)', () => {
|
||||
|
||||
});
|
||||
|
||||
describe('removeEntries', () => {
|
||||
it('Should remove all entries in the collection.', () => {
|
||||
const journalPoster = new JournalPoster(accountsDepGraph);
|
||||
const journalEntry1 = new JournalEntry({
|
||||
id: 1,
|
||||
credit: 1000,
|
||||
account: 1,
|
||||
accountNormal: 'credit',
|
||||
});
|
||||
const journalEntry2 = new JournalEntry({
|
||||
id: 2,
|
||||
debit: 1000,
|
||||
account: 2,
|
||||
accountNormal: 'debit',
|
||||
});
|
||||
journalPoster.credit(journalEntry1);
|
||||
journalPoster.debit(journalEntry2);
|
||||
|
||||
journalPoster.removeEntries();
|
||||
|
||||
expect(journalPoster.entries.length).equals(0);
|
||||
});
|
||||
|
||||
it('Should remove the given entries ids from the collection.', () => {
|
||||
const journalPoster = new JournalPoster(accountsDepGraph);
|
||||
const journalEntry1 = new JournalEntry({
|
||||
id: 1,
|
||||
credit: 1000,
|
||||
account: 1,
|
||||
accountNormal: 'credit',
|
||||
});
|
||||
const journalEntry2 = new JournalEntry({
|
||||
id: 2,
|
||||
debit: 1000,
|
||||
account: 2,
|
||||
accountNormal: 'debit',
|
||||
});
|
||||
journalPoster.credit(journalEntry1);
|
||||
journalPoster.debit(journalEntry2);
|
||||
|
||||
journalPoster.removeEntries([1]);
|
||||
expect(journalPoster.entries.length).equals(1);
|
||||
});
|
||||
|
||||
it('Should the removed entries ids be stacked to deleted entries ids.', () => {
|
||||
const journalPoster = new JournalPoster(accountsDepGraph);
|
||||
const journalEntry1 = new JournalEntry({
|
||||
id: 1,
|
||||
credit: 1000,
|
||||
account: 1,
|
||||
accountNormal: 'credit',
|
||||
});
|
||||
const journalEntry2 = new JournalEntry({
|
||||
id: 2,
|
||||
debit: 1000,
|
||||
account: 2,
|
||||
accountNormal: 'debit',
|
||||
});
|
||||
journalPoster.credit(journalEntry1);
|
||||
journalPoster.debit(journalEntry2);
|
||||
|
||||
journalPoster.removeEntries();
|
||||
|
||||
expect(journalPoster.deletedEntriesIds.length).equals(2);
|
||||
expect(journalPoster.deletedEntriesIds[0]).equals(1);
|
||||
expect(journalPoster.deletedEntriesIds[1]).equals(2);
|
||||
});
|
||||
|
||||
it('Should revert the account balance after remove the entries.', () => {
|
||||
const journalPoster = new JournalPoster(accountsDepGraph);
|
||||
const journalEntry1 = new JournalEntry({
|
||||
id: 1,
|
||||
credit: 1000,
|
||||
account: 1,
|
||||
accountNormal: 'credit',
|
||||
});
|
||||
const journalEntry2 = new JournalEntry({
|
||||
id: 2,
|
||||
debit: 1000,
|
||||
account: 2,
|
||||
accountNormal: 'debit',
|
||||
});
|
||||
journalPoster.credit(journalEntry1);
|
||||
journalPoster.debit(journalEntry2);
|
||||
|
||||
journalPoster.removeEntries([1]);
|
||||
|
||||
expect(journalPoster.balancesChange['1']).equals(0);
|
||||
expect(journalPoster.balancesChange['2']).equals(1000);
|
||||
})
|
||||
});
|
||||
|
||||
describe('deleteEntries', () => {
|
||||
it('Should delete all entries from the storage based on the stacked deleted entries ids.', () => {
|
||||
|
||||
});
|
||||
});
|
||||
|
||||
describe('effectParentAccountsBalance()', () => {
|
||||
it('Should all parent accounts increment after one of child accounts balance increment.', async () => {
|
||||
const debitType = await tenantFactory.create('account_type', { normal: 'debit', balance_sheet: true });
|
||||
const mixin = { account_type_id: debitType.id };
|
||||
|
||||
const accountA = await tenantFactory.create('account', { ...mixin });
|
||||
const accountB = await tenantFactory.create('account', { ...mixin });
|
||||
|
||||
const accountAC = await tenantFactory.create('account', { parent_account_id: accountA.id, ...mixin });
|
||||
const accountBD = await tenantFactory.create('account', { ...mixin });
|
||||
|
||||
const depGraph = await Account.tenant().depGraph().query();
|
||||
const journalPoster = new JournalPoster(depGraph);
|
||||
const journalEntryA = new JournalEntry({
|
||||
id: 1,
|
||||
debit: 1000,
|
||||
account: accountAC.id,
|
||||
accountNormal: 'debit',
|
||||
});
|
||||
const journalEntryB = new JournalEntry({
|
||||
id: 1,
|
||||
debit: 1000,
|
||||
account: accountBD.id,
|
||||
accountNormal: 'debit',
|
||||
});
|
||||
|
||||
journalPoster.debit(journalEntryA);
|
||||
journalPoster.debit(journalEntryB);
|
||||
|
||||
await journalPoster.saveBalance();
|
||||
|
||||
const accountBalances = await AccountBalance.tenant().query();
|
||||
const simplifiedArray = accountBalances.map(x => ({ ...omit(x, ['id']) }));
|
||||
|
||||
expect(simplifiedArray.length).equals(3);
|
||||
expect(simplifiedArray).to.include.something.deep.equals({
|
||||
accountId: accountA.id,
|
||||
amount: 1000,
|
||||
currencyCode: 'USD'
|
||||
});
|
||||
expect(simplifiedArray).to.include.something.deep.equals({
|
||||
accountId: accountAC.id,
|
||||
amount: 1000,
|
||||
currencyCode: 'USD'
|
||||
});
|
||||
expect(simplifiedArray).to.include.something.deep.equals({
|
||||
accountId: accountBD.id,
|
||||
amount: 1000,
|
||||
currencyCode: 'USD'
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('reverseEntries()', () => {
|
||||
|
||||
});
|
||||
|
||||
describe('loadFromCollection', () => {
|
||||
|
||||
});
|
||||
});
|
||||
88
packages/server/tests/testInit.js
Normal file
88
packages/server/tests/testInit.js
Normal file
@@ -0,0 +1,88 @@
|
||||
import chai from 'chai';
|
||||
import chaiHttp from 'chai-http';
|
||||
import chaiThings from 'chai-things';
|
||||
import systemDb from '@/database/knex';
|
||||
import app from 'app';
|
||||
import createTenantFactory from '@/database/factories';
|
||||
import TenantsManager from '@/system/TenantsManager';
|
||||
import faker from 'faker';
|
||||
import { hashPassword } from 'utils';
|
||||
import TenantModel from 'models/TenantModel';
|
||||
import createSystemFactory from '@/database/factories/system';
|
||||
|
||||
|
||||
const { expect } = chai;
|
||||
const request = () => chai.request(app);
|
||||
|
||||
beforeEach(async () => {
|
||||
// Rollback/migrate the system database.
|
||||
await systemDb.migrate.rollback();
|
||||
await systemDb.migrate.latest();
|
||||
});
|
||||
|
||||
afterEach(async () => {
|
||||
});
|
||||
|
||||
chai.use(chaiHttp);
|
||||
chai.use(chaiThings);
|
||||
|
||||
// Create tenant database.
|
||||
const createTenant = () => {
|
||||
return TenantsManager.createTenant();
|
||||
};
|
||||
|
||||
// Drops tenant database.
|
||||
const dropTenant = async (tenantWebsite) => {
|
||||
return TenantsManager.dropTenant(tenantWebsite);
|
||||
};
|
||||
|
||||
// Create a new user that associate to the given tenant Db.
|
||||
const createUser = async (tenantWebsite, givenUser) => {
|
||||
const userPassword = (givenUser && givenUser.password) ? givenUser.password : 'admin'
|
||||
const hashedPassword = await hashPassword(userPassword);
|
||||
|
||||
const userInfo = {
|
||||
first_name: faker.lorem.word(),
|
||||
last_name: faker.lorem.word(),
|
||||
email: faker.internet.email(),
|
||||
active: 1,
|
||||
phone_number: faker.phone.phoneNumberFormat().replace('-', ''),
|
||||
password: hashedPassword,
|
||||
...givenUser,
|
||||
};
|
||||
const user = await TenantsManager.createTenantUser(tenantWebsite, userInfo);
|
||||
return user;
|
||||
};
|
||||
|
||||
const login = async (tenantWebsite, givenUser) => {
|
||||
let user = givenUser;
|
||||
|
||||
if (!givenUser && tenantWebsite) {
|
||||
const createdUser = await createUser(tenantWebsite, givenUser);
|
||||
user = createdUser;
|
||||
}
|
||||
return request()
|
||||
.post('/api/auth/login')
|
||||
.send({
|
||||
crediential: user.email,
|
||||
password: 'admin',
|
||||
});
|
||||
};
|
||||
|
||||
const bindTenantModel = (tenantDb) => {
|
||||
TenantModel.knexBinded = tenantDb;
|
||||
};
|
||||
|
||||
const systemFactory = createSystemFactory();
|
||||
|
||||
export {
|
||||
login,
|
||||
systemFactory,
|
||||
createTenantFactory,
|
||||
createTenant,
|
||||
createUser,
|
||||
dropTenant,
|
||||
expect,
|
||||
request,
|
||||
bindTenantModel,
|
||||
};
|
||||
16
packages/server/tests/utils/utils.test.js
Normal file
16
packages/server/tests/utils/utils.test.js
Normal file
@@ -0,0 +1,16 @@
|
||||
import { dateRangeCollection } from 'utils';
|
||||
import { expect } from '../testInit';
|
||||
|
||||
describe('utils', () => {
|
||||
|
||||
describe('dateRangeCollection()', () => {
|
||||
it('Should retrieve all range dates.', () => {
|
||||
const fromDate = new Date('2020-1-1');
|
||||
const toDate = new Date('2020-1-25');
|
||||
|
||||
const range = dateRangeCollection(fromDate, toDate);
|
||||
|
||||
expect(range.length).equals(25);
|
||||
});
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user