mirror of
https://github.com/frappe/books.git
synced 2025-01-11 02:36:14 +00:00
Merge pull request #424 from frappe/minor-fixes-two
fix: a bunch of minor issues
This commit is contained in:
commit
8c7088d752
@ -394,7 +394,7 @@ export class Doc extends Observable<DocValue | Doc[]> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (filterComputed) {
|
if (filterComputed) {
|
||||||
fields = this.schema.fields.filter((f) => !f.computed);
|
fields = fields.filter((f) => !f.computed);
|
||||||
}
|
}
|
||||||
|
|
||||||
const data: DocValueMap = {};
|
const data: DocValueMap = {};
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
import { app, dialog, ipcMain } from 'electron';
|
import { app, dialog, ipcMain } from 'electron';
|
||||||
import { autoUpdater } from 'electron-updater';
|
import { autoUpdater, UpdateInfo } from 'electron-updater';
|
||||||
import fs from 'fs/promises';
|
import fs from 'fs/promises';
|
||||||
import path from 'path';
|
import path from 'path';
|
||||||
import databaseManager from '../backend/database/manager';
|
import databaseManager from '../backend/database/manager';
|
||||||
@ -15,6 +15,40 @@ import {
|
|||||||
} from './helpers';
|
} from './helpers';
|
||||||
import { saveHtmlAsPdf } from './saveHtmlAsPdf';
|
import { saveHtmlAsPdf } from './saveHtmlAsPdf';
|
||||||
|
|
||||||
|
autoUpdater.autoDownload = false;
|
||||||
|
|
||||||
|
autoUpdater.on('error', (error) => {
|
||||||
|
dialog.showErrorBox(
|
||||||
|
'Update Error: ',
|
||||||
|
error == null ? 'unknown' : (error.stack || error).toString()
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
autoUpdater.on('update-available', async (info: UpdateInfo) => {
|
||||||
|
const currentVersion = app.getVersion();
|
||||||
|
const nextVersion = info.version;
|
||||||
|
const isCurrentBeta = currentVersion.includes('beta');
|
||||||
|
const isNextBeta = nextVersion.includes('beta');
|
||||||
|
|
||||||
|
let downloadUpdate = true;
|
||||||
|
if (!isCurrentBeta && isNextBeta) {
|
||||||
|
const option = await dialog.showMessageBox({
|
||||||
|
type: 'info',
|
||||||
|
title: `Update Frappe Books?`,
|
||||||
|
message: `Download version ${nextVersion}?`,
|
||||||
|
buttons: ['Yes', 'No'],
|
||||||
|
});
|
||||||
|
|
||||||
|
downloadUpdate = option.response === 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!downloadUpdate) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
await autoUpdater.downloadUpdate();
|
||||||
|
});
|
||||||
|
|
||||||
export default function registerIpcMainActionListeners(main: Main) {
|
export default function registerIpcMainActionListeners(main: Main) {
|
||||||
ipcMain.handle(IPC_ACTIONS.GET_OPEN_FILEPATH, async (event, options) => {
|
ipcMain.handle(IPC_ACTIONS.GET_OPEN_FILEPATH, async (event, options) => {
|
||||||
return await dialog.showOpenDialog(main.mainWindow!, options);
|
return await dialog.showOpenDialog(main.mainWindow!, options);
|
||||||
@ -51,9 +85,9 @@ export default function registerIpcMainActionListeners(main: Main) {
|
|||||||
sendError(bodyJson);
|
sendError(bodyJson);
|
||||||
});
|
});
|
||||||
|
|
||||||
ipcMain.handle(IPC_ACTIONS.CHECK_FOR_UPDATES, () => {
|
ipcMain.handle(IPC_ACTIONS.CHECK_FOR_UPDATES, async () => {
|
||||||
if (!main.isDevelopment && !main.checkedForUpdate) {
|
if (!main.isDevelopment && !main.checkedForUpdate) {
|
||||||
autoUpdater.checkForUpdates();
|
await autoUpdater.checkForUpdates();
|
||||||
main.checkedForUpdate = true;
|
main.checkedForUpdate = true;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
@ -539,7 +539,9 @@ function pruneAccountTree(accountTree: AccountTree) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
for (const root of Object.keys(accountTree)) {
|
for (const root of Object.keys(accountTree)) {
|
||||||
accountTree[root].children = getPrunedChildren(accountTree[root].children!);
|
accountTree[root].children = getPrunedChildren(
|
||||||
|
accountTree[root].children ?? []
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -74,21 +74,65 @@ export class ProfitAndLoss extends AccountReport {
|
|||||||
async getReportDataFromRows(
|
async getReportDataFromRows(
|
||||||
incomeRows: ReportData,
|
incomeRows: ReportData,
|
||||||
expenseRows: ReportData,
|
expenseRows: ReportData,
|
||||||
incomeRoot: AccountTreeNode,
|
incomeRoot: AccountTreeNode | undefined,
|
||||||
expenseRoot: AccountTreeNode
|
expenseRoot: AccountTreeNode | undefined
|
||||||
): Promise<ReportData> {
|
): Promise<ReportData> {
|
||||||
|
if (incomeRoot && !expenseRoot) {
|
||||||
|
return await this.getIncomeOrExpenseRows(
|
||||||
|
incomeRoot,
|
||||||
|
incomeRows,
|
||||||
|
t`Total Income (Credit)`
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (expenseRoot && !incomeRoot) {
|
||||||
|
return await this.getIncomeOrExpenseRows(
|
||||||
|
expenseRoot,
|
||||||
|
expenseRows,
|
||||||
|
t`Total Income (Credit)`
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
if (!incomeRoot || !expenseRoot) {
|
if (!incomeRoot || !expenseRoot) {
|
||||||
return [];
|
return [];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return await this.getIncomeAndExpenseRows(
|
||||||
|
incomeRows,
|
||||||
|
expenseRows,
|
||||||
|
incomeRoot,
|
||||||
|
expenseRoot
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
async getIncomeOrExpenseRows(
|
||||||
|
root: AccountTreeNode,
|
||||||
|
rows: ReportData,
|
||||||
|
totalRowName: string
|
||||||
|
): Promise<ReportData> {
|
||||||
|
const total = await this.getTotalNode(root, totalRowName);
|
||||||
|
const totalRow = this.getRowFromAccountListNode(total);
|
||||||
|
|
||||||
|
return [rows, totalRow].flat();
|
||||||
|
}
|
||||||
|
|
||||||
|
async getIncomeAndExpenseRows(
|
||||||
|
incomeRows: ReportData,
|
||||||
|
expenseRows: ReportData,
|
||||||
|
incomeRoot: AccountTreeNode,
|
||||||
|
expenseRoot: AccountTreeNode
|
||||||
|
) {
|
||||||
const totalIncome = await this.getTotalNode(
|
const totalIncome = await this.getTotalNode(
|
||||||
incomeRoot,
|
incomeRoot,
|
||||||
t`Total Income (Credit)`
|
t`Total Income (Credit)`
|
||||||
);
|
);
|
||||||
|
const totalIncomeRow = this.getRowFromAccountListNode(totalIncome);
|
||||||
|
|
||||||
const totalExpense = await this.getTotalNode(
|
const totalExpense = await this.getTotalNode(
|
||||||
expenseRoot,
|
expenseRoot,
|
||||||
t`Total Expense (Debit)`
|
t`Total Expense (Debit)`
|
||||||
);
|
);
|
||||||
|
const totalExpenseRow = this.getRowFromAccountListNode(totalExpense);
|
||||||
|
|
||||||
const totalValueMap: ValueMap = new Map();
|
const totalValueMap: ValueMap = new Map();
|
||||||
for (const key of totalIncome.valueMap!.keys()) {
|
for (const key of totalIncome.valueMap!.keys()) {
|
||||||
@ -103,9 +147,6 @@ export class ProfitAndLoss extends AccountReport {
|
|||||||
level: 0,
|
level: 0,
|
||||||
} as AccountListNode;
|
} as AccountListNode;
|
||||||
|
|
||||||
const totalIncomeRow = this.getRowFromAccountListNode(totalIncome);
|
|
||||||
const totalExpenseRow = this.getRowFromAccountListNode(totalExpense);
|
|
||||||
|
|
||||||
const totalProfitRow = this.getRowFromAccountListNode(totalProfit);
|
const totalProfitRow = this.getRowFromAccountListNode(totalProfit);
|
||||||
totalProfitRow.cells.forEach((c) => {
|
totalProfitRow.cells.forEach((c) => {
|
||||||
c.bold = true;
|
c.bold = true;
|
||||||
|
@ -175,7 +175,6 @@ export default {
|
|||||||
this.filters = this.filters.filter((f) => f !== filter);
|
this.filters = this.filters.filter((f) => f !== filter);
|
||||||
},
|
},
|
||||||
setFilter(filters, implicit) {
|
setFilter(filters, implicit) {
|
||||||
console.log(filters);
|
|
||||||
this.filters = [];
|
this.filters = [];
|
||||||
|
|
||||||
Object.keys(filters).map((fieldname) => {
|
Object.keys(filters).map((fieldname) => {
|
||||||
|
@ -1,15 +1,10 @@
|
|||||||
<template>
|
<template>
|
||||||
<div
|
<div
|
||||||
class="
|
class="px-4 flex justify-between items-center h-row-largest flex-shrink-0"
|
||||||
px-4
|
:class="[
|
||||||
flex
|
border ? 'border-b' : '',
|
||||||
justify-between
|
platform !== 'Windows' ? 'window-drag' : '',
|
||||||
window-drag
|
]"
|
||||||
items-center
|
|
||||||
h-row-largest
|
|
||||||
flex-shrink-0
|
|
||||||
"
|
|
||||||
:class="border ? 'border-b' : ''"
|
|
||||||
>
|
>
|
||||||
<h1 class="text-xl font-semibold select-none" v-if="title">
|
<h1 class="text-xl font-semibold select-none" v-if="title">
|
||||||
{{ title }}
|
{{ title }}
|
||||||
|
@ -121,9 +121,11 @@ export default {
|
|||||||
},
|
},
|
||||||
setActiveTab() {
|
setActiveTab() {
|
||||||
const { tab } = this.$route.query;
|
const { tab } = this.$route.query;
|
||||||
const index = this.tabs.findIndex((i) => i.key === tab || 'Invoice');
|
const index = this.tabs.findIndex((i) => i.key === tab);
|
||||||
if (index !== -1) {
|
if (index !== -1) {
|
||||||
this.activeTab = index;
|
this.activeTab = index;
|
||||||
|
} else {
|
||||||
|
this.activeTab = 0;
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
getIconComponent(tab) {
|
getIconComponent(tab) {
|
||||||
|
@ -1,5 +1,8 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="flex-1 bg-gray-25 flex justify-center items-center window-drag">
|
<div
|
||||||
|
class="flex-1 bg-gray-25 flex justify-center items-center window-drag"
|
||||||
|
:class="{ 'window-drag': platform !== 'Windows' }"
|
||||||
|
>
|
||||||
<!-- Setup Wizard Slide -->
|
<!-- Setup Wizard Slide -->
|
||||||
<Slide
|
<Slide
|
||||||
:primary-disabled="!valuesFilled || loading"
|
:primary-disabled="!valuesFilled || loading"
|
||||||
|
@ -1,35 +1,39 @@
|
|||||||
import { Directive } from 'vue';
|
import { Directive } from 'vue';
|
||||||
|
|
||||||
const instances: OutsideClickCallback[] = [];
|
|
||||||
type OutsideClickCallback = (e: Event) => void;
|
type OutsideClickCallback = (e: Event) => void;
|
||||||
|
const instanceMap: Map<HTMLElement, OutsideClickCallback> = new Map();
|
||||||
|
|
||||||
export const outsideClickDirective: Directive<
|
export const outsideClickDirective: Directive<
|
||||||
HTMLElement,
|
HTMLElement,
|
||||||
OutsideClickCallback
|
OutsideClickCallback
|
||||||
> = {
|
> = {
|
||||||
beforeMount(el, binding) {
|
beforeMount(el, binding) {
|
||||||
el.dataset.outsideClickIndex = String(instances.length);
|
const clickHandler = function (e: Event) {
|
||||||
|
onDocumentClick(e, el, binding.value);
|
||||||
const fn = binding.value;
|
|
||||||
const click = function (e: Event) {
|
|
||||||
onDocumentClick(e, el, fn);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
document.addEventListener('click', click);
|
removeHandlerIfPresent(el);
|
||||||
instances.push(click);
|
instanceMap.set(el, clickHandler);
|
||||||
|
document.addEventListener('click', clickHandler);
|
||||||
},
|
},
|
||||||
unmounted(el) {
|
unmounted(el) {
|
||||||
const index = parseInt(el.dataset.outsideClickIndex ?? '0');
|
removeHandlerIfPresent(el);
|
||||||
const handler = instances[index];
|
|
||||||
document.addEventListener('click', handler);
|
|
||||||
instances.splice(index, 1);
|
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
function onDocumentClick(e: Event, el: HTMLElement, fn: OutsideClickCallback) {
|
function onDocumentClick(e: Event, el: HTMLElement, fn: OutsideClickCallback) {
|
||||||
const target = e.target;
|
const target = e.target as Node;
|
||||||
|
if (el !== target && !el.contains(target)) {
|
||||||
if (el !== target && !el.contains(target as Node)) {
|
fn?.(e);
|
||||||
fn(e);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function removeHandlerIfPresent(el: HTMLElement) {
|
||||||
|
const clickHandler = instanceMap.get(el);
|
||||||
|
if (!clickHandler) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
instanceMap.delete(el);
|
||||||
|
document.removeEventListener('click', clickHandler);
|
||||||
|
}
|
||||||
|
@ -94,7 +94,7 @@ export function getGetStartedConfig() {
|
|||||||
key: 'Add Customers',
|
key: 'Add Customers',
|
||||||
label: t`Add Customers`,
|
label: t`Add Customers`,
|
||||||
icon: 'customer',
|
icon: 'customer',
|
||||||
description: t`Add a few customers to create your first invoice`,
|
description: t`Add a few customers to create your first sales invoice`,
|
||||||
action: () => routeTo(`/list/Party/role/Customer/${t`Customers`}`),
|
action: () => routeTo(`/list/Party/role/Customer/${t`Customers`}`),
|
||||||
fieldname: 'customerCreated',
|
fieldname: 'customerCreated',
|
||||||
documentation:
|
documentation:
|
||||||
@ -104,7 +104,7 @@ export function getGetStartedConfig() {
|
|||||||
key: 'Create Sales Invoice',
|
key: 'Create Sales Invoice',
|
||||||
label: t`Create Sales Invoice`,
|
label: t`Create Sales Invoice`,
|
||||||
icon: 'sales-invoice',
|
icon: 'sales-invoice',
|
||||||
description: t`Create your first invoice and mail it to your customer`,
|
description: t`Create your first sales invoice for the created customer`,
|
||||||
action: () => routeTo('/list/SalesInvoice'),
|
action: () => routeTo('/list/SalesInvoice'),
|
||||||
fieldname: 'invoiceCreated',
|
fieldname: 'invoiceCreated',
|
||||||
documentation:
|
documentation:
|
||||||
@ -129,7 +129,7 @@ export function getGetStartedConfig() {
|
|||||||
key: 'Add Suppliers',
|
key: 'Add Suppliers',
|
||||||
label: t`Add Suppliers`,
|
label: t`Add Suppliers`,
|
||||||
icon: 'supplier',
|
icon: 'supplier',
|
||||||
description: t`Add a few suppliers to create your first bill`,
|
description: t`Add a few suppliers to create your first purchase invoice`,
|
||||||
action: () => routeTo(`/list/Party/role/Supplier/${t`Suppliers`}`),
|
action: () => routeTo(`/list/Party/role/Supplier/${t`Suppliers`}`),
|
||||||
fieldname: 'supplierCreated',
|
fieldname: 'supplierCreated',
|
||||||
},
|
},
|
||||||
@ -137,7 +137,7 @@ export function getGetStartedConfig() {
|
|||||||
key: 'Create Purchase Invoice',
|
key: 'Create Purchase Invoice',
|
||||||
label: t`Create Purchase Invoice`,
|
label: t`Create Purchase Invoice`,
|
||||||
icon: 'purchase-invoice',
|
icon: 'purchase-invoice',
|
||||||
description: t`Create your first bill and mail it to your supplier`,
|
description: t`Create your first purchase invoice from the created supplier`,
|
||||||
action: () => routeTo('/list/PurchaseInvoice'),
|
action: () => routeTo('/list/PurchaseInvoice'),
|
||||||
fieldname: 'billCreated',
|
fieldname: 'billCreated',
|
||||||
documentation:
|
documentation:
|
||||||
|
Loading…
Reference in New Issue
Block a user