2
0
mirror of https://github.com/frappe/books.git synced 2024-09-20 03:29:00 +00:00

Merge pull request #30 from netchampfaris/coa

Chart of Accounts
This commit is contained in:
Faris Ansari 2018-04-09 11:14:29 +05:30 committed by GitHub
commit 13e3d46d54
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
14 changed files with 2742 additions and 1405 deletions

3
.gitignore vendored
View File

@ -5,4 +5,5 @@ Thumbs.db
*.log
.cache
/temp
dist
dist
Frappe Accounting*

View File

@ -19,7 +19,7 @@ module.exports = {
})
frappe.desk.menu.addItem('ToDo', '#list/ToDo');
frappe.desk.menu.addItem('Accounts', '#list/Account');
frappe.desk.menu.addItem('Chart of Accounts', '#tree/Account');
frappe.desk.menu.addItem('Items', '#list/Item');
frappe.desk.menu.addItem('Customers', '#list/Customer');
frappe.desk.menu.addItem('Invoice', '#list/Invoice');
@ -27,7 +27,7 @@ module.exports = {
frappe.desk.menu.addItem('Contact', "#list/Contact");
frappe.desk.menu.addItem('Settings', () => frappe.desk.showFormModal('SystemSettings'));
frappe.router.default = '#list/ToDo';
frappe.router.default = '#tree/Account';
frappe.router.show(window.location.hash);

View File

@ -4,6 +4,12 @@ const { writeFile } = require('frappejs/server/utils');
const appClient = require('../client');
const SetupWizard = require('../setup');
const fs = require('fs');
require.extensions['.html'] = function (module, filename) {
module.exports = fs.readFileSync(filename, 'utf8');
};
(async () => {
const configFilePath = path.join(require('os').homedir(), '.config', 'frappe-accounting', 'settings.json');
@ -20,6 +26,8 @@ const SetupWizard = require('../setup');
dbPath,
models: require('../models')
}).then(() => {
frappe.syncDoc(require('../fixtures/invoicePrint'));
appClient.start();
});
} else {
@ -50,15 +58,20 @@ const SetupWizard = require('../setup');
const doc = await frappe.getDoc('AccountingSettings');
await doc.set('companyName', companyName);
await doc.set('file', dbPath);
await doc.set('country', country);
await doc.set('fullname', name);
await doc.set('email', email);
await doc.set('abbreviation', abbreviation);
await doc.set('bankName', bankName);
await doc.update();
// bootstrap Chart of Accounts
const importCOA = require('../models/doctype/account/importCOA');
const chart = require('../fixtures/standardCOA');
await importCOA(chart);
frappe.syncDoc(require('../fixtures/invoicePrint'));
appClient.start();
})
}

173
fixtures/standardCOA.js Normal file
View File

@ -0,0 +1,173 @@
const frappe = require('frappejs');
const _ = frappe._.bind(frappe);
module.exports = {
[_("Application of Funds (Assets)")]: {
[_("Current Assets")]: {
[_("Accounts Receivable")]: {
[_("Debtors")]: {
"accountType": "Receivable"
}
},
[_("Bank Accounts")]: {
"accountType": "Bank",
"isGroup": 1
},
[_("Cash In Hand")]: {
[_("Cash")]: {
"accountType": "Cash"
},
"accountType": "Cash"
},
[_("Loans and Advances (Assets)")]: {
"isGroup": 1
},
[_("Securities and Deposits")]: {
[_("Earnest Money")]: {}
},
[_("Stock Assets")]: {
[_("Stock In Hand")]: {
"accountType": "Stock"
},
"accountType": "Stock",
},
[_("Tax Assets")]: {
"isGroup": 1
}
},
[_("Fixed Assets")]: {
[_("Capital Equipments")]: {
"accountType": "Fixed Asset"
},
[_("Electronic Equipments")]: {
"accountType": "Fixed Asset"
},
[_("Furnitures and Fixtures")]: {
"accountType": "Fixed Asset"
},
[_("Office Equipments")]: {
"accountType": "Fixed Asset"
},
[_("Plants and Machineries")]: {
"accountType": "Fixed Asset"
},
[_("Buildings")]: {
"accountType": "Fixed Asset"
},
[_("Softwares")]: {
"accountType": "Fixed Asset"
},
[_("Accumulated Depreciation")]: {
"accountType": "Accumulated Depreciation"
}
},
[_("Investments")]: {
"isGroup": 1
},
[_("Temporary Accounts")]: {
[_("Temporary Opening")]: {
"accountType": "Temporary"
}
},
"rootType": "Asset"
},
[_("Expenses")]: {
[_("Direct Expenses")]: {
[_("Stock Expenses")]: {
[_("Cost of Goods Sold")]: {
"accountType": "Cost of Goods Sold"
},
[_("Expenses Included In Valuation")]: {
"accountType": "Expenses Included In Valuation"
},
[_("Stock Adjustment")]: {
"accountType": "Stock Adjustment"
}
},
},
[_("Indirect Expenses")]: {
[_("Administrative Expenses")]: {},
[_("Commission on Sales")]: {},
[_("Depreciation")]: {
"accountType": "Depreciation"
},
[_("Entertainment Expenses")]: {},
[_("Freight and Forwarding Charges")]: {
"accountType": "Chargeable"
},
[_("Legal Expenses")]: {},
[_("Marketing Expenses")]: {
"accountType": "Chargeable"
},
[_("Miscellaneous Expenses")]: {
"accountType": "Chargeable"
},
[_("Office Maintenance Expenses")]: {},
[_("Office Rent")]: {},
[_("Postal Expenses")]: {},
[_("Print and Stationery")]: {},
[_("Round Off")]: {
"accountType": "Round Off"
},
[_("Salary")]: {},
[_("Sales Expenses")]: {},
[_("Telephone Expenses")]: {},
[_("Travel Expenses")]: {},
[_("Utility Expenses")]: {},
[_("Write Off")]: {},
[_("Exchange Gain/Loss")]: {},
[_("Gain/Loss on Asset Disposal")]: {}
},
"rootType": "Expense"
},
[_("Income")]: {
[_("Direct Income")]: {
[_("Sales")]: {},
[_("Service")]: {}
},
[_("Indirect Income")]: {
"isGroup": 1
},
"rootType": "Income"
},
[_("Source of Funds (Liabilities)")]: {
[_("Current Liabilities")]: {
[_("Accounts Payable")]: {
[_("Creditors")]: {
"accountType": "Payable"
},
[_("Payroll Payable")]: {},
},
[_("Stock Liabilities")]: {
[_("Stock Received But Not Billed")]: {
"accountType": "Stock Received But Not Billed"
},
},
[_("Duties and Taxes")]: {
"accountType": "Tax",
"isGroup": 1
},
[_("Loans (Liabilities)")]: {
[_("Secured Loans")]: {},
[_("Unsecured Loans")]: {},
[_("Bank Overdraft Account")]: {},
},
},
"rootType": "Liability"
},
[_("Equity")]: {
[_("Capital Stock")]: {
"accountType": "Equity"
},
[_("Dividends Paid")]: {
"accountType": "Equity"
},
[_("Opening Balance Equity")]: {
"accountType": "Equity"
},
[_("Retained Earnings")]: {
"accountType": "Equity"
},
"rootType": "Equity"
}
}

View File

@ -13,7 +13,7 @@ let mainWindow
function createWindow () {
// Create the browser window.
mainWindow = new BrowserWindow({width: 800, height: 600})
mainWindow = new BrowserWindow({width: 1024, height: 768})
// and load the index.html of the app.
mainWindow.loadURL(url.format({

View File

@ -5,7 +5,8 @@ module.exports = {
"isSingle": 0,
"keywordFields": [
"name",
"account_type"
"rootType",
"accountType"
],
"fields": [
{
@ -15,7 +16,7 @@ module.exports = {
"required": 1
},
{
"fieldname": "parent_account",
"fieldname": "parentAccount",
"label": "Parent Account",
"fieldtype": "Link",
"target": "Account",
@ -27,8 +28,8 @@ module.exports = {
}
},
{
"fieldname": "account_type",
"label": "Account Type",
"fieldname": "rootType",
"label": "Root Type",
"fieldtype": "Select",
"options": [
"Asset",
@ -37,6 +38,37 @@ module.exports = {
"Income",
"Expense"
]
},
{
"fieldname": "accountType",
"label": "Account Type",
"fieldtype": "Select",
"options": [
"Accumulated Depreciation",
"Bank",
"Cash",
"Chargeable",
"Cost of Goods Sold",
"Depreciation",
"Equity",
"Expense Account",
"Expenses Included In Valuation",
"Fixed Asset",
"Income Account",
"Payable",
"Receivable",
"Round Off",
"Stock",
"Stock Adjustment",
"Stock Received But Not Billed",
"Tax",
"Temporary"
]
},
{
"fieldname": "isGroup",
"label": "Is Group",
"fieldtype": "Check"
}
],
@ -48,10 +80,14 @@ module.exports = {
listSettings: {
getFields(list) {
return ['name', 'account_type'];
return ['name', 'accountType', 'rootType'];
},
getRowHTML(list, data) {
return `<div class="col-11">${list.getNameHTML(data)} (${data.account_type})</div>`;
return `<div class="col-11">${list.getNameHTML(data)} (${data.rootType})</div>`;
}
},
treeSettings: {
parentField: 'parentAccount'
}
}

View File

@ -3,11 +3,11 @@ const BaseDocument = require('frappejs/model/document');
module.exports = class Account extends BaseDocument {
async validate() {
if (!this.account_type) {
if (this.parent_account) {
this.account_type = await frappe.db.getValue('Account', this.parent_account, 'account_type');
if (!this.accountType) {
if (this.parentAccount) {
this.accountType = await frappe.db.getValue('Account', this.parentAccount, 'accountType');
} else {
this.account_type = 'Asset';
this.accountType = 'Asset';
}
}
}

View File

@ -23,14 +23,6 @@ module.exports = {
fieldtype: "Account"
},
{
"fieldname": "file",
"label": "File",
"fieldtype": "Data",
"required": 1,
"directory": 1
},
{
"fieldname": "country",
"label": "Country",
@ -53,13 +45,6 @@ module.exports = {
"required": 1
},
{
"fieldname": "abbreviation",
"label": "Abbreviation",
"fieldtype": "Data",
"required": 1
},
{
"fieldname": "bankName",
"label": "Bank Name",

View File

@ -0,0 +1,50 @@
const frappe = require('frappejs');
const accountFields = ['accountType', 'rootType', 'isGroup'];
async function importAccounts(children, parent, rootType, rootAccount) {
for (let accountName in children) {
const child = children[accountName];
if (rootAccount) {
rootType = child.rootType;
}
if (!accountFields.includes(accountName)) {
let isGroup = identifyIsGroup(child);
const doc = frappe.newDoc({
doctype: 'Account',
name: accountName,
parentAccount: parent,
isGroup,
rootType,
accountType: child.accountType
})
await doc.insert()
await importAccounts(child, accountName, rootType)
}
}
}
function identifyIsGroup(child) {
if (child.isGroup) {
return child.isGroup;
}
const keys = Object.keys(child);
const children = keys.filter(key => !accountFields.includes(key))
if (children.length) {
return 1;
}
return 0;
}
module.exports = async function importCharts(chart) {
if (chart) {
await importAccounts(chart, '', '', true)
}
}

View File

@ -30,7 +30,8 @@ module.exports = {
"fieldname": "email",
"label": "Email",
"fieldtype": "Data",
"required": 1
"required": 1,
"inputType": "email"
},
{
@ -40,13 +41,6 @@ module.exports = {
"required": 1
},
{
"fieldname": "abbreviation",
"label": "Abbreviation",
"fieldtype": "Data",
"required": 1
},
{
"fieldname": "bankName",
"label": "Bank Name",
@ -73,14 +67,7 @@ module.exports = {
{
title: 'Add your Company',
columns: [
{
fields: ['companyName', 'bankName']
},
{
fields: ['abbreviation']
},
]
fields: ['companyName', 'bankName']
}
]
}

View File

@ -89,7 +89,29 @@ module.exports = class SetupWizard {
}
nextSlide() {
this.showSlide(this.currentIndex + 1);
const isValid = this.validateCurrentSlide();
frappe.ui.toggleClass(this.formLayout.sections[this.currentIndex], 'was-validated', !isValid);
if (isValid) {
this.showSlide(this.currentIndex + 1);
}
}
validateCurrentSlide() {
const fields = this.getFieldsInSlide(this.currentIndex);
const inputValidityMap = fields.map(field => this.formLayout.controls[field].input.checkValidity());
const isValid = !inputValidityMap.includes(false);
return isValid;
}
getFieldsInSlide(index) {
const visibleSection = slideConfigs.layout[index];
const fieldsInSlide = visibleSection.fields ||
visibleSection.columns.reduce(
(col, fields) => fields.concat(col.fields), []
);
return fieldsInSlide;
}
activateIndicator(index) {

View File

@ -8,7 +8,7 @@ async function makeFixtures() {
await frappe.insert({doctype:'Party', name:'Test Customer'})
await frappe.insert({doctype:'Item', name:'Test Item 1', description:'Test Item Description 1', unit:'No', rate: 100})
await frappe.insert({doctype:'Item', name:'Test Item 2', description:'Test Item Description 2', unit:'No', rate: 200})
await frappe.insert({doctype:'Account', name:'GST', parent_account: 'Liabilities'});
await frappe.insert({doctype:'Account', name:'GST', parentAccount: 'Liabilities'});
await frappe.insert({doctype:'Tax', name:'GST',
details: [{account: 'GST', rate:10}]
})

View File

@ -7499,29 +7499,31 @@ mark {
.vertical-margin {
margin: 1rem 0px; }
.tree {
padding: 15px; }
padding: 1rem 2rem; }
.tree li {
list-style: none;
margin: 2px 0px; }
list-style: none; }
ul.tree-children {
padding-left: 20px; }
padding-left: 2rem; }
.tree-link {
cursor: pointer;
display: inline-block;
padding: 1px; }
display: -webkit-box;
display: -ms-flexbox;
display: flex;
-webkit-box-align: center;
-ms-flex-align: center;
align-items: center;
width: 100%; }
.tree-link:hover {
background-color: #f8f9fa; }
.tree-link .node-parent {
color: #6c757d;
font-size: 14px;
width: 10px;
width: 24px;
height: 24px;
text-align: center; }
.tree-link .node-leaf {
color: #ced4da; }
.tree-link .node-parent, .tree-link .node-leaf {
margin-right: 5px;
margin-left: 2px;
margin-top: 3px; }
.tree-link.active svg {
color: #007bff; }
padding: 0.5rem; }
.tree-link.active a {
color: #6c757d; }
.tree-hover {
@ -7587,3 +7589,5 @@ input[type=file] {
overflow: hidden;
position: absolute;
z-index: -1; }
.was-validated input[type=file]:invalid + button {
border-color: #dc3545; }

3752
www/dist/js/bundle.js vendored

File diff suppressed because it is too large Load Diff