Files
bigcapital/server/tests/routes/expenses.test.js
2020-06-21 21:10:30 +02:00

720 lines
24 KiB
JavaScript

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);
})
});
});