2
0
mirror of https://github.com/frappe/books.git synced 2024-12-23 03:19:01 +00:00

- Bug Fixes

- PnL & Balance Sheet
- Search Keyboard Navigation
This commit is contained in:
thefalconx33 2019-08-20 14:27:27 +05:30
parent 54e115b030
commit 562b4759e0
27 changed files with 234 additions and 81 deletions

View File

@ -11,12 +11,14 @@ module.exports = class LedgerPosting {
async debit(account, amount, referenceType, referenceName) { async debit(account, amount, referenceType, referenceName) {
const entry = this.getEntry(account, referenceType, referenceName); const entry = this.getEntry(account, referenceType, referenceName);
amount = frappe.parseNumber(amount);
entry.debit += amount; entry.debit += amount;
await this.setAccountBalanceChange(account, 'debit', amount); await this.setAccountBalanceChange(account, 'debit', amount);
} }
async credit(account, amount, referenceType, referenceName) { async credit(account, amount, referenceType, referenceName) {
const entry = this.getEntry(account, referenceType, referenceName); const entry = this.getEntry(account, referenceType, referenceName);
amount = frappe.parseNumber(amount);
entry.credit += amount; entry.credit += amount;
await this.setAccountBalanceChange(account, 'credit', amount); await this.setAccountBalanceChange(account, 'credit', amount);
} }
@ -83,7 +85,6 @@ module.exports = class LedgerPosting {
let credit = 0; let credit = 0;
let debitAccounts = []; let debitAccounts = [];
let creditAccounts = []; let creditAccounts = [];
for (let entry of this.entries) { for (let entry of this.entries) {
debit += entry.debit; debit += entry.debit;
credit += entry.credit; credit += entry.credit;
@ -93,11 +94,20 @@ module.exports = class LedgerPosting {
creditAccounts.push(entry.account); creditAccounts.push(entry.account);
} }
} }
debit = Math.floor(debit * 100) / 100;
credit = Math.floor(credit * 100) / 100;
if (debit !== credit) { if (debit !== credit) {
throw new frappe.errors.ValidationError( frappe.call({
frappe._('Debit {0} must be equal to Credit {1}', [debit, credit]) method: 'show-dialog',
); args: {
title: 'Invalid Entry',
message: frappe._('Debit {0} must be equal to Credit {1}', [
debit,
credit
])
}
});
throw new Error();
} }
} }

View File

@ -2,6 +2,6 @@ import { _ } from 'frappejs/utils';
export default { export default {
doctype: 'Account', doctype: 'Account',
title: _('Accounts'), title: _('Account'),
columns: ['name', 'parentAccount', 'rootType'] columns: ['name', 'parentAccount', 'rootType']
}; };

View File

@ -118,7 +118,7 @@ module.exports = {
invoice.on('afterInsert', async () => { invoice.on('afterInsert', async () => {
form.$formModal.close(); form.$formModal.close();
form.$router.push({ form.$router.push({
path: `/edit/PurchaseInvoice/${invoice.name}` path: `/edit/SalesInvoice/${invoice.name}`
}); });
}); });
await form.$formModal.open(invoice); await form.$formModal.open(invoice);

View File

@ -17,6 +17,7 @@ module.exports = {
label: 'Entry Type', label: 'Entry Type',
fieldtype: 'Select', fieldtype: 'Select',
options: [ options: [
'Select...',
'Journal Entry', 'Journal Entry',
'Bank Entry', 'Bank Entry',
'Cash Entry', 'Cash Entry',

View File

@ -30,13 +30,11 @@ module.exports = {
required: 1, required: 1,
getFilters: (query, doc) => { getFilters: (query, doc) => {
if (doc.paymentType === 'Pay') { if (doc.paymentType === 'Pay') {
if (doc.paymentMethod === 'Cash') if (doc.paymentMethod === 'Cash') {
return { accountType: 'Cash', isGroup: 0 }; return { accountType: 'Cash', isGroup: 0 };
else } else {
return { return { accountType: ['in', ['Bank', 'Cash']], isGroup: 0 };
accountType: ['in', ['Bank', 'Cash']], }
isGroup: 0
};
} }
} }
}, },
@ -96,7 +94,6 @@ module.exports = {
required: 1, required: 1,
disabled: true, disabled: true,
formula: doc => { formula: doc => {
console.log(doc.getSum('for', 'amount'));
return frappe.format(doc.getSum('for', 'amount'), 'Currency'); return frappe.format(doc.getSum('for', 'amount'), 'Currency');
} }
}, },

View File

@ -23,13 +23,12 @@ module.exports = class PaymentServer extends BaseDocument {
if (outstandingAmount === null) { if (outstandingAmount === null) {
outstandingAmount = grandTotal; outstandingAmount = grandTotal;
} }
if (this.amount > outstandingAmount) { if (0 >= this.amount || this.amount > outstandingAmount) {
frappe.call({ frappe.call({
method: 'show-dialog', method: 'show-dialog',
args: { args: {
title: 'Invalid Payment Entry', title: 'Invalid Payment Entry',
message: `Payment amount is greater than Outstanding amount by \ message: `Payment amount is greater than 0 and less than Outstanding amount (${outstandingAmount})`
${this.amount - outstandingAmount}`
} }
}); });
throw new Error(); throw new Error();
@ -38,7 +37,8 @@ module.exports = class PaymentServer extends BaseDocument {
row.referenceType, row.referenceType,
row.referenceName, row.referenceName,
'outstandingAmount', 'outstandingAmount',
outstandingAmount - this.amount frappe.parseNumber(outstandingAmount) -
frappe.parseNumber(this.amount)
); );
} }
} }

View File

@ -22,9 +22,8 @@ module.exports = {
fieldname: 'amount', fieldname: 'amount',
label: 'Amount', label: 'Amount',
fieldtype: 'Currency', fieldtype: 'Currency',
formula: (row, doc) => { formula: (row, doc) =>
doc.getFrom(doc.referenceType, doc.referenceName, 'grandTotal'); doc.getFrom(row.referenceType, row.referenceName, 'grandTotal'),
},
required: 1 required: 1
} }
] ]

View File

@ -127,9 +127,11 @@ module.exports = {
], ],
links: [ links: [
utils.ledgerLink,
{ {
label: 'Make Payment', label: 'Make Payment',
condition: form => form.doc.submitted, condition: form =>
form.doc.submitted && form.doc.outstandingAmount != 0.0,
action: async form => { action: async form => {
const payment = await frappe.getNewDoc('Payment'); const payment = await frappe.getNewDoc('Payment');
payment.paymentType = 'Pay'; payment.paymentType = 'Pay';

View File

@ -85,9 +85,9 @@ module.exports = {
<div class='col-6'></div> <div class='col-6'></div>
<div class='col-6'> <div class='col-6'>
<div class='row' v-for='row in value'> <div class='row' v-for='row in value'>
<div class='col-6'>{{row.account}} ({{row.rate}}%)</div> <div class='col-6'>{{ row.account }} ({{row.rate}}%)</div>
<div class='col-6 text-right'> <div class='col-6 text-right'>
{{frappe.format(row.amount, 'Currency')}} {{ frappe.format(row.amount, 'Currency')}}
</div> </div>
</div> </div>
</div> </div>
@ -98,7 +98,7 @@ module.exports = {
fieldname: 'grandTotal', fieldname: 'grandTotal',
label: 'Grand Total', label: 'Grand Total',
fieldtype: 'Currency', fieldtype: 'Currency',
formula: doc => doc.getGrandTotal(), formula: doc => frappe.format(doc.getGrandTotal(), 'Currency'),
disabled: true, disabled: true,
readOnly: 1 readOnly: 1
}, },
@ -142,7 +142,7 @@ module.exports = {
{ {
label: 'Make Payment', label: 'Make Payment',
condition: form => condition: form =>
form.doc.submitted && form.doc.outstandingAmount !== 0.0, form.doc.submitted && form.doc.outstandingAmount != 0.0,
action: async form => { action: async form => {
const payment = await frappe.getNewDoc('Payment'); const payment = await frappe.getNewDoc('Payment');
payment.paymentType = 'Receive'; payment.paymentType = 'Receive';

View File

@ -76,6 +76,6 @@ module.exports = class SalesInvoice extends BaseDocument {
} }
grandTotal = Math.floor(grandTotal * 100) / 100; grandTotal = Math.floor(grandTotal * 100) / 100;
return frappe.format(grandTotal, 'Currency'); return grandTotal;
} }
}; };

View File

@ -20,7 +20,7 @@ module.exports = {
fieldtype: 'Select', fieldtype: 'Select',
options: ['Basic I', 'Basic II', 'Modern'], options: ['Basic I', 'Basic II', 'Modern'],
required: 1, required: 1,
defaultValue: 'Basic I' default: 'Basic I'
}, },
{ {
fieldname: 'font', fieldname: 'font',
@ -28,14 +28,14 @@ module.exports = {
fieldtype: 'Select', fieldtype: 'Select',
options: ['Montserrat', 'Open Sans', 'Oxygen', 'Merriweather'], options: ['Montserrat', 'Open Sans', 'Oxygen', 'Merriweather'],
required: 1, required: 1,
defaultValue: 'Montserrat' default: 'Montserrat'
}, },
{ {
fieldname: 'themeColor', fieldname: 'themeColor',
label: 'Theme Color', label: 'Theme Color',
fieldtype: 'Data', fieldtype: 'Data',
required: 1, required: 1,
defaultValue: '#000000', default: '#000000',
hidden: 1 hidden: 1
} }
] ]

View File

@ -86,6 +86,12 @@ module.exports = {
return countryList[doc.country].currency; return countryList[doc.country].currency;
}, },
required: 1 required: 1
},
{
fieldname: 'completed',
label: 'Completed',
fieldtype: 'Check',
readonly: 1
} }
], ],

View File

@ -61,7 +61,7 @@
"cross-env": "^5.2.0", "cross-env": "^5.2.0",
"file-saver": "^2.0.2", "file-saver": "^2.0.2",
"frappe-charts": "^1.2.4", "frappe-charts": "^1.2.4",
"frappejs": "github:thefalconx33/frappejs#test", "frappejs": "https://github.com/thefalconx33/frappejs#test",
"nodemailer": "^4.7.0", "nodemailer": "^4.7.0",
"popper.js": "^1.14.4", "popper.js": "^1.14.4",
"vue-color": "^2.7.0", "vue-color": "^2.7.0",

View File

@ -0,0 +1,46 @@
module.exports = {
title: 'Balance Sheet',
method: 'balance-sheet',
filterFields: [
{
fieldtype: 'Date',
fieldname: 'toDate',
size: 'small',
placeholder: 'ToDate',
label: 'To Date',
required: 1
},
{
fieldtype: 'Select',
size: 'small',
options: [
'Select Period...',
'Monthly',
'Quarterly',
'Half Yearly',
'Yearly'
],
label: 'Periodicity',
fieldname: 'periodicity',
default: 'Monthly'
}
],
getColumns(data) {
const columns = [
{ label: 'Account', fieldtype: 'Data', fieldname: 'account', width: 340 }
];
if (data && data.columns) {
const currencyColumns = data.columns;
const columnDefs = currencyColumns.map(name => ({
label: name,
fieldname: name,
fieldtype: 'Currency'
}));
columns.push(...columnDefs);
}
return columns;
}
};

View File

@ -2,12 +2,36 @@ const title = 'Profit and Loss';
module.exports = { module.exports = {
title: title, title: title,
method: 'profit-and-loss', method: 'profit-and-loss',
treeView: true,
filterFields: [ filterFields: [
{ fieldtype: 'Date', fieldname: 'fromDate', label: 'From Date', required: 1 },
{ fieldtype: 'Date', fieldname: 'toDate', label: 'To Date', required: 1 },
{ {
fieldtype: 'Select', options: ['Monthly', 'Quarterly', 'Half Yearly', 'Yearly'], fieldtype: 'Date',
label: 'Periodicity', fieldname: 'periodicity', default: 'Monthly' fieldname: 'fromDate',
size: 'small',
placeholder: 'From Date',
label: 'From Date',
required: 1
},
{
fieldtype: 'Date',
fieldname: 'toDate',
size: 'small',
placeholder: 'To Date',
label: 'To Date',
required: 1
},
{
fieldtype: 'Select',
size: 'small',
options: [
'Select Period...',
'Monthly',
'Quarterly',
'Half Yearly',
'Yearly'
],
label: 'Periodicity',
fieldname: 'periodicity'
} }
], ],
getColumns(data) { getColumns(data) {

View File

@ -2,6 +2,7 @@ module.exports = {
'general-ledger': require('./GeneralLedger/viewConfig'), 'general-ledger': require('./GeneralLedger/viewConfig'),
'sales-register': require('./SalesRegister/viewConfig'), 'sales-register': require('./SalesRegister/viewConfig'),
'purchase-register': require('./PurchaseRegister/viewConfig'), 'purchase-register': require('./PurchaseRegister/viewConfig'),
'balance-sheet': require('./BalanceSheet/viewConfig'),
'profit-and-loss': require('./ProfitAndLoss/viewConfig'), 'profit-and-loss': require('./ProfitAndLoss/viewConfig'),
'trial-balance': require('./TrialBalance/viewConfig'), 'trial-balance': require('./TrialBalance/viewConfig'),
'bank-reconciliation': require('./BankReconciliation/viewConfig'), 'bank-reconciliation': require('./BankReconciliation/viewConfig'),

View File

@ -6,7 +6,7 @@ let winURL;
if (process.env.NODE_ENV !== 'development') { if (process.env.NODE_ENV !== 'development') {
global.__static = require('path') global.__static = require('path')
.join(__dirname, '/static') .join(__dirname, '../static')
.replace(/\\/g, '\\\\'); .replace(/\\/g, '\\\\');
} }

View File

@ -19,12 +19,12 @@ export default {
showDatabaseSelector: false, showDatabaseSelector: false,
showDesk: false, showDesk: false,
showSetupWizard: false showSetupWizard: false
} };
}, },
components: { components: {
Desk, Desk,
SetupWizard, SetupWizard,
DatabaseSelector, DatabaseSelector
}, },
mounted() { mounted() {
if (!localStorage.dbPath) { if (!localStorage.dbPath) {
@ -43,15 +43,15 @@ export default {
this.showDesk = true; this.showDesk = true;
this.showSetupWizard = false; this.showSetupWizard = false;
this.showDatabaseSelector = false; this.showDatabaseSelector = false;
}) });
}, },
methods: { methods: {
connectToDBFile(filePath) { connectToDBFile(filePath) {
frappe.events.trigger('DatabaseSelector:file-selected', filePath); frappe.events.trigger('DatabaseSelector:file-selected', filePath);
} }
} }
} };
</script> </script>
<style lang="scss"> <style lang="scss">
@import "styles/index.scss"; @import 'styles/index.scss';
</style> </style>

View File

@ -9,19 +9,23 @@
<input <input
type="search" type="search"
class="form-control" class="form-control"
@click="focus(0)"
@keydown.down="navigate('down')"
@keydown.up="navigate('up')"
placeholder="Search..." placeholder="Search..."
autocomplete="off" autocomplete="off"
spellcheck="false" spellcheck="false"
v-model="inputValue" v-model="inputValue"
@keyup.enter="search" @keydown.enter="searchOrSelect"
aria-label="Recipient's username"
/> />
</div> </div>
<div v-if="inputValue" class="suggestion-list position-absolute shadow-sm" style="width: 98%"> <div v-if="inputValue" class="search-list position-absolute shadow-sm" style="width: 98%">
<list-row <list-row
v-for="doc in suggestion" v-for="(doc, i) in suggestion"
:key="doc.name" :key="i+1"
:class="doc.seperator ? 'seperator': ''" :ref="i+1"
:route="doc.route"
:class="{ 'seperator': doc.seperator, 'item-active': isFocused(i+1) && !doc.seperator }"
class="d-flex align-items-center" class="d-flex align-items-center"
@click.native="routeTo(doc.route)" @click.native="routeTo(doc.route)"
> >
@ -40,7 +44,8 @@ export default {
data() { data() {
return { return {
inputValue: '', inputValue: '',
suggestion: [] suggestion: [],
currentlyFocused: 0
}; };
}, },
components: { components: {
@ -53,7 +58,31 @@ export default {
} }
}, },
methods: { methods: {
async search() { focus(key) {
this.currentlyFocused = key % (this.suggestion.length + 1);
},
navigate(dir) {
const seperatorIndexes = this.suggestion.map((item, i) => {
if (item.seperator) return i;
});
let nextItem = this.currentlyFocused + (dir === 'up' ? -1 : 1);
if (seperatorIndexes.includes(this.currentlyFocused)) {
nextItem = this.currentlyFocused + (dir === 'up' ? -2 : 2);
}
this.focus(nextItem);
},
isFocused(i) {
if (i === this.currentlyFocused) {
return true;
}
return false;
},
async searchOrSelect() {
if (this.currentlyFocused != 0) {
this.routeTo(this.$refs[this.currentlyFocused][0].$attrs.route);
return;
}
const searchableDoctypes = frappe.getDoctypeList({ const searchableDoctypes = frappe.getDoctypeList({
isSingle: 0, isSingle: 0,
isChild: 0 isChild: 0
@ -73,7 +102,10 @@ export default {
const promises = searchableDoctypes.map(doctype => { const promises = searchableDoctypes.map(doctype => {
return frappe.db.getAll({ return frappe.db.getAll({
doctype, doctype,
filters: { name: ['includes', this.inputValue] }, filters: {
name: ['includes', this.inputValue],
keywords: ['like', this.inputValue]
},
fields: ['name'] fields: ['name']
}); });
}); });
@ -166,10 +198,14 @@ input:focus {
outline: none !important; outline: none !important;
box-shadow: none !important; box-shadow: none !important;
} }
.suggestion-list { .search-list {
z-index: 2; z-index: 2;
max-height: 90vh; max-height: 90vh;
overflow: auto; overflow: auto;
} }
.item-active {
background-color: var(--light);
}
</style> </style>

View File

@ -70,19 +70,20 @@ export default {
setActive() { setActive() {
let currentRoute = this.$route.fullPath; let currentRoute = this.$route.fullPath;
// check each group items // check each group items
this.groups.forEach(title => { this.groups.forEach(groupTitle => {
// filter items which contains the current route // filter items which contains the current route
sidebarConfig.getItems(title).filter(item => { sidebarConfig.getItems(groupTitle).some(item => {
// check for substring 'list' 'SalesInvoice' etc. // check for substring 'list' 'SalesInvoice' etc.
let found = true; let found = false;
currentRoute.split('/').forEach(str => { currentRoute.split('/').some(str => {
if (str.length) { if (str.length) {
item.route.indexOf(str) != -1 ? '' : (found = false); item.route.indexOf(str) > -1 ? (found = true) : (found = false);
}
if (found) {
this.toggleGroup(groupTitle);
return found;
} }
}); });
if (found) {
this.toggleGroup(title);
}
return found; return found;
}); });
}); });
@ -122,6 +123,7 @@ export default {
.page-sidebar { .page-sidebar {
height: 100vh; height: 100vh;
min-width: 208px; min-width: 208px;
max-width: 208px;
} }
.sidebar-item { .sidebar-item {

View File

@ -26,6 +26,13 @@ import Toasted from 'vue-toasted';
frappe.events.on('connect-database', async filepath => { frappe.events.on('connect-database', async filepath => {
await connectToLocalDatabase(filepath); await connectToLocalDatabase(filepath);
const { completed } = await frappe.getSingle('SetupWizard');
if (!completed) {
frappe.events.trigger('show-setup-wizard');
return;
}
const { country } = await frappe.getSingle('AccountingSettings'); const { country } = await frappe.getSingle('AccountingSettings');
if (country === 'India') { if (country === 'India') {
@ -84,8 +91,12 @@ import Toasted from 'vue-toasted';
await setupAccountsAndDashboard(bankName); await setupAccountsAndDashboard(bankName);
await setupRegionalChanges(country); await setupRegionalChanges(country);
await setupWizardValues.set({ completed: 1 });
await setupWizardValues.update();
frappe.events.trigger('show-desk'); frappe.events.trigger('show-desk');
}); });
async function setupAccountsAndDashboard(bankName) { async function setupAccountsAndDashboard(bankName) {
await frappe.call({ await frappe.call({
method: 'import-coa' method: 'import-coa'
@ -98,7 +109,8 @@ import Toasted from 'vue-toasted';
name: bankName, name: bankName,
rootType: 'Asset', rootType: 'Asset',
parentAccount: 'Bank Accounts', parentAccount: 'Bank Accounts',
accountType: 'Bank' accountType: 'Bank',
isGroup: 0
}); });
accountDoc.insert(); accountDoc.insert();

View File

@ -42,8 +42,6 @@
</div> </div>
</template> </template>
<script> <script>
import { setTimeout } from 'timers';
const Branch = { const Branch = {
props: ['label', 'parentValue', 'doctype', 'balance', 'currency', 'rootType'], props: ['label', 'parentValue', 'doctype', 'balance', 'currency', 'rootType'],
data() { data() {
@ -64,9 +62,9 @@ const Branch = {
}, },
creditOrDebit() { creditOrDebit() {
if (['Asset', 'Expense'].includes(this.rootType)) if (['Asset', 'Expense'].includes(this.rootType))
return this.nodeBalance > 0 ? 'Dr' : 'Cr'; return this.nodeBalance >= 0 ? 'Dr' : 'Cr';
return this.nodeBalance > 0 ? 'Cr' : 'Dr'; return this.nodeBalance >= 0 ? 'Cr' : 'Dr';
} }
}, },
components: { components: {

View File

@ -18,12 +18,13 @@ export default {
<style> <style>
.page-container { .page-container {
height: 100vh; height: 100vh;
max-height: 100vh;
width: 100%; width: 100%;
padding-left: 208px; padding-left: 208px;
overflow-x: hidden; overflow-x: hidden;
} }
.sidebar { .sidebar {
position: fixed; position: fixed;
z-index: 1; z-index: 20;
} }
</style> </style>

View File

@ -95,10 +95,10 @@ export default {
this.doc.set('name', ''); this.doc.set('name', '');
} }
if (this.defaults) { if (this.doc._notInserted && this.defaults) {
for (let fieldname in this.defaults) { for (let fieldname in this.defaults) {
const value = this.defaults[fieldname]; const value = this.defaults[fieldname];
this.doc.set(fieldname, value); await this.doc.set(fieldname, value);
} }
} }
@ -106,11 +106,15 @@ export default {
this.doc.on('change', this.setLinks); this.doc.on('change', this.setLinks);
} catch (e) { } catch (e) {
this.notFound = true; this.notFound = true;
this.$router.push({
path: `/`
});
} }
}, },
getFormTitle() { getFormTitle() {
try { try {
// For different list/form based on same doctype since they will have different title // For different list/form based on same doctype
// Since they will have different title
return ( return (
this.meta.getFormTitle(this.doc) || this.meta.label || this.doctype this.meta.getFormTitle(this.doc) || this.meta.label || this.doctype
); );
@ -121,7 +125,7 @@ export default {
getListTitle() { getListTitle() {
try { try {
// For different list/form based on same doctype // For different list/form based on same doctype
// Since they will have different list route // Since they will have different route to their list
return this.meta.getListTitle(this.doc); return this.meta.getListTitle(this.doc);
} catch (e) { } catch (e) {
return this.doctype; return this.doctype;
@ -132,12 +136,11 @@ export default {
if (this.isFormInvalid) return; if (this.isFormInvalid) return;
try { try {
if (this.doc._notInserted) { if (this.doc.isNew()) {
await this.doc.insert(); await this.doc.insert();
} else { } else {
await this.doc.update(); await this.doc.update();
} }
this.$emit('save', this.doc); this.$emit('save', this.doc);
} catch (e) { } catch (e) {
console.error(e); console.error(e);
@ -146,12 +149,12 @@ export default {
}, },
async submit() { async submit() {
this.doc.set('submitted', 1); await this.doc.set('submitted', 1);
try { try {
await this.save(); await this.save();
} catch (e) { } catch (e) {
this.doc.set('submitted', 0); await this.doc.set('submitted', 0);
this.doc.set('_dirty', false); await this.doc.set('_dirty', false);
} }
}, },
@ -160,8 +163,8 @@ export default {
try { try {
await this.save(); await this.save();
} catch (e) { } catch (e) {
this.doc.set('submitted', 1); await this.doc.set('submitted', 1);
this.doc._dirty = false; await this.doc.set('_dirty', false);
} }
}, },

View File

@ -1,5 +1,5 @@
<template> <template>
<div> <div class="report-view">
<div> <div>
<div class="pb-4 d-flex"> <div class="pb-4 d-flex">
<page-header :breadcrumbs="breadcrumbs" style="flex-grow: 1;" /> <page-header :breadcrumbs="breadcrumbs" style="flex-grow: 1;" />
@ -145,4 +145,10 @@ export default {
.datatable { .datatable {
font-size: 12px; font-size: 12px;
} }
.dt-scrollable {
height: 77vh;
}
.report-view {
overflow: hidden;
}
</style> </style>

View File

@ -97,6 +97,14 @@ const config = {
label: _('General Ledger'), label: _('General Ledger'),
route: '/report/general-ledger' route: '/report/general-ledger'
}, },
{
label: _('Profit And Loss'),
route: '/report/profit-and-loss'
},
{
label: _('Balance Sheet'),
route: '/report/balance-sheet'
},
{ {
label: _('Trial Balance'), label: _('Trial Balance'),
route: '/report/trial-balance' route: '/report/trial-balance'

View File

@ -1,7 +1,8 @@
@import "variables.scss"; @import 'variables.scss';
@import "~bootstrap/scss/bootstrap"; @import '~bootstrap/scss/bootstrap';
@import "~frappe-datatable/dist/frappe-datatable.css"; @import '~frappe-datatable/dist/frappe-datatable.css';
html { html {
font-size: 14px; font-size: 14px;
} overflow: hidden;
}