feat: fix accounts issue.

This commit is contained in:
Ahmed Bouhuolia
2020-06-25 13:43:47 +02:00
parent 6074134a53
commit 111aa83908
46 changed files with 797 additions and 345 deletions

View File

@@ -40,6 +40,11 @@ export default {
},
'created_at': {
column: 'created_at',
columnType: 'date',
},
active: {
column: 'active',
},
},

View File

@@ -12,6 +12,7 @@ exports.up = function (knex) {
table.boolean('builtin').defaultTo(false);
table.boolean('columnable');
table.integer('index');
table.string('data_resource');
table.json('options');
table.integer('resource_id').unsigned();
}).raw('ALTER TABLE `RESOURCE_FIELDS` AUTO_INCREMENT = 1000').then(() => {

View File

@@ -1,15 +1,51 @@
exports.seed = function(knex) {
exports.seed = function (knex) {
// Deletes ALL existing entries
return knex('resource_fields').del()
return knex('resource_fields')
.del()
.then(() => {
// Inserts seed entries
return knex('resource_fields').insert([
{ id: 1, label_name: 'Name', key: 'name', data_type: '', active: 1, predefined: 1 },
{ id: 2, label_name: 'Code', key: 'code', data_type: '', active: 1, predefined: 1 },
{ id: 3, label_name: 'Account Type', key: 'type', data_type: '', active: 1, predefined: 1 },
{ id: 4, label_name: 'Description', key: 'description', data_type: '', active: 1, predefined: 1 },
{ id: 5, label_name: 'Account Normal', key: 'normal', data_type: 'string', active: 1, predefined: 1 },
{
id: 1,
label_name: 'Name',
key: 'name',
data_type: '',
active: 1,
predefined: 1,
},
{
id: 2,
label_name: 'Code',
key: 'code',
data_type: '',
active: 1,
predefined: 1,
},
{
id: 3,
label_name: 'Account Type',
key: 'type',
data_type: '',
active: 1,
predefined: 1,
data_resource_id: 8,
},
{
id: 4,
label_name: 'Description',
key: 'description',
data_type: '',
active: 1,
predefined: 1,
},
{
id: 5,
label_name: 'Account Normal',
key: 'normal',
data_type: 'string',
active: 1,
predefined: 1,
},
{
id: 6,
label_name: 'Root Account Type',
@@ -18,6 +54,14 @@ exports.seed = function(knex) {
active: 1,
predefined: 1,
},
{
id: 7,
label_name: 'Active',
key: 'active',
data_type: 'boolean',
active: 1,
predefined: 1,
},
]);
});
};

View File

@@ -6,6 +6,8 @@ exports.seed = (knex) => {
// Inserts seed entries
return knex('resources').insert([
{ id: 1, name: 'accounts' },
{ id: 8, name: 'accounts_types' },
{ id: 2, name: 'items' },
{ id: 3, name: 'expenses' },
{ id: 4, name: 'manual_journals' },

View File

@@ -30,6 +30,7 @@ exports.seed = (knex) => {
data_type: 'options',
predefined: 1,
columnable: true,
data_resource: 'accounts_types',
},
{
id: 5,
@@ -58,6 +59,15 @@ exports.seed = (knex) => {
predefined: 1,
columnable: true,
},
{
id: 17,
resource_id: 1,
data_type: 'boolean',
label_name: 'Active',
key: 'active',
predefined: 1,
columnable: true,
},
// Expenses
{

View File

@@ -120,9 +120,9 @@ export default {
errors: [{ type: 'NOT_EXIST_ACCOUNT_TYPE', code: 200 }],
});
}
await Account.query().insert({ ...form });
const insertedAccount = await Account.query().insertAndFetch({ ...form });
return res.status(200).send({ item: { } });
return res.status(200).send({ account: { ...insertedAccount } });
},
},
@@ -135,7 +135,7 @@ export default {
check('name').exists().isLength({ min: 3 })
.trim()
.escape(),
check('code').exists().isLength({ max: 10 })
check('code').optional().isLength({ max: 10 })
.trim()
.escape(),
check('account_type_id').exists().isNumeric().toInt(),
@@ -157,28 +157,30 @@ export default {
if (!account) {
return res.boom.notFound();
}
const foundAccountCodePromise = (form.code && form.code !== account.code)
? Account.query().where('code', form.code).whereNot('id', account.id) : null;
const errorReasons = [];
const foundAccountTypePromise = (form.account_type_id !== account.account_type_id)
? AccountType.query().where('id', form.account_type_id) : null;
const [foundAccountCode, foundAccountType] = await Promise.all([
foundAccountCodePromise, foundAccountTypePromise,
]);
if (foundAccountCode.length > 0 && foundAccountCodePromise) {
return res.boom.badRequest(null, {
errors: [{ type: 'NOT_UNIQUE_CODE', code: 100 }],
// Validate the account type is not changed.
if (account.account_type_id != form.accountTypeId) {
errorReasons.push({
type: 'NOT.ALLOWED.TO.CHANGE.ACCOUNT.TYPE', code: 100,
});
}
if (foundAccountType.length <= 0 && foundAccountTypePromise) {
return res.boom.badRequest(null, {
errors: [{ type: 'NOT_EXIST_ACCOUNT_TYPE', code: 110 }],
});
}
await account.patch({ ...form });
// Validate the account code not exists on the storage.
if (form.code && form.code !== account.code) {
const foundAccountCode = await Account.query().where('code', form.code).whereNot('id', account.id);
return res.status(200).send();
if (foundAccountCode.length > 0) {
errorReasons.push({ type: 'NOT_UNIQUE_CODE', code: 200 });
}
}
if (errorReasons.length > 0) {
return res.status(400).send({ error: errorReasons });
}
// Update the account on the storage.
const updatedAccount = await Account.query().patchAndFetchById(account.id, { ...form });
return res.status(200).send({ account: { ...updatedAccount } });
},
},
@@ -268,7 +270,6 @@ export default {
if (filter.stringified_filter_roles) {
filter.filter_roles = JSON.parse(filter.stringified_filter_roles);
}
const { Resource, Account, View } = req.models;
const errorReasons = [];
@@ -338,14 +339,31 @@ export default {
if (errorReasons.length > 0) {
return res.status(400).send({ errors: errorReasons });
}
const query = Account.query()
// .remember()
.onBuild((builder) => {
builder.modify('filterAccountTypes', filter.account_types);
builder.withGraphFetched('type');
builder.withGraphFetched('balance');
dynamicFilter.buildQuery()(builder);
// console.log(builder.toKnexQuery().toSQL());
}).toKnexQuery().toSQL();
console.log(query);
const accounts = await Account.query()
.remember()
// .remember()
.onBuild((builder) => {
builder.modify('filterAccountTypes', filter.account_types);
builder.withGraphFetched('type');
builder.withGraphFetched('balance');
dynamicFilter.buildQuery()(builder);
// console.log(builder.toKnexQuery().toSQL());
});
const nestedAccounts = Account.toNestedArray(accounts);

View File

@@ -1,4 +1,5 @@
import { difference } from 'lodash';
import moment from 'moment';
import { Lexer } from '@/lib/LogicEvaluation/Lexer';
import Parser from '@/lib/LogicEvaluation/Parser';
import QueryParser from '@/lib/LogicEvaluation/QueryParser';
@@ -12,25 +13,8 @@ import resourceFieldsKeys from '@/data/ResourceFieldsKeys';
// index: Number,
// }
/**
* Get field column metadata and its relation with other tables.
* @param {String} tableName - Table name of target column.
* @param {String} columnKey - Target column key that stored in resource field.
*/
export function getRoleFieldColumn(tableName, columnKey) {
const tableFields = resourceFieldsKeys[tableName];
return (tableFields[columnKey]) ? tableFields[columnKey] : null;
}
/**
* Builds roles queries.
* @param {String} tableName -
* @param {Object} role -
*/
export function buildRoleQuery(tableName, role) {
const fieldRelation = getRoleFieldColumn(tableName, role.columnKey);
const comparatorColumn = fieldRelation.relationColumn || `${tableName}.${fieldRelation.column}`;
const textRoleQueryBuilder = (role, comparatorColumn) => {
switch (role.comparator) {
case 'equals':
default:
@@ -47,7 +31,82 @@ export function buildRoleQuery(tableName, role) {
return (builder) => {
builder.where(comparatorColumn, 'LIKE', `%${role.value}%`);
};
case 'not_contain':
case 'not_contains':
return (builder) => {
builder.whereNot(comparatorColumn, 'LIKE', `%${role.value}%`);
};
}
};
const dateQueryBuilder = (role, comparatorColumn) => {
switch(role.comparator) {
case 'after':
case 'before':
return (builder) => {
const comparator = role.comparator === 'before' ? '<' : '>';
const hasTimeFormat = moment(role.value, 'YYYY-MM-DD HH:MM', true).isValid();
const targetDate = moment(role.value);
const dateFormat = 'YYYY-MM-DD HH:MM:SS';
if (!hasTimeFormat) {
if (role.comparator === 'before') {
targetDate.startOf('day');
} else {
targetDate.endOf('day');
}
}
const comparatorValue = targetDate.format(dateFormat);
builder.where(comparatorColumn, comparator, comparatorValue);
};
case 'in':
return (builder) => {
const hasTimeFormat = moment(role.value, 'YYYY-MM-DD HH:MM', true).isValid();
const dateFormat = 'YYYY-MM-DD HH:MM:SS';
if (hasTimeFormat) {
const targetDateTime = moment(role.value).format(dateFormat);
builder.where(comparatorColumn, '=', targetDateTime);
} else {
const startDate = moment(role.value).startOf('day');
const endDate = moment(role.value).endOf('day');
builder.where(comparatorColumn, '>=', startDate.format(dateFormat));
builder.where(comparatorColumn, '<=', endDate.format(dateFormat));
}
};
}
};
/**
* Get field column metadata and its relation with other tables.
* @param {String} tableName - Table name of target column.
* @param {String} columnKey - Target column key that stored in resource field.
*/
export function getRoleFieldColumn(tableName, columnKey) {
const tableFields = resourceFieldsKeys[tableName];
return (tableFields[columnKey]) ? tableFields[columnKey] : null;
}
/**
* Builds roles queries.
* @param {String} tableName -
* @param {Object} role -
*/
export function buildRoleQuery(tableName, role) {
const fieldRelation = getRoleFieldColumn(tableName, role.columnKey);
const comparatorColumn = fieldRelation.relationColumn || `${tableName}.${fieldRelation.column}`;
switch (fieldRelation.columnType) {
case 'date':
return dateQueryBuilder(role, comparatorColumn);
case 'text':
case 'varchar':
default:
return textRoleQueryBuilder(role, comparatorColumn);
}
}
/**