mirror of
https://github.com/frappe/books.git
synced 2024-12-22 19:09:01 +00:00
fix(ux): display can't delete cause link
- update reports on ledger entries - pull data until .plus({days: 1}) to account for all entries of the day
This commit is contained in:
parent
69f8ef11fe
commit
3975eb3f64
@ -1,8 +1,6 @@
|
||||
import {
|
||||
CannotCommitError,
|
||||
DatabaseError,
|
||||
DuplicateEntryError,
|
||||
LinkValidationError,
|
||||
getDbError,
|
||||
NotFoundError,
|
||||
ValueError,
|
||||
} from 'fyo/utils/errors';
|
||||
@ -98,7 +96,7 @@ export default class DatabaseCore extends DatabaseBase {
|
||||
async connect() {
|
||||
this.knex = knex(this.connectionParams);
|
||||
this.knex.on('query-error', (error) => {
|
||||
error.type = this.#getError(error);
|
||||
error.type = getDbError(error);
|
||||
});
|
||||
await this.knex.raw('PRAGMA foreign_keys=ON');
|
||||
}
|
||||
@ -116,7 +114,7 @@ export default class DatabaseCore extends DatabaseBase {
|
||||
try {
|
||||
// await this.knex!.raw('commit');
|
||||
} catch (err) {
|
||||
const type = this.#getError(err as Error);
|
||||
const type = getDbError(err as Error);
|
||||
if (type !== CannotCommitError) {
|
||||
throw err;
|
||||
}
|
||||
@ -155,7 +153,7 @@ export default class DatabaseCore extends DatabaseBase {
|
||||
}
|
||||
row = await qb.limit(1);
|
||||
} catch (err) {
|
||||
if (this.#getError(err as Error) !== NotFoundError) {
|
||||
if (getDbError(err as Error) !== NotFoundError) {
|
||||
throw err;
|
||||
}
|
||||
}
|
||||
@ -293,7 +291,7 @@ export default class DatabaseCore extends DatabaseBase {
|
||||
try {
|
||||
values = await builder.select('fieldname', 'value', 'parent');
|
||||
} catch (err) {
|
||||
if (this.#getError(err as Error) === NotFoundError) {
|
||||
if (getDbError(err as Error) === NotFoundError) {
|
||||
return [];
|
||||
}
|
||||
|
||||
@ -364,23 +362,6 @@ export default class DatabaseCore extends DatabaseBase {
|
||||
this.prestigeTheTable(schemaName, tableRows);
|
||||
}
|
||||
|
||||
#getError(err: Error) {
|
||||
let errorType = DatabaseError;
|
||||
if (err.message.includes('SQLITE_ERROR: no such table')) {
|
||||
errorType = NotFoundError;
|
||||
}
|
||||
if (err.message.includes('FOREIGN KEY')) {
|
||||
errorType = LinkValidationError;
|
||||
}
|
||||
if (err.message.includes('SQLITE_ERROR: cannot commit')) {
|
||||
errorType = CannotCommitError;
|
||||
}
|
||||
if (err.message.includes('SQLITE_CONSTRAINT: UNIQUE constraint failed:')) {
|
||||
errorType = DuplicateEntryError;
|
||||
}
|
||||
return errorType;
|
||||
}
|
||||
|
||||
async prestigeTheTable(schemaName: string, tableRows: FieldValueMap[]) {
|
||||
const max = 200;
|
||||
|
||||
|
@ -36,7 +36,6 @@ export function validateOptions(field: OptionField, value: string, doc: Doc) {
|
||||
return;
|
||||
}
|
||||
|
||||
const labels = options.map((o) => o.label).join(', ');
|
||||
throw new ValueError(t`Invalid value ${value} for ${field.label}`);
|
||||
}
|
||||
|
||||
|
@ -76,3 +76,27 @@ export class NotImplemented extends BaseError {
|
||||
export class ValueError extends ValidationError {}
|
||||
export class ConflictError extends ValidationError {}
|
||||
export class InvalidFieldError extends ValidationError {}
|
||||
|
||||
export function getDbError(err: Error) {
|
||||
if (!err.message) {
|
||||
return DatabaseError;
|
||||
}
|
||||
|
||||
if (err.message.includes('SQLITE_ERROR: no such table')) {
|
||||
return NotFoundError;
|
||||
}
|
||||
|
||||
if (err.message.includes('FOREIGN KEY')) {
|
||||
return LinkValidationError;
|
||||
}
|
||||
|
||||
if (err.message.includes('SQLITE_ERROR: cannot commit')) {
|
||||
return CannotCommitError;
|
||||
}
|
||||
|
||||
if (err.message.includes('SQLITE_CONSTRAINT: UNIQUE constraint failed:')) {
|
||||
return DuplicateEntryError;
|
||||
}
|
||||
|
||||
return DatabaseError;
|
||||
}
|
||||
|
@ -50,7 +50,7 @@ export abstract class AccountReport extends LedgerReport {
|
||||
|
||||
async setDefaultFilters(): Promise<void> {
|
||||
if (this.basedOn === 'Until Date' && !this.toDate) {
|
||||
this.toDate = DateTime.now().toISODate();
|
||||
this.toDate = DateTime.now().plus({ days: 1 }).toISODate();
|
||||
}
|
||||
|
||||
if (this.basedOn === 'Fiscal Year' && !this.toYear) {
|
||||
|
@ -23,9 +23,9 @@ export class BalanceSheet extends AccountReport {
|
||||
];
|
||||
}
|
||||
|
||||
async setReportData(filter?: string) {
|
||||
async setReportData(filter?: string, force?: boolean) {
|
||||
this.loading = true;
|
||||
if (filter !== 'hideGroupAmounts') {
|
||||
if (force || filter !== 'hideGroupAmounts') {
|
||||
await this._setRawData();
|
||||
}
|
||||
|
||||
@ -86,11 +86,14 @@ export class BalanceSheet extends AccountReport {
|
||||
continue;
|
||||
}
|
||||
|
||||
reportData.push(...row.rows);
|
||||
|
||||
if (row.rootNode) {
|
||||
const totalNode = await this.getTotalNode(row.rootNode, totalName);
|
||||
const totalRow = this.getRowFromAccountListNode(totalNode);
|
||||
|
||||
reportData.push(...row.rows);
|
||||
reportData.push(totalRow);
|
||||
}
|
||||
|
||||
reportData.push(emptyRow);
|
||||
}
|
||||
|
||||
|
@ -37,15 +37,15 @@ export class GeneralLedger extends LedgerReport {
|
||||
|
||||
async setDefaultFilters() {
|
||||
if (!this.toDate) {
|
||||
this.toDate = DateTime.now().toISODate();
|
||||
this.toDate = DateTime.now().plus({ days: 1 }).toISODate();
|
||||
this.fromDate = DateTime.now().minus({ years: 1 }).toISODate();
|
||||
}
|
||||
}
|
||||
|
||||
async setReportData(filter?: string) {
|
||||
async setReportData(filter?: string, force?: boolean) {
|
||||
this.loading = true;
|
||||
let sort = true;
|
||||
if (filter !== 'grouped' || this._rawData.length === 0) {
|
||||
if (force || filter !== 'grouped' || this._rawData.length === 0) {
|
||||
await this._setRawData();
|
||||
sort = false;
|
||||
}
|
||||
@ -141,6 +141,10 @@ export class GeneralLedger extends LedgerReport {
|
||||
value = String(value);
|
||||
}
|
||||
|
||||
if (fieldname === 'referenceType') {
|
||||
value = this.fyo.schemaMap[value]?.label ?? value;
|
||||
}
|
||||
|
||||
row.cells.push({
|
||||
italics: entry.name === -1,
|
||||
bold: entry.name === -2,
|
||||
|
@ -1,4 +1,4 @@
|
||||
import { t } from 'fyo';
|
||||
import { Fyo, t } from 'fyo';
|
||||
import { Action } from 'fyo/model/types';
|
||||
import { ModelNameEnum } from 'models/types';
|
||||
import { Report } from 'reports/Report';
|
||||
@ -13,6 +13,26 @@ export abstract class LedgerReport extends Report {
|
||||
static reportName = 'general-ledger';
|
||||
|
||||
_rawData: LedgerEntry[] = [];
|
||||
shouldRefresh: boolean = false;
|
||||
|
||||
constructor(fyo: Fyo) {
|
||||
super(fyo);
|
||||
this._setObservers();
|
||||
}
|
||||
|
||||
_setObservers() {
|
||||
const listener = () => (this.shouldRefresh = true);
|
||||
|
||||
this.fyo.doc.observer.on(
|
||||
`sync:${ModelNameEnum.AccountingLedgerEntry}`,
|
||||
listener
|
||||
);
|
||||
|
||||
this.fyo.doc.observer.on(
|
||||
`delete:${ModelNameEnum.AccountingLedgerEntry}`,
|
||||
listener
|
||||
);
|
||||
}
|
||||
|
||||
_getGroupByKey() {
|
||||
let groupBy: GroupByKey = 'referenceName';
|
||||
|
@ -23,9 +23,9 @@ export class ProfitAndLoss extends AccountReport {
|
||||
return [AccountRootTypeEnum.Income, AccountRootTypeEnum.Expense];
|
||||
}
|
||||
|
||||
async setReportData(filter?: string) {
|
||||
async setReportData(filter?: string, force?: boolean) {
|
||||
this.loading = true;
|
||||
if (filter !== 'hideGroupAmounts') {
|
||||
if (force || filter !== 'hideGroupAmounts') {
|
||||
await this._setRawData();
|
||||
}
|
||||
|
||||
@ -77,6 +77,10 @@ export class ProfitAndLoss extends AccountReport {
|
||||
incomeRoot: AccountTreeNode,
|
||||
expenseRoot: AccountTreeNode
|
||||
): Promise<ReportData> {
|
||||
if (!incomeRoot || !expenseRoot) {
|
||||
return [];
|
||||
}
|
||||
|
||||
const totalIncome = await this.getTotalNode(
|
||||
incomeRoot,
|
||||
t`Total Income (Credit)`
|
||||
|
@ -14,6 +14,7 @@ export abstract class Report extends Observable<RawValue> {
|
||||
filters: Field[] = [];
|
||||
reportData: ReportData;
|
||||
usePagination: boolean = false;
|
||||
shouldRefresh: boolean = false;
|
||||
abstract loading: boolean;
|
||||
|
||||
constructor(fyo: Fyo) {
|
||||
@ -75,15 +76,15 @@ export abstract class Report extends Observable<RawValue> {
|
||||
}
|
||||
|
||||
if (callPostSet) {
|
||||
await this.postSet(key);
|
||||
await this.updateData(key);
|
||||
}
|
||||
}
|
||||
|
||||
async postSet(key?: string) {
|
||||
async updateData(key?: string, force?: boolean) {
|
||||
await this.setDefaultFilters();
|
||||
this.filters = await this.getFilters();
|
||||
this.columns = await this.getColumns();
|
||||
await this.setReportData(key);
|
||||
await this.setReportData(key, force);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -94,5 +95,5 @@ export abstract class Report extends Observable<RawValue> {
|
||||
abstract getActions(): Action[];
|
||||
abstract getFilters(): Field[] | Promise<Field[]>;
|
||||
abstract getColumns(): ColumnField[] | Promise<ColumnField[]>;
|
||||
abstract setReportData(filter?: string): Promise<void>;
|
||||
abstract setReportData(filter?: string, force?: boolean): Promise<void>;
|
||||
}
|
||||
|
@ -53,9 +53,9 @@ export class TrialBalance extends AccountReport {
|
||||
];
|
||||
}
|
||||
|
||||
async setReportData(filter?: string) {
|
||||
async setReportData(filter?: string, force?: boolean) {
|
||||
this.loading = true;
|
||||
if (filter !== 'hideGroupAmounts') {
|
||||
if (force || filter !== 'hideGroupAmounts') {
|
||||
await this._setRawData();
|
||||
}
|
||||
|
||||
|
@ -11,7 +11,7 @@ import { truncate } from 'lodash';
|
||||
import { IPC_ACTIONS, IPC_MESSAGES } from 'utils/messages';
|
||||
import { fyo } from './initFyo';
|
||||
import router from './router';
|
||||
import { getErrorMessage } from './utils';
|
||||
import { getErrorMessage, stringifyCircular } from './utils';
|
||||
import { MessageDialogOptions, ToastOptions } from './utils/types';
|
||||
import { showMessageDialog, showToast } from './utils/ui';
|
||||
|
||||
@ -30,7 +30,7 @@ async function reportError(errorLogObj: ErrorLog) {
|
||||
error_name: errorLogObj.name,
|
||||
message: errorLogObj.message,
|
||||
stack: errorLogObj.stack,
|
||||
more: JSON.stringify(errorLogObj.more ?? {}),
|
||||
more: stringifyCircular(errorLogObj.more ?? {}),
|
||||
};
|
||||
|
||||
if (fyo.store.isDevelopment) {
|
||||
|
@ -77,7 +77,7 @@ export default {
|
||||
let colors = ['#2490EF', '#B7BFC6'];
|
||||
if (!this.hasData) {
|
||||
data = dummyData;
|
||||
colors = ['#E9EBED', '#B7BFC6'];
|
||||
colors = ['#E9EBED', '#DFE1E2'];
|
||||
}
|
||||
|
||||
const xLabels = data.map((cf) => cf['yearmonth']);
|
||||
|
@ -74,7 +74,7 @@ export default defineComponent({
|
||||
}
|
||||
|
||||
if (filterKeys.length) {
|
||||
await this.report.postSet()
|
||||
await this.report.postSet();
|
||||
}
|
||||
|
||||
if (fyo.store.isDevelopment) {
|
||||
@ -117,6 +117,8 @@ export default defineComponent({
|
||||
|
||||
if (!this.report.reportData.length) {
|
||||
await this.report.setReportData();
|
||||
} else if (this.report.shouldRefresh) {
|
||||
await this.report.setReportData(undefined, true);
|
||||
}
|
||||
},
|
||||
},
|
||||
|
@ -9,7 +9,7 @@ import { fyo } from 'src/initFyo';
|
||||
export function getDatesAndPeriodList(
|
||||
period: 'This Year' | 'This Quarter' | 'This Month'
|
||||
): { periodList: DateTime[]; fromDate: DateTime; toDate: DateTime } {
|
||||
const toDate: DateTime = DateTime.now();
|
||||
const toDate: DateTime = DateTime.now().plus({ days: 1 });
|
||||
let fromDate: DateTime;
|
||||
|
||||
if (period === 'This Year') {
|
||||
|
@ -417,7 +417,7 @@ export class Search {
|
||||
_setFilterDefaults() {
|
||||
const totalChildKeywords = Object.values(this.searchables)
|
||||
.filter((s) => s.isChild)
|
||||
.map((s) => this.keywords[s.schemaName].length)
|
||||
.map((s) => this.keywords[s.schemaName]?.length ?? 0)
|
||||
.reduce((a, b) => a + b);
|
||||
|
||||
if (totalChildKeywords > 2_000) {
|
||||
|
@ -7,6 +7,7 @@ import { t } from 'fyo';
|
||||
import { Doc } from 'fyo/model/doc';
|
||||
import { Action } from 'fyo/model/types';
|
||||
import { getActions } from 'fyo/utils';
|
||||
import { getDbError, LinkValidationError } from 'fyo/utils/errors';
|
||||
import { ModelNameEnum } from 'models/types';
|
||||
import { handleErrorWithDialog } from 'src/errorHandling';
|
||||
import { fyo } from 'src/initFyo';
|
||||
@ -106,7 +107,7 @@ export async function showToast(options: ToastOptions) {
|
||||
}
|
||||
|
||||
// @ts-ignore
|
||||
window.st = showToast
|
||||
window.st = showToast;
|
||||
|
||||
function replaceAndAppendMount(app: App<Element>, replaceId: string) {
|
||||
const fragment = document.createDocumentFragment();
|
||||
@ -162,7 +163,15 @@ export async function deleteDocWithPrompt(doc: Doc) {
|
||||
await doc.delete();
|
||||
return true;
|
||||
} catch (err) {
|
||||
if (getDbError(err as Error) === LinkValidationError) {
|
||||
showMessageDialog({
|
||||
message: t`Delete Failed`,
|
||||
detail: t`Cannot delete ${schemaLabel} ${doc.name!} because of linked entries.`,
|
||||
});
|
||||
} else {
|
||||
handleErrorWithDialog(err as Error, doc);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
},
|
||||
|
Loading…
Reference in New Issue
Block a user