From 76c61a5c29d22fda8e79fd312aa7acdeea800f39 Mon Sep 17 00:00:00 2001 From: 18alantom <2.alan.tom@gmail.com> Date: Sat, 23 Apr 2022 14:53:44 +0530 Subject: [PATCH] incr: get setupwizard to display - make converter more explicit --- fyo/core/converter.ts | 241 +++++++++++++++--- fyo/core/dbHandler.ts | 4 +- fyo/model/doc.ts | 118 +++++---- fyo/model/helpers.ts | 2 +- fyo/model/validationFunction.ts | 2 +- fyo/utils/consts.ts | 5 +- fyo/utils/format.ts | 10 +- .../AccountingSettings/AccountingSettings.ts | 4 +- models/baseModels/Address/Address.ts | 4 +- models/baseModels/SetupWizard/SetupWizard.ts | 32 ++- src/App.vue | 81 +++--- src/README.md | 20 +- src/components/Controls/Base.vue | 22 +- src/components/Controls/Date.vue | 13 +- src/components/Controls/FormControl.vue | 28 +- src/components/Controls/Link.vue | 2 +- src/components/DatePicker/DatePicker.vue | 2 +- src/components/Dropdown.vue | 2 +- src/components/SearchBar.vue | 2 +- src/components/Toast.vue | 1 + src/components/TwoColumnForm.vue | 5 +- src/components/WindowsTitleBar.vue | 2 +- src/pages/SetupWizard/SetupWizard.vue | 143 ++++------- src/renderer.ts | 6 +- src/renderer/helpers.ts | 13 - src/renderer/registerIpcRendererListeners.ts | 3 +- src/setup/setupInstance.ts | 28 +- src/setup/types.ts | 13 - src/utils/misc.ts | 29 +++ utils/misc.ts | 17 ++ utils/types.ts | 14 + 31 files changed, 529 insertions(+), 339 deletions(-) create mode 100644 utils/misc.ts diff --git a/fyo/core/converter.ts b/fyo/core/converter.ts index 41135f3b..0fcf96c6 100644 --- a/fyo/core/converter.ts +++ b/fyo/core/converter.ts @@ -1,7 +1,11 @@ import { Fyo } from 'fyo'; import Doc from 'fyo/model/doc'; +import { isPesa } from 'fyo/utils'; +import { ValueError } from 'fyo/utils/errors'; +import { DateTime } from 'luxon'; import Money from 'pesa/dist/types/src/money'; -import { FieldType, FieldTypeEnum, RawValue } from 'schemas/types'; +import { Field, FieldTypeEnum, RawValue } from 'schemas/types'; +import { getIsNullOrUndef } from 'utils'; import { DatabaseHandler } from './dbHandler'; import { DocValue, DocValueMap, RawValueMap } from './types'; @@ -51,55 +55,41 @@ export class Converter { } } - static toDocValue( - value: RawValue, - fieldtype: FieldType, - fyo: Fyo - ): DocValue { - switch (fieldtype) { + static toDocValue(value: RawValue, field: Field, fyo: Fyo): DocValue { + switch (field.fieldtype) { case FieldTypeEnum.Currency: - return fyo.pesa((value ?? 0) as string | number); + return toDocCurrency(value, field, fyo); case FieldTypeEnum.Date: - return new Date(value as string); + return toDocDate(value, field); case FieldTypeEnum.Datetime: - return new Date(value as string); + return toDocDate(value, field); case FieldTypeEnum.Int: - return +(value as string | number); + return toDocInt(value, field); case FieldTypeEnum.Float: - return +(value as string | number); + return toDocFloat(value, field); case FieldTypeEnum.Check: - return Boolean(value as number); + return toDocCheck(value, field); default: return String(value); } } - static toRawValue(value: DocValue, fieldtype: FieldType): RawValue { - switch (fieldtype) { + static toRawValue(value: DocValue, field: Field, fyo: Fyo): RawValue { + switch (field.fieldtype) { case FieldTypeEnum.Currency: - return (value as Money).store; + return toRawCurrency(value, fyo, field); case FieldTypeEnum.Date: - return (value as Date).toISOString().split('T')[0]; + return toRawDate(value, field); case FieldTypeEnum.Datetime: - return (value as Date).toISOString(); - case FieldTypeEnum.Int: { - if (typeof value === 'string') { - return parseInt(value); - } - - return Math.floor(value as number); - } - case FieldTypeEnum.Float: { - if (typeof value === 'string') { - return parseFloat(value); - } - - return value as number; - } + return toRawDateTime(value, field); + case FieldTypeEnum.Int: + return toRawInt(value, field); + case FieldTypeEnum.Float: + return toRawFloat(value, field); case FieldTypeEnum.Check: - return Number(value); + return toRawCheck(value, field); default: - return String(value); + return toRawString(value, field); } } @@ -118,7 +108,7 @@ export class Converter { } else { docValueMap[fieldname] = Converter.toDocValue( rawValue, - field.fieldtype, + field, this.fyo ); } @@ -146,7 +136,8 @@ export class Converter { } else { rawValueMap[fieldname] = Converter.toRawValue( docValue, - field.fieldtype + field, + this.fyo ); } } @@ -154,3 +145,181 @@ export class Converter { return rawValueMap; } } + +function toDocDate(value: RawValue, field: Field) { + if (typeof value !== 'number' && typeof value !== 'string') { + throwError(value, field, 'doc'); + } + + const date = new Date(value); + if (date.toString() === 'Invalid Date') { + throwError(value, field, 'doc'); + } + + return date; +} + +function toDocCurrency(value: RawValue, field: Field, fyo: Fyo) { + if (typeof value === 'string') { + return fyo.pesa(value); + } + + if (typeof value === 'number') { + return fyo.pesa(value); + } + + if (typeof value === 'boolean') { + return fyo.pesa(Number(value)); + } + + throwError(value, field, 'doc'); +} + +function toDocInt(value: RawValue, field: Field): number { + if (typeof value === 'string') { + value = parseInt(value); + } + + return toDocFloat(value, field); +} + +function toDocFloat(value: RawValue, field: Field): number { + if (typeof value === 'boolean') { + return Number(value); + } + + if (typeof value === 'string') { + value = parseFloat(value); + } + + if (typeof value === 'number' && !Number.isNaN(value)) { + return value; + } + + throwError(value, field, 'doc'); +} + +function toDocCheck(value: RawValue, field: Field): boolean { + if (typeof value === 'boolean') { + return value; + } + + if (typeof value === 'string') { + return value === '1'; + } + + if (typeof value === 'number') { + return Boolean(value); + } + + throwError(value, field, 'doc'); +} + +function toRawCurrency(value: DocValue, fyo: Fyo, field: Field): string { + if (isPesa(value)) { + return (value as Money).store; + } + + if (getIsNullOrUndef(value)) { + return fyo.pesa(0).store; + } + + if (typeof value === 'number') { + return fyo.pesa(value).store; + } + + if (typeof value === 'string') { + return fyo.pesa(value).store; + } + + throwError(value, field, 'raw'); +} + +function toRawInt(value: DocValue, field: Field): number { + if (typeof value === 'string') { + return parseInt(value); + } + + if (getIsNullOrUndef(value)) { + return 0; + } + + if (typeof value === 'number') { + return Math.floor(value as number); + } + + throwError(value, field, 'raw'); +} + +function toRawFloat(value: DocValue, field: Field): number { + if (typeof value === 'string') { + return parseFloat(value); + } + + if (getIsNullOrUndef(value)) { + return 0; + } + + if (typeof value === 'number') { + return value; + } + + throwError(value, field, 'raw'); +} + +function toRawDate(value: DocValue, field: Field): string { + const dateTime = toRawDateTime(value, field); + return dateTime.split('T')[0]; +} + +function toRawDateTime(value: DocValue, field: Field): string { + if (getIsNullOrUndef(value)) { + return ''; + } + + if (typeof value === 'string') { + return value; + } + + if (value instanceof Date) { + return (value as Date).toISOString(); + } + + if (value instanceof DateTime) { + return (value as DateTime).toISO(); + } + + throwError(value, field, 'raw'); +} + +function toRawCheck(value: DocValue, field: Field): number { + if (typeof value === 'number') { + value = Boolean(value); + } + + if (typeof value === 'boolean') { + return Number(value); + } + + throwError(value, field, 'raw'); +} + +function toRawString(value: DocValue, field: Field): string { + if (getIsNullOrUndef(value)) { + return ''; + } + + if (typeof value === 'string') { + return value; + } + + throwError(value, field, 'raw'); +} + +function throwError(value: T, field: Field, type: 'raw' | 'doc'): never { + throw new ValueError( + `invalid ${type} conversion '${value}' of type ${typeof value} found, field: ${JSON.stringify( + field + )}` + ); +} diff --git a/fyo/core/dbHandler.ts b/fyo/core/dbHandler.ts index 6769477e..b5ee7750 100644 --- a/fyo/core/dbHandler.ts +++ b/fyo/core/dbHandler.ts @@ -129,8 +129,8 @@ export class DatabaseHandler extends DatabaseBase { const docSingleValue: SingleValue = []; for (const sv of rawSingleValue) { - const fieldtype = this.fieldValueMap[sv.parent][sv.fieldname].fieldtype; - const value = Converter.toDocValue(sv.value, fieldtype, this.#fyo); + const field = this.fieldValueMap[sv.parent][sv.fieldname]; + const value = Converter.toDocValue(sv.value, field, this.#fyo); docSingleValue.push({ value, diff --git a/fyo/model/doc.ts b/fyo/model/doc.ts index 22a2b47c..43f259db 100644 --- a/fyo/model/doc.ts +++ b/fyo/model/doc.ts @@ -1,6 +1,7 @@ import { Fyo } from 'fyo'; import { DocValue, DocValueMap } from 'fyo/core/types'; import { Verb } from 'fyo/telemetry/types'; +import { DEFAULT_USER } from 'fyo/utils/consts'; import { Conflict, MandatoryError, @@ -123,7 +124,7 @@ export default class Doc extends Observable { } } - setDirty(value: boolean) { + _setDirty(value: boolean) { this._dirty = value; if (this.schema.isChild && this.parentdoc) { this.parentdoc._dirty = value; @@ -133,27 +134,15 @@ export default class Doc extends Observable { // set value and trigger change async set(fieldname: string | DocValueMap, value?: DocValue | Doc[]) { if (typeof fieldname === 'object') { - this.setMultiple(fieldname as DocValueMap); + await this.setMultiple(fieldname as DocValueMap); return; } - if (fieldname === 'numberSeries' && !this._notInserted) { + if (!this._canSet(fieldname, value)) { return; } - if (value === undefined) { - return; - } - - if ( - this.fieldMap[fieldname] === undefined || - (this[fieldname] !== undefined && - areDocValuesEqual(this[fieldname] as DocValue, value as DocValue)) - ) { - return; - } - - this.setDirty(true); + this._setDirty(true); if (Array.isArray(value)) { this[fieldname] = value.map((row, i) => { row.idx = i; @@ -161,16 +150,16 @@ export default class Doc extends Observable { }); } else { const field = this.fieldMap[fieldname]; - await this.validateField(field, value); + await this._validateField(field, value); this[fieldname] = value; } // always run applyChange from the parentdoc if (this.schema.isChild && this.parentdoc) { - await this.applyChange(fieldname); - await this.parentdoc.applyChange(this.parentfield as string); + await this._applyChange(fieldname); + await this.parentdoc._applyChange(this.parentfield as string); } else { - await this.applyChange(fieldname); + await this._applyChange(fieldname); } } @@ -180,8 +169,29 @@ export default class Doc extends Observable { } } - async applyChange(fieldname: string) { - await this.applyFormula(fieldname); + _canSet(fieldname: string, value?: DocValue | Doc[]): boolean { + if (fieldname === 'numberSeries' && !this._notInserted) { + return false; + } + + if (value === undefined) { + return false; + } + + if (this.fieldMap[fieldname] === undefined) { + return false; + } + + const currentValue = this.get(fieldname); + if (currentValue === undefined) { + return true; + } + + return !areDocValuesEqual(currentValue as DocValue, value as DocValue); + } + + async _applyChange(fieldname: string) { + await this._applyFormula(fieldname); await this.trigger('change', { doc: this, changed: fieldname, @@ -218,7 +228,7 @@ export default class Doc extends Observable { // push child row and trigger change this.push(fieldname, docValueMap); this._dirty = true; - this.applyChange(fieldname); + this._applyChange(fieldname); } push(fieldname: string, docValueMap: Doc | DocValueMap = {}) { @@ -256,11 +266,11 @@ export default class Doc extends Observable { } async validateInsert() { - this.validateMandatory(); - await this.validateFields(); + this._validateMandatory(); + await this._validateFields(); } - validateMandatory() { + _validateMandatory() { const checkForMandatory: Doc[] = [this]; const tableFields = this.schema.fields.filter( (f) => f.fieldtype === FieldTypeEnum.Table @@ -282,7 +292,7 @@ export default class Doc extends Observable { } } - async validateFields() { + async _validateFields() { const fields = this.schema.fields; for (const field of fields) { if (field.fieldtype === FieldTypeEnum.Table) { @@ -290,11 +300,11 @@ export default class Doc extends Observable { } const value = this.get(field.fieldname) as DocValue; - await this.validateField(field, value); + await this._validateField(field, value); } } - async validateField(field: Field, value: DocValue) { + async _validateField(field: Field, value: DocValue) { if (field.fieldtype == 'Select') { validateSelect(field as OptionField, value as string); } @@ -329,25 +339,25 @@ export default class Doc extends Observable { return data; } - setBaseMetaValues() { + _setBaseMetaValues() { if (this.schema.isSubmittable && typeof this.submitted !== 'boolean') { this.submitted = false; this.cancelled = false; } if (!this.createdBy) { - this.createdBy = this.fyo.auth.session.user; + this.createdBy = this.fyo.auth.session.user || DEFAULT_USER; } if (!this.created) { this.created = new Date(); } - this.updateModified(); + this._updateModified(); } - updateModified() { - this.modifiedBy = this.fyo.auth.session.user; + _updateModified() { + this.modifiedBy = this.fyo.auth.session.user || DEFAULT_USER; this.modified = new Date(); } @@ -474,11 +484,7 @@ export default class Doc extends Observable { } } - async applyFormula(fieldname?: string) { - if (fieldname && this.formulas[fieldname] === undefined) { - return false; - } - + async _applyFormula(fieldname?: string) { const doc = this; let changed = false; @@ -492,7 +498,7 @@ export default class Doc extends Observable { (fn) => this.fieldMap[fn] ); - changed ||= await this.applyFormulaForFields( + changed ||= await this._applyFormulaForFields( formulaFields, row, fieldname @@ -503,22 +509,27 @@ export default class Doc extends Observable { const formulaFields = Object.keys(this.formulas).map( (fn) => this.fieldMap[fn] ); - changed ||= await this.applyFormulaForFields(formulaFields, doc, fieldname); + changed ||= await this._applyFormulaForFields( + formulaFields, + doc, + fieldname + ); return changed; } - async applyFormulaForFields( + async _applyFormulaForFields( formulaFields: Field[], doc: Doc, fieldname?: string ) { let changed = false; for (const field of formulaFields) { - if (!shouldApplyFormula(field, doc, fieldname)) { + const shouldApply = shouldApplyFormula(field, doc, fieldname); + if (!shouldApply) { continue; } - const newVal = await this.getValueFromFormula(field, doc); + const newVal = await this._getValueFromFormula(field, doc); const previousVal = doc.get(field.fieldname); const isSame = areDocValuesEqual(newVal as DocValue, previousVal); if (newVal === undefined || isSame) { @@ -532,15 +543,18 @@ export default class Doc extends Observable { return changed; } - async getValueFromFormula(field: Field, doc: Doc) { - let value: FormulaReturn; - - const formula = doc.formulas[field.fieldtype]; + async _getValueFromFormula(field: Field, doc: Doc) { + const formula = doc.formulas[field.fieldname]; if (formula === undefined) { return; } - value = await formula(); + let value: FormulaReturn; + try { + value = await formula(); + } catch { + return; + } if (Array.isArray(value) && field.fieldtype === FieldTypeEnum.Table) { value = value.map((row) => this._initChild(row, field.fieldname)); } @@ -551,13 +565,13 @@ export default class Doc extends Observable { async commit() { // re-run triggers this.setChildIdx(); - await this.applyFormula(); + await this._applyFormula(); await this.trigger('validate', null); } async insert() { await setName(this, this.fyo); - this.setBaseMetaValues(); + this._setBaseMetaValues(); await this.commit(); await this.validateInsert(); await this.trigger('beforeInsert', null); @@ -587,7 +601,7 @@ export default class Doc extends Observable { if (this.flags.revertAction) await this.trigger('beforeRevert'); // update modifiedBy and modified - this.updateModified(); + this._updateModified(); const data = this.getValidDict(); await this.fyo.db.update(this.schemaName, data); diff --git a/fyo/model/helpers.ts b/fyo/model/helpers.ts index ffd4d6c2..9d9a16ed 100644 --- a/fyo/model/helpers.ts +++ b/fyo/model/helpers.ts @@ -88,7 +88,7 @@ function getMandatory(doc: Doc): Field[] { } export function shouldApplyFormula(field: Field, doc: Doc, fieldname?: string) { - if (!doc.formulas[field.fieldtype]) { + if (!doc.formulas[field.fieldname]) { return false; } diff --git a/fyo/model/validationFunction.ts b/fyo/model/validationFunction.ts index 4536d2d0..9c51726c 100644 --- a/fyo/model/validationFunction.ts +++ b/fyo/model/validationFunction.ts @@ -23,7 +23,7 @@ export function validateSelect(field: OptionField, value: string) { return; } - if (!field.required && (value === null || value === undefined)) { + if (!field.required && !value) { return; } diff --git a/fyo/utils/consts.ts b/fyo/utils/consts.ts index 1f35baf4..d969d9eb 100644 --- a/fyo/utils/consts.ts +++ b/fyo/utils/consts.ts @@ -1,8 +1,9 @@ export const DEFAULT_INTERNAL_PRECISION = 11; export const DEFAULT_DISPLAY_PRECISION = 2; -export const DEFAULT_DATE_FORMAT = 'yyyy-MM-dd'; +export const DEFAULT_DATE_FORMAT = 'MMM d, y'; export const DEFAULT_LOCALE = 'en-IN'; export const DEFAULT_COUNTRY_CODE = 'in'; export const DEFAULT_CURRENCY = 'INR'; export const DEFAULT_LANGUAGE = 'English'; -export const DEFAULT_SERIES_START = 1001; \ No newline at end of file +export const DEFAULT_SERIES_START = 1001; +export const DEFAULT_USER = 'Admin'; \ No newline at end of file diff --git a/fyo/utils/format.ts b/fyo/utils/format.ts index 9395e737..bc7c2cb1 100644 --- a/fyo/utils/format.ts +++ b/fyo/utils/format.ts @@ -129,12 +129,14 @@ function getNumberFormatter(fyo: Fyo) { } function getCurrency(field: Field, doc: Doc | null, fyo: Fyo): string { - if (doc && doc.getCurrencies[field.fieldname]) { - return doc.getCurrencies[field.fieldname](); + let getCurrency = doc?.getCurrencies[field.fieldname]; + if (getCurrency !== undefined) { + return getCurrency(); } - if (doc && doc.parentdoc?.getCurrencies[field.fieldname]) { - return doc.parentdoc.getCurrencies[field.fieldname](); + getCurrency = doc?.parentdoc?.getCurrencies[field.fieldname]; + if (getCurrency !== undefined) { + return getCurrency(); } return (fyo.singles.SystemSettings?.currency as string) ?? DEFAULT_CURRENCY; diff --git a/models/baseModels/AccountingSettings/AccountingSettings.ts b/models/baseModels/AccountingSettings/AccountingSettings.ts index 9bdf0f6a..ac8cd45c 100644 --- a/models/baseModels/AccountingSettings/AccountingSettings.ts +++ b/models/baseModels/AccountingSettings/AccountingSettings.ts @@ -1,7 +1,7 @@ import Doc from 'fyo/model/doc'; import { FiltersMap, ListsMap, ValidationMap } from 'fyo/model/types'; import { validateEmail } from 'fyo/model/validationFunction'; -import countryInfo from '../../../fixtures/countryInfo.json'; +import { getCountryInfo } from 'utils/misc'; export class AccountingSettings extends Doc { static filters: FiltersMap = { @@ -20,6 +20,6 @@ export class AccountingSettings extends Doc { }; static lists: ListsMap = { - country: () => Object.keys(countryInfo), + country: () => Object.keys(getCountryInfo()), }; } diff --git a/models/baseModels/Address/Address.ts b/models/baseModels/Address/Address.ts index 3829c309..af9abaa6 100644 --- a/models/baseModels/Address/Address.ts +++ b/models/baseModels/Address/Address.ts @@ -3,7 +3,7 @@ import Doc from 'fyo/model/doc'; import { EmptyMessageMap, FormulaMap, ListsMap } from 'fyo/model/types'; import { stateCodeMap } from 'regional/in'; import { titleCase } from 'utils'; -import countryInfo from '../../../fixtures/countryInfo.json'; +import { getCountryInfo } from 'utils/misc'; export class Address extends Doc { formulas: FormulaMap = { @@ -32,7 +32,7 @@ export class Address extends Doc { } }, country() { - return Object.keys(countryInfo).sort(); + return Object.keys(getCountryInfo()).sort(); }, }; diff --git a/models/baseModels/SetupWizard/SetupWizard.ts b/models/baseModels/SetupWizard/SetupWizard.ts index 0ae066b2..2081e37c 100644 --- a/models/baseModels/SetupWizard/SetupWizard.ts +++ b/models/baseModels/SetupWizard/SetupWizard.ts @@ -1,9 +1,14 @@ import { t } from 'fyo'; import Doc from 'fyo/model/doc'; -import { FormulaMap, ListsMap, ValidationMap } from 'fyo/model/types'; +import { + DependsOnMap, + FormulaMap, + ListsMap, + ValidationMap, +} from 'fyo/model/types'; import { validateEmail } from 'fyo/model/validationFunction'; import { DateTime } from 'luxon'; -import countryInfo from '../../../fixtures/countryInfo.json'; +import { getCountryInfo } from 'utils/misc'; export function getCOAList() { return [ @@ -26,14 +31,21 @@ export function getCOAList() { } export class SetupWizard extends Doc { + dependsOn: DependsOnMap = { + fiscalYearStart: ['country'], + fiscalYearEnd: ['country'], + currency: ['country'], + chartOfAccounts: ['country'], + }; + formulas: FormulaMap = { fiscalYearStart: async () => { if (!this.country) return; const today = DateTime.local(); - // @ts-ignore - const fyStart = countryInfo[this.country].fiscal_year_start as + const countryInfo = getCountryInfo(); + const fyStart = countryInfo[this.country as string]?.fiscal_year_start as | string | undefined; @@ -50,8 +62,8 @@ export class SetupWizard extends Doc { const today = DateTime.local(); - // @ts-ignore - const fyEnd = countryInfo[this.country].fiscal_year_end as + const countryInfo = getCountryInfo(); + const fyEnd = countryInfo[this.country as string]?.fiscal_year_end as | string | undefined; if (fyEnd) { @@ -64,8 +76,8 @@ export class SetupWizard extends Doc { if (!this.country) { return; } - // @ts-ignore - return countryInfo[this.country].currency; + const countryInfo = getCountryInfo(); + return countryInfo[this.country as string]?.currency; }, chartOfAccounts: async () => { const country = this.get('country') as string | undefined; @@ -73,7 +85,7 @@ export class SetupWizard extends Doc { return; } - // @ts-ignore + const countryInfo = getCountryInfo(); const code = (countryInfo[country] as undefined | { code: string })?.code; if (code === undefined) { return; @@ -94,7 +106,7 @@ export class SetupWizard extends Doc { }; static lists: ListsMap = { - country: () => Object.keys(countryInfo), + country: () => Object.keys(getCountryInfo()), chartOfAccounts: () => getCOAList().map(({ name }) => name), }; } diff --git a/src/App.vue b/src/App.vue index b713a0b8..f991c0aa 100644 --- a/src/App.vue +++ b/src/App.vue @@ -10,6 +10,13 @@ v-if="activeScreen === 'Desk'" @change-db-file="changeDbFile" />--> +
+

Desk

+
+
- +
diff --git a/src/README.md b/src/README.md index 9fd6cab7..9c399a07 100644 --- a/src/README.md +++ b/src/README.md @@ -2,12 +2,18 @@ This is where all the frontend code lives -## Initialization -New Instance -1. Run _Setup Wizard_ for initialization values (eg: `countryCode`). -2. +## Fyo Initialization -Existing Instance -1. Connect to db +The initialization flows are different when the instance is new or is existing. +All of them are triggered from `src/App.vue`. + +**New Instance** + +1. Run _Setup Wizard_ for init values (eg: `country`). +2. Call `setupInstance.ts/setupInstance` using init values. + +**Existing Instance** + +1. Connect to db. 2. Check if _Setup Wizard_ has been completed, if not, jump to **New Instance** -3. Call `initFyo/initializeInstance` with `dbPath` and `countryCode` \ No newline at end of file +3. Call `initFyo/initializeInstance` with `dbPath` and `countryCode` diff --git a/src/components/Controls/Base.vue b/src/components/Controls/Base.vue index 9e693e91..705ca30e 100644 --- a/src/components/Controls/Base.vue +++ b/src/components/Controls/Base.vue @@ -22,19 +22,19 @@ diff --git a/src/components/Controls/FormControl.vue b/src/components/Controls/FormControl.vue index c334fb19..e1268cb6 100644 --- a/src/components/Controls/FormControl.vue +++ b/src/components/Controls/FormControl.vue @@ -1,19 +1,19 @@ diff --git a/src/renderer.ts b/src/renderer.ts index 32e07d71..8ce8aca2 100644 --- a/src/renderer.ts +++ b/src/renderer.ts @@ -7,7 +7,7 @@ import Badge from './components/Badge.vue'; import FeatherIcon from './components/FeatherIcon.vue'; import { getErrorHandled, handleError } from './errorHandling'; import { fyo } from './initFyo'; -import { incrementOpenCount, outsideClickDirective } from './renderer/helpers'; +import { outsideClickDirective } from './renderer/helpers'; import registerIpcRendererListeners from './renderer/registerIpcRendererListeners'; import router from './router'; import { stringifyCircular } from './utils'; @@ -33,7 +33,7 @@ import { setLanguageMap } from './utils/language'; app.use(router); app.component('App', App); - app.component('feather-icon', FeatherIcon); + app.component('FeatherIcon', FeatherIcon); app.component('Badge', Badge); app.directive('on-outside-click', outsideClickDirective); @@ -62,8 +62,6 @@ import { setLanguageMap } from './utils/language'; }); fyo.store.appVersion = await ipcRenderer.invoke(IPC_ACTIONS.GET_VERSION); - - incrementOpenCount(); app.mount('body'); })(); diff --git a/src/renderer/helpers.ts b/src/renderer/helpers.ts index 148966cf..71806b39 100644 --- a/src/renderer/helpers.ts +++ b/src/renderer/helpers.ts @@ -1,5 +1,3 @@ -import { ConfigKeys } from 'fyo/core/types'; -import { fyo } from 'src/initFyo'; import { Directive } from 'vue'; const instances: OutsideClickCallback[] = []; @@ -35,14 +33,3 @@ function onDocumentClick(e: Event, el: HTMLElement, fn: OutsideClickCallback) { fn(e); } } - -export function incrementOpenCount() { - let openCount = fyo.config.get(ConfigKeys.OpenCount); - if (typeof openCount !== 'number') { - openCount = 1; - } else { - openCount += 1; - } - - fyo.config.set(ConfigKeys.OpenCount, openCount); -} diff --git a/src/renderer/registerIpcRendererListeners.ts b/src/renderer/registerIpcRendererListeners.ts index 1c5c5ed7..732225f1 100644 --- a/src/renderer/registerIpcRendererListeners.ts +++ b/src/renderer/registerIpcRendererListeners.ts @@ -1,6 +1,7 @@ import { ipcRenderer } from 'electron'; import { handleError } from 'src/errorHandling'; import { fyo } from 'src/initFyo'; +import { startTelemetry } from 'src/utils/misc'; import { showToast } from 'src/utils/ui'; import { IPC_CHANNELS, IPC_MESSAGES } from 'utils/messages'; @@ -56,7 +57,7 @@ export default function registerIpcRendererListeners() { document.addEventListener('visibilitychange', function () { const { visibilityState } = document; if (visibilityState === 'visible' && !fyo.telemetry.started) { - fyo.telemetry.start(); + startTelemetry(); } if (visibilityState !== 'hidden') { diff --git a/src/setup/setupInstance.ts b/src/setup/setupInstance.ts index f48ad646..1becabe6 100644 --- a/src/setup/setupInstance.ts +++ b/src/setup/setupInstance.ts @@ -1,4 +1,3 @@ -import countryInfo from 'fixtures/countryInfo.json'; import { ConfigFile, DocValueMap } from 'fyo/core/types'; import Doc from 'fyo/model/doc'; import { createNumberSeries } from 'fyo/model/naming'; @@ -9,16 +8,21 @@ import { DEFAULT_SERIES_START, } from 'fyo/utils/consts'; import { AccountingSettings } from 'models/baseModels/AccountingSettings/AccountingSettings'; -import { fyo } from 'src/initFyo'; +import { fyo, initializeInstance } from 'src/initFyo'; import { createRegionalRecords } from 'src/regional'; +import { getCountryCodeFromCountry, getCountryInfo } from 'utils/misc'; +import { CountryInfo } from 'utils/types'; import { createCOA } from './createCOA'; -import { CountrySettings, SetupWizardOptions } from './types'; +import { SetupWizardOptions } from './types'; export default async function setupInstance( + dbPath: string, setupWizardOptions: SetupWizardOptions ) { const { companyName, country, bankName, chartOfAccounts } = setupWizardOptions; + + await initializeDatabase(dbPath, country); await updateSystemSettings(setupWizardOptions); await updateAccountingSettings(setupWizardOptions); await updatePrintSettings(setupWizardOptions); @@ -31,10 +35,15 @@ export default async function setupInstance( await completeSetup(companyName); } +async function initializeDatabase(dbPath: string, country: string) { + const countryCode = getCountryCodeFromCountry(country); + await initializeInstance(dbPath, true, countryCode); +} + async function updateAccountingSettings({ companyName, country, - name, + fullname, email, bankName, fiscalYearStart, @@ -46,7 +55,7 @@ async function updateAccountingSettings({ await accountingSettings.setAndUpdate({ companyName, country, - fullname: name, + fullname, email, bankName, fiscalYearStart, @@ -73,8 +82,8 @@ async function updateSystemSettings({ country, currency: companyCurrency, }: SetupWizardOptions) { - // @ts-ignore - const countryOptions = countryInfo[country] as CountrySettings; + const countryInfo = getCountryInfo(); + const countryOptions = countryInfo[country] as CountryInfo; const currency = companyCurrency ?? countryOptions.currency ?? DEFAULT_CURRENCY; const locale = countryOptions.locale ?? DEFAULT_LOCALE; @@ -88,10 +97,7 @@ async function updateSystemSettings({ async function createCurrencyRecords() { const promises: Promise[] = []; const queue: string[] = []; - const countrySettings: CountrySettings[] = Object.values( - // @ts-ignore - countryInfo as Record - ); + const countrySettings = Object.values(getCountryInfo()) as CountryInfo[]; for (const country of countrySettings) { const { diff --git a/src/setup/types.ts b/src/setup/types.ts index e2db66f6..2abf8adf 100644 --- a/src/setup/types.ts +++ b/src/setup/types.ts @@ -3,7 +3,6 @@ export interface SetupWizardOptions { companyName: string; country: string; fullname: string; - name: string; email: string; bankName: string; currency: string; @@ -11,15 +10,3 @@ export interface SetupWizardOptions { fiscalYearEnd: string; chartOfAccounts: string; } - -export interface CountrySettings { - code: string; - currency: string; - fiscal_year_start: string; - fiscal_year_end: string; - locale: string; - currency_fraction?: string; - currency_fraction_units?: number; - smallest_currency_fraction_value?: number; - currency_symbol?: string; -} \ No newline at end of file diff --git a/src/utils/misc.ts b/src/utils/misc.ts index cc32b0e1..2a62dec3 100644 --- a/src/utils/misc.ts +++ b/src/utils/misc.ts @@ -1,3 +1,4 @@ +import { ConfigKeys } from 'fyo/core/types'; import { getSingleValue } from 'fyo/utils'; import { DateTime } from 'luxon'; import { SetupWizard } from 'models/baseModels/SetupWizard/SetupWizard'; @@ -51,3 +52,31 @@ export async function getSetupComplete(): Promise { fyo )); } + +export function incrementOpenCount() { + let openCount = fyo.config.get(ConfigKeys.OpenCount); + if (typeof openCount !== 'number') { + openCount = 1; + } else { + openCount += 1; + } + + fyo.config.set(ConfigKeys.OpenCount, openCount); +} + +export async function startTelemetry() { + fyo.telemetry.interestingDocs = [ + ModelNameEnum.Payment, + ModelNameEnum.PaymentFor, + ModelNameEnum.SalesInvoice, + ModelNameEnum.SalesInvoiceItem, + ModelNameEnum.PurchaseInvoice, + ModelNameEnum.PurchaseInvoiceItem, + ModelNameEnum.JournalEntry, + ModelNameEnum.JournalEntryAccount, + ModelNameEnum.Party, + ModelNameEnum.Account, + ModelNameEnum.Tax, + ]; + await fyo.telemetry.start(); +} diff --git a/utils/misc.ts b/utils/misc.ts new file mode 100644 index 00000000..82cff3a4 --- /dev/null +++ b/utils/misc.ts @@ -0,0 +1,17 @@ +import countryInfo from 'fixtures/countryInfo.json'; +import { CountryInfoMap } from './types'; + +export function getCountryInfo(): CountryInfoMap { + // @ts-ignore + return countryInfo as CountryInfoMap; +} + +export function getCountryCodeFromCountry(countryName: string): string { + const countryInfoMap = getCountryInfo(); + const countryInfo = countryInfoMap[countryName]; + if (countryInfo === undefined) { + return ''; + } + + return countryInfo.code; +} diff --git a/utils/types.ts b/utils/types.ts index 254518a6..359e26ee 100644 --- a/utils/types.ts +++ b/utils/types.ts @@ -1,2 +1,16 @@ export type Translation = { translation: string; context?: string }; export type LanguageMap = Record; + +export type CountryInfoMap = Record; +export interface CountryInfo { + code: string; + currency: string; + currency_fraction?: string; + currency_fraction_units?: number; + smallest_currency_fraction_value?: number; + currency_symbol?: string; + timezones?: string[]; + fiscal_year_start: string; + fiscal_year_end: string; + locale: string; +}