2
0
mirror of https://github.com/frappe/books.git synced 2025-01-25 16:18:33 +00:00

Merge pull request #434 from 18alantom/minor-fixes-three

Minor fixes three
This commit is contained in:
Alan 2022-07-30 10:56:43 -07:00 committed by GitHub
commit 5899f92c9a
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
41 changed files with 143 additions and 78 deletions

Binary file not shown.

Before

Width:  |  Height:  |  Size: 264 KiB

After

Width:  |  Height:  |  Size: 145 KiB

BIN
.github/logo.png vendored

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.4 KiB

After

Width:  |  Height:  |  Size: 7.3 KiB

View File

@ -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';
/** /**

Binary file not shown.

Binary file not shown.

Before

Width:  |  Height:  |  Size: 8.5 KiB

After

Width:  |  Height:  |  Size: 3.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 21 KiB

After

Width:  |  Height:  |  Size: 55 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.4 KiB

After

Width:  |  Height:  |  Size: 2.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 295 B

After

Width:  |  Height:  |  Size: 383 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.4 KiB

After

Width:  |  Height:  |  Size: 5.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 555 B

After

Width:  |  Height:  |  Size: 665 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 802 B

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.4 KiB

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 941 B

After

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 8.5 KiB

After

Width:  |  Height:  |  Size: 3.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 9.2 KiB

After

Width:  |  Height:  |  Size: 4.5 KiB

View File

@ -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,

View File

@ -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 || '';

View File

@ -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();
} }
/** /**

View File

@ -26,7 +26,7 @@ export class DocHandler {
this.observer = new Observable(); this.observer = new Observable();
} }
purgeCache() { async purgeCache() {
this.init(); this.init();
} }

View File

@ -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) {

View File

@ -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 = {

View File

@ -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;
} }

View File

@ -34,7 +34,7 @@ describe('Fyo Init', function () {
true, true,
'non zero schemas' 'non zero schemas'
); );
await fyo.db.close(); await fyo.db.purgeCache();
}); });
}); });

View File

@ -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';
} }
} }

View File

@ -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,
}; };
} }

View File

@ -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 (_) => {

View File

@ -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;
} }
} }

View File

@ -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",

View File

@ -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",

View File

@ -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.
} }

View File

@ -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;

View File

@ -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() {

View File

@ -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>

View File

@ -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);
} }

View File

@ -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 }[];

View File

@ -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;

View File

@ -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}`)"
> >

View File

@ -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;
} }

View File

@ -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) {

View File

@ -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) {

View File

@ -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 };
} }