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

Dynamic Labels

This commit is contained in:
thefalconx33 2019-09-17 13:44:09 +05:30
parent 187b852538
commit b0e572b16c
6 changed files with 259 additions and 272 deletions

View File

@ -358,7 +358,7 @@ module.exports = class BaseDocument extends Observable {
// helper functions // helper functions
getSum(tablefield, childfield) { getSum(tablefield, childfield) {
return this[tablefield] return this[tablefield]
.map(d => frappe.parseNumber(d[childfield]) || 0) .map(d => d[childfield] || 0)
.reduce((a, b) => a + b, 0); .reduce((a, b) => a + b, 0);
} }

View File

@ -1,232 +1,254 @@
const BaseDocument = require('./document'); const BaseDocument = require('./document');
const frappe = require('frappejs'); const frappe = require('frappejs');
const model = require('./index') const model = require('./index');
const indicatorColor = require('frappejs/ui/constants/indicators'); const indicatorColor = require('frappejs/ui/constants/indicators');
module.exports = class BaseMeta extends BaseDocument { module.exports = class BaseMeta extends BaseDocument {
constructor(data) { constructor(data) {
super(data); super(data);
this.setDefaultIndicators(); this.setDefaultIndicators();
if (this.setupMeta) { if (this.setupMeta) {
this.setupMeta(); this.setupMeta();
}
if (!this.titleField) {
this.titleField = 'name';
}
}
hasField(fieldname) {
return this.getField(fieldname) ? true : false;
}
getField(fieldname) {
if (!this._field_map) {
this._field_map = {};
for (let field of this.fields) {
this._field_map[field.fieldname] = field;
}
}
return this._field_map[fieldname];
}
/**
* Get fields filtered by filters
* @param {Object} filters
*
* Usage:
* meta = frappe.getMeta('ToDo')
* dataFields = meta.getFieldsWith({ fieldtype: 'Data' })
*/
getFieldsWith(filters) {
return this.fields.filter(df => {
let match = true;
for (const key in filters) {
const value = filters[key];
match = df[key] === value;
}
return match;
});
}
getLabel(fieldname) {
let df = this.getField(fieldname);
return df.getLabel || df.label;
}
getTableFields() {
if (this._tableFields === undefined) {
this._tableFields = this.fields.filter(
field => field.fieldtype === 'Table'
);
}
return this._tableFields;
}
getFormulaFields() {
if (this._formulaFields === undefined) {
this._formulaFields = this.fields.filter(field => field.formula);
}
return this._formulaFields;
}
hasFormula() {
if (this._hasFormula === undefined) {
this._hasFormula = false;
if (this.getFormulaFields().length) {
this._hasFormula = true;
} else {
for (let tablefield of this.getTableFields()) {
if (frappe.getMeta(tablefield.childtype).getFormulaFields().length) {
this._hasFormula = true;
break;
}
} }
if (!this.titleField) { }
this.titleField = 'name'; }
return this._hasFormula;
}
async set(fieldname, value) {
this[fieldname] = value;
await this.trigger(fieldname);
}
get(fieldname) {
return this[fieldname];
}
getValidFields({ withChildren = true } = {}) {
if (!this._validFields) {
this._validFields = [];
this._validFieldsWithChildren = [];
const _add = field => {
this._validFields.push(field);
this._validFieldsWithChildren.push(field);
};
const doctype_fields = this.fields.map(field => field.fieldname);
// standard fields
for (let field of model.commonFields) {
if (
frappe.db.typeMap[field.fieldtype] &&
!doctype_fields.includes(field.fieldname)
) {
_add(field);
} }
} }
hasField(fieldname) { if (this.isSubmittable) {
return this.getField(fieldname) ? true : false; _add({
} fieldtype: 'Check',
fieldname: 'submitted',
getField(fieldname) { label: frappe._('Submitted')
if (!this._field_map) {
this._field_map = {};
for (let field of this.fields) {
this._field_map[field.fieldname] = field;
}
}
return this._field_map[fieldname];
}
/**
* Get fields filtered by filters
* @param {Object} filters
*
* Usage:
* meta = frappe.getMeta('ToDo')
* dataFields = meta.getFieldsWith({ fieldtype: 'Data' })
*/
getFieldsWith(filters) {
return this.fields.filter(df => {
let match = true;
for (const key in filters) {
const value = filters[key];
match = df[key] === value;
}
return match;
});
}
getLabel(fieldname) {
return this.getField(fieldname).label;
}
getTableFields() {
if (this._tableFields===undefined) {
this._tableFields = this.fields.filter(field => field.fieldtype === 'Table');
}
return this._tableFields;
}
getFormulaFields() {
if (this._formulaFields===undefined) {
this._formulaFields = this.fields.filter(field => field.formula);
}
return this._formulaFields;
}
hasFormula() {
if (this._hasFormula===undefined) {
this._hasFormula = false;
if (this.getFormulaFields().length) {
this._hasFormula = true;
} else {
for (let tablefield of this.getTableFields()) {
if (frappe.getMeta(tablefield.childtype).getFormulaFields().length) {
this._hasFormula = true;
break;
}
}
}
}
return this._hasFormula;
}
async set(fieldname, value) {
this[fieldname] = value;
await this.trigger(fieldname);
}
get(fieldname) {
return this[fieldname];
}
getValidFields({ withChildren = true } = {}) {
if (!this._validFields) {
this._validFields = [];
this._validFieldsWithChildren = [];
const _add = (field) => {
this._validFields.push(field);
this._validFieldsWithChildren.push(field);
}
const doctype_fields = this.fields.map((field) => field.fieldname);
// standard fields
for (let field of model.commonFields) {
if (frappe.db.typeMap[field.fieldtype] && !doctype_fields.includes(field.fieldname)) {
_add(field);
}
}
if (this.isSubmittable) {
_add({fieldtype:'Check', fieldname: 'submitted', label: frappe._('Submitted')})
}
if (this.isChild) {
// child fields
for (let field of model.childFields) {
if (frappe.db.typeMap[field.fieldtype] && !doctype_fields.includes(field.fieldname)) {
_add(field);
}
}
} else {
// parent fields
for (let field of model.parentFields) {
if (frappe.db.typeMap[field.fieldtype] && !doctype_fields.includes(field.fieldname)) {
_add(field);
}
}
}
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];
if (include) {
_add(field);
}
// include tables if (withChildren = True)
if (!include && field.fieldtype === 'Table') {
this._validFieldsWithChildren.push(field);
}
}
}
if (withChildren) {
return this._validFieldsWithChildren;
} else {
return this._validFields;
}
}
getKeywordFields() {
if (!this._keywordFields) {
this._keywordFields = this.keywordFields;
if (!(this._keywordFields && this._keywordFields.length && this.fields)) {
this._keywordFields = this.fields.filter(field => field.fieldtype !== 'Table' && field.required).map(field => field.fieldname);
}
if (!(this._keywordFields && this._keywordFields.length)) {
this._keywordFields = ['name']
}
}
return this._keywordFields;
}
validateSelect(field, value) {
let options = field.options;
if (!options) return;
if (typeof options === 'string') {
// values given as string
options = field.options.split('\n');
}
if (!options.includes(value)) {
throw new frappe.errors.ValueError(`${value} must be one of ${options.join(", ")}`);
}
return value;
}
async trigger(event, params = {}) {
Object.assign(params, {
doc: this,
name: event
}); });
}
await super.trigger(event, params); if (this.isChild) {
} // child fields
for (let field of model.childFields) {
setDefaultIndicators() { if (
if (!this.indicators) { frappe.db.typeMap[field.fieldtype] &&
if (this.isSubmittable) { !doctype_fields.includes(field.fieldname)
this.indicators = { ) {
key: 'submitted', _add(field);
colors: { }
0: indicatorColor.GRAY,
1: indicatorColor.BLUE
}
}
}
} }
} else {
// parent fields
for (let field of model.parentFields) {
if (
frappe.db.typeMap[field.fieldtype] &&
!doctype_fields.includes(field.fieldname)
) {
_add(field);
}
}
}
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];
if (include) {
_add(field);
}
// include tables if (withChildren = True)
if (!include && field.fieldtype === 'Table') {
this._validFieldsWithChildren.push(field);
}
}
} }
getIndicatorColor(doc) { if (withChildren) {
if (frappe.isDirty(this.name, doc.name)) { return this._validFieldsWithChildren;
return indicatorColor.ORANGE; } else {
return this._validFields;
}
}
getKeywordFields() {
if (!this._keywordFields) {
this._keywordFields = this.keywordFields;
if (!(this._keywordFields && this._keywordFields.length && this.fields)) {
this._keywordFields = this.fields
.filter(field => field.fieldtype !== 'Table' && field.required)
.map(field => field.fieldname);
}
if (!(this._keywordFields && this._keywordFields.length)) {
this._keywordFields = ['name'];
}
}
return this._keywordFields;
}
validateSelect(field, value) {
let options = field.options;
if (!options) return;
if (typeof options === 'string') {
// values given as string
options = field.options.split('\n');
}
if (!options.includes(value)) {
throw new frappe.errors.ValueError(
`${value} must be one of ${options.join(', ')}`
);
}
return value;
}
async trigger(event, params = {}) {
Object.assign(params, {
doc: this,
name: event
});
await super.trigger(event, params);
}
setDefaultIndicators() {
if (!this.indicators) {
if (this.isSubmittable) {
this.indicators = {
key: 'submitted',
colors: {
0: indicatorColor.GRAY,
1: indicatorColor.BLUE
}
};
}
}
}
getIndicatorColor(doc) {
if (frappe.isDirty(this.name, doc.name)) {
return indicatorColor.ORANGE;
} else {
if (this.indicators) {
let value = doc[this.indicators.key];
if (value) {
return this.indicators.colors[value] || indicatorColor.GRAY;
} else { } else {
if (this.indicators) { return indicatorColor.GRAY;
let value = doc[this.indicators.key];
if (value) {
return this.indicators.colors[value] || indicatorColor.GRAY;
} else {
return indicatorColor.GRAY;
}
} else {
return indicatorColor.GRAY;
}
} }
} else {
return indicatorColor.GRAY;
}
} }
} }
};

View File

@ -8,9 +8,10 @@
> >
<div class="col" v-for="(column, j) in section.columns" :key="j"> <div class="col" v-for="(column, j) in section.columns" :key="j">
<frappe-control <frappe-control
ref="frappe-control"
v-for="(fieldname, k) in column.fields" v-for="(fieldname, k) in column.fields"
v-if="shouldRenderField(fieldname)" v-if="shouldRenderField(fieldname)"
:key="k" :key="getDocField(fieldname).label"
:docfield="getDocField(fieldname)" :docfield="getDocField(fieldname)"
:value="$data[fieldname]" :value="$data[fieldname]"
:doc="doc" :doc="doc"
@ -48,10 +49,17 @@ export default {
this[df.fieldname] = doc[df.fieldname]; this[df.fieldname] = doc[df.fieldname];
}); });
} }
this.updateLabels();
}); });
this.setLabelOptions();
}, },
methods: { methods: {
updateLabels() {
this.$refs['frappe-control'].forEach(control => {
control.docfield.label = control.docfield.getLabel
? control.docfield.getLabel(this.doc)
: control.docfield.label;
});
},
getDocField(fieldname) { getDocField(fieldname) {
return this.fields.find(df => df.fieldname === fieldname); return this.fields.find(df => df.fieldname === fieldname);
}, },
@ -73,13 +81,6 @@ export default {
return true; return true;
}, },
setLabelOptions() {
this.fields.forEach(field => {
if (field.labelOption) {
field.labelOption = field.labelOption(this.doc);
}
});
},
updateDoc(fieldname, value) { updateDoc(fieldname, value) {
this.doc.set(fieldname, value); this.doc.set(fieldname, value);
this.$emit('updateDoc', { this.$emit('updateDoc', {

View File

@ -6,6 +6,11 @@ export default {
} }
return this.getWrapperElement(h); return this.getWrapperElement(h);
}, },
data() {
return {
label: this.docfield.label
};
},
props: { props: {
docfield: Object, docfield: Object,
value: [String, Number, Array, FileList], value: [String, Number, Array, FileList],
@ -68,23 +73,13 @@ export default {
]; ];
}, },
getLabelElement(h) { getLabelElement(h) {
const hasLabelOptions = Boolean(this.docfield.labelOption);
let label = this.docfield.label;
if (hasLabelOptions) {
const replaceableKeys = Object.keys(this.docfield.labelOption);
for (let key of replaceableKeys) {
label = label.replace(key.toString(), this.docfield.labelOption[key]);
}
}
return h('label', { return h('label', {
class: [this.labelClass, 'text-muted'], class: [this.labelClass, 'text-muted'],
attrs: { attrs: {
for: this.id for: this.id
}, },
domProps: { domProps: {
textContent: label textContent: this.label
} }
}); });
}, },

View File

@ -9,15 +9,7 @@ module.exports = {
field = { fieldtype: field }; field = { fieldtype: field };
} }
if (field.fieldtype === 'Currency') { if (field.fieldtype === 'Currency') {
if (field.currencyInfo) { value = numberFormat.formatNumber(value);
value = numberFormat.formatNumber(
value,
field.currencyInfo.numberFormat,
field.currencyInfo.symbol
);
} else {
value = numberFormat.formatNumber(value);
}
} else if (field.fieldtype === 'Text') { } else if (field.fieldtype === 'Text') {
// value = markdown.makeHtml(value || ''); // value = markdown.makeHtml(value || '');
} else if (field.fieldtype === 'Date') { } else if (field.fieldtype === 'Date') {

View File

@ -14,39 +14,21 @@ const numberFormats = {
module.exports = { module.exports = {
// parse a formatted number string // parse a formatted number string
// from "4,555,000.34" -> 4555000.34 // from "4,555,000.34" -> 4555000.34
parseNumber(number, format, symbol) { parseNumber(number, format = '#,###.##') {
if (!number) { if (!number) {
return 0; return 0;
} }
if (!format) {
format = frappe.AccountingSettings.numberFormat || '#,###.##';
}
if (!symbol) {
symbol = frappe.AccountingSettings.symbol || '';
}
if (typeof number === 'number') { if (typeof number === 'number') {
return number; return number;
} }
if (isNaN(parseFloat(number))) {
// remove symbol
number = number.substr(2);
}
const info = this.getFormatInfo(format); const info = this.getFormatInfo(format);
return parseFloat(this.removeSeparator(number, info.groupSep)); return parseFloat(this.removeSeparator(number, info.groupSep));
}, },
formatNumber(number, format, symbol, precision = null) { formatNumber(number, format = '#,###.##', precision = null) {
if (!number) { if (!number) {
number = 0; number = 0;
} }
if (!format) {
format = frappe.AccountingSettings.numberFormat || '#,###.##';
}
if (!symbol) {
symbol = frappe.AccountingSettings.symbol || '';
}
let info = this.getFormatInfo(format); let info = this.getFormatInfo(format);
if (precision) { if (precision) {
info.precision = precision; info.precision = precision;
@ -96,12 +78,7 @@ module.exports = {
parts[1] = parts[1] && info.fractionSep ? info.fractionSep + parts[1] : ''; parts[1] = parts[1] && info.fractionSep ? info.fractionSep + parts[1] : '';
// join // join
return ( return (is_negative ? '-' : '') + parts[0] + parts[1];
(symbol.length ? `${symbol} ` : '') +
(is_negative ? '-' : '') +
parts[0] +
parts[1]
);
}, },
getFormatInfo(format) { getFormatInfo(format) {