Merge pull request #434 from 18alantom/minor-fixes-three
Minor fixes three
BIN
.github/frappe-books-preview.png
vendored
Before Width: | Height: | Size: 264 KiB After Width: | Height: | Size: 145 KiB |
BIN
.github/logo.png
vendored
Before Width: | Height: | Size: 2.4 KiB After Width: | Height: | Size: 7.3 KiB |
@ -2,7 +2,7 @@ import {
|
|||||||
CannotCommitError,
|
CannotCommitError,
|
||||||
getDbError,
|
getDbError,
|
||||||
NotFoundError,
|
NotFoundError,
|
||||||
ValueError
|
ValueError,
|
||||||
} from 'fyo/utils/errors';
|
} from 'fyo/utils/errors';
|
||||||
import { knex, Knex } from 'knex';
|
import { knex, Knex } from 'knex';
|
||||||
import {
|
import {
|
||||||
@ -11,12 +11,12 @@ import {
|
|||||||
RawValue,
|
RawValue,
|
||||||
Schema,
|
Schema,
|
||||||
SchemaMap,
|
SchemaMap,
|
||||||
TargetField
|
TargetField,
|
||||||
} from '../../schemas/types';
|
} from '../../schemas/types';
|
||||||
import {
|
import {
|
||||||
getIsNullOrUndef,
|
getIsNullOrUndef,
|
||||||
getRandomString,
|
getRandomString,
|
||||||
getValueMapFromList
|
getValueMapFromList,
|
||||||
} from '../../utils';
|
} from '../../utils';
|
||||||
import { DatabaseBase, GetAllOptions, QueryFilter } from '../../utils/db/types';
|
import { DatabaseBase, GetAllOptions, QueryFilter } from '../../utils/db/types';
|
||||||
import { getDefaultMetaFieldValueMap, sqliteTypeMap, SYSTEM } from '../helpers';
|
import { getDefaultMetaFieldValueMap, sqliteTypeMap, SYSTEM } from '../helpers';
|
||||||
@ -24,7 +24,7 @@ import {
|
|||||||
ColumnDiff,
|
ColumnDiff,
|
||||||
FieldValueMap,
|
FieldValueMap,
|
||||||
GetQueryBuilderOptions,
|
GetQueryBuilderOptions,
|
||||||
SingleValue
|
SingleValue,
|
||||||
} from './types';
|
} from './types';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
BIN
build/icon.icns
BIN
build/icon.ico
Before Width: | Height: | Size: 8.5 KiB After Width: | Height: | Size: 3.9 KiB |
BIN
build/icon.png
Before Width: | Height: | Size: 21 KiB After Width: | Height: | Size: 55 KiB |
Before Width: | Height: | Size: 1.4 KiB After Width: | Height: | Size: 2.7 KiB |
Before Width: | Height: | Size: 295 B After Width: | Height: | Size: 383 B |
Before Width: | Height: | Size: 2.4 KiB After Width: | Height: | Size: 5.3 KiB |
Before Width: | Height: | Size: 555 B After Width: | Height: | Size: 665 B |
Before Width: | Height: | Size: 802 B After Width: | Height: | Size: 1.1 KiB |
Before Width: | Height: | Size: 4.4 KiB After Width: | Height: | Size: 11 KiB |
Before Width: | Height: | Size: 941 B After Width: | Height: | Size: 1.3 KiB |
Before Width: | Height: | Size: 8.5 KiB After Width: | Height: | Size: 3.9 KiB |
Before Width: | Height: | Size: 9.2 KiB After Width: | Height: | Size: 4.5 KiB |
@ -29,7 +29,7 @@ export async function setupDummyInstance(
|
|||||||
baseCount: number = 1000,
|
baseCount: number = 1000,
|
||||||
notifier?: Notifier
|
notifier?: Notifier
|
||||||
) {
|
) {
|
||||||
fyo.purgeCache();
|
await fyo.purgeCache();
|
||||||
notifier?.(fyo.t`Setting Up Instance`, -1);
|
notifier?.(fyo.t`Setting Up Instance`, -1);
|
||||||
const options = {
|
const options = {
|
||||||
logo: null,
|
logo: null,
|
||||||
|
@ -107,7 +107,7 @@ export class AuthHandler {
|
|||||||
// TODO: Implement this with auth flow
|
// TODO: Implement this with auth flow
|
||||||
}
|
}
|
||||||
|
|
||||||
purgeCache() {}
|
async purgeCache() {}
|
||||||
|
|
||||||
#getServerURL() {
|
#getServerURL() {
|
||||||
return this.#config.serverURL || '';
|
return this.#config.serverURL || '';
|
||||||
|
@ -85,7 +85,8 @@ export class DatabaseHandler extends DatabaseBase {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
purgeCache() {
|
async purgeCache() {
|
||||||
|
await this.close();
|
||||||
this.dbPath = undefined;
|
this.dbPath = undefined;
|
||||||
this.#schemaMap = {};
|
this.#schemaMap = {};
|
||||||
this.fieldValueMap = {};
|
this.fieldValueMap = {};
|
||||||
@ -214,7 +215,6 @@ export class DatabaseHandler extends DatabaseBase {
|
|||||||
|
|
||||||
async close(): Promise<void> {
|
async close(): Promise<void> {
|
||||||
await this.#demux.call('close');
|
await this.#demux.call('close');
|
||||||
this.purgeCache();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -26,7 +26,7 @@ export class DocHandler {
|
|||||||
this.observer = new Observable();
|
this.observer = new Observable();
|
||||||
}
|
}
|
||||||
|
|
||||||
purgeCache() {
|
async purgeCache() {
|
||||||
this.init();
|
this.init();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2,7 +2,7 @@ import { ipcRenderer } from 'electron';
|
|||||||
import { DatabaseError, NotImplemented } from 'fyo/utils/errors';
|
import { DatabaseError, NotImplemented } from 'fyo/utils/errors';
|
||||||
import { SchemaMap } from 'schemas/types';
|
import { SchemaMap } from 'schemas/types';
|
||||||
import { DatabaseDemuxBase, DatabaseMethod } from 'utils/db/types';
|
import { DatabaseDemuxBase, DatabaseMethod } from 'utils/db/types';
|
||||||
import { DatabaseResponse } from 'utils/ipc/types';
|
import { BackendResponse } from 'utils/ipc/types';
|
||||||
import { IPC_ACTIONS } from 'utils/messages';
|
import { IPC_ACTIONS } from 'utils/messages';
|
||||||
|
|
||||||
export class DatabaseDemux extends DatabaseDemuxBase {
|
export class DatabaseDemux extends DatabaseDemuxBase {
|
||||||
@ -12,7 +12,7 @@ export class DatabaseDemux extends DatabaseDemuxBase {
|
|||||||
this.#isElectron = isElectron;
|
this.#isElectron = isElectron;
|
||||||
}
|
}
|
||||||
|
|
||||||
async #handleDBCall(func: () => Promise<DatabaseResponse>): Promise<unknown> {
|
async #handleDBCall(func: () => Promise<BackendResponse>): Promise<unknown> {
|
||||||
const response = await func();
|
const response = await func();
|
||||||
|
|
||||||
if (response.error?.name) {
|
if (response.error?.name) {
|
||||||
|
@ -202,7 +202,7 @@ export class Fyo {
|
|||||||
return value;
|
return value;
|
||||||
}
|
}
|
||||||
|
|
||||||
purgeCache() {
|
async purgeCache() {
|
||||||
this.pesa = getMoneyMaker({
|
this.pesa = getMoneyMaker({
|
||||||
currency: DEFAULT_CURRENCY,
|
currency: DEFAULT_CURRENCY,
|
||||||
precision: DEFAULT_INTERNAL_PRECISION,
|
precision: DEFAULT_INTERNAL_PRECISION,
|
||||||
@ -216,9 +216,9 @@ export class Fyo {
|
|||||||
this.currencySymbols = {};
|
this.currencySymbols = {};
|
||||||
this.errorLog = [];
|
this.errorLog = [];
|
||||||
this.temp = {};
|
this.temp = {};
|
||||||
this.db.purgeCache();
|
await this.db.purgeCache();
|
||||||
this.auth.purgeCache();
|
await this.auth.purgeCache();
|
||||||
this.doc.purgeCache();
|
await this.doc.purgeCache();
|
||||||
}
|
}
|
||||||
|
|
||||||
store = {
|
store = {
|
||||||
|
@ -126,6 +126,30 @@ export class Doc extends Observable<DocValue | Doc[]> {
|
|||||||
return this._syncing;
|
return this._syncing;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
get canDelete() {
|
||||||
|
if (this.notInserted) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this.schema.isSingle) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!this.schema.isSubmittable) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this.schema.isSubmittable && this.isCancelled) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this.schema.isSubmittable && !this.isSubmitted) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
_setValuesWithoutChecks(data: DocValueMap) {
|
_setValuesWithoutChecks(data: DocValueMap) {
|
||||||
for (const field of this.schema.fields) {
|
for (const field of this.schema.fields) {
|
||||||
const fieldname = field.fieldname;
|
const fieldname = field.fieldname;
|
||||||
@ -694,7 +718,7 @@ export class Doc extends Observable<DocValue | Doc[]> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async delete() {
|
async delete() {
|
||||||
if (this.schema.isSubmittable && !this.isCancelled) {
|
if (!this.canDelete) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -34,7 +34,7 @@ describe('Fyo Init', function () {
|
|||||||
true,
|
true,
|
||||||
'non zero schemas'
|
'non zero schemas'
|
||||||
);
|
);
|
||||||
await fyo.db.close();
|
await fyo.db.purgeCache();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -1,74 +1,76 @@
|
|||||||
export class BaseError extends Error {
|
export class BaseError extends Error {
|
||||||
message: string;
|
message: string;
|
||||||
statusCode: number;
|
statusCode: number;
|
||||||
|
shouldStore: boolean;
|
||||||
|
|
||||||
constructor(statusCode: number, message: string) {
|
constructor(statusCode: number, message: string, shouldStore: boolean = true) {
|
||||||
super(message);
|
super(message);
|
||||||
this.name = 'BaseError';
|
this.name = 'BaseError';
|
||||||
this.statusCode = statusCode;
|
this.statusCode = statusCode;
|
||||||
this.message = message;
|
this.message = message;
|
||||||
|
this.shouldStore = shouldStore;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export class ValidationError extends BaseError {
|
export class ValidationError extends BaseError {
|
||||||
constructor(message: string) {
|
constructor(message: string, shouldStore: boolean = false) {
|
||||||
super(417, message);
|
super(417, message, shouldStore);
|
||||||
this.name = 'ValidationError';
|
this.name = 'ValidationError';
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export class NotFoundError extends BaseError {
|
export class NotFoundError extends BaseError {
|
||||||
constructor(message: string) {
|
constructor(message: string, shouldStore: boolean = true) {
|
||||||
super(404, message);
|
super(404, message, shouldStore);
|
||||||
this.name = 'NotFoundError';
|
this.name = 'NotFoundError';
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export class ForbiddenError extends BaseError {
|
export class ForbiddenError extends BaseError {
|
||||||
constructor(message: string) {
|
constructor(message: string, shouldStore: boolean = true) {
|
||||||
super(403, message);
|
super(403, message, shouldStore);
|
||||||
this.name = 'ForbiddenError';
|
this.name = 'ForbiddenError';
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export class DuplicateEntryError extends ValidationError {
|
export class DuplicateEntryError extends ValidationError {
|
||||||
constructor(message: string) {
|
constructor(message: string, shouldStore: boolean = false) {
|
||||||
super(message);
|
super(message, shouldStore);
|
||||||
this.name = 'DuplicateEntryError';
|
this.name = 'DuplicateEntryError';
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export class LinkValidationError extends ValidationError {
|
export class LinkValidationError extends ValidationError {
|
||||||
constructor(message: string) {
|
constructor(message: string, shouldStore: boolean = false) {
|
||||||
super(message);
|
super(message, shouldStore);
|
||||||
this.name = 'LinkValidationError';
|
this.name = 'LinkValidationError';
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export class MandatoryError extends ValidationError {
|
export class MandatoryError extends ValidationError {
|
||||||
constructor(message: string) {
|
constructor(message: string, shouldStore: boolean = false) {
|
||||||
super(message);
|
super(message, shouldStore);
|
||||||
this.name = 'MandatoryError';
|
this.name = 'MandatoryError';
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export class DatabaseError extends BaseError {
|
export class DatabaseError extends BaseError {
|
||||||
constructor(message: string) {
|
constructor(message: string, shouldStore: boolean = true) {
|
||||||
super(500, message);
|
super(500, message, shouldStore);
|
||||||
this.name = 'DatabaseError';
|
this.name = 'DatabaseError';
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export class CannotCommitError extends DatabaseError {
|
export class CannotCommitError extends DatabaseError {
|
||||||
constructor(message: string) {
|
constructor(message: string, shouldStore: boolean = true) {
|
||||||
super(message);
|
super(message, shouldStore);
|
||||||
this.name = 'CannotCommitError';
|
this.name = 'CannotCommitError';
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export class NotImplemented extends BaseError {
|
export class NotImplemented extends BaseError {
|
||||||
constructor() {
|
constructor(message: string = '', shouldStore: boolean = false) {
|
||||||
super(501, '');
|
super(501, message, shouldStore);
|
||||||
this.name = 'NotImplemented';
|
this.name = 'NotImplemented';
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -3,7 +3,7 @@ import fs from 'fs/promises';
|
|||||||
import { ConfigFile, ConfigKeys } from 'fyo/core/types';
|
import { ConfigFile, ConfigKeys } from 'fyo/core/types';
|
||||||
import { Main } from 'main';
|
import { Main } from 'main';
|
||||||
import config from 'utils/config';
|
import config from 'utils/config';
|
||||||
import { DatabaseResponse } from 'utils/ipc/types';
|
import { BackendResponse } from 'utils/ipc/types';
|
||||||
import { IPC_CHANNELS } from 'utils/messages';
|
import { IPC_CHANNELS } from 'utils/messages';
|
||||||
|
|
||||||
interface ConfigFilesWithModified extends ConfigFile {
|
interface ConfigFilesWithModified extends ConfigFile {
|
||||||
@ -54,15 +54,16 @@ export async function getConfigFilesWithModified(files: ConfigFile[]) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export async function getErrorHandledReponse(func: () => Promise<unknown>) {
|
export async function getErrorHandledReponse(func: () => Promise<unknown>) {
|
||||||
const response: DatabaseResponse = {};
|
const response: BackendResponse = {};
|
||||||
|
|
||||||
try {
|
try {
|
||||||
response.data = await func();
|
response.data = await func();
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
response.error = {
|
response.error = {
|
||||||
name: (err as Error).name,
|
name: (err as NodeJS.ErrnoException).name,
|
||||||
message: (err as Error).message,
|
message: (err as NodeJS.ErrnoException).message,
|
||||||
stack: (err as Error).stack,
|
stack: (err as NodeJS.ErrnoException).stack,
|
||||||
|
code: (err as NodeJS.ErrnoException).code,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -139,7 +139,7 @@ export default function registerIpcMainActionListeners(main: Main) {
|
|||||||
});
|
});
|
||||||
|
|
||||||
ipcMain.handle(IPC_ACTIONS.DELETE_FILE, async (_, filePath) => {
|
ipcMain.handle(IPC_ACTIONS.DELETE_FILE, async (_, filePath) => {
|
||||||
await fs.unlink(filePath);
|
return getErrorHandledReponse(async () => await fs.unlink(filePath));
|
||||||
});
|
});
|
||||||
|
|
||||||
ipcMain.handle(IPC_ACTIONS.GET_DB_LIST, async (_) => {
|
ipcMain.handle(IPC_ACTIONS.GET_DB_LIST, async (_) => {
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
import { Fyo, t } from 'fyo';
|
import { Fyo, t } from 'fyo';
|
||||||
import { ValidationError } from 'fyo/utils/errors';
|
import { NotFoundError, ValidationError } from 'fyo/utils/errors';
|
||||||
import { Account } from 'models/baseModels/Account/Account';
|
import { Account } from 'models/baseModels/Account/Account';
|
||||||
import { AccountingLedgerEntry } from 'models/baseModels/AccountingLedgerEntry/AccountingLedgerEntry';
|
import { AccountingLedgerEntry } from 'models/baseModels/AccountingLedgerEntry/AccountingLedgerEntry';
|
||||||
import { ModelNameEnum } from 'models/types';
|
import { ModelNameEnum } from 'models/types';
|
||||||
@ -210,9 +210,20 @@ export class LedgerPosting {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async _getRoundOffAccount() {
|
async _getRoundOffAccount() {
|
||||||
return (await this.fyo.getValue(
|
const roundOffAccount = (await this.fyo.getValue(
|
||||||
ModelNameEnum.AccountingSettings,
|
ModelNameEnum.AccountingSettings,
|
||||||
'roundOffAccount'
|
'roundOffAccount'
|
||||||
)) as string;
|
)) as string;
|
||||||
|
|
||||||
|
if (!roundOffAccount) {
|
||||||
|
const notFoundError = new NotFoundError(
|
||||||
|
t`Please set Round Off Account in the Settings.`,
|
||||||
|
false
|
||||||
|
);
|
||||||
|
notFoundError.name = t`Round Off Account Not Found`;
|
||||||
|
throw notFoundError;
|
||||||
|
}
|
||||||
|
|
||||||
|
return roundOffAccount;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -91,7 +91,8 @@
|
|||||||
"fieldname": "outstandingAmount",
|
"fieldname": "outstandingAmount",
|
||||||
"label": "Outstanding Amount",
|
"label": "Outstanding Amount",
|
||||||
"fieldtype": "Currency",
|
"fieldtype": "Currency",
|
||||||
"readOnly": true
|
"readOnly": true,
|
||||||
|
"filter": true
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"fieldname": "setDiscountAmount",
|
"fieldname": "setDiscountAmount",
|
||||||
|
@ -90,7 +90,8 @@
|
|||||||
"fieldname": "outstandingAmount",
|
"fieldname": "outstandingAmount",
|
||||||
"label": "Outstanding Amount",
|
"label": "Outstanding Amount",
|
||||||
"fieldtype": "Currency",
|
"fieldtype": "Currency",
|
||||||
"readOnly": true
|
"readOnly": true,
|
||||||
|
"filter": true
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"fieldname": "setDiscountAmount",
|
"fieldname": "setDiscountAmount",
|
||||||
|
@ -33,6 +33,7 @@ export interface BaseField {
|
|||||||
groupBy?: string; // UI Facing used in dropdowns fields
|
groupBy?: string; // UI Facing used in dropdowns fields
|
||||||
meta?: boolean; // Field is a meta field, i.e. only for the db, not UI
|
meta?: boolean; // Field is a meta field, i.e. only for the db, not UI
|
||||||
inline?: boolean; // UI Facing config, whether to display doc inline.
|
inline?: boolean; // UI Facing config, whether to display doc inline.
|
||||||
|
filter?: boolean; // UI Facing config, whether to be used to filter the List.
|
||||||
computed?: boolean; // Computed values are not stored in the database.
|
computed?: boolean; // Computed values are not stored in the database.
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -102,6 +102,7 @@ export default {
|
|||||||
'companyName'
|
'companyName'
|
||||||
);
|
);
|
||||||
await this.setSearcher();
|
await this.setSearcher();
|
||||||
|
await updateConfigFiles(fyo);
|
||||||
},
|
},
|
||||||
async setSearcher() {
|
async setSearcher() {
|
||||||
this.searcher = new Search(fyo);
|
this.searcher = new Search(fyo);
|
||||||
@ -133,7 +134,6 @@ export default {
|
|||||||
}
|
}
|
||||||
|
|
||||||
await initializeInstance(filePath, false, countryCode, fyo);
|
await initializeInstance(filePath, false, countryCode, fyo);
|
||||||
await updateConfigFiles(fyo);
|
|
||||||
await this.setDesk(filePath);
|
await this.setDesk(filePath);
|
||||||
},
|
},
|
||||||
async setDeskRoute() {
|
async setDeskRoute() {
|
||||||
@ -149,7 +149,7 @@ export default {
|
|||||||
async showDbSelector() {
|
async showDbSelector() {
|
||||||
fyo.config.set('lastSelectedFilePath', null);
|
fyo.config.set('lastSelectedFilePath', null);
|
||||||
fyo.telemetry.stop();
|
fyo.telemetry.stop();
|
||||||
fyo.purgeCache();
|
await fyo.purgeCache();
|
||||||
this.activeScreen = 'DatabaseSelector';
|
this.activeScreen = 'DatabaseSelector';
|
||||||
this.dbPath = '';
|
this.dbPath = '';
|
||||||
this.searcher = null;
|
this.searcher = null;
|
||||||
|
@ -214,10 +214,11 @@ export default {
|
|||||||
];
|
];
|
||||||
return fyo.schemaMap[this.schemaName].fields.filter(
|
return fyo.schemaMap[this.schemaName].fields.filter(
|
||||||
(f) =>
|
(f) =>
|
||||||
!f.computed &&
|
f.filter ||
|
||||||
!excludedFieldsTypes.includes(f.fieldtype) &&
|
(!f.computed &&
|
||||||
!f.meta &&
|
!excludedFieldsTypes.includes(f.fieldtype) &&
|
||||||
!f.readOnly
|
!f.meta &&
|
||||||
|
!f.readOnly)
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
fieldOptions() {
|
fieldOptions() {
|
||||||
|
@ -12,11 +12,11 @@
|
|||||||
/>
|
/>
|
||||||
<path
|
<path
|
||||||
d="M7.73114 2.75564V0.75855H0.0548096V2.75564H7.73114Z"
|
d="M7.73114 2.75564V0.75855H0.0548096V2.75564H7.73114Z"
|
||||||
fill="#0089FF"
|
fill="#2490EF"
|
||||||
/>
|
/>
|
||||||
<path
|
<path
|
||||||
d="M2.48876 7.43646H7.35669V5.43935H0.0548096V12.1796H2.48876V7.43646Z"
|
d="M2.48876 7.43646H7.35669V5.43935H0.0548096V12.1796H2.48876V7.43646Z"
|
||||||
fill="#0089FF"
|
fill="#2490EF"
|
||||||
/>
|
/>
|
||||||
</svg>
|
</svg>
|
||||||
</template>
|
</template>
|
||||||
|
@ -1,11 +1,7 @@
|
|||||||
import { ipcRenderer } from 'electron';
|
import { ipcRenderer } from 'electron';
|
||||||
import { t } from 'fyo';
|
import { t } from 'fyo';
|
||||||
import { Doc } from 'fyo/model/doc';
|
import { Doc } from 'fyo/model/doc';
|
||||||
import {
|
import { BaseError } from 'fyo/utils/errors';
|
||||||
MandatoryError,
|
|
||||||
NotFoundError,
|
|
||||||
ValidationError,
|
|
||||||
} from 'fyo/utils/errors';
|
|
||||||
import { ErrorLog } from 'fyo/utils/types';
|
import { ErrorLog } from 'fyo/utils/types';
|
||||||
import { truncate } from 'lodash';
|
import { truncate } from 'lodash';
|
||||||
import { IPC_ACTIONS, IPC_MESSAGES } from 'utils/messages';
|
import { IPC_ACTIONS, IPC_MESSAGES } from 'utils/messages';
|
||||||
@ -16,9 +12,8 @@ import { MessageDialogOptions, ToastOptions } from './utils/types';
|
|||||||
import { showMessageDialog, showToast } from './utils/ui';
|
import { showMessageDialog, showToast } from './utils/ui';
|
||||||
|
|
||||||
function shouldNotStore(error: Error) {
|
function shouldNotStore(error: Error) {
|
||||||
return [MandatoryError, ValidationError, NotFoundError].some(
|
const shouldLog = (error as BaseError).shouldStore ?? true;
|
||||||
(errorClass) => error instanceof errorClass
|
return !shouldLog;
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
async function reportError(errorLogObj: ErrorLog) {
|
async function reportError(errorLogObj: ErrorLog) {
|
||||||
@ -58,18 +53,17 @@ export function getErrorLogObject(
|
|||||||
const { name, stack, message } = error;
|
const { name, stack, message } = error;
|
||||||
const errorLogObj = { name, stack, message, more };
|
const errorLogObj = { name, stack, message, more };
|
||||||
|
|
||||||
// @ts-ignore
|
|
||||||
fyo.errorLog.push(errorLogObj);
|
fyo.errorLog.push(errorLogObj);
|
||||||
|
|
||||||
return errorLogObj;
|
return errorLogObj;
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function handleError(
|
export async function handleError(
|
||||||
shouldLog: boolean,
|
logToConsole: boolean,
|
||||||
error: Error,
|
error: Error,
|
||||||
more?: Record<string, unknown>
|
more?: Record<string, unknown>
|
||||||
) {
|
) {
|
||||||
if (shouldLog) {
|
if (logToConsole) {
|
||||||
console.error(error);
|
console.error(error);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -11,7 +11,7 @@ async function closeDbIfConnected() {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
await fyo.db.close();
|
await fyo.db.purgeCache();
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function initializeInstance(
|
export async function initializeInstance(
|
||||||
@ -89,7 +89,7 @@ async function setInstanceId(fyo: Fyo) {
|
|||||||
)) as string;
|
)) as string;
|
||||||
}
|
}
|
||||||
|
|
||||||
async function setCurrencySymbols(fyo: Fyo) {
|
export async function setCurrencySymbols(fyo: Fyo) {
|
||||||
const currencies = (await fyo.db.getAll(ModelNameEnum.Currency, {
|
const currencies = (await fyo.db.getAll(ModelNameEnum.Currency, {
|
||||||
fields: ['name', 'symbol'],
|
fields: ['name', 'symbol'],
|
||||||
})) as { name: string; symbol: string }[];
|
})) as { name: string; symbol: string }[];
|
||||||
|
@ -299,7 +299,7 @@ export default {
|
|||||||
);
|
);
|
||||||
|
|
||||||
updateConfigFiles(fyo);
|
updateConfigFiles(fyo);
|
||||||
fyo.purgeCache();
|
await fyo.purgeCache();
|
||||||
await this.setFiles();
|
await this.setFiles();
|
||||||
|
|
||||||
this.creatingDemo = false;
|
this.creatingDemo = false;
|
||||||
|
@ -4,7 +4,7 @@
|
|||||||
<template #header v-if="doc">
|
<template #header v-if="doc">
|
||||||
<StatusBadge :status="status" />
|
<StatusBadge :status="status" />
|
||||||
<Button
|
<Button
|
||||||
v-if="doc?.submitted"
|
v-if="!doc.isCancelled && !doc.dirty"
|
||||||
:icon="true"
|
:icon="true"
|
||||||
@click="routeTo(`/print/${doc.schemaName}/${doc.name}`)"
|
@click="routeTo(`/print/${doc.schemaName}/${doc.name}`)"
|
||||||
>
|
>
|
||||||
|
@ -10,7 +10,7 @@ import {
|
|||||||
import { AccountRootTypeEnum } from 'models/baseModels/Account/types';
|
import { AccountRootTypeEnum } from 'models/baseModels/Account/types';
|
||||||
import { AccountingSettings } from 'models/baseModels/AccountingSettings/AccountingSettings';
|
import { AccountingSettings } from 'models/baseModels/AccountingSettings/AccountingSettings';
|
||||||
import { ModelNameEnum } from 'models/types';
|
import { ModelNameEnum } from 'models/types';
|
||||||
import { initializeInstance } from 'src/initFyo';
|
import { initializeInstance, setCurrencySymbols } from 'src/initFyo';
|
||||||
import { createRegionalRecords } from 'src/regional';
|
import { createRegionalRecords } from 'src/regional';
|
||||||
import { getRandomString } from 'utils';
|
import { getRandomString } from 'utils';
|
||||||
import { defaultUOMs } from 'utils/defaults';
|
import { defaultUOMs } from 'utils/defaults';
|
||||||
@ -40,6 +40,10 @@ export default async function setupInstance(
|
|||||||
await createDefaultNumberSeries(fyo);
|
await createDefaultNumberSeries(fyo);
|
||||||
|
|
||||||
await completeSetup(companyName, fyo);
|
await completeSetup(companyName, fyo);
|
||||||
|
if (!Object.keys(fyo.currencySymbols).length) {
|
||||||
|
await setCurrencySymbols(fyo);
|
||||||
|
}
|
||||||
|
|
||||||
fyo.store.skipTelemetryLogging = false;
|
fyo.store.skipTelemetryLogging = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -3,9 +3,11 @@
|
|||||||
*/
|
*/
|
||||||
import { ipcRenderer } from 'electron';
|
import { ipcRenderer } from 'electron';
|
||||||
import { t } from 'fyo';
|
import { t } from 'fyo';
|
||||||
|
import { BaseError } from 'fyo/utils/errors';
|
||||||
|
import { BackendResponse } from 'utils/ipc/types';
|
||||||
import { IPC_ACTIONS, IPC_MESSAGES } from 'utils/messages';
|
import { IPC_ACTIONS, IPC_MESSAGES } from 'utils/messages';
|
||||||
import { setLanguageMap } from './language';
|
import { setLanguageMap } from './language';
|
||||||
import { showToast } from './ui';
|
import { showMessageDialog, showToast } from './ui';
|
||||||
|
|
||||||
export async function checkForUpdates() {
|
export async function checkForUpdates() {
|
||||||
await ipcRenderer.invoke(IPC_ACTIONS.CHECK_FOR_UPDATES);
|
await ipcRenderer.invoke(IPC_ACTIONS.CHECK_FOR_UPDATES);
|
||||||
@ -17,7 +19,32 @@ export async function openLink(link: string) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export async function deleteDb(filePath: string) {
|
export async function deleteDb(filePath: string) {
|
||||||
await ipcRenderer.invoke(IPC_ACTIONS.DELETE_FILE, filePath);
|
const { error } = (await ipcRenderer.invoke(
|
||||||
|
IPC_ACTIONS.DELETE_FILE,
|
||||||
|
filePath
|
||||||
|
)) as BackendResponse;
|
||||||
|
|
||||||
|
if (error?.code === 'EBUSY') {
|
||||||
|
showMessageDialog({
|
||||||
|
message: t`Delete Failed`,
|
||||||
|
detail: t`Please restart and try again`,
|
||||||
|
});
|
||||||
|
} else if (error?.code === 'ENOENT') {
|
||||||
|
showMessageDialog({
|
||||||
|
message: t`Delete Failed`,
|
||||||
|
detail: t`File ${filePath} does not exist`,
|
||||||
|
});
|
||||||
|
} else if (error?.code === 'EPERM') {
|
||||||
|
showMessageDialog({
|
||||||
|
message: t`Cannot Delete`,
|
||||||
|
detail: t`Close Frappe Books and try manually`,
|
||||||
|
});
|
||||||
|
} else if (error) {
|
||||||
|
const err = new BaseError(500, error.message);
|
||||||
|
err.name = error.name;
|
||||||
|
err.stack = error.stack;
|
||||||
|
throw err;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function saveData(data: string, savePath: string) {
|
export async function saveData(data: string, savePath: string) {
|
||||||
|
@ -150,7 +150,7 @@ export async function routeTo(route: string | RouteLocationRaw) {
|
|||||||
export async function deleteDocWithPrompt(doc: Doc) {
|
export async function deleteDocWithPrompt(doc: Doc) {
|
||||||
const schemaLabel = fyo.schemaMap[doc.schemaName]!.label;
|
const schemaLabel = fyo.schemaMap[doc.schemaName]!.label;
|
||||||
let detail = t`This action is permanent.`;
|
let detail = t`This action is permanent.`;
|
||||||
if (doc.isTransactional) {
|
if (doc.isTransactional && doc.isSubmitted) {
|
||||||
detail = t`This action is permanent and will delete associated ledger entries.`;
|
detail = t`This action is permanent and will delete associated ledger entries.`;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -291,9 +291,7 @@ function getDeleteAction(doc: Doc): Action {
|
|||||||
component: {
|
component: {
|
||||||
template: '<span class="text-red-700">{{ t`Delete` }}</span>',
|
template: '<span class="text-red-700">{{ t`Delete` }}</span>',
|
||||||
},
|
},
|
||||||
condition: (doc: Doc) =>
|
condition: (doc: Doc) => doc.canDelete,
|
||||||
(!doc.notInserted && !doc.schema.isSubmittable && !doc.schema.isSingle) ||
|
|
||||||
doc.isCancelled,
|
|
||||||
async action() {
|
async action() {
|
||||||
const res = await deleteDocWithPrompt(doc);
|
const res = await deleteDocWithPrompt(doc);
|
||||||
if (res) {
|
if (res) {
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
export interface DatabaseResponse {
|
export interface BackendResponse {
|
||||||
data?: unknown;
|
data?: unknown;
|
||||||
error?: { message: string; name: string; stack?: string };
|
error?: { message: string; name: string; stack?: string; code?: string };
|
||||||
}
|
}
|
||||||
|