From 2b5ad93c3333987876712a64bd723602e09b0493 Mon Sep 17 00:00:00 2001 From: 18alantom <2.alan.tom@gmail.com> Date: Tue, 23 Nov 2021 16:50:33 +0530 Subject: [PATCH 01/25] add pesa as dependency --- package.json | 1 + yarn.lock | 5 +++++ 2 files changed, 6 insertions(+) diff --git a/package.json b/package.json index 8c3c836c..239cd8bb 100644 --- a/package.json +++ b/package.json @@ -32,6 +32,7 @@ "multer": "^1.4.3", "node-fetch": "^3.0.0", "nunjucks": "^3.2.3", + "pesa": "^1.0.1", "postcss": "^8.3.11", "postcss-loader": "^6.2.0", "sass-loader": "^12.3.0", diff --git a/yarn.lock b/yarn.lock index 1b62a4b3..960b3d5f 100644 --- a/yarn.lock +++ b/yarn.lock @@ -3417,6 +3417,11 @@ performance-now@^2.1.0: resolved "https://registry.yarnpkg.com/performance-now/-/performance-now-2.1.0.tgz#6309f4e0e5fa913ec1c69307ae364b4b377c9e7b" integrity sha1-Ywn04OX6kT7BxpMHrjZLSzd8nns= +pesa@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/pesa/-/pesa-1.0.1.tgz#8cbcdeb1f6326b4f3322a49236917632c8dd1fb9" + integrity sha512-GEwY93Dl3q3Z89H7gIEs+WaPA5TAKFAPpqOxQbdwJ6jXChhIVAQVGjReQ0vgCGfB29x7FPoj6qeijwpd7G/66w== + pg-connection-string@2.5.0: version "2.5.0" resolved "https://registry.yarnpkg.com/pg-connection-string/-/pg-connection-string-2.5.0.tgz#538cadd0f7e603fc09a12590f3b8a452c2c0cf34" From b74620005045ae7213ee7c4e35f99cc7a784181a Mon Sep 17 00:00:00 2001 From: 18alantom <2.alan.tom@gmail.com> Date: Mon, 29 Nov 2021 14:38:56 +0530 Subject: [PATCH 02/25] chore: update pesa to latest, add stuff to system settings --- models/doctype/SystemSettings/SystemSettings.js | 16 +++++++++++++++- package.json | 2 +- yarn.lock | 8 ++++---- 3 files changed, 20 insertions(+), 6 deletions(-) diff --git a/models/doctype/SystemSettings/SystemSettings.js b/models/doctype/SystemSettings/SystemSettings.js index 58ff7fdd..7c6ae875 100644 --- a/models/doctype/SystemSettings/SystemSettings.js +++ b/models/doctype/SystemSettings/SystemSettings.js @@ -37,6 +37,7 @@ module.exports = { options: dateFormatOptions, default: 'MMM d, y', required: 1, + description: _('Sets the app-wide date display format.'), }, { fieldname: 'floatPrecision', @@ -45,12 +46,25 @@ module.exports = { options: ['2', '3', '4', '5'], default: '2', required: 1, + description: _('Sets how many digits are shown after the decimal point.'), + }, + { + fieldname: 'internalPrecision', + label: 'Internal Precision', + fieldtype: 'Int', + default: 12, + description: _( + 'Sets the internal precision used for monetary calculations. Above 6 should be sufficient for most currencies.' + ), }, { fieldname: 'hideGetStarted', label: 'Hide Get Started', fieldtype: 'Check', default: 0, + description: _( + 'Hides the Get Started section from the sidebar. Change will be visible on restart or refreshing the app.' + ), }, { fieldname: 'autoUpdate', @@ -58,7 +72,7 @@ module.exports = { fieldtype: 'Check', default: 1, description: _( - 'Automatically check for updates and download them if available. The update will be applied after you restart the app.' + 'Automatically checks for updates and download them if available. The update will be applied after you restart the app.' ), }, ], diff --git a/package.json b/package.json index 239cd8bb..3ccd243c 100644 --- a/package.json +++ b/package.json @@ -32,7 +32,7 @@ "multer": "^1.4.3", "node-fetch": "^3.0.0", "nunjucks": "^3.2.3", - "pesa": "^1.0.1", + "pesa": "latest", "postcss": "^8.3.11", "postcss-loader": "^6.2.0", "sass-loader": "^12.3.0", diff --git a/yarn.lock b/yarn.lock index 960b3d5f..3973cecd 100644 --- a/yarn.lock +++ b/yarn.lock @@ -3417,10 +3417,10 @@ performance-now@^2.1.0: resolved "https://registry.yarnpkg.com/performance-now/-/performance-now-2.1.0.tgz#6309f4e0e5fa913ec1c69307ae364b4b377c9e7b" integrity sha1-Ywn04OX6kT7BxpMHrjZLSzd8nns= -pesa@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/pesa/-/pesa-1.0.1.tgz#8cbcdeb1f6326b4f3322a49236917632c8dd1fb9" - integrity sha512-GEwY93Dl3q3Z89H7gIEs+WaPA5TAKFAPpqOxQbdwJ6jXChhIVAQVGjReQ0vgCGfB29x7FPoj6qeijwpd7G/66w== +pesa@latest: + version "1.0.2" + resolved "https://registry.yarnpkg.com/pesa/-/pesa-1.0.2.tgz#78410dbbebb92382cb5c4285aa0a781de2dfc769" + integrity sha512-ITR9V8bRe1GDbBQq8/SyMBtzXJlDs8ludO2ZBMtCZen6D7oqlJXVBeZQSJQs4FfoHBLKJtdsk/JvsleE5Qqu4g== pg-connection-string@2.5.0: version "2.5.0" From 7698af67e669c72d93f901337f963e662d977378 Mon Sep 17 00:00:00 2001 From: 18alantom <2.alan.tom@gmail.com> Date: Tue, 30 Nov 2021 14:50:54 +0530 Subject: [PATCH 03/25] feat: init pesa and set on the frappe object --- backends/database.js | 109 ++++++++++++++++++++++++++++++++++--------- index.js | 32 +++++++++++++ package.json | 2 +- yarn.lock | 8 ++-- 4 files changed, 123 insertions(+), 28 deletions(-) diff --git a/backends/database.js b/backends/database.js index fe339284..00d58d0a 100644 --- a/backends/database.js +++ b/backends/database.js @@ -13,9 +13,10 @@ module.exports = class Database extends Observable { connect() { this.knex = Knex(this.connectionParams); - this.knex.on('query-error', error => { + this.knex.on('query-error', (error) => { error.type = this.getError(error); }); + this.executePostDbConnect(); } close() { @@ -41,15 +42,25 @@ module.exports = class Database extends Observable { async initializeSingles() { let singleDoctypes = frappe - .getModels(model => model.isSingle) - .map(model => model.name); + .getModels((model) => model.isSingle) + .map((model) => model.name); for (let doctype of singleDoctypes) { if (await this.singleExists(doctype)) { + const singleValues = await this.getSingleFieldsToInsert(doctype); + singleValues.forEach(({ fieldname, value }) => { + let singleValue = frappe.newDoc({ + doctype: 'SingleValue', + parent: doctype, + fieldname, + value, + }); + singleValue.insert(); + }); continue; } let meta = frappe.getMeta(doctype); - if (meta.fields.every(df => df.default == null)) { + if (meta.fields.every((df) => df.default == null)) { continue; } let defaultValues = meta.fields.reduce((doc, df) => { @@ -70,6 +81,26 @@ module.exports = class Database extends Observable { return res.count > 0; } + async getSingleFieldsToInsert(doctype) { + const existingFields = ( + await frappe.db + .knex('SingleValue') + .where({ parent: doctype }) + .select('fieldname') + ).map(({ fieldname }) => fieldname); + + return frappe + .getMeta(doctype) + .fields.map(({ fieldname, default: value }) => ({ + fieldname, + value, + })) + .filter( + ({ fieldname, value }) => + !existingFields.includes(fieldname) && value !== undefined + ); + } + tableExists(table) { return this.knex.schema.hasTable(table); } @@ -80,7 +111,7 @@ module.exports = class Database extends Observable { } runCreateTableQuery(doctype, fields) { - return this.knex.schema.createTable(doctype, table => { + return this.knex.schema.createTable(doctype, (table) => { for (let field of fields) { this.buildColumnForTable(table, field); } @@ -93,7 +124,7 @@ module.exports = class Database extends Observable { let newForeignKeys = await this.getNewForeignKeys(doctype); return this.knex.schema - .table(doctype, table => { + .table(doctype, (table) => { if (diff.added.length) { for (let field of diff.added) { this.buildColumnForTable(table, field); @@ -162,7 +193,7 @@ module.exports = class Database extends Observable { } } - const validFieldNames = validFields.map(field => field.fieldname); + const validFieldNames = validFields.map((field) => field.fieldname); for (let column of tableColumns) { if (!validFieldNames.includes(column)) { diff.removed.push(column); @@ -235,7 +266,7 @@ module.exports = class Database extends Observable { fields: ['*'], filters: { parent: doc.name }, orderBy: 'idx', - order: 'asc' + order: 'asc', }); } } @@ -246,7 +277,7 @@ module.exports = class Database extends Observable { fields: ['fieldname', 'value'], filters: { parent: doctype }, orderBy: 'fieldname', - order: 'asc' + order: 'asc', }); let doc = {}; for (let row of values) { @@ -255,6 +286,38 @@ module.exports = class Database extends Observable { return doc; } + /** + * Get list of values from the singles table. + * @param {...string | Object} fieldnames list of fieldnames to get the values of + * @returns {Array} array of {parent, value, fieldname}. + * @example + * Database.getSingleValues('internalPrecision'); + * // returns [{ fieldname: 'internalPrecision', parent: 'SystemSettings', value: '12' }] + * @example + * Database.getSingleValues({fieldname:'internalPrecision', parent: 'SystemSettings'}); + * // returns [{ fieldname: 'internalPrecision', parent: 'SystemSettings', value: '12' }] + */ + async getSingleValues(...fieldnames) { + fieldnames = fieldnames.map((fieldname) => { + if (typeof fieldname === 'string') { + return { fieldname }; + } + return fieldname; + }); + + let builder = frappe.db.knex('SingleValue'); + builder = builder.where(fieldnames[0]); + + fieldnames.slice(1).forEach(({ fieldname, parent }) => { + if (typeof parent === 'undefined') { + builder = builder.orWhere({ fieldname }); + } else { + builder = builder.orWhere({ fieldname, parent }); + } + }); + return await builder.select('fieldname', 'value', 'parent'); + } + getOne(doctype, name, fields = '*') { let meta = frappe.getMeta(doctype); let baseDoctype = meta.getBaseDocType(); @@ -358,8 +421,8 @@ module.exports = class Database extends Observable { updateOne(doctype, doc) { let validFields = this.getValidFields(doctype); - let fieldsToUpdate = Object.keys(doc).filter(f => f !== 'name'); - let fields = validFields.filter(df => + let fieldsToUpdate = Object.keys(doc).filter((f) => f !== 'name'); + let fields = validFields.filter((df) => fieldsToUpdate.includes(df.fieldname) ); let formattedDoc = this.getFormattedDoc(fields, doc); @@ -396,7 +459,7 @@ module.exports = class Database extends Observable { doctype: 'SingleValue', parent: doctype, fieldname: field.fieldname, - value: value + value: value, }); await singleValue.insert(); } @@ -404,9 +467,7 @@ module.exports = class Database extends Observable { } deleteSingleValues(name) { - return this.knex('SingleValue') - .where('parent', name) - .delete(); + return this.knex('SingleValue').where('parent', name).delete(); } async rename(doctype, oldName, newName) { @@ -439,7 +500,7 @@ module.exports = class Database extends Observable { getFormattedDoc(fields, doc) { let formattedDoc = {}; - fields.map(field => { + fields.map((field) => { let value = doc[field.fieldname]; formattedDoc[field.fieldname] = this.getFormattedValue(field, value); }); @@ -507,9 +568,7 @@ module.exports = class Database extends Observable { } deleteChildren(parenttype, parent) { - return this.knex(parenttype) - .where('parent', parent) - .delete(); + return this.knex(parenttype).where('parent', parent).delete(); } async exists(doctype, name) { @@ -533,14 +592,14 @@ module.exports = class Database extends Observable { start: 0, limit: 1, orderBy: 'name', - order: 'asc' + order: 'asc', }); return row.length ? row[0][fieldname] : null; } async setValue(doctype, name, fieldname, value) { return await this.setValues(doctype, name, { - [fieldname]: value + [fieldname]: value, }); } @@ -565,7 +624,7 @@ module.exports = class Database extends Observable { limit, groupBy, orderBy = 'creation', - order = 'desc' + order = 'desc', } = {}) { let meta = frappe.getMeta(doctype); let baseDoctype = meta.getBaseDocType(); @@ -643,7 +702,7 @@ module.exports = class Database extends Observable { } } - filtersArray.map(filter => { + filtersArray.map((filter) => { const [field, operator, comparisonValue] = filter; if (operator === '=') { builder.where(field, comparisonValue); @@ -689,4 +748,8 @@ module.exports = class Database extends Observable { initTypeMap() { this.typeMap = {}; } + + executePostDbConnect() { + frappe.initializeMoneyMaker(); + } }; diff --git a/index.js b/index.js index ba076f5d..e51c7755 100644 --- a/index.js +++ b/index.js @@ -1,5 +1,6 @@ const Observable = require('./utils/observable'); const utils = require('./utils'); +const { getMoneyMaker } = require('pesa'); module.exports = { initializeAndRegister(customModels = {}, force = false) { @@ -11,6 +12,37 @@ module.exports = { this.registerModels(customModels); }, + async initializeMoneyMaker() { + // to be called after db initialization + const { currency, internalPrecision: precision } = ( + await frappe.db.getSingleValues( + { fieldname: 'currency', parent: 'AccountingSettings' }, + { fieldname: 'internalPrecision', parent: 'SystemSettings' } + ) + ).reduce((acc, { fieldname, value }) => { + acc[fieldname] = value; + return acc; + }, {}); + + if (typeof precision === 'undefined') { + precision = this.getMeta('SystemSettings').fields.find( + (f) => f.fieldname === 'internalPrecision' + )?.default; + } + + if (typeof precision === 'undefined') { + throw new frappe.errors.NotFoundError( + 'SystemSettings internalPrecision value is undefined' + ); + } + + if (typeof precision.value === 'string') { + precision = parseInt(precision); + } + + this.pesa = getMoneyMaker({ currency, precision }); + }, + init(force) { if (this._initialized && !force) return; this.initConfig(); diff --git a/package.json b/package.json index 3ccd243c..a1c5855b 100644 --- a/package.json +++ b/package.json @@ -32,7 +32,7 @@ "multer": "^1.4.3", "node-fetch": "^3.0.0", "nunjucks": "^3.2.3", - "pesa": "latest", + "pesa": "^1.0.3", "postcss": "^8.3.11", "postcss-loader": "^6.2.0", "sass-loader": "^12.3.0", diff --git a/yarn.lock b/yarn.lock index 3973cecd..3caaa78e 100644 --- a/yarn.lock +++ b/yarn.lock @@ -3417,10 +3417,10 @@ performance-now@^2.1.0: resolved "https://registry.yarnpkg.com/performance-now/-/performance-now-2.1.0.tgz#6309f4e0e5fa913ec1c69307ae364b4b377c9e7b" integrity sha1-Ywn04OX6kT7BxpMHrjZLSzd8nns= -pesa@latest: - version "1.0.2" - resolved "https://registry.yarnpkg.com/pesa/-/pesa-1.0.2.tgz#78410dbbebb92382cb5c4285aa0a781de2dfc769" - integrity sha512-ITR9V8bRe1GDbBQq8/SyMBtzXJlDs8ludO2ZBMtCZen6D7oqlJXVBeZQSJQs4FfoHBLKJtdsk/JvsleE5Qqu4g== +pesa@^1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/pesa/-/pesa-1.0.3.tgz#e0eab7a13a6a8d0cfd1cbc0214aece6befd63a74" + integrity sha512-UGw3TPnQKAcM0EhPzQO17cXtibBcJCCqlB/hjfYtVPFAgDOIJ2kv6az9Fwq5Gflp2R7hODZlJy1cG+eL70od/g== pg-connection-string@2.5.0: version "2.5.0" From 0bad10e1be2dbc3452496ec2d61a60e69768ed27 Mon Sep 17 00:00:00 2001 From: 18alantom <2.alan.tom@gmail.com> Date: Thu, 2 Dec 2021 14:09:45 +0530 Subject: [PATCH 04/25] refactor: shift currency to books, change iP to 11, update --- index.js | 35 ++++++++++++------- .../doctype/SystemSettings/SystemSettings.js | 2 +- package.json | 2 +- yarn.lock | 8 ++--- 4 files changed, 28 insertions(+), 19 deletions(-) diff --git a/index.js b/index.js index e51c7755..19bf2be4 100644 --- a/index.js +++ b/index.js @@ -12,17 +12,28 @@ module.exports = { this.registerModels(customModels); }, - async initializeMoneyMaker() { + async initializeMoneyMaker(currency) { + currency ??= 'XXX'; + // to be called after db initialization - const { currency, internalPrecision: precision } = ( - await frappe.db.getSingleValues( - { fieldname: 'currency', parent: 'AccountingSettings' }, - { fieldname: 'internalPrecision', parent: 'SystemSettings' } - ) - ).reduce((acc, { fieldname, value }) => { - acc[fieldname] = value; - return acc; - }, {}); + let values; + try { + // error thrown if migration hasn't taken place + values = await frappe.db.getSingleValues({ + fieldname: 'internalPrecision', + parent: 'SystemSettings', + }); + } catch { + values = []; + } + + let { internalPrecision: precision } = values.reduce( + (acc, { fieldname, value }) => { + acc[fieldname] = value; + return acc; + }, + {} + ); if (typeof precision === 'undefined') { precision = this.getMeta('SystemSettings').fields.find( @@ -31,9 +42,7 @@ module.exports = { } if (typeof precision === 'undefined') { - throw new frappe.errors.NotFoundError( - 'SystemSettings internalPrecision value is undefined' - ); + precision = 11; } if (typeof precision.value === 'string') { diff --git a/models/doctype/SystemSettings/SystemSettings.js b/models/doctype/SystemSettings/SystemSettings.js index 7c6ae875..ac68075e 100644 --- a/models/doctype/SystemSettings/SystemSettings.js +++ b/models/doctype/SystemSettings/SystemSettings.js @@ -52,7 +52,7 @@ module.exports = { fieldname: 'internalPrecision', label: 'Internal Precision', fieldtype: 'Int', - default: 12, + default: 11, description: _( 'Sets the internal precision used for monetary calculations. Above 6 should be sufficient for most currencies.' ), diff --git a/package.json b/package.json index a1c5855b..27b8794a 100644 --- a/package.json +++ b/package.json @@ -32,7 +32,7 @@ "multer": "^1.4.3", "node-fetch": "^3.0.0", "nunjucks": "^3.2.3", - "pesa": "^1.0.3", + "pesa": "^1.0.4", "postcss": "^8.3.11", "postcss-loader": "^6.2.0", "sass-loader": "^12.3.0", diff --git a/yarn.lock b/yarn.lock index 3caaa78e..84e6bdc5 100644 --- a/yarn.lock +++ b/yarn.lock @@ -3417,10 +3417,10 @@ performance-now@^2.1.0: resolved "https://registry.yarnpkg.com/performance-now/-/performance-now-2.1.0.tgz#6309f4e0e5fa913ec1c69307ae364b4b377c9e7b" integrity sha1-Ywn04OX6kT7BxpMHrjZLSzd8nns= -pesa@^1.0.3: - version "1.0.3" - resolved "https://registry.yarnpkg.com/pesa/-/pesa-1.0.3.tgz#e0eab7a13a6a8d0cfd1cbc0214aece6befd63a74" - integrity sha512-UGw3TPnQKAcM0EhPzQO17cXtibBcJCCqlB/hjfYtVPFAgDOIJ2kv6az9Fwq5Gflp2R7hODZlJy1cG+eL70od/g== +pesa@^1.0.4: + version "1.0.4" + resolved "https://registry.yarnpkg.com/pesa/-/pesa-1.0.4.tgz#aaed9760b319d1435ea663bdb96c0a99f88cbd53" + integrity sha512-SuXEyavfSv1GGk625Mgdmw8ZJvNaMQ6C5e413zxTpkdLmDdTwWidhlQDDbFuI+Drj1GBHu/L20NVsoRUjUjU5w== pg-connection-string@2.5.0: version "2.5.0" From 3610f79732e36d7aa33896b413db5701b71e5771 Mon Sep 17 00:00:00 2001 From: 18alantom <2.alan.tom@gmail.com> Date: Thu, 23 Dec 2021 12:58:17 +0530 Subject: [PATCH 05/25] fix: convert from and to pesa on db i/o --- backends/database.js | 67 ++++++++++++++++++++++++++++++++++++++++---- backends/sqlite.js | 2 +- 2 files changed, 63 insertions(+), 6 deletions(-) diff --git a/backends/database.js b/backends/database.js index 00d58d0a..cbb6ec22 100644 --- a/backends/database.js +++ b/backends/database.js @@ -315,18 +315,54 @@ module.exports = class Database extends Observable { builder = builder.orWhere({ fieldname, parent }); } }); - return await builder.select('fieldname', 'value', 'parent'); + + const values = await builder.select('fieldname', 'value', 'parent'); + + return values.map((value) => { + const fields = frappe.getMeta(value.parent).fields; + return this.getDocFormattedDoc(fields, values); + }); } - getOne(doctype, name, fields = '*') { + async getOne(doctype, name, fields = '*') { let meta = frappe.getMeta(doctype); let baseDoctype = meta.getBaseDocType(); - return this.knex + const doc = await this.knex .select(fields) .from(baseDoctype) .where('name', name) .first(); + + if (!doc) { + return doc; + } + + return this.getDocFormattedDoc(meta.fields, doc); + } + + getDocFormattedDoc(fields, doc) { + // format for usage, not going into the db + const docFields = Object.keys(doc); + const filteredFields = fields.filter(({ fieldname }) => + docFields.includes(fieldname) + ); + + const formattedValues = filteredFields.reduce((d, field) => { + const { fieldname } = field; + d[fieldname] = this.getDocFormattedValues(field, doc[fieldname]); + return d; + }, {}); + + return Object.assign(doc, formattedValues); + } + + getDocFormattedValues(field, value) { + // format for usage, not going into the db + if (field.fieldtype === 'Currency') { + return frappe.pesa(value); + } + return value; } triggerChange(doctype, name) { @@ -499,6 +535,7 @@ module.exports = class Database extends Observable { } getFormattedDoc(fields, doc) { + // format for storage, going into the db let formattedDoc = {}; fields.map((field) => { let value = doc[field.fieldname]; @@ -508,6 +545,25 @@ module.exports = class Database extends Observable { } getFormattedValue(field, value) { + // format for storage, going into the db + const type = typeof value; + if (field.fieldtype === 'Currency') { + let currency = value; + + if (type === 'number' || type === 'string') { + currency = frappe.pesa(value); + } + + const currencyValue = currency.store; + if (typeof currencyValue !== 'string') { + throw new Error( + `invalid currencyValue '${currencyValue}' of type '${typeof currencyValue}' on converting from '${value}' of type '${type}'` + ); + } + + return currencyValue; + } + if (value instanceof Date) { if (field.fieldtype === 'Date') { // date @@ -616,7 +672,7 @@ module.exports = class Database extends Observable { return value; } - getAll({ + async getAll({ doctype, fields, filters, @@ -659,7 +715,8 @@ module.exports = class Database extends Observable { builder.limit(limit); } - return builder; + const docs = await builder; + return docs.map((doc) => this.getDocFormattedDoc(meta.fields, doc)); } applyFiltersToBuilder(builder, filters) { diff --git a/backends/sqlite.js b/backends/sqlite.js index ddfd54d8..f4711866 100644 --- a/backends/sqlite.js +++ b/backends/sqlite.js @@ -61,7 +61,7 @@ class SqliteDatabase extends Database { // prettier-ignore this.typeMap = { 'AutoComplete': 'text', - 'Currency': 'float', + 'Currency': 'text', 'Int': 'integer', 'Float': 'float', 'Percent': 'float', From 8bf257c68565ddd1427ec8e79248c6498be67c9a Mon Sep 17 00:00:00 2001 From: 18alantom <2.alan.tom@gmail.com> Date: Thu, 23 Dec 2021 13:50:44 +0530 Subject: [PATCH 06/25] fix: deprecate floatPrecision add displayPrecision --- model/document.js | 2 +- model/meta.js | 2 +- .../doctype/SystemSettings/SystemSettings.js | 21 +++++++++++++------ 3 files changed, 17 insertions(+), 8 deletions(-) diff --git a/model/document.js b/model/document.js index ccf8a032..88c158b7 100644 --- a/model/document.js +++ b/model/document.js @@ -673,7 +673,7 @@ module.exports = class BaseDocument extends Observable { if (typeof df === 'string') { df = this.meta.getField(df); } - let systemPrecision = frappe.SystemSettings.floatPrecision; + let systemPrecision = frappe.SystemSettings.internalPrecision; let defaultPrecision = systemPrecision != null ? systemPrecision : 2; let precision = df && df.precision != null ? df.precision : defaultPrecision; diff --git a/model/meta.js b/model/meta.js index fa6973ea..6107219d 100644 --- a/model/meta.js +++ b/model/meta.js @@ -51,7 +51,7 @@ module.exports = class BaseMeta extends BaseDocument { // attach default precision to Float and Currency if (['Float', 'Currency'].includes(df.fieldtype)) { let defaultPrecision = frappe.SystemSettings - ? frappe.SystemSettings.floatPrecision + ? frappe.SystemSettings.internalPrecision : 2; df.precision = df.precision || defaultPrecision; } diff --git a/models/doctype/SystemSettings/SystemSettings.js b/models/doctype/SystemSettings/SystemSettings.js index ac68075e..92396cfe 100644 --- a/models/doctype/SystemSettings/SystemSettings.js +++ b/models/doctype/SystemSettings/SystemSettings.js @@ -40,12 +40,21 @@ module.exports = { description: _('Sets the app-wide date display format.'), }, { - fieldname: 'floatPrecision', - label: 'Precision', - fieldtype: 'Select', - options: ['2', '3', '4', '5'], - default: '2', + fieldname: 'displayPrecision', + label: 'Display Precision', + fieldtype: 'Int', + default: 2, required: 1, + minValue: 0, + maxValue: 9, + validate(value, doc) { + if (value >= 0 && value <= 9) { + return; + } + throw new frappe.errors.ValidationError( + _('Display Precision should have a value between 0 and 9.') + ); + }, description: _('Sets how many digits are shown after the decimal point.'), }, { @@ -78,7 +87,7 @@ module.exports = { ], quickEditFields: [ 'dateFormat', - 'floatPrecision', + 'displayPrecision', 'hideGetStarted', 'autoUpdate', ], From 23189aaf93bfadc4228625c58eef0182048c3eda Mon Sep 17 00:00:00 2001 From: 18alantom <2.alan.tom@gmail.com> Date: Thu, 23 Dec 2021 16:56:47 +0530 Subject: [PATCH 07/25] fix: don't set precision on df, should be global --- index.js | 3 ++- model/document.js | 7 +++---- model/meta.js | 7 ------- utils/consts.js | 1 + 4 files changed, 6 insertions(+), 12 deletions(-) create mode 100644 utils/consts.js diff --git a/index.js b/index.js index 19bf2be4..1754c156 100644 --- a/index.js +++ b/index.js @@ -1,6 +1,7 @@ const Observable = require('./utils/observable'); const utils = require('./utils'); const { getMoneyMaker } = require('pesa'); +const { DEFAULT_INTERNAL_PRECISION } = require('./utils/consts'); module.exports = { initializeAndRegister(customModels = {}, force = false) { @@ -42,7 +43,7 @@ module.exports = { } if (typeof precision === 'undefined') { - precision = 11; + precision = DEFAULT_INTERNAL_PRECISION; } if (typeof precision.value === 'string') { diff --git a/model/document.js b/model/document.js index 88c158b7..84ea48ba 100644 --- a/model/document.js +++ b/model/document.js @@ -2,6 +2,7 @@ const frappe = require('frappejs'); const Observable = require('frappejs/utils/observable'); const naming = require('./naming'); const { round } = require('frappejs/utils/numberFormat'); +const { DEFAULT_INTERNAL_PRECISION } = require('../utils/consts'); module.exports = class BaseDocument extends Observable { constructor(data) { @@ -673,10 +674,8 @@ module.exports = class BaseDocument extends Observable { if (typeof df === 'string') { df = this.meta.getField(df); } - let systemPrecision = frappe.SystemSettings.internalPrecision; - let defaultPrecision = systemPrecision != null ? systemPrecision : 2; - let precision = - df && df.precision != null ? df.precision : defaultPrecision; + const precision = + frappe.SystemSettings.internalPrecision ?? DEFAULT_INTERNAL_PRECISION; return round(value, precision); } diff --git a/model/meta.js b/model/meta.js index 6107219d..2c43da80 100644 --- a/model/meta.js +++ b/model/meta.js @@ -48,13 +48,6 @@ module.exports = class BaseMeta extends BaseDocument { df.required = 1; } - // attach default precision to Float and Currency - if (['Float', 'Currency'].includes(df.fieldtype)) { - let defaultPrecision = frappe.SystemSettings - ? frappe.SystemSettings.internalPrecision - : 2; - df.precision = df.precision || defaultPrecision; - } return df; }); } diff --git a/utils/consts.js b/utils/consts.js new file mode 100644 index 00000000..f601d1d8 --- /dev/null +++ b/utils/consts.js @@ -0,0 +1 @@ +export const DEFAULT_INTERNAL_PRECISION = 11; From e1f1ffd2024ee60c7b94b9b69ca887cf2abbe4e3 Mon Sep 17 00:00:00 2001 From: 18alantom <2.alan.tom@gmail.com> Date: Thu, 23 Dec 2021 17:08:32 +0530 Subject: [PATCH 08/25] fix: init pesa with display too --- index.js | 43 +++++++++++-------- .../doctype/SystemSettings/SystemSettings.js | 9 +++- utils/consts.js | 1 + 3 files changed, 34 insertions(+), 19 deletions(-) diff --git a/index.js b/index.js index 1754c156..7c522ea6 100644 --- a/index.js +++ b/index.js @@ -1,7 +1,10 @@ const Observable = require('./utils/observable'); const utils = require('./utils'); const { getMoneyMaker } = require('pesa'); -const { DEFAULT_INTERNAL_PRECISION } = require('./utils/consts'); +const { + DEFAULT_INTERNAL_PRECISION, + DEFAULT_DISPLAY_PRECISION, +} = require('./utils/consts'); module.exports = { initializeAndRegister(customModels = {}, force = false) { @@ -20,27 +23,25 @@ module.exports = { let values; try { // error thrown if migration hasn't taken place - values = await frappe.db.getSingleValues({ - fieldname: 'internalPrecision', - parent: 'SystemSettings', - }); + values = await frappe.db.getSingleValues( + { + fieldname: 'internalPrecision', + parent: 'SystemSettings', + }, + { + fieldname: 'displayPrecision', + parent: 'SystemSettings', + } + ); } catch { values = []; } - let { internalPrecision: precision } = values.reduce( - (acc, { fieldname, value }) => { + let { internalPrecision: precision, displayPrecision: display } = + values.reduce((acc, { fieldname, value }) => { acc[fieldname] = value; return acc; - }, - {} - ); - - if (typeof precision === 'undefined') { - precision = this.getMeta('SystemSettings').fields.find( - (f) => f.fieldname === 'internalPrecision' - )?.default; - } + }, {}); if (typeof precision === 'undefined') { precision = DEFAULT_INTERNAL_PRECISION; @@ -50,7 +51,15 @@ module.exports = { precision = parseInt(precision); } - this.pesa = getMoneyMaker({ currency, precision }); + if (typeof display === 'undefined') { + display = DEFAULT_DISPLAY_PRECISION; + } + + if (typeof display === 'string') { + display = parseInt(display); + } + + this.pesa = getMoneyMaker({ currency, precision, display }); }, init(force) { diff --git a/models/doctype/SystemSettings/SystemSettings.js b/models/doctype/SystemSettings/SystemSettings.js index 92396cfe..c2b29e79 100644 --- a/models/doctype/SystemSettings/SystemSettings.js +++ b/models/doctype/SystemSettings/SystemSettings.js @@ -1,5 +1,9 @@ const { DateTime } = require('luxon'); const { _ } = require('frappejs/utils'); +const { + DEFAULT_DISPLAY_PRECISION, + DEFAULT_INTERNAL_PRECISION, +} = require('../../../utils/consts'); let dateFormatOptions = (() => { let formats = [ @@ -43,7 +47,7 @@ module.exports = { fieldname: 'displayPrecision', label: 'Display Precision', fieldtype: 'Int', - default: 2, + default: DEFAULT_DISPLAY_PRECISION, required: 1, minValue: 0, maxValue: 9, @@ -61,7 +65,8 @@ module.exports = { fieldname: 'internalPrecision', label: 'Internal Precision', fieldtype: 'Int', - default: 11, + minValue: 0, + default: DEFAULT_INTERNAL_PRECISION, description: _( 'Sets the internal precision used for monetary calculations. Above 6 should be sufficient for most currencies.' ), diff --git a/utils/consts.js b/utils/consts.js index f601d1d8..2fc503b5 100644 --- a/utils/consts.js +++ b/utils/consts.js @@ -1 +1,2 @@ export const DEFAULT_INTERNAL_PRECISION = 11; +export const DEFAULT_DISPLAY_PRECISION = 2; From e3351e1e0637847481937a5d3b831052a35e2565 Mon Sep 17 00:00:00 2001 From: 18alantom <2.alan.tom@gmail.com> Date: Thu, 23 Dec 2021 18:06:55 +0530 Subject: [PATCH 09/25] feat: add locale for number formatting --- models/doctype/SystemSettings/SystemSettings.js | 9 +++++++++ utils/consts.js | 1 + 2 files changed, 10 insertions(+) diff --git a/models/doctype/SystemSettings/SystemSettings.js b/models/doctype/SystemSettings/SystemSettings.js index c2b29e79..d2ea81bb 100644 --- a/models/doctype/SystemSettings/SystemSettings.js +++ b/models/doctype/SystemSettings/SystemSettings.js @@ -3,6 +3,7 @@ const { _ } = require('frappejs/utils'); const { DEFAULT_DISPLAY_PRECISION, DEFAULT_INTERNAL_PRECISION, + DEFAULT_LOCALE, } = require('../../../utils/consts'); let dateFormatOptions = (() => { @@ -43,6 +44,13 @@ module.exports = { required: 1, description: _('Sets the app-wide date display format.'), }, + { + fieldname: 'locale', + label: 'Locale', + fieldtype: 'Data', + default: DEFAULT_LOCALE, + description: _('Set the local code, this is used for number formatting.'), + }, { fieldname: 'displayPrecision', label: 'Display Precision', @@ -92,6 +100,7 @@ module.exports = { ], quickEditFields: [ 'dateFormat', + 'locale', 'displayPrecision', 'hideGetStarted', 'autoUpdate', diff --git a/utils/consts.js b/utils/consts.js index 2fc503b5..df3432cf 100644 --- a/utils/consts.js +++ b/utils/consts.js @@ -1,2 +1,3 @@ export const DEFAULT_INTERNAL_PRECISION = 11; export const DEFAULT_DISPLAY_PRECISION = 2; +export const DEFAULT_LOCALE = 'en-IN'; From ac642b205b7ac2bbaca26baea39f50a72875066d Mon Sep 17 00:00:00 2001 From: 18alantom <2.alan.tom@gmail.com> Date: Thu, 23 Dec 2021 19:34:49 +0530 Subject: [PATCH 10/25] fix: use Intl and locales for currency formatting --- utils/format.js | 31 ++++++++++++++++----------- utils/numberFormat.js | 50 +++++++++++++++++++++++++++++++++++++------ 2 files changed, 62 insertions(+), 19 deletions(-) diff --git a/utils/format.js b/utils/format.js index f6d162b8..8caee5db 100644 --- a/utils/format.js +++ b/utils/format.js @@ -46,23 +46,28 @@ module.exports = { } } return value; - } + }, }; -function formatCurrency(value, df, doc) { - let currency = df.currency || ''; - if (doc && df.getCurrency) { - if (doc.meta && doc.meta.isChild) { - currency = df.getCurrency(doc, doc.parentdoc); - } else { - currency = df.getCurrency(doc); - } +function getCurrency(df, doc) { + if (!(doc && df.getCurrency)) { + return df.currency || frappe.AccountingSettings.currency || ''; } - if (!currency) { - currency = frappe.AccountingSettings.currency; + if (doc.meta && doc.meta.isChild) { + return df.getCurrency(doc, doc.parentdoc); } - let currencySymbol = frappe.currencySymbols[currency] || ''; - return currencySymbol + ' ' + numberFormat.formatNumber(value); + return df.getCurrency(doc); +} + +function formatCurrency(value, df, doc) { + const currency = getCurrency(df, doc); + const valueString = numberFormat.formatCurrency(value); + const currencySymbol = frappe.currencySymbols[currency]; + + if (currencySymbol) { + return currencySymbol + ' ' + valueString; + } + return valueString; } diff --git a/utils/numberFormat.js b/utils/numberFormat.js index fee4a11a..c874bcbf 100644 --- a/utils/numberFormat.js +++ b/utils/numberFormat.js @@ -1,3 +1,5 @@ +const frappe = require('frappejs'); +const { DEFAULT_DISPLAY_PRECISION, DEFAULT_LOCALE } = require('./consts'); const numberFormats = { '#,###.##': { fractionSep: '.', groupSep: ',', precision: 2 }, '#.###,##': { fractionSep: ',', groupSep: '.', precision: 2 }, @@ -8,7 +10,7 @@ const numberFormats = { '#,##,###.##': { fractionSep: '.', groupSep: ',', precision: 2 }, '#,###.###': { fractionSep: '.', groupSep: ',', precision: 3 }, '#.###': { fractionSep: '', groupSep: '.', precision: 0 }, - '#,###': { fractionSep: '', groupSep: ',', precision: 0 } + '#,###': { fractionSep: '', groupSep: ',', precision: 0 }, }; module.exports = { @@ -65,10 +67,7 @@ module.exports = { str += info.groupSep; } } - parts[0] = str - .split('') - .reverse() - .join(''); + parts[0] = str.split('').reverse().join(''); } if (parts[0] + '' == '') { parts[0] = '0'; @@ -105,5 +104,44 @@ module.exports = { removeSeparator(text, sep) { return text.replace(new RegExp(sep === '.' ? '\\.' : sep, 'g'), ''); - } + }, + + getDisplayPrecision() { + return frappe.SystemSettings.displayPrecision ?? DEFAULT_DISPLAY_PRECISION; + }, + + getCurrencyFormatter() { + if (frappe.currencyFormatter) { + return frappe.currencyFormatter; + } + + const locale = frappe.SystemSettings.locale ?? DEFAULT_LOCALE; + const display = this.getDisplayPrecision(); + + return (frappe.currencyFormatter = Intl.NumberFormat(locale, { + style: 'decimal', + minimumFractionDigits: display, + })); + }, + + formatCurrency(value) { + const currencyFormatter = this.getCurrencyFormatter(); + if (typeof value === 'number') { + return currencyFormatter.format(value); + } + + if (value.round) { + const displayPrecision = this.getDisplayPrecision(); + return currencyFormatter.format(value.round(displayPrecision)); + } + + const formattedCurrency = currencyFormatter(value); + if (formattedCurrency === 'NaN') { + throw Error( + `invalide value passed to formatCurrency: '${value}' of type ${typeof value}` + ); + } + + return formattedCurrency; + }, }; From 4b0cf18b38b785199d54691da128e7331573812f Mon Sep 17 00:00:00 2001 From: 18alantom <2.alan.tom@gmail.com> Date: Mon, 27 Dec 2021 13:13:38 +0530 Subject: [PATCH 11/25] feat: util to check if pesa, also fix indents --- utils/index.js | 135 +++++++++++++++++++++++++++---------------------- 1 file changed, 74 insertions(+), 61 deletions(-) diff --git a/utils/index.js b/utils/index.js index 18917a01..2518ab19 100644 --- a/utils/index.js +++ b/utils/index.js @@ -1,68 +1,76 @@ -Array.prototype.equals = function( array ) { - return this.length == array.length && - this.every( function(item,i) { return item == array[i] } ); -} +const { pesa } = require('pesa'); + +Array.prototype.equals = function (array) { + return ( + this.length == array.length && + this.every(function (item, i) { + return item == array[i]; + }) + ); +}; function slug(str) { - return str.replace(/(?:^\w|[A-Z]|\b\w)/g, function(letter, index) { - return index == 0 ? letter.toLowerCase() : letter.toUpperCase(); - }).replace(/\s+/g, ''); + return str + .replace(/(?:^\w|[A-Z]|\b\w)/g, function (letter, index) { + return index == 0 ? letter.toLowerCase() : letter.toUpperCase(); + }) + .replace(/\s+/g, ''); } function getRandomString() { - return Math.random().toString(36).substr(3); + return Math.random().toString(36).substr(3); } async function sleep(seconds) { - return new Promise(resolve => { - setTimeout(resolve, seconds * 1000); - }); + return new Promise((resolve) => { + setTimeout(resolve, seconds * 1000); + }); } function _(text, args) { - // should return translated text - return stringReplace(text, args); + // should return translated text + return stringReplace(text, args); } function stringReplace(str, args) { - if (!Array.isArray(args)) { - args = [args]; + if (!Array.isArray(args)) { + args = [args]; + } + + if (str == undefined) return str; + + let unkeyed_index = 0; + return str.replace(/\{(\w*)\}/g, (match, key) => { + if (key === '') { + key = unkeyed_index; + unkeyed_index++; } - - if(str==undefined) return str; - - let unkeyed_index = 0; - return str.replace(/\{(\w*)\}/g, (match, key) => { - if (key === '') { - key = unkeyed_index; - unkeyed_index++ - } - if (key == +key) { - return args[key] !== undefined - ? args[key] - : match; - } - }); + if (key == +key) { + return args[key] !== undefined ? args[key] : match; + } + }); } function getQueryString(params) { - if (!params) return ''; - let parts = []; - for (let key in params) { - if (key!=null && params[key]!=null) { - parts.push(encodeURIComponent(key) + '=' + encodeURIComponent(params[key])) - } + if (!params) return ''; + let parts = []; + for (let key in params) { + if (key != null && params[key] != null) { + parts.push( + encodeURIComponent(key) + '=' + encodeURIComponent(params[key]) + ); } - return parts.join('&'); + } + return parts.join('&'); } function asyncHandler(fn) { - return (req, res, next) => Promise.resolve(fn(req, res, next)) - .catch((err) => { - console.log(err); - // handle error - res.status(err.statusCode || 500).send({error: err.message}); - }); + return (req, res, next) => + Promise.resolve(fn(req, res, next)).catch((err) => { + console.log(err); + // handle error + res.status(err.statusCode || 500).send({ error: err.message }); + }); } /** @@ -70,15 +78,15 @@ function asyncHandler(fn) { * @param {Number} n */ function range(n) { - return Array.from(Array(4)).map((d, i) => i) + return Array.from(Array(4)).map((d, i) => i); } -function unique(list, key = it => it) { - var seen = {}; - return list.filter(item => { - var k = key(item); - return seen.hasOwnProperty(k) ? false : (seen[k] = true); - }); +function unique(list, key = (it) => it) { + var seen = {}; + return list.filter((item) => { + var k = key(item); + return seen.hasOwnProperty(k) ? false : (seen[k] = true); + }); } function getDuplicates(array) { @@ -96,15 +104,20 @@ function getDuplicates(array) { return duplicates; } -module.exports = { - _, - slug, - getRandomString, - sleep, - stringReplace, - getQueryString, - asyncHandler, - range, - unique, - getDuplicates +function isPesa(value) { + return value instanceof pesa().constructor; } + +module.exports = { + _, + slug, + getRandomString, + sleep, + stringReplace, + getQueryString, + asyncHandler, + range, + unique, + getDuplicates, + isPesa, +}; From e2148911565f69de052984bd54432edf457d178f Mon Sep 17 00:00:00 2001 From: 18alantom <2.alan.tom@gmail.com> Date: Mon, 27 Dec 2021 16:57:58 +0530 Subject: [PATCH 12/25] fix: update calcs - set child doc defaults - remove Currency from rounding --- model/document.js | 91 ++++++++++++++++++++++++++++++----------------- 1 file changed, 58 insertions(+), 33 deletions(-) diff --git a/model/document.js b/model/document.js index 84ea48ba..80097c50 100644 --- a/model/document.js +++ b/model/document.js @@ -1,6 +1,7 @@ const frappe = require('frappejs'); const Observable = require('frappejs/utils/observable'); const naming = require('./naming'); +const { isPesa } = require('../utils/index'); const { round } = require('frappejs/utils/numberFormat'); const { DEFAULT_INTERNAL_PRECISION } = require('../utils/consts'); @@ -107,17 +108,12 @@ module.exports = class BaseDocument extends Observable { setDefaults() { for (let field of this.meta.fields) { if (this[field.fieldname] == null) { - let defaultValue = null; + let defaultValue = getPreDefaultValues(field.fieldtype); - if (field.fieldtype === 'Table') { - defaultValue = []; - } - if (field.default) { - if (typeof field.default === 'function') { - defaultValue = field.default(this); - } else { - defaultValue = field.default; - } + if (typeof field.default === 'function') { + defaultValue = field.default(this); + } else if (field.default !== undefined) { + defaultValue = field.default; } this[field.fieldname] = defaultValue; @@ -137,8 +133,10 @@ module.exports = class BaseDocument extends Observable { } if (['Int', 'Check'].includes(field.fieldtype)) { value = parseInt(value, 10); - } else if (['Float', 'Currency'].includes(field.fieldtype)) { + } else if (field.fieldtype === 'Float') { value = parseFloat(value); + } else if (field.fieldtype === 'Currency' && !isPesa(value)) { + value = frappe.pesa(value); } this[field.fieldname] = value; } @@ -170,23 +168,25 @@ module.exports = class BaseDocument extends Observable { _initChild(data, key) { if (data instanceof BaseDocument) { return data; - } else { - data.doctype = this.meta.getField(key).childtype; - data.parent = this.name; - data.parenttype = this.doctype; - data.parentfield = key; - data.parentdoc = this; - - if (!data.idx) { - data.idx = (this[key] || []).length; - } - - if (!data.name) { - data.name = frappe.getRandomString(); - } - - return new BaseDocument(data); } + + data.doctype = this.meta.getField(key).childtype; + data.parent = this.name; + data.parenttype = this.doctype; + data.parentfield = key; + data.parentdoc = this; + + if (!data.idx) { + data.idx = (this[key] || []).length; + } + + if (!data.name) { + data.name = frappe.getRandomString(); + } + + const childDoc = new BaseDocument(data); + childDoc.setDefaults(); + return childDoc; } validateInsert() { @@ -509,7 +509,7 @@ module.exports = class BaseDocument extends Observable { return; } - if (['Float', 'Currency'].includes(field.fieldtype)) { + if ('Float' === field.fieldtype) { value = this.round(value, field); } @@ -527,7 +527,7 @@ module.exports = class BaseDocument extends Observable { roundFloats() { let fields = this.meta .getValidFields() - .filter((df) => ['Float', 'Currency', 'Table'].includes(df.fieldtype)); + .filter((df) => ['Float', 'Table'].includes(df.fieldtype)); for (let df of fields) { let value = this[df.fieldname]; @@ -659,10 +659,21 @@ module.exports = class BaseDocument extends Observable { } // helper functions - getSum(tablefield, childfield) { - return (this[tablefield] || []) - .map((d) => parseFloat(d[childfield], 10) || 0) - .reduce((a, b) => a + b, 0); + getSum(tablefield, childfield, convertToFloat = true) { + const sum = (this[tablefield] || []) + .map((d) => { + const value = d[childfield] ?? 0; + if (!isPesa(value)) { + return frappe.pesa(value); + } + return value; + }) + .reduce((a, b) => a.add(b), frappe.pesa(0)); + + if (convertToFloat) { + return sum.float; + } + return sum; } getFrom(doctype, name, fieldname) { @@ -690,3 +701,17 @@ module.exports = class BaseDocument extends Observable { }, {}); } }; + +function getPreDefaultValues(fieldtype) { + switch (fieldtype) { + case 'Table': + return []; + case 'Currency': + return frappe.pesa(0.0); + case 'Int': + case 'Float': + return 0; + default: + return null; + } +} From b058b06af7214c1a70972bef05b9cd6ab007a626 Mon Sep 17 00:00:00 2001 From: 18alantom <2.alan.tom@gmail.com> Date: Tue, 28 Dec 2021 11:17:04 +0530 Subject: [PATCH 13/25] chore: bump pesa --- package.json | 2 +- yarn.lock | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/package.json b/package.json index 27b8794a..781060f8 100644 --- a/package.json +++ b/package.json @@ -32,7 +32,7 @@ "multer": "^1.4.3", "node-fetch": "^3.0.0", "nunjucks": "^3.2.3", - "pesa": "^1.0.4", + "pesa": "^1.0.5", "postcss": "^8.3.11", "postcss-loader": "^6.2.0", "sass-loader": "^12.3.0", diff --git a/yarn.lock b/yarn.lock index 84e6bdc5..5c62aca0 100644 --- a/yarn.lock +++ b/yarn.lock @@ -3417,10 +3417,10 @@ performance-now@^2.1.0: resolved "https://registry.yarnpkg.com/performance-now/-/performance-now-2.1.0.tgz#6309f4e0e5fa913ec1c69307ae364b4b377c9e7b" integrity sha1-Ywn04OX6kT7BxpMHrjZLSzd8nns= -pesa@^1.0.4: - version "1.0.4" - resolved "https://registry.yarnpkg.com/pesa/-/pesa-1.0.4.tgz#aaed9760b319d1435ea663bdb96c0a99f88cbd53" - integrity sha512-SuXEyavfSv1GGk625Mgdmw8ZJvNaMQ6C5e413zxTpkdLmDdTwWidhlQDDbFuI+Drj1GBHu/L20NVsoRUjUjU5w== +pesa@^1.0.5: + version "1.0.5" + resolved "https://registry.yarnpkg.com/pesa/-/pesa-1.0.5.tgz#56c01c6d538a9078aadd324cbf8a44dff93a5a91" + integrity sha512-qxc2Z4RltIzIWAhoo5eCSKr6oF3AAH9ajojgfWELPjrZ+NRhnC59oHMW8IzeXrkXYozMNmtaR/peTeNtvfYiKg== pg-connection-string@2.5.0: version "2.5.0" From 581de5f6a9da721ccf7c134f7ae275919345cf28 Mon Sep 17 00:00:00 2001 From: 18alantom <2.alan.tom@gmail.com> Date: Tue, 28 Dec 2021 11:37:59 +0530 Subject: [PATCH 14/25] refactor: don't pass display, it's set on init --- utils/numberFormat.js | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/utils/numberFormat.js b/utils/numberFormat.js index c874bcbf..dc023c65 100644 --- a/utils/numberFormat.js +++ b/utils/numberFormat.js @@ -131,8 +131,7 @@ module.exports = { } if (value.round) { - const displayPrecision = this.getDisplayPrecision(); - return currencyFormatter.format(value.round(displayPrecision)); + return currencyFormatter.format(value.round()); } const formattedCurrency = currencyFormatter(value); From 45f7ccf54c935bb317225a32d39418001efd197d Mon Sep 17 00:00:00 2001 From: 18alantom <2.alan.tom@gmail.com> Date: Tue, 28 Dec 2021 13:35:33 +0530 Subject: [PATCH 15/25] chore: bump pesa --- package.json | 2 +- yarn.lock | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/package.json b/package.json index 781060f8..92759883 100644 --- a/package.json +++ b/package.json @@ -32,7 +32,7 @@ "multer": "^1.4.3", "node-fetch": "^3.0.0", "nunjucks": "^3.2.3", - "pesa": "^1.0.5", + "pesa": "^1.1.1", "postcss": "^8.3.11", "postcss-loader": "^6.2.0", "sass-loader": "^12.3.0", diff --git a/yarn.lock b/yarn.lock index 5c62aca0..b6f703ec 100644 --- a/yarn.lock +++ b/yarn.lock @@ -3417,10 +3417,10 @@ performance-now@^2.1.0: resolved "https://registry.yarnpkg.com/performance-now/-/performance-now-2.1.0.tgz#6309f4e0e5fa913ec1c69307ae364b4b377c9e7b" integrity sha1-Ywn04OX6kT7BxpMHrjZLSzd8nns= -pesa@^1.0.5: - version "1.0.5" - resolved "https://registry.yarnpkg.com/pesa/-/pesa-1.0.5.tgz#56c01c6d538a9078aadd324cbf8a44dff93a5a91" - integrity sha512-qxc2Z4RltIzIWAhoo5eCSKr6oF3AAH9ajojgfWELPjrZ+NRhnC59oHMW8IzeXrkXYozMNmtaR/peTeNtvfYiKg== +pesa@^1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/pesa/-/pesa-1.1.1.tgz#cfe3e0d88ab95dff6fbbe4c704bd99050f6275f7" + integrity sha512-Dchotfg04CaWeQxRqeT9enJ6y5sFnW/GoImMGgNbGUT77Vhm72wGQE5ens36ht7N8LVxWMfJwWzdoWZl38RUWQ== pg-connection-string@2.5.0: version "2.5.0" From 0c556ff8a4cba082713464e4fa9d86b3e4371fe3 Mon Sep 17 00:00:00 2001 From: 18alantom <2.alan.tom@gmail.com> Date: Wed, 29 Dec 2021 11:06:17 +0530 Subject: [PATCH 16/25] fix: foolproofing currency defaults --- model/document.js | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/model/document.js b/model/document.js index 80097c50..3834c0ac 100644 --- a/model/document.js +++ b/model/document.js @@ -116,6 +116,10 @@ module.exports = class BaseDocument extends Observable { defaultValue = field.default; } + if (field.fieldtype === 'Currency' && !isPesa(defaultValue)) { + defaultValue = frappe.pesa(defaultValue); + } + this[field.fieldname] = defaultValue; } } From e249b033f1f22a96c53e0d3fb397e7cae7b5f6a2 Mon Sep 17 00:00:00 2001 From: 18alantom <2.alan.tom@gmail.com> Date: Wed, 29 Dec 2021 11:23:16 +0530 Subject: [PATCH 17/25] fix: display a better error message --- backends/database.js | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/backends/database.js b/backends/database.js index cbb6ec22..b94e4c31 100644 --- a/backends/database.js +++ b/backends/database.js @@ -359,8 +359,15 @@ module.exports = class Database extends Observable { getDocFormattedValues(field, value) { // format for usage, not going into the db - if (field.fieldtype === 'Currency') { - return frappe.pesa(value); + try { + if (field.fieldtype === 'Currency') { + return frappe.pesa(value); + } + } catch (err) { + err.message += ` value: '${value}' of type: ${typeof value}, fieldname: '${ + field.fieldname + }', label: '${field.label}'`; + throw err; } return value; } From 84724ff731631fe5ee91eb8b300de5a227fb0f6a Mon Sep 17 00:00:00 2001 From: 18alantom <2.alan.tom@gmail.com> Date: Wed, 29 Dec 2021 11:43:39 +0530 Subject: [PATCH 18/25] fix: more informative error messages - set currency columns as not null --- backends/database.js | 5 ++++- model/document.js | 7 ++++++- 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/backends/database.js b/backends/database.js index b94e4c31..e6bed042 100644 --- a/backends/database.js +++ b/backends/database.js @@ -163,7 +163,10 @@ module.exports = class Database extends Observable { } // required - if (!!field.required && !(field.required instanceof Function)) { + if ( + (!!field.required && !(field.required instanceof Function)) || + field.fieldtype === 'Currency' + ) { column.notNullable(); } diff --git a/model/document.js b/model/document.js index 3834c0ac..c816a991 100644 --- a/model/document.js +++ b/model/document.js @@ -668,7 +668,12 @@ module.exports = class BaseDocument extends Observable { .map((d) => { const value = d[childfield] ?? 0; if (!isPesa(value)) { - return frappe.pesa(value); + try { + return frappe.pesa(value); + } catch (err) { + err.message += ` value: '${value}' of type: ${typeof value}, fieldname: '${tablefield}', childfield: '${childfield}'`; + throw err; + } } return value; }) From 3ac628f4b97961233c99ab9ab7275e3050726f79 Mon Sep 17 00:00:00 2001 From: 18alantom <2.alan.tom@gmail.com> Date: Wed, 29 Dec 2021 16:02:24 +0530 Subject: [PATCH 19/25] fix: bug, forgot to call .format --- utils/numberFormat.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/utils/numberFormat.js b/utils/numberFormat.js index dc023c65..7fc8dad5 100644 --- a/utils/numberFormat.js +++ b/utils/numberFormat.js @@ -134,10 +134,10 @@ module.exports = { return currencyFormatter.format(value.round()); } - const formattedCurrency = currencyFormatter(value); + const formattedCurrency = currencyFormatter.format(value); if (formattedCurrency === 'NaN') { throw Error( - `invalide value passed to formatCurrency: '${value}' of type ${typeof value}` + `invalid value passed to formatCurrency: '${value}' of type ${typeof value}` ); } From 8fcfd9489001a89e57bf8456a275c1bacfafce60 Mon Sep 17 00:00:00 2001 From: 18alantom <2.alan.tom@gmail.com> Date: Wed, 29 Dec 2021 16:22:40 +0530 Subject: [PATCH 20/25] chore: bump pesa, add neq, neg --- package.json | 2 +- yarn.lock | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/package.json b/package.json index 92759883..8b6738b7 100644 --- a/package.json +++ b/package.json @@ -32,7 +32,7 @@ "multer": "^1.4.3", "node-fetch": "^3.0.0", "nunjucks": "^3.2.3", - "pesa": "^1.1.1", + "pesa": "^1.1.2", "postcss": "^8.3.11", "postcss-loader": "^6.2.0", "sass-loader": "^12.3.0", diff --git a/yarn.lock b/yarn.lock index b6f703ec..ca508039 100644 --- a/yarn.lock +++ b/yarn.lock @@ -3417,10 +3417,10 @@ performance-now@^2.1.0: resolved "https://registry.yarnpkg.com/performance-now/-/performance-now-2.1.0.tgz#6309f4e0e5fa913ec1c69307ae364b4b377c9e7b" integrity sha1-Ywn04OX6kT7BxpMHrjZLSzd8nns= -pesa@^1.1.1: - version "1.1.1" - resolved "https://registry.yarnpkg.com/pesa/-/pesa-1.1.1.tgz#cfe3e0d88ab95dff6fbbe4c704bd99050f6275f7" - integrity sha512-Dchotfg04CaWeQxRqeT9enJ6y5sFnW/GoImMGgNbGUT77Vhm72wGQE5ens36ht7N8LVxWMfJwWzdoWZl38RUWQ== +pesa@^1.1.2: + version "1.1.2" + resolved "https://registry.yarnpkg.com/pesa/-/pesa-1.1.2.tgz#84e765095c198ac03ccc397458cabfd512cfdbe7" + integrity sha512-eL9Vc8IOqO/DT+iv94JIBgR2HjcLWU/9bjvmGktVAJqy9C7rAYuT6EdyJsx/LGbOUk9wTE0LbKMzW5pGr5e7rg== pg-connection-string@2.5.0: version "2.5.0" From 021d1d2a39433ef08ce5a41c5fa7e4372a33b5f9 Mon Sep 17 00:00:00 2001 From: 18alantom <2.alan.tom@gmail.com> Date: Wed, 29 Dec 2021 17:22:07 +0530 Subject: [PATCH 21/25] fix: better message on format error --- utils/format.js | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/utils/format.js b/utils/format.js index 8caee5db..932126b7 100644 --- a/utils/format.js +++ b/utils/format.js @@ -63,7 +63,14 @@ function getCurrency(df, doc) { function formatCurrency(value, df, doc) { const currency = getCurrency(df, doc); - const valueString = numberFormat.formatCurrency(value); + let valueString; + try { + valueString = numberFormat.formatCurrency(value); + } catch (err) { + err.message += ` value: '${value}', type: ${typeof value}`; + console.error(df); + throw err; + } const currencySymbol = frappe.currencySymbols[currency]; if (currencySymbol) { From 36f9e47d58cfbb58a969479122b6290b5c2d401b Mon Sep 17 00:00:00 2001 From: 18alantom <2.alan.tom@gmail.com> Date: Fri, 31 Dec 2021 13:40:17 +0530 Subject: [PATCH 22/25] chore: deprecate numberFormat --- common/index.js | 18 +++--- model/document.js | 3 +- tests/test_utils.js | 35 ---------- utils/format.js | 77 ++++++++++++++++------ utils/numberFormat.js | 146 ------------------------------------------ 5 files changed, 66 insertions(+), 213 deletions(-) delete mode 100644 tests/test_utils.js delete mode 100644 utils/numberFormat.js diff --git a/common/index.js b/common/index.js index 9a7afec7..50e71fba 100644 --- a/common/index.js +++ b/common/index.js @@ -1,17 +1,15 @@ const utils = require('../utils'); -const numberFormat = require('../utils/numberFormat'); const format = require('../utils/format'); const errors = require('./errors'); const BaseDocument = require('frappejs/model/document'); const BaseMeta = require('frappejs/model/meta'); module.exports = { - initLibs(frappe) { - Object.assign(frappe, utils); - Object.assign(frappe, numberFormat); - Object.assign(frappe, format); - frappe.errors = errors; - frappe.BaseDocument = BaseDocument; - frappe.BaseMeta = BaseMeta; - } -} \ No newline at end of file + initLibs(frappe) { + Object.assign(frappe, utils); + Object.assign(frappe, format); + frappe.errors = errors; + frappe.BaseDocument = BaseDocument; + frappe.BaseMeta = BaseMeta; + }, +}; diff --git a/model/document.js b/model/document.js index c816a991..fbaa8eeb 100644 --- a/model/document.js +++ b/model/document.js @@ -2,7 +2,6 @@ const frappe = require('frappejs'); const Observable = require('frappejs/utils/observable'); const naming = require('./naming'); const { isPesa } = require('../utils/index'); -const { round } = require('frappejs/utils/numberFormat'); const { DEFAULT_INTERNAL_PRECISION } = require('../utils/consts'); module.exports = class BaseDocument extends Observable { @@ -696,7 +695,7 @@ module.exports = class BaseDocument extends Observable { } const precision = frappe.SystemSettings.internalPrecision ?? DEFAULT_INTERNAL_PRECISION; - return round(value, precision); + return frappe.pesa(value).clip(precision).float; } isNew() { diff --git a/tests/test_utils.js b/tests/test_utils.js deleted file mode 100644 index 0dc51f9a..00000000 --- a/tests/test_utils.js +++ /dev/null @@ -1,35 +0,0 @@ -const numberFormat = require('frappejs/utils/numberFormat'); -const assert = require('assert'); - -describe('Number Formatting', () => { - it('should format numbers', () => { - assert.equal(numberFormat.formatNumber(100), '100.00'); - assert.equal(numberFormat.formatNumber(1000), '1,000.00'); - assert.equal(numberFormat.formatNumber(10000), '10,000.00'); - assert.equal(numberFormat.formatNumber(100000), '100,000.00'); - assert.equal(numberFormat.formatNumber(1000000), '1,000,000.00'); - assert.equal(numberFormat.formatNumber(100.1234), '100.12'); - assert.equal(numberFormat.formatNumber(1000.1234), '1,000.12'); - }); - - it('should parse numbers', () => { - assert.equal(numberFormat.parseNumber('100.00'), 100); - assert.equal(numberFormat.parseNumber('1,000.00'), 1000); - assert.equal(numberFormat.parseNumber('10,000.00'), 10000); - assert.equal(numberFormat.parseNumber('100,000.00'), 100000); - assert.equal(numberFormat.parseNumber('1,000,000.00'), 1000000); - assert.equal(numberFormat.parseNumber('100.1234'), 100.1234); - assert.equal(numberFormat.parseNumber('1,000.1234'), 1000.1234); - }); - - it('should format lakhs and crores', () => { - assert.equal(numberFormat.formatNumber(100, '#,##,###.##'), '100.00'); - assert.equal(numberFormat.formatNumber(1000, '#,##,###.##'), '1,000.00'); - assert.equal(numberFormat.formatNumber(10000, '#,##,###.##'), '10,000.00'); - assert.equal(numberFormat.formatNumber(100000, '#,##,###.##'), '1,00,000.00'); - assert.equal(numberFormat.formatNumber(1000000, '#,##,###.##'), '10,00,000.00'); - assert.equal(numberFormat.formatNumber(10000000, '#,##,###.##'), '1,00,00,000.00'); - assert.equal(numberFormat.formatNumber(100.1234, '#,##,###.##'), '100.12'); - assert.equal(numberFormat.formatNumber(1000.1234, '#,##,###.##'), '1,000.12'); - }); -}); \ No newline at end of file diff --git a/utils/format.js b/utils/format.js index 932126b7..e00a85ac 100644 --- a/utils/format.js +++ b/utils/format.js @@ -1,6 +1,6 @@ -const numberFormat = require('./numberFormat'); const luxon = require('luxon'); const frappe = require('frappejs'); +const { DEFAULT_DISPLAY_PRECISION, DEFAULT_LOCALE } = require('./consts'); module.exports = { format(value, df, doc) { @@ -13,7 +13,8 @@ module.exports = { } if (df.fieldtype === 'Currency') { - value = formatCurrency(value, df, doc); + const currency = getCurrency(df, doc); + value = formatCurrency(value, currency); } else if (df.fieldtype === 'Date') { let dateFormat; if (!frappe.SystemSettings) { @@ -47,8 +48,62 @@ module.exports = { } return value; }, + formatCurrency, + formatNumber, }; +function formatCurrency(value, currency) { + let valueString; + try { + valueString = formatNumber(value); + } catch (err) { + err.message += ` value: '${value}', type: ${typeof value}`; + throw err; + } + + const currencySymbol = frappe.currencySymbols[currency]; + if (currencySymbol) { + return currencySymbol + ' ' + valueString; + } + + return valueString; +} + +function formatNumber(value) { + const currencyFormatter = getNumberFormatter(); + if (typeof value === 'number') { + return currencyFormatter.format(value); + } + + if (value.round) { + return currencyFormatter.format(value.round()); + } + + const formattedCurrency = currencyFormatter.format(value); + if (formattedCurrency === 'NaN') { + throw Error( + `invalid value passed to formatCurrency: '${value}' of type ${typeof value}` + ); + } + + return formattedCurrency; +} + +function getNumberFormatter() { + if (frappe.currencyFormatter) { + return frappe.currencyFormatter; + } + + const locale = frappe.SystemSettings.locale ?? DEFAULT_LOCALE; + const display = + frappe.SystemSettings.displayPrecision ?? DEFAULT_DISPLAY_PRECISION; + + return (frappe.currencyFormatter = Intl.NumberFormat(locale, { + style: 'decimal', + minimumFractionDigits: display, + })); +} + function getCurrency(df, doc) { if (!(doc && df.getCurrency)) { return df.currency || frappe.AccountingSettings.currency || ''; @@ -60,21 +115,3 @@ function getCurrency(df, doc) { return df.getCurrency(doc); } - -function formatCurrency(value, df, doc) { - const currency = getCurrency(df, doc); - let valueString; - try { - valueString = numberFormat.formatCurrency(value); - } catch (err) { - err.message += ` value: '${value}', type: ${typeof value}`; - console.error(df); - throw err; - } - const currencySymbol = frappe.currencySymbols[currency]; - - if (currencySymbol) { - return currencySymbol + ' ' + valueString; - } - return valueString; -} diff --git a/utils/numberFormat.js b/utils/numberFormat.js deleted file mode 100644 index 7fc8dad5..00000000 --- a/utils/numberFormat.js +++ /dev/null @@ -1,146 +0,0 @@ -const frappe = require('frappejs'); -const { DEFAULT_DISPLAY_PRECISION, DEFAULT_LOCALE } = require('./consts'); -const numberFormats = { - '#,###.##': { fractionSep: '.', groupSep: ',', precision: 2 }, - '#.###,##': { fractionSep: ',', groupSep: '.', precision: 2 }, - '# ###.##': { fractionSep: '.', groupSep: ' ', precision: 2 }, - '# ###,##': { fractionSep: ',', groupSep: ' ', precision: 2 }, - "#'###.##": { fractionSep: '.', groupSep: "'", precision: 2 }, - '#, ###.##': { fractionSep: '.', groupSep: ', ', precision: 2 }, - '#,##,###.##': { fractionSep: '.', groupSep: ',', precision: 2 }, - '#,###.###': { fractionSep: '.', groupSep: ',', precision: 3 }, - '#.###': { fractionSep: '', groupSep: '.', precision: 0 }, - '#,###': { fractionSep: '', groupSep: ',', precision: 0 }, -}; - -module.exports = { - // parse a formatted number string - // from "4,555,000.34" -> 4555000.34 - parseNumber(number, format = '#,###.##') { - if (!number) { - return 0; - } - if (typeof number === 'number') { - return number; - } - const info = this.getFormatInfo(format); - return parseFloat(this.removeSeparator(number, info.groupSep)); - }, - - formatNumber(number, format = '#,###.##', precision = null) { - if (!number) { - number = 0; - } - let info = this.getFormatInfo(format); - if (precision) { - info.precision = precision; - } - let is_negative = false; - - number = this.parseNumber(number); - if (number < 0) { - is_negative = true; - } - number = Math.abs(number); - number = number.toFixed(info.precision); - - var parts = number.split('.'); - - // get group position and parts - var group_position = info.groupSep ? 3 : 0; - - if (group_position) { - var integer = parts[0]; - var str = ''; - - for (var i = integer.length; i >= 0; i--) { - var l = this.removeSeparator(str, info.groupSep).length; - if (format == '#,##,###.##' && str.indexOf(',') != -1) { - // INR - group_position = 2; - l += 1; - } - - str += integer.charAt(i); - - if (l && !((l + 1) % group_position) && i != 0) { - str += info.groupSep; - } - } - parts[0] = str.split('').reverse().join(''); - } - if (parts[0] + '' == '') { - parts[0] = '0'; - } - - // join decimal - parts[1] = parts[1] && info.fractionSep ? info.fractionSep + parts[1] : ''; - - // join - return (is_negative ? '-' : '') + parts[0] + parts[1]; - }, - - getFormatInfo(format) { - let format_info = numberFormats[format]; - - if (!format_info) { - throw new Error(`Unknown number format "${format}"`); - } - - return format_info; - }, - - round(num, precision) { - var is_negative = num < 0 ? true : false; - var d = parseInt(precision || 0); - var m = Math.pow(10, d); - var n = +(d ? Math.abs(num) * m : Math.abs(num)).toFixed(8); // Avoid rounding errors - var i = Math.floor(n), - f = n - i; - var r = !precision && f == 0.5 ? (i % 2 == 0 ? i : i + 1) : Math.round(n); - r = d ? r / m : r; - return is_negative ? -r : r; - }, - - removeSeparator(text, sep) { - return text.replace(new RegExp(sep === '.' ? '\\.' : sep, 'g'), ''); - }, - - getDisplayPrecision() { - return frappe.SystemSettings.displayPrecision ?? DEFAULT_DISPLAY_PRECISION; - }, - - getCurrencyFormatter() { - if (frappe.currencyFormatter) { - return frappe.currencyFormatter; - } - - const locale = frappe.SystemSettings.locale ?? DEFAULT_LOCALE; - const display = this.getDisplayPrecision(); - - return (frappe.currencyFormatter = Intl.NumberFormat(locale, { - style: 'decimal', - minimumFractionDigits: display, - })); - }, - - formatCurrency(value) { - const currencyFormatter = this.getCurrencyFormatter(); - if (typeof value === 'number') { - return currencyFormatter.format(value); - } - - if (value.round) { - return currencyFormatter.format(value.round()); - } - - const formattedCurrency = currencyFormatter.format(value); - if (formattedCurrency === 'NaN') { - throw Error( - `invalid value passed to formatCurrency: '${value}' of type ${typeof value}` - ); - } - - return formattedCurrency; - }, -}; From 01609def725c78884d7b527237bd0a3ec53eb4cf Mon Sep 17 00:00:00 2001 From: 18alantom <2.alan.tom@gmail.com> Date: Mon, 3 Jan 2022 14:33:48 +0530 Subject: [PATCH 23/25] chore: bump pesa, default to bankersRounding --- package.json | 2 +- yarn.lock | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/package.json b/package.json index 8b6738b7..0a5046bd 100644 --- a/package.json +++ b/package.json @@ -32,7 +32,7 @@ "multer": "^1.4.3", "node-fetch": "^3.0.0", "nunjucks": "^3.2.3", - "pesa": "^1.1.2", + "pesa": "^1.1.3", "postcss": "^8.3.11", "postcss-loader": "^6.2.0", "sass-loader": "^12.3.0", diff --git a/yarn.lock b/yarn.lock index ca508039..ae1e723e 100644 --- a/yarn.lock +++ b/yarn.lock @@ -3417,10 +3417,10 @@ performance-now@^2.1.0: resolved "https://registry.yarnpkg.com/performance-now/-/performance-now-2.1.0.tgz#6309f4e0e5fa913ec1c69307ae364b4b377c9e7b" integrity sha1-Ywn04OX6kT7BxpMHrjZLSzd8nns= -pesa@^1.1.2: - version "1.1.2" - resolved "https://registry.yarnpkg.com/pesa/-/pesa-1.1.2.tgz#84e765095c198ac03ccc397458cabfd512cfdbe7" - integrity sha512-eL9Vc8IOqO/DT+iv94JIBgR2HjcLWU/9bjvmGktVAJqy9C7rAYuT6EdyJsx/LGbOUk9wTE0LbKMzW5pGr5e7rg== +pesa@^1.1.3: + version "1.1.3" + resolved "https://registry.yarnpkg.com/pesa/-/pesa-1.1.3.tgz#cddd43b02a1db55cd6fb7b220257d33a268588a4" + integrity sha512-WcgR2zb5h8h+k9JQb+xkLsYkdMuoxqKgqWm5uTcbi3EGNg3r0tfzcvIBpRYLtZ6TtICbyCRZxWi0WXCh5jSw0A== pg-connection-string@2.5.0: version "2.5.0" From 490837a5e1749fa7ab30e7b397728cd40aebead3 Mon Sep 17 00:00:00 2001 From: 18alantom <2.alan.tom@gmail.com> Date: Fri, 7 Jan 2022 12:22:40 +0530 Subject: [PATCH 24/25] fix: remove unnecessary try-catch --- index.js | 13 ++++--------- 1 file changed, 4 insertions(+), 9 deletions(-) diff --git a/index.js b/index.js index 7c522ea6..9ec09088 100644 --- a/index.js +++ b/index.js @@ -20,10 +20,8 @@ module.exports = { currency ??= 'XXX'; // to be called after db initialization - let values; - try { - // error thrown if migration hasn't taken place - values = await frappe.db.getSingleValues( + const values = + (await frappe.db?.getSingleValues( { fieldname: 'internalPrecision', parent: 'SystemSettings', @@ -32,10 +30,7 @@ module.exports = { fieldname: 'displayPrecision', parent: 'SystemSettings', } - ); - } catch { - values = []; - } + )) ?? []; let { internalPrecision: precision, displayPrecision: display } = values.reduce((acc, { fieldname, value }) => { @@ -47,7 +42,7 @@ module.exports = { precision = DEFAULT_INTERNAL_PRECISION; } - if (typeof precision.value === 'string') { + if (typeof precision === 'string') { precision = parseInt(precision); } From 77d7ce3531e7bd21c23d53c2828be5e62c79659b Mon Sep 17 00:00:00 2001 From: 18alantom <2.alan.tom@gmail.com> Date: Mon, 10 Jan 2022 15:05:29 +0530 Subject: [PATCH 25/25] fix: update prestiege to drop temp table if exists --- backends/sqlite.js | 1 + 1 file changed, 1 insertion(+) diff --git a/backends/sqlite.js b/backends/sqlite.js index f4711866..7d7911ed 100644 --- a/backends/sqlite.js +++ b/backends/sqlite.js @@ -107,6 +107,7 @@ class SqliteDatabase extends Database { async prestigeTheTable(tableName, tableRows) { // Alter table hacx for sqlite in case of schema change. const tempName = `__${tableName}`; + await this.knex.schema.dropTableIfExists(tempName); await this.knex.raw('PRAGMA foreign_keys=OFF'); await this.createTable(tableName, tempName); await this.knex.batchInsert(tempName, tableRows);