feat: Financial statements dependency graph calculate.

This commit is contained in:
Ahmed Bouhuolia
2020-05-23 06:47:00 +02:00
parent b2c9ac54f4
commit 17c1b6ad51
26 changed files with 2041 additions and 900 deletions

View File

@@ -2,61 +2,129 @@ import { expect } from '~/testInit';
import NestedSet from '@/collection/NestedSet';
describe('NestedSet', () => {
it('Should link parent and children nodes.', () => {
const flattenArray = [
{ id: 10 },
{ id: 1 },
{
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,
},
{
id: 2,
parent_id: 1,
},
{
id: 4,
parent_id: 3,
},
];
const collection = new NestedSet(flattenArray);
const treeGroups = collection.toTree();
expect(treeGroups[0].id).equals(10);
expect(treeGroups[1].id).equals(1);
expect(treeGroups[1].children.length).equals(2);
expect(treeGroups[1].children[0].id).equals(3);
expect(treeGroups[1].children[1].id).equals(2);
expect(treeGroups[1].children[0].children[0].id).equals(4);
children: { '4': { id: 4, parent_id: 3, children: {} } }
});
expect(treeGroups['4']).deep.equals({
id: 4, parent_id: 3, children: {},
});
});
});
it('Should flatten the nested set collection.', () => {
const flattenArray = [
{ id: 1 },
{
id: 2,
parent_id: 1,
},
{
id: 3,
parent_id: 1,
},
{
id: 4,
parent_id: 3,
},
];
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();
const collection = new NestedSet(flattenArray);
const treeGroups = collection.toTree();
const flatten = collection.flattenTree();
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: []
}] }
]
});
});
});
expect(flatten.length).equals(4);
expect(flatten[0].id).equals(1);
expect(flatten[1].id).equals(2);
expect(flatten[2].id).equals(3);
expect(flatten[3].id).equals(4);
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: {} }
}
}
}
}
]);
});
})
});

View File

@@ -8,6 +8,7 @@ import {
systemFactory,
dropTenant,
} from '~/testInit';
import CacheService from '@/services/Cache';
let tenantWebsite;
let tenantFactory;
@@ -19,6 +20,8 @@ beforeEach(async () => {
bindTenantModel(tenantWebsite.tenantDb);
loginRes = await login(tenantWebsite);
CacheService.flush();
});
afterEach(async () => {

View File

@@ -10,7 +10,7 @@ import {
} from '~/dbInit';
import { times } from 'lodash';
describe.only('CachableModel', () => {
describe('CachableModel', () => {
describe('remember()', () => {
it('Should retrieve the data from the storage.', async () => {

View File

@@ -337,7 +337,6 @@ describe('routes: /accounts/', () => {
.get('/api/accounts')
.set('x-access-token', loginRes.body.token)
.set('organization-id', tenantWebsite.organizationId)
.query({ display_type: 'tree' })
.send();
expect(res.status).equals(200);

View File

@@ -11,6 +11,7 @@ import {
let creditAccount;
let debitAccount;
let incomeAccount;
let incomeType;
describe('routes: `/financial_statements`', () => {
@@ -28,7 +29,7 @@ describe('routes: `/financial_statements`', () => {
debitAccount = await tenantFactory.create('account', { account_type_id: assetType.id });
// Income && expenses accounts.
const incomeAccount = await tenantFactory.create('account', { account_type_id: incomeType.id });
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 });
@@ -183,8 +184,8 @@ describe('routes: `/financial_statements`', () => {
const journal = res.body.journal.find((j) => j.id === '1-Expense');
expect(journal.credit).equals(1);
expect(journal.debit).equals(1);
expect(journal.formatted_credit).equals(1);
expect(journal.formatted_debit).equals(1);
});
});
@@ -244,10 +245,10 @@ describe('routes: `/financial_statements`', () => {
expect(targetAccount).to.be.an('object');
expect(targetAccount.opening).to.deep.equal({
amount: 0, date: '2020-01-01',
amount: 0, formatted_amount: 0, date: '2020-01-01',
});
expect(targetAccount.closing).to.deep.equal({
amount: 4000, date: '2020-12-31',
amount: 4000, formatted_amount: 4000, date: '2020-12-31',
});
});
@@ -263,16 +264,14 @@ describe('routes: `/financial_statements`', () => {
})
.send();
console.log(res.body);
const targetAccount = res.body.accounts.find((a) => a.id === creditAccount.id);
expect(targetAccount).to.be.an('object');
expect(targetAccount.opening).to.deep.equal({
amount: 4000, date: '2020-01-01',
amount: 0, formatted_amount: 0, date: '2018-01-01',
});
expect(targetAccount.closing).to.deep.equal({
amount: 4000, date: '2020-03-30',
amount: 4000, formatted_amount: 4000, date: '2020-03-30',
});
});
@@ -286,10 +285,25 @@ describe('routes: `/financial_statements`', () => {
})
.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)
@@ -301,23 +315,7 @@ describe('routes: `/financial_statements`', () => {
})
.send();
});
it('Should not retrieve all accounts that have no transactions in the given date range when `none_zero` is `false`.', 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: false,
})
.send();
res.body.accounts.forEach((account) => {
expect(account.transactions.length).not.equals(0);
});
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 () => {
@@ -335,7 +333,7 @@ describe('routes: `/financial_statements`', () => {
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).not.equals(0);
expect(accountsNoTransactions.length).equals(0);
expect(accountsWithTransactions.length).not.equals(0);
});
@@ -347,6 +345,7 @@ describe('routes: `/financial_statements`', () => {
.query({
from_date: '2020-01-01',
to_date: '2020-03-30',
accounts_ids: [creditAccount.id],
number_format: {
divide_1000: true,
},
@@ -358,6 +357,8 @@ describe('routes: `/financial_statements`', () => {
name: creditAccount.name,
code: creditAccount.code,
index: null,
parentAccountId: null,
children: [],
transactions: [
{
id: 1002,
@@ -367,11 +368,12 @@ describe('routes: `/financial_statements`', () => {
referenceId: null,
date: '2020-01-09T22:00:00.000Z',
createdAt: null,
amount: 4
formatted_amount: 4,
amount: 4000,
}
],
opening: { date: '2020-01-01', amount: 0 },
closing: { date: '2020-03-30', amount: 4 }
opening: { date: '2020-01-01', formatted_amount: 0, amount: 0 },
closing: { date: '2020-03-30', formatted_amount: 4, amount: 4000 }
});
});
@@ -395,7 +397,7 @@ describe('routes: `/financial_statements`', () => {
})
.send();
expect(res.body.accounts[0].transactions[2].amount).equal(2);
expect(res.body.accounts[0].transactions[2].formatted_amount).equal(2);
});
it('Should retrieve only accounts that given in the query.', async () => {
@@ -413,6 +415,25 @@ describe('routes: `/financial_statements`', () => {
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/balance_sheet`', () => {
@@ -480,6 +501,8 @@ describe('routes: `/financial_statements`', () => {
index: null,
name: debitAccount.name,
code: debitAccount.code,
parentAccountId: null,
children: [],
total: { formatted_amount: 5000, amount: 5000, date: '2032-02-02' }
});
@@ -488,6 +511,8 @@ describe('routes: `/financial_statements`', () => {
index: null,
name: creditAccount.name,
code: creditAccount.code,
parentAccountId: null,
children: [],
total: { formatted_amount: 4000, amount: 4000, date: '2032-02-02' }
});
});
@@ -565,6 +590,8 @@ describe('routes: `/financial_statements`', () => {
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 },
@@ -579,6 +606,8 @@ describe('routes: `/financial_statements`', () => {
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 },
@@ -608,6 +637,8 @@ describe('routes: `/financial_statements`', () => {
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 },
@@ -644,6 +675,8 @@ describe('routes: `/financial_statements`', () => {
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 },
@@ -678,6 +711,8 @@ describe('routes: `/financial_statements`', () => {
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 },
@@ -709,6 +744,8 @@ describe('routes: `/financial_statements`', () => {
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 },
@@ -739,6 +776,104 @@ describe('routes: `/financial_statements`', () => {
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' }
])
});
});
describe('routes: `/financial_statements/trial_balance`', () => {
@@ -758,22 +893,37 @@ describe('routes: `/financial_statements`', () => {
.send();
expect(res.body.accounts).include.something.deep.equals({
account_id: debitAccount.id,
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({
account_id: creditAccount.id,
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: [],
});
});
@@ -807,13 +957,20 @@ describe('routes: `/financial_statements`', () => {
.send();
expect(res.body.accounts).include.something.deep.equals({
account_id: creditAccount.id,
id: creditAccount.id,
name: creditAccount.name,
code: creditAccount.code,
accountNormal: 'credit',
parentAccountId: null,
credit: 4000,
debit: 0,
balance: 4000
balance: 4000,
formatted_credit: 4000,
formatted_debit: 0,
formatted_balance: 4000,
children: []
});
});
@@ -833,13 +990,21 @@ describe('routes: `/financial_statements`', () => {
.send();
expect(res.body.accounts).include.something.deep.equals({
account_id: creditAccount.id,
id: creditAccount.id,
name: creditAccount.name,
code: creditAccount.code,
accountNormal: 'credit',
credit: 4,
parentAccountId: null,
credit: 4000,
debit: 0,
balance: 4
balance: 4000,
formatted_credit: 4,
formatted_debit: 0,
formatted_balance: 4,
children: [],
});
});
@@ -862,6 +1027,25 @@ describe('routes: `/financial_statements`', () => {
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`', () => {
@@ -955,7 +1139,7 @@ describe('routes: `/financial_statements`', () => {
.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'),
to_date: moment('2020-01-31').endOf('month').format('YYYY-MM-DD'),
display_columns_type: 'total',
display_columns_by: 'month',
none_zero: false,
@@ -967,6 +1151,8 @@ describe('routes: `/financial_statements`', () => {
index: zeroAccount.index,
name: zeroAccount.name,
code: zeroAccount.code,
parentAccountId: null,
children: [],
total: { amount: 0, date: '2020-01-31', formatted_amount: 0 },
});
});
@@ -1120,5 +1306,90 @@ describe('routes: `/financial_statements`', () => {
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);
});
});
});

View File

@@ -10,7 +10,7 @@ import {
} from '~/dbInit';
describe('routes: `/items`', () => {
describe.only('routes: `/items`', () => {
describe('POST: `/items`', () => {
it('Should not create a new item if the user was not authorized.', async () => {
const res = await request()
@@ -553,6 +553,43 @@ describe('routes: `/items`', () => {
});
});
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()

View File

@@ -0,0 +1,396 @@
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('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', () => {
});
});