diff --git a/erpnext/accounts/report/balance_sheet/balance_sheet.py b/erpnext/accounts/report/balance_sheet/balance_sheet.py index 4efd098f76..23fa762fbc 100644 --- a/erpnext/accounts/report/balance_sheet/balance_sheet.py +++ b/erpnext/accounts/report/balance_sheet/balance_sheet.py @@ -8,7 +8,7 @@ from frappe.utils import flt from erpnext.accounts.report.financial_statements import (get_period_list, get_columns, get_data) def execute(filters=None): - period_list = get_period_list(filters.fiscal_year, filters.periodicity) + period_list = get_period_list(filters.from_fiscal_year, filters.to_fiscal_year, filters.periodicity) asset = get_data(filters.company, "Asset", "Debit", period_list, only_current_fiscal_year=False) liability = get_data(filters.company, "Liability", "Credit", period_list, only_current_fiscal_year=False) diff --git a/erpnext/accounts/report/cash_flow/cash_flow.js b/erpnext/accounts/report/cash_flow/cash_flow.js index f5ddd150e3..455664ffea 100644 --- a/erpnext/accounts/report/cash_flow/cash_flow.js +++ b/erpnext/accounts/report/cash_flow/cash_flow.js @@ -2,7 +2,8 @@ // For license information, please see license.txt frappe.require("assets/erpnext/js/financial_statements.js", function() { - frappe.query_reports["Cash Flow"] = erpnext.financial_statements; + frappe.query_reports["Cash Flow"] = $.extend({}, + erpnext.financial_statements); frappe.query_reports["Cash Flow"]["filters"].push({ "fieldname": "accumulated_values", diff --git a/erpnext/accounts/report/cash_flow/cash_flow.py b/erpnext/accounts/report/cash_flow/cash_flow.py index 3407526516..73b5c4bf1c 100644 --- a/erpnext/accounts/report/cash_flow/cash_flow.py +++ b/erpnext/accounts/report/cash_flow/cash_flow.py @@ -9,7 +9,7 @@ from erpnext.accounts.report.profit_and_loss_statement.profit_and_loss_statement def execute(filters=None): - period_list = get_period_list(filters.fiscal_year, filters.periodicity) + period_list = get_period_list(filters.from_fiscal_year, filters.to_fiscal_year, filters.periodicity) operation_accounts = { "section_name": "Operations", diff --git a/erpnext/accounts/report/financial_statements.py b/erpnext/accounts/report/financial_statements.py index c930952831..cfbfc54474 100644 --- a/erpnext/accounts/report/financial_statements.py +++ b/erpnext/accounts/report/financial_statements.py @@ -3,61 +3,69 @@ from __future__ import unicode_literals import frappe +import math from frappe import _ from frappe.utils import (flt, getdate, get_first_day, get_last_day, - add_months, add_days, formatdate) + add_months, add_days, formatdate, cint) -def get_period_list(fiscal_year, periodicity): +def get_period_list(from_fiscal_year, to_fiscal_year, periodicity): """Get a list of dict {"from_date": from_date, "to_date": to_date, "key": key, "label": label} Periodicity can be (Yearly, Quarterly, Monthly)""" - fy_start_end_date = frappe.db.get_value("Fiscal Year", fiscal_year, ["year_start_date", "year_end_date"]) - if not fy_start_end_date: - frappe.throw(_("Fiscal Year {0} not found.").format(fiscal_year)) + from_fy_start_end_date = frappe.db.get_value("Fiscal Year", from_fiscal_year, ["year_start_date", "year_end_date"]) + to_fy_start_end_date = frappe.db.get_value("Fiscal Year", to_fiscal_year, ["year_start_date", "year_end_date"]) + + if not from_fy_start_end_date: + frappe.throw(_("Fiscal Year {0} not found.").format(from_fiscal_year)) + + if not to_fy_start_end_date: + frappe.throw(_("Fiscal Year {0} not found.").format(to_fiscal_year)) # start with first day, so as to avoid year to_dates like 2-April if ever they occur] - year_start_date = get_first_day(getdate(fy_start_end_date[0])) - year_end_date = getdate(fy_start_end_date[1]) + year_start_date = get_first_day(getdate(from_fy_start_end_date[0])) + year_end_date = getdate(to_fy_start_end_date[1]) - if periodicity == "Yearly": - period_list = [frappe._dict({"from_date": year_start_date, "to_date": year_end_date, - "key": fiscal_year, "label": fiscal_year})] - else: - months_to_add = { - "Half-Yearly": 6, - "Quarterly": 3, - "Monthly": 1 - }[periodicity] + months_to_add = { + "Yearly": 12, + "Half-Yearly": 6, + "Quarterly": 3, + "Monthly": 1 + }[periodicity] - period_list = [] + period_list = [] - start_date = year_start_date - for i in xrange(12 / months_to_add): - period = frappe._dict({ - "from_date": start_date - }) - to_date = add_months(start_date, months_to_add) - start_date = to_date - - if to_date == get_first_day(to_date): - # if to_date is the first day, get the last day of previous month - to_date = add_days(to_date, -1) - else: - # to_date should be the last day of the new to_date's month - to_date = get_last_day(to_date) + start_date = year_start_date + months = flt(get_months(year_start_date, year_end_date)) + + for i in xrange(cint(math.ceil(months / flt(months_to_add)))): + period = frappe._dict({ + "from_date": start_date + }) + + to_date = add_months(start_date, months_to_add) + start_date = to_date + + if to_date == get_first_day(to_date): + # if to_date is the first day, get the last day of previous month + to_date = add_days(to_date, -1) + else: + # to_date should be the last day of the new to_date's month + to_date = get_last_day(to_date) + + if to_date <= year_end_date: + # the normal case + period.to_date = to_date + else: + # if a fiscal year ends before a 12 month period + period.to_date = year_end_date + + period.to_date_fiscal_year = get_date_fiscal_year(period.to_date) + + period_list.append(period) + + if period.to_date == year_end_date: + break - if to_date <= year_end_date: - # the normal case - period.to_date = to_date - else: - # if a fiscal year ends before a 12 month period - period.to_date = year_end_date - - period_list.append(period) - - if period.to_date == year_end_date: - break - # common processing for opts in period_list: key = opts["to_date"].strftime("%b_%Y").lower() @@ -74,6 +82,10 @@ def get_period_list(fiscal_year, periodicity): }) return period_list + +def get_months(start_date, end_date): + diff = (12 * end_date.year + end_date.month) - (12 * start_date.year + start_date.month) + return diff + 1 def get_label(periodicity, from_date, to_date): if periodicity=="Yearly": @@ -87,7 +99,8 @@ def get_label(periodicity, from_date, to_date): return label def get_data(company, root_type, balance_must_be, period_list, - accumulated_values=1, only_current_fiscal_year=True, ignore_closing_entries=False): + accumulated_values=1, only_current_fiscal_year=True, ignore_closing_entries=False, + ignore_accumulated_values_for_fy=False): accounts = get_accounts(company, root_type) if not accounts: return None @@ -106,7 +119,7 @@ def get_data(company, root_type, balance_must_be, period_list, root.lft, root.rgt, gl_entries_by_account, ignore_closing_entries=ignore_closing_entries) - calculate_values(accounts_by_name, gl_entries_by_account, period_list, accumulated_values) + calculate_values(accounts_by_name, gl_entries_by_account, period_list, accumulated_values, ignore_accumulated_values_for_fy) accumulate_values_into_parents(accounts, accounts_by_name, period_list, accumulated_values) out = prepare_data(accounts, balance_must_be, period_list, company_currency) out = filter_out_zero_value_rows(out, parent_children_map) @@ -116,18 +129,26 @@ def get_data(company, root_type, balance_must_be, period_list, return out -def calculate_values(accounts_by_name, gl_entries_by_account, period_list, accumulated_values): +def calculate_values(accounts_by_name, gl_entries_by_account, period_list, accumulated_values, ignore_accumulated_values_for_fy): for entries in gl_entries_by_account.values(): for entry in entries: d = accounts_by_name.get(entry.account) for period in period_list: # check if posting date is within the period + + fiscal_year = get_date_fiscal_year(entry.posting_date) if entry.posting_date <= period.to_date: - if accumulated_values or entry.posting_date >= period.from_date: + if (accumulated_values or entry.posting_date >= period.from_date) and \ + (fiscal_year == period.to_date_fiscal_year or not ignore_accumulated_values_for_fy): d[period.key] = d.get(period.key, 0.0) + flt(entry.debit) - flt(entry.credit) - + if entry.posting_date < period_list[0].year_start_date: d["opening_balance"] = d.get("opening_balance", 0.0) + flt(entry.debit) - flt(entry.credit) + +def get_date_fiscal_year(date): + from erpnext.accounts.utils import get_fiscal_year + + return get_fiscal_year(date)[0] def accumulate_values_into_parents(accounts, accounts_by_name, period_list, accumulated_values): """accumulate children's values in parent accounts""" diff --git a/erpnext/accounts/report/profit_and_loss_statement/profit_and_loss_statement.py b/erpnext/accounts/report/profit_and_loss_statement/profit_and_loss_statement.py index 62d6e69623..e15336b3bc 100644 --- a/erpnext/accounts/report/profit_and_loss_statement/profit_and_loss_statement.py +++ b/erpnext/accounts/report/profit_and_loss_statement/profit_and_loss_statement.py @@ -8,12 +8,12 @@ from frappe.utils import flt from erpnext.accounts.report.financial_statements import (get_period_list, get_columns, get_data) def execute(filters=None): - period_list = get_period_list(filters.fiscal_year, filters.periodicity) + period_list = get_period_list(filters.from_fiscal_year, filters.to_fiscal_year, filters.periodicity) income = get_data(filters.company, "Income", "Credit", period_list, - accumulated_values=filters.accumulated_values, ignore_closing_entries=True) + accumulated_values=filters.accumulated_values, ignore_closing_entries=True, ignore_accumulated_values_for_fy= True) expense = get_data(filters.company, "Expense", "Debit", period_list, - accumulated_values=filters.accumulated_values, ignore_closing_entries=True) + accumulated_values=filters.accumulated_values, ignore_closing_entries=True, ignore_accumulated_values_for_fy= True) net_profit_loss = get_net_profit_loss(income, expense, period_list, filters.company) diff --git a/erpnext/public/js/financial_statements.js b/erpnext/public/js/financial_statements.js index c1e53a272f..bb13f81a3c 100644 --- a/erpnext/public/js/financial_statements.js +++ b/erpnext/public/js/financial_statements.js @@ -1,37 +1,7 @@ frappe.provide("erpnext.financial_statements"); erpnext.financial_statements = { - "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 - }, - { - "fieldname": "periodicity", - "label": __("Periodicity"), - "fieldtype": "Select", - "options": [ - { "value": "Monthly", "label": __("Monthly") }, - { "value": "Quarterly", "label": __("Quarterly") }, - { "value": "Half-Yearly", "label": __("Half-Yearly") }, - { "value": "Yearly", "label": __("Yearly") } - ], - "default": "Monthly", - "reqd": 1 - } - ], + "filters": get_filters(), "formatter": function(row, cell, value, columnDef, dataContext, default_formatter) { if (columnDef.df.fieldname=="account") { value = dataContext.account_name; @@ -71,6 +41,8 @@ erpnext.financial_statements = { "initial_depth": 3, onload: function(report) { // dropdown for links to other financial statements + erpnext.financial_statements.filters = get_filters() + report.page.add_inner_button(__("Balance Sheet"), function() { var filters = report.get_values(); frappe.set_route('query-report', 'Balance Sheet', {company: filters.company}); @@ -85,3 +57,45 @@ erpnext.financial_statements = { }, 'Financial Statements'); } }; + +function get_filters(){ + return [ + { + "fieldname":"company", + "label": __("Company"), + "fieldtype": "Link", + "options": "Company", + "default": frappe.defaults.get_user_default("Company"), + "reqd": 1 + }, + { + "fieldname":"from_fiscal_year", + "label": __("Fiscal Year"), + "fieldtype": "Link", + "options": "Fiscal Year", + "default": frappe.defaults.get_user_default("fiscal_year"), + "reqd": 1 + }, + { + "fieldname":"to_fiscal_year", + "label": __("Fiscal Year"), + "fieldtype": "Link", + "options": "Fiscal Year", + "default": frappe.defaults.get_user_default("fiscal_year"), + "reqd": 1 + }, + { + "fieldname": "periodicity", + "label": __("Periodicity"), + "fieldtype": "Select", + "options": [ + { "value": "Monthly", "label": __("Monthly") }, + { "value": "Quarterly", "label": __("Quarterly") }, + { "value": "Half-Yearly", "label": __("Half-Yearly") }, + { "value": "Yearly", "label": __("Yearly") } + ], + "default": "Monthly", + "reqd": 1 + } + ] +}