mirror of
https://github.com/bigcapitalhq/bigcapital.git
synced 2026-02-15 20:30:33 +00:00
feat: fix accounts issue.
This commit is contained in:
@@ -40,6 +40,11 @@ export default {
|
||||
},
|
||||
'created_at': {
|
||||
column: 'created_at',
|
||||
columnType: 'date',
|
||||
},
|
||||
active: {
|
||||
column: 'active',
|
||||
|
||||
},
|
||||
},
|
||||
|
||||
|
||||
@@ -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(() => {
|
||||
|
||||
@@ -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,
|
||||
},
|
||||
]);
|
||||
});
|
||||
};
|
||||
|
||||
@@ -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' },
|
||||
|
||||
@@ -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
|
||||
{
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
Reference in New Issue
Block a user