feat: Dimension-wise Accounts Balance Report
This commit is contained in:
parent
c6b3766fb2
commit
31b5dfe9ee
@ -0,0 +1,81 @@
|
|||||||
|
// Copyright (c) 2016, Frappe Technologies Pvt. Ltd. and contributors
|
||||||
|
// For license information, please see license.txt
|
||||||
|
/* eslint-disable */
|
||||||
|
|
||||||
|
frappe.require("assets/erpnext/js/financial_statements.js", function() {
|
||||||
|
frappe.query_reports["Dimension-wise Accounts Balance Report"] = {
|
||||||
|
"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);
|
||||||
|
frappe.query_report.set_filter_value({
|
||||||
|
from_date: fy.year_start_date,
|
||||||
|
to_date: fy.year_end_date
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"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": "finance_book",
|
||||||
|
"label": __("Finance Book"),
|
||||||
|
"fieldtype": "Link",
|
||||||
|
"options": "Finance Book",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldname": "dimension",
|
||||||
|
"label": __("Select Dimension"),
|
||||||
|
"fieldtype": "Select",
|
||||||
|
"options": get_accounting_dimension_options(),
|
||||||
|
"reqd": 1,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
"formatter": erpnext.financial_statements.formatter,
|
||||||
|
"tree": true,
|
||||||
|
"name_field": "account",
|
||||||
|
"parent_field": "parent_account",
|
||||||
|
"initial_depth": 3
|
||||||
|
}
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
|
function get_accounting_dimension_options() {
|
||||||
|
let options =["", "Cost Center", "Project"];
|
||||||
|
frappe.db.get_list('Accounting Dimension',
|
||||||
|
{fields:['document_type']}).then((res) => {
|
||||||
|
res.forEach((dimension) => {
|
||||||
|
options.push(dimension.document_type);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
return options
|
||||||
|
}
|
||||||
@ -0,0 +1,22 @@
|
|||||||
|
{
|
||||||
|
"add_total_row": 0,
|
||||||
|
"columns": [],
|
||||||
|
"creation": "2021-04-09 16:48:59.548018",
|
||||||
|
"disable_prepared_report": 0,
|
||||||
|
"disabled": 0,
|
||||||
|
"docstatus": 0,
|
||||||
|
"doctype": "Report",
|
||||||
|
"filters": [],
|
||||||
|
"idx": 0,
|
||||||
|
"is_standard": "Yes",
|
||||||
|
"modified": "2021-04-09 16:48:59.548018",
|
||||||
|
"modified_by": "Administrator",
|
||||||
|
"module": "Accounts",
|
||||||
|
"name": "Dimension-wise Accounts Balance Report",
|
||||||
|
"owner": "Administrator",
|
||||||
|
"prepared_report": 0,
|
||||||
|
"ref_doctype": "GL Entry",
|
||||||
|
"report_name": "Dimension-wise Accounts Balance Report",
|
||||||
|
"report_type": "Script Report",
|
||||||
|
"roles": []
|
||||||
|
}
|
||||||
@ -0,0 +1,205 @@
|
|||||||
|
# Copyright (c) 2013, Frappe Technologies Pvt. Ltd. and contributors
|
||||||
|
# For license information, please see license.txt
|
||||||
|
|
||||||
|
from __future__ import unicode_literals
|
||||||
|
import frappe, erpnext
|
||||||
|
from frappe import _
|
||||||
|
from frappe.utils import (flt, getdate, get_first_day, add_months, add_days, formatdate, cstr, cint)
|
||||||
|
|
||||||
|
from erpnext.accounts.report.financial_statements import get_accounts, filter_accounts, get_appropriate_currency, get_fiscal_year_data, validate_fiscal_year, filter_out_zero_value_rows
|
||||||
|
from erpnext.accounts.doctype.accounting_dimension.accounting_dimension import get_accounting_dimensions, get_dimension_with_children
|
||||||
|
from erpnext.accounts.report.trial_balance.trial_balance import validate_filters, get_opening_balances, calculate_values
|
||||||
|
|
||||||
|
from six import itervalues
|
||||||
|
|
||||||
|
def execute(filters=None):
|
||||||
|
validate_filters(filters)
|
||||||
|
dimension_items_list = get_dimension_items_list(filters.dimension, filters.company)
|
||||||
|
|
||||||
|
if not dimension_items_list:
|
||||||
|
return [], []
|
||||||
|
|
||||||
|
dimension_items_list = [''.join(d) for d in dimension_items_list]
|
||||||
|
columns = get_columns(dimension_items_list)
|
||||||
|
data = get_data(filters, dimension_items_list)
|
||||||
|
|
||||||
|
return columns, data
|
||||||
|
|
||||||
|
def get_data(filters, dimension_items_list):
|
||||||
|
company_currency = erpnext.get_company_currency(filters.company)
|
||||||
|
acc = frappe.db.sql("""
|
||||||
|
select
|
||||||
|
name, account_number, parent_account, lft, rgt, root_type,
|
||||||
|
report_type, account_name, include_in_gross, account_type, is_group
|
||||||
|
from
|
||||||
|
`tabAccount`
|
||||||
|
where
|
||||||
|
company=%s
|
||||||
|
order by lft""", (filters.company), as_dict=True)
|
||||||
|
|
||||||
|
if not acc:
|
||||||
|
return None
|
||||||
|
|
||||||
|
accounts, accounts_by_name, parent_children_map = filter_accounts(acc)
|
||||||
|
|
||||||
|
min_lft, max_rgt = frappe.db.sql("""select min(lft), max(rgt) from `tabAccount`
|
||||||
|
where company=%s""", (filters.company))[0]
|
||||||
|
|
||||||
|
account = frappe.db.sql_list("""select name from `tabAccount`
|
||||||
|
where lft >= %s and rgt <= %s and company = %s""", (min_lft, max_rgt, filters.company))
|
||||||
|
|
||||||
|
gl_entries_by_account = {}
|
||||||
|
set_gl_entries_by_account(dimension_items_list, filters, account, gl_entries_by_account)
|
||||||
|
format_gl_entries(gl_entries_by_account, accounts_by_name, dimension_items_list)
|
||||||
|
accumulate_values_into_parents(accounts, accounts_by_name, dimension_items_list)
|
||||||
|
out = prepare_data(accounts, filters, parent_children_map, company_currency, dimension_items_list)
|
||||||
|
out = filter_out_zero_value_rows(out, parent_children_map)
|
||||||
|
|
||||||
|
return out
|
||||||
|
|
||||||
|
def set_gl_entries_by_account(dimension_items_list, filters, account, gl_entries_by_account):
|
||||||
|
for item in dimension_items_list:
|
||||||
|
condition = get_condition(filters.from_date, item, filters.dimension)
|
||||||
|
if account:
|
||||||
|
condition += " and account in ({})"\
|
||||||
|
.format(", ".join([frappe.db.escape(d) for d in account]))
|
||||||
|
|
||||||
|
gl_filters = {
|
||||||
|
"company": filters.get("company"),
|
||||||
|
"from_date": filters.get("from_date"),
|
||||||
|
"to_date": filters.get("to_date"),
|
||||||
|
"finance_book": cstr(filters.get("finance_book"))
|
||||||
|
}
|
||||||
|
|
||||||
|
gl_filters['item'] = ''.join(item)
|
||||||
|
|
||||||
|
if filters.get("include_default_book_entries"):
|
||||||
|
gl_filters["company_fb"] = frappe.db.get_value("Company",
|
||||||
|
filters.company, 'default_finance_book')
|
||||||
|
|
||||||
|
for key, value in filters.items():
|
||||||
|
if value:
|
||||||
|
gl_filters.update({
|
||||||
|
key: value
|
||||||
|
})
|
||||||
|
|
||||||
|
gl_entries = frappe.db.sql("""
|
||||||
|
select
|
||||||
|
posting_date, account, debit, credit, is_opening, fiscal_year,
|
||||||
|
debit_in_account_currency, credit_in_account_currency, account_currency
|
||||||
|
from
|
||||||
|
`tabGL Entry`
|
||||||
|
where
|
||||||
|
company=%(company)s
|
||||||
|
{condition}
|
||||||
|
and posting_date <= %(to_date)s
|
||||||
|
and is_cancelled = 0
|
||||||
|
order by account, posting_date""".format(
|
||||||
|
condition=condition),
|
||||||
|
gl_filters, as_dict=True) #nosec
|
||||||
|
|
||||||
|
for entry in gl_entries:
|
||||||
|
entry['dimension_item'] = ''.join(item)
|
||||||
|
gl_entries_by_account.setdefault(entry.account, []).append(entry)
|
||||||
|
|
||||||
|
def format_gl_entries(gl_entries_by_account, accounts_by_name, dimension_items_list):
|
||||||
|
|
||||||
|
for entries in itervalues(gl_entries_by_account):
|
||||||
|
for entry in entries:
|
||||||
|
d = accounts_by_name.get(entry.account)
|
||||||
|
if not d:
|
||||||
|
frappe.msgprint(
|
||||||
|
_("Could not retrieve information for {0}.").format(entry.account), title="Error",
|
||||||
|
raise_exception=1
|
||||||
|
)
|
||||||
|
for item in dimension_items_list:
|
||||||
|
if item == entry.dimension_item:
|
||||||
|
x = flt(entry.debit) - flt(entry.credit)
|
||||||
|
d[frappe.scrub(item)] = d.get(frappe.scrub(item), 0.0) + flt(entry.debit) - flt(entry.credit)
|
||||||
|
|
||||||
|
def prepare_data(accounts, filters, parent_children_map, company_currency, dimension_items_list):
|
||||||
|
data = []
|
||||||
|
|
||||||
|
for d in accounts:
|
||||||
|
has_value = False
|
||||||
|
row = {
|
||||||
|
"account": d.name,
|
||||||
|
"parent_account": d.parent_account,
|
||||||
|
"indent": d.indent,
|
||||||
|
"from_date": filters.from_date,
|
||||||
|
"to_date": filters.to_date,
|
||||||
|
"currency": company_currency,
|
||||||
|
"account_name": ('{} - {}'.format(d.account_number, d.account_name)
|
||||||
|
if d.account_number else d.account_name)
|
||||||
|
}
|
||||||
|
|
||||||
|
for item in dimension_items_list:
|
||||||
|
row[frappe.scrub(item)] = flt(d.get(frappe.scrub(item), 0.0), 3)
|
||||||
|
|
||||||
|
if abs(row[frappe.scrub(item)]) >= 0.005:
|
||||||
|
# ignore zero values
|
||||||
|
has_value = True
|
||||||
|
|
||||||
|
row["has_value"] = has_value
|
||||||
|
data.append(row)
|
||||||
|
|
||||||
|
return data
|
||||||
|
|
||||||
|
def accumulate_values_into_parents(accounts, accounts_by_name, dimension_items_list):
|
||||||
|
"""accumulate children's values in parent accounts"""
|
||||||
|
for d in reversed(accounts):
|
||||||
|
if d.parent_account:
|
||||||
|
for item in dimension_items_list:
|
||||||
|
accounts_by_name[d.parent_account][frappe.scrub(item)] = \
|
||||||
|
accounts_by_name[d.parent_account].get(frappe.scrub(item), 0.0) + d.get(frappe.scrub(item), 0.0)
|
||||||
|
|
||||||
|
def get_condition(from_date, item, dimension):
|
||||||
|
conditions = []
|
||||||
|
|
||||||
|
if from_date:
|
||||||
|
conditions.append("posting_date >= %(from_date)s")
|
||||||
|
if dimension:
|
||||||
|
if dimension not in ['Cost Center', 'Project']:
|
||||||
|
if dimension in ['Customer', 'Supplier']:
|
||||||
|
dimension = 'Party'
|
||||||
|
else:
|
||||||
|
dimension = 'Voucher No'
|
||||||
|
txt = "{0} = %(item)s".format(frappe.scrub(dimension))
|
||||||
|
conditions.append(txt)
|
||||||
|
|
||||||
|
return " and {}".format(" and ".join(conditions)) if conditions else ""
|
||||||
|
|
||||||
|
def get_dimension_items_list(dimension, company):
|
||||||
|
meta = frappe.get_meta(dimension, cached=False)
|
||||||
|
fieldnames = [d.fieldname for d in meta.get("fields")]
|
||||||
|
filters = {}
|
||||||
|
if 'company' in fieldnames:
|
||||||
|
filters['company'] = company
|
||||||
|
return frappe.get_all(dimension, filters, as_list=True)
|
||||||
|
|
||||||
|
def get_columns(dimension_items_list, accumulated_values=1, company=None):
|
||||||
|
columns = [{
|
||||||
|
"fieldname": "account",
|
||||||
|
"label": _("Account"),
|
||||||
|
"fieldtype": "Link",
|
||||||
|
"options": "Account",
|
||||||
|
"width": 300
|
||||||
|
}]
|
||||||
|
if company:
|
||||||
|
columns.append({
|
||||||
|
"fieldname": "currency",
|
||||||
|
"label": _("Currency"),
|
||||||
|
"fieldtype": "Link",
|
||||||
|
"options": "Currency",
|
||||||
|
"hidden": 1
|
||||||
|
})
|
||||||
|
for item in dimension_items_list:
|
||||||
|
columns.append({
|
||||||
|
"fieldname": frappe.scrub(item),
|
||||||
|
"label": item,
|
||||||
|
"fieldtype": "Currency",
|
||||||
|
"options": "currency",
|
||||||
|
"width": 150
|
||||||
|
})
|
||||||
|
|
||||||
|
return columns
|
||||||
Loading…
x
Reference in New Issue
Block a user