2
0
mirror of https://github.com/frappe/books.git synced 2025-02-02 12:08:27 +00:00

fix: make setupInstance code work

This commit is contained in:
18alantom 2022-04-25 12:03:31 +05:30
parent 9877bf4fd3
commit 1b85fee5e6
19 changed files with 166 additions and 75 deletions

View File

@ -198,9 +198,9 @@ export async function assertDoesNotThrow(
await func(); await func();
} catch (err) { } catch (err) {
throw new assert.AssertionError({ throw new assert.AssertionError({
message: `Missing expected exception: ${message} Error: ${ message: `Got unwanted exception: ${message}\nError: ${
(err as Error).message (err as Error).message
}`, }\n${(err as Error).stack}`,
}); });
} }
} }

View File

@ -4,7 +4,7 @@ import { isPesa } from 'fyo/utils';
import { ValueError } from 'fyo/utils/errors'; import { ValueError } from 'fyo/utils/errors';
import { DateTime } from 'luxon'; import { DateTime } from 'luxon';
import Money from 'pesa/dist/types/src/money'; import Money from 'pesa/dist/types/src/money';
import { Field, FieldTypeEnum, RawValue } from 'schemas/types'; import { Field, FieldTypeEnum, RawValue, TargetField } from 'schemas/types';
import { getIsNullOrUndef } from 'utils'; import { getIsNullOrUndef } from 'utils';
import { DatabaseHandler } from './dbHandler'; import { DatabaseHandler } from './dbHandler';
import { DocValue, DocValueMap, RawValueMap } from './types'; import { DocValue, DocValueMap, RawValueMap } from './types';
@ -70,7 +70,7 @@ export class Converter {
case FieldTypeEnum.Check: case FieldTypeEnum.Check:
return toDocCheck(value, field); return toDocCheck(value, field);
default: default:
return String(value); return toDocString(value, field);
} }
} }
@ -102,8 +102,9 @@ export class Converter {
const rawValue = rawValueMap[fieldname]; const rawValue = rawValueMap[fieldname];
if (Array.isArray(rawValue)) { if (Array.isArray(rawValue)) {
const parentSchemaName = (field as TargetField).target;
docValueMap[fieldname] = rawValue.map((rv) => docValueMap[fieldname] = rawValue.map((rv) =>
this.#toDocValueMap(schemaName, rv) this.#toDocValueMap(parentSchemaName, rv)
); );
} else { } else {
docValueMap[fieldname] = Converter.toDocValue( docValueMap[fieldname] = Converter.toDocValue(
@ -126,12 +127,14 @@ export class Converter {
const docValue = docValueMap[fieldname]; const docValue = docValueMap[fieldname];
if (Array.isArray(docValue)) { if (Array.isArray(docValue)) {
const parentSchemaName = (field as TargetField).target;
rawValueMap[fieldname] = docValue.map((value) => { rawValueMap[fieldname] = docValue.map((value) => {
if (value instanceof Doc) { if (value instanceof Doc) {
return this.#toRawValueMap(schemaName, value.getValidDict()); return this.#toRawValueMap(parentSchemaName, value.getValidDict());
} }
return this.#toRawValueMap(schemaName, value as DocValueMap); return this.#toRawValueMap(parentSchemaName, value as DocValueMap);
}); });
} else { } else {
rawValueMap[fieldname] = Converter.toRawValue( rawValueMap[fieldname] = Converter.toRawValue(
@ -146,6 +149,18 @@ export class Converter {
} }
} }
function toDocString(value: RawValue, field: Field) {
if (typeof value === 'string') {
return value;
}
if (value === null) {
return value;
}
throwError(value, field, 'doc');
}
function toDocDate(value: RawValue, field: Field) { function toDocDate(value: RawValue, field: Field) {
if (typeof value !== 'number' && typeof value !== 'string') { if (typeof value !== 'number' && typeof value !== 'string') {
throwError(value, field, 'doc'); throwError(value, field, 'doc');

View File

@ -3,7 +3,7 @@ import { DocValue, DocValueMap } from 'fyo/core/types';
import { Verb } from 'fyo/telemetry/types'; import { Verb } from 'fyo/telemetry/types';
import { DEFAULT_USER } from 'fyo/utils/consts'; import { DEFAULT_USER } from 'fyo/utils/consts';
import { import {
Conflict, ConflictError,
MandatoryError, MandatoryError,
NotFoundError, NotFoundError,
ValidationError, ValidationError,
@ -57,7 +57,8 @@ export class Doc extends Observable<DocValue | Doc[]> {
*/ */
idx?: number; idx?: number;
parentdoc?: Doc; parentdoc?: Doc;
parentfield?: string; parentFieldname?: string;
parentSchemaName?: string;
_links?: Record<string, Doc>; _links?: Record<string, Doc>;
_dirty: boolean = true; _dirty: boolean = true;
@ -115,7 +116,7 @@ export class Doc extends Observable<DocValue | Doc[]> {
this.push(fieldname, row); this.push(fieldname, row);
} }
} else { } else {
this[fieldname] = value ?? null; this[fieldname] = value ?? this[fieldname] ?? null;
} }
} }
} }
@ -153,7 +154,7 @@ export class Doc extends Observable<DocValue | Doc[]> {
// always run applyChange from the parentdoc // always run applyChange from the parentdoc
if (this.schema.isChild && this.parentdoc) { if (this.schema.isChild && this.parentdoc) {
await this._applyChange(fieldname); await this._applyChange(fieldname);
await this.parentdoc._applyChange(this.parentfield as string); await this.parentdoc._applyChange(this.parentFieldname as string);
} else { } else {
await this._applyChange(fieldname); await this._applyChange(fieldname);
} }
@ -196,23 +197,20 @@ export class Doc extends Observable<DocValue | Doc[]> {
_setDefaults() { _setDefaults() {
for (const field of this.schema.fields) { for (const field of this.schema.fields) {
if (!getIsNullOrUndef(this[field.fieldname])) {
continue;
}
let defaultValue: DocValue | Doc[] = getPreDefaultValues( let defaultValue: DocValue | Doc[] = getPreDefaultValues(
field.fieldtype, field.fieldtype,
this.fyo this.fyo
); );
const defaultFunction = this.defaults[field.fieldname];
const defaultFunction =
this.fyo.models[this.schemaName]?.defaults?.[field.fieldname];
if (defaultFunction !== undefined) { if (defaultFunction !== undefined) {
defaultValue = defaultFunction(); defaultValue = defaultFunction();
} else if (field.default !== undefined) { } else if (field.default !== undefined) {
defaultValue = field.default; defaultValue = field.default;
} }
if (field.fieldtype === 'Currency' && !isPesa(defaultValue)) { if (field.fieldtype === FieldTypeEnum.Currency && !isPesa(defaultValue)) {
defaultValue = this.fyo.pesa!(defaultValue as string | number); defaultValue = this.fyo.pesa!(defaultValue as string | number);
} }
@ -242,8 +240,8 @@ export class Doc extends Observable<DocValue | Doc[]> {
const data: Record<string, unknown> = Object.assign({}, docValueMap); const data: Record<string, unknown> = Object.assign({}, docValueMap);
data.parent = this.name; data.parent = this.name;
data.parenttype = this.schemaName; data.parentSchemaName = this.schemaName;
data.parentfield = fieldname; data.parentFieldname = fieldname;
data.parentdoc = this; data.parentdoc = this;
if (!data.idx) { if (!data.idx) {
@ -329,6 +327,10 @@ export class Doc extends Observable<DocValue | Doc[]> {
value = (value as Money).copy(); value = (value as Money).copy();
} }
if (value === null && this.schema.isSingle) {
continue;
}
data[field.fieldname] = value; data[field.fieldname] = value;
} }
return data; return data;
@ -348,10 +350,10 @@ export class Doc extends Observable<DocValue | Doc[]> {
this.created = new Date(); this.created = new Date();
} }
this._updateModified(); this._updateModifiedMetaValues();
} }
_updateModified() { _updateModifiedMetaValues() {
this.modifiedBy = this.fyo.auth.session.user || DEFAULT_USER; this.modifiedBy = this.fyo.auth.session.user || DEFAULT_USER;
this.modified = new Date(); this.modified = new Date();
} }
@ -442,20 +444,19 @@ export class Doc extends Observable<DocValue | Doc[]> {
} }
async _compareWithCurrentDoc() { async _compareWithCurrentDoc() {
if (this.isNew || !this.name) { if (this.isNew || !this.name || this.schema.isSingle) {
return; return;
} }
const currentDoc = await this.fyo.db.get(this.schemaName, this.name); const dbValues = await this.fyo.db.get(this.schemaName, this.name);
const docModified = this.modified as Date;
const dbModified = dbValues.modified as Date;
// check for conflict if (dbValues && docModified !== dbModified) {
if ( throw new ConflictError(
currentDoc &&
(this.modified as Date) !== (currentDoc.modified as Date)
) {
throw new Conflict(
this.fyo this.fyo
.t`Document ${this.schemaName} ${this.name} has been modified after loading` .t`Document ${this.schemaName} ${this.name} has been modified after loading` +
`${docModified?.toISOString()}, ${dbModified?.toISOString()}`
); );
} }
@ -466,11 +467,11 @@ export class Doc extends Observable<DocValue | Doc[]> {
} }
// set submit action flag // set submit action flag
if (this.submitted && !currentDoc.submitted) { if (this.submitted && !dbValues.submitted) {
this.flags.submitAction = true; this.flags.submitAction = true;
} }
if (currentDoc.submitted && !this.submitted) { if (dbValues.submitted && !this.submitted) {
this.flags.revertAction = true; this.flags.revertAction = true;
} }
} }
@ -568,15 +569,16 @@ export class Doc extends Observable<DocValue | Doc[]> {
await this.trigger('beforeInsert', null); await this.trigger('beforeInsert', null);
const oldName = this.name!; const oldName = this.name!;
const data = await this.fyo.db.insert(this.schemaName, this.getValidDict()); const validDict = this.getValidDict();
const data = await this.fyo.db.insert(this.schemaName, validDict);
this.syncValues(data); this.syncValues(data);
this._notInserted = false;
if (oldName !== this.name) { if (oldName !== this.name) {
this.fyo.doc.removeFromCache(this.schemaName, oldName); this.fyo.doc.removeFromCache(this.schemaName, oldName);
} }
await this.trigger('afterInsert', null); await this.trigger('afterInsert', null);
await this.trigger('afterSave', null);
this.fyo.telemetry.log(Verb.Created, this.schemaName); this.fyo.telemetry.log(Verb.Created, this.schemaName);
return this; return this;
@ -592,14 +594,13 @@ export class Doc extends Observable<DocValue | Doc[]> {
if (this.flags.revertAction) await this.trigger('beforeRevert'); if (this.flags.revertAction) await this.trigger('beforeRevert');
// update modifiedBy and modified // update modifiedBy and modified
this._updateModified(); this._updateModifiedMetaValues();
const data = this.getValidDict(); const data = this.getValidDict();
await this.fyo.db.update(this.schemaName, data); await this.fyo.db.update(this.schemaName, data);
this.syncValues(data); this.syncValues(data);
await this.trigger('afterUpdate'); await this.trigger('afterUpdate');
await this.trigger('afterSave');
// after submit // after submit
if (this.flags.submitAction) await this.trigger('afterSubmit'); if (this.flags.submitAction) await this.trigger('afterSubmit');
@ -609,11 +610,15 @@ export class Doc extends Observable<DocValue | Doc[]> {
} }
async sync() { async sync() {
await this.trigger('beforeSync');
let doc;
if (this._notInserted) { if (this._notInserted) {
return await this._insert(); doc = await this._insert();
} else { } else {
return await this._update(); doc = await this._update();
} }
await this.trigger('afterSync');
return doc;
} }
async delete() { async delete() {
@ -738,14 +743,14 @@ export class Doc extends Observable<DocValue | Doc[]> {
async afterInsert() {} async afterInsert() {}
async beforeUpdate() {} async beforeUpdate() {}
async afterUpdate() {} async afterUpdate() {}
async afterSave() {} async beforeSync() {}
async afterSync() {}
async beforeDelete() {} async beforeDelete() {}
async afterDelete() {} async afterDelete() {}
async beforeRevert() {} async beforeRevert() {}
async afterRevert() {} async afterRevert() {}
formulas: FormulaMap = {}; formulas: FormulaMap = {};
defaults: DefaultMap = {};
validations: ValidationMap = {}; validations: ValidationMap = {};
required: RequiredMap = {}; required: RequiredMap = {};
hidden: HiddenMap = {}; hidden: HiddenMap = {};
@ -755,6 +760,7 @@ export class Doc extends Observable<DocValue | Doc[]> {
static lists: ListsMap = {}; static lists: ListsMap = {};
static filters: FiltersMap = {}; static filters: FiltersMap = {};
static defaults: DefaultMap = {};
static emptyMessages: EmptyMessageMap = {}; static emptyMessages: EmptyMessageMap = {};
static getListViewSettings(fyo: Fyo): ListViewSettings { static getListViewSettings(fyo: Fyo): ListViewSettings {

View File

@ -56,11 +56,11 @@ export function getMissingMandatoryMessage(doc: Doc) {
return isNullOrUndef || value === ''; return isNullOrUndef || value === '';
}) })
.map((f) => f.label) .map((f) => f.label ?? f.fieldname)
.join(', '); .join(', ');
if (message && doc.schema.isChild && doc.parentdoc && doc.parentfield) { if (message && doc.schema.isChild && doc.parentdoc && doc.parentFieldname) {
const parentfield = doc.parentdoc.fieldMap[doc.parentfield]; const parentfield = doc.parentdoc.fieldMap[doc.parentFieldname];
return `${parentfield.label} Row ${(doc.idx ?? 0) + 1}: ${message}`; return `${parentfield.label} Row ${(doc.idx ?? 0) + 1}: ${message}`;
} }
@ -75,11 +75,7 @@ function getMandatory(doc: Doc): Field[] {
} }
const requiredFunction = doc.required[field.fieldname]; const requiredFunction = doc.required[field.fieldname];
if (typeof requiredFunction !== 'function') { if (requiredFunction?.()) {
continue;
}
if (requiredFunction()) {
mandatoryFields.push(field); mandatoryFields.push(field);
} }
} }

View File

@ -67,5 +67,5 @@ export class CannotCommitError extends DatabaseError {
} }
export class ValueError extends ValidationError {} export class ValueError extends ValidationError {}
export class Conflict extends ValidationError {} export class ConflictError extends ValidationError {}
export class InvalidFieldError extends ValidationError {} export class InvalidFieldError extends ValidationError {}

View File

@ -1,6 +1,7 @@
import { Fyo } from 'fyo'; import { Fyo } from 'fyo';
import { Doc } from 'fyo/model/doc'; import { Doc } from 'fyo/model/doc';
import { import {
DefaultMap,
FiltersMap, FiltersMap,
ListViewSettings, ListViewSettings,
TreeViewSettings, TreeViewSettings,
@ -13,6 +14,16 @@ export class Account extends Doc {
accountType?: AccountType; accountType?: AccountType;
parentAccount?: string; parentAccount?: string;
static defaults: DefaultMap = {
/**
* NestedSet indices are actually not used
* this needs updation as they may be required
* later on.
*/
lft: () => 0,
rgt: () => 0,
};
async beforeInsert() { async beforeInsert() {
if (this.accountType || !this.parentAccount) { if (this.accountType || !this.parentAccount) {
return; return;

View File

@ -188,7 +188,7 @@ export abstract class Invoice extends Doc {
}, },
}; };
defaults: DefaultMap = { static defaults: DefaultMap = {
date: () => new Date().toISOString().slice(0, 10), date: () => new Date().toISOString().slice(0, 10),
}; };

View File

@ -48,7 +48,7 @@ export class JournalEntry extends Doc {
await this.getPosting().postReverse(); await this.getPosting().postReverse();
} }
defaults: DefaultMap = { static defaults: DefaultMap = {
date: () => DateTime.local().toISODate(), date: () => DateTime.local().toISODate(),
}; };

View File

@ -281,7 +281,7 @@ export class Payment extends Doc {
); );
} }
defaults: DefaultMap = { date: () => new Date().toISOString() }; static defaults: DefaultMap = { date: () => new Date().toISOString() };
formulas: FormulaMap = { formulas: FormulaMap = {
account: async () => { account: async () => {

View File

@ -16,7 +16,7 @@
"postinstall": "electron-builder install-app-deps", "postinstall": "electron-builder install-app-deps",
"postuninstall": "electron-builder install-app-deps", "postuninstall": "electron-builder install-app-deps",
"script:translate": "ts-node -O '{\"module\":\"commonjs\"}' scripts/generateTranslations.ts", "script:translate": "ts-node -O '{\"module\":\"commonjs\"}' scripts/generateTranslations.ts",
"test": "TS_NODE_COMPILER_OPTIONS='{\"module\":\"commonjs\"}' mocha --reporter nyan --require ts-node/register --require tsconfig-paths/register ./**/tests/**/*.spec.ts" "test": "TS_NODE_COMPILER_OPTIONS='{\"module\":\"commonjs\"}' mocha --reporter nyan --require ts-node/register --require tsconfig-paths/register ./**/tests/**/*.spec.ts --exit"
}, },
"dependencies": { "dependencies": {
"@popperjs/core": "^2.10.2", "@popperjs/core": "^2.10.2",
@ -52,6 +52,7 @@
"@vue/eslint-config-typescript": "^7.0.0", "@vue/eslint-config-typescript": "^7.0.0",
"autoprefixer": "^9", "autoprefixer": "^9",
"babel-loader": "^8.2.3", "babel-loader": "^8.2.3",
"dotenv": "^16.0.0",
"electron": "^15.3.5", "electron": "^15.3.5",
"electron-devtools-installer": "^3.2.0", "electron-devtools-installer": "^3.2.0",
"electron-notarize": "^1.1.1", "electron-notarize": "^1.1.1",

View File

@ -6,7 +6,7 @@
"isSubmittable": false, "isSubmittable": false,
"fields": [ "fields": [
{ {
"fieldname": "companyLogo", "fieldname": "logo",
"label": "Company Logo", "label": "Company Logo",
"fieldtype": "AttachImage" "fieldtype": "AttachImage"
}, },

View File

@ -78,6 +78,7 @@
"fieldname": "countryCode", "fieldname": "countryCode",
"label": "Country Code", "label": "Country Code",
"fieldtype": "Data", "fieldtype": "Data",
"default": "in",
"description": "Country code used to initialize regional settings." "description": "Country code used to initialize regional settings."
}, },
{ {

View File

@ -14,7 +14,6 @@ export enum FieldTypeEnum {
Currency = 'Currency', Currency = 'Currency',
Text = 'Text', Text = 'Text',
Color = 'Color', Color = 'Color',
Code = 'Code',
} }
export type FieldType = keyof typeof FieldTypeEnum; export type FieldType = keyof typeof FieldTypeEnum;

View File

@ -45,9 +45,9 @@
<div v-if="doc"> <div v-if="doc">
<div class="flex items-center px-6 py-5 mb-8 bg-brand rounded-xl"> <div class="flex items-center px-6 py-5 mb-8 bg-brand rounded-xl">
<FormControl <FormControl
:df="getField('companyLogo')" :df="getField('logo')"
:value="doc.companyLogo" :value="doc.logo"
@change="(value) => setValue('companyLogo', value)" @change="(value) => setValue('logo', value)"
/> />
<div class="ml-2"> <div class="ml-2">
<FormControl <FormControl

View File

@ -70,15 +70,15 @@ async function updateAccountingSettings(
} }
async function updatePrintSettings( async function updatePrintSettings(
{ companyLogo, companyName, email }: SetupWizardOptions, { logo, companyName, email }: SetupWizardOptions,
fyo: Fyo fyo: Fyo
) { ) {
const printSettings = await fyo.doc.getSingle('PrintSettings'); const printSettings = await fyo.doc.getSingle('PrintSettings');
await printSettings.setAndSync({ await printSettings.setAndSync({
logo: companyLogo, logo,
companyName, companyName,
email, email,
displayLogo: companyLogo ? true : false, displayLogo: logo ? true : false,
}); });
} }
@ -91,10 +91,13 @@ async function updateSystemSettings(
const currency = const currency =
companyCurrency ?? countryOptions.currency ?? DEFAULT_CURRENCY; companyCurrency ?? countryOptions.currency ?? DEFAULT_CURRENCY;
const locale = countryOptions.locale ?? DEFAULT_LOCALE; const locale = countryOptions.locale ?? DEFAULT_LOCALE;
const countryCode = getCountryCodeFromCountry(country);
const systemSettings = await fyo.doc.getSingle('SystemSettings'); const systemSettings = await fyo.doc.getSingle('SystemSettings');
systemSettings.setAndSync({ systemSettings.setAndSync({
locale, locale,
currency, currency,
countryCode,
}); });
} }
@ -154,8 +157,7 @@ async function createAccountRecords(
async function completeSetup(companyName: string, fyo: Fyo) { async function completeSetup(companyName: string, fyo: Fyo) {
updateInitializationConfig(companyName, fyo); updateInitializationConfig(companyName, fyo);
await fyo.singles.AccountingSettings!.set('setupComplete', true); await fyo.singles.AccountingSettings!.setAndSync('setupComplete', true);
await fyo.singles.AccountingSettings!.sync();
} }
function updateInitializationConfig(companyName: string, fyo: Fyo) { function updateInitializationConfig(companyName: string, fyo: Fyo) {

View File

@ -1,5 +1,5 @@
export interface SetupWizardOptions { export interface SetupWizardOptions {
companyLogo: string; logo: string | null;
companyName: string; companyName: string;
country: string; country: string;
fullname: string; fullname: string;

View File

@ -1,9 +1,10 @@
import { config } from 'dotenv';
import { SetupWizardOptions } from 'src/setup/types'; import { SetupWizardOptions } from 'src/setup/types';
import { getFiscalYear } from 'utils/misc'; import { getFiscalYear } from 'utils/misc';
export function getTestSetupWizardOptions(): SetupWizardOptions { export function getTestSetupWizardOptions(): SetupWizardOptions {
return { return {
companyLogo: '', logo: null,
companyName: 'Test Company', companyName: 'Test Company',
country: 'India', country: 'India',
fullname: 'Test Person', fullname: 'Test Person',
@ -15,3 +16,8 @@ export function getTestSetupWizardOptions(): SetupWizardOptions {
chartOfAccounts: 'India - Chart of Accounts', chartOfAccounts: 'India - Chart of Accounts',
}; };
} }
export function getTestDbPath() {
config();
return process.env.TEST_DB_PATH ?? ':memory:';
}

View File

@ -1,25 +1,74 @@
import * as assert from 'assert';
import { DatabaseManager } from 'backend/database/manager'; import { DatabaseManager } from 'backend/database/manager';
import { assertDoesNotThrow } from 'backend/database/tests/helpers'; import { assertDoesNotThrow } from 'backend/database/tests/helpers';
import { Fyo } from 'fyo'; import { Fyo } from 'fyo';
import { DummyAuthDemux } from 'fyo/tests/helpers'; import { DummyAuthDemux } from 'fyo/tests/helpers';
import 'mocha'; import 'mocha';
import setupInstance from 'src/setup/setupInstance'; import setupInstance from 'src/setup/setupInstance';
import { getTestSetupWizardOptions } from './helpers'; import { SetupWizardOptions } from 'src/setup/types';
import { getValueMapFromList } from 'utils';
import { getTestDbPath, getTestSetupWizardOptions } from './helpers';
const DB_PATH = '/Users/alan/Desktop/test.db';
describe('setupInstance', function () { describe('setupInstance', function () {
const fyo = new Fyo({ const dbPath = getTestDbPath();
const setupOptions = getTestSetupWizardOptions();
let fyo: Fyo;
this.beforeAll(function () {
fyo = new Fyo({
DatabaseDemux: DatabaseManager, DatabaseDemux: DatabaseManager,
AuthDemux: DummyAuthDemux, AuthDemux: DummyAuthDemux,
isTest: true, isTest: true,
isElectron: false, isElectron: false,
}); });
});
this.afterAll(async function () {
await fyo.close();
});
const setupOptions = getTestSetupWizardOptions();
specify('setupInstance', async function () { specify('setupInstance', async function () {
await setupInstance(DB_PATH, setupOptions, fyo);
await assertDoesNotThrow(async () => { await assertDoesNotThrow(async () => {
// await setupInstance(':memory:', setupOptions, fyo); await setupInstance(dbPath, setupOptions, fyo);
}, 'setup instance failed'); }, 'setup instance failed');
}); });
specify('check setup Singles', async function () {
const setupFields = [
'companyName',
'country',
'fullname',
'email',
'bankName',
'fiscalYearStart',
'fiscalYearEnd',
'currency',
];
const setupSingles = await fyo.db.getSingleValues(...setupFields);
const singlesMap = getValueMapFromList(setupSingles, 'fieldname', 'value');
for (const field of setupFields) {
let dbValue = singlesMap[field];
const optionsValue = setupOptions[field as keyof SetupWizardOptions];
if (dbValue instanceof Date) {
dbValue = dbValue.toISOString().split('T')[0];
}
assert.strictEqual(dbValue as string, optionsValue, `${field} mismatch`);
}
});
specify('check null singles', async function () {
const nullFields = ['gstin', 'logo', 'phone', 'address'];
const nullSingles = await fyo.db.getSingleValues(...nullFields);
assert.strictEqual(
nullSingles.length,
0,
`null singles found ${JSON.stringify(nullSingles)}`
);
});
}); });

View File

@ -4680,6 +4680,11 @@ dotenv-expand@^5.1.0:
resolved "https://registry.yarnpkg.com/dotenv-expand/-/dotenv-expand-5.1.0.tgz#3fbaf020bfd794884072ea26b1e9791d45a629f0" resolved "https://registry.yarnpkg.com/dotenv-expand/-/dotenv-expand-5.1.0.tgz#3fbaf020bfd794884072ea26b1e9791d45a629f0"
integrity sha512-YXQl1DSa4/PQyRfgrv6aoNjhasp/p4qs9FjJ4q4cQk+8m4r6k4ZSiEyytKG8f8W9gi8WsQtIObNmKd+tMzNTmA== integrity sha512-YXQl1DSa4/PQyRfgrv6aoNjhasp/p4qs9FjJ4q4cQk+8m4r6k4ZSiEyytKG8f8W9gi8WsQtIObNmKd+tMzNTmA==
dotenv@^16.0.0:
version "16.0.0"
resolved "https://registry.yarnpkg.com/dotenv/-/dotenv-16.0.0.tgz#c619001253be89ebb638d027b609c75c26e47411"
integrity sha512-qD9WU0MPM4SWLPJy/r2Be+2WgQj8plChsyrCNQzW/0WjvcJQiKQJ9mH3ZgB3fxbUUxgc/11ZJ0Fi5KiimWGz2Q==
dotenv@^8.2.0: dotenv@^8.2.0:
version "8.6.0" version "8.6.0"
resolved "https://registry.yarnpkg.com/dotenv/-/dotenv-8.6.0.tgz#061af664d19f7f4d8fc6e4ff9b584ce237adcb8b" resolved "https://registry.yarnpkg.com/dotenv/-/dotenv-8.6.0.tgz#061af664d19f7f4d8fc6e4ff9b584ce237adcb8b"