mirror of
https://github.com/frappe/books.git
synced 2024-12-23 03:19:01 +00:00
commit
9d5808e4d1
@ -388,31 +388,68 @@ module.exports = class Database extends Observable {
|
||||
|
||||
getFilterConditions(filters) {
|
||||
// {"status": "Open"} => `status = "Open"`
|
||||
|
||||
// {"status": "Open", "name": ["like", "apple%"]}
|
||||
// => `status="Open" and name like "apple%"
|
||||
let conditions = [];
|
||||
let values = [];
|
||||
|
||||
// {"date": [">=", "2017-09-09", "<=", "2017-11-01"]}
|
||||
// => `date >= 2017-09-09 and date <= 2017-11-01`
|
||||
|
||||
let filtersArray = [];
|
||||
|
||||
for (let key in filters) {
|
||||
const value = filters[key];
|
||||
if (value instanceof Array) {
|
||||
const condition = value[0];
|
||||
// if its like, we should add the wildcard "%" if the user has not added
|
||||
if (condition.toLowerCase()==='includes') {
|
||||
condition = 'like';
|
||||
let value = filters[key];
|
||||
let field = key;
|
||||
let operator = '=';
|
||||
let comparisonValue = value;
|
||||
|
||||
if (Array.isArray(value)) {
|
||||
operator = value[0];
|
||||
comparisonValue = value[1];
|
||||
operator = operator.toLowerCase();
|
||||
|
||||
if (operator === 'includes') {
|
||||
operator = 'like';
|
||||
}
|
||||
if (['like', 'includes'].includes(condition.toLowerCase()) && !value[1].includes('%')) {
|
||||
value[1] = `%${value[1]}%`;
|
||||
|
||||
if (['like', 'includes'].includes(operator) && !comparisonValue.includes('%')) {
|
||||
comparisonValue = `%${comparisonValue}%`;
|
||||
}
|
||||
conditions.push(`ifnull(${key}, '') ${condition} ?`);
|
||||
values.push(value[1]);
|
||||
} else {
|
||||
conditions.push(`ifnull(${key}, '') = ?`);
|
||||
values.push(value);
|
||||
}
|
||||
|
||||
filtersArray.push([field, operator, comparisonValue]);
|
||||
|
||||
if (Array.isArray(value) && value.length > 2) {
|
||||
// multiple conditions
|
||||
let operator = value[2];
|
||||
let comparisonValue = value[3];
|
||||
filtersArray.push([field, operator, comparisonValue]);
|
||||
}
|
||||
}
|
||||
|
||||
let conditions = filtersArray.map(filter => {
|
||||
const [field, operator, comparisonValue] = filter;
|
||||
|
||||
let placeholder = Array.isArray(comparisonValue) ?
|
||||
comparisonValue.map(v => '?').join(', ') :
|
||||
'?';
|
||||
|
||||
return `ifnull(${field}, '') ${operator} (${placeholder})`;
|
||||
});
|
||||
|
||||
let values = filtersArray.reduce((acc, filter) => {
|
||||
const comparisonValue = filter[2];
|
||||
if (Array.isArray(comparisonValue)) {
|
||||
acc = acc.concat(comparisonValue);
|
||||
} else {
|
||||
acc.push(comparisonValue);
|
||||
}
|
||||
return acc;
|
||||
}, []);
|
||||
|
||||
return {
|
||||
conditions: conditions.length ? conditions.join(" and ") : "",
|
||||
values: values
|
||||
values
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -1,5 +1,5 @@
|
||||
const Page = require('frappejs/client/view/page');
|
||||
const Form = require('frappejs/client/view/form');
|
||||
const FormLayout = require('frappejs/client/view/formLayout');
|
||||
const DataTable = require('frappe-datatable');
|
||||
const frappe = require('frappejs');
|
||||
const utils = require('frappejs/client/ui/utils');
|
||||
@ -10,7 +10,7 @@ const Observable = require('frappejs/utils/observable');
|
||||
// `getColumns` return columns
|
||||
|
||||
module.exports = class ReportPage extends Page {
|
||||
constructor({title, filterFields}) {
|
||||
constructor({title, filterFields = []}) {
|
||||
super({title: title, hasRoute: true});
|
||||
|
||||
this.fullPage = true;
|
||||
@ -30,19 +30,24 @@ module.exports = class ReportPage extends Page {
|
||||
// overrride
|
||||
}
|
||||
|
||||
getRowsForDataTable(data) {
|
||||
return data;
|
||||
}
|
||||
|
||||
makeFilters() {
|
||||
this.form = new Form({
|
||||
this.filters = new FormLayout({
|
||||
parent: this.filterWrapper,
|
||||
meta: { fields: this.filterFields },
|
||||
fields: this.filterFields,
|
||||
doc: new Observable(),
|
||||
inline: true,
|
||||
container: this
|
||||
inline: true
|
||||
});
|
||||
|
||||
this.filterWrapper.appendChild(this.filters.form);
|
||||
}
|
||||
|
||||
getFilterValues() {
|
||||
const values = {};
|
||||
for (let control of this.form.formLayout.controlList) {
|
||||
for (let control of this.filters.controlList) {
|
||||
values[control.fieldname] = control.getInputValue();
|
||||
if (control.required && !values[control.fieldname]) {
|
||||
frappe.ui.showAlert({message: frappe._('{0} is mandatory', control.label), color: 'red'});
|
||||
@ -60,8 +65,8 @@ module.exports = class ReportPage extends Page {
|
||||
async run() {
|
||||
if (frappe.params && frappe.params.filters) {
|
||||
for (let key in frappe.params.filters) {
|
||||
if (this.form.controls[key]) {
|
||||
this.form.controls[key].setInputValue(frappe.params.filters[key]);
|
||||
if (this.filters.controls[key]) {
|
||||
this.filters.controls[key].setInputValue(frappe.params.filters[key]);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -79,14 +84,17 @@ module.exports = class ReportPage extends Page {
|
||||
method: this.method,
|
||||
args: filterValues
|
||||
});
|
||||
this.datatable.refresh(data);
|
||||
|
||||
const rows = this.getRowsForDataTable(data);
|
||||
const columns = utils.convertFieldsToDatatableColumns(this.getColumns(data), this.layout);
|
||||
this.datatable.refresh(rows, columns);
|
||||
}
|
||||
|
||||
makeDataTable() {
|
||||
this.datatable = new DataTable(this.tableWrapper, {
|
||||
this.datatable = new DataTable(this.tableWrapper, Object.assign({
|
||||
columns: utils.convertFieldsToDatatableColumns(this.getColumns(), this.layout),
|
||||
data: [],
|
||||
layout: this.layout || 'fluid',
|
||||
});
|
||||
}, this.datatableOptions || {}));
|
||||
}
|
||||
}
|
@ -11,7 +11,9 @@ class DateControl extends BaseControl {
|
||||
'mm/dd/yyyy': 'm/d/Y',
|
||||
'mm-dd-yyyy': 'm-d-Y'
|
||||
}
|
||||
let altFormat = dateFormat[frappe.SystemSettings.dateFormat];
|
||||
let altFormat = frappe.SystemSettings ?
|
||||
dateFormat[frappe.SystemSettings.dateFormat] :
|
||||
dateFormat['yyyy-mm-dd'];
|
||||
|
||||
super.make();
|
||||
this.input.setAttribute('type', 'text');
|
||||
|
@ -14,6 +14,12 @@ class LinkControl extends BaseControl {
|
||||
minChars: 0,
|
||||
maxItems: 99,
|
||||
filter: () => true,
|
||||
sort: (a, b) => {
|
||||
if (a.value === '__newitem' || b.value === '__newitem') {
|
||||
return -1;
|
||||
}
|
||||
return a.value > b.value;
|
||||
}
|
||||
});
|
||||
|
||||
// rebuild the list on input
|
||||
|
@ -206,7 +206,7 @@ module.exports = class BaseForm extends Observable {
|
||||
}
|
||||
|
||||
refreshLinks(links) {
|
||||
if (!this.container) return;
|
||||
if (!(this.container && this.container.clearLinks)) return;
|
||||
|
||||
this.container.clearLinks();
|
||||
for(let link of links) {
|
||||
|
@ -3,7 +3,7 @@ const controls = require('./controls');
|
||||
const Observable = require('frappejs/utils/observable');
|
||||
|
||||
module.exports = class FormLayout extends Observable {
|
||||
constructor({fields, doc, layout, events = []}) {
|
||||
constructor({fields, doc, layout, inline = false, events = []}) {
|
||||
super();
|
||||
Object.assign(this, arguments[0]);
|
||||
this.controls = {};
|
||||
@ -14,6 +14,11 @@ module.exports = class FormLayout extends Observable {
|
||||
this.form = document.createElement('div');
|
||||
this.form.classList.add('form-body');
|
||||
|
||||
if (this.inline) {
|
||||
this.form.classList.add('row');
|
||||
this.form.classList.add('p-0');
|
||||
}
|
||||
|
||||
this.makeLayout();
|
||||
|
||||
if (doc) {
|
||||
@ -63,6 +68,9 @@ module.exports = class FormLayout extends Observable {
|
||||
let control = controls.makeControl({field: field, form: this, parent: parent});
|
||||
this.controlList.push(control);
|
||||
this.controls[field.fieldname] = control;
|
||||
if (this.inline) {
|
||||
control.inputContainer.classList.add('col');
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -105,6 +105,8 @@ module.exports = class BaseTree extends BaseList {
|
||||
|
||||
if (action === 'edit') {
|
||||
this.edit(treeNode.props.doc.name);
|
||||
} else if (action === 'addChild') {
|
||||
this.addChildNode(treeNode.props.doc.name);
|
||||
}
|
||||
});
|
||||
|
||||
@ -115,6 +117,15 @@ module.exports = class BaseTree extends BaseList {
|
||||
frappe.desk.showFormModal(this.doctype, name);
|
||||
}
|
||||
|
||||
async addChildNode(name) {
|
||||
const newDoc = await frappe.getNewDoc(this.doctype);
|
||||
const formModal = await frappe.desk.showFormModal(this.doctype, newDoc.name);
|
||||
const parentField = this.treeSettings.parentField;
|
||||
if (formModal.form.doc.meta.hasField(parentField)) {
|
||||
formModal.form.doc.set(parentField, name);
|
||||
}
|
||||
}
|
||||
|
||||
async getData(node) {
|
||||
let fields = this.getFields();
|
||||
let filters = {};
|
||||
@ -150,8 +161,8 @@ module.exports = class BaseTree extends BaseList {
|
||||
|
||||
getActionButtonsHTML() {
|
||||
return [
|
||||
{ id: 'edit', label: frappe._('Edit') }
|
||||
// { id: 'addChild', label: frappe._('Add Child') },
|
||||
{ id: 'edit', label: frappe._('Edit') },
|
||||
{ id: 'addChild', label: frappe._('Add Child') },
|
||||
// { id: 'delete', label: frappe._('Delete') },
|
||||
].map(button => {
|
||||
return `<button class="btn btn-link btn-sm m-0" slot="actions" data-action="${button.id}">
|
||||
|
@ -7,8 +7,6 @@ async function getHTML(doctype, name) {
|
||||
let doc = await frappe.getDoc(doctype, name);
|
||||
let context = {doc: doc, frappe: frappe};
|
||||
|
||||
console.log(context);
|
||||
|
||||
let html;
|
||||
try {
|
||||
html = nunjucks.renderString(printFormat.template, context);
|
||||
|
@ -34,5 +34,13 @@ module.exports = {
|
||||
{
|
||||
fieldname: 'parentfield', fieldtype: 'Data', required: 1
|
||||
}
|
||||
],
|
||||
treeFields: [
|
||||
{
|
||||
fieldname: 'lft', fieldtype: 'Int', required: 1
|
||||
},
|
||||
{
|
||||
fieldname: 'rgt', fieldtype: 'Int', required: 1
|
||||
}
|
||||
]
|
||||
};
|
||||
};
|
||||
|
@ -112,6 +112,15 @@ module.exports = class BaseMeta extends BaseDocument {
|
||||
}
|
||||
}
|
||||
|
||||
if (this.isTree) {
|
||||
// tree fields
|
||||
for (let field of model.treeFields) {
|
||||
if (frappe.db.typeMap[field.fieldtype] && !doctype_fields.includes(field.fieldname)) {
|
||||
_add(field);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// doctype fields
|
||||
for (let field of this.fields) {
|
||||
let include = frappe.db.typeMap[field.fieldtype];
|
||||
|
@ -16,12 +16,14 @@
|
||||
"clusterize.js": "^0.18.0",
|
||||
"codemirror": "^5.35.0",
|
||||
"commander": "^2.13.0",
|
||||
"deepmerge": "^2.1.0",
|
||||
"eslint": "^4.19.1",
|
||||
"express": "^4.16.2",
|
||||
"flatpickr": "^4.3.2",
|
||||
"frappe-datatable": "frappe/datatable",
|
||||
"frappejs": "../frappejs",
|
||||
"jquery": "^3.3.1",
|
||||
"luxon": "^1.0.0",
|
||||
"mkdirp": "^0.5.1",
|
||||
"mocha": "^4.1.0",
|
||||
"moment": "^2.20.1",
|
||||
|
@ -66,4 +66,19 @@ module.exports = {
|
||||
});
|
||||
},
|
||||
|
||||
/**
|
||||
* Returns array from 0 to n - 1
|
||||
* @param {Number} n
|
||||
*/
|
||||
range(n) {
|
||||
return Array.from(Array(4)).map((d, i) => i)
|
||||
},
|
||||
|
||||
unique(list, key = it => it) {
|
||||
var seen = {};
|
||||
return list.filter(item => {
|
||||
var k = key(item);
|
||||
return seen.hasOwnProperty(k) ? false : (seen[k] = true);
|
||||
});
|
||||
}
|
||||
};
|
10
yarn.lock
10
yarn.lock
@ -872,6 +872,10 @@ deep-is@~0.1.3:
|
||||
version "0.1.3"
|
||||
resolved "https://registry.yarnpkg.com/deep-is/-/deep-is-0.1.3.tgz#b369d6fb5dbc13eecf524f91b070feedc357cf34"
|
||||
|
||||
deepmerge@^2.1.0:
|
||||
version "2.1.0"
|
||||
resolved "https://registry.yarnpkg.com/deepmerge/-/deepmerge-2.1.0.tgz#511a54fff405fc346f0240bb270a3e9533a31102"
|
||||
|
||||
defined@^1.0.0:
|
||||
version "1.0.0"
|
||||
resolved "https://registry.yarnpkg.com/defined/-/defined-1.0.0.tgz#c98d9bcef75674188e110969151199e39b1fa693"
|
||||
@ -1392,6 +1396,7 @@ frappejs@../frappejs:
|
||||
clusterize.js "^0.18.0"
|
||||
codemirror "^5.35.0"
|
||||
commander "^2.13.0"
|
||||
deepmerge "^2.1.0"
|
||||
eslint "^4.19.1"
|
||||
express "^4.16.2"
|
||||
flatpickr "^4.3.2"
|
||||
@ -1412,6 +1417,7 @@ frappejs@../frappejs:
|
||||
puppeteer "^1.2.0"
|
||||
rollup "^0.55.1"
|
||||
rollup-plugin-commonjs "^8.3.0"
|
||||
rollup-plugin-html "^0.2.1"
|
||||
rollup-plugin-json "^2.3.0"
|
||||
rollup-plugin-node-resolve "^3.0.2"
|
||||
rollup-plugin-postcss "^1.2.7"
|
||||
@ -2264,6 +2270,10 @@ lru-cache@^4.0.1:
|
||||
pseudomap "^1.0.2"
|
||||
yallist "^2.1.2"
|
||||
|
||||
luxon@^1.0.0:
|
||||
version "1.0.0"
|
||||
resolved "https://registry.yarnpkg.com/luxon/-/luxon-1.0.0.tgz#ec1cba8cf53be14d2375c2f17e3468eb195c20bb"
|
||||
|
||||
macaddress@^0.2.8:
|
||||
version "0.2.8"
|
||||
resolved "https://registry.yarnpkg.com/macaddress/-/macaddress-0.2.8.tgz#5904dc537c39ec6dbefeae902327135fa8511f12"
|
||||
|
Loading…
Reference in New Issue
Block a user