mirror of
https://github.com/frappe/books.git
synced 2025-02-12 00:49:28 +00:00
fix: Formula
- Trigger applyChange on parent if child is changed - roundFloats after applyChange - formulaDependsOn - process formula value in getValueFromFormula
This commit is contained in:
parent
254b810fd0
commit
16ad083426
@ -1,6 +1,7 @@
|
|||||||
const frappe = require('frappejs');
|
const frappe = require('frappejs');
|
||||||
const Observable = require('frappejs/utils/observable');
|
const Observable = require('frappejs/utils/observable');
|
||||||
const naming = require('./naming');
|
const naming = require('./naming');
|
||||||
|
const { round } = require('frappejs/utils/numberFormat');
|
||||||
|
|
||||||
module.exports = class BaseDocument extends Observable {
|
module.exports = class BaseDocument extends Observable {
|
||||||
constructor(data) {
|
constructor(data) {
|
||||||
@ -86,25 +87,23 @@ module.exports = class BaseDocument extends Observable {
|
|||||||
} else {
|
} else {
|
||||||
this[fieldname] = await this.validateField(fieldname, value);
|
this[fieldname] = await this.validateField(fieldname, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// always run applyChange from the parentdoc
|
||||||
|
if (this.meta.isChild && this.parentdoc) {
|
||||||
|
await this.parentdoc.applyChange(this.parentfield);
|
||||||
|
} else {
|
||||||
await this.applyChange(fieldname);
|
await this.applyChange(fieldname);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
async applyChange(fieldname) {
|
async applyChange(fieldname) {
|
||||||
if (await this.applyFormula()) {
|
await this.applyFormula(fieldname);
|
||||||
// multiple changes
|
this.roundFloats();
|
||||||
await this.trigger('change', {
|
await this.trigger('change', {
|
||||||
doc: this,
|
doc: this,
|
||||||
changed: fieldname
|
changed: fieldname
|
||||||
});
|
});
|
||||||
} else {
|
|
||||||
// no other change, trigger control refresh
|
|
||||||
await this.trigger('change', {
|
|
||||||
doc: this,
|
|
||||||
fieldname: fieldname,
|
|
||||||
changed: fieldname
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
setDefaults() {
|
setDefaults() {
|
||||||
@ -180,18 +179,13 @@ module.exports = class BaseDocument extends Observable {
|
|||||||
for (let field of this.meta.getValidFields()) {
|
for (let field of this.meta.getValidFields()) {
|
||||||
let value = this[field.fieldname];
|
let value = this[field.fieldname];
|
||||||
if (Array.isArray(value)) {
|
if (Array.isArray(value)) {
|
||||||
value = value.map(doc => doc.getValidDict ? doc.getValidDict() : doc);
|
value = value.map(doc => (doc.getValidDict ? doc.getValidDict() : doc));
|
||||||
}
|
}
|
||||||
data[field.fieldname] = value;
|
data[field.fieldname] = value;
|
||||||
}
|
}
|
||||||
return data;
|
return data;
|
||||||
}
|
}
|
||||||
|
|
||||||
getFullDict() {
|
|
||||||
let data = this.getValidDict();
|
|
||||||
return data;
|
|
||||||
}
|
|
||||||
|
|
||||||
setStandardValues() {
|
setStandardValues() {
|
||||||
// set standard values on server-side only
|
// set standard values on server-side only
|
||||||
if (frappe.isServer) {
|
if (frappe.isServer) {
|
||||||
@ -313,12 +307,13 @@ module.exports = class BaseDocument extends Observable {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async applyFormula() {
|
async applyFormula(fieldname) {
|
||||||
if (!this.meta.hasFormula()) {
|
if (!this.meta.hasFormula()) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
let doc = this;
|
let doc = this;
|
||||||
|
let changed = false;
|
||||||
|
|
||||||
// children
|
// children
|
||||||
for (let tablefield of this.meta.getTableFields()) {
|
for (let tablefield of this.meta.getTableFields()) {
|
||||||
@ -330,9 +325,11 @@ module.exports = class BaseDocument extends Observable {
|
|||||||
for (let row of this[tablefield.fieldname]) {
|
for (let row of this[tablefield.fieldname]) {
|
||||||
for (let field of formulaFields) {
|
for (let field of formulaFields) {
|
||||||
if (shouldApplyFormula(field, row)) {
|
if (shouldApplyFormula(field, row)) {
|
||||||
const val = await field.formula(row, doc);
|
let val = await this.getValueFromFormula(field, row);
|
||||||
if (val !== false && val !== undefined) {
|
let previousVal = row[field.fieldname];
|
||||||
|
if (val !== undefined && previousVal !== val) {
|
||||||
row[field.fieldname] = val;
|
row[field.fieldname] = val;
|
||||||
|
changed = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -343,24 +340,28 @@ module.exports = class BaseDocument extends Observable {
|
|||||||
// parent or child row
|
// parent or child row
|
||||||
for (let field of this.meta.getFormulaFields()) {
|
for (let field of this.meta.getFormulaFields()) {
|
||||||
if (shouldApplyFormula(field, doc)) {
|
if (shouldApplyFormula(field, doc)) {
|
||||||
let val;
|
let previousVal = doc[field.fieldname];
|
||||||
if (this.meta.isChild) {
|
let val = await this.getValueFromFormula(field, doc);
|
||||||
val = await field.formula(doc, this.parentdoc);
|
if (val !== undefined && previousVal !== val) {
|
||||||
} else {
|
|
||||||
val = await field.formula(doc);
|
|
||||||
}
|
|
||||||
if (val !== false && val !== undefined) {
|
|
||||||
doc[field.fieldname] = val;
|
doc[field.fieldname] = val;
|
||||||
|
changed = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return changed;
|
||||||
|
|
||||||
function shouldApplyFormula(field, doc) {
|
function shouldApplyFormula(field, doc) {
|
||||||
if (field.readOnly) {
|
if (field.readOnly) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
if (
|
||||||
|
fieldname &&
|
||||||
|
field.formulaDependsOn &&
|
||||||
|
field.formulaDependsOn.includes(fieldname)
|
||||||
|
) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
if (!frappe.isServer || frappe.isElectron) {
|
if (!frappe.isServer || frappe.isElectron) {
|
||||||
if (doc[field.fieldname] == null || doc[field.fieldname] == '') {
|
if (doc[field.fieldname] == null || doc[field.fieldname] == '') {
|
||||||
@ -371,6 +372,57 @@ module.exports = class BaseDocument extends Observable {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async getValueFromFormula(field, doc) {
|
||||||
|
let value;
|
||||||
|
|
||||||
|
if (doc.meta.isChild) {
|
||||||
|
value = await field.formula(doc, doc.parentdoc);
|
||||||
|
} else {
|
||||||
|
value = await field.formula(doc);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (value === undefined) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (['Float', 'Currency'].includes(field.fieldtype)) {
|
||||||
|
value = round(value, field.precision || 2);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (field.fieldtype === 'Table' && Array.isArray(value)) {
|
||||||
|
value = value.map(row => {
|
||||||
|
let doc = this._initChild(row, field.fieldname);
|
||||||
|
doc.roundFloats();
|
||||||
|
return doc;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
roundFloats() {
|
||||||
|
let fields = this.meta
|
||||||
|
.getValidFields()
|
||||||
|
.filter(df => ['Float', 'Currency', 'Table'].includes(df.fieldtype));
|
||||||
|
|
||||||
|
for (let df of fields) {
|
||||||
|
let value = this[df.fieldname];
|
||||||
|
if (value == null) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
// child
|
||||||
|
if (Array.isArray(value)) {
|
||||||
|
value.map(row => row.roundFloats());
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
// field
|
||||||
|
let roundedValue = round(value, df.precision);
|
||||||
|
if (roundedValue && value !== roundedValue) {
|
||||||
|
this[df.fieldname] = roundedValue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
async setName() {
|
async setName() {
|
||||||
await naming.setName(this);
|
await naming.setName(this);
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user