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:
parent
54e115b030
commit
562b4759e0
@ -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();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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']
|
||||||
};
|
};
|
||||||
|
@ -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);
|
||||||
|
@ -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',
|
||||||
|
@ -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');
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
@ -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)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
@ -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';
|
||||||
|
@ -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';
|
||||||
|
@ -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;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@ -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
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
@ -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
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
|
|
||||||
|
@ -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",
|
||||||
|
46
reports/BalanceSheet/viewConfig.js
Normal file
46
reports/BalanceSheet/viewConfig.js
Normal 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;
|
||||||
|
}
|
||||||
|
};
|
@ -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) {
|
||||||
|
@ -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'),
|
||||||
|
@ -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, '\\\\');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
10
src/App.vue
10
src/App.vue
@ -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>
|
||||||
|
@ -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>
|
||||||
|
|
||||||
|
@ -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 {
|
||||||
|
@ -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();
|
||||||
|
|
||||||
|
@ -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: {
|
||||||
|
@ -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>
|
||||||
|
@ -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);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
|
@ -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>
|
||||||
|
@ -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'
|
||||||
|
@ -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;
|
||||||
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user