mirror of
https://github.com/frappe/books.git
synced 2024-11-08 23:00:56 +00:00
report fixes
This commit is contained in:
parent
dd88baaf41
commit
497c2ab742
@ -1,56 +1,54 @@
|
||||
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 frappe = require('frappejs');
|
||||
const utils = require('frappejs/client/ui/utils');
|
||||
const Observable = require('frappejs/utils/observable');
|
||||
|
||||
// baseclass for report
|
||||
// `url` url for report
|
||||
// `getColumns` return columns
|
||||
|
||||
module.exports = class ReportPage extends Page {
|
||||
constructor({title, }) {
|
||||
constructor({title, filterFields}) {
|
||||
super({title: title, hasRoute: 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.btnNew = this.addButton(frappe._('Refresh'), 'btn-primary', async () => {
|
||||
await this.run();
|
||||
});
|
||||
|
||||
this.filters = {};
|
||||
this.makeFilters();
|
||||
}
|
||||
|
||||
getColumns() {
|
||||
// overrride
|
||||
}
|
||||
|
||||
addFilter(field) {
|
||||
if (!field.fieldname) {
|
||||
field.fieldname = frappe.slug(field.label);
|
||||
}
|
||||
|
||||
field.placeholder = field.label;
|
||||
field.inline = true;
|
||||
|
||||
this.filters[field.fieldname] = controls.makeControl({field: field, form: this, parent: this.filterWrapper});
|
||||
return this.filters[field.fieldname];
|
||||
makeFilters() {
|
||||
this.form = new Form({
|
||||
parent: this.filterWrapper,
|
||||
meta: { fields: this.filterFields },
|
||||
doc: new Observable(),
|
||||
inline: true,
|
||||
container: this
|
||||
});
|
||||
}
|
||||
|
||||
getFilterValues() {
|
||||
const values = {};
|
||||
for (let fieldname in this.filters) {
|
||||
let control = this.filters[fieldname];
|
||||
values[fieldname] = control.getInputValue();
|
||||
if (control.required && !values[fieldname]) {
|
||||
for (let control of this.form.controlList) {
|
||||
values[control.fieldname] = control.getInputValue();
|
||||
if (control.required && !values[control.fieldname]) {
|
||||
frappe.ui.showAlert({message: frappe._('{0} is mandatory', control.label), color: 'red'});
|
||||
return false;
|
||||
}
|
||||
}
|
||||
console.log(values);
|
||||
return values;
|
||||
}
|
||||
|
||||
@ -60,6 +58,16 @@ 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]);
|
||||
}
|
||||
}
|
||||
}
|
||||
frappe.params = null;
|
||||
|
||||
|
||||
if (!this.datatable) {
|
||||
this.makeDataTable();
|
||||
}
|
||||
|
@ -30,7 +30,7 @@ module.exports = class TablePage extends Page {
|
||||
this.filterSelector.reset(this.doctype);
|
||||
}
|
||||
|
||||
if (frappe.params.filters) {
|
||||
if (frappe.params && frappe.params.filters) {
|
||||
this.filterSelector.setFilters(frappe.params.filters);
|
||||
}
|
||||
frappe.params = null;
|
||||
|
@ -86,7 +86,8 @@ html {
|
||||
|
||||
.form-inline {
|
||||
.form-group {
|
||||
margin-right: $spacer-2;
|
||||
margin-right: $spacer-3;
|
||||
margin-bottom: $spacer-3;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -86,8 +86,8 @@ class BaseControl {
|
||||
if (!this.onlyInput) {
|
||||
this.makeDescription();
|
||||
}
|
||||
if (this.placeholder) {
|
||||
this.input.setAttribute('placeholder', this.placeholder);
|
||||
if (this.placeholder || this.inline) {
|
||||
this.input.setAttribute('placeholder', this.placeholder || this.label);
|
||||
}
|
||||
|
||||
}
|
||||
|
9
client/view/controls/dynamicLink.js
Normal file
9
client/view/controls/dynamicLink.js
Normal file
@ -0,0 +1,9 @@
|
||||
const LinkControl = require('./link');
|
||||
|
||||
class DynamicLinkControl extends LinkControl {
|
||||
getTarget() {
|
||||
return this.doc[this.references];
|
||||
}
|
||||
};
|
||||
|
||||
module.exports = DynamicLinkControl;
|
@ -3,6 +3,7 @@ const controlClasses = {
|
||||
Code: require('./code'),
|
||||
Data: require('./data'),
|
||||
Date: require('./date'),
|
||||
DynamicLink: require('./dynamicLink'),
|
||||
Currency: require('./currency'),
|
||||
Float: require('./float'),
|
||||
Int: require('./int'),
|
||||
|
@ -33,8 +33,8 @@ class LinkControl extends BaseControl {
|
||||
this.input.addEventListener('awesomplete-select', async (e) => {
|
||||
if (e.text && e.text.value === '__newItem') {
|
||||
e.preventDefault();
|
||||
const newDoc = await frappe.getNewDoc(this.target);
|
||||
const formModal = await frappe.desk.showFormModal(this.target, newDoc.name);
|
||||
const newDoc = await frappe.getNewDoc(this.getTarget());
|
||||
const formModal = await frappe.desk.showFormModal(this.getTarget(), newDoc.name);
|
||||
if (formModal.form.doc.meta.hasField('name')) {
|
||||
formModal.form.doc.set('name', this.input.value);
|
||||
}
|
||||
@ -49,7 +49,7 @@ class LinkControl extends BaseControl {
|
||||
|
||||
async getList(query) {
|
||||
return (await frappe.db.getAll({
|
||||
doctype: this.target,
|
||||
doctype: this.getTarget(),
|
||||
filters: this.getFilters(query, this),
|
||||
limit: 50
|
||||
})).map(d => d.name);
|
||||
@ -58,6 +58,10 @@ class LinkControl extends BaseControl {
|
||||
getFilters(query) {
|
||||
return { keywords: ["like", query] }
|
||||
}
|
||||
|
||||
getTarget() {
|
||||
return this.target;
|
||||
}
|
||||
};
|
||||
|
||||
module.exports = LinkControl;
|
@ -4,7 +4,7 @@ const Observable = require('frappejs/utils/observable');
|
||||
const keyboard = require('frappejs/client/ui/keyboard');
|
||||
|
||||
module.exports = class BaseForm extends Observable {
|
||||
constructor({doctype, parent, submit_label='Submit', container}) {
|
||||
constructor({doctype, parent, submit_label='Submit', container, meta, inline=false}) {
|
||||
super();
|
||||
Object.assign(this, arguments[0]);
|
||||
this.controls = {};
|
||||
@ -12,12 +12,21 @@ module.exports = class BaseForm extends Observable {
|
||||
this.sections = [];
|
||||
this.links = [];
|
||||
|
||||
this.meta = frappe.getMeta(this.doctype);
|
||||
if (!this.meta) {
|
||||
this.meta = frappe.getMeta(this.doctype);
|
||||
}
|
||||
|
||||
if (this.setup) {
|
||||
this.setup();
|
||||
}
|
||||
|
||||
this.make();
|
||||
this.bindFormEvents();
|
||||
|
||||
if (this.doc) {
|
||||
// bootstrapped with a doc
|
||||
this.bindEvents(this.doc);
|
||||
}
|
||||
}
|
||||
|
||||
make() {
|
||||
@ -25,10 +34,22 @@ module.exports = class BaseForm extends Observable {
|
||||
return;
|
||||
}
|
||||
|
||||
this.body = frappe.ui.add('div', 'form-body', this.parent);
|
||||
this.makeToolbar();
|
||||
if (this.inline) {
|
||||
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);
|
||||
|
||||
if (this.inline) {
|
||||
this.form.classList.add('form-inline');
|
||||
}
|
||||
|
||||
this.form.onValidate = true;
|
||||
|
||||
this.makeLayout();
|
||||
@ -74,6 +95,9 @@ module.exports = class BaseForm extends Observable {
|
||||
makeControls(fields, parent) {
|
||||
for(let field of fields) {
|
||||
if (!field.hidden && controls.getControlClass(field.fieldtype)) {
|
||||
if (this.inline) {
|
||||
field.inline = true;
|
||||
}
|
||||
let control = controls.makeControl({field: field, form: this, parent: parent});
|
||||
this.controlList.push(control);
|
||||
this.controls[field.fieldname] = control;
|
||||
@ -180,6 +204,8 @@ module.exports = class BaseForm extends Observable {
|
||||
}
|
||||
|
||||
setTitle() {
|
||||
if (!this.container) return;
|
||||
|
||||
const doctypeLabel = this.doc.meta.label || this.doc.meta.name;
|
||||
|
||||
if (this.doc.meta.isSingle || this.doc.meta.naming === 'random') {
|
||||
@ -216,6 +242,8 @@ module.exports = class BaseForm extends Observable {
|
||||
}
|
||||
|
||||
refreshLinks(links) {
|
||||
if (!this.container) return;
|
||||
|
||||
this.container.clearLinks();
|
||||
for(let link of links) {
|
||||
// make the link
|
||||
|
@ -11,8 +11,8 @@ module.exports = class Page extends Observable {
|
||||
}
|
||||
this.make();
|
||||
this.dropdowns = {};
|
||||
|
||||
if(this.title) {
|
||||
this.wrapper.setAttribute('title', this.title);
|
||||
this.setTitle(this.title);
|
||||
}
|
||||
}
|
||||
|
@ -11,6 +11,8 @@ module.exports = {
|
||||
naming: "name", // {random|autoincrement}
|
||||
isSingle: 0,
|
||||
isChild: 0,
|
||||
isSubmittable: 0,
|
||||
settings: null,
|
||||
keywordFields: [],
|
||||
fields: [
|
||||
{
|
||||
|
@ -5,11 +5,13 @@ const naming = require('./naming');
|
||||
module.exports = class BaseDocument extends Observable {
|
||||
constructor(data) {
|
||||
super();
|
||||
this.fetchValues = {};
|
||||
this.fetchValuesCache = {};
|
||||
this.flags = {};
|
||||
this.setup();
|
||||
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() {
|
||||
@ -30,10 +32,6 @@ module.exports = class BaseDocument extends Observable {
|
||||
return this._settings;
|
||||
}
|
||||
|
||||
get(fieldname) {
|
||||
return this[fieldname];
|
||||
}
|
||||
|
||||
// set value and trigger change
|
||||
async set(fieldname, value) {
|
||||
if (this[fieldname] !== value) {
|
||||
@ -298,7 +296,7 @@ module.exports = class BaseDocument extends Observable {
|
||||
|
||||
async getFrom(doctype, name, fieldname) {
|
||||
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]) {
|
||||
_values[fieldname] = await frappe.db.getValue(doctype, name, fieldname);
|
||||
}
|
||||
|
@ -65,10 +65,22 @@ module.exports = {
|
||||
if (!e.status_code || e.status_code !== 404) {
|
||||
throw e;
|
||||
}
|
||||
series = frappe.newDoc({doctype: 'NumberSeries', name: prefix, current: 0});
|
||||
await series.insert();
|
||||
await this.createNumberSeries(prefix);
|
||||
}
|
||||
let next = await series.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();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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) {
|
||||
this._addListener('listeners', event, listener);
|
||||
if (this._observable.socketClient) {
|
||||
|
Loading…
Reference in New Issue
Block a user