2
0
mirror of https://github.com/frappe/books.git synced 2025-02-02 12:08:27 +00:00

report fixes

This commit is contained in:
Rushabh Mehta 2018-03-27 19:25:26 +05:30
parent dd88baaf41
commit 497c2ab742
13 changed files with 113 additions and 40 deletions

View File

@ -1,56 +1,54 @@
const Page = require('frappejs/client/view/page'); const Page = require('frappejs/client/view/page');
const controls = require('frappejs/client/view/controls'); const Form = require('frappejs/client/view/form');
const DataTable = require('frappe-datatable'); const DataTable = require('frappe-datatable');
const frappe = require('frappejs'); const frappe = require('frappejs');
const utils = require('frappejs/client/ui/utils'); const utils = require('frappejs/client/ui/utils');
const Observable = require('frappejs/utils/observable');
// baseclass for report // baseclass for report
// `url` url for report // `url` url for report
// `getColumns` return columns // `getColumns` return columns
module.exports = class ReportPage extends Page { module.exports = class ReportPage extends Page {
constructor({title, }) { constructor({title, filterFields}) {
super({title: title, hasRoute: true}); super({title: title, hasRoute: true});
this.fullPage = true; this.fullPage = true;
this.filterFields = filterFields;
this.filterWrapper = frappe.ui.add('div', 'filter-toolbar form-inline', this.body); this.filterWrapper = frappe.ui.add('div', 'filter-toolbar', this.body);
this.tableWrapper = frappe.ui.add('div', 'table-page-wrapper', this.body); this.tableWrapper = frappe.ui.add('div', 'table-page-wrapper', this.body);
this.btnNew = this.addButton(frappe._('Refresh'), 'btn-primary', async () => { this.btnNew = this.addButton(frappe._('Refresh'), 'btn-primary', async () => {
await this.run(); await this.run();
}); });
this.filters = {}; this.makeFilters();
} }
getColumns() { getColumns() {
// overrride // overrride
} }
addFilter(field) { makeFilters() {
if (!field.fieldname) { this.form = new Form({
field.fieldname = frappe.slug(field.label); parent: this.filterWrapper,
} meta: { fields: this.filterFields },
doc: new Observable(),
field.placeholder = field.label; inline: true,
field.inline = true; container: this
});
this.filters[field.fieldname] = controls.makeControl({field: field, form: this, parent: this.filterWrapper});
return this.filters[field.fieldname];
} }
getFilterValues() { getFilterValues() {
const values = {}; const values = {};
for (let fieldname in this.filters) { for (let control of this.form.controlList) {
let control = this.filters[fieldname]; values[control.fieldname] = control.getInputValue();
values[fieldname] = control.getInputValue(); if (control.required && !values[control.fieldname]) {
if (control.required && !values[fieldname]) {
frappe.ui.showAlert({message: frappe._('{0} is mandatory', control.label), color: 'red'}); frappe.ui.showAlert({message: frappe._('{0} is mandatory', control.label), color: 'red'});
return false; return false;
} }
} }
console.log(values);
return values; return values;
} }
@ -60,6 +58,16 @@ module.exports = class ReportPage extends Page {
} }
async run() { 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]);
}
}
}
frappe.params = null;
if (!this.datatable) { if (!this.datatable) {
this.makeDataTable(); this.makeDataTable();
} }

View File

@ -30,7 +30,7 @@ module.exports = class TablePage extends Page {
this.filterSelector.reset(this.doctype); this.filterSelector.reset(this.doctype);
} }
if (frappe.params.filters) { if (frappe.params && frappe.params.filters) {
this.filterSelector.setFilters(frappe.params.filters); this.filterSelector.setFilters(frappe.params.filters);
} }
frappe.params = null; frappe.params = null;

View File

@ -86,7 +86,8 @@ html {
.form-inline { .form-inline {
.form-group { .form-group {
margin-right: $spacer-2; margin-right: $spacer-3;
margin-bottom: $spacer-3;
} }
} }

View File

@ -86,8 +86,8 @@ class BaseControl {
if (!this.onlyInput) { if (!this.onlyInput) {
this.makeDescription(); this.makeDescription();
} }
if (this.placeholder) { if (this.placeholder || this.inline) {
this.input.setAttribute('placeholder', this.placeholder); this.input.setAttribute('placeholder', this.placeholder || this.label);
} }
} }

View File

@ -0,0 +1,9 @@
const LinkControl = require('./link');
class DynamicLinkControl extends LinkControl {
getTarget() {
return this.doc[this.references];
}
};
module.exports = DynamicLinkControl;

View File

@ -3,6 +3,7 @@ const controlClasses = {
Code: require('./code'), Code: require('./code'),
Data: require('./data'), Data: require('./data'),
Date: require('./date'), Date: require('./date'),
DynamicLink: require('./dynamicLink'),
Currency: require('./currency'), Currency: require('./currency'),
Float: require('./float'), Float: require('./float'),
Int: require('./int'), Int: require('./int'),

View File

@ -33,8 +33,8 @@ class LinkControl extends BaseControl {
this.input.addEventListener('awesomplete-select', async (e) => { this.input.addEventListener('awesomplete-select', async (e) => {
if (e.text && e.text.value === '__newItem') { if (e.text && e.text.value === '__newItem') {
e.preventDefault(); e.preventDefault();
const newDoc = await frappe.getNewDoc(this.target); const newDoc = await frappe.getNewDoc(this.getTarget());
const formModal = await frappe.desk.showFormModal(this.target, newDoc.name); const formModal = await frappe.desk.showFormModal(this.getTarget(), newDoc.name);
if (formModal.form.doc.meta.hasField('name')) { if (formModal.form.doc.meta.hasField('name')) {
formModal.form.doc.set('name', this.input.value); formModal.form.doc.set('name', this.input.value);
} }
@ -49,7 +49,7 @@ class LinkControl extends BaseControl {
async getList(query) { async getList(query) {
return (await frappe.db.getAll({ return (await frappe.db.getAll({
doctype: this.target, doctype: this.getTarget(),
filters: this.getFilters(query, this), filters: this.getFilters(query, this),
limit: 50 limit: 50
})).map(d => d.name); })).map(d => d.name);
@ -58,6 +58,10 @@ class LinkControl extends BaseControl {
getFilters(query) { getFilters(query) {
return { keywords: ["like", query] } return { keywords: ["like", query] }
} }
getTarget() {
return this.target;
}
}; };
module.exports = LinkControl; module.exports = LinkControl;

View File

@ -4,7 +4,7 @@ const Observable = require('frappejs/utils/observable');
const keyboard = require('frappejs/client/ui/keyboard'); const keyboard = require('frappejs/client/ui/keyboard');
module.exports = class BaseForm extends Observable { module.exports = class BaseForm extends Observable {
constructor({doctype, parent, submit_label='Submit', container}) { constructor({doctype, parent, submit_label='Submit', container, meta, inline=false}) {
super(); super();
Object.assign(this, arguments[0]); Object.assign(this, arguments[0]);
this.controls = {}; this.controls = {};
@ -12,12 +12,21 @@ module.exports = class BaseForm extends Observable {
this.sections = []; this.sections = [];
this.links = []; this.links = [];
this.meta = frappe.getMeta(this.doctype); if (!this.meta) {
this.meta = frappe.getMeta(this.doctype);
}
if (this.setup) { if (this.setup) {
this.setup(); this.setup();
} }
this.make(); this.make();
this.bindFormEvents(); this.bindFormEvents();
if (this.doc) {
// bootstrapped with a doc
this.bindEvents(this.doc);
}
} }
make() { make() {
@ -25,10 +34,22 @@ module.exports = class BaseForm extends Observable {
return; return;
} }
this.body = frappe.ui.add('div', 'form-body', this.parent); if (this.inline) {
this.makeToolbar(); this.body = this.parent
} else {
this.body = frappe.ui.add('div', 'form-body', this.parent);
}
if (this.actions) {
this.makeToolbar();
}
this.form = frappe.ui.add('form', 'form-container', this.body); this.form = frappe.ui.add('form', 'form-container', this.body);
if (this.inline) {
this.form.classList.add('form-inline');
}
this.form.onValidate = true; this.form.onValidate = true;
this.makeLayout(); this.makeLayout();
@ -74,6 +95,9 @@ module.exports = class BaseForm extends Observable {
makeControls(fields, parent) { makeControls(fields, parent) {
for(let field of fields) { for(let field of fields) {
if (!field.hidden && controls.getControlClass(field.fieldtype)) { if (!field.hidden && controls.getControlClass(field.fieldtype)) {
if (this.inline) {
field.inline = true;
}
let control = controls.makeControl({field: field, form: this, parent: parent}); let control = controls.makeControl({field: field, form: this, parent: parent});
this.controlList.push(control); this.controlList.push(control);
this.controls[field.fieldname] = control; this.controls[field.fieldname] = control;
@ -180,6 +204,8 @@ module.exports = class BaseForm extends Observable {
} }
setTitle() { setTitle() {
if (!this.container) return;
const doctypeLabel = this.doc.meta.label || this.doc.meta.name; const doctypeLabel = this.doc.meta.label || this.doc.meta.name;
if (this.doc.meta.isSingle || this.doc.meta.naming === 'random') { if (this.doc.meta.isSingle || this.doc.meta.naming === 'random') {
@ -216,6 +242,8 @@ module.exports = class BaseForm extends Observable {
} }
refreshLinks(links) { refreshLinks(links) {
if (!this.container) return;
this.container.clearLinks(); this.container.clearLinks();
for(let link of links) { for(let link of links) {
// make the link // make the link

View File

@ -11,8 +11,8 @@ module.exports = class Page extends Observable {
} }
this.make(); this.make();
this.dropdowns = {}; this.dropdowns = {};
if(this.title) { if(this.title) {
this.wrapper.setAttribute('title', this.title);
this.setTitle(this.title); this.setTitle(this.title);
} }
} }

View File

@ -11,6 +11,8 @@ module.exports = {
naming: "name", // {random|autoincrement} naming: "name", // {random|autoincrement}
isSingle: 0, isSingle: 0,
isChild: 0, isChild: 0,
isSubmittable: 0,
settings: null,
keywordFields: [], keywordFields: [],
fields: [ fields: [
{ {

View File

@ -5,11 +5,13 @@ const naming = require('./naming');
module.exports = class BaseDocument extends Observable { module.exports = class BaseDocument extends Observable {
constructor(data) { constructor(data) {
super(); super();
this.fetchValues = {}; this.fetchValuesCache = {};
this.flags = {}; this.flags = {};
this.setup(); this.setup();
Object.assign(this, data); Object.assign(this, data);
frappe.db.on('change', (params) => this.fetchValues[`${params.doctype}:${params.name}`] = {});
// clear fetch-values cache
frappe.db.on('change', (params) => this.fetchValuesCache[`${params.doctype}:${params.name}`] = {});
} }
setup() { setup() {
@ -30,10 +32,6 @@ module.exports = class BaseDocument extends Observable {
return this._settings; return this._settings;
} }
get(fieldname) {
return this[fieldname];
}
// set value and trigger change // set value and trigger change
async set(fieldname, value) { async set(fieldname, value) {
if (this[fieldname] !== value) { if (this[fieldname] !== value) {
@ -298,7 +296,7 @@ module.exports = class BaseDocument extends Observable {
async getFrom(doctype, name, fieldname) { async getFrom(doctype, name, fieldname) {
if (!name) return ''; if (!name) return '';
let _values = this.fetchValues[`${doctype}:${name}`] || (this.fetchValues[`${doctype}:${name}`] = {}); let _values = this.fetchValuesCache[`${doctype}:${name}`] || (this.fetchValuesCache[`${doctype}:${name}`] = {});
if (!_values[fieldname]) { if (!_values[fieldname]) {
_values[fieldname] = await frappe.db.getValue(doctype, name, fieldname); _values[fieldname] = await frappe.db.getValue(doctype, name, fieldname);
} }

View File

@ -65,10 +65,22 @@ module.exports = {
if (!e.status_code || e.status_code !== 404) { if (!e.status_code || e.status_code !== 404) {
throw e; throw e;
} }
series = frappe.newDoc({doctype: 'NumberSeries', name: prefix, current: 0}); await this.createNumberSeries(prefix);
await series.insert();
} }
let next = await series.next() let next = await series.next()
return prefix + next; return prefix + next;
},
async createNumberSeries(prefix, setting, start=1000) {
if (!(await frappe.db.exists('NumberSeries', prefix))) {
const series = frappe.newDoc({doctype: 'NumberSeries', name: prefix, current: start});
await series.insert();
if (setting) {
const settingDoc = await frappe.getSingle(setting);
settingDoc.numberSeries = series.name;
await settingDoc.update();
}
}
} }
} }

View File

@ -8,6 +8,16 @@ module.exports = class Observable {
} }
} }
// getter, setter stubs, so Observable can be used as a simple Document
get(key) {
return this[key];
}
set(key, value) {
this[key] = value;
this.trigger('change', {doc: this, fieldname: key});
}
on(event, listener) { on(event, listener) {
this._addListener('listeners', event, listener); this._addListener('listeners', event, listener);
if (this._observable.socketClient) { if (this._observable.socketClient) {