2
0
mirror of https://github.com/frappe/books.git synced 2024-11-10 07:40:55 +00:00

* Added Country Currency.

* Invoice reverts linked Payments
 * Transactions affects account balance
 * Chart Of Accounts shows account balance
This commit is contained in:
thefalconx33 2019-07-16 12:34:51 +05:30
parent 5032f0397c
commit 96476f56c3
13 changed files with 523 additions and 345 deletions

View File

@ -5,16 +5,38 @@ module.exports = class LedgerPosting {
Object.assign(this, arguments[0]);
this.entries = [];
this.entryMap = {};
// To change balance while entering ledger entries
this.accountEntries = [];
}
debit(account, amount, referenceType, referenceName) {
async debit(account, amount, referenceType, referenceName) {
const entry = this.getEntry(account, referenceType, referenceName);
entry.debit += amount;
await this.setAccountBalanceChange(account, 'debit', amount);
}
credit(account, amount, referenceType, referenceName) {
async credit(account, amount, referenceType, referenceName) {
const entry = this.getEntry(account, referenceType, referenceName);
entry.credit += amount;
await this.setAccountBalanceChange(account, 'credit', amount);
}
async setAccountBalanceChange(accountName, type, amount) {
const debitAccounts = ['Asset', 'Expense'];
const { rootType } = await frappe.getDoc('Account', accountName);
if (debitAccounts.indexOf(rootType) === -1) {
const change = type == 'credit' ? amount : -1 * amount;
this.accountEntries.push({
name: accountName,
balanceChange: change
});
} else {
const change = type == 'debit' ? amount : -1 * amount;
this.accountEntries.push({
name: accountName,
balanceChange: change
});
}
}
getEntry(account, referenceType, referenceName) {
@ -50,6 +72,9 @@ module.exports = class LedgerPosting {
entry.debit = entry.credit;
entry.credit = temp;
}
for (let entry of this.accountEntries) {
entry.balanceChange = -1 * entry.balanceChange;
}
await this.insertEntries();
}
@ -70,7 +95,9 @@ module.exports = class LedgerPosting {
}
if (debit !== credit) {
throw new frappe.errors.ValidationError(frappe._('Debit {0} must be equal to Credit {1}', [debit, credit]));
throw new frappe.errors.ValidationError(
frappe._('Debit {0} must be equal to Credit {1}', [debit, credit])
);
}
}
@ -82,5 +109,10 @@ module.exports = class LedgerPosting {
Object.assign(entryDoc, entry);
await entryDoc.insert();
}
for (let entry of this.accountEntries) {
let entryDoc = await frappe.getDoc('Account', entry.name);
entryDoc.balance += entry.balanceChange;
await entryDoc.update();
}
}
};

View File

@ -1,70 +1,79 @@
const countryList = Object.keys(require('../../../fixtures/countryInfo.json')).sort();
const countryList = Object.keys(
require('../../../fixtures/countryInfo.json')
).sort();
module.exports = {
name: "AccountingSettings",
label: "Accounting Settings",
naming: "name", // {random|autoincrement}
isSingle: 1,
isChild: 0,
isSubmittable: 0,
settings: null,
keywordFields: [],
fields: [{
label: "Company Name",
fieldname: "companyName",
fieldtype: "Data",
required: 1,
disabled: 0
},
name: 'AccountingSettings',
label: 'Accounting Settings',
naming: 'name', // {random|autoincrement}
isSingle: 1,
isChild: 0,
isSubmittable: 0,
settings: null,
keywordFields: [],
fields: [
{
label: 'Company Name',
fieldname: 'companyName',
fieldtype: 'Data',
required: 1,
disabled: 0
},
{
label: "Writeoff Account",
fieldname: "writeOffAccount",
fieldtype: "Account"
},
{
label: 'Writeoff Account',
fieldname: 'writeOffAccount',
fieldtype: 'Account'
},
{
"fieldname": "country",
"label": "Country",
"fieldtype": "Autocomplete",
"required": 1,
getList: () => countryList
},
{
fieldname: 'country',
label: 'Country',
fieldtype: 'Autocomplete',
required: 1,
getList: () => countryList
},
{
"fieldname": "fullname",
"label": "Name",
"fieldtype": "Data",
"required": 1
},
{
fieldname: 'currency',
label: 'Country Currency',
fieldtype: 'Data',
required: 0
},
{
"fieldname": "email",
"label": "Email",
"fieldtype": "Data",
"required": 1
},
{
fieldname: 'fullname',
label: 'Name',
fieldtype: 'Data',
required: 1
},
{
"fieldname": "bankName",
"label": "Bank Name",
"fieldtype": "Data",
"required": 1
},
{
fieldname: 'email',
label: 'Email',
fieldtype: 'Data',
required: 1
},
{
"fieldname": "fiscalYearStart",
"label": "Fiscal Year Start Date",
"fieldtype": "Date",
"required": 1
},
{
fieldname: 'bankName',
label: 'Bank Name',
fieldtype: 'Data',
required: 1
},
{
"fieldname": "fiscalYearEnd",
"label": "Fiscal Year End Date",
"fieldtype": "Date",
"required": 1
},
{
fieldname: 'fiscalYearStart',
label: 'Fiscal Year Start Date',
fieldtype: 'Date',
required: 1
},
]
}
{
fieldname: 'fiscalYearEnd',
label: 'Fiscal Year End Date',
fieldtype: 'Date',
required: 1
}
]
};

View File

@ -23,11 +23,6 @@ export default {
},
'grandTotal',
'date',
{
label: 'INV #',
getValue(doc) {
return doc.name;
}
}
'outstandingAmount'
]
}
};

View File

@ -2,27 +2,57 @@ const Invoice = require('./InvoiceDocument');
const LedgerPosting = require('../../../accounting/ledgerPosting');
module.exports = class InvoiceServer extends Invoice {
getPosting() {
async getPosting() {
let entries = new LedgerPosting({ reference: this, party: this.customer });
entries.debit(this.account, this.grandTotal);
await entries.debit(this.account, this.grandTotal);
for (let item of this.items) {
entries.credit(item.account, item.amount);
await entries.credit(item.account, item.amount);
}
if (this.taxes) {
for (let tax of this.taxes) {
entries.credit(tax.account, tax.amount);
await entries.credit(tax.account, tax.amount);
}
}
return entries;
}
async getPayments() {
let payments = await frappe.db.getAll({
doctype: 'PaymentFor',
fields: ['parent'],
filters: { referenceName: this.name },
orderBy: 'name'
});
if (payments.length != 0) {
return payments;
}
return [];
}
async afterSubmit() {
await this.getPosting().post();
const entries = await this.getPosting();
await entries.post();
await frappe.db.setValue(
'Invoice',
this.name,
'outstandingAmount',
this.grandTotal
);
}
async afterRevert() {
await this.getPosting().postReverse();
let paymentRefList = await this.getPayments();
for (let paymentFor of paymentRefList) {
const paymentReference = paymentFor.parent;
const payment = await frappe.getDoc('Payment', paymentReference);
const paymentEntries = await payment.getPosting();
await paymentEntries.postReverse();
// To set the payment status as unsubmitted.
payment.revert();
}
const entries = await this.getPosting();
await entries.postReverse();
}
};

View File

@ -2,11 +2,9 @@ module.exports = {
name: 'Item',
doctype: 'DocType',
isSingle: 0,
keywordFields: [
'name',
'description'
],
fields: [{
keywordFields: ['name', 'description'],
fields: [
{
fieldname: 'name',
label: 'Item Name',
fieldtype: 'Data',
@ -22,20 +20,20 @@ module.exports = {
label: 'Unit',
fieldtype: 'Select',
default: 'No',
options: [
'No',
'Kg',
'Gram',
'Hour',
'Day'
]
options: ['No', 'Kg', 'Gram', 'Hour', 'Day']
},
{
fieldname: 'incomeAccount',
label: 'Income Account',
fieldtype: 'Link',
target: 'Account',
required: 1
required: 1,
getFilters: (query, control) => {
return {
isGroup: 0,
accountType: 'Income Account'
};
}
},
{
fieldname: 'expenseAccount',
@ -58,7 +56,8 @@ module.exports = {
layout: [
// section 1
{
columns: [{
columns: [
{
fields: ['name', 'unit']
},
{
@ -69,15 +68,18 @@ module.exports = {
// section 2
{
columns: [{
fields: ['description']
}]
columns: [
{
fields: ['description']
}
]
},
// section 3
{
title: 'Accounting',
columns: [{
columns: [
{
fields: ['incomeAccount', 'expenseAccount']
},
{

View File

@ -3,28 +3,48 @@ const frappe = require('frappejs');
const LedgerPosting = require('../../../accounting/ledgerPosting');
module.exports = class PaymentServer extends BaseDocument {
getPosting() {
let entries = new LedgerPosting({reference: this, party: this.party});
entries.debit(this.paymentAccount, this.amount);
async getPosting() {
let entries = new LedgerPosting({ reference: this, party: this.party });
await entries.debit(this.paymentAccount, this.amount);
for (let row of this.for) {
entries.credit(this.account, row.amount, row.referenceType, row.referenceName);
for (let row of this.for) {
await entries.credit(
this.account,
row.amount,
row.referenceType,
row.referenceName
);
}
return entries;
}
async afterSubmit() {
for (let row of this.for) {
if (row.referenceType === 'Invoice') {
const { outstandingAmount } = await frappe.getDoc(
'Invoice',
row.referenceName
);
if (this.amount > outstandingAmount) {
console.log('Over Payment');
} else {
await frappe.db.setValue(
'Invoice',
row.referenceName,
'outstandingAmount',
outstandingAmount - this.amount
);
const entries = await this.getPosting();
await entries.post();
}
return entries;
}
}
}
async afterSubmit() {
await this.getPosting().post();
for (let row of this.for) {
if (row.referenceType === 'Invoice') {
await frappe.db.setValue('Invoice', row.referenceName, 'outstandingAmount', 0.0);
}
}
}
async afterRevert() {
const entries = await this.getPosting();
await entries.postReverse();
async afterRevert() {
await this.getPosting().postReverse();
}
}
// Maybe revert outstanding amount of invoice too?
}
};

View File

@ -1,102 +1,128 @@
const countryList = require('../../../fixtures/countryInfo.json');
module.exports = {
name: "SetupWizard",
label: "Setup Wizard",
naming: "name",
isSingle: 1,
isChild: 0,
isSubmittable: 0,
settings: null,
keywordFields: [],
fields: [{
fieldname: 'country',
label: 'Country',
fieldtype: 'Autocomplete',
required: 1,
getList: () => Object.keys(countryList).sort()
},
name: 'SetupWizard',
label: 'Setup Wizard',
naming: 'name',
isSingle: 1,
isChild: 0,
isSubmittable: 0,
settings: null,
keywordFields: [],
fields: [
{
fieldname: 'country',
label: 'Country',
fieldtype: 'Autocomplete',
required: 1,
getList: () => Object.keys(countryList).sort()
},
{
fieldname: 'fullname',
label: 'Name',
fieldtype: 'Data',
required: 1
},
{
fieldname: 'fullname',
label: 'Name',
fieldtype: 'Data',
required: 1
},
{
fieldname: 'email',
label: 'Email',
fieldtype: 'Data',
required: 1,
inputType: 'email'
},
{
fieldname: 'email',
label: 'Email',
fieldtype: 'Data',
required: 1,
inputType: 'email'
},
{
fieldname: 'companyName',
label: 'Company Name',
fieldtype: 'Data',
required: 1
},
{
fieldname: 'companyName',
label: 'Company Name',
fieldtype: 'Data',
required: 1
},
{
fieldname: 'bankName',
label: 'Bank Name',
fieldtype: 'Data',
required: 1
},
{
fieldname: 'bankName',
label: 'Bank Name',
fieldtype: 'Data',
required: 1
},
{
fieldname: 'fiscalYearStart',
label: 'Fiscal Year Start Date',
fieldtype: 'Date',
formula: (doc) => {
let date = countryList[doc.country]["fiscal_year_start"].split("-");
var currentYear = (new Date).getFullYear();
let currentMonth = date[0] - 1 ;
let currentDate = date[1];
return new Date(currentYear,currentMonth,currentDate).toISOString().substr(0, 10);;
},
required: 1
},
{
fieldname: 'fiscalYearStart',
label: 'Fiscal Year Start Date',
fieldtype: 'Date',
formula: doc => {
let date = countryList[doc.country]['fiscal_year_start'].split('-');
var currentYear = new Date().getFullYear();
let currentMonth = date[0] - 1;
let currentDate = date[1];
return new Date(currentYear, currentMonth, currentDate)
.toISOString()
.substr(0, 10);
},
required: 1
},
{
fieldname: 'fiscalYearEnd',
label: 'Fiscal Year End Date',
fieldtype: 'Date',
formula: (doc) => {
let date = countryList[doc.country]["fiscal_year_end"].split("-");
var currentYear = (new Date).getFullYear() + 1 ;
let currentMonth = date[0] - 1 ;
let currentDate = date[1];
return new Date(currentYear,currentMonth,currentDate).toISOString().substr(0, 10);;
},
required: 1
}
],
layout: {
paginated: true,
sections: [{
title: 'Select Country',
columns: [{
fields: ['country']
}]
},
{
title: 'Add a Profile',
columns: [{
fields: ['fullname', 'email']
}]
},
{
title: 'Add your Company',
columns: [{
fields: ['companyName', 'bankName', 'fiscalYearStart', 'fiscalYearEnd']
}]
}
].filter(Boolean)
{
fieldname: 'fiscalYearEnd',
label: 'Fiscal Year End Date',
fieldtype: 'Date',
formula: doc => {
let date = countryList[doc.country]['fiscal_year_end'].split('-');
var currentYear = new Date().getFullYear() + 1;
let currentMonth = date[0] - 1;
let currentDate = date[1];
return new Date(currentYear, currentMonth, currentDate)
.toISOString()
.substr(0, 10);
},
required: 1
},
{
fieldname: 'currency',
label: 'Currency',
fieldtype: 'Currency',
formula: doc => {
return countryList[doc.country]['currency'];
},
required: 1
}
}
],
layout: {
paginated: true,
sections: [
{
title: 'Select Country',
columns: [
{
fields: ['country']
}
]
},
{
title: 'Add a Profile',
columns: [
{
fields: ['fullname', 'email']
}
]
},
{
title: 'Add your Company',
columns: [
{
fields: [
'companyName',
'bankName',
'fiscalYearStart',
'fiscalYearEnd'
]
}
]
}
].filter(Boolean)
}
};

View File

@ -3,67 +3,75 @@ const path = require('path');
const fs = require('fs');
const countries = require('../../../fixtures/countryInfo.json');
const standardCOA = require('../../../fixtures/verified/standardCOA.json');
const accountFields = ['accountType', 'rootType', 'isGroup', 'account_type', 'root_type', 'is_group'];
const accountFields = [
'accountType',
'rootType',
'isGroup',
'account_type',
'root_type',
'is_group'
];
async function importAccounts(children, parent, rootType, rootAccount) {
for (let accountName in children) {
const child = children[accountName];
for (let accountName in children) {
const child = children[accountName];
if (rootAccount) {
rootType = child.rootType || child.root_type;
}
if (!accountFields.includes(accountName)) {
let isGroup = identifyIsGroup(child);
const doc = frappe.newDoc({
doctype: 'Account',
name: accountName,
parentAccount: parent,
isGroup,
rootType,
balance: 0,
accountType: child.accountType
})
await doc.insert()
await importAccounts(child, accountName, rootType)
}
if (rootAccount) {
rootType = child.rootType || child.root_type;
}
if (!accountFields.includes(accountName)) {
let isGroup = identifyIsGroup(child);
const doc = frappe.newDoc({
doctype: 'Account',
name: accountName,
parentAccount: parent,
isGroup,
rootType,
balance: 0,
accountType: child.accountType || child.account_type
});
await doc.insert();
await importAccounts(child, accountName, rootType);
}
}
}
function identifyIsGroup(child) {
if (child.isGroup || child.is_group) {
return child.isGroup || child.is_group;
}
if (child.isGroup || child.is_group) {
return child.isGroup || child.is_group;
}
const keys = Object.keys(child);
const children = keys.filter(key => !accountFields.includes(key))
const keys = Object.keys(child);
const children = keys.filter(key => !accountFields.includes(key));
if (children.length) {
return 1;
}
if (children.length) {
return 1;
}
return 0;
return 0;
}
async function getCountryCOA(){
const doc = await frappe.getDoc('AccountingSettings');
const conCode = countries[doc.country].code;
async function getCountryCOA() {
const doc = await frappe.getDoc('AccountingSettings');
const conCode = countries[doc.country].code;
const countryCOA = path.resolve(path.join('./fixtures/verified/', conCode + '.json'));
const countryCOA = path.resolve(
path.join('./fixtures/verified/', conCode + '.json')
);
if(fs.existsSync(countryCOA)){
const jsonText = fs.readFileSync(countryCOA, 'utf-8');
const json = JSON.parse(jsonText);
return json.tree;
} else {
return standardCOA;
}
if (fs.existsSync(countryCOA)) {
const jsonText = fs.readFileSync(countryCOA, 'utf-8');
const json = JSON.parse(jsonText);
return json.tree;
} else {
return standardCOA;
}
}
module.exports = async function importCharts() {
const chart = await getCountryCOA();
await importAccounts(chart, '', '', true)
}
const chart = await getCountryCOA();
await importAccounts(chart, '', '', true);
};

View File

@ -6,10 +6,7 @@ import common from 'frappejs/common';
import coreModels from 'frappejs/models';
import models from '../models';
import postStart from '../server/postStart';
import {
getSettings,
saveSettings
} from '../electron/settings';
import { getSettings, saveSettings } from '../electron/settings';
// vue imports
import Vue from 'vue';
@ -26,35 +23,34 @@ import Toasted from 'vue-toasted';
frappe.registerModels(coreModels);
frappe.registerModels(models);
frappe.fetch = window.fetch.bind();
frappe.events.on('connect-database', async (filepath) => {
frappe.events.on('connect-database', async filepath => {
await connectToLocalDatabase(filepath);
const accountingSettings = await frappe.getSingle('AccountingSettings');
const country = accountingSettings.country;
const { country } = await frappe.getSingle('AccountingSettings');
if (country === "India") {
frappe.models.Party = require('../models/doctype/Party/RegionalChanges.js')
if (country === 'India') {
frappe.models.Party = require('../models/doctype/Party/RegionalChanges.js');
} else {
frappe.models.Party = require('../models/doctype/Party/Party.js')
frappe.models.Party = require('../models/doctype/Party/Party.js');
}
frappe.events.trigger('show-desk');
});
frappe.events.on('DatabaseSelector:file-selected', async (filepath) => {
frappe.events.on('DatabaseSelector:file-selected', async filepath => {
await connectToLocalDatabase(filepath);
localStorage.dbPath = filepath;
const accountingSettings = await frappe.getSingle('AccountingSettings');
if (!accountingSettings.companyName) {
const { companyName } = await frappe.getSingle('AccountingSettings');
if (!companyName) {
frappe.events.trigger('show-setup-wizard');
} else {
frappe.events.trigger('show-desk');
}
});
frappe.events.on('SetupWizard:setup-complete', async (setupWizardValues) => {
frappe.events.on('SetupWizard:setup-complete', async setupWizardValues => {
const countryList = require('../fixtures/countryInfo.json');
const {
companyName,
country,
@ -73,7 +69,8 @@ import Toasted from 'vue-toasted';
email,
bankName,
fiscalYearStart,
fiscalYearEnd
fiscalYearEnd,
currency: countryList[country]['currency']
});
await doc.update();
@ -81,9 +78,9 @@ import Toasted from 'vue-toasted';
method: 'import-coa'
});
if (country === "India") {
frappe.models.Party = require('../models/doctype/Party/RegionalChanges.js')
await frappe.db.migrate()
if (country === 'India') {
frappe.models.Party = require('../models/doctype/Party/RegionalChanges.js');
await frappe.db.migrate();
await generateGstTaxes();
}
frappe.events.trigger('show-desk');
@ -98,25 +95,28 @@ import Toasted from 'vue-toasted';
case 'Out of State':
await newTax.set({
name: `${type}-${percent}`,
details: [{
account: "IGST",
rate: percent
}]
})
details: [
{
account: 'IGST',
rate: percent
}
]
});
break;
case 'In State':
await newTax.set({
name: `${type}-${percent}`,
details: [{
account: "CGST",
details: [
{
account: 'CGST',
rate: percent / 2
},
{
account: "SGST",
account: 'SGST',
rate: percent / 2
}
]
})
});
break;
}
await newTax.insert();
@ -124,11 +124,13 @@ import Toasted from 'vue-toasted';
}
await newTax.set({
name: `Exempt-0`,
details: [{
account: "Exempt",
rate: 0
}]
})
details: [
{
account: 'Exempt',
rate: 0
}
]
});
await newTax.insert();
}
@ -147,7 +149,6 @@ import Toasted from 'vue-toasted';
}
}
window.frappe = frappe;
Vue.config.productionTip = false;
@ -166,4 +167,4 @@ import Toasted from 'vue-toasted';
},
template: '<App/>'
});
})()
})();

View File

@ -26,46 +26,50 @@ frappe.db.bindSocketClient(socket);
frappe.getSingle('SystemSettings');
registerReportMethods();
frappe.getSingle('AccountingSettings')
.then(accountingSettings => {
if (router.currentRoute.fullPath !== '/') return;
frappe.getSingle('AccountingSettings').then(accountingSettings => {
if (router.currentRoute.fullPath !== '/') return;
if (accountingSettings.companyName) {
frappe.events.trigger('show-desk');
} else {
frappe.events.trigger('show-setup-wizard');
}
});
frappe.events.on('SetupWizard:setup-complete', async ({ setupWizardValues }) => {
const {
companyName,
country,
name,
email,
abbreviation,
bankName,
fiscalYearStart,
fiscalYearEnd
} = setupWizardValues;
const doc = await frappe.getSingle('AccountingSettings');
await doc.set({
companyName,
country,
fullname: name,
email,
bankName,
fiscalYearStart,
fiscalYearEnd
});
await doc.update();
await frappe.call({ method: 'import-coa' });
frappe.events.trigger('show-desk');
if (accountingSettings.companyName) {
frappe.events.trigger('show-desk');
} else {
frappe.events.trigger('show-setup-wizard');
}
});
frappe.events.on(
'SetupWizard:setup-complete',
async ({ setupWizardValues }) => {
const countryList = require('../fixtures/countryInfo.json');
const {
companyName,
country,
name,
email,
abbreviation,
bankName,
fiscalYearStart,
fiscalYearEnd
} = setupWizardValues;
const doc = await frappe.getSingle('AccountingSettings');
await doc.set({
companyName,
country,
fullname: name,
email,
bankName,
fiscalYearStart,
fiscalYearEnd,
currency: countryList[country]['currency']
});
await doc.update();
await frappe.call({ method: 'import-coa' });
frappe.events.trigger('show-desk');
}
);
window.frappe = frappe;
Vue.config.productionTip = false;

View File

@ -5,47 +5,69 @@
<feather-icon class="mr-1" :name="iconName" v-show="iconName" />
<span>{{ label }}</span>
<div class="ml-auto d-flex align-items-center">
<feather-icon v-if="balance !== ''" style="width:15px; height:15px" name="dollar-sign"/>
<span>{{ balance }}</span>
<span>
{{ currency }}
<span style="font-weight: 800">{{ computedBalance }}</span>
</span>
</div>
</div>
</div>
<div :class="['branch-children', expanded ? '' : 'd-none']">
<branch v-for="child in children" :key="child.label"
<branch
v-for="child in children"
:key="child.label"
:label="child.label"
:balance="child.balance"
:parentValue="child.name"
:doctype="doctype"
:currency="currency"
@updateBalance="updateBalance"
/>
</div>
</div>
</template>
<script>
const Branch = {
props: ['label', 'parentValue', 'doctype', 'balance'],
props: ['label', 'parentValue', 'doctype', 'balance', 'currency'],
data() {
return {
expanded: false,
children: null
}
children: null,
nodeBalance: this.balance
};
},
computed: {
iconName() {
if (this.children && this.children.length ==0) return 'chevron-right';
if (this.children && this.children.length == 0) return 'chevron-right';
return this.expanded ? 'chevron-down' : 'chevron-right';
},
computedBalance() {
return this.nodeBalance;
}
},
components: {
Branch: () => Promise.resolve(Branch)
},
mounted() {
async mounted() {
this.settings = frappe.getMeta(this.doctype).treeSettings;
if (this.nodeBalance > 0) {
this.$emit('updateBalance', this.nodeBalance);
}
await this.toggleChildren();
this.expanded = !this.expanded;
if (this.label === (await this.settings.getRootLabel())) {
await this.toggleChildren();
}
},
methods: {
async toggleChildren() {
await this.getChildren();
this.expanded = !this.expanded;
},
updateBalance(balance) {
this.nodeBalance += balance;
this.$emit('updateBalance', this.nodeBalance);
},
async getChildren() {
if (this.children) return;
@ -65,7 +87,7 @@ const Branch = {
this.children = children.map(c => {
c.label = c.name;
c.balance = c.balance
c.balance = c.balance;
return c;
});
}
@ -75,7 +97,7 @@ const Branch = {
export default Branch;
</script>
<style lang="scss">
@import "../../styles/variables";
@import '../../styles/variables';
.branch {
font-size: 1rem;

View File

@ -1,28 +1,42 @@
<template>
<div class="p-3" v-if="root">
<branch :label="root.label" :balance="root.balance" :parentValue="''" :doctype="doctype" ref="root"/>
<branch
:label="root.label"
:balance="root.balance"
:parentValue="''"
:doctype="doctype"
ref="root"
:currency="root.currency"
@updateBalance="updateBalance"
/>
</div>
</template>
<script>
import frappe from 'frappejs';
import Branch from './Branch';
import { setTimeout } from 'timers';
export default {
components: {
Branch,
Branch
},
data() {
return {
root: null,
doctype: "Account"
doctype: 'Account'
};
},
computed: {
rootBalance() {
return this.root.balance;
}
},
async mounted() {
this.settings = frappe.getMeta(this.doctype).treeSettings;
const { currency } = await frappe.getSingle('AccountingSettings');
this.root = {
label: await this.settings.getRootLabel(),
balance: 'Net Worth'
balance: 0,
currency
};
},
methods: {
@ -44,7 +58,10 @@ export default {
c.balance = c.balance;
return c;
});
},
updateBalance(balance) {
this.root.balance += balance;
}
}
}
};
</script>

View File

@ -1,6 +1,6 @@
<template>
<div class="bg-light">
<div class="form-container col-8 bg-white mt-4 ml-auto mr-auto border p-5">
<div class="form-container col-10 bg-white mt-4 ml-auto mr-auto border p-5">
<form-actions
v-if="shouldRenderForm"
:doc="doc"
@ -10,7 +10,7 @@
@print="print"
:links="links"
/>
<hr class="mb-3">
<hr class="mb-3" />
<form-layout
v-if="shouldRenderForm"
:doc="doc"
@ -87,10 +87,9 @@ export default {
this.setLinks();
this.doc.on('change', this.setLinks);
} catch (e) {
this.notFound = true;
this.$router.push(`/list/${this.doctype}`)//if reloaded while insert new Item,Invoice etc form.
this.$router.push(`/list/${this.doctype}`); //if reloaded while insert new Item,Invoice etc form.
}
},
async save() {
@ -148,3 +147,16 @@ export default {
}
};
</script>
<style>
/* FIX: For table cell expanding when active */
.table-cell {
min-height: 58px;
}
.table-cell > div {
margin-top: 6px;
}
.table th,
.table td {
vertical-align: middle;
}
</style>