mirror of
https://github.com/frappe/books.git
synced 2025-01-11 02:36:14 +00:00
* Added Country Currency.
* Invoice reverts linked Payments * Transactions affects account balance * Chart Of Accounts shows account balance
This commit is contained in:
parent
5032f0397c
commit
96476f56c3
@ -5,16 +5,38 @@ module.exports = class LedgerPosting {
|
|||||||
Object.assign(this, arguments[0]);
|
Object.assign(this, arguments[0]);
|
||||||
this.entries = [];
|
this.entries = [];
|
||||||
this.entryMap = {};
|
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);
|
const entry = this.getEntry(account, referenceType, referenceName);
|
||||||
entry.debit += amount;
|
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);
|
const entry = this.getEntry(account, referenceType, referenceName);
|
||||||
entry.credit += amount;
|
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) {
|
getEntry(account, referenceType, referenceName) {
|
||||||
@ -50,6 +72,9 @@ module.exports = class LedgerPosting {
|
|||||||
entry.debit = entry.credit;
|
entry.debit = entry.credit;
|
||||||
entry.credit = temp;
|
entry.credit = temp;
|
||||||
}
|
}
|
||||||
|
for (let entry of this.accountEntries) {
|
||||||
|
entry.balanceChange = -1 * entry.balanceChange;
|
||||||
|
}
|
||||||
await this.insertEntries();
|
await this.insertEntries();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -70,7 +95,9 @@ module.exports = class LedgerPosting {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (debit !== credit) {
|
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);
|
Object.assign(entryDoc, entry);
|
||||||
await entryDoc.insert();
|
await entryDoc.insert();
|
||||||
}
|
}
|
||||||
|
for (let entry of this.accountEntries) {
|
||||||
|
let entryDoc = await frappe.getDoc('Account', entry.name);
|
||||||
|
entryDoc.balance += entry.balanceChange;
|
||||||
|
await entryDoc.update();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@ -1,70 +1,79 @@
|
|||||||
const countryList = Object.keys(require('../../../fixtures/countryInfo.json')).sort();
|
const countryList = Object.keys(
|
||||||
|
require('../../../fixtures/countryInfo.json')
|
||||||
|
).sort();
|
||||||
|
|
||||||
module.exports = {
|
module.exports = {
|
||||||
name: "AccountingSettings",
|
name: 'AccountingSettings',
|
||||||
label: "Accounting Settings",
|
label: 'Accounting Settings',
|
||||||
naming: "name", // {random|autoincrement}
|
naming: 'name', // {random|autoincrement}
|
||||||
isSingle: 1,
|
isSingle: 1,
|
||||||
isChild: 0,
|
isChild: 0,
|
||||||
isSubmittable: 0,
|
isSubmittable: 0,
|
||||||
settings: null,
|
settings: null,
|
||||||
keywordFields: [],
|
keywordFields: [],
|
||||||
fields: [{
|
fields: [
|
||||||
label: "Company Name",
|
{
|
||||||
fieldname: "companyName",
|
label: 'Company Name',
|
||||||
fieldtype: "Data",
|
fieldname: 'companyName',
|
||||||
|
fieldtype: 'Data',
|
||||||
required: 1,
|
required: 1,
|
||||||
disabled: 0
|
disabled: 0
|
||||||
},
|
},
|
||||||
|
|
||||||
{
|
{
|
||||||
label: "Writeoff Account",
|
label: 'Writeoff Account',
|
||||||
fieldname: "writeOffAccount",
|
fieldname: 'writeOffAccount',
|
||||||
fieldtype: "Account"
|
fieldtype: 'Account'
|
||||||
},
|
},
|
||||||
|
|
||||||
{
|
{
|
||||||
"fieldname": "country",
|
fieldname: 'country',
|
||||||
"label": "Country",
|
label: 'Country',
|
||||||
"fieldtype": "Autocomplete",
|
fieldtype: 'Autocomplete',
|
||||||
"required": 1,
|
required: 1,
|
||||||
getList: () => countryList
|
getList: () => countryList
|
||||||
},
|
},
|
||||||
|
|
||||||
{
|
{
|
||||||
"fieldname": "fullname",
|
fieldname: 'currency',
|
||||||
"label": "Name",
|
label: 'Country Currency',
|
||||||
"fieldtype": "Data",
|
fieldtype: 'Data',
|
||||||
"required": 1
|
required: 0
|
||||||
},
|
},
|
||||||
|
|
||||||
{
|
{
|
||||||
"fieldname": "email",
|
fieldname: 'fullname',
|
||||||
"label": "Email",
|
label: 'Name',
|
||||||
"fieldtype": "Data",
|
fieldtype: 'Data',
|
||||||
"required": 1
|
required: 1
|
||||||
},
|
},
|
||||||
|
|
||||||
{
|
{
|
||||||
"fieldname": "bankName",
|
fieldname: 'email',
|
||||||
"label": "Bank Name",
|
label: 'Email',
|
||||||
"fieldtype": "Data",
|
fieldtype: 'Data',
|
||||||
"required": 1
|
required: 1
|
||||||
},
|
},
|
||||||
|
|
||||||
{
|
{
|
||||||
"fieldname": "fiscalYearStart",
|
fieldname: 'bankName',
|
||||||
"label": "Fiscal Year Start Date",
|
label: 'Bank Name',
|
||||||
"fieldtype": "Date",
|
fieldtype: 'Data',
|
||||||
"required": 1
|
required: 1
|
||||||
},
|
},
|
||||||
|
|
||||||
{
|
{
|
||||||
"fieldname": "fiscalYearEnd",
|
fieldname: 'fiscalYearStart',
|
||||||
"label": "Fiscal Year End Date",
|
label: 'Fiscal Year Start Date',
|
||||||
"fieldtype": "Date",
|
fieldtype: 'Date',
|
||||||
"required": 1
|
required: 1
|
||||||
},
|
},
|
||||||
|
|
||||||
]
|
{
|
||||||
|
fieldname: 'fiscalYearEnd',
|
||||||
|
label: 'Fiscal Year End Date',
|
||||||
|
fieldtype: 'Date',
|
||||||
|
required: 1
|
||||||
}
|
}
|
||||||
|
]
|
||||||
|
};
|
||||||
|
@ -23,11 +23,6 @@ export default {
|
|||||||
},
|
},
|
||||||
'grandTotal',
|
'grandTotal',
|
||||||
'date',
|
'date',
|
||||||
{
|
'outstandingAmount'
|
||||||
label: 'INV #',
|
|
||||||
getValue(doc) {
|
|
||||||
return doc.name;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
]
|
]
|
||||||
}
|
};
|
||||||
|
@ -2,27 +2,57 @@ const Invoice = require('./InvoiceDocument');
|
|||||||
const LedgerPosting = require('../../../accounting/ledgerPosting');
|
const LedgerPosting = require('../../../accounting/ledgerPosting');
|
||||||
|
|
||||||
module.exports = class InvoiceServer extends Invoice {
|
module.exports = class InvoiceServer extends Invoice {
|
||||||
getPosting() {
|
async getPosting() {
|
||||||
let entries = new LedgerPosting({ reference: this, party: this.customer });
|
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) {
|
for (let item of this.items) {
|
||||||
entries.credit(item.account, item.amount);
|
await entries.credit(item.account, item.amount);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this.taxes) {
|
if (this.taxes) {
|
||||||
for (let tax of this.taxes) {
|
for (let tax of this.taxes) {
|
||||||
entries.credit(tax.account, tax.amount);
|
await entries.credit(tax.account, tax.amount);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return entries;
|
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() {
|
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() {
|
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();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@ -2,11 +2,9 @@ module.exports = {
|
|||||||
name: 'Item',
|
name: 'Item',
|
||||||
doctype: 'DocType',
|
doctype: 'DocType',
|
||||||
isSingle: 0,
|
isSingle: 0,
|
||||||
keywordFields: [
|
keywordFields: ['name', 'description'],
|
||||||
'name',
|
fields: [
|
||||||
'description'
|
{
|
||||||
],
|
|
||||||
fields: [{
|
|
||||||
fieldname: 'name',
|
fieldname: 'name',
|
||||||
label: 'Item Name',
|
label: 'Item Name',
|
||||||
fieldtype: 'Data',
|
fieldtype: 'Data',
|
||||||
@ -22,20 +20,20 @@ module.exports = {
|
|||||||
label: 'Unit',
|
label: 'Unit',
|
||||||
fieldtype: 'Select',
|
fieldtype: 'Select',
|
||||||
default: 'No',
|
default: 'No',
|
||||||
options: [
|
options: ['No', 'Kg', 'Gram', 'Hour', 'Day']
|
||||||
'No',
|
|
||||||
'Kg',
|
|
||||||
'Gram',
|
|
||||||
'Hour',
|
|
||||||
'Day'
|
|
||||||
]
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
fieldname: 'incomeAccount',
|
fieldname: 'incomeAccount',
|
||||||
label: 'Income Account',
|
label: 'Income Account',
|
||||||
fieldtype: 'Link',
|
fieldtype: 'Link',
|
||||||
target: 'Account',
|
target: 'Account',
|
||||||
required: 1
|
required: 1,
|
||||||
|
getFilters: (query, control) => {
|
||||||
|
return {
|
||||||
|
isGroup: 0,
|
||||||
|
accountType: 'Income Account'
|
||||||
|
};
|
||||||
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
fieldname: 'expenseAccount',
|
fieldname: 'expenseAccount',
|
||||||
@ -58,7 +56,8 @@ module.exports = {
|
|||||||
layout: [
|
layout: [
|
||||||
// section 1
|
// section 1
|
||||||
{
|
{
|
||||||
columns: [{
|
columns: [
|
||||||
|
{
|
||||||
fields: ['name', 'unit']
|
fields: ['name', 'unit']
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@ -69,15 +68,18 @@ module.exports = {
|
|||||||
|
|
||||||
// section 2
|
// section 2
|
||||||
{
|
{
|
||||||
columns: [{
|
columns: [
|
||||||
|
{
|
||||||
fields: ['description']
|
fields: ['description']
|
||||||
}]
|
}
|
||||||
|
]
|
||||||
},
|
},
|
||||||
|
|
||||||
// section 3
|
// section 3
|
||||||
{
|
{
|
||||||
title: 'Accounting',
|
title: 'Accounting',
|
||||||
columns: [{
|
columns: [
|
||||||
|
{
|
||||||
fields: ['incomeAccount', 'expenseAccount']
|
fields: ['incomeAccount', 'expenseAccount']
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
@ -3,28 +3,48 @@ const frappe = require('frappejs');
|
|||||||
const LedgerPosting = require('../../../accounting/ledgerPosting');
|
const LedgerPosting = require('../../../accounting/ledgerPosting');
|
||||||
|
|
||||||
module.exports = class PaymentServer extends BaseDocument {
|
module.exports = class PaymentServer extends BaseDocument {
|
||||||
getPosting() {
|
async getPosting() {
|
||||||
let entries = new LedgerPosting({ reference: this, party: this.party });
|
let entries = new LedgerPosting({ reference: this, party: this.party });
|
||||||
entries.debit(this.paymentAccount, this.amount);
|
await entries.debit(this.paymentAccount, this.amount);
|
||||||
|
|
||||||
for (let row of this.for) {
|
for (let row of this.for) {
|
||||||
entries.credit(this.account, row.amount, row.referenceType, row.referenceName);
|
await entries.credit(
|
||||||
|
this.account,
|
||||||
|
row.amount,
|
||||||
|
row.referenceType,
|
||||||
|
row.referenceName
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
return entries;
|
return entries;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
async afterSubmit() {
|
async afterSubmit() {
|
||||||
await this.getPosting().post();
|
|
||||||
for (let row of this.for) {
|
for (let row of this.for) {
|
||||||
if (row.referenceType === 'Invoice') {
|
if (row.referenceType === 'Invoice') {
|
||||||
await frappe.db.setValue('Invoice', row.referenceName, 'outstandingAmount', 0.0);
|
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();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async afterRevert() {
|
async afterRevert() {
|
||||||
await this.getPosting().postReverse();
|
const entries = await this.getPosting();
|
||||||
}
|
await entries.postReverse();
|
||||||
|
|
||||||
|
// Maybe revert outstanding amount of invoice too?
|
||||||
}
|
}
|
||||||
|
};
|
||||||
|
@ -1,15 +1,16 @@
|
|||||||
const countryList = require('../../../fixtures/countryInfo.json');
|
const countryList = require('../../../fixtures/countryInfo.json');
|
||||||
|
|
||||||
module.exports = {
|
module.exports = {
|
||||||
name: "SetupWizard",
|
name: 'SetupWizard',
|
||||||
label: "Setup Wizard",
|
label: 'Setup Wizard',
|
||||||
naming: "name",
|
naming: 'name',
|
||||||
isSingle: 1,
|
isSingle: 1,
|
||||||
isChild: 0,
|
isChild: 0,
|
||||||
isSubmittable: 0,
|
isSubmittable: 0,
|
||||||
settings: null,
|
settings: null,
|
||||||
keywordFields: [],
|
keywordFields: [],
|
||||||
fields: [{
|
fields: [
|
||||||
|
{
|
||||||
fieldname: 'country',
|
fieldname: 'country',
|
||||||
label: 'Country',
|
label: 'Country',
|
||||||
fieldtype: 'Autocomplete',
|
fieldtype: 'Autocomplete',
|
||||||
@ -50,12 +51,14 @@ module.exports = {
|
|||||||
fieldname: 'fiscalYearStart',
|
fieldname: 'fiscalYearStart',
|
||||||
label: 'Fiscal Year Start Date',
|
label: 'Fiscal Year Start Date',
|
||||||
fieldtype: 'Date',
|
fieldtype: 'Date',
|
||||||
formula: (doc) => {
|
formula: doc => {
|
||||||
let date = countryList[doc.country]["fiscal_year_start"].split("-");
|
let date = countryList[doc.country]['fiscal_year_start'].split('-');
|
||||||
var currentYear = (new Date).getFullYear();
|
var currentYear = new Date().getFullYear();
|
||||||
let currentMonth = date[0] - 1;
|
let currentMonth = date[0] - 1;
|
||||||
let currentDate = date[1];
|
let currentDate = date[1];
|
||||||
return new Date(currentYear,currentMonth,currentDate).toISOString().substr(0, 10);;
|
return new Date(currentYear, currentMonth, currentDate)
|
||||||
|
.toISOString()
|
||||||
|
.substr(0, 10);
|
||||||
},
|
},
|
||||||
required: 1
|
required: 1
|
||||||
},
|
},
|
||||||
@ -64,12 +67,23 @@ module.exports = {
|
|||||||
fieldname: 'fiscalYearEnd',
|
fieldname: 'fiscalYearEnd',
|
||||||
label: 'Fiscal Year End Date',
|
label: 'Fiscal Year End Date',
|
||||||
fieldtype: 'Date',
|
fieldtype: 'Date',
|
||||||
formula: (doc) => {
|
formula: doc => {
|
||||||
let date = countryList[doc.country]["fiscal_year_end"].split("-");
|
let date = countryList[doc.country]['fiscal_year_end'].split('-');
|
||||||
var currentYear = (new Date).getFullYear() + 1 ;
|
var currentYear = new Date().getFullYear() + 1;
|
||||||
let currentMonth = date[0] - 1;
|
let currentMonth = date[0] - 1;
|
||||||
let currentDate = date[1];
|
let currentDate = date[1];
|
||||||
return new Date(currentYear,currentMonth,currentDate).toISOString().substr(0, 10);;
|
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
|
required: 1
|
||||||
}
|
}
|
||||||
@ -77,26 +91,38 @@ module.exports = {
|
|||||||
|
|
||||||
layout: {
|
layout: {
|
||||||
paginated: true,
|
paginated: true,
|
||||||
sections: [{
|
sections: [
|
||||||
|
{
|
||||||
title: 'Select Country',
|
title: 'Select Country',
|
||||||
columns: [{
|
columns: [
|
||||||
|
{
|
||||||
fields: ['country']
|
fields: ['country']
|
||||||
}]
|
}
|
||||||
|
]
|
||||||
},
|
},
|
||||||
|
|
||||||
{
|
{
|
||||||
title: 'Add a Profile',
|
title: 'Add a Profile',
|
||||||
columns: [{
|
columns: [
|
||||||
|
{
|
||||||
fields: ['fullname', 'email']
|
fields: ['fullname', 'email']
|
||||||
}]
|
}
|
||||||
|
]
|
||||||
},
|
},
|
||||||
|
|
||||||
{
|
{
|
||||||
title: 'Add your Company',
|
title: 'Add your Company',
|
||||||
columns: [{
|
columns: [
|
||||||
fields: ['companyName', 'bankName', 'fiscalYearStart', 'fiscalYearEnd']
|
{
|
||||||
}]
|
fields: [
|
||||||
|
'companyName',
|
||||||
|
'bankName',
|
||||||
|
'fiscalYearStart',
|
||||||
|
'fiscalYearEnd'
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
}
|
}
|
||||||
].filter(Boolean)
|
].filter(Boolean)
|
||||||
}
|
}
|
||||||
}
|
};
|
||||||
|
@ -3,7 +3,14 @@ const path = require('path');
|
|||||||
const fs = require('fs');
|
const fs = require('fs');
|
||||||
const countries = require('../../../fixtures/countryInfo.json');
|
const countries = require('../../../fixtures/countryInfo.json');
|
||||||
const standardCOA = require('../../../fixtures/verified/standardCOA.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) {
|
async function importAccounts(children, parent, rootType, rootAccount) {
|
||||||
for (let accountName in children) {
|
for (let accountName in children) {
|
||||||
@ -22,12 +29,12 @@ async function importAccounts(children, parent, rootType, rootAccount) {
|
|||||||
isGroup,
|
isGroup,
|
||||||
rootType,
|
rootType,
|
||||||
balance: 0,
|
balance: 0,
|
||||||
accountType: child.accountType
|
accountType: child.accountType || child.account_type
|
||||||
})
|
});
|
||||||
|
|
||||||
await doc.insert()
|
await doc.insert();
|
||||||
|
|
||||||
await importAccounts(child, accountName, rootType)
|
await importAccounts(child, accountName, rootType);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -38,7 +45,7 @@ function identifyIsGroup(child) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const keys = Object.keys(child);
|
const keys = Object.keys(child);
|
||||||
const children = keys.filter(key => !accountFields.includes(key))
|
const children = keys.filter(key => !accountFields.includes(key));
|
||||||
|
|
||||||
if (children.length) {
|
if (children.length) {
|
||||||
return 1;
|
return 1;
|
||||||
@ -51,7 +58,9 @@ async function getCountryCOA(){
|
|||||||
const doc = await frappe.getDoc('AccountingSettings');
|
const doc = await frappe.getDoc('AccountingSettings');
|
||||||
const conCode = countries[doc.country].code;
|
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)) {
|
if (fs.existsSync(countryCOA)) {
|
||||||
const jsonText = fs.readFileSync(countryCOA, 'utf-8');
|
const jsonText = fs.readFileSync(countryCOA, 'utf-8');
|
||||||
@ -64,6 +73,5 @@ async function getCountryCOA(){
|
|||||||
|
|
||||||
module.exports = async function importCharts() {
|
module.exports = async function importCharts() {
|
||||||
const chart = await getCountryCOA();
|
const chart = await getCountryCOA();
|
||||||
await importAccounts(chart, '', '', true)
|
await importAccounts(chart, '', '', true);
|
||||||
}
|
};
|
||||||
|
|
||||||
|
@ -6,10 +6,7 @@ import common from 'frappejs/common';
|
|||||||
import coreModels from 'frappejs/models';
|
import coreModels from 'frappejs/models';
|
||||||
import models from '../models';
|
import models from '../models';
|
||||||
import postStart from '../server/postStart';
|
import postStart from '../server/postStart';
|
||||||
import {
|
import { getSettings, saveSettings } from '../electron/settings';
|
||||||
getSettings,
|
|
||||||
saveSettings
|
|
||||||
} from '../electron/settings';
|
|
||||||
|
|
||||||
// vue imports
|
// vue imports
|
||||||
import Vue from 'vue';
|
import Vue from 'vue';
|
||||||
@ -26,35 +23,34 @@ import Toasted from 'vue-toasted';
|
|||||||
frappe.registerModels(coreModels);
|
frappe.registerModels(coreModels);
|
||||||
frappe.registerModels(models);
|
frappe.registerModels(models);
|
||||||
frappe.fetch = window.fetch.bind();
|
frappe.fetch = window.fetch.bind();
|
||||||
frappe.events.on('connect-database', async (filepath) => {
|
frappe.events.on('connect-database', async filepath => {
|
||||||
await connectToLocalDatabase(filepath);
|
await connectToLocalDatabase(filepath);
|
||||||
|
|
||||||
const accountingSettings = await frappe.getSingle('AccountingSettings');
|
const { country } = await frappe.getSingle('AccountingSettings');
|
||||||
const country = accountingSettings.country;
|
|
||||||
|
|
||||||
if (country === "India") {
|
if (country === 'India') {
|
||||||
frappe.models.Party = require('../models/doctype/Party/RegionalChanges.js')
|
frappe.models.Party = require('../models/doctype/Party/RegionalChanges.js');
|
||||||
} else {
|
} 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.trigger('show-desk');
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|
||||||
frappe.events.on('DatabaseSelector:file-selected', async (filepath) => {
|
frappe.events.on('DatabaseSelector:file-selected', async filepath => {
|
||||||
await connectToLocalDatabase(filepath);
|
await connectToLocalDatabase(filepath);
|
||||||
|
|
||||||
localStorage.dbPath = filepath;
|
localStorage.dbPath = filepath;
|
||||||
|
|
||||||
const accountingSettings = await frappe.getSingle('AccountingSettings');
|
const { companyName } = await frappe.getSingle('AccountingSettings');
|
||||||
if (!accountingSettings.companyName) {
|
if (!companyName) {
|
||||||
frappe.events.trigger('show-setup-wizard');
|
frappe.events.trigger('show-setup-wizard');
|
||||||
} else {
|
} else {
|
||||||
frappe.events.trigger('show-desk');
|
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 {
|
const {
|
||||||
companyName,
|
companyName,
|
||||||
country,
|
country,
|
||||||
@ -73,7 +69,8 @@ import Toasted from 'vue-toasted';
|
|||||||
email,
|
email,
|
||||||
bankName,
|
bankName,
|
||||||
fiscalYearStart,
|
fiscalYearStart,
|
||||||
fiscalYearEnd
|
fiscalYearEnd,
|
||||||
|
currency: countryList[country]['currency']
|
||||||
});
|
});
|
||||||
|
|
||||||
await doc.update();
|
await doc.update();
|
||||||
@ -81,9 +78,9 @@ import Toasted from 'vue-toasted';
|
|||||||
method: 'import-coa'
|
method: 'import-coa'
|
||||||
});
|
});
|
||||||
|
|
||||||
if (country === "India") {
|
if (country === 'India') {
|
||||||
frappe.models.Party = require('../models/doctype/Party/RegionalChanges.js')
|
frappe.models.Party = require('../models/doctype/Party/RegionalChanges.js');
|
||||||
await frappe.db.migrate()
|
await frappe.db.migrate();
|
||||||
await generateGstTaxes();
|
await generateGstTaxes();
|
||||||
}
|
}
|
||||||
frappe.events.trigger('show-desk');
|
frappe.events.trigger('show-desk');
|
||||||
@ -98,25 +95,28 @@ import Toasted from 'vue-toasted';
|
|||||||
case 'Out of State':
|
case 'Out of State':
|
||||||
await newTax.set({
|
await newTax.set({
|
||||||
name: `${type}-${percent}`,
|
name: `${type}-${percent}`,
|
||||||
details: [{
|
details: [
|
||||||
account: "IGST",
|
{
|
||||||
|
account: 'IGST',
|
||||||
rate: percent
|
rate: percent
|
||||||
}]
|
}
|
||||||
})
|
]
|
||||||
|
});
|
||||||
break;
|
break;
|
||||||
case 'In State':
|
case 'In State':
|
||||||
await newTax.set({
|
await newTax.set({
|
||||||
name: `${type}-${percent}`,
|
name: `${type}-${percent}`,
|
||||||
details: [{
|
details: [
|
||||||
account: "CGST",
|
{
|
||||||
|
account: 'CGST',
|
||||||
rate: percent / 2
|
rate: percent / 2
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
account: "SGST",
|
account: 'SGST',
|
||||||
rate: percent / 2
|
rate: percent / 2
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
})
|
});
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
await newTax.insert();
|
await newTax.insert();
|
||||||
@ -124,11 +124,13 @@ import Toasted from 'vue-toasted';
|
|||||||
}
|
}
|
||||||
await newTax.set({
|
await newTax.set({
|
||||||
name: `Exempt-0`,
|
name: `Exempt-0`,
|
||||||
details: [{
|
details: [
|
||||||
account: "Exempt",
|
{
|
||||||
|
account: 'Exempt',
|
||||||
rate: 0
|
rate: 0
|
||||||
}]
|
}
|
||||||
})
|
]
|
||||||
|
});
|
||||||
await newTax.insert();
|
await newTax.insert();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -147,7 +149,6 @@ import Toasted from 'vue-toasted';
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
window.frappe = frappe;
|
window.frappe = frappe;
|
||||||
|
|
||||||
Vue.config.productionTip = false;
|
Vue.config.productionTip = false;
|
||||||
@ -166,4 +167,4 @@ import Toasted from 'vue-toasted';
|
|||||||
},
|
},
|
||||||
template: '<App/>'
|
template: '<App/>'
|
||||||
});
|
});
|
||||||
})()
|
})();
|
||||||
|
14
src/main.js
14
src/main.js
@ -26,8 +26,7 @@ frappe.db.bindSocketClient(socket);
|
|||||||
frappe.getSingle('SystemSettings');
|
frappe.getSingle('SystemSettings');
|
||||||
registerReportMethods();
|
registerReportMethods();
|
||||||
|
|
||||||
frappe.getSingle('AccountingSettings')
|
frappe.getSingle('AccountingSettings').then(accountingSettings => {
|
||||||
.then(accountingSettings => {
|
|
||||||
if (router.currentRoute.fullPath !== '/') return;
|
if (router.currentRoute.fullPath !== '/') return;
|
||||||
|
|
||||||
if (accountingSettings.companyName) {
|
if (accountingSettings.companyName) {
|
||||||
@ -37,7 +36,10 @@ frappe.getSingle('AccountingSettings')
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
frappe.events.on('SetupWizard:setup-complete', async ({ setupWizardValues }) => {
|
frappe.events.on(
|
||||||
|
'SetupWizard:setup-complete',
|
||||||
|
async ({ setupWizardValues }) => {
|
||||||
|
const countryList = require('../fixtures/countryInfo.json');
|
||||||
const {
|
const {
|
||||||
companyName,
|
companyName,
|
||||||
country,
|
country,
|
||||||
@ -57,14 +59,16 @@ frappe.events.on('SetupWizard:setup-complete', async ({ setupWizardValues }) =>
|
|||||||
email,
|
email,
|
||||||
bankName,
|
bankName,
|
||||||
fiscalYearStart,
|
fiscalYearStart,
|
||||||
fiscalYearEnd
|
fiscalYearEnd,
|
||||||
|
currency: countryList[country]['currency']
|
||||||
});
|
});
|
||||||
|
|
||||||
await doc.update();
|
await doc.update();
|
||||||
await frappe.call({ method: 'import-coa' });
|
await frappe.call({ method: 'import-coa' });
|
||||||
|
|
||||||
frappe.events.trigger('show-desk');
|
frappe.events.trigger('show-desk');
|
||||||
});
|
}
|
||||||
|
);
|
||||||
|
|
||||||
window.frappe = frappe;
|
window.frappe = frappe;
|
||||||
|
|
||||||
|
@ -5,47 +5,69 @@
|
|||||||
<feather-icon class="mr-1" :name="iconName" v-show="iconName" />
|
<feather-icon class="mr-1" :name="iconName" v-show="iconName" />
|
||||||
<span>{{ label }}</span>
|
<span>{{ label }}</span>
|
||||||
<div class="ml-auto d-flex align-items-center">
|
<div class="ml-auto d-flex align-items-center">
|
||||||
<feather-icon v-if="balance !== ''" style="width:15px; height:15px" name="dollar-sign"/>
|
<span>
|
||||||
<span>{{ balance }}</span>
|
{{ currency }}
|
||||||
|
<span style="font-weight: 800">{{ computedBalance }}</span>
|
||||||
|
</span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div :class="['branch-children', expanded ? '' : 'd-none']">
|
<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"
|
:label="child.label"
|
||||||
:balance="child.balance"
|
:balance="child.balance"
|
||||||
:parentValue="child.name"
|
:parentValue="child.name"
|
||||||
:doctype="doctype"
|
:doctype="doctype"
|
||||||
|
:currency="currency"
|
||||||
|
@updateBalance="updateBalance"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
<script>
|
<script>
|
||||||
const Branch = {
|
const Branch = {
|
||||||
props: ['label', 'parentValue', 'doctype', 'balance'],
|
props: ['label', 'parentValue', 'doctype', 'balance', 'currency'],
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
expanded: false,
|
expanded: false,
|
||||||
children: null
|
children: null,
|
||||||
}
|
nodeBalance: this.balance
|
||||||
|
};
|
||||||
},
|
},
|
||||||
computed: {
|
computed: {
|
||||||
iconName() {
|
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';
|
return this.expanded ? 'chevron-down' : 'chevron-right';
|
||||||
|
},
|
||||||
|
computedBalance() {
|
||||||
|
return this.nodeBalance;
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
components: {
|
components: {
|
||||||
Branch: () => Promise.resolve(Branch)
|
Branch: () => Promise.resolve(Branch)
|
||||||
},
|
},
|
||||||
mounted() {
|
async mounted() {
|
||||||
this.settings = frappe.getMeta(this.doctype).treeSettings;
|
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: {
|
methods: {
|
||||||
async toggleChildren() {
|
async toggleChildren() {
|
||||||
await this.getChildren();
|
await this.getChildren();
|
||||||
this.expanded = !this.expanded;
|
this.expanded = !this.expanded;
|
||||||
},
|
},
|
||||||
|
updateBalance(balance) {
|
||||||
|
this.nodeBalance += balance;
|
||||||
|
this.$emit('updateBalance', this.nodeBalance);
|
||||||
|
},
|
||||||
async getChildren() {
|
async getChildren() {
|
||||||
if (this.children) return;
|
if (this.children) return;
|
||||||
|
|
||||||
@ -65,7 +87,7 @@ const Branch = {
|
|||||||
|
|
||||||
this.children = children.map(c => {
|
this.children = children.map(c => {
|
||||||
c.label = c.name;
|
c.label = c.name;
|
||||||
c.balance = c.balance
|
c.balance = c.balance;
|
||||||
return c;
|
return c;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@ -75,7 +97,7 @@ const Branch = {
|
|||||||
export default Branch;
|
export default Branch;
|
||||||
</script>
|
</script>
|
||||||
<style lang="scss">
|
<style lang="scss">
|
||||||
@import "../../styles/variables";
|
@import '../../styles/variables';
|
||||||
|
|
||||||
.branch {
|
.branch {
|
||||||
font-size: 1rem;
|
font-size: 1rem;
|
||||||
|
@ -1,28 +1,42 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="p-3" v-if="root">
|
<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>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
<script>
|
<script>
|
||||||
import frappe from 'frappejs';
|
import frappe from 'frappejs';
|
||||||
import Branch from './Branch';
|
import Branch from './Branch';
|
||||||
import { setTimeout } from 'timers';
|
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
components: {
|
components: {
|
||||||
Branch,
|
Branch
|
||||||
},
|
},
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
root: null,
|
root: null,
|
||||||
doctype: "Account"
|
doctype: 'Account'
|
||||||
|
};
|
||||||
|
},
|
||||||
|
computed: {
|
||||||
|
rootBalance() {
|
||||||
|
return this.root.balance;
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
async mounted() {
|
async mounted() {
|
||||||
this.settings = frappe.getMeta(this.doctype).treeSettings;
|
this.settings = frappe.getMeta(this.doctype).treeSettings;
|
||||||
|
const { currency } = await frappe.getSingle('AccountingSettings');
|
||||||
this.root = {
|
this.root = {
|
||||||
label: await this.settings.getRootLabel(),
|
label: await this.settings.getRootLabel(),
|
||||||
balance: 'Net Worth'
|
balance: 0,
|
||||||
|
currency
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
@ -44,7 +58,10 @@ export default {
|
|||||||
c.balance = c.balance;
|
c.balance = c.balance;
|
||||||
return c;
|
return c;
|
||||||
});
|
});
|
||||||
|
},
|
||||||
|
updateBalance(balance) {
|
||||||
|
this.root.balance += balance;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
};
|
||||||
</script>
|
</script>
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="bg-light">
|
<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
|
<form-actions
|
||||||
v-if="shouldRenderForm"
|
v-if="shouldRenderForm"
|
||||||
:doc="doc"
|
:doc="doc"
|
||||||
@ -10,7 +10,7 @@
|
|||||||
@print="print"
|
@print="print"
|
||||||
:links="links"
|
:links="links"
|
||||||
/>
|
/>
|
||||||
<hr class="mb-3">
|
<hr class="mb-3" />
|
||||||
<form-layout
|
<form-layout
|
||||||
v-if="shouldRenderForm"
|
v-if="shouldRenderForm"
|
||||||
:doc="doc"
|
:doc="doc"
|
||||||
@ -87,10 +87,9 @@ export default {
|
|||||||
|
|
||||||
this.setLinks();
|
this.setLinks();
|
||||||
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(`/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() {
|
async save() {
|
||||||
@ -148,3 +147,16 @@ export default {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
</script>
|
</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>
|
||||||
|
Loading…
Reference in New Issue
Block a user