mirror of
https://github.com/frappe/books.git
synced 2024-12-23 03:19:01 +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]);
|
||||
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();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
@ -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
|
||||
}
|
||||
]
|
||||
};
|
||||
|
@ -23,11 +23,6 @@ export default {
|
||||
},
|
||||
'grandTotal',
|
||||
'date',
|
||||
{
|
||||
label: 'INV #',
|
||||
getValue(doc) {
|
||||
return doc.name;
|
||||
}
|
||||
}
|
||||
'outstandingAmount'
|
||||
]
|
||||
}
|
||||
};
|
||||
|
@ -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();
|
||||
}
|
||||
};
|
||||
|
@ -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']
|
||||
},
|
||||
{
|
||||
|
@ -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?
|
||||
}
|
||||
};
|
||||
|
@ -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)
|
||||
}
|
||||
};
|
||||
|
@ -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);
|
||||
};
|
||||
|
@ -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/>'
|
||||
});
|
||||
})()
|
||||
})();
|
||||
|
78
src/main.js
78
src/main.js
@ -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;
|
||||
|
@ -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;
|
||||
|
@ -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>
|
||||
|
@ -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>
|
||||
|
Loading…
Reference in New Issue
Block a user