mirror of
https://github.com/frappe/books.git
synced 2024-12-22 19:09:01 +00:00
incr: simplify doc a bit
- allow nulls in converter else not not null'll fail
This commit is contained in:
parent
76c61a5c29
commit
9877bf4fd3
@ -1,5 +1,5 @@
|
||||
import { Fyo } from 'fyo';
|
||||
import Doc from 'fyo/model/doc';
|
||||
import { Doc } from 'fyo/model/doc';
|
||||
import { isPesa } from 'fyo/utils';
|
||||
import { ValueError } from 'fyo/utils/errors';
|
||||
import { DateTime } from 'luxon';
|
||||
@ -267,14 +267,18 @@ function toRawFloat(value: DocValue, field: Field): number {
|
||||
throwError(value, field, 'raw');
|
||||
}
|
||||
|
||||
function toRawDate(value: DocValue, field: Field): string {
|
||||
function toRawDate(value: DocValue, field: Field): string | null {
|
||||
const dateTime = toRawDateTime(value, field);
|
||||
if (dateTime === null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return dateTime.split('T')[0];
|
||||
}
|
||||
|
||||
function toRawDateTime(value: DocValue, field: Field): string {
|
||||
if (getIsNullOrUndef(value)) {
|
||||
return '';
|
||||
function toRawDateTime(value: DocValue, field: Field): string | null {
|
||||
if (value === null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
if (typeof value === 'string') {
|
||||
@ -304,9 +308,9 @@ function toRawCheck(value: DocValue, field: Field): number {
|
||||
throwError(value, field, 'raw');
|
||||
}
|
||||
|
||||
function toRawString(value: DocValue, field: Field): string {
|
||||
if (getIsNullOrUndef(value)) {
|
||||
return '';
|
||||
function toRawString(value: DocValue, field: Field): string | null {
|
||||
if (value === null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
if (typeof value === 'string') {
|
||||
|
@ -1,4 +1,4 @@
|
||||
import Doc from 'fyo/model/doc';
|
||||
import { Doc } from 'fyo/model/doc';
|
||||
import { DocMap, ModelMap, SinglesMap } from 'fyo/model/types';
|
||||
import { coreModels } from 'fyo/models';
|
||||
import Observable from 'fyo/utils/observable';
|
||||
@ -143,20 +143,10 @@ export class DocHandler {
|
||||
return newDoc;
|
||||
}
|
||||
|
||||
getEmptyDoc(schemaName: string, cacheDoc: boolean = true): Doc {
|
||||
const doc = this.getNewDoc(schemaName);
|
||||
doc.name = getRandomString();
|
||||
|
||||
if (cacheDoc) {
|
||||
this.addToCache(doc);
|
||||
}
|
||||
|
||||
return doc;
|
||||
}
|
||||
|
||||
getNewDoc(
|
||||
schemaName: string,
|
||||
data: DocValueMap = {},
|
||||
cacheDoc: boolean = true,
|
||||
schema?: Schema,
|
||||
Model?: typeof Doc
|
||||
): Doc {
|
||||
@ -166,12 +156,17 @@ export class DocHandler {
|
||||
|
||||
Model ??= this.models[schemaName];
|
||||
schema ??= this.fyo.schemaMap[schemaName];
|
||||
|
||||
if (schema === undefined) {
|
||||
throw new Error(`Schema not found for ${schemaName}`);
|
||||
}
|
||||
|
||||
const doc = new Model!(schema, data, this.fyo);
|
||||
doc.setDefaults();
|
||||
doc.name ??= getRandomString();
|
||||
if (cacheDoc) {
|
||||
this.addToCache(doc);
|
||||
}
|
||||
|
||||
return doc;
|
||||
}
|
||||
|
||||
@ -184,12 +179,12 @@ export class DocHandler {
|
||||
const docExists = await this.fyo.db.exists(schemaName, name);
|
||||
if (!docExists) {
|
||||
const doc = this.getNewDoc(schemaName, data);
|
||||
await doc.insert;
|
||||
await doc.sync();
|
||||
return;
|
||||
}
|
||||
|
||||
const doc = await this.getDoc(schemaName, name);
|
||||
await doc.setMultiple(data);
|
||||
await doc.update();
|
||||
await doc.sync();
|
||||
}
|
||||
}
|
||||
|
@ -1,4 +1,4 @@
|
||||
import Doc from 'fyo/model/doc';
|
||||
import { Doc } from 'fyo/model/doc';
|
||||
import Money from 'pesa/dist/types/src/money';
|
||||
import { RawValue } from 'schemas/types';
|
||||
import { AuthDemuxBase } from 'utils/auth/types';
|
||||
|
@ -1,14 +1,14 @@
|
||||
import config from 'utils/config';
|
||||
|
||||
export class Config {
|
||||
#isElectron: boolean;
|
||||
#useElectronConfig: boolean;
|
||||
fallback: Map<string, unknown> = new Map();
|
||||
constructor(isElectron: boolean) {
|
||||
this.#isElectron = isElectron;
|
||||
this.#useElectronConfig = isElectron;
|
||||
}
|
||||
|
||||
get store(): Record<string, unknown> {
|
||||
if (this.#isElectron) {
|
||||
if (this.#useElectronConfig) {
|
||||
return config.store;
|
||||
} else {
|
||||
const store: Record<string, unknown> = {};
|
||||
@ -22,7 +22,7 @@ export class Config {
|
||||
}
|
||||
|
||||
get(key: string, defaultValue?: unknown): unknown {
|
||||
if (this.#isElectron) {
|
||||
if (this.#useElectronConfig) {
|
||||
return config.get(key, defaultValue);
|
||||
} else {
|
||||
return this.fallback.get(key) ?? defaultValue;
|
||||
@ -30,7 +30,7 @@ export class Config {
|
||||
}
|
||||
|
||||
set(key: string, value: unknown) {
|
||||
if (this.#isElectron) {
|
||||
if (this.#useElectronConfig) {
|
||||
config.set(key, value);
|
||||
} else {
|
||||
this.fallback.set(key, value);
|
||||
@ -38,7 +38,7 @@ export class Config {
|
||||
}
|
||||
|
||||
delete(key: string) {
|
||||
if (this.#isElectron) {
|
||||
if (this.#useElectronConfig) {
|
||||
config.delete(key);
|
||||
} else {
|
||||
this.fallback.delete(key);
|
||||
@ -46,7 +46,7 @@ export class Config {
|
||||
}
|
||||
|
||||
clear() {
|
||||
if (this.#isElectron) {
|
||||
if (this.#useElectronConfig) {
|
||||
config.clear();
|
||||
} else {
|
||||
this.fallback.clear();
|
||||
|
@ -6,7 +6,7 @@ import { DatabaseHandler } from './core/dbHandler';
|
||||
import { DocHandler } from './core/docHandler';
|
||||
import { DocValue, FyoConfig } from './core/types';
|
||||
import { Config } from './demux/config';
|
||||
import Doc from './model/doc';
|
||||
import { Doc } from './model/doc';
|
||||
import { ModelMap } from './model/types';
|
||||
import { TelemetryManager } from './telemetry/telemetry';
|
||||
import {
|
||||
@ -60,7 +60,7 @@ export class Fyo {
|
||||
});
|
||||
|
||||
this.telemetry = new TelemetryManager(this);
|
||||
this.config = new Config(this.isElectron);
|
||||
this.config = new Config(this.isElectron && !this.isTest);
|
||||
}
|
||||
|
||||
get initialized() {
|
||||
|
@ -45,7 +45,7 @@ import {
|
||||
} from './types';
|
||||
import { validateSelect } from './validationFunction';
|
||||
|
||||
export default class Doc extends Observable<DocValue | Doc[]> {
|
||||
export class Doc extends Observable<DocValue | Doc[]> {
|
||||
name?: string;
|
||||
schema: Readonly<Schema>;
|
||||
fyo: Fyo;
|
||||
@ -72,12 +72,14 @@ export default class Doc extends Observable<DocValue | Doc[]> {
|
||||
super();
|
||||
this.fyo = fyo;
|
||||
this.schema = schema;
|
||||
this._setInitialValues(data);
|
||||
this.fieldMap = getMapFromList(schema.fields, 'fieldname');
|
||||
|
||||
if (this.schema.isSingle) {
|
||||
this.name = this.schemaName;
|
||||
}
|
||||
|
||||
this._setDefaults();
|
||||
this._setValuesWithoutChecks(data);
|
||||
}
|
||||
|
||||
get schemaName(): string {
|
||||
@ -103,23 +105,17 @@ export default class Doc extends Observable<DocValue | Doc[]> {
|
||||
return fieldnames.map((f) => this.fieldMap[f]);
|
||||
}
|
||||
|
||||
_setInitialValues(data: DocValueMap) {
|
||||
for (const fieldname in data) {
|
||||
const value = data[fieldname];
|
||||
_setValuesWithoutChecks(data: DocValueMap) {
|
||||
for (const field of this.schema.fields) {
|
||||
const fieldname = field.fieldname;
|
||||
const value = data[field.fieldname];
|
||||
|
||||
if (Array.isArray(value)) {
|
||||
for (const row of value) {
|
||||
this.push(fieldname, row);
|
||||
}
|
||||
} else {
|
||||
this[fieldname] = value;
|
||||
}
|
||||
}
|
||||
|
||||
// set unset fields as null
|
||||
for (const field of this.schema.fields) {
|
||||
if (this[field.fieldname] === undefined) {
|
||||
this[field.fieldname] = null;
|
||||
this[fieldname] = value ?? null;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -198,7 +194,7 @@ export default class Doc extends Observable<DocValue | Doc[]> {
|
||||
});
|
||||
}
|
||||
|
||||
setDefaults() {
|
||||
_setDefaults() {
|
||||
for (const field of this.schema.fields) {
|
||||
if (!getIsNullOrUndef(this[field.fieldname])) {
|
||||
continue;
|
||||
@ -224,21 +220,21 @@ export default class Doc extends Observable<DocValue | Doc[]> {
|
||||
}
|
||||
}
|
||||
|
||||
append(fieldname: string, docValueMap: Doc | DocValueMap = {}) {
|
||||
async append(fieldname: string, docValueMap: Doc | DocValueMap = {}) {
|
||||
// push child row and trigger change
|
||||
this.push(fieldname, docValueMap);
|
||||
this._dirty = true;
|
||||
this._applyChange(fieldname);
|
||||
await this._applyChange(fieldname);
|
||||
}
|
||||
|
||||
push(fieldname: string, docValueMap: Doc | DocValueMap = {}) {
|
||||
// push child row without triggering change
|
||||
this[fieldname] ??= [];
|
||||
const childDoc = this._initChild(docValueMap, fieldname);
|
||||
const childDoc = this._getChildDoc(docValueMap, fieldname);
|
||||
(this[fieldname] as Doc[]).push(childDoc);
|
||||
}
|
||||
|
||||
_initChild(docValueMap: Doc | DocValueMap, fieldname: string): Doc {
|
||||
_getChildDoc(docValueMap: Doc | DocValueMap, fieldname: string): Doc {
|
||||
if (docValueMap instanceof Doc) {
|
||||
return docValueMap;
|
||||
}
|
||||
@ -258,14 +254,13 @@ export default class Doc extends Observable<DocValue | Doc[]> {
|
||||
data.name = getRandomString();
|
||||
}
|
||||
|
||||
const childSchemaName = this.fieldMap[fieldname] as TargetField;
|
||||
const schema = this.fyo.db.schemaMap[childSchemaName.target] as Schema;
|
||||
const targetField = this.fieldMap[fieldname] as TargetField;
|
||||
const schema = this.fyo.db.schemaMap[targetField.target] as Schema;
|
||||
const childDoc = new Doc(schema, data as DocValueMap, this.fyo);
|
||||
childDoc.setDefaults();
|
||||
return childDoc;
|
||||
}
|
||||
|
||||
async validateInsert() {
|
||||
async _validateInsert() {
|
||||
this._validateMandatory();
|
||||
await this._validateFields();
|
||||
}
|
||||
@ -373,10 +368,6 @@ export default class Doc extends Observable<DocValue | Doc[]> {
|
||||
|
||||
if (data && data.name) {
|
||||
this.syncValues(data);
|
||||
if (this.schema.isSingle) {
|
||||
this.setDefaults();
|
||||
}
|
||||
|
||||
await this.loadLinks();
|
||||
} else {
|
||||
throw new NotFoundError(`Not Found: ${this.schemaName} ${this.name}`);
|
||||
@ -420,7 +411,7 @@ export default class Doc extends Observable<DocValue | Doc[]> {
|
||||
|
||||
syncValues(data: DocValueMap) {
|
||||
this.clearValues();
|
||||
this._setInitialValues(data);
|
||||
this._setValuesWithoutChecks(data);
|
||||
this._dirty = false;
|
||||
this.trigger('change', {
|
||||
doc: this,
|
||||
@ -436,7 +427,7 @@ export default class Doc extends Observable<DocValue | Doc[]> {
|
||||
this._notInserted = true;
|
||||
}
|
||||
|
||||
setChildIdx() {
|
||||
_setChildIdx() {
|
||||
const childFields = this.schema.fields.filter(
|
||||
(f) => f.fieldtype === FieldTypeEnum.Table
|
||||
) as TargetField[];
|
||||
@ -450,7 +441,7 @@ export default class Doc extends Observable<DocValue | Doc[]> {
|
||||
}
|
||||
}
|
||||
|
||||
async compareWithCurrentDoc() {
|
||||
async _compareWithCurrentDoc() {
|
||||
if (this.isNew || !this.name) {
|
||||
return;
|
||||
}
|
||||
@ -556,24 +547,24 @@ export default class Doc extends Observable<DocValue | Doc[]> {
|
||||
return;
|
||||
}
|
||||
if (Array.isArray(value) && field.fieldtype === FieldTypeEnum.Table) {
|
||||
value = value.map((row) => this._initChild(row, field.fieldname));
|
||||
value = value.map((row) => this._getChildDoc(row, field.fieldname));
|
||||
}
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
async commit() {
|
||||
async _commit() {
|
||||
// re-run triggers
|
||||
this.setChildIdx();
|
||||
this._setChildIdx();
|
||||
await this._applyFormula();
|
||||
await this.trigger('validate', null);
|
||||
}
|
||||
|
||||
async insert() {
|
||||
async _insert() {
|
||||
await setName(this, this.fyo);
|
||||
this._setBaseMetaValues();
|
||||
await this.commit();
|
||||
await this.validateInsert();
|
||||
await this._commit();
|
||||
await this._validateInsert();
|
||||
await this.trigger('beforeInsert', null);
|
||||
|
||||
const oldName = this.name!;
|
||||
@ -591,9 +582,9 @@ export default class Doc extends Observable<DocValue | Doc[]> {
|
||||
return this;
|
||||
}
|
||||
|
||||
async update() {
|
||||
await this.compareWithCurrentDoc();
|
||||
await this.commit();
|
||||
async _update() {
|
||||
await this._compareWithCurrentDoc();
|
||||
await this._commit();
|
||||
await this.trigger('beforeUpdate');
|
||||
|
||||
// before submit
|
||||
@ -617,11 +608,11 @@ export default class Doc extends Observable<DocValue | Doc[]> {
|
||||
return this;
|
||||
}
|
||||
|
||||
async insertOrUpdate() {
|
||||
async sync() {
|
||||
if (this._notInserted) {
|
||||
return await this.insert();
|
||||
return await this._insert();
|
||||
} else {
|
||||
return await this.update();
|
||||
return await this._update();
|
||||
}
|
||||
}
|
||||
|
||||
@ -633,11 +624,11 @@ export default class Doc extends Observable<DocValue | Doc[]> {
|
||||
this.fyo.telemetry.log(Verb.Deleted, this.schemaName);
|
||||
}
|
||||
|
||||
async submitOrRevert(isSubmit: boolean) {
|
||||
async _submitOrRevert(isSubmit: boolean) {
|
||||
const wasSubmitted = this.submitted;
|
||||
this.submitted = isSubmit;
|
||||
try {
|
||||
await this.update();
|
||||
await this.sync();
|
||||
} catch (e) {
|
||||
this.submitted = wasSubmitted;
|
||||
throw e;
|
||||
@ -646,11 +637,11 @@ export default class Doc extends Observable<DocValue | Doc[]> {
|
||||
|
||||
async submit() {
|
||||
this.cancelled = false;
|
||||
await this.submitOrRevert(true);
|
||||
await this._submitOrRevert(true);
|
||||
}
|
||||
|
||||
async revert() {
|
||||
await this.submitOrRevert(false);
|
||||
await this._submitOrRevert(false);
|
||||
}
|
||||
|
||||
async rename(newName: string) {
|
||||
@ -701,15 +692,12 @@ export default class Doc extends Observable<DocValue | Doc[]> {
|
||||
return this.fyo.doc.getCachedValue(schemaName, name, fieldname);
|
||||
}
|
||||
|
||||
async setAndUpdate(
|
||||
fieldname: string | DocValueMap,
|
||||
value?: DocValue | Doc[]
|
||||
) {
|
||||
async setAndSync(fieldname: string | DocValueMap, value?: DocValue | Doc[]) {
|
||||
await this.set(fieldname, value);
|
||||
return await this.update();
|
||||
return await this.sync();
|
||||
}
|
||||
|
||||
async duplicate(shouldInsert: boolean = true): Promise<Doc> {
|
||||
async duplicate(shouldSync: boolean = true): Promise<Doc> {
|
||||
const updateMap: DocValueMap = {};
|
||||
const docValueMap = this.getValidDict();
|
||||
const fieldnames = this.schema.fields.map((f) => f.fieldname);
|
||||
@ -736,11 +724,11 @@ export default class Doc extends Observable<DocValue | Doc[]> {
|
||||
updateMap.name = updateMap.name + ' CPY';
|
||||
}
|
||||
|
||||
const doc = this.fyo.doc.getEmptyDoc(this.schemaName, false);
|
||||
const doc = this.fyo.doc.getNewDoc(this.schemaName, {}, false);
|
||||
await doc.setMultiple(updateMap);
|
||||
|
||||
if (shouldInsert) {
|
||||
await doc.insert();
|
||||
if (shouldSync) {
|
||||
await doc.sync();
|
||||
}
|
||||
|
||||
return doc;
|
||||
|
@ -5,7 +5,7 @@ import { isEqual } from 'lodash';
|
||||
import Money from 'pesa/dist/types/src/money';
|
||||
import { Field, FieldType, FieldTypeEnum } from 'schemas/types';
|
||||
import { getIsNullOrUndef } from 'utils';
|
||||
import Doc from './doc';
|
||||
import { Doc } from './doc';
|
||||
|
||||
export function areDocValuesEqual(
|
||||
dvOne: DocValue | Doc[],
|
||||
|
@ -4,7 +4,7 @@ import { DEFAULT_SERIES_START } from 'fyo/utils/consts';
|
||||
import { BaseError } from 'fyo/utils/errors';
|
||||
import { Field, Schema } from 'schemas/types';
|
||||
import { getRandomString } from 'utils';
|
||||
import Doc from './doc';
|
||||
import { Doc } from './doc';
|
||||
|
||||
export function getNumberSeries(schema: Schema): Field | undefined {
|
||||
const numberSeries = schema.fields.find(
|
||||
@ -119,5 +119,5 @@ export async function createNumberSeries(
|
||||
referenceType,
|
||||
});
|
||||
|
||||
await series.insert();
|
||||
await series.sync();
|
||||
}
|
||||
|
@ -4,7 +4,7 @@ import SystemSettings from 'fyo/models/SystemSettings';
|
||||
import { FieldType } from 'schemas/types';
|
||||
import { QueryFilter } from 'utils/db/types';
|
||||
import { Router } from 'vue-router';
|
||||
import Doc from './doc';
|
||||
import { Doc } from './doc';
|
||||
|
||||
/**
|
||||
* The functions below are used for dynamic evaluation
|
||||
|
@ -1,4 +1,4 @@
|
||||
import Doc from 'fyo/model/doc';
|
||||
import { Doc } from 'fyo/model/doc';
|
||||
|
||||
function getPaddedName(prefix: string, next: number, padZeros: number): string {
|
||||
return prefix + next.toString().padStart(padZeros ?? 4, '0');
|
||||
@ -21,7 +21,7 @@ export default class NumberSeries extends Doc {
|
||||
}
|
||||
|
||||
this.current = (this.current as number) + 1;
|
||||
await this.update();
|
||||
await this.sync();
|
||||
return this.getPaddedName(this.current as number);
|
||||
}
|
||||
|
||||
|
@ -1,5 +1,5 @@
|
||||
import { DocValue } from 'fyo/core/types';
|
||||
import Doc from 'fyo/model/doc';
|
||||
import { Doc } from 'fyo/model/doc';
|
||||
import { ValidationMap } from 'fyo/model/types';
|
||||
import { ValidationError } from 'fyo/utils/errors';
|
||||
import { t } from 'fyo/utils/translation';
|
||||
|
@ -58,14 +58,14 @@ describe('Fyo Docs', function () {
|
||||
await fyo.close();
|
||||
});
|
||||
|
||||
specify('getEmptyDoc', async function () {
|
||||
specify('getNewDoc', async function () {
|
||||
for (const schemaName in schemaMap) {
|
||||
const schema = schemaMap[schemaName];
|
||||
if (schema?.isSingle) {
|
||||
continue;
|
||||
}
|
||||
|
||||
const doc = fyo.doc.getEmptyDoc(schemaName);
|
||||
const doc = fyo.doc.getNewDoc(schemaName);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
@ -1,6 +1,6 @@
|
||||
import { Fyo } from 'fyo';
|
||||
import { DocValue } from 'fyo/core/types';
|
||||
import Doc from 'fyo/model/doc';
|
||||
import { Doc } from 'fyo/model/doc';
|
||||
import { DateTime } from 'luxon';
|
||||
import Money from 'pesa/dist/types/src/money';
|
||||
import { Field, FieldType, FieldTypeEnum } from 'schemas/types';
|
||||
|
@ -1,5 +1,5 @@
|
||||
import { Fyo } from 'fyo';
|
||||
import Doc from 'fyo/model/doc';
|
||||
import { Doc } from 'fyo/model/doc';
|
||||
import { Action } from 'fyo/model/types';
|
||||
import { pesa } from 'pesa';
|
||||
|
||||
|
@ -1,5 +1,5 @@
|
||||
import { Fyo } from 'fyo';
|
||||
import Doc from 'fyo/model/doc';
|
||||
import { Doc } from 'fyo/model/doc';
|
||||
import {
|
||||
FiltersMap,
|
||||
ListViewSettings,
|
||||
|
@ -1,4 +1,4 @@
|
||||
import Doc from 'fyo/model/doc';
|
||||
import { Doc } from 'fyo/model/doc';
|
||||
import { ListViewSettings } from 'fyo/model/types';
|
||||
|
||||
export class AccountingLedgerEntry extends Doc {
|
||||
|
@ -1,4 +1,4 @@
|
||||
import Doc from 'fyo/model/doc';
|
||||
import { Doc } from 'fyo/model/doc';
|
||||
import { FiltersMap, ListsMap, ValidationMap } from 'fyo/model/types';
|
||||
import { validateEmail } from 'fyo/model/validationFunction';
|
||||
import { getCountryInfo } from 'utils/misc';
|
||||
|
@ -1,5 +1,5 @@
|
||||
import { Fyo } from 'fyo';
|
||||
import Doc from 'fyo/model/doc';
|
||||
import { Doc } from 'fyo/model/doc';
|
||||
import { EmptyMessageMap, FormulaMap, ListsMap } from 'fyo/model/types';
|
||||
import { stateCodeMap } from 'regional/in';
|
||||
import { titleCase } from 'utils';
|
||||
|
@ -1,5 +1,5 @@
|
||||
import { DocValue } from 'fyo/core/types';
|
||||
import Doc from 'fyo/model/doc';
|
||||
import { Doc } from 'fyo/model/doc';
|
||||
import { DefaultMap, FiltersMap, FormulaMap } from 'fyo/model/types';
|
||||
import { getExchangeRate } from 'models/helpers';
|
||||
import { LedgerPosting } from 'models/ledgerPosting/ledgerPosting';
|
||||
|
@ -1,5 +1,5 @@
|
||||
import { DocValue } from 'fyo/core/types';
|
||||
import Doc from 'fyo/model/doc';
|
||||
import { Doc } from 'fyo/model/doc';
|
||||
import {
|
||||
DependsOnMap,
|
||||
FiltersMap,
|
||||
|
@ -1,6 +1,6 @@
|
||||
import { Fyo } from 'fyo';
|
||||
import { DocValue } from 'fyo/core/types';
|
||||
import Doc from 'fyo/model/doc';
|
||||
import { Doc } from 'fyo/model/doc';
|
||||
import {
|
||||
Action,
|
||||
DependsOnMap,
|
||||
@ -68,8 +68,8 @@ export class Item extends Doc {
|
||||
label: fyo.t`New Invoice`,
|
||||
condition: (doc) => !doc.isNew,
|
||||
action: async (doc, router) => {
|
||||
const invoice = await fyo.doc.getEmptyDoc('SalesInvoice');
|
||||
invoice.append('items', {
|
||||
const invoice = await fyo.doc.getNewDoc('SalesInvoice');
|
||||
await invoice.append('items', {
|
||||
item: doc.name as string,
|
||||
rate: doc.rate as Money,
|
||||
tax: doc.tax as string,
|
||||
@ -81,8 +81,8 @@ export class Item extends Doc {
|
||||
label: fyo.t`New Bill`,
|
||||
condition: (doc) => !doc.isNew,
|
||||
action: async (doc, router) => {
|
||||
const invoice = await fyo.doc.getEmptyDoc('PurchaseInvoice');
|
||||
invoice.append('items', {
|
||||
const invoice = await fyo.doc.getNewDoc('PurchaseInvoice');
|
||||
await invoice.append('items', {
|
||||
item: doc.name as string,
|
||||
rate: doc.rate as Money,
|
||||
tax: doc.tax as string,
|
||||
|
@ -1,5 +1,5 @@
|
||||
import { Fyo } from 'fyo';
|
||||
import Doc from 'fyo/model/doc';
|
||||
import { Doc } from 'fyo/model/doc';
|
||||
import {
|
||||
Action,
|
||||
DefaultMap,
|
||||
|
@ -1,4 +1,4 @@
|
||||
import Doc from 'fyo/model/doc';
|
||||
import { Doc } from 'fyo/model/doc';
|
||||
import { FiltersMap, FormulaMap } from 'fyo/model/types';
|
||||
import Money from 'pesa/dist/types/src/money';
|
||||
|
||||
|
@ -1,5 +1,5 @@
|
||||
import { Fyo } from 'fyo';
|
||||
import Doc from 'fyo/model/doc';
|
||||
import { Doc } from 'fyo/model/doc';
|
||||
import {
|
||||
Action,
|
||||
FiltersMap,
|
||||
@ -47,7 +47,7 @@ export class Party extends Doc {
|
||||
.reduce((a, b) => a.add(b), this.fyo.pesa(0));
|
||||
|
||||
await this.set('outstandingAmount', totalOutstanding);
|
||||
await this.update();
|
||||
await this.sync();
|
||||
}
|
||||
|
||||
formulas: FormulaMap = {
|
||||
@ -111,7 +111,7 @@ export class Party extends Doc {
|
||||
condition: (doc: Doc) =>
|
||||
!doc.isNew && (doc.role as PartyRole) !== 'Customer',
|
||||
action: async (partyDoc, router) => {
|
||||
const doc = await fyo.doc.getEmptyDoc('PurchaseInvoice');
|
||||
const doc = await fyo.doc.getNewDoc('PurchaseInvoice');
|
||||
router.push({
|
||||
path: `/edit/PurchaseInvoice/${doc.name}`,
|
||||
query: {
|
||||
@ -146,7 +146,7 @@ export class Party extends Doc {
|
||||
condition: (doc: Doc) =>
|
||||
!doc.isNew && (doc.role as PartyRole) !== 'Supplier',
|
||||
action: async (partyDoc, router) => {
|
||||
const doc = await fyo.doc.getEmptyDoc('SalesInvoice');
|
||||
const doc = await fyo.doc.getNewDoc('SalesInvoice');
|
||||
router.push({
|
||||
path: `/edit/SalesInvoice/${doc.name}`,
|
||||
query: {
|
||||
|
@ -1,7 +1,6 @@
|
||||
import { LedgerPosting } from 'models/ledgerPosting/ledgerPosting';
|
||||
import { Fyo } from 'fyo';
|
||||
import { DocValue } from 'fyo/core/types';
|
||||
import Doc from 'fyo/model/doc';
|
||||
import { Doc } from 'fyo/model/doc';
|
||||
import {
|
||||
Action,
|
||||
DefaultMap,
|
||||
@ -14,6 +13,7 @@ import {
|
||||
} from 'fyo/model/types';
|
||||
import { ValidationError } from 'fyo/utils/errors';
|
||||
import { getLedgerLinkAction } from 'models/helpers';
|
||||
import { LedgerPosting } from 'models/ledgerPosting/ledgerPosting';
|
||||
import Money from 'pesa/dist/types/src/money';
|
||||
import { getIsNullOrUndef } from 'utils';
|
||||
import { Party } from '../Party/Party';
|
||||
@ -237,7 +237,7 @@ export class Payment extends Doc {
|
||||
// update outstanding amounts in invoice and party
|
||||
const newOutstanding = outstandingAmount.sub(amount);
|
||||
await referenceDoc.set('outstandingAmount', newOutstanding);
|
||||
await referenceDoc.update();
|
||||
await referenceDoc.sync();
|
||||
const party = (await this.fyo.doc.getDoc(
|
||||
'Party',
|
||||
this.party!
|
||||
@ -276,7 +276,7 @@ export class Payment extends Doc {
|
||||
amount as Money
|
||||
),
|
||||
});
|
||||
refDoc.update();
|
||||
refDoc.sync();
|
||||
}
|
||||
);
|
||||
}
|
||||
|
@ -1,4 +1,4 @@
|
||||
import Doc from 'fyo/model/doc';
|
||||
import { Doc } from 'fyo/model/doc';
|
||||
import { FiltersMap, FormulaMap } from 'fyo/model/types';
|
||||
import Money from 'pesa/dist/types/src/money';
|
||||
|
||||
|
@ -1,5 +1,5 @@
|
||||
import { t } from 'fyo';
|
||||
import Doc from 'fyo/model/doc';
|
||||
import { Doc } from 'fyo/model/doc';
|
||||
import {
|
||||
DependsOnMap,
|
||||
FormulaMap,
|
||||
@ -7,8 +7,7 @@ import {
|
||||
ValidationMap,
|
||||
} from 'fyo/model/types';
|
||||
import { validateEmail } from 'fyo/model/validationFunction';
|
||||
import { DateTime } from 'luxon';
|
||||
import { getCountryInfo } from 'utils/misc';
|
||||
import { getCountryInfo, getFiscalYear } from 'utils/misc';
|
||||
|
||||
export function getCOAList() {
|
||||
return [
|
||||
@ -42,35 +41,19 @@ export class SetupWizard extends Doc {
|
||||
fiscalYearStart: async () => {
|
||||
if (!this.country) return;
|
||||
|
||||
const today = DateTime.local();
|
||||
|
||||
const countryInfo = getCountryInfo();
|
||||
const fyStart = countryInfo[this.country as string]?.fiscal_year_start as
|
||||
| string
|
||||
| undefined;
|
||||
|
||||
if (fyStart) {
|
||||
return DateTime.fromFormat(fyStart, 'MM-dd')
|
||||
.plus({ year: [1, 2, 3].includes(today.month) ? -1 : 0 })
|
||||
.toISODate();
|
||||
}
|
||||
const fyStart =
|
||||
countryInfo[this.country as string]?.fiscal_year_start ?? '';
|
||||
return getFiscalYear(fyStart, true);
|
||||
},
|
||||
fiscalYearEnd: async () => {
|
||||
if (!this.country) {
|
||||
return;
|
||||
}
|
||||
|
||||
const today = DateTime.local();
|
||||
|
||||
const countryInfo = getCountryInfo();
|
||||
const fyEnd = countryInfo[this.country as string]?.fiscal_year_end as
|
||||
| string
|
||||
| undefined;
|
||||
if (fyEnd) {
|
||||
return DateTime.fromFormat(fyEnd, 'MM-dd')
|
||||
.plus({ year: [1, 2, 3].includes(today.month) ? 0 : 1 })
|
||||
.toISODate();
|
||||
}
|
||||
const fyEnd = countryInfo[this.country as string]?.fiscal_year_end ?? '';
|
||||
return getFiscalYear(fyEnd, false);
|
||||
},
|
||||
currency: async () => {
|
||||
if (!this.country) {
|
||||
|
@ -1,4 +1,4 @@
|
||||
import Doc from 'fyo/model/doc';
|
||||
import { Doc } from 'fyo/model/doc';
|
||||
import { ListViewSettings } from 'fyo/model/types';
|
||||
|
||||
export class Tax extends Doc {
|
||||
|
@ -1,4 +1,4 @@
|
||||
import Doc from 'fyo/model/doc';
|
||||
import { Doc } from 'fyo/model/doc';
|
||||
import { FormulaMap } from 'fyo/model/types';
|
||||
import Money from 'pesa/dist/types/src/money';
|
||||
|
||||
|
@ -1,5 +1,5 @@
|
||||
import { Fyo } from 'fyo';
|
||||
import Doc from 'fyo/model/doc';
|
||||
import { Doc } from 'fyo/model/doc';
|
||||
import { Action, ColumnConfig } from 'fyo/model/types';
|
||||
import { NotFoundError } from 'fyo/utils/errors';
|
||||
import { DateTime } from 'luxon';
|
||||
@ -34,7 +34,7 @@ export function getTransactionActions(schemaName: string, fyo: Fyo): Action[] {
|
||||
condition: (doc: Doc) =>
|
||||
(doc.submitted as boolean) && (doc.outstandingAmount as Money).gt(0),
|
||||
action: async function makePayment(doc: Doc) {
|
||||
const payment = await fyo.doc.getEmptyDoc('Payment');
|
||||
const payment = await fyo.doc.getNewDoc('Payment');
|
||||
payment.once('afterInsert', async () => {
|
||||
await payment.submit();
|
||||
});
|
||||
|
@ -1,5 +1,5 @@
|
||||
import { Fyo } from 'fyo';
|
||||
import Doc from 'fyo/model/doc';
|
||||
import { Doc } from 'fyo/model/doc';
|
||||
import { ValidationError } from 'fyo/utils/errors';
|
||||
import Money from 'pesa/dist/types/src/money';
|
||||
import {
|
||||
@ -127,7 +127,7 @@ export class LedgerPosting {
|
||||
entry.name as string
|
||||
);
|
||||
entryDoc.reverted = true;
|
||||
await entryDoc.update();
|
||||
await entryDoc.sync();
|
||||
}
|
||||
|
||||
let temp;
|
||||
@ -193,13 +193,13 @@ export class LedgerPosting {
|
||||
for (const entry of this.entries) {
|
||||
const entryDoc = this.fyo.doc.getNewDoc('AccountingLedgerEntry');
|
||||
Object.assign(entryDoc, entry);
|
||||
await entryDoc.insert();
|
||||
await entryDoc.sync();
|
||||
}
|
||||
for (const entry of this.accountEntries) {
|
||||
const entryDoc = await this.fyo.doc.getDoc('Account', entry.name);
|
||||
const balance = entryDoc.get('balance') as Money;
|
||||
entryDoc.balance = balance.add(entry.balanceChange);
|
||||
await entryDoc.update();
|
||||
await entryDoc.sync();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1,4 +1,4 @@
|
||||
import Doc from 'fyo/model/doc';
|
||||
import { Doc } from 'fyo/model/doc';
|
||||
import Money from 'pesa/dist/types/src/money';
|
||||
|
||||
export interface LedgerPostingOptions {
|
||||
|
@ -101,7 +101,7 @@ export default {
|
||||
},
|
||||
async setupComplete(setupWizardOptions) {
|
||||
const filePath = fyo.config.get(ConfigKeys.LastSelectedFilePath);
|
||||
await setupInstance(filePath, setupWizardOptions);
|
||||
await setupInstance(filePath, setupWizardOptions, fyo);
|
||||
await this.setDesk();
|
||||
},
|
||||
async showSetupWizardOrDesk(filePath) {
|
||||
@ -113,7 +113,7 @@ export default {
|
||||
return;
|
||||
}
|
||||
|
||||
await initializeInstance(filePath, false, countryCode);
|
||||
await initializeInstance(filePath, false, countryCode, fyo);
|
||||
await this.setDesk();
|
||||
},
|
||||
async setDeskRoute() {
|
||||
|
@ -17,3 +17,8 @@ All of them are triggered from `src/App.vue`.
|
||||
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`
|
||||
|
||||
## Global Fyo
|
||||
|
||||
Global fyo is exported from `initFyo.ts`. Only code that isn't going to be unit
|
||||
tested should use this.
|
||||
|
@ -104,7 +104,7 @@ export default {
|
||||
},
|
||||
async openNewDoc() {
|
||||
let doctype = this.df.target;
|
||||
let doc = await fyo.getEmptyDoc(doctype);
|
||||
let doc = await fyo.doc.getNewDoc(doctype);
|
||||
let filters = await this.getFilters();
|
||||
openQuickEdit({
|
||||
doctype,
|
||||
|
@ -78,7 +78,7 @@ export default {
|
||||
'dd/MM/yyyy'
|
||||
).toISO();
|
||||
payment.set({ clearanceDate });
|
||||
await payment.update();
|
||||
await payment.sync();
|
||||
}
|
||||
this.close();
|
||||
await this.afterReconcile();
|
||||
|
@ -87,7 +87,7 @@
|
||||
</div>
|
||||
</template>
|
||||
<script>
|
||||
import Doc from 'fyo/model/doc';
|
||||
import { Doc } from 'fyo/model/doc';
|
||||
import Button from 'src/components/Button.vue';
|
||||
import FormControl from 'src/components/Controls/FormControl.vue';
|
||||
import { getErrorMessage, handleErrorWithDialog } from 'src/errorHandling';
|
||||
@ -201,14 +201,11 @@ export default {
|
||||
if (df.fieldtype === 'Table') {
|
||||
return;
|
||||
}
|
||||
this.doc.update();
|
||||
this.doc.sync();
|
||||
}
|
||||
},
|
||||
insertOrUpdate() {
|
||||
return this.doc.insertOrUpdate().catch(this.handleError);
|
||||
},
|
||||
insert() {
|
||||
return this.doc.insert().catch(this.handleError);
|
||||
sync() {
|
||||
return this.doc.sync().catch(this.handleError);
|
||||
},
|
||||
submit() {
|
||||
return this.doc.submit().catch(this.handleError);
|
||||
@ -223,7 +220,7 @@ export default {
|
||||
|
||||
this.inlineEditField = df;
|
||||
if (!this.doc[df.fieldname]) {
|
||||
this.inlineEditDoc = await fyo.doc.getEmptyDoc(df.target);
|
||||
this.inlineEditDoc = await fyo.doc.getNewDoc(df.target);
|
||||
this.inlineEditDoc.once('afterInsert', () => {
|
||||
this.onChangeCommon(df, this.inlineEditDoc.name);
|
||||
});
|
||||
@ -239,7 +236,7 @@ export default {
|
||||
if (!this.inlineEditDoc) {
|
||||
return;
|
||||
}
|
||||
await this.$refs.inlineEditForm[0].insertOrUpdate();
|
||||
await this.$refs.inlineEditForm[0].sync();
|
||||
await this.doc.loadLinks();
|
||||
|
||||
if (this.emitChange && df.inline) {
|
||||
|
@ -1,6 +1,6 @@
|
||||
import { Fyo, t } from 'fyo';
|
||||
import { DocValueMap } from 'fyo/core/types';
|
||||
import Doc from 'fyo/model/doc';
|
||||
import { Doc } from 'fyo/model/doc';
|
||||
import { isNameAutoSet } from 'fyo/model/naming';
|
||||
import { Noun, Verb } from 'fyo/telemetry/types';
|
||||
import {
|
||||
@ -389,7 +389,7 @@ export class Importer {
|
||||
delete docObj[key];
|
||||
}
|
||||
|
||||
const doc: Doc = this.fyo.doc.getEmptyDoc(this.schemaName, false);
|
||||
const doc: Doc = this.fyo.doc.getNewDoc(this.schemaName, {}, false);
|
||||
try {
|
||||
await this.makeEntry(doc, docObj);
|
||||
entriesMade += 1;
|
||||
@ -425,7 +425,7 @@ export class Importer {
|
||||
|
||||
async makeEntry(doc: Doc, docObj: Map) {
|
||||
await doc.setMultiple(docObj as DocValueMap);
|
||||
await doc.insert();
|
||||
await doc.sync();
|
||||
if (this.shouldSubmit) {
|
||||
await doc.submit();
|
||||
}
|
||||
|
@ -1,7 +1,7 @@
|
||||
import { ipcRenderer } from 'electron';
|
||||
import { t } from 'fyo';
|
||||
import { ConfigKeys } from 'fyo/core/types';
|
||||
import Doc from 'fyo/model/doc';
|
||||
import { Doc } from 'fyo/model/doc';
|
||||
import { TelemetrySetting } from 'fyo/telemetry/types';
|
||||
import {
|
||||
DuplicateEntryError,
|
||||
|
@ -1,5 +1,6 @@
|
||||
import { Fyo } from 'fyo';
|
||||
import { getRegionalModels, models } from 'models';
|
||||
import { ModelNameEnum } from 'models/types';
|
||||
import { getValueMapFromList } from 'utils';
|
||||
|
||||
export const fyo = new Fyo({ isTest: false, isElectron: true });
|
||||
@ -15,7 +16,8 @@ async function closeDbIfConnected() {
|
||||
export async function initializeInstance(
|
||||
dbPath: string,
|
||||
isNew: boolean,
|
||||
countryCode: string
|
||||
countryCode: string,
|
||||
fyo: Fyo
|
||||
) {
|
||||
if (isNew) {
|
||||
await closeDbIfConnected();
|
||||
@ -27,17 +29,17 @@ export async function initializeInstance(
|
||||
const regionalModels = await getRegionalModels(countryCode);
|
||||
await fyo.initializeAndRegister(models, regionalModels);
|
||||
|
||||
await setSingles();
|
||||
await setCurrencySymbols();
|
||||
await setSingles(fyo);
|
||||
await setCurrencySymbols(fyo);
|
||||
}
|
||||
|
||||
async function setSingles() {
|
||||
await fyo.doc.getSingle('AccountingSettings');
|
||||
await fyo.doc.getSingle('GetStarted');
|
||||
async function setSingles(fyo: Fyo) {
|
||||
await fyo.doc.getSingle(ModelNameEnum.AccountingSettings);
|
||||
await fyo.doc.getSingle(ModelNameEnum.GetStarted);
|
||||
}
|
||||
|
||||
async function setCurrencySymbols() {
|
||||
const currencies = (await fyo.db.getAll('Currency', {
|
||||
async function setCurrencySymbols(fyo: Fyo) {
|
||||
const currencies = (await fyo.db.getAll(ModelNameEnum.Currency, {
|
||||
fields: ['name', 'symbol'],
|
||||
})) as { name: string; symbol: string }[];
|
||||
|
||||
|
@ -240,7 +240,7 @@ export default {
|
||||
this.insertingAccount = true;
|
||||
|
||||
accountName = accountName.trim();
|
||||
let account = await fyo.getEmptyDoc('Account');
|
||||
let account = await fyo.doc.getNewDoc('Account');
|
||||
try {
|
||||
let { name, rootType, accountType } = parentAccount;
|
||||
await account.set({
|
||||
@ -250,7 +250,7 @@ export default {
|
||||
accountType,
|
||||
isGroup,
|
||||
});
|
||||
await account.insert();
|
||||
await account.sync();
|
||||
|
||||
// turn off editing
|
||||
parentAccount.addingAccount = 0;
|
||||
|
@ -74,7 +74,6 @@ export default {
|
||||
},
|
||||
methods: {
|
||||
selectOption(value) {
|
||||
console.log(value);
|
||||
this.$emit('change', value);
|
||||
this.$refs.dropdown.toggleDropdown(false);
|
||||
},
|
||||
|
@ -143,7 +143,7 @@ export default {
|
||||
this.invoices = await Promise.all(promises);
|
||||
},
|
||||
async newInvoice(invoice) {
|
||||
let doc = await fyo.doc.getEmptyDoc(invoice.doctype);
|
||||
let doc = await fyo.doc.getNewDoc(invoice.doctype);
|
||||
routeTo(`/edit/${invoice.doctype}/${doc.name}`);
|
||||
},
|
||||
},
|
||||
|
@ -308,7 +308,7 @@ export default {
|
||||
await this.updateChecks({ onboardingComplete });
|
||||
const systemSettings = await fyo.getSingle('SystemSettings');
|
||||
await systemSettings.set({ hideGetStarted: 1 });
|
||||
await systemSettings.update();
|
||||
await systemSettings.sync();
|
||||
}
|
||||
|
||||
return onboardingComplete;
|
||||
@ -361,7 +361,7 @@ export default {
|
||||
},
|
||||
async updateChecks(toUpdate) {
|
||||
await fyo.GetStarted.setMultiple(toUpdate);
|
||||
await fyo.GetStarted.update();
|
||||
await fyo.GetStarted.sync();
|
||||
fyo.GetStarted = await fyo.getSingle('GetStarted');
|
||||
},
|
||||
isCompleted(item) {
|
||||
|
@ -293,7 +293,7 @@ export default {
|
||||
'items',
|
||||
this.doc.items.filter((row) => row.item)
|
||||
);
|
||||
return this.doc.insertOrUpdate().catch(this.handleError);
|
||||
return this.doc.sync().catch(this.handleError);
|
||||
},
|
||||
onSubmitClick() {
|
||||
let message =
|
||||
|
@ -204,7 +204,7 @@ export default {
|
||||
},
|
||||
methods: {
|
||||
async onSaveClick() {
|
||||
return this.doc.insertOrUpdate().catch(this.handleError);
|
||||
return this.doc.sync().catch(this.handleError);
|
||||
},
|
||||
async onSubmitClick() {
|
||||
showMessageDialog({
|
||||
|
@ -63,7 +63,7 @@ export default {
|
||||
methods: {
|
||||
async makeNewDoc() {
|
||||
const doctype = this.listConfig.doctype;
|
||||
const doc = await fyo.doc.getEmptyDoc(doctype);
|
||||
const doc = await fyo.doc.getNewDoc(doctype);
|
||||
if (this.listConfig.filters) {
|
||||
doc.set(this.listConfig.filters);
|
||||
}
|
||||
|
@ -14,7 +14,7 @@
|
||||
<StatusBadge :status="status" />
|
||||
<Button
|
||||
:icon="true"
|
||||
@click="insertDoc"
|
||||
@click="sync"
|
||||
type="primary"
|
||||
v-if="doc && doc._notInserted"
|
||||
class="ml-2 text-white text-xs"
|
||||
@ -210,8 +210,8 @@ export default {
|
||||
valueChange(df, value) {
|
||||
this.$refs.form.onChange(df, value);
|
||||
},
|
||||
insertDoc() {
|
||||
this.$refs.form.insert();
|
||||
sync() {
|
||||
this.$refs.form.sync();
|
||||
},
|
||||
async submitDoc() {
|
||||
try {
|
||||
|
@ -7,7 +7,7 @@
|
||||
@change="
|
||||
(value) => {
|
||||
doc.set('logo', value);
|
||||
doc.update();
|
||||
doc.sync();
|
||||
forwardChangeEvent(getField('logo'));
|
||||
}
|
||||
"
|
||||
@ -27,7 +27,7 @@
|
||||
@change="
|
||||
(value) => {
|
||||
doc.set('displayLogo', value);
|
||||
doc.update();
|
||||
doc.sync();
|
||||
forwardChangeEvent(getField('displayLogo'));
|
||||
}
|
||||
"
|
||||
|
@ -1,30 +1,26 @@
|
||||
import { fyo } from 'src/initFyo';
|
||||
import { Fyo } from 'fyo';
|
||||
|
||||
export type TaxType = 'GST' | 'IGST' | 'Exempt-GST' | 'Exempt-IGST';
|
||||
|
||||
export async function createIndianRecords() {
|
||||
await generateTaxes();
|
||||
export async function createIndianRecords(fyo: Fyo) {
|
||||
await createTaxes(fyo);
|
||||
}
|
||||
|
||||
async function generateTaxes() {
|
||||
async function createTaxes(fyo: Fyo) {
|
||||
const GSTs = {
|
||||
GST: [28, 18, 12, 6, 5, 3, 0.25, 0],
|
||||
IGST: [28, 18, 12, 6, 5, 3, 0.25, 0],
|
||||
'Exempt-GST': [0],
|
||||
'Exempt-IGST': [0],
|
||||
};
|
||||
const newTax = await fyo.doc.getEmptyDoc('Tax');
|
||||
|
||||
for (const type of Object.keys(GSTs)) {
|
||||
for (const percent of GSTs[type as TaxType]) {
|
||||
const name = `${type}-${percent}`;
|
||||
|
||||
// Not cross checking cause hardcoded values.
|
||||
await fyo.db.delete('Tax', name);
|
||||
|
||||
const details = getTaxDetails(type as TaxType, percent);
|
||||
await newTax.set({ name, details });
|
||||
await newTax.insert();
|
||||
|
||||
const newTax = fyo.doc.getNewDoc('Tax', { name, details });
|
||||
await newTax.sync();
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -41,12 +37,12 @@ function getTaxDetails(type: TaxType, percent: number) {
|
||||
rate: percent / 2,
|
||||
},
|
||||
];
|
||||
} else {
|
||||
return [
|
||||
{
|
||||
account: type.toString().split('-')[0],
|
||||
rate: percent,
|
||||
},
|
||||
];
|
||||
}
|
||||
|
||||
return [
|
||||
{
|
||||
account: type.toString().split('-')[0],
|
||||
rate: percent,
|
||||
},
|
||||
];
|
||||
}
|
||||
|
@ -1,8 +1,9 @@
|
||||
import { Fyo } from 'fyo';
|
||||
import { createIndianRecords } from './in/in';
|
||||
|
||||
export async function createRegionalRecords(country: string) {
|
||||
export async function createRegionalRecords(country: string, fyo: Fyo) {
|
||||
if (country === 'India') {
|
||||
await createIndianRecords();
|
||||
await createIndianRecords(fyo);
|
||||
}
|
||||
|
||||
return;
|
||||
|
@ -1,3 +1,4 @@
|
||||
import { Fyo } from 'fyo';
|
||||
import {
|
||||
AccountRootType,
|
||||
COAChildAccount,
|
||||
@ -5,57 +6,66 @@ import {
|
||||
COATree,
|
||||
} from 'models/baseModels/Account/types';
|
||||
import { getCOAList } from 'models/baseModels/SetupWizard/SetupWizard';
|
||||
import { fyo } from 'src/initFyo';
|
||||
import { getStandardCOA } from './standardCOA';
|
||||
|
||||
const accountFields = ['accountType', 'accountNumber', 'rootType', 'isGroup'];
|
||||
|
||||
function getAccountName(accountName: string, accountNumber?: string) {
|
||||
if (accountNumber) {
|
||||
return `${accountName} - ${accountNumber}`;
|
||||
export class CreateCOA {
|
||||
fyo: Fyo;
|
||||
chartOfAccounts: string;
|
||||
|
||||
constructor(chartOfAccounts: string, fyo: Fyo) {
|
||||
this.chartOfAccounts = chartOfAccounts;
|
||||
this.fyo = fyo;
|
||||
}
|
||||
|
||||
return accountName;
|
||||
}
|
||||
async run() {
|
||||
const chart = await getCOA(this.chartOfAccounts);
|
||||
await this.createCOAAccounts(chart, null, '', true);
|
||||
}
|
||||
|
||||
async function createCOAAccounts(
|
||||
children: COATree | COARootAccount | COAChildAccount,
|
||||
parentAccount: string,
|
||||
rootType: AccountRootType | '',
|
||||
rootAccount: boolean
|
||||
) {
|
||||
for (const rootName in children) {
|
||||
if (accountFields.includes(rootName)) {
|
||||
continue;
|
||||
async createCOAAccounts(
|
||||
children: COATree | COARootAccount | COAChildAccount,
|
||||
parentAccount: string | null,
|
||||
rootType: AccountRootType | '',
|
||||
rootAccount: boolean
|
||||
) {
|
||||
for (const rootName in children) {
|
||||
if (accountFields.includes(rootName)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
const child = children[rootName];
|
||||
|
||||
if (rootAccount) {
|
||||
rootType = (child as COARootAccount).rootType as AccountRootType;
|
||||
}
|
||||
|
||||
const accountType = (child as COAChildAccount).accountType ?? '';
|
||||
const accountNumber = (child as COAChildAccount).accountNumber;
|
||||
const accountName = getAccountName(rootName, accountNumber);
|
||||
|
||||
const isGroup = identifyIsGroup(
|
||||
child as COAChildAccount | COARootAccount
|
||||
);
|
||||
|
||||
const doc = this.fyo.doc.getNewDoc('Account', {
|
||||
name: accountName,
|
||||
parentAccount,
|
||||
isGroup,
|
||||
rootType,
|
||||
balance: 0,
|
||||
accountType,
|
||||
});
|
||||
|
||||
await doc.sync();
|
||||
await this.createCOAAccounts(
|
||||
child as COAChildAccount,
|
||||
accountName,
|
||||
rootType,
|
||||
false
|
||||
);
|
||||
}
|
||||
|
||||
const child = children[rootName];
|
||||
|
||||
if (rootAccount) {
|
||||
rootType = (child as COARootAccount).rootType as AccountRootType;
|
||||
}
|
||||
|
||||
const accountType = (child as COAChildAccount).accountType ?? '';
|
||||
const accountNumber = (child as COAChildAccount).accountNumber;
|
||||
const accountName = getAccountName(rootName, accountNumber);
|
||||
|
||||
const isGroup = identifyIsGroup(child as COAChildAccount | COARootAccount);
|
||||
const doc = fyo.doc.getNewDoc('Account', {
|
||||
name: accountName,
|
||||
parentAccount,
|
||||
isGroup,
|
||||
rootType,
|
||||
balance: 0,
|
||||
accountType,
|
||||
});
|
||||
|
||||
await doc.insert();
|
||||
await createCOAAccounts(
|
||||
child as COAChildAccount,
|
||||
accountName,
|
||||
rootType,
|
||||
false
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@ -92,7 +102,10 @@ async function getCOA(chartOfAccounts: string) {
|
||||
}
|
||||
}
|
||||
|
||||
export async function createCOA(chartOfAccounts: string) {
|
||||
const chart = await getCOA(chartOfAccounts);
|
||||
await createCOAAccounts(chart, '', '', true);
|
||||
function getAccountName(accountName: string, accountNumber?: string) {
|
||||
if (accountNumber) {
|
||||
return `${accountName} - ${accountNumber}`;
|
||||
}
|
||||
|
||||
return accountName;
|
||||
}
|
||||
|
@ -1,5 +1,6 @@
|
||||
import { Fyo } from 'fyo';
|
||||
import { ConfigFile, DocValueMap } from 'fyo/core/types';
|
||||
import Doc from 'fyo/model/doc';
|
||||
import { Doc } from 'fyo/model/doc';
|
||||
import { createNumberSeries } from 'fyo/model/naming';
|
||||
import { getId } from 'fyo/telemetry/helpers';
|
||||
import {
|
||||
@ -8,51 +9,55 @@ import {
|
||||
DEFAULT_SERIES_START,
|
||||
} from 'fyo/utils/consts';
|
||||
import { AccountingSettings } from 'models/baseModels/AccountingSettings/AccountingSettings';
|
||||
import { fyo, initializeInstance } from 'src/initFyo';
|
||||
import { 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 { CreateCOA } from './createCOA';
|
||||
import { SetupWizardOptions } from './types';
|
||||
|
||||
export default async function setupInstance(
|
||||
dbPath: string,
|
||||
setupWizardOptions: SetupWizardOptions
|
||||
setupWizardOptions: SetupWizardOptions,
|
||||
fyo: Fyo
|
||||
) {
|
||||
const { companyName, country, bankName, chartOfAccounts } =
|
||||
setupWizardOptions;
|
||||
|
||||
await initializeDatabase(dbPath, country);
|
||||
await updateSystemSettings(setupWizardOptions);
|
||||
await updateAccountingSettings(setupWizardOptions);
|
||||
await updatePrintSettings(setupWizardOptions);
|
||||
await initializeDatabase(dbPath, country, fyo);
|
||||
await updateSystemSettings(setupWizardOptions, fyo);
|
||||
await updateAccountingSettings(setupWizardOptions, fyo);
|
||||
await updatePrintSettings(setupWizardOptions, fyo);
|
||||
|
||||
await createCurrencyRecords();
|
||||
await createAccountRecords(bankName, country, chartOfAccounts);
|
||||
await createRegionalRecords(country);
|
||||
await createDefaultNumberSeries();
|
||||
await createCurrencyRecords(fyo);
|
||||
await createAccountRecords(bankName, country, chartOfAccounts, fyo);
|
||||
await createRegionalRecords(country, fyo);
|
||||
await createDefaultNumberSeries(fyo);
|
||||
|
||||
await completeSetup(companyName);
|
||||
await completeSetup(companyName, fyo);
|
||||
}
|
||||
|
||||
async function initializeDatabase(dbPath: string, country: string) {
|
||||
async function initializeDatabase(dbPath: string, country: string, fyo: Fyo) {
|
||||
const countryCode = getCountryCodeFromCountry(country);
|
||||
await initializeInstance(dbPath, true, countryCode);
|
||||
await initializeInstance(dbPath, true, countryCode, fyo);
|
||||
}
|
||||
|
||||
async function updateAccountingSettings({
|
||||
companyName,
|
||||
country,
|
||||
fullname,
|
||||
email,
|
||||
bankName,
|
||||
fiscalYearStart,
|
||||
fiscalYearEnd,
|
||||
}: SetupWizardOptions) {
|
||||
async function updateAccountingSettings(
|
||||
{
|
||||
companyName,
|
||||
country,
|
||||
fullname,
|
||||
email,
|
||||
bankName,
|
||||
fiscalYearStart,
|
||||
fiscalYearEnd,
|
||||
}: SetupWizardOptions,
|
||||
fyo: Fyo
|
||||
) {
|
||||
const accountingSettings = (await fyo.doc.getSingle(
|
||||
'AccountingSettings'
|
||||
)) as AccountingSettings;
|
||||
await accountingSettings.setAndUpdate({
|
||||
await accountingSettings.setAndSync({
|
||||
companyName,
|
||||
country,
|
||||
fullname,
|
||||
@ -64,13 +69,12 @@ async function updateAccountingSettings({
|
||||
return accountingSettings;
|
||||
}
|
||||
|
||||
async function updatePrintSettings({
|
||||
companyLogo,
|
||||
companyName,
|
||||
email,
|
||||
}: SetupWizardOptions) {
|
||||
async function updatePrintSettings(
|
||||
{ companyLogo, companyName, email }: SetupWizardOptions,
|
||||
fyo: Fyo
|
||||
) {
|
||||
const printSettings = await fyo.doc.getSingle('PrintSettings');
|
||||
await printSettings.setAndUpdate({
|
||||
await printSettings.setAndSync({
|
||||
logo: companyLogo,
|
||||
companyName,
|
||||
email,
|
||||
@ -78,23 +82,23 @@ async function updatePrintSettings({
|
||||
});
|
||||
}
|
||||
|
||||
async function updateSystemSettings({
|
||||
country,
|
||||
currency: companyCurrency,
|
||||
}: SetupWizardOptions) {
|
||||
async function updateSystemSettings(
|
||||
{ country, currency: companyCurrency }: SetupWizardOptions,
|
||||
fyo: Fyo
|
||||
) {
|
||||
const countryInfo = getCountryInfo();
|
||||
const countryOptions = countryInfo[country] as CountryInfo;
|
||||
const currency =
|
||||
companyCurrency ?? countryOptions.currency ?? DEFAULT_CURRENCY;
|
||||
const locale = countryOptions.locale ?? DEFAULT_LOCALE;
|
||||
const systemSettings = await fyo.doc.getSingle('SystemSettings');
|
||||
systemSettings.setAndUpdate({
|
||||
systemSettings.setAndSync({
|
||||
locale,
|
||||
currency,
|
||||
});
|
||||
}
|
||||
|
||||
async function createCurrencyRecords() {
|
||||
async function createCurrencyRecords(fyo: Fyo) {
|
||||
const promises: Promise<Doc | undefined>[] = [];
|
||||
const queue: string[] = [];
|
||||
const countrySettings = Object.values(getCountryInfo()) as CountryInfo[];
|
||||
@ -120,7 +124,7 @@ async function createCurrencyRecords() {
|
||||
symbol: currency_symbol ?? '',
|
||||
};
|
||||
|
||||
const doc = checkAndCreateDoc('Currency', docObject);
|
||||
const doc = checkAndCreateDoc('Currency', docObject, fyo);
|
||||
if (doc) {
|
||||
promises.push(doc);
|
||||
queue.push(currency);
|
||||
@ -132,10 +136,12 @@ async function createCurrencyRecords() {
|
||||
async function createAccountRecords(
|
||||
bankName: string,
|
||||
country: string,
|
||||
chartOfAccounts: string
|
||||
chartOfAccounts: string,
|
||||
fyo: Fyo
|
||||
) {
|
||||
await createCOA(chartOfAccounts);
|
||||
const parentAccount = await getBankAccountParentName(country);
|
||||
const createCOA = new CreateCOA(chartOfAccounts, fyo);
|
||||
await createCOA.run();
|
||||
const parentAccount = await getBankAccountParentName(country, fyo);
|
||||
const docObject = {
|
||||
name: bankName,
|
||||
rootType: 'Asset',
|
||||
@ -143,16 +149,16 @@ async function createAccountRecords(
|
||||
accountType: 'Bank',
|
||||
isGroup: false,
|
||||
};
|
||||
await checkAndCreateDoc('Account', docObject);
|
||||
await checkAndCreateDoc('Account', docObject, fyo);
|
||||
}
|
||||
|
||||
async function completeSetup(companyName: string) {
|
||||
updateInitializationConfig(companyName);
|
||||
async function completeSetup(companyName: string, fyo: Fyo) {
|
||||
updateInitializationConfig(companyName, fyo);
|
||||
await fyo.singles.AccountingSettings!.set('setupComplete', true);
|
||||
await fyo.singles.AccountingSettings!.update();
|
||||
await fyo.singles.AccountingSettings!.sync();
|
||||
}
|
||||
|
||||
function updateInitializationConfig(companyName: string) {
|
||||
function updateInitializationConfig(companyName: string, fyo: Fyo) {
|
||||
const dbPath = fyo.db.dbPath;
|
||||
const files = fyo.config.get('files', []) as ConfigFile[];
|
||||
|
||||
@ -166,19 +172,24 @@ function updateInitializationConfig(companyName: string) {
|
||||
fyo.config.set('files', files);
|
||||
}
|
||||
|
||||
async function checkAndCreateDoc(schemaName: string, docObject: DocValueMap) {
|
||||
const canCreate = await checkIfExactRecordAbsent(schemaName, docObject);
|
||||
async function checkAndCreateDoc(
|
||||
schemaName: string,
|
||||
docObject: DocValueMap,
|
||||
fyo: Fyo
|
||||
) {
|
||||
const canCreate = await checkIfExactRecordAbsent(schemaName, docObject, fyo);
|
||||
if (!canCreate) {
|
||||
return;
|
||||
}
|
||||
|
||||
const doc = await fyo.doc.getNewDoc(schemaName, docObject);
|
||||
return doc.insert();
|
||||
return doc.sync();
|
||||
}
|
||||
|
||||
async function checkIfExactRecordAbsent(
|
||||
schemaName: string,
|
||||
docMap: DocValueMap
|
||||
docMap: DocValueMap,
|
||||
fyo: Fyo
|
||||
) {
|
||||
const name = docMap.name as string;
|
||||
const newDocObject = Object.assign({}, docMap);
|
||||
@ -207,7 +218,7 @@ async function checkIfExactRecordAbsent(
|
||||
return false;
|
||||
}
|
||||
|
||||
async function getBankAccountParentName(country: string) {
|
||||
async function getBankAccountParentName(country: string, fyo: Fyo) {
|
||||
const parentBankAccount = await fyo.db.getAllRaw('Account', {
|
||||
fields: ['*'],
|
||||
filters: { isGroup: true, accountType: 'Bank' },
|
||||
@ -228,7 +239,7 @@ async function getBankAccountParentName(country: string) {
|
||||
return parentBankAccount[0].name;
|
||||
}
|
||||
|
||||
async function createDefaultNumberSeries() {
|
||||
async function createDefaultNumberSeries(fyo: Fyo) {
|
||||
await createNumberSeries('SINV-', 'SalesInvoice', DEFAULT_SERIES_START, fyo);
|
||||
await createNumberSeries(
|
||||
'PINV-',
|
||||
|
@ -1,4 +1,4 @@
|
||||
import Doc from 'fyo/model/doc';
|
||||
import { Doc } from 'fyo/model/doc';
|
||||
import { Field, OptionField, SelectOption } from 'schemas/types';
|
||||
import { fyo } from 'src/initFyo';
|
||||
|
||||
|
@ -1,10 +1,9 @@
|
||||
/**
|
||||
* General purpose utils used by the frontend.
|
||||
*/
|
||||
import Doc from 'fyo/model/doc';
|
||||
import { Doc } from 'fyo/model/doc';
|
||||
import { isPesa } from 'fyo/utils';
|
||||
import Money from 'pesa/dist/types/src/money';
|
||||
import { fyo } from 'src/initFyo';
|
||||
|
||||
export function stringifyCircular(
|
||||
obj: unknown,
|
||||
|
@ -40,6 +40,7 @@ export async function getSetupWizardDoc() {
|
||||
return await fyo.doc.getNewDoc(
|
||||
'SetupWizard',
|
||||
{},
|
||||
false,
|
||||
SetupWizardSchema as Schema,
|
||||
SetupWizard
|
||||
);
|
||||
|
@ -4,7 +4,7 @@
|
||||
*/
|
||||
import { ipcRenderer } from 'electron';
|
||||
import { t } from 'fyo';
|
||||
import Doc from 'fyo/model/doc';
|
||||
import { Doc } from 'fyo/model/doc';
|
||||
import { Action } from 'fyo/model/types';
|
||||
import { getActions } from 'fyo/utils';
|
||||
import { handleErrorWithDialog } from 'src/errorHandling';
|
||||
@ -222,7 +222,7 @@ export async function cancelDocWithPrompt(doc: Doc) {
|
||||
async action() {
|
||||
const entryDoc = await fyo.doc.getDoc(doc.schemaName, doc.name!);
|
||||
entryDoc.cancelled = 1;
|
||||
await entryDoc.update();
|
||||
await entryDoc.sync();
|
||||
entryDoc
|
||||
.revert()
|
||||
.then(() => resolve(true))
|
||||
|
17
tests/helpers.ts
Normal file
17
tests/helpers.ts
Normal file
@ -0,0 +1,17 @@
|
||||
import { SetupWizardOptions } from 'src/setup/types';
|
||||
import { getFiscalYear } from 'utils/misc';
|
||||
|
||||
export function getTestSetupWizardOptions(): SetupWizardOptions {
|
||||
return {
|
||||
companyLogo: '',
|
||||
companyName: 'Test Company',
|
||||
country: 'India',
|
||||
fullname: 'Test Person',
|
||||
email: 'test@testmyfantasy.com',
|
||||
bankName: 'Test Bank of Scriptia',
|
||||
currency: 'INR',
|
||||
fiscalYearStart: getFiscalYear('04-01', true),
|
||||
fiscalYearEnd: getFiscalYear('04-01', false),
|
||||
chartOfAccounts: 'India - Chart of Accounts',
|
||||
};
|
||||
}
|
25
tests/testSetupInstance.spec.ts
Normal file
25
tests/testSetupInstance.spec.ts
Normal file
@ -0,0 +1,25 @@
|
||||
import { DatabaseManager } from 'backend/database/manager';
|
||||
import { assertDoesNotThrow } from 'backend/database/tests/helpers';
|
||||
import { Fyo } from 'fyo';
|
||||
import { DummyAuthDemux } from 'fyo/tests/helpers';
|
||||
import 'mocha';
|
||||
import setupInstance from 'src/setup/setupInstance';
|
||||
import { getTestSetupWizardOptions } from './helpers';
|
||||
|
||||
const DB_PATH = '/Users/alan/Desktop/test.db';
|
||||
describe('setupInstance', function () {
|
||||
const fyo = new Fyo({
|
||||
DatabaseDemux: DatabaseManager,
|
||||
AuthDemux: DummyAuthDemux,
|
||||
isTest: true,
|
||||
isElectron: false,
|
||||
});
|
||||
|
||||
const setupOptions = getTestSetupWizardOptions();
|
||||
specify('setupInstance', async function () {
|
||||
await setupInstance(DB_PATH, setupOptions, fyo);
|
||||
await assertDoesNotThrow(async () => {
|
||||
// await setupInstance(':memory:', setupOptions, fyo);
|
||||
}, 'setup instance failed');
|
||||
});
|
||||
});
|
@ -46,6 +46,7 @@
|
||||
"regional/**/*.ts",
|
||||
"reports/**/*.ts",
|
||||
"utils/**/*.ts",
|
||||
"tests/**/*.ts",
|
||||
],
|
||||
"exclude": ["node_modules"]
|
||||
}
|
||||
|
@ -1,4 +1,5 @@
|
||||
import countryInfo from 'fixtures/countryInfo.json';
|
||||
import { DateTime } from 'luxon';
|
||||
import { CountryInfoMap } from './types';
|
||||
|
||||
export function getCountryInfo(): CountryInfoMap {
|
||||
@ -15,3 +16,21 @@ export function getCountryCodeFromCountry(countryName: string): string {
|
||||
|
||||
return countryInfo.code;
|
||||
}
|
||||
|
||||
export function getFiscalYear(date: string, isStart: boolean) {
|
||||
if (!date) {
|
||||
return '';
|
||||
}
|
||||
|
||||
const today = DateTime.local();
|
||||
const dateTime = DateTime.fromFormat(date, 'MM-dd');
|
||||
if (isStart) {
|
||||
return dateTime
|
||||
.plus({ year: [1, 2, 3].includes(today.month) ? -1 : 0 })
|
||||
.toISODate();
|
||||
}
|
||||
|
||||
return dateTime
|
||||
.plus({ year: [1, 2, 3].includes(today.month) ? 0 : 1 })
|
||||
.toISODate();
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user