2
0
mirror of https://github.com/frappe/books.git synced 2024-12-26 12:28:12 +00:00
books/model/meta.js

334 lines
8.0 KiB
JavaScript
Raw Normal View History

2018-01-24 11:52:05 +00:00
const BaseDocument = require('./document');
2018-01-16 06:09:17 +00:00
const frappe = require('frappejs');
2019-09-17 08:14:09 +00:00
const model = require('./index');
const indicatorColor = require('frappejs/ui/constants/indicators');
2018-01-12 12:25:07 +00:00
2018-01-24 11:52:05 +00:00
module.exports = class BaseMeta extends BaseDocument {
2019-09-17 08:14:09 +00:00
constructor(data) {
if (data.basedOn) {
let config = frappe.models[data.basedOn];
Object.assign(data, config, {
name: data.name,
label: data.label,
filters: data.filters
});
}
2019-09-17 08:14:09 +00:00
super(data);
this.setDefaultIndicators();
if (this.setupMeta) {
this.setupMeta();
}
if (!this.titleField) {
this.titleField = 'name';
}
}
setValues(data) {
Object.assign(this, data);
this.processFields();
}
processFields() {
// add name field
2019-10-26 14:46:19 +00:00
if (!this.fields.find(df => df.fieldname === 'name') && !this.isSingle) {
this.fields = [
{
label: frappe._('ID'),
fieldname: 'name',
fieldtype: 'Data',
required: 1,
readOnly: 1
}
].concat(this.fields);
}
this.fields = this.fields.map(df => {
2019-12-09 19:57:26 +00:00
// name field is always required
if (df.fieldname === 'name') {
df.required = 1;
}
// attach default precision to Float and Currency
if (['Float', 'Currency'].includes(df.fieldtype)) {
let defaultPrecision = frappe.SystemSettings
? frappe.SystemSettings.floatPrecision
: 2;
2019-12-04 18:43:17 +00:00
df.precision = df.precision || defaultPrecision;
}
return df;
});
}
2019-09-17 08:14:09 +00:00
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;
}
2018-01-12 12:25:07 +00:00
}
2019-09-17 08:14:09 +00:00
}
}
return this._hasFormula;
}
getBaseDocType() {
return this.basedOn || this.name;
}
2019-09-17 08:14:09 +00:00
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);
};
2020-01-28 10:56:29 +00:00
// fields validation
this.fields.forEach((df, i) => {
if (!df.fieldname) {
throw new frappe.errors.ValidationError(
`DocType ${this.name}: "fieldname" is required for field at index ${i}`
);
}
if (!df.fieldtype) {
throw new frappe.errors.ValidationError(
`DocType ${this.name}: "fieldtype" is required for field "${df.fieldname}"`
);
}
});
const doctypeFields = this.fields.map(field => field.fieldname);
2019-09-17 08:14:09 +00:00
// standard fields
for (let field of model.commonFields) {
if (
frappe.db.typeMap[field.fieldtype] &&
2020-01-28 10:56:29 +00:00
!doctypeFields.includes(field.fieldname)
2019-09-17 08:14:09 +00:00
) {
_add(field);
}
2019-09-17 08:14:09 +00:00
}
2018-01-12 12:25:07 +00:00
2019-09-17 08:14:09 +00:00
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] &&
2020-01-28 10:56:29 +00:00
!doctypeFields.includes(field.fieldname)
2019-09-17 08:14:09 +00:00
) {
_add(field);
}
2018-01-12 12:25:07 +00:00
}
2019-09-17 08:14:09 +00:00
} else {
// parent fields
for (let field of model.parentFields) {
if (
frappe.db.typeMap[field.fieldtype] &&
2020-01-28 10:56:29 +00:00
!doctypeFields.includes(field.fieldname)
2019-09-17 08:14:09 +00:00
) {
_add(field);
}
2018-02-01 11:07:36 +00:00
}
2019-09-17 08:14:09 +00:00
}
if (this.isTree) {
// tree fields
for (let field of model.treeFields) {
if (
frappe.db.typeMap[field.fieldtype] &&
2020-01-28 10:56:29 +00:00
!doctypeFields.includes(field.fieldname)
2019-09-17 08:14:09 +00:00
) {
_add(field);
}
2018-02-12 12:01:31 +00:00
}
2019-09-17 08:14:09 +00:00
}
2018-01-12 12:25:07 +00:00
2019-09-17 08:14:09 +00:00
// doctype fields
for (let field of this.fields) {
let include = frappe.db.typeMap[field.fieldtype];
2018-03-08 13:31:22 +00:00
2019-09-17 08:14:09 +00:00
if (include) {
_add(field);
2018-01-12 12:25:07 +00:00
}
2019-09-17 08:14:09 +00:00
// include tables if (withChildren = True)
if (!include && field.fieldtype === 'Table') {
this._validFieldsWithChildren.push(field);
}
2019-09-17 08:14:09 +00:00
}
}
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;
}
getQuickEditFields() {
if (this.quickEditFields) {
return this.quickEditFields.map(fieldname => this.getField(fieldname));
}
return this.getFieldsWith({ required: 1 });
}
2019-09-17 08:14:09 +00:00
validateSelect(field, value) {
let options = field.options;
if (!options) return;
if (!field.required && value == null) {
return;
}
2019-09-17 08:14:09 +00:00
let validValues = options;
2019-09-17 08:14:09 +00:00
if (typeof options === 'string') {
// values given as string
validValues = options.split('\n');
}
if (typeof options[0] === 'object') {
// options as array of {label, value} pairs
validValues = options.map(o => o.value);
2019-09-17 08:14:09 +00:00
}
if (!validValues.includes(value)) {
2019-09-17 08:14:09 +00:00
throw new frappe.errors.ValueError(
2020-01-28 10:56:29 +00:00
// prettier-ignore
`DocType ${this.name}: Invalid value "${value}" for "${field.label}". Must be one of ${options.join(', ')}`
2019-09-17 08:14:09 +00:00
);
}
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 {
2019-09-17 08:14:09 +00:00
return indicatorColor.GRAY;
}
2019-09-17 08:14:09 +00:00
} else {
return indicatorColor.GRAY;
}
}
2019-09-17 08:14:09 +00:00
}
};