Report: Trial Balance

This commit is contained in:
Anand Doshi 2014-07-22 19:02:11 +05:30
parent 9df4196597
commit cb86d597b7
16 changed files with 341 additions and 157 deletions

View File

@ -1 +0,0 @@
Period wise opening and closing balance of all transactions.

View File

@ -1 +0,0 @@
from __future__ import unicode_literals

View File

@ -1,78 +0,0 @@
// Copyright (c) 2013, Web Notes Technologies Pvt. Ltd. and Contributors
// License: GNU General Public License v3. See license.txt
frappe.require("assets/erpnext/js/account_tree_grid.js");
frappe.pages['trial-balance'].onload = function(wrapper) {
frappe.ui.make_app_page({
parent: wrapper,
title: __('Trial Balance'),
single_column: true
});
var TrialBalance = erpnext.AccountTreeGrid.extend({
init: function(wrapper, title) {
var me = this;
this._super(wrapper, title);
// period closing entry checkbox
this.wrapper.bind("make", function() {
$('<div style="margin: 10px 0px; "\
class="with_period_closing_entry"><input type="checkbox" checked="checked">' +
__("With period closing entry") + '</div>')
.appendTo(me.wrapper)
.find("input").click(function() { me.refresh(); });
});
},
prepare_balances: function() {
// store value of with closing entry
this.with_period_closing_entry = this.wrapper
.find(".with_period_closing_entry input:checked").length;
this._super();
this.add_total_debit_credit();
},
update_balances: function(account, posting_date, v) {
// for period closing voucher,
// only consider them when adding "With Closing Entry is checked"
if(v.voucher_type === "Period Closing Voucher") {
if(this.with_period_closing_entry) {
this._super(account, posting_date, v);
}
} else {
this._super(account, posting_date, v);
}
},
add_total_debit_credit: function() {
var me = this;
var total_row = {
company: me.company,
id: "Total Debit / Credit",
name: "Total Debit / Credit",
indent: 0,
opening_dr: "NA",
opening_cr: "NA",
debit: 0,
credit: 0,
checked: false,
};
me.item_by_name[total_row.name] = total_row;
$.each(this.data, function(i, account) {
if((account.group_or_ledger == "Ledger") || (account.rgt - account.lft == 1)) {
total_row["debit"] += account.debit;
total_row["credit"] += account.credit;
}
});
this.data.push(total_row);
}
})
erpnext.trial_balance = new TrialBalance(wrapper, 'Trial Balance');
wrapper.appframe.add_module_icon("Accounts")
}

View File

@ -1,23 +0,0 @@
{
"creation": "2013-01-27 16:30:52.000000",
"docstatus": 0,
"doctype": "Page",
"icon": "icon-table",
"idx": 1,
"modified": "2013-07-11 14:44:49.000000",
"modified_by": "Administrator",
"module": "Accounts",
"name": "trial-balance",
"owner": "Administrator",
"page_name": "trial-balance",
"roles": [
{
"role": "Analytics"
},
{
"role": "Accounts Manager"
}
],
"standard": "Yes",
"title": "Trial Balance"
}

View File

@ -5,15 +5,14 @@ from __future__ import unicode_literals
import frappe
from frappe import _
from frappe.utils import flt
from erpnext.accounts.report.financial_statements import (process_filters, get_period_list, get_columns, get_data)
from erpnext.accounts.report.financial_statements import (get_period_list, get_columns, get_data)
def execute(filters=None):
process_filters(filters)
period_list = get_period_list(filters.fiscal_year, filters.periodicity, from_beginning=True)
asset = get_data(filters.company, "Asset", "Debit", period_list, filters.depth)
liability = get_data(filters.company, "Liability", "Credit", period_list, filters.depth)
equity = get_data(filters.company, "Equity", "Credit", period_list, filters.depth)
asset = get_data(filters.company, "Asset", "Debit", period_list)
liability = get_data(filters.company, "Liability", "Credit", period_list)
equity = get_data(filters.company, "Equity", "Credit", period_list)
provisional_profit_loss = get_provisional_profit_loss(asset, liability, equity, period_list)
data = []
@ -32,7 +31,7 @@ def get_provisional_profit_loss(asset, liability, equity, period_list):
provisional_profit_loss = {
"account_name": _("Provisional Profit / Loss (Credit)"),
"account": None,
"is_profit_loss": True
"warn_if_negative": True
}
has_value = False

View File

@ -1,5 +1,5 @@
{%
if (report.columns.length > 6) {
if (report.columns.length > 8) {
frappe.throw(__("Too many columns. Export the report and print it using a spreadsheet application."));
}
%}
@ -17,11 +17,14 @@
<h2 class="text-center">{%= __(report.report_name) %}</h2>
<h4 class="text-center">{%= filters.company %}</h3>
<h4 class="text-center">{%= filters.fiscal_year %}</h3>
{% if (filters.from_date) { %}
<h4 class="text-center">{%= dateutil.str_to_user(filters.from_date) %} - {%= dateutil.str_to_user(filters.to_date) %}</h3>
{% } %}
<hr>
<table class="table table-bordered">
<thead>
<tr>
<th style="width: {%= 100 - (report.columns.length - 2) * 15 %}%"></th>
<th style="width: {%= 100 - (report.columns.length - 2) * 13 %}%"></th>
{% for(var i=2, l=report.columns.length; i<l; i++) { %}
<th class="text-right">{%= report.columns[i].label %}</th>
{% } %}

View File

@ -4,14 +4,9 @@
from __future__ import unicode_literals
import frappe
from frappe import _, _dict
from frappe.utils import (flt, cint, getdate, get_first_day, get_last_day,
from frappe.utils import (flt, getdate, get_first_day, get_last_day,
add_months, add_days, formatdate)
def process_filters(filters):
filters.depth = cint(filters.depth) or 3
if not filters.periodicity:
filters.periodicity = "Yearly"
def get_period_list(fiscal_year, periodicity, from_beginning=False):
"""Get a list of dict {"to_date": to_date, "key": key, "label": label}
Periodicity can be (Yearly, Quarterly, Monthly)"""
@ -76,13 +71,13 @@ def get_period_list(fiscal_year, periodicity, from_beginning=False):
return period_list
def get_data(company, root_type, balance_must_be, period_list, depth, ignore_closing_entries=False):
def get_data(company, root_type, balance_must_be, period_list, ignore_closing_entries=False):
accounts = get_accounts(company, root_type)
if not accounts:
return None
accounts, accounts_by_name = filter_accounts(accounts, depth)
gl_entries_by_account = get_gl_entries(company, root_type, period_list[0]["from_date"], period_list[-1]["to_date"],
accounts, accounts_by_name = filter_accounts(accounts)
gl_entries_by_account = get_gl_entries(company, period_list[0]["from_date"], period_list[-1]["to_date"],
accounts[0].lft, accounts[0].rgt, ignore_closing_entries=ignore_closing_entries)
calculate_values(accounts, gl_entries_by_account, period_list)
@ -127,8 +122,8 @@ def prepare_data(accounts, balance_must_be, period_list):
"account": d.name,
"parent_account": d.parent_account,
"indent": flt(d.indent),
"year_start_date": year_start_date,
"year_end_date": year_end_date
"from_date": year_start_date,
"to_date": year_end_date
}
for period in period_list:
if d.get(period.key):
@ -177,7 +172,7 @@ def get_accounts(company, root_type):
return accounts
def filter_accounts(accounts, depth):
def filter_accounts(accounts, depth=10):
parent_children_map = {}
accounts_by_name = {}
for d in accounts:
@ -204,7 +199,7 @@ def filter_accounts(accounts, depth):
return filtered_accounts, accounts_by_name
def get_gl_entries(company, root_type, from_date, to_date, root_lft, root_rgt, ignore_closing_entries=False):
def get_gl_entries(company, from_date, to_date, root_lft, root_rgt, ignore_closing_entries=False):
"""Returns a dict like { "account": [gl entries], ... }"""
additional_conditions = []

View File

@ -5,14 +5,13 @@ from __future__ import unicode_literals
import frappe
from frappe import _
from frappe.utils import flt
from erpnext.accounts.report.financial_statements import (process_filters, get_period_list, get_columns, get_data)
from erpnext.accounts.report.financial_statements import (get_period_list, get_columns, get_data)
def execute(filters=None):
process_filters(filters)
period_list = get_period_list(filters.fiscal_year, filters.periodicity)
income = get_data(filters.company, "Income", "Credit", period_list, filters.depth, ignore_closing_entries=True)
expense = get_data(filters.company, "Expense", "Debit", period_list, filters.depth, ignore_closing_entries=True)
income = get_data(filters.company, "Income", "Credit", period_list, ignore_closing_entries=True)
expense = get_data(filters.company, "Expense", "Debit", period_list, ignore_closing_entries=True)
net_profit_loss = get_net_profit_loss(income, expense, period_list)
data = []
@ -30,7 +29,7 @@ def get_net_profit_loss(income, expense, period_list):
net_profit_loss = {
"account_name": _("Net Profit / Loss"),
"account": None,
"is_profit_loss": True
"warn_if_negative": True
}
for period in period_list:

View File

@ -0,0 +1 @@
{% include "accounts/report/financial_statements.html" %}

View File

@ -0,0 +1,65 @@
// Copyright (c) 2013, Web Notes Technologies Pvt. Ltd. and Contributors
// License: GNU General Public License v3. See license.txt
frappe.require("assets/erpnext/js/financial_statements.js");
frappe.query_reports["Trial Balance"] = {
"filters": [
{
"fieldname": "company",
"label": __("Company"),
"fieldtype": "Link",
"options": "Company",
"default": frappe.defaults.get_user_default("company"),
"reqd": 1
},
{
"fieldname": "fiscal_year",
"label": __("Fiscal Year"),
"fieldtype": "Link",
"options": "Fiscal Year",
"default": frappe.defaults.get_user_default("fiscal_year"),
"reqd": 1,
"on_change": function(query_report) {
var fiscal_year = query_report.get_values().fiscal_year;
if (!fiscal_year) {
return;
}
frappe.model.with_doc("Fiscal Year", fiscal_year, function(r) {
var fy = frappe.model.get_doc("Fiscal Year", fiscal_year);
query_report.filters_by_name.from_date.set_input(fy.year_start_date);
query_report.filters_by_name.to_date.set_input(fy.year_end_date);
query_report.trigger_refresh();
});
}
},
{
"fieldname": "from_date",
"label": __("From Date"),
"fieldtype": "Date",
"default": frappe.defaults.get_user_default("year_start_date"),
},
{
"fieldname": "to_date",
"label": __("To Date"),
"fieldtype": "Date",
"default": frappe.defaults.get_user_default("year_end_date"),
},
{
"fieldname": "with_period_closing_entry",
"label": __("With Period Closing Entry"),
"fieldtype": "Check",
"default": 1
},
{
"fieldname": "show_zero_values",
"label": __("Show rows with zero values"),
"fieldtype": "Check"
},
],
"formatter": erpnext.financial_statements.formatter,
"tree": true,
"name_field": "account",
"parent_field": "parent_account",
"initial_depth": 3
}

View File

@ -0,0 +1,17 @@
{
"add_total_row": 0,
"apply_user_permissions": 1,
"creation": "2014-07-22 11:41:23.743564",
"disabled": 0,
"docstatus": 0,
"doctype": "Report",
"is_standard": "Yes",
"modified": "2014-07-22 11:41:23.743564",
"modified_by": "Administrator",
"module": "Accounts",
"name": "Trial Balance",
"owner": "Administrator",
"ref_doctype": "GL Entry",
"report_name": "Trial Balance",
"report_type": "Script Report"
}

View File

@ -0,0 +1,216 @@
# Copyright (c) 2013, Web Notes Technologies Pvt. Ltd. and Contributors
# License: GNU General Public License v3. See license.txt
from __future__ import unicode_literals
import frappe
from frappe import _
from frappe.utils import cint, flt, getdate, formatdate
from erpnext.accounts.report.financial_statements import filter_accounts, get_gl_entries
value_fields = ("opening_debit", "opening_credit", "debit", "credit", "closing_debit", "closing_credit")
def execute(filters):
validate_filters(filters)
data = get_data(filters)
columns = get_columns()
return columns, data
def validate_filters(filters):
filters.year_start_date, filters.year_end_date = frappe.db.get_value("Fiscal Year", filters.fiscal_year,
["year_start_date", "year_end_date"])
filters.year_start_date = getdate(filters.year_start_date)
filters.year_end_date = getdate(filters.year_end_date)
if not filters.from_date:
filters.from_date = filters.year_start_date
if not filters.to_date:
filters.to_date = filters.year_end_date
filters.from_date = getdate(filters.from_date)
filters.to_date = getdate(filters.to_date)
if filters.from_date > filters.to_date:
frappe.throw(_("From Date cannot be greater than To Date"))
if (filters.from_date < filters.year_start_date) or (filters.from_date > filters.year_end_date):
frappe.msgprint(_("From Date should be within the Fiscal Year. Assuming From Date = {0}")\
.format(formatdate(filters.year_start_date)))
filters.from_date = filters.year_start_date
if (filters.to_date < filters.year_start_date) or (filters.to_date > filters.year_end_date):
frappe.msgprint(_("To Date should be within the Fiscal Year. Assuming To Date = {0}")\
.format(formatdate(filters.year_end_date)))
filters.to_date = filters.year_end_date
def get_data(filters):
accounts = frappe.db.sql("""select * from `tabAccount` where company=%s order by lft""",
filters.company, as_dict=True)
if not accounts:
return None
accounts, accounts_by_name = filter_accounts(accounts)
min_lft, max_rgt = frappe.db.sql("""select min(lft), max(rgt) from `tabAccount`
where company=%s""", (filters.company,))[0]
gl_entries_by_account = get_gl_entries(filters.company, None, filters.to_date, min_lft, max_rgt,
ignore_closing_entries=not flt(filters.with_period_closing_entry))
total_row = calculate_values(accounts, gl_entries_by_account, filters)
accumulate_values_into_parents(accounts, accounts_by_name)
data = prepare_data(accounts, filters, total_row)
return data
def calculate_values(accounts, gl_entries_by_account, filters):
init = {
"opening_debit": 0.0,
"opening_credit": 0.0,
"debit": 0.0,
"credit": 0.0,
"closing_debit": 0.0,
"closing_credit": 0.0
}
total_row = {
"account": None,
"account_name": _("Total"),
"warn_if_negative": True,
"debit": 0.0,
"credit": 0.0
}
for d in accounts:
d.update(init.copy())
for entry in gl_entries_by_account.get(d.name, []):
posting_date = getdate(entry.posting_date)
# opening
if posting_date < filters.from_date:
is_valid_opening = (d.root_type in ("Asset", "Liability", "Equity") or
(filters.year_start_date <= posting_date < filters.from_date))
if is_valid_opening:
d["opening_debit"] += flt(entry.debit)
d["opening_credit"] += flt(entry.credit)
elif posting_date <= filters.to_date:
if entry.is_opening == "Yes" and d.root_type in ("Asset", "Liability", "Equity"):
d["opening_debit"] += flt(entry.debit)
d["opening_credit"] += flt(entry.credit)
else:
d["debit"] += flt(entry.debit)
d["credit"] += flt(entry.credit)
total_row["debit"] += d["debit"]
total_row["credit"] += d["credit"]
return total_row
def accumulate_values_into_parents(accounts, accounts_by_name):
for d in reversed(accounts):
if d.parent_account:
for key in value_fields:
accounts_by_name[d.parent_account][key] += d[key]
def prepare_data(accounts, filters, total_row):
show_zero_values = cint(filters.show_zero_values)
data = []
for i, d in enumerate(accounts):
has_value = False
row = {
"account_name": d.account_name,
"account": d.name,
"parent_account": d.parent_account,
"indent": d.indent,
"from_date": filters.from_date,
"to_date": filters.to_date
}
prepare_opening_and_closing(d)
for key in value_fields:
row[key] = d.get(key, 0.0)
if row[key]:
has_value = True
if has_value or show_zero_values:
data.append(row)
data.extend([{},total_row])
return data
def get_columns():
return [
{
"fieldname": "account",
"label": _("Account"),
"fieldtype": "Link",
"options": "Account",
"width": 300
},
{
"fieldname": "opening_debit",
"label": _("Opening (Dr)"),
"fieldtype": "Currency",
"width": 120
},
{
"fieldname": "opening_credit",
"label": _("Opening (Cr)"),
"fieldtype": "Currency",
"width": 120
},
{
"fieldname": "debit",
"label": _("Debit"),
"fieldtype": "Currency",
"width": 120
},
{
"fieldname": "credit",
"label": _("Credit"),
"fieldtype": "Currency",
"width": 120
},
{
"fieldname": "closing_debit",
"label": _("Closing (Dr)"),
"fieldtype": "Currency",
"width": 120
},
{
"fieldname": "closing_credit",
"label": _("Closing (Cr)"),
"fieldtype": "Currency",
"width": 120
}
]
def prepare_opening_and_closing(d):
d["closing_debit"] = d["opening_debit"] + d["debit"]
d["closing_credit"] = d["opening_credit"] + d["credit"]
if d["closing_debit"] > d["closing_credit"]:
d["closing_debit"] -= d["closing_credit"]
d["closing_credit"] = 0.0
else:
d["closing_credit"] -= d["closing_debit"]
d["closing_debit"] = 0.0
if d["opening_debit"] > d["opening_credit"]:
d["opening_debit"] -= d["opening_credit"]
d["opening_credit"] = 0.0
else:
d["opening_credit"] -= d["opening_debit"]
d["opening_debit"] = 0.0

View File

@ -166,10 +166,10 @@ def get_data():
"is_query_report": True,
},
{
"type": "page",
"name": "trial-balance",
"label": _("Trial Balance"),
"icon": "icon-table"
"type": "report",
"name": "Trial Balance",
"doctype": "GL Entry",
"is_query_report": True,
},
{
"type": "report",

View File

@ -70,4 +70,5 @@ erpnext.patches.v4_1.fix_sales_order_delivered_status
erpnext.patches.v4_1.fix_delivery_and_billing_status
execute:frappe.db.sql("update `tabAccount` set root_type='Liability' where root_type='Income' and report_type='Balance Sheet'")
execute:frappe.delete_doc("DocType", "Payment to Invoice Matching Tool")
execute:frappe.delete_doc("DocType", "Payment to Invoice Matching Tool Detail")
execute:frappe.delete_doc("DocType", "Payment to Invoice Matching Tool Detail")
execute:frappe.delete_doc("Page", "trial-balance") #2014-07-22

View File

@ -25,34 +25,21 @@ erpnext.financial_statements = {
"options": "Yearly\nHalf-yearly\nQuarterly\nMonthly",
"default": "Yearly",
"reqd": 1
},
{
"fieldname": "depth",
"label": __("Depth"),
"fieldtype": "Select",
"options": "3\n4\n5",
"default": "3"
}
],
"formatter": function(row, cell, value, columnDef, dataContext) {
"formatter": function(row, cell, value, columnDef, dataContext, default_formatter) {
if (columnDef.df.fieldname=="account") {
var link = $("<a></a>")
.text(dataContext.account_name)
.attr("onclick", "erpnext.financial_statements.open_general_ledger(" + JSON.stringify(dataContext) + ")");
value = dataContext.account_name;
var span = $("<span></span>")
.css("padding-left", (cint(dataContext.indent) * 21) + "px")
.append(link);
value = span.wrap("<p></p>").parent().html();
} else {
value = erpnext.financial_statements.default_formatter(row, cell, value, columnDef, dataContext);
columnDef.df.link_onclick = "erpnext.financial_statements.open_general_ledger(" + JSON.stringify(dataContext) + ")";
columnDef.df.is_tree = true;
}
value = default_formatter(row, cell, value, columnDef, dataContext);
if (!dataContext.parent_account) {
var $value = $(value).css("font-weight", "bold");
if (dataContext.is_profit_loss && dataContext[columnDef.df.fieldname] < 0) {
if (dataContext.warn_if_negative && dataContext[columnDef.df.fieldname] < 0) {
$value.addClass("text-danger");
}
@ -67,9 +54,13 @@ erpnext.financial_statements = {
frappe.route_options = {
"account": data.account,
"company": frappe.query_report.filters_by_name.company.get_value(),
"from_date": data.year_start_date,
"to_date": data.year_end_date
"from_date": data.from_date,
"to_date": data.to_date
};
frappe.set_route("query-report", "General Ledger");
}
},
"tree": true,
"name_field": "account",
"parent_field": "parent_account",
"initial_depth": 3
};