Merge pull request #7440 from nabinhait/gle_repost_optimization

Optimization to reduce GLE reposting time for future stock transactions
This commit is contained in:
Nabin Hait
2017-01-13 11:33:42 +05:30
committed by GitHub
16 changed files with 128 additions and 78 deletions

View File

@@ -43,11 +43,13 @@ class FiscalYear(Document):
def on_update(self):
check_duplicate_fiscal_year(self)
frappe.cache().delete_value("fiscal_years")
def on_trash(self):
global_defaults = frappe.get_doc("Global Defaults")
if global_defaults.current_fiscal_year == self.name:
frappe.throw(_("You cannot delete Fiscal Year {0}. Fiscal Year {0} is set as default in Global Settings").format(self.name))
frappe.cache().delete_value("fiscal_years")
def validate_overlap(self):
existing_fiscal_years = frappe.db.sql("""select name from `tabFiscal Year`

View File

@@ -18,22 +18,27 @@ class GLEntry(Document):
def validate(self):
self.flags.ignore_submit_comment = True
self.check_mandatory()
self.pl_must_have_cost_center()
self.check_pl_account()
self.validate_cost_center()
self.validate_party()
self.validate_currency()
self.validate_and_set_fiscal_year()
if not self.flags.from_repost:
self.pl_must_have_cost_center()
self.check_pl_account()
self.validate_cost_center()
self.validate_party()
self.validate_currency()
def on_update_with_args(self, adv_adj, update_outstanding = 'Yes'):
self.validate_account_details(adv_adj)
def on_update_with_args(self, adv_adj, update_outstanding = 'Yes', from_repost=False):
if not from_repost:
self.validate_account_details(adv_adj)
check_freezing_date(self.posting_date, adv_adj)
validate_frozen_account(self.account, adv_adj)
check_freezing_date(self.posting_date, adv_adj)
validate_balance_type(self.account, adv_adj)
# Update outstanding amt on against voucher
if self.against_voucher_type in ['Journal Entry', 'Sales Invoice', 'Purchase Invoice'] \
and self.against_voucher and update_outstanding == 'Yes':
and self.against_voucher and update_outstanding == 'Yes' and not from_repost:
update_outstanding_amt(self.account, self.party_type, self.party, self.against_voucher_type,
self.against_voucher)

View File

@@ -35,9 +35,9 @@ class PeriodClosingVoucher(AccountsController):
def validate_posting_date(self):
from erpnext.accounts.utils import get_fiscal_year, validate_fiscal_year
validate_fiscal_year(self.posting_date, self.fiscal_year, label=_("Posting Date"), doc=self)
validate_fiscal_year(self.posting_date, self.fiscal_year, self.company, label=_("Posting Date"), doc=self)
self.year_start_date = get_fiscal_year(self.posting_date, self.fiscal_year)[1]
self.year_start_date = get_fiscal_year(self.posting_date, self.fiscal_year, company=self.company)[1]
pce = frappe.db.sql("""select name from `tabPeriod Closing Voucher`
where posting_date > %s and fiscal_year = %s and docstatus = 1""",

View File

@@ -11,7 +11,7 @@ from erpnext.accounts.doctype.journal_entry.test_journal_entry import make_journ
class TestPeriodClosingVoucher(unittest.TestCase):
def test_closing_entry(self):
year_start_date = get_fiscal_year(today())[1]
year_start_date = get_fiscal_year(today(), company="_Test Company")[1]
make_journal_entry("_Test Bank - _TC", "Sales - _TC", 400,
"_Test Cost Center - _TC", posting_date=now(), submit=True)
@@ -70,7 +70,7 @@ class TestPeriodClosingVoucher(unittest.TestCase):
"doctype": "Period Closing Voucher",
"closing_account_head": "_Test Account Reserves and Surplus - _TC",
"company": "_Test Company",
"fiscal_year": get_fiscal_year(today())[0],
"fiscal_year": get_fiscal_year(today(), company="_Test Company")[0],
"posting_date": today(),
"remarks": "test"
})

View File

@@ -302,11 +302,11 @@ class PurchaseInvoice(BuyingController):
asset.flags.ignore_validate_update_after_submit = True
asset.save()
def make_gl_entries(self, repost_future_gle=True):
def make_gl_entries(self, gl_entries=None, repost_future_gle=True, from_repost=False):
if not self.grand_total:
return
gl_entries = self.get_gl_entries()
if not gl_entries:
gl_entries = self.get_gl_entries()
if gl_entries:
update_outstanding = "No" if (cint(self.is_paid) or self.write_off_account) else "Yes"

View File

@@ -532,10 +532,12 @@ class SalesInvoice(SellingController):
if d.delivery_note and frappe.db.get_value("Delivery Note", d.delivery_note, "docstatus") != 1:
throw(_("Delivery Note {0} is not submitted").format(d.delivery_note))
def make_gl_entries(self, repost_future_gle=True):
def make_gl_entries(self, gl_entries=None, repost_future_gle=True, from_repost=False):
if not self.grand_total:
return
gl_entries = self.get_gl_entries()
if not gl_entries:
gl_entries = self.get_gl_entries()
if gl_entries:
from erpnext.accounts.general_ledger import make_gl_entries

View File

@@ -11,12 +11,12 @@ from erpnext.accounts.doctype.budget.budget import validate_expense_against_budg
class StockAccountInvalidTransaction(frappe.ValidationError): pass
def make_gl_entries(gl_map, cancel=False, adv_adj=False, merge_entries=True, update_outstanding='Yes'):
def make_gl_entries(gl_map, cancel=False, adv_adj=False, merge_entries=True, update_outstanding='Yes', from_repost=False):
if gl_map:
if not cancel:
gl_map = process_gl_map(gl_map, merge_entries)
if gl_map and len(gl_map) > 1:
save_entries(gl_map, adv_adj, update_outstanding)
save_entries(gl_map, adv_adj, update_outstanding, from_repost)
else:
frappe.throw(_("Incorrect number of General Ledger Entries found. You might have selected a wrong Account in the transaction."))
else:
@@ -78,21 +78,26 @@ def check_if_in_list(gle, gl_map):
and cstr(e.get('project')) == cstr(gle.get('project')):
return e
def save_entries(gl_map, adv_adj, update_outstanding):
validate_account_for_auto_accounting_for_stock(gl_map)
def save_entries(gl_map, adv_adj, update_outstanding, from_repost=False):
if not from_repost:
validate_account_for_auto_accounting_for_stock(gl_map)
round_off_debit_credit(gl_map)
for entry in gl_map:
make_entry(entry, adv_adj, update_outstanding)
make_entry(entry, adv_adj, update_outstanding, from_repost)
# check against budget
validate_expense_against_budget(entry)
if not from_repost:
validate_expense_against_budget(entry)
def make_entry(args, adv_adj, update_outstanding):
def make_entry(args, adv_adj, update_outstanding, from_repost=False):
args.update({"doctype": "GL Entry"})
gle = frappe.get_doc(args)
gle.flags.ignore_permissions = 1
gle.flags.from_repost = from_repost
gle.insert()
gle.run_method("on_update_with_args", adv_adj, update_outstanding)
gle.run_method("on_update_with_args", adv_adj, update_outstanding, from_repost)
gle.submit()
def validate_account_for_auto_accounting_for_stock(gl_map):

View File

@@ -10,7 +10,8 @@ from erpnext.accounts.utils import get_fiscal_year
def execute(filters=None):
period_list = get_period_list(filters.from_fiscal_year, filters.to_fiscal_year, filters.periodicity)
period_list = get_period_list(filters.from_fiscal_year, filters.to_fiscal_year,
filters.periodicity)
operation_accounts = {
"section_name": "Operations",
@@ -103,7 +104,7 @@ def get_account_type_based_data(company, account_type, period_list, accumulated_
data = {}
total = 0
for period in period_list:
start_date = get_start_date(period, accumulated_values)
start_date = get_start_date(period, accumulated_values, company)
gl_sum = frappe.db.sql_list("""
select sum(credit) - sum(debit)
from `tabGL Entry`
@@ -126,10 +127,10 @@ def get_account_type_based_data(company, account_type, period_list, accumulated_
data["total"] = total
return data
def get_start_date(period, accumulated_values):
def get_start_date(period, accumulated_values, company):
start_date = period["year_start_date"]
if accumulated_values:
start_date = get_fiscal_year(period.to_date)[1]
start_date = get_fiscal_year(period.to_date, company=company)[1]
return start_date

View File

@@ -3,10 +3,8 @@
from __future__ import unicode_literals
import frappe
import math
from frappe import _
from frappe.utils import (flt, getdate, get_first_day, get_last_day, date_diff,
add_months, add_days, formatdate, cint)
from frappe.utils import flt, getdate, get_first_day, add_months, add_days, formatdate
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}
@@ -149,7 +147,6 @@ def calculate_values(accounts_by_name, gl_entries_by_account, period_list, accum
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):

View File

@@ -20,32 +20,63 @@ def get_fiscal_year(date=None, fiscal_year=None, label="Date", verbose=1, compan
return get_fiscal_years(date, fiscal_year, label, verbose, company, as_dict=as_dict)[0]
def get_fiscal_years(transaction_date=None, fiscal_year=None, label="Date", verbose=1, company=None, as_dict=False):
# if year start date is 2012-04-01, year end date should be 2013-03-31 (hence subdate)
cond = " disabled = 0"
if fiscal_year:
cond += " and fy.name = %(fiscal_year)s"
else:
cond += " and %(transaction_date)s >= fy.year_start_date and %(transaction_date)s <= fy.year_end_date"
fiscal_years = frappe.cache().hget("fiscal_years", company) or []
if not fiscal_years:
# if year start date is 2012-04-01, year end date should be 2013-03-31 (hence subdate)
cond = ""
if fiscal_year:
cond += " and fy.name = {0}".format(frappe.db.escape(fiscal_year))
if company:
cond += """
and (not exists (select name
from `tabFiscal Year Company` fyc
where fyc.parent = fy.name)
or exists(select company
from `tabFiscal Year Company` fyc
where fyc.parent = fy.name
and fyc.company=%(company)s)
)
"""
if company:
cond += """ and (not exists(select name from `tabFiscal Year Company` fyc where fyc.parent = fy.name)
or exists(select company from `tabFiscal Year Company` fyc where fyc.parent = fy.name and fyc.company=%(company)s ))"""
fiscal_years = frappe.db.sql("""
select
fy.name, fy.year_start_date, fy.year_end_date
from
`tabFiscal Year` fy
where
disabled = 0 {0}
order by
fy.year_start_date desc""".format(cond), {
"company": company
}, as_dict=True)
frappe.cache().hset("fiscal_years", company, fiscal_years)
fy = frappe.db.sql("""select fy.name, fy.year_start_date, fy.year_end_date from `tabFiscal Year` fy
where %s order by fy.year_start_date desc""" % cond, {
"fiscal_year": fiscal_year,
"transaction_date": transaction_date,
"company": company
}, as_dict=as_dict)
if transaction_date:
transaction_date = getdate(transaction_date)
if not fy:
error_msg = _("""{0} {1} not in any active Fiscal Year. For more details check {2}.""").format(label, formatdate(transaction_date), "https://frappe.github.io/erpnext/user/manual/en/accounts/articles/fiscal-year-error")
if verbose==1: frappe.msgprint(error_msg)
raise FiscalYearError, error_msg
return fy
for fy in fiscal_years:
matched = False
if fiscal_year and fy.name == fiscal_year:
matched = True
def validate_fiscal_year(date, fiscal_year, label=_("Date"), doc=None):
years = [f[0] for f in get_fiscal_years(date, label=label)]
if (transaction_date and getdate(fy.year_start_date) <= transaction_date
and getdate(fy.year_end_date) >= transaction_date):
matched = True
if matched:
if as_dict:
return (fy,)
else:
return ((fy.name, fy.year_start_date, fy.year_end_date),)
error_msg = _("""{0} {1} not in any active Fiscal Year.""").format(label, formatdate(transaction_date))
if verbose==1: frappe.msgprint(error_msg)
raise FiscalYearError, error_msg
def validate_fiscal_year(date, fiscal_year, company, label=_("Date"), doc=None):
years = [f[0] for f in get_fiscal_years(date, label=label, company=company)]
if fiscal_year not in years:
if doc:
doc.fiscal_year = years[0]