From e014b898bdd5bfa7563e1609deb0bc139e44a7e9 Mon Sep 17 00:00:00 2001 From: Mangesh-Khairnar Date: Mon, 19 Aug 2019 10:04:34 +0530 Subject: [PATCH 01/10] fix: valuation rate in stock ledger (#18743) * fix: valuation rate in stock ledger * test: allow zero valuation rate for items --- .../doctype/delivery_note/test_delivery_note.py | 1 + erpnext/stock/stock_ledger.py | 16 +++++++++++----- 2 files changed, 12 insertions(+), 5 deletions(-) diff --git a/erpnext/stock/doctype/delivery_note/test_delivery_note.py b/erpnext/stock/doctype/delivery_note/test_delivery_note.py index bc95c965bc5..91b6f4c6063 100644 --- a/erpnext/stock/doctype/delivery_note/test_delivery_note.py +++ b/erpnext/stock/doctype/delivery_note/test_delivery_note.py @@ -701,6 +701,7 @@ def create_delivery_note(**args): "qty": args.qty or 1, "rate": args.rate or 100, "conversion_factor": 1.0, + "allow_zero_valuation_rate": args.allow_zero_valuation_rate or 1, "expense_account": "Cost of Goods Sold - _TC", "cost_center": args.cost_center or "_Test Cost Center - _TC", "serial_no": args.serial_no, diff --git a/erpnext/stock/stock_ledger.py b/erpnext/stock/stock_ledger.py index 9517cd495b4..26fe517ad71 100644 --- a/erpnext/stock/stock_ledger.py +++ b/erpnext/stock/stock_ledger.py @@ -457,16 +457,22 @@ def get_valuation_rate(item_code, warehouse, voucher_type, voucher_no, last_valuation_rate = frappe.db.sql("""select valuation_rate from `tabStock Ledger Entry` - where item_code = %s and warehouse = %s - and valuation_rate >= 0 - order by posting_date desc, posting_time desc, name desc limit 1""", (item_code, warehouse)) + where + item_code = %s + AND warehouse = %s + AND valuation_rate >= 0 + AND NOT (voucher_no = %s AND voucher_type = %s) + order by posting_date desc, posting_time desc, name desc limit 1""", (item_code, warehouse, voucher_no, voucher_type)) if not last_valuation_rate: # Get valuation rate from last sle for the item against any warehouse last_valuation_rate = frappe.db.sql("""select valuation_rate from `tabStock Ledger Entry` - where item_code = %s and valuation_rate > 0 - order by posting_date desc, posting_time desc, name desc limit 1""", item_code) + where + item_code = %s + AND valuation_rate > 0 + AND NOT(voucher_no = %s AND voucher_type = %s) + order by posting_date desc, posting_time desc, name desc limit 1""", (item_code, voucher_no, voucher_type)) if last_valuation_rate: return flt(last_valuation_rate[0][0]) # as there is previous records, it might come with zero rate From 736eed01c2d00419086330234ad4d9fad3eaa189 Mon Sep 17 00:00:00 2001 From: Mangesh-Khairnar Date: Mon, 19 Aug 2019 10:20:48 +0530 Subject: [PATCH 02/10] fix: notify update on status change (#18764) --- erpnext/projects/doctype/project/project.py | 1 + 1 file changed, 1 insertion(+) diff --git a/erpnext/projects/doctype/project/project.py b/erpnext/projects/doctype/project/project.py index aab125fa923..bbf5fec3453 100644 --- a/erpnext/projects/doctype/project/project.py +++ b/erpnext/projects/doctype/project/project.py @@ -165,6 +165,7 @@ class Project(Document): task.run_method("validate") task.db_update() + task.notify_update() else: task.save(ignore_permissions = True) task_names.append(task.name) From 269868130fe5c462660a613cc18d265c7be5cf7d Mon Sep 17 00:00:00 2001 From: Anurag Mishra <32095923+Anurag810@users.noreply.github.com> Date: Mon, 19 Aug 2019 10:27:53 +0530 Subject: [PATCH 03/10] fix: validated cost center in financial_statement (#18732) * fix: validated cost center in financial_statement * Update financial_statements.py --- erpnext/accounts/report/financial_statements.py | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/erpnext/accounts/report/financial_statements.py b/erpnext/accounts/report/financial_statements.py index 9765310fc9b..c615f7b23fb 100644 --- a/erpnext/accounts/report/financial_statements.py +++ b/erpnext/accounts/report/financial_statements.py @@ -407,9 +407,12 @@ def get_cost_centers_with_children(cost_centers): all_cost_centers = [] for d in cost_centers: - lft, rgt = frappe.db.get_value("Cost Center", d, ["lft", "rgt"]) - children = frappe.get_all("Cost Center", filters={"lft": [">=", lft], "rgt": ["<=", rgt]}) - all_cost_centers += [c.name for c in children] + if frappe.db.exists("Cost Center", d): + lft, rgt = frappe.db.get_value("Cost Center", d, ["lft", "rgt"]) + children = frappe.get_all("Cost Center", filters={"lft": [">=", lft], "rgt": ["<=", rgt]}) + all_cost_centers += [c.name for c in children] + else: + frappe.throw(_("Cost Center: {0} does not exist".format(d))) return list(set(all_cost_centers)) From 311fe5b3dc65d96467e5ff5fdb371438e97c2448 Mon Sep 17 00:00:00 2001 From: Anurag Mishra <32095923+Anurag810@users.noreply.github.com> Date: Mon, 19 Aug 2019 10:30:44 +0530 Subject: [PATCH 04/10] fix: removed filters(not required) (#18728) --- .../controllers/sales_and_purchase_return.py | 35 ++++++++----------- 1 file changed, 15 insertions(+), 20 deletions(-) diff --git a/erpnext/controllers/sales_and_purchase_return.py b/erpnext/controllers/sales_and_purchase_return.py index 2fddcdf24c5..7d03722b161 100644 --- a/erpnext/controllers/sales_and_purchase_return.py +++ b/erpnext/controllers/sales_and_purchase_return.py @@ -18,34 +18,29 @@ def validate_return(doc): validate_returned_items(doc) def validate_return_against(doc): - filters = {"doctype": doc.doctype, "docstatus": 1, "company": doc.company} - if doc.meta.get_field("customer") and doc.customer: - filters["customer"] = doc.customer - elif doc.meta.get_field("supplier") and doc.supplier: - filters["supplier"] = doc.supplier - - if not frappe.db.exists(filters): + if not frappe.db.exists(doc.doctype, doc.return_against): frappe.throw(_("Invalid {0}: {1}") .format(doc.meta.get_label("return_against"), doc.return_against)) else: ref_doc = frappe.get_doc(doc.doctype, doc.return_against) - # validate posting date time - return_posting_datetime = "%s %s" % (doc.posting_date, doc.get("posting_time") or "00:00:00") - ref_posting_datetime = "%s %s" % (ref_doc.posting_date, ref_doc.get("posting_time") or "00:00:00") + if ref_doc.company == doc.company and ref_doc.customer = doc.customer and ref_doc.docstatus == 1: + # validate posting date time + return_posting_datetime = "%s %s" % (doc.posting_date, doc.get("posting_time") or "00:00:00") + ref_posting_datetime = "%s %s" % (ref_doc.posting_date, ref_doc.get("posting_time") or "00:00:00") - if get_datetime(return_posting_datetime) < get_datetime(ref_posting_datetime): - frappe.throw(_("Posting timestamp must be after {0}").format(format_datetime(ref_posting_datetime))) + if get_datetime(return_posting_datetime) < get_datetime(ref_posting_datetime): + frappe.throw(_("Posting timestamp must be after {0}").format(format_datetime(ref_posting_datetime))) - # validate same exchange rate - if doc.conversion_rate != ref_doc.conversion_rate: - frappe.throw(_("Exchange Rate must be same as {0} {1} ({2})") - .format(doc.doctype, doc.return_against, ref_doc.conversion_rate)) + # validate same exchange rate + if doc.conversion_rate != ref_doc.conversion_rate: + frappe.throw(_("Exchange Rate must be same as {0} {1} ({2})") + .format(doc.doctype, doc.return_against, ref_doc.conversion_rate)) - # validate update stock - if doc.doctype == "Sales Invoice" and doc.update_stock and not ref_doc.update_stock: - frappe.throw(_("'Update Stock' can not be checked because items are not delivered via {0}") - .format(doc.return_against)) + # validate update stock + if doc.doctype == "Sales Invoice" and doc.update_stock and not ref_doc.update_stock: + frappe.throw(_("'Update Stock' can not be checked because items are not delivered via {0}") + .format(doc.return_against)) def validate_returned_items(doc): from erpnext.stock.doctype.serial_no.serial_no import get_serial_nos From 7cb8c51b2de357ed8d11d12da6f16bd8fc95731c Mon Sep 17 00:00:00 2001 From: Deepesh Garg <42651287+deepeshgarg007@users.noreply.github.com> Date: Mon, 19 Aug 2019 11:49:47 +0530 Subject: [PATCH 05/10] fix: Party dashboard heatmap not capturing sales, purchase and other activities (#18752) --- erpnext/accounts/party.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/erpnext/accounts/party.py b/erpnext/accounts/party.py index 240dc4255b9..ebe41f734fc 100644 --- a/erpnext/accounts/party.py +++ b/erpnext/accounts/party.py @@ -450,7 +450,9 @@ def get_timeline_data(doctype, name): # fetch and append data from Activity Log data += frappe.db.sql("""select {fields} from `tabActivity Log` - where reference_doctype="{doctype}" and reference_name="{name}" + where (reference_doctype="{doctype}" and reference_name="{name}") + or (timeline_doctype in ("{doctype}") and timeline_name="{name}") + or (reference_doctype in ("Quotation", "Opportunity") and timeline_name="{name}") and status!='Success' and creation > {after} {group_by} order by creation desc """.format(doctype=frappe.db.escape(doctype), name=frappe.db.escape(name), fields=fields, From 55b8b4e374705f6f6958ccd6074930cb06091bf4 Mon Sep 17 00:00:00 2001 From: Deepesh Garg <42651287+deepeshgarg007@users.noreply.github.com> Date: Mon, 19 Aug 2019 12:56:49 +0530 Subject: [PATCH 06/10] fix: Travis (#18773) --- erpnext/controllers/sales_and_purchase_return.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/erpnext/controllers/sales_and_purchase_return.py b/erpnext/controllers/sales_and_purchase_return.py index 7d03722b161..28dd4ea8b6f 100644 --- a/erpnext/controllers/sales_and_purchase_return.py +++ b/erpnext/controllers/sales_and_purchase_return.py @@ -24,7 +24,7 @@ def validate_return_against(doc): else: ref_doc = frappe.get_doc(doc.doctype, doc.return_against) - if ref_doc.company == doc.company and ref_doc.customer = doc.customer and ref_doc.docstatus == 1: + if ref_doc.company == doc.company and ref_doc.customer == doc.customer and ref_doc.docstatus == 1: # validate posting date time return_posting_datetime = "%s %s" % (doc.posting_date, doc.get("posting_time") or "00:00:00") ref_posting_datetime = "%s %s" % (ref_doc.posting_date, ref_doc.get("posting_time") or "00:00:00") From 9f7098115b58ac8e2b06885727d3adea02239425 Mon Sep 17 00:00:00 2001 From: deepeshgarg007 Date: Mon, 19 Aug 2019 17:53:47 +0530 Subject: [PATCH 07/10] fix: Failing sales and purchase return test cases --- erpnext/controllers/sales_and_purchase_return.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/erpnext/controllers/sales_and_purchase_return.py b/erpnext/controllers/sales_and_purchase_return.py index 28dd4ea8b6f..611a1fceadd 100644 --- a/erpnext/controllers/sales_and_purchase_return.py +++ b/erpnext/controllers/sales_and_purchase_return.py @@ -24,7 +24,9 @@ def validate_return_against(doc): else: ref_doc = frappe.get_doc(doc.doctype, doc.return_against) - if ref_doc.company == doc.company and ref_doc.customer == doc.customer and ref_doc.docstatus == 1: + party_type = "customer" if doc.doctype in ("Sales Invoice", "Delivery Note") else "supplier" + + if ref_doc.company == doc.company and ref_doc.get(party_type) == doc.get(party_type) and ref_doc.docstatus == 1:: # validate posting date time return_posting_datetime = "%s %s" % (doc.posting_date, doc.get("posting_time") or "00:00:00") ref_posting_datetime = "%s %s" % (ref_doc.posting_date, ref_doc.get("posting_time") or "00:00:00") From f1618af76c3ee18918e0ccbd3b17a8b0fe0b2a68 Mon Sep 17 00:00:00 2001 From: deepeshgarg007 Date: Mon, 19 Aug 2019 18:53:11 +0530 Subject: [PATCH 08/10] fix: Syntax error --- erpnext/controllers/sales_and_purchase_return.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/erpnext/controllers/sales_and_purchase_return.py b/erpnext/controllers/sales_and_purchase_return.py index 611a1fceadd..b713958b1b8 100644 --- a/erpnext/controllers/sales_and_purchase_return.py +++ b/erpnext/controllers/sales_and_purchase_return.py @@ -26,7 +26,7 @@ def validate_return_against(doc): party_type = "customer" if doc.doctype in ("Sales Invoice", "Delivery Note") else "supplier" - if ref_doc.company == doc.company and ref_doc.get(party_type) == doc.get(party_type) and ref_doc.docstatus == 1:: + if ref_doc.company == doc.company and ref_doc.get(party_type) == doc.get(party_type) and ref_doc.docstatus == 1: # validate posting date time return_posting_datetime = "%s %s" % (doc.posting_date, doc.get("posting_time") or "00:00:00") ref_posting_datetime = "%s %s" % (ref_doc.posting_date, ref_doc.get("posting_time") or "00:00:00") From 6155114bfd6609893463979e705328e0a1c7bdee Mon Sep 17 00:00:00 2001 From: rohitwaghchaure Date: Tue, 20 Aug 2019 12:35:38 +0530 Subject: [PATCH 09/10] fix: group by voucher consolidated showing incorrect data for deferred entries (#18778) --- .../report/general_ledger/general_ledger.py | 25 ++++++++++--------- 1 file changed, 13 insertions(+), 12 deletions(-) diff --git a/erpnext/accounts/report/general_ledger/general_ledger.py b/erpnext/accounts/report/general_ledger/general_ledger.py index 2c72ac0eed1..fb0bff5620d 100644 --- a/erpnext/accounts/report/general_ledger/general_ledger.py +++ b/erpnext/accounts/report/general_ledger/general_ledger.py @@ -121,19 +121,11 @@ def get_gl_entries(filters): select_fields = """, debit, credit, debit_in_account_currency, credit_in_account_currency """ - group_by_statement = '' order_by_statement = "order by posting_date, account" if filters.get("group_by") == _("Group by Voucher"): order_by_statement = "order by posting_date, voucher_type, voucher_no" - if filters.get("group_by") == _("Group by Voucher (Consolidated)"): - group_by_statement = "group by voucher_type, voucher_no, account, cost_center" - - select_fields = """, sum(debit) as debit, sum(credit) as credit, - sum(debit_in_account_currency) as debit_in_account_currency, - sum(credit_in_account_currency) as credit_in_account_currency""" - if filters.get("include_default_book_entries"): filters['company_fb'] = frappe.db.get_value("Company", filters.get("company"), 'default_finance_book') @@ -146,11 +138,10 @@ def get_gl_entries(filters): against_voucher_type, against_voucher, account_currency, remarks, against, is_opening {select_fields} from `tabGL Entry` - where company=%(company)s {conditions} {group_by_statement} + where company=%(company)s {conditions} {order_by_statement} """.format( select_fields=select_fields, conditions=get_conditions(filters), - group_by_statement=group_by_statement, order_by_statement=order_by_statement ), filters, as_dict=1) @@ -187,7 +178,8 @@ def get_conditions(filters): if not (filters.get("account") or filters.get("party") or filters.get("group_by") in ["Group by Account", "Group by Party"]): conditions.append("posting_date >=%(from_date)s") - conditions.append("posting_date <=%(to_date)s") + + conditions.append("(posting_date <=%(to_date)s or is_opening = 'Yes')") if filters.get("project"): conditions.append("project in %(project)s") @@ -281,6 +273,7 @@ def initialize_gle_map(gl_entries, filters): def get_accountwise_gle(filters, gl_entries, gle_map): totals = get_totals_dict() entries = [] + consolidated_gle = OrderedDict() group_by = group_by_field(filters.get('group_by')) def update_value_in_dict(data, key, gle): @@ -306,11 +299,19 @@ def get_accountwise_gle(filters, gl_entries, gle_map): if filters.get("group_by") != _('Group by Voucher (Consolidated)'): gle_map[gle.get(group_by)].entries.append(gle) else: - entries.append(gle) + key = (gle.get("voucher_type"), gle.get("voucher_no"), + gle.get("account"), gle.get("cost_center")) + if key not in consolidated_gle: + consolidated_gle.setdefault(key, gle) + else: + update_value_in_dict(consolidated_gle, key, gle) update_value_in_dict(gle_map[gle.get(group_by)].totals, 'closing', gle) update_value_in_dict(totals, 'closing', gle) + for key, value in consolidated_gle.items(): + entries.append(value) + return totals, entries def get_result_as_list(data, filters): From a621466219a9c357b7be767d4bae42bdaf1276eb Mon Sep 17 00:00:00 2001 From: Sahil Khan Date: Tue, 20 Aug 2019 16:18:20 +0550 Subject: [PATCH 10/10] bumped to version 11.1.56 --- erpnext/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/erpnext/__init__.py b/erpnext/__init__.py index beae706ff7d..c961cad11f6 100644 --- a/erpnext/__init__.py +++ b/erpnext/__init__.py @@ -5,7 +5,7 @@ import frappe from erpnext.hooks import regional_overrides from frappe.utils import getdate -__version__ = '11.1.55' +__version__ = '11.1.56' def get_default_company(user=None): '''Get default company for user'''