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,
|
||||
getDbError,
|
||||
NotFoundError,
|
||||
ValueError
|
||||
ValueError,
|
||||
} from 'fyo/utils/errors';
|
||||
import { knex, Knex } from 'knex';
|
||||
import {
|
||||
@ -11,12 +11,12 @@ import {
|
||||
RawValue,
|
||||
Schema,
|
||||
SchemaMap,
|
||||
TargetField
|
||||
TargetField,
|
||||
} from '../../schemas/types';
|
||||
import {
|
||||
getIsNullOrUndef,
|
||||
getRandomString,
|
||||
getValueMapFromList
|
||||
getValueMapFromList,
|
||||
} from '../../utils';
|
||||
import { DatabaseBase, GetAllOptions, QueryFilter } from '../../utils/db/types';
|
||||
import { getDefaultMetaFieldValueMap, sqliteTypeMap, SYSTEM } from '../helpers';
|
||||
@ -24,7 +24,7 @@ import {
|
||||
ColumnDiff,
|
||||
FieldValueMap,
|
||||
GetQueryBuilderOptions,
|
||||
SingleValue
|
||||
SingleValue,
|
||||
} 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,
|
||||
notifier?: Notifier
|
||||
) {
|
||||
fyo.purgeCache();
|
||||
await fyo.purgeCache();
|
||||
notifier?.(fyo.t`Setting Up Instance`, -1);
|
||||
const options = {
|
||||
logo: null,
|
||||
|
@ -107,7 +107,7 @@ export class AuthHandler {
|
||||
// TODO: Implement this with auth flow
|
||||
}
|
||||
|
||||
purgeCache() {}
|
||||
async purgeCache() {}
|
||||
|
||||
#getServerURL() {
|
||||
return this.#config.serverURL || '';
|
||||
|
@ -85,7 +85,8 @@ export class DatabaseHandler extends DatabaseBase {
|
||||
}
|
||||
}
|
||||
|
||||
purgeCache() {
|
||||
async purgeCache() {
|
||||
await this.close();
|
||||
this.dbPath = undefined;
|
||||
this.#schemaMap = {};
|
||||
this.fieldValueMap = {};
|
||||
@ -214,7 +215,6 @@ export class DatabaseHandler extends DatabaseBase {
|
||||
|
||||
async close(): Promise<void> {
|
||||
await this.#demux.call('close');
|
||||
this.purgeCache();
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -26,7 +26,7 @@ export class DocHandler {
|
||||
this.observer = new Observable();
|
||||
}
|
||||
|
||||
purgeCache() {
|
||||
async purgeCache() {
|
||||
this.init();
|
||||
}
|
||||
|
||||
|
@ -2,7 +2,7 @@ import { ipcRenderer } from 'electron';
|
||||
import { DatabaseError, NotImplemented } from 'fyo/utils/errors';
|
||||
import { SchemaMap } from 'schemas/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';
|
||||
|
||||
export class DatabaseDemux extends DatabaseDemuxBase {
|
||||
@ -12,7 +12,7 @@ export class DatabaseDemux extends DatabaseDemuxBase {
|
||||
this.#isElectron = isElectron;
|
||||
}
|
||||
|
||||
async #handleDBCall(func: () => Promise<DatabaseResponse>): Promise<unknown> {
|
||||
async #handleDBCall(func: () => Promise<BackendResponse>): Promise<unknown> {
|
||||
const response = await func();
|
||||
|
||||
if (response.error?.name) {
|
||||
|
@ -202,7 +202,7 @@ export class Fyo {
|
||||
return value;
|
||||
}
|
||||
|
||||
purgeCache() {
|
||||
async purgeCache() {
|
||||
this.pesa = getMoneyMaker({
|
||||
currency: DEFAULT_CURRENCY,
|
||||
precision: DEFAULT_INTERNAL_PRECISION,
|
||||
@ -216,9 +216,9 @@ export class Fyo {
|
||||
this.currencySymbols = {};
|
||||
this.errorLog = [];
|
||||
this.temp = {};
|
||||
this.db.purgeCache();
|
||||
this.auth.purgeCache();
|
||||
this.doc.purgeCache();
|
||||
await this.db.purgeCache();
|
||||
await this.auth.purgeCache();
|
||||
await this.doc.purgeCache();
|
||||
}
|
||||
|
||||
store = {
|
||||
|
@ -126,6 +126,30 @@ export class Doc extends Observable<DocValue | Doc[]> {
|
||||
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) {
|
||||
for (const field of this.schema.fields) {
|
||||
const fieldname = field.fieldname;
|
||||
@ -694,7 +718,7 @@ export class Doc extends Observable<DocValue | Doc[]> {
|
||||
}
|
||||
|
||||
async delete() {
|
||||
if (this.schema.isSubmittable && !this.isCancelled) {
|
||||
if (!this.canDelete) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -34,7 +34,7 @@ describe('Fyo Init', function () {
|
||||
true,
|
||||
'non zero schemas'
|
||||
);
|
||||
await fyo.db.close();
|
||||
await fyo.db.purgeCache();
|
||||
});
|
||||
});
|
||||
|
||||
|
@ -1,74 +1,76 @@
|
||||
export class BaseError extends Error {
|
||||
message: string;
|
||||
statusCode: number;
|
||||
shouldStore: boolean;
|
||||
|
||||
constructor(statusCode: number, message: string) {
|
||||
constructor(statusCode: number, message: string, shouldStore: boolean = true) {
|
||||
super(message);
|
||||
this.name = 'BaseError';
|
||||
this.statusCode = statusCode;
|
||||
this.message = message;
|
||||
this.shouldStore = shouldStore;
|
||||
}
|
||||
}
|
||||
|
||||
export class ValidationError extends BaseError {
|
||||
constructor(message: string) {
|
||||
super(417, message);
|
||||
constructor(message: string, shouldStore: boolean = false) {
|
||||
super(417, message, shouldStore);
|
||||
this.name = 'ValidationError';
|
||||
}
|
||||
}
|
||||
|
||||
export class NotFoundError extends BaseError {
|
||||
constructor(message: string) {
|
||||
super(404, message);
|
||||
constructor(message: string, shouldStore: boolean = true) {
|
||||
super(404, message, shouldStore);
|
||||
this.name = 'NotFoundError';
|
||||
}
|
||||
}
|
||||
|
||||
export class ForbiddenError extends BaseError {
|
||||
constructor(message: string) {
|
||||
super(403, message);
|
||||
constructor(message: string, shouldStore: boolean = true) {
|
||||
super(403, message, shouldStore);
|
||||
this.name = 'ForbiddenError';
|
||||
}
|
||||
}
|
||||
|
||||
export class DuplicateEntryError extends ValidationError {
|
||||
constructor(message: string) {
|
||||
super(message);
|
||||
constructor(message: string, shouldStore: boolean = false) {
|
||||
super(message, shouldStore);
|
||||
this.name = 'DuplicateEntryError';
|
||||
}
|
||||
}
|
||||
|
||||
export class LinkValidationError extends ValidationError {
|
||||
constructor(message: string) {
|
||||
super(message);
|
||||
constructor(message: string, shouldStore: boolean = false) {
|
||||
super(message, shouldStore);
|
||||
this.name = 'LinkValidationError';
|
||||
}
|
||||
}
|
||||
|
||||
export class MandatoryError extends ValidationError {
|
||||
constructor(message: string) {
|
||||
super(message);
|
||||
constructor(message: string, shouldStore: boolean = false) {
|
||||
super(message, shouldStore);
|
||||
this.name = 'MandatoryError';
|
||||
}
|
||||
}
|
||||
|
||||
export class DatabaseError extends BaseError {
|
||||
constructor(message: string) {
|
||||
super(500, message);
|
||||
constructor(message: string, shouldStore: boolean = true) {
|
||||
super(500, message, shouldStore);
|
||||
this.name = 'DatabaseError';
|
||||
}
|
||||
}
|
||||
|
||||
export class CannotCommitError extends DatabaseError {
|
||||
constructor(message: string) {
|
||||
super(message);
|
||||
constructor(message: string, shouldStore: boolean = true) {
|
||||
super(message, shouldStore);
|
||||
this.name = 'CannotCommitError';
|
||||
}
|
||||
}
|
||||
|
||||
export class NotImplemented extends BaseError {
|
||||
constructor() {
|
||||
super(501, '');
|
||||
constructor(message: string = '', shouldStore: boolean = false) {
|
||||
super(501, message, shouldStore);
|
||||
this.name = 'NotImplemented';
|
||||
}
|
||||
}
|
||||
|
@ -3,7 +3,7 @@ import fs from 'fs/promises';
|
||||
import { ConfigFile, ConfigKeys } from 'fyo/core/types';
|
||||
import { Main } from 'main';
|
||||
import config from 'utils/config';
|
||||
import { DatabaseResponse } from 'utils/ipc/types';
|
||||
import { BackendResponse } from 'utils/ipc/types';
|
||||
import { IPC_CHANNELS } from 'utils/messages';
|
||||
|
||||
interface ConfigFilesWithModified extends ConfigFile {
|
||||
@ -54,15 +54,16 @@ export async function getConfigFilesWithModified(files: ConfigFile[]) {
|
||||
}
|
||||
|
||||
export async function getErrorHandledReponse(func: () => Promise<unknown>) {
|
||||
const response: DatabaseResponse = {};
|
||||
const response: BackendResponse = {};
|
||||
|
||||
try {
|
||||
response.data = await func();
|
||||
} catch (err) {
|
||||
response.error = {
|
||||
name: (err as Error).name,
|
||||
message: (err as Error).message,
|
||||
stack: (err as Error).stack,
|
||||
name: (err as NodeJS.ErrnoException).name,
|
||||
message: (err as NodeJS.ErrnoException).message,
|
||||
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) => {
|
||||
await fs.unlink(filePath);
|
||||
return getErrorHandledReponse(async () => await fs.unlink(filePath));
|
||||
});
|
||||
|
||||
ipcMain.handle(IPC_ACTIONS.GET_DB_LIST, async (_) => {
|
||||
|
@ -1,5 +1,5 @@
|
||||
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 { AccountingLedgerEntry } from 'models/baseModels/AccountingLedgerEntry/AccountingLedgerEntry';
|
||||
import { ModelNameEnum } from 'models/types';
|
||||
@ -210,9 +210,20 @@ export class LedgerPosting {
|
||||
}
|
||||
|
||||
async _getRoundOffAccount() {
|
||||
return (await this.fyo.getValue(
|
||||
const roundOffAccount = (await this.fyo.getValue(
|
||||
ModelNameEnum.AccountingSettings,
|
||||
'roundOffAccount'
|
||||
)) 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",
|
||||
"label": "Outstanding Amount",
|
||||
"fieldtype": "Currency",
|
||||
"readOnly": true
|
||||
"readOnly": true,
|
||||
"filter": true
|
||||
},
|
||||
{
|
||||
"fieldname": "setDiscountAmount",
|
||||
|
@ -90,7 +90,8 @@
|
||||
"fieldname": "outstandingAmount",
|
||||
"label": "Outstanding Amount",
|
||||
"fieldtype": "Currency",
|
||||
"readOnly": true
|
||||
"readOnly": true,
|
||||
"filter": true
|
||||
},
|
||||
{
|
||||
"fieldname": "setDiscountAmount",
|
||||
|
@ -33,6 +33,7 @@ export interface BaseField {
|
||||
groupBy?: string; // UI Facing used in dropdowns fields
|
||||
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.
|
||||
filter?: boolean; // UI Facing config, whether to be used to filter the List.
|
||||
computed?: boolean; // Computed values are not stored in the database.
|
||||
}
|
||||
|
||||
|
@ -102,6 +102,7 @@ export default {
|
||||
'companyName'
|
||||
);
|
||||
await this.setSearcher();
|
||||
await updateConfigFiles(fyo);
|
||||
},
|
||||
async setSearcher() {
|
||||
this.searcher = new Search(fyo);
|
||||
@ -133,7 +134,6 @@ export default {
|
||||
}
|
||||
|
||||
await initializeInstance(filePath, false, countryCode, fyo);
|
||||
await updateConfigFiles(fyo);
|
||||
await this.setDesk(filePath);
|
||||
},
|
||||
async setDeskRoute() {
|
||||
@ -149,7 +149,7 @@ export default {
|
||||
async showDbSelector() {
|
||||
fyo.config.set('lastSelectedFilePath', null);
|
||||
fyo.telemetry.stop();
|
||||
fyo.purgeCache();
|
||||
await fyo.purgeCache();
|
||||
this.activeScreen = 'DatabaseSelector';
|
||||
this.dbPath = '';
|
||||
this.searcher = null;
|
||||
|
@ -214,10 +214,11 @@ export default {
|
||||
];
|
||||
return fyo.schemaMap[this.schemaName].fields.filter(
|
||||
(f) =>
|
||||
!f.computed &&
|
||||
!excludedFieldsTypes.includes(f.fieldtype) &&
|
||||
!f.meta &&
|
||||
!f.readOnly
|
||||
f.filter ||
|
||||
(!f.computed &&
|
||||
!excludedFieldsTypes.includes(f.fieldtype) &&
|
||||
!f.meta &&
|
||||
!f.readOnly)
|
||||
);
|
||||
},
|
||||
fieldOptions() {
|
||||
|
@ -12,11 +12,11 @@
|
||||
/>
|
||||
<path
|
||||
d="M7.73114 2.75564V0.75855H0.0548096V2.75564H7.73114Z"
|
||||
fill="#0089FF"
|
||||
fill="#2490EF"
|
||||
/>
|
||||
<path
|
||||
d="M2.48876 7.43646H7.35669V5.43935H0.0548096V12.1796H2.48876V7.43646Z"
|
||||
fill="#0089FF"
|
||||
fill="#2490EF"
|
||||
/>
|
||||
</svg>
|
||||
</template>
|
||||
|
@ -1,11 +1,7 @@
|
||||
import { ipcRenderer } from 'electron';
|
||||
import { t } from 'fyo';
|
||||
import { Doc } from 'fyo/model/doc';
|
||||
import {
|
||||
MandatoryError,
|
||||
NotFoundError,
|
||||
ValidationError,
|
||||
} from 'fyo/utils/errors';
|
||||
import { BaseError } from 'fyo/utils/errors';
|
||||
import { ErrorLog } from 'fyo/utils/types';
|
||||
import { truncate } from 'lodash';
|
||||
import { IPC_ACTIONS, IPC_MESSAGES } from 'utils/messages';
|
||||
@ -16,9 +12,8 @@ import { MessageDialogOptions, ToastOptions } from './utils/types';
|
||||
import { showMessageDialog, showToast } from './utils/ui';
|
||||
|
||||
function shouldNotStore(error: Error) {
|
||||
return [MandatoryError, ValidationError, NotFoundError].some(
|
||||
(errorClass) => error instanceof errorClass
|
||||
);
|
||||
const shouldLog = (error as BaseError).shouldStore ?? true;
|
||||
return !shouldLog;
|
||||
}
|
||||
|
||||
async function reportError(errorLogObj: ErrorLog) {
|
||||
@ -58,18 +53,17 @@ export function getErrorLogObject(
|
||||
const { name, stack, message } = error;
|
||||
const errorLogObj = { name, stack, message, more };
|
||||
|
||||
// @ts-ignore
|
||||
fyo.errorLog.push(errorLogObj);
|
||||
|
||||
return errorLogObj;
|
||||
}
|
||||
|
||||
export async function handleError(
|
||||
shouldLog: boolean,
|
||||
logToConsole: boolean,
|
||||
error: Error,
|
||||
more?: Record<string, unknown>
|
||||
) {
|
||||
if (shouldLog) {
|
||||
if (logToConsole) {
|
||||
console.error(error);
|
||||
}
|
||||
|
||||
|
@ -11,7 +11,7 @@ async function closeDbIfConnected() {
|
||||
return;
|
||||
}
|
||||
|
||||
await fyo.db.close();
|
||||
await fyo.db.purgeCache();
|
||||
}
|
||||
|
||||
export async function initializeInstance(
|
||||
@ -89,7 +89,7 @@ async function setInstanceId(fyo: Fyo) {
|
||||
)) as string;
|
||||
}
|
||||
|
||||
async function setCurrencySymbols(fyo: Fyo) {
|
||||
export async function setCurrencySymbols(fyo: Fyo) {
|
||||
const currencies = (await fyo.db.getAll(ModelNameEnum.Currency, {
|
||||
fields: ['name', 'symbol'],
|
||||
})) as { name: string; symbol: string }[];
|
||||
|
@ -299,7 +299,7 @@ export default {
|
||||
);
|
||||
|
||||
updateConfigFiles(fyo);
|
||||
fyo.purgeCache();
|
||||
await fyo.purgeCache();
|
||||
await this.setFiles();
|
||||
|
||||
this.creatingDemo = false;
|
||||
|
@ -4,7 +4,7 @@
|
||||
<template #header v-if="doc">
|
||||
<StatusBadge :status="status" />
|
||||
<Button
|
||||
v-if="doc?.submitted"
|
||||
v-if="!doc.isCancelled && !doc.dirty"
|
||||
:icon="true"
|
||||
@click="routeTo(`/print/${doc.schemaName}/${doc.name}`)"
|
||||
>
|
||||
|
@ -10,7 +10,7 @@ import {
|
||||
import { AccountRootTypeEnum } from 'models/baseModels/Account/types';
|
||||
import { AccountingSettings } from 'models/baseModels/AccountingSettings/AccountingSettings';
|
||||
import { ModelNameEnum } from 'models/types';
|
||||
import { initializeInstance } from 'src/initFyo';
|
||||
import { initializeInstance, setCurrencySymbols } from 'src/initFyo';
|
||||
import { createRegionalRecords } from 'src/regional';
|
||||
import { getRandomString } from 'utils';
|
||||
import { defaultUOMs } from 'utils/defaults';
|
||||
@ -40,6 +40,10 @@ export default async function setupInstance(
|
||||
await createDefaultNumberSeries(fyo);
|
||||
|
||||
await completeSetup(companyName, fyo);
|
||||
if (!Object.keys(fyo.currencySymbols).length) {
|
||||
await setCurrencySymbols(fyo);
|
||||
}
|
||||
|
||||
fyo.store.skipTelemetryLogging = false;
|
||||
}
|
||||
|
||||
|
@ -3,9 +3,11 @@
|
||||
*/
|
||||
import { ipcRenderer } from 'electron';
|
||||
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 { setLanguageMap } from './language';
|
||||
import { showToast } from './ui';
|
||||
import { showMessageDialog, showToast } from './ui';
|
||||
|
||||
export async function checkForUpdates() {
|
||||
await ipcRenderer.invoke(IPC_ACTIONS.CHECK_FOR_UPDATES);
|
||||
@ -17,7 +19,32 @@ export async function openLink(link: 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) {
|
||||
|
@ -150,7 +150,7 @@ export async function routeTo(route: string | RouteLocationRaw) {
|
||||
export async function deleteDocWithPrompt(doc: Doc) {
|
||||
const schemaLabel = fyo.schemaMap[doc.schemaName]!.label;
|
||||
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.`;
|
||||
}
|
||||
|
||||
@ -291,9 +291,7 @@ function getDeleteAction(doc: Doc): Action {
|
||||
component: {
|
||||
template: '<span class="text-red-700">{{ t`Delete` }}</span>',
|
||||
},
|
||||
condition: (doc: Doc) =>
|
||||
(!doc.notInserted && !doc.schema.isSubmittable && !doc.schema.isSingle) ||
|
||||
doc.isCancelled,
|
||||
condition: (doc: Doc) => doc.canDelete,
|
||||
async action() {
|
||||
const res = await deleteDocWithPrompt(doc);
|
||||
if (res) {
|
||||
|
@ -1,4 +1,4 @@
|
||||
export interface DatabaseResponse {
|
||||
export interface BackendResponse {
|
||||
data?: unknown;
|
||||
error?: { message: string; name: string; stack?: string };
|
||||
error?: { message: string; name: string; stack?: string; code?: string };
|
||||
}
|
||||
|