# 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