From 907e9080c4625dbc62d491556615a2732d4cc2c5 Mon Sep 17 00:00:00 2001 From: Faris Ansari Date: Wed, 12 Dec 2018 19:26:52 +0530 Subject: [PATCH 01/25] fix(product-search): Include variants in product search --- erpnext/templates/pages/product_search.py | 1 - 1 file changed, 1 deletion(-) diff --git a/erpnext/templates/pages/product_search.py b/erpnext/templates/pages/product_search.py index d503490eb7..c34001bacf 100644 --- a/erpnext/templates/pages/product_search.py +++ b/erpnext/templates/pages/product_search.py @@ -26,7 +26,6 @@ def get_product_list(search=None, start=0, limit=12): left join tabBin S on I.item_code = S.item_code and I.website_warehouse = S.warehouse where (I.show_in_website = 1) and I.disabled = 0 - and (I.variant_of is null or I.variant_of='') and (I.end_of_life is null or I.end_of_life='0000-00-00' or I.end_of_life > %(today)s)""" # search term condition From 9fde660aaf71f70e9e01e87cdc43dda95b09e15c Mon Sep 17 00:00:00 2001 From: Zlash65 Date: Thu, 13 Dec 2018 13:28:01 +0530 Subject: [PATCH 02/25] make quality inspection in query configurable --- .../doctype/quality_inspection/quality_inspection.py | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/erpnext/stock/doctype/quality_inspection/quality_inspection.py b/erpnext/stock/doctype/quality_inspection/quality_inspection.py index 36f6405ae4..e0b738202c 100644 --- a/erpnext/stock/doctype/quality_inspection/quality_inspection.py +++ b/erpnext/stock/doctype/quality_inspection/quality_inspection.py @@ -61,7 +61,7 @@ def item_query(doctype, txt, searchfield, start, page_len, filters): if filters.get("from"): from frappe.desk.reportview import get_match_cond mcond = get_match_cond(filters["from"]) - cond = "" + cond, qi_condition = "", "and (quality_inspection is null or quality_inspection = '')" if filters.get('from') in ['Purchase Invoice Item', 'Purchase Receipt Item']: cond = """and item_code in (select name from `tabItem` where @@ -72,9 +72,13 @@ def item_query(doctype, txt, searchfield, start, page_len, filters): elif filters.get('from') == 'Stock Entry Detail': cond = """and s_warehouse is null""" + if filters.get('from') in ['Supplier Quotation Item']: + qi_condition = "" + return frappe.db.sql(""" select item_code from `tab{doc}` where parent=%(parent)s and docstatus < 2 and item_code like %(txt)s - and (quality_inspection is null or quality_inspection = '') - {cond} {mcond} order by item_code limit {start}, {page_len}""".format(doc=filters.get('from'), - parent=filters.get('parent'), cond=cond, mcond=mcond, start=start, page_len = page_len), + {qi_condition} {cond} {mcond} + order by item_code limit {start}, {page_len}""".format(doc=filters.get('from'), + parent=filters.get('parent'), cond = cond, mcond = mcond, start = start, + page_len = page_len, qi_condition = qi_condition), {'parent': filters.get('parent'), 'txt': "%%%s%%" % txt}) From 82e01bc9234d70e50adbbb77b284e45eae346648 Mon Sep 17 00:00:00 2001 From: Zlash65 Date: Thu, 13 Dec 2018 18:31:05 +0530 Subject: [PATCH 03/25] fix fetch material request items logic --- .../doctype/production_plan/production_plan.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/erpnext/manufacturing/doctype/production_plan/production_plan.py b/erpnext/manufacturing/doctype/production_plan/production_plan.py index 7d11ae4993..24ce7d41f7 100644 --- a/erpnext/manufacturing/doctype/production_plan/production_plan.py +++ b/erpnext/manufacturing/doctype/production_plan/production_plan.py @@ -514,7 +514,7 @@ def get_items_for_material_requests(doc, company=None): doc = frappe._dict(json.loads(doc)) doc['mr_items'] = [] - po_items = doc['po_items'] if doc.get('po_items') else doc['items'] + po_items = doc.get('po_items') if doc.get('po_items') else doc.get('items') for data in po_items: warehouse = None @@ -533,10 +533,10 @@ def get_items_for_material_requests(doc, company=None): else: planned_qty = data.get('planned_qty') bom_no = data.get('bom_no') - include_subcontracted_items = doc['include_subcontracted_items'] - company = doc['company'] - include_non_stock_items = doc['include_non_stock_items'] - ignore_existing_ordered_qty = doc['ignore_existing_ordered_qty'] + include_subcontracted_items = doc.get('include_subcontracted_items') + company = doc.get('company') + include_non_stock_items = doc.get('include_non_stock_items') + ignore_existing_ordered_qty = doc.get('ignore_existing_ordered_qty') if not planned_qty: frappe.throw(_("For row {0}: Enter Planned Qty").format(data.get('idx'))) From 4994d845658dbc22c2256bd0437f020471b45896 Mon Sep 17 00:00:00 2001 From: Faris Ansari Date: Fri, 14 Dec 2018 14:19:14 +0530 Subject: [PATCH 04/25] fix(pos-profile): Cleanup Form for POS Profile (#16208) - Remove pos_profile_name field and use `name` as Prompt - Reorganize form and label sections - Remove `apply_discount` which was not used --- .../doctype/pos_profile/pos_profile.js | 4 +- .../doctype/pos_profile/pos_profile.json | 731 ++++++++---------- .../doctype/pos_profile/pos_profile.py | 11 +- .../doctype/pos_profile/test_pos_profile.py | 1 - erpnext/demo/setup/setup_data.py | 2 +- .../add_user_to_child_table_in_pos_profile.py | 2 +- erpnext/patches/v9_0/set_pos_profile_name.py | 6 +- 7 files changed, 334 insertions(+), 423 deletions(-) diff --git a/erpnext/accounts/doctype/pos_profile/pos_profile.js b/erpnext/accounts/doctype/pos_profile/pos_profile.js index 5162c29604..13d53d1f6a 100755 --- a/erpnext/accounts/doctype/pos_profile/pos_profile.js +++ b/erpnext/accounts/doctype/pos_profile/pos_profile.js @@ -37,8 +37,8 @@ frappe.ui.form.on('POS Profile', { return { filters: { doc_type: "Sales Invoice", print_format_type: "Js"} }; }); - frappe.db.get_value('POS Settings', {name: 'POS Settings'}, 'use_pos_in_offline_mode', (r) => { - is_offline = r && cint(r.use_pos_in_offline_mode) + frappe.db.get_value('POS Settings', 'POS Settings', 'use_pos_in_offline_mode', (r) => { + const is_offline = r && cint(r.use_pos_in_offline_mode) frm.toggle_display('offline_pos_section', is_offline); frm.toggle_display('print_format_for_online', !is_offline); }); diff --git a/erpnext/accounts/doctype/pos_profile/pos_profile.json b/erpnext/accounts/doctype/pos_profile/pos_profile.json index a089b4c91b..077c396c71 100644 --- a/erpnext/accounts/doctype/pos_profile/pos_profile.json +++ b/erpnext/accounts/doctype/pos_profile/pos_profile.json @@ -4,7 +4,7 @@ "allow_guest_to_view": 0, "allow_import": 0, "allow_rename": 1, - "autoname": "field:pos_profile_name", + "autoname": "Prompt", "beta": 0, "creation": "2013-05-24 12:15:51", "custom": 0, @@ -52,6 +52,7 @@ "bold": 0, "collapsible": 0, "columns": 0, + "depends_on": "", "fieldname": "section_break_2", "fieldtype": "Section Break", "hidden": 0, @@ -76,38 +77,6 @@ "translatable": 0, "unique": 0 }, - { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fieldname": "pos_profile_name", - "fieldtype": "Data", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "label": "POS Profile Name", - "length": 0, - "no_copy": 0, - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 1, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 1 - }, { "allow_bulk_edit": 0, "allow_in_quick_entry": 0, @@ -142,6 +111,240 @@ "translatable": 0, "unique": 0 }, + { + "allow_bulk_edit": 0, + "allow_in_quick_entry": 0, + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "columns": 0, + "fieldname": "customer", + "fieldtype": "Link", + "hidden": 0, + "ignore_user_permissions": 0, + "ignore_xss_filter": 0, + "in_filter": 0, + "in_global_search": 0, + "in_list_view": 0, + "in_standard_filter": 0, + "label": "Customer", + "length": 0, + "no_copy": 0, + "oldfieldname": "customer_account", + "oldfieldtype": "Link", + "options": "Customer", + "permlevel": 0, + "print_hide": 0, + "print_hide_if_no_value": 0, + "read_only": 0, + "remember_last_selected_value": 0, + "report_hide": 0, + "reqd": 0, + "search_index": 0, + "set_only_once": 0, + "translatable": 0, + "unique": 0 + }, + { + "allow_bulk_edit": 0, + "allow_in_quick_entry": 0, + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "columns": 0, + "fieldname": "company", + "fieldtype": "Link", + "hidden": 0, + "ignore_user_permissions": 0, + "ignore_xss_filter": 0, + "in_filter": 0, + "in_global_search": 0, + "in_list_view": 1, + "in_standard_filter": 0, + "label": "Company", + "length": 0, + "no_copy": 0, + "oldfieldname": "company", + "oldfieldtype": "Link", + "options": "Company", + "permlevel": 0, + "print_hide": 0, + "print_hide_if_no_value": 0, + "read_only": 0, + "remember_last_selected_value": 1, + "report_hide": 0, + "reqd": 1, + "search_index": 0, + "set_only_once": 0, + "translatable": 0, + "unique": 0 + }, + { + "allow_bulk_edit": 0, + "allow_in_quick_entry": 0, + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "columns": 0, + "fetch_from": "company.country", + "fieldname": "country", + "fieldtype": "Read Only", + "hidden": 0, + "ignore_user_permissions": 0, + "ignore_xss_filter": 0, + "in_filter": 0, + "in_global_search": 0, + "in_list_view": 0, + "in_standard_filter": 0, + "label": "Country", + "length": 0, + "no_copy": 0, + "options": "", + "permlevel": 0, + "precision": "", + "print_hide": 0, + "print_hide_if_no_value": 0, + "read_only": 0, + "remember_last_selected_value": 0, + "report_hide": 0, + "reqd": 0, + "search_index": 0, + "set_only_once": 0, + "translatable": 0, + "unique": 0 + }, + { + "allow_bulk_edit": 0, + "allow_in_quick_entry": 0, + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "columns": 0, + "depends_on": "update_stock", + "fieldname": "warehouse", + "fieldtype": "Link", + "hidden": 0, + "ignore_user_permissions": 0, + "ignore_xss_filter": 0, + "in_filter": 0, + "in_global_search": 0, + "in_list_view": 0, + "in_standard_filter": 0, + "label": "Warehouse", + "length": 0, + "no_copy": 0, + "oldfieldname": "warehouse", + "oldfieldtype": "Link", + "options": "Warehouse", + "permlevel": 0, + "print_hide": 0, + "print_hide_if_no_value": 0, + "read_only": 0, + "remember_last_selected_value": 0, + "report_hide": 0, + "reqd": 0, + "search_index": 0, + "set_only_once": 0, + "translatable": 0, + "unique": 0 + }, + { + "allow_bulk_edit": 0, + "allow_in_quick_entry": 0, + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "columns": 0, + "fieldname": "campaign", + "fieldtype": "Link", + "hidden": 0, + "ignore_user_permissions": 0, + "ignore_xss_filter": 0, + "in_filter": 0, + "in_global_search": 0, + "in_list_view": 0, + "in_standard_filter": 0, + "label": "Campaign", + "length": 0, + "no_copy": 0, + "options": "Campaign", + "permlevel": 0, + "precision": "", + "print_hide": 0, + "print_hide_if_no_value": 0, + "read_only": 0, + "remember_last_selected_value": 0, + "report_hide": 0, + "reqd": 0, + "search_index": 0, + "set_only_once": 0, + "translatable": 0, + "unique": 0 + }, + { + "allow_bulk_edit": 0, + "allow_in_quick_entry": 0, + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "columns": 0, + "fieldname": "company_address", + "fieldtype": "Link", + "hidden": 0, + "ignore_user_permissions": 0, + "ignore_xss_filter": 0, + "in_filter": 0, + "in_global_search": 0, + "in_list_view": 0, + "in_standard_filter": 0, + "label": "Company Address", + "length": 0, + "no_copy": 0, + "options": "Address", + "permlevel": 0, + "precision": "", + "print_hide": 0, + "print_hide_if_no_value": 0, + "read_only": 0, + "remember_last_selected_value": 0, + "report_hide": 0, + "reqd": 0, + "search_index": 0, + "set_only_once": 0, + "translatable": 0, + "unique": 0 + }, + { + "allow_bulk_edit": 0, + "allow_in_quick_entry": 0, + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "columns": 0, + "fieldname": "column_break_9", + "fieldtype": "Column Break", + "hidden": 0, + "ignore_user_permissions": 0, + "ignore_xss_filter": 0, + "in_filter": 0, + "in_global_search": 0, + "in_list_view": 0, + "in_standard_filter": 0, + "length": 0, + "no_copy": 0, + "permlevel": 0, + "precision": "", + "print_hide": 0, + "print_hide_if_no_value": 0, + "read_only": 0, + "remember_last_selected_value": 0, + "report_hide": 0, + "reqd": 0, + "search_index": 0, + "set_only_once": 0, + "translatable": 0, + "unique": 0 + }, { "allow_bulk_edit": 0, "allow_in_quick_entry": 0, @@ -374,207 +577,7 @@ "bold": 0, "collapsible": 0, "columns": 0, - "fieldname": "column_break_4", - "fieldtype": "Column Break", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "length": 0, - "no_copy": 0, - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 - }, - { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fieldname": "customer", - "fieldtype": "Link", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "label": "Customer", - "length": 0, - "no_copy": 0, - "oldfieldname": "customer_account", - "oldfieldtype": "Link", - "options": "Customer", - "permlevel": 0, - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 - }, - { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fieldname": "company", - "fieldtype": "Link", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 1, - "in_standard_filter": 0, - "label": "Company", - "length": 0, - "no_copy": 0, - "oldfieldname": "company", - "oldfieldtype": "Link", - "options": "Company", - "permlevel": 0, - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 1, - "report_hide": 0, - "reqd": 1, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 - }, - { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fetch_from": "company.country", - "fieldname": "country", - "fieldtype": "Read Only", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "label": "Country", - "length": 0, - "no_copy": 0, - "options": "", - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 - }, - { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "depends_on": "update_stock", - "fieldname": "warehouse", - "fieldtype": "Link", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "label": "Warehouse", - "length": 0, - "no_copy": 0, - "oldfieldname": "warehouse", - "oldfieldtype": "Link", - "options": "Warehouse", - "permlevel": 0, - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 - }, - { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fieldname": "campaign", - "fieldtype": "Link", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "label": "Campaign", - "length": 0, - "no_copy": 0, - "options": "Campaign", - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 - }, - { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, + "depends_on": "", "fieldname": "section_break_15", "fieldtype": "Section Break", "hidden": 0, @@ -649,6 +652,7 @@ "in_global_search": 0, "in_list_view": 0, "in_standard_filter": 0, + "label": "Mode of Payment", "length": 0, "no_copy": 0, "permlevel": 0, @@ -714,6 +718,7 @@ "in_global_search": 0, "in_list_view": 0, "in_standard_filter": 0, + "label": "", "length": 0, "no_copy": 0, "permlevel": 0, @@ -736,6 +741,7 @@ "bold": 0, "collapsible": 0, "columns": 0, + "description": "Only show Items from these Item Groups", "fieldname": "item_groups", "fieldtype": "Table", "hidden": 0, @@ -800,6 +806,7 @@ "bold": 0, "collapsible": 0, "columns": 0, + "description": "Only show Customer of these Customer Groups", "fieldname": "customer_groups", "fieldtype": "Table", "hidden": 0, @@ -843,6 +850,7 @@ "in_global_search": 0, "in_list_view": 0, "in_standard_filter": 0, + "label": "Print Settings", "length": 0, "no_copy": 0, "permlevel": 0, @@ -925,40 +933,6 @@ "translatable": 0, "unique": 0 }, - { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 1, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fieldname": "select_print_heading", - "fieldtype": "Link", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "label": "Print Heading", - "length": 0, - "no_copy": 0, - "oldfieldname": "select_print_heading", - "oldfieldtype": "Select", - "options": "Print Heading", - "permlevel": 0, - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 - }, { "allow_bulk_edit": 0, "allow_in_quick_entry": 0, @@ -990,40 +964,6 @@ "translatable": 0, "unique": 0 }, - { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fieldname": "selling_price_list", - "fieldtype": "Link", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "label": "Price List", - "length": 0, - "no_copy": 0, - "oldfieldname": "price_list_name", - "oldfieldtype": "Select", - "options": "Price List", - "permlevel": 0, - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 - }, { "allow_bulk_edit": 0, "allow_in_quick_entry": 0, @@ -1061,110 +1001,11 @@ { "allow_bulk_edit": 0, "allow_in_quick_entry": 0, - "allow_on_submit": 0, + "allow_on_submit": 1, "bold": 0, "collapsible": 0, "columns": 0, - "fieldname": "apply_discount", - "fieldtype": "Check", - "hidden": 1, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "label": "Apply Discount", - "length": 0, - "no_copy": 0, - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 1, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 - }, - { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "default": "Grand Total", - "depends_on": "", - "fieldname": "apply_discount_on", - "fieldtype": "Select", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "label": "Apply Discount On", - "length": 0, - "no_copy": 0, - "options": "Grand Total\nNet Total", - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 - }, - { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fieldname": "company_address_section", - "fieldtype": "Section Break", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "label": "Company Address", - "length": 0, - "no_copy": 0, - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 - }, - { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fieldname": "company_address", + "fieldname": "select_print_heading", "fieldtype": "Link", "hidden": 0, "ignore_user_permissions": 0, @@ -1173,12 +1014,13 @@ "in_global_search": 0, "in_list_view": 0, "in_standard_filter": 0, - "label": "Company Address Name", + "label": "Print Heading", "length": 0, "no_copy": 0, - "options": "Address", + "oldfieldname": "select_print_heading", + "oldfieldtype": "Select", + "options": "Print Heading", "permlevel": 0, - "precision": "", "print_hide": 0, "print_hide_if_no_value": 0, "read_only": 0, @@ -1207,7 +1049,7 @@ "in_global_search": 0, "in_list_view": 0, "in_standard_filter": 0, - "label": "Offline POS Section", + "label": "Offline POS Settings", "length": 0, "no_copy": 0, "permlevel": 0, @@ -1389,6 +1231,40 @@ "translatable": 0, "unique": 0 }, + { + "allow_bulk_edit": 0, + "allow_in_quick_entry": 0, + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "columns": 0, + "fieldname": "selling_price_list", + "fieldtype": "Link", + "hidden": 0, + "ignore_user_permissions": 0, + "ignore_xss_filter": 0, + "in_filter": 0, + "in_global_search": 0, + "in_list_view": 0, + "in_standard_filter": 0, + "label": "Price List", + "length": 0, + "no_copy": 0, + "oldfieldname": "price_list_name", + "oldfieldtype": "Select", + "options": "Price List", + "permlevel": 0, + "print_hide": 0, + "print_hide_if_no_value": 0, + "read_only": 0, + "remember_last_selected_value": 0, + "report_hide": 0, + "reqd": 0, + "search_index": 0, + "set_only_once": 0, + "translatable": 0, + "unique": 0 + }, { "allow_bulk_edit": 0, "allow_in_quick_entry": 0, @@ -1688,6 +1564,41 @@ "set_only_once": 0, "translatable": 0, "unique": 0 + }, + { + "allow_bulk_edit": 0, + "allow_in_quick_entry": 0, + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "columns": 0, + "default": "Grand Total", + "depends_on": "", + "fieldname": "apply_discount_on", + "fieldtype": "Select", + "hidden": 0, + "ignore_user_permissions": 0, + "ignore_xss_filter": 0, + "in_filter": 0, + "in_global_search": 0, + "in_list_view": 0, + "in_standard_filter": 0, + "label": "Apply Discount On", + "length": 0, + "no_copy": 0, + "options": "Grand Total\nNet Total", + "permlevel": 0, + "precision": "", + "print_hide": 0, + "print_hide_if_no_value": 0, + "read_only": 0, + "remember_last_selected_value": 0, + "report_hide": 0, + "reqd": 0, + "search_index": 0, + "set_only_once": 0, + "translatable": 0, + "unique": 0 } ], "has_web_view": 0, @@ -1701,7 +1612,7 @@ "issingle": 0, "istable": 0, "max_attachments": 0, - "modified": "2018-12-03 14:16:08.589778", + "modified": "2018-12-13 13:36:22.045519", "modified_by": "Administrator", "module": "Accounts", "name": "POS Profile", @@ -1749,11 +1660,11 @@ "quick_entry": 0, "read_only": 0, "read_only_onload": 0, - "search_fields": "pos_profile_name", + "search_fields": "", "show_name_in_global_search": 0, "sort_field": "modified", "sort_order": "DESC", - "title_field": "pos_profile_name", + "title_field": "", "track_changes": 0, "track_seen": 0, "track_views": 0 diff --git a/erpnext/accounts/doctype/pos_profile/pos_profile.py b/erpnext/accounts/doctype/pos_profile/pos_profile.py index bf2e20c248..723ef4366a 100644 --- a/erpnext/accounts/doctype/pos_profile/pos_profile.py +++ b/erpnext/accounts/doctype/pos_profile/pos_profile.py @@ -127,25 +127,26 @@ def pos_profile_query(doctype, txt, searchfield, start, page_len, filters): 'txt': '%%%s%%' % txt } - pos_profile = frappe.db.sql("""select pf.name, pf.pos_profile_name + pos_profile = frappe.db.sql("""select pf.name from `tabPOS Profile` pf, `tabPOS Profile User` pfu where pfu.parent = pf.name and pfu.user = %(user)s and pf.company = %(company)s - and (pf.name like %(txt)s or pf.pos_profile_name like %(txt)s) + and (pf.name like %(txt)s) and pf.disabled = 0 limit %(start)s, %(page_len)s""", args) if not pos_profile: del args['user'] - pos_profile = frappe.db.sql("""select pf.name, pf.pos_profile_name + pos_profile = frappe.db.sql("""select pf.name from `tabPOS Profile` pf left join `tabPOS Profile User` pfu on pf.name = pfu.parent where - ifnull(pfu.user, '') = '' and pf.company = %(company)s and - (pf.name like %(txt)s or pf.pos_profile_name like %(txt)s) + ifnull(pfu.user, '') = '' + and pf.company = %(company)s + and pf.name like %(txt)s and pf.disabled = 0""", args) return pos_profile diff --git a/erpnext/accounts/doctype/pos_profile/test_pos_profile.py b/erpnext/accounts/doctype/pos_profile/test_pos_profile.py index c1b033cdda..58f12162d1 100644 --- a/erpnext/accounts/doctype/pos_profile/test_pos_profile.py +++ b/erpnext/accounts/doctype/pos_profile/test_pos_profile.py @@ -40,7 +40,6 @@ def make_pos_profile(): "expense_account": "_Test Account Cost for Goods Sold - _TC", "income_account": "Sales - _TC", "name": "_Test POS Profile", - "pos_profile_name": "_Test POS Profile", "naming_series": "_T-POS Profile-", "selling_price_list": "_Test Price List", "territory": "_Test Territory", diff --git a/erpnext/demo/setup/setup_data.py b/erpnext/demo/setup/setup_data.py index 0fd7bb7ac8..48dcdbe863 100644 --- a/erpnext/demo/setup/setup_data.py +++ b/erpnext/demo/setup/setup_data.py @@ -376,7 +376,7 @@ def setup_pos_profile(): company_abbr = frappe.get_cached_value('Company', erpnext.get_default_company(), "abbr") pos = frappe.new_doc('POS Profile') pos.user = frappe.db.get_global('demo_accounts_user') - pos.pos_profile_name = "Demo POS Profile" + pos.name = "Demo POS Profile" pos.naming_series = 'SINV-' pos.update_stock = 0 pos.write_off_account = 'Cost of Goods Sold - '+ company_abbr diff --git a/erpnext/patches/v9_0/add_user_to_child_table_in_pos_profile.py b/erpnext/patches/v9_0/add_user_to_child_table_in_pos_profile.py index 942f089bce..8a8c8064dd 100644 --- a/erpnext/patches/v9_0/add_user_to_child_table_in_pos_profile.py +++ b/erpnext/patches/v9_0/add_user_to_child_table_in_pos_profile.py @@ -32,7 +32,7 @@ def execute(): 'user': user, 'default': 1 }) - _doc.pos_profile_name = user + ' - ' + _doc.company + _doc.flags.ignore_validate = True _doc.flags.ignore_mandatory = True _doc.save() \ No newline at end of file diff --git a/erpnext/patches/v9_0/set_pos_profile_name.py b/erpnext/patches/v9_0/set_pos_profile_name.py index 1958e2c777..a3a9735215 100644 --- a/erpnext/patches/v9_0/set_pos_profile_name.py +++ b/erpnext/patches/v9_0/set_pos_profile_name.py @@ -11,14 +11,14 @@ def execute(): for pos in frappe.get_all(doctype, filters={'disabled': 0}): doc = frappe.get_doc(doctype, pos.name) - if not doc.user or doc.pos_profile_name: continue + if not doc.user: continue try: - doc.pos_profile_name = doc.user + ' - ' + doc.company + pos_profile_name = doc.user + ' - ' + doc.company doc.flags.ignore_validate = True doc.flags.ignore_mandatory = True doc.save() - frappe.rename_doc(doctype, doc.name, doc.pos_profile_name, force=True) + frappe.rename_doc(doctype, doc.name, pos_profile_name, force=True) except frappe.LinkValidationError: frappe.db.set_value("POS Profile", doc.name, 'disabled', 1) From 22a1e281a9f11769b3449bb4886c5f72941cd153 Mon Sep 17 00:00:00 2001 From: Nabin Hait Date: Fri, 14 Dec 2018 09:52:45 +0100 Subject: [PATCH 05/25] fix(variant): Show attribute values on single variant creation (#16204) --- erpnext/stock/doctype/item/item.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/erpnext/stock/doctype/item/item.js b/erpnext/stock/doctype/item/item.js index a26da7fbe3..388b64325d 100644 --- a/erpnext/stock/doctype/item/item.js +++ b/erpnext/stock/doctype/item/item.js @@ -651,7 +651,7 @@ $.extend(erpnext.item, { frappe.call({ method:"erpnext.stock.doctype.item.item.get_item_attribute", args:{ - parent: "Item Attribute", + parent: i, attribute_value: term }, callback: function(r) { From 1ee19e4167f72dd73ed1bc35dd58b60b4c51f012 Mon Sep 17 00:00:00 2001 From: deepeshgarg007 Date: Sat, 15 Dec 2018 15:36:09 +0530 Subject: [PATCH 06/25] Analytics report graph fix --- .../purchase_analytics/purchase_analytics.js | 17 ++++++++++++++--- .../report/sales_analytics/sales_analytics.js | 19 +++++++++++++++---- .../report/sales_analytics/sales_analytics.py | 6 +++++- 3 files changed, 34 insertions(+), 8 deletions(-) diff --git a/erpnext/buying/report/purchase_analytics/purchase_analytics.js b/erpnext/buying/report/purchase_analytics/purchase_analytics.js index b55046e065..e17973c337 100644 --- a/erpnext/buying/report/purchase_analytics/purchase_analytics.js +++ b/erpnext/buying/report/purchase_analytics/purchase_analytics.js @@ -77,9 +77,20 @@ frappe.query_reports["Purchase Analytics"] = { events: { onCheckRow: function(data) { row_name = data[2].content; - row_values = data.slice(5).map(function (column) { - return column.content; - }) + length = data.length; + + var tree_type = frappe.query_report.filters[0].value; + + if(tree_type == "Supplier" || tree_type == "Item") { + row_values = data.slice(4,length-1).map(function (column) { + return column.content; + }) + } + else { + row_values = data.slice(3,length-1).map(function (column) { + return column.content; + }) + } entry = { 'name':row_name, diff --git a/erpnext/selling/report/sales_analytics/sales_analytics.js b/erpnext/selling/report/sales_analytics/sales_analytics.js index 0df425d1cd..fbe045bf35 100644 --- a/erpnext/selling/report/sales_analytics/sales_analytics.js +++ b/erpnext/selling/report/sales_analytics/sales_analytics.js @@ -76,10 +76,21 @@ frappe.query_reports["Sales Analytics"] = { events: { onCheckRow: function(data) { row_name = data[2].content; - length = data.length - row_values = data.slice(4,length-1).map(function (column) { - return column.content; - }) + length = data.length; + + var tree_type = frappe.query_report.filters[0].value; + + if(tree_type == "Customer" || tree_type == "Item") { + row_values = data.slice(4,length-1).map(function (column) { + return column.content; + }) + } + else { + row_values = data.slice(3,length-1).map(function (column) { + return column.content; + }) + } + entry = { 'name':row_name, 'values':row_values diff --git a/erpnext/selling/report/sales_analytics/sales_analytics.py b/erpnext/selling/report/sales_analytics/sales_analytics.py index 9cc6c404a6..c078a08249 100644 --- a/erpnext/selling/report/sales_analytics/sales_analytics.py +++ b/erpnext/selling/report/sales_analytics/sales_analytics.py @@ -276,7 +276,11 @@ class Analytics(object): def get_chart_data(self): length = len(self.columns) - labels = [d.get("label") for d in self.columns[2:length-1]] + + if self.filters.tree_type in ["Customer", "Supplier", "Item"]: + labels = [d.get("label") for d in self.columns[2:length-1]] + else: + labels = [d.get("label") for d in self.columns[1:length-1]] self.chart = { "data": { 'labels': labels, From c8337c6d83953b15cc7ff63df1c9ae581bd8b5fa Mon Sep 17 00:00:00 2001 From: Zlash65 Date: Sat, 15 Dec 2018 21:15:45 +0530 Subject: [PATCH 07/25] fix check for leave on holiday for half day --- erpnext/hr/doctype/leave_application/leave_application.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/erpnext/hr/doctype/leave_application/leave_application.py b/erpnext/hr/doctype/leave_application/leave_application.py index aca277effd..6b7c0f7e79 100755 --- a/erpnext/hr/doctype/leave_application/leave_application.py +++ b/erpnext/hr/doctype/leave_application/leave_application.py @@ -187,7 +187,7 @@ class LeaveApplication(Document): self.total_leave_days = get_number_of_leave_days(self.employee, self.leave_type, self.from_date, self.to_date, self.half_day, self.half_day_date) - if self.total_leave_days == 0: + if self.total_leave_days <= 0: frappe.throw(_("The day(s) on which you are applying for leave are holidays. You need not apply for leave.")) if not is_lwp(self.leave_type): From 4ac9ea0e85794b1cdee0bf40662835092a09ce4a Mon Sep 17 00:00:00 2001 From: Rohit Waghchaure Date: Mon, 17 Dec 2018 11:18:46 +0530 Subject: [PATCH 08/25] [Fix] Get items from material request not working for PO --- erpnext/buying/doctype/purchase_order/purchase_order.js | 1 - 1 file changed, 1 deletion(-) diff --git a/erpnext/buying/doctype/purchase_order/purchase_order.js b/erpnext/buying/doctype/purchase_order/purchase_order.js index a505e4976a..019d0de470 100644 --- a/erpnext/buying/doctype/purchase_order/purchase_order.js +++ b/erpnext/buying/doctype/purchase_order/purchase_order.js @@ -315,7 +315,6 @@ erpnext.buying.PurchaseOrderController = erpnext.buying.BuyingController.extend( method: "erpnext.stock.doctype.material_request.material_request.make_purchase_order", source_doctype: "Material Request", target: me.frm, - args: args, setters: { company: me.frm.doc.company }, From 0543f03b58d980e06dc377ab7a6352806a680cdc Mon Sep 17 00:00:00 2001 From: "shreyashah115@gmail.com" Date: Mon, 17 Dec 2018 15:02:30 +0530 Subject: [PATCH 09/25] fix: Remove date_of_joining from field list --- .../hr/doctype/employee_separation/employee_separation_list.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/erpnext/hr/doctype/employee_separation/employee_separation_list.js b/erpnext/hr/doctype/employee_separation/employee_separation_list.js index 11487cc6f0..76c58f5632 100644 --- a/erpnext/hr/doctype/employee_separation/employee_separation_list.js +++ b/erpnext/hr/doctype/employee_separation/employee_separation_list.js @@ -1,5 +1,5 @@ frappe.listview_settings['Employee Separation'] = { - add_fields: ["boarding_status", "employee_name", "date_of_joining", "department"], + add_fields: ["boarding_status", "employee_name", "department"], filters:[["boarding_status","=", "Pending"]], get_indicator: function(doc) { return [__(doc.boarding_status), frappe.utils.guess_colour(doc.boarding_status), "status,=," + doc.boarding_status]; From a5dc08ee8e1cbd406396e8d4e7f11c6a4ffbfc84 Mon Sep 17 00:00:00 2001 From: "shreyashah115@gmail.com" Date: Mon, 17 Dec 2018 15:29:47 +0530 Subject: [PATCH 10/25] fix: remove paid_amount and modify query --- .../student_fee_collection/student_fee_collection.json | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/erpnext/education/report/student_fee_collection/student_fee_collection.json b/erpnext/education/report/student_fee_collection/student_fee_collection.json index 07fc27c7a0..eb945cfffb 100644 --- a/erpnext/education/report/student_fee_collection/student_fee_collection.json +++ b/erpnext/education/report/student_fee_collection/student_fee_collection.json @@ -1,18 +1,18 @@ { "add_total_row": 0, - "apply_user_permissions": 1, "creation": "2016-06-22 02:58:41.024538", "disabled": 0, "docstatus": 0, "doctype": "Report", "idx": 3, "is_standard": "Yes", - "modified": "2017-11-10 19:41:37.320224", + "modified": "2018-12-17 16:46:46.176620", "modified_by": "Administrator", "module": "Education", "name": "Student Fee Collection", "owner": "Administrator", - "query": "SELECT\n student as \"Student:Link/Student:200\",\n student_name as \"Student Name::200\",\n sum(paid_amount) as \"Paid Amount:Currency:150\",\n sum(outstanding_amount) as \"Outstanding Amount:Currency:150\",\n sum(grand_total) as \"Grand Total:Currency:150\"\nFROM\n `tabFees` \nGROUP BY\n student", + "prepared_report": 0, + "query": "SELECT\n student as \"Student:Link/Student:200\",\n student_name as \"Student Name::200\",\n sum(grand_total) - sum(outstanding_amount) as \"Paid Amount:Currency:150\",\n sum(outstanding_amount) as \"Outstanding Amount:Currency:150\",\n sum(grand_total) as \"Grand Total:Currency:150\"\nFROM\n `tabFees` \nGROUP BY\n student", "ref_doctype": "Fees", "report_name": "Student Fee Collection", "report_type": "Query Report", From 159897d88da08c7e699e0bdf0b2fbe892f9c1afe Mon Sep 17 00:00:00 2001 From: Rohan Date: Tue, 18 Dec 2018 14:52:23 +0530 Subject: [PATCH 11/25] fix(customer): Fix Total Unpaid amount in Customer dashboard (#16234) --- erpnext/public/js/utils.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) mode change 100644 => 100755 erpnext/public/js/utils.js diff --git a/erpnext/public/js/utils.js b/erpnext/public/js/utils.js old mode 100644 new mode 100755 index dc989e2fa9..0784b02798 --- a/erpnext/public/js/utils.js +++ b/erpnext/public/js/utils.js @@ -126,7 +126,7 @@ $.extend(erpnext.utils, { '
Annual Billing: ' +format_currency(company_wise_info[0].billing_this_year, company_wise_info[0].currency)+'
' + '
Total Unpaid: ' - +format_currency(company_wise_info[0].billing_this_year, company_wise_info[0].currency)+'
' + +format_currency(company_wise_info[0].total_unpaid, company_wise_info[0].currency)+'' ); } } From a8d9bfdcfda80623a62b164ebdac936c66f349d9 Mon Sep 17 00:00:00 2001 From: Suraj Shetty Date: Tue, 18 Dec 2018 14:53:17 +0530 Subject: [PATCH 12/25] Fix: currency symbol issue in delivery note list (#16233) --- erpnext/stock/doctype/delivery_note/delivery_note_list.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/erpnext/stock/doctype/delivery_note/delivery_note_list.js b/erpnext/stock/doctype/delivery_note/delivery_note_list.js index 9631264f20..6a50c5a9f7 100644 --- a/erpnext/stock/doctype/delivery_note/delivery_note_list.js +++ b/erpnext/stock/doctype/delivery_note/delivery_note_list.js @@ -1,5 +1,5 @@ frappe.listview_settings['Delivery Note'] = { - add_fields: ["grand_total", "is_return", "per_billed", "status"], + add_fields: ["grand_total", "is_return", "per_billed", "status", "currency"], get_indicator: function (doc) { if (cint(doc.is_return) == 1) { return [__("Return"), "darkgrey", "is_return,=,Yes"]; From a8ab9b5c3d9a289cb4d96abdb93ded1e8e11f509 Mon Sep 17 00:00:00 2001 From: deepeshgarg007 Date: Mon, 12 Nov 2018 11:17:39 +0530 Subject: [PATCH 13/25] Accounts Receivable report based on payment terms --- .../accounts_receivable.js | 5 + .../accounts_receivable.py | 169 +++++++++++------- 2 files changed, 113 insertions(+), 61 deletions(-) diff --git a/erpnext/accounts/report/accounts_receivable/accounts_receivable.js b/erpnext/accounts/report/accounts_receivable/accounts_receivable.js index b1bdce95c8..bbfee1112f 100644 --- a/erpnext/accounts/report/accounts_receivable/accounts_receivable.js +++ b/erpnext/accounts/report/accounts_receivable/accounts_receivable.js @@ -107,6 +107,11 @@ frappe.query_reports["Accounts Receivable"] = { "label": __("Show PDC in Print"), "fieldtype": "Check", }, + { + "fieldname":"based_on_payment_terms", + "label": __("Based On Payment Terms"), + "fieldtype": "Check", + }, { "fieldname":"tax_id", "label": __("Tax Id"), diff --git a/erpnext/accounts/report/accounts_receivable/accounts_receivable.py b/erpnext/accounts/report/accounts_receivable/accounts_receivable.py index 8e05a087af..4455be4ad2 100755 --- a/erpnext/accounts/report/accounts_receivable/accounts_receivable.py +++ b/erpnext/accounts/report/accounts_receivable/accounts_receivable.py @@ -152,106 +152,139 @@ class ReceivablePayableReport(object): def get_data(self, party_naming_by, args): from erpnext.accounts.utils import get_currency_precision currency_precision = get_currency_precision() or 2 - dr_or_cr = "debit" if args.get("party_type") == "Customer" else "credit" + self.dr_or_cr = "debit" if args.get("party_type") == "Customer" else "credit" future_vouchers = self.get_entries_after(self.filters.report_date, args.get("party_type")) if not self.filters.get("company"): self.filters["company"] = frappe.db.get_single_value('Global Defaults', 'default_company') - company_currency = frappe.get_cached_value('Company', self.filters.get("company"), "default_currency") + self.company_currency = frappe.get_cached_value('Company', self.filters.get("company"), "default_currency") return_entries = self.get_return_entries(args.get("party_type")) data = [] - pdc_details = get_pdc_details(args.get("party_type"), self.filters.report_date) + self.pdc_details = get_pdc_details(args.get("party_type"), self.filters.report_date) gl_entries_data = self.get_entries_till(self.filters.report_date, args.get("party_type")) if gl_entries_data: voucher_nos = [d.voucher_no for d in gl_entries_data] or [] dn_details = get_dn_details(args.get("party_type"), voucher_nos) - voucher_details = get_voucher_details(args.get("party_type"), voucher_nos, dn_details) + self.voucher_details = get_voucher_details(args.get("party_type"), voucher_nos, dn_details) + + if self.filters.based_on_payment_terms: + self.payment_term_map = self.get_payment_term_detail(voucher_nos) for gle in gl_entries_data: - if self.is_receivable_or_payable(gle, dr_or_cr, future_vouchers): - outstanding_amount, credit_note_amount = self.get_outstanding_amount(gle, - self.filters.report_date, dr_or_cr, return_entries, currency_precision) - if abs(outstanding_amount) > 0.1/10**currency_precision: - row = [gle.posting_date, gle.party] + if self.is_receivable_or_payable(gle, self.dr_or_cr, future_vouchers): + if self.filters.based_on_payment_terms and self.payment_term_map.get(gle.voucher_no): + outstanding_amount, credit_note_amount, payment_amount = self.get_outstanding_amount( + gle,self.filters.report_date, self.dr_or_cr, return_entries, currency_precision) + if abs(outstanding_amount) > 0.1/10**currency_precision: + for d in self.payment_term_map.get(gle.voucher_no): + if payment_amount >= d[1]: + payment_amount -= d[1] + else: + outstanding_amount = d[1] - payment_amount + row = self.prepare_row(party_naming_by, args, gle, outstanding_amount, + credit_note_amount, d[0], payment_amount ) + payment_amount = 0 + data.append(row) + else: + outstanding_amount, credit_note_amount, payment_amount = self.get_outstanding_amount( + gle,self.filters.report_date, self.dr_or_cr, return_entries, currency_precision) + if abs(outstanding_amount) > 0.1/10**currency_precision: + row = self.prepare_row(party_naming_by, args, gle, outstanding_amount, credit_note_amount) + data.append(row) + return data - # customer / supplier name - if party_naming_by == "Naming Series": - row += [self.get_party_name(gle.party_type, gle.party)] + def prepare_row(self, party_naming_by, args, gle, outstanding_amount, credit_note_amount, + due_date=None, paid_amt=None): + row = [gle.posting_date, gle.party] - # get due date - due_date = voucher_details.get(gle.voucher_no, {}).get("due_date", "") - bill_date = voucher_details.get(gle.voucher_no, {}).get("bill_date", "") + # customer / supplier name + if party_naming_by == "Naming Series": + row += [self.get_party_name(gle.party_type, gle.party)] - row += [gle.voucher_type, gle.voucher_no, due_date] + # get due date + if not due_date: + due_date = self.voucher_details.get(gle.voucher_no, {}).get("due_date", "") + bill_date = self.voucher_details.get(gle.voucher_no, {}).get("bill_date", "") - # get supplier bill details - if args.get("party_type") == "Supplier": - row += [ - voucher_details.get(gle.voucher_no, {}).get("bill_no", ""), - voucher_details.get(gle.voucher_no, {}).get("bill_date", "") - ] + row += [gle.voucher_type, gle.voucher_no, due_date] - # invoiced and paid amounts - invoiced_amount = gle.get(dr_or_cr) if (gle.get(dr_or_cr) > 0) else 0 - paid_amt = invoiced_amount - outstanding_amount - credit_note_amount - row += [invoiced_amount, paid_amt, credit_note_amount, outstanding_amount] + # get supplier bill details + if args.get("party_type") == "Supplier": + row += [ + self.voucher_details.get(gle.voucher_no, {}).get("bill_no", ""), + self.voucher_details.get(gle.voucher_no, {}).get("bill_date", "") + ] - # ageing data - if self.filters.ageing_based_on == "Due Date": - entry_date = due_date - elif self.filters.ageing_based_on == "Supplier Invoice Date": - entry_date = bill_date - else: - entry_date = gle.posting_date + # invoiced and paid amounts + invoiced_amount = gle.get(self.dr_or_cr) if (gle.get(self.dr_or_cr) > 0) else 0 - row += get_ageing_data(cint(self.filters.range1), cint(self.filters.range2), - cint(self.filters.range3), self.age_as_on, entry_date, outstanding_amount) + if not self.filters.based_on_payment_terms: + paid_amt = invoiced_amount - outstanding_amount - credit_note_amount + row += [invoiced_amount, paid_amt, credit_note_amount, outstanding_amount] + + # ageing data + if self.filters.ageing_based_on == "Due Date": + entry_date = due_date + elif self.filters.ageing_based_on == "Supplier Invoice Date": + entry_date = bill_date + else: + entry_date = gle.posting_date + + row += get_ageing_data(cint(self.filters.range1), cint(self.filters.range2), + cint(self.filters.range3), self.age_as_on, entry_date, outstanding_amount) - # issue 6371-Ageing buckets should not have amounts if due date is not reached - if self.filters.ageing_based_on == "Due Date" \ - and getdate(due_date) > getdate(self.filters.report_date): - row[-1]=row[-2]=row[-3]=row[-4]=0 + # issue 6371-Ageing buckets should not have amounts if due date is not reached + if self.filters.ageing_based_on == "Due Date" \ + and getdate(due_date) > getdate(self.filters.report_date): + row[-1]=row[-2]=row[-3]=row[-4]=0 - if self.filters.ageing_based_on == "Supplier Invoice Date" \ - and getdate(bill_date) > getdate(self.filters.report_date): + if self.filters.ageing_based_on == "Supplier Invoice Date" \ + and getdate(bill_date) > getdate(self.filters.report_date): - row[-1]=row[-2]=row[-3]=row[-4]=0 + row[-1]=row[-2]=row[-3]=row[-4]=0 - if self.filters.get(scrub(args.get("party_type"))): - row.append(gle.account_currency) - else: - row.append(company_currency) + if self.filters.get(scrub(args.get("party_type"))): + row.append(gle.account_currency) + else: + row.append(self.company_currency) - pdc = pdc_details.get((gle.voucher_no, gle.party), {}) + pdc = self.pdc_details.get((gle.voucher_no, gle.party), {}) - remaining_balance = outstanding_amount - flt(pdc.get("pdc_amount")) - row += [pdc.get("pdc_date"), pdc.get("pdc_ref"), - flt(pdc.get("pdc_amount")), remaining_balance] - - if args.get('party_type') == 'Customer': - # customer LPO - row += [voucher_details.get(gle.voucher_no, {}).get("po_no")] - - # Delivery Note - row += [voucher_details.get(gle.voucher_no, {}).get("delivery_note")] + remaining_balance = outstanding_amount - flt(pdc.get("pdc_amount")) + row += [pdc.get("pdc_date"), pdc.get("pdc_ref"), + flt(pdc.get("pdc_amount")), remaining_balance] +<<<<<<< HEAD # customer territory / supplier group if args.get("party_type") == "Customer": row += [self.get_territory(gle.party), self.get_customer_group(gle.party), voucher_details.get(gle.voucher_no, {}).get("sales_person")] if args.get("party_type") == "Supplier": row += [self.get_supplier_group(gle.party)] +======= + if args.get('party_type') == 'Customer': + # customer LPO + row += [self.voucher_details.get(gle.voucher_no, {}).get("po_no")] +>>>>>>> Accounts Receivable report based on payment terms - row.append(gle.remarks) - data.append(row) + # Delivery Note + row += [self.voucher_details.get(gle.voucher_no, {}).get("delivery_note")] - return data + # customer territory / supplier group + if args.get("party_type") == "Customer": + row += [self.get_territory(gle.party), self.get_customer_group(gle.party)] + if args.get("party_type") == "Supplier": + row += [self.get_supplier_group(gle.party)] + + row.append(gle.remarks) + + return row def get_entries_after(self, report_date, party_type): # returns a distinct list @@ -298,7 +331,7 @@ class ReceivablePayableReport(object): credit_note_amount = flt(credit_note_amount, currency_precision) - return outstanding_amount, credit_note_amount + return outstanding_amount, credit_note_amount, payment_amount def get_party_name(self, party_type, party_name): return self.get_party_map(party_type).get(party_name, {}).get("customer_name" if party_type == "Customer" else "supplier_name") or "" @@ -432,6 +465,20 @@ class ReceivablePayableReport(object): .get(against_voucher_type, {})\ .get(against_voucher, []) + def get_payment_term_detail(self, voucher_nos): + payment_term_map = frappe._dict() + for d in frappe.db.sql(""" select si.name, si.payment_terms_template, ps.due_date, ps.payment_amount + from `tabSales Invoice` si, `tabPayment Schedule` ps + where si.name = ps.parent and + si.docstatus = 1 and si.company = '%s' and + si.name in (%s) order by ps.due_date""" + % (self.filters.company, ','.join(['%s'] *len(voucher_nos))), (tuple(voucher_nos)), as_dict = 1): + if d.payment_terms_template: + payment_term_map.setdefault(d.name,[]) + payment_term_map[d.name].append((d.due_date,d.payment_amount)) + + return payment_term_map + def get_chart_data(self, columns, data): ageing_columns = columns[self.ageing_col_idx_start : self.ageing_col_idx_start+4] From 24f8d3ed0c8bb48839e0581373fe6e3169e489a5 Mon Sep 17 00:00:00 2001 From: deepeshgarg007 Date: Mon, 12 Nov 2018 14:45:33 +0530 Subject: [PATCH 14/25] Add columns based on payment terms --- .../accounts_receivable.py | 30 +++++++++++++++---- 1 file changed, 24 insertions(+), 6 deletions(-) diff --git a/erpnext/accounts/report/accounts_receivable/accounts_receivable.py b/erpnext/accounts/report/accounts_receivable/accounts_receivable.py index 4455be4ad2..20b19eb40c 100755 --- a/erpnext/accounts/report/accounts_receivable/accounts_receivable.py +++ b/erpnext/accounts/report/accounts_receivable/accounts_receivable.py @@ -57,6 +57,21 @@ class ReceivablePayableReport(object): credit_or_debit_note = "Credit Note" if args.get("party_type") == "Customer" else "Debit Note" + if self.filters.based_on_payment_terms: + columns.append({ + "label": "Payment Term", + "fieldname": "payment_term", + "fieldtype": "Data", + "width": 120 + }) + columns.append({ + "label": "Payment Term Amount", + "fieldname": "payment_term_amount", + "fieldtype": "Currency", + "options": "currency", + "width": 120 + }) + for label in ("Invoiced Amount", "Paid Amount", credit_or_debit_note, "Outstanding Amount"): columns.append({ "label": label, @@ -187,7 +202,7 @@ class ReceivablePayableReport(object): else: outstanding_amount = d[1] - payment_amount row = self.prepare_row(party_naming_by, args, gle, outstanding_amount, - credit_note_amount, d[0], payment_amount ) + credit_note_amount, d[0], payment_amount , d[1], d[2]) payment_amount = 0 data.append(row) else: @@ -199,7 +214,7 @@ class ReceivablePayableReport(object): return data def prepare_row(self, party_naming_by, args, gle, outstanding_amount, credit_note_amount, - due_date=None, paid_amt=None): + due_date=None, paid_amt=None, payment_term_amount=None, payment_term=None): row = [gle.posting_date, gle.party] # customer / supplier name @@ -223,7 +238,10 @@ class ReceivablePayableReport(object): # invoiced and paid amounts invoiced_amount = gle.get(self.dr_or_cr) if (gle.get(self.dr_or_cr) > 0) else 0 - if not self.filters.based_on_payment_terms: + if self.filters.based_on_payment_terms: + row+=[payment_term, payment_term_amount] + + if paid_amt == None: paid_amt = invoiced_amount - outstanding_amount - credit_note_amount row += [invoiced_amount, paid_amt, credit_note_amount, outstanding_amount] @@ -467,15 +485,15 @@ class ReceivablePayableReport(object): def get_payment_term_detail(self, voucher_nos): payment_term_map = frappe._dict() - for d in frappe.db.sql(""" select si.name, si.payment_terms_template, ps.due_date, ps.payment_amount + for d in frappe.db.sql(""" select si.name, si.payment_terms_template, ps.due_date, ps.payment_amount, ps.description from `tabSales Invoice` si, `tabPayment Schedule` ps where si.name = ps.parent and si.docstatus = 1 and si.company = '%s' and si.name in (%s) order by ps.due_date""" % (self.filters.company, ','.join(['%s'] *len(voucher_nos))), (tuple(voucher_nos)), as_dict = 1): if d.payment_terms_template: - payment_term_map.setdefault(d.name,[]) - payment_term_map[d.name].append((d.due_date,d.payment_amount)) + payment_term_map.setdefault(d.name, []) + payment_term_map[d.name].append((d.due_date, d.payment_amount, d.description)) return payment_term_map From b6c083706a3ebfa8e4684cb224226917f571441e Mon Sep 17 00:00:00 2001 From: deepeshgarg007 Date: Tue, 13 Nov 2018 12:11:04 +0530 Subject: [PATCH 15/25] Allocation of credit note amount and pdc in payment terms --- .../accounts_receivable.py | 51 ++++++++++++------- 1 file changed, 32 insertions(+), 19 deletions(-) diff --git a/erpnext/accounts/report/accounts_receivable/accounts_receivable.py b/erpnext/accounts/report/accounts_receivable/accounts_receivable.py index 20b19eb40c..5db186b8f5 100755 --- a/erpnext/accounts/report/accounts_receivable/accounts_receivable.py +++ b/erpnext/accounts/report/accounts_receivable/accounts_receivable.py @@ -174,7 +174,7 @@ class ReceivablePayableReport(object): if not self.filters.get("company"): self.filters["company"] = frappe.db.get_single_value('Global Defaults', 'default_company') - self.company_currency = frappe.get_cached_value('Company', self.filters.get("company"), "default_currency") + self.company_currency = frappe.get_cached_value('Company', self.filters.get("company"), "default_currency") return_entries = self.get_return_entries(args.get("party_type")) @@ -192,29 +192,37 @@ class ReceivablePayableReport(object): for gle in gl_entries_data: if self.is_receivable_or_payable(gle, self.dr_or_cr, future_vouchers): - if self.filters.based_on_payment_terms and self.payment_term_map.get(gle.voucher_no): - outstanding_amount, credit_note_amount, payment_amount = self.get_outstanding_amount( - gle,self.filters.report_date, self.dr_or_cr, return_entries, currency_precision) - if abs(outstanding_amount) > 0.1/10**currency_precision: + outstanding_amount, credit_note_amount, payment_amount = self.get_outstanding_amount( + gle,self.filters.report_date, self.dr_or_cr, return_entries, currency_precision) + if abs(outstanding_amount) > 0.1/10**currency_precision: + if self.filters.based_on_payment_terms and self.payment_term_map.get(gle.voucher_no): + pdc_amount = flt(self.pdc_details.get((gle.voucher_no, gle.party), {}).get("pdc_amount")) for d in self.payment_term_map.get(gle.voucher_no): - if payment_amount >= d[1]: - payment_amount -= d[1] + if payment_amount + credit_note_amount >= d[1]: + temp = payment_amount + payment_amount = payment_amount - d[1] + credit_note_amount + credit_note_amount = credit_note_amount - d[1] + temp - payment_amount else: - outstanding_amount = d[1] - payment_amount - row = self.prepare_row(party_naming_by, args, gle, outstanding_amount, - credit_note_amount, d[0], payment_amount , d[1], d[2]) + outstanding_amount = d[1] - payment_amount - credit_note_amount + if pdc_amount > outstanding_amount: + pdc = outstanding_amount + pdc_amount -= outstanding_amount + else: + pdc = pdc_amount + pdc_amount = 0 + + row = self.prepare_row(party_naming_by, args, gle, outstanding_amount, + credit_note_amount, d[0], payment_amount , d[1], d[2], pdc) payment_amount = 0 + credit_note_amount = 0 data.append(row) - else: - outstanding_amount, credit_note_amount, payment_amount = self.get_outstanding_amount( - gle,self.filters.report_date, self.dr_or_cr, return_entries, currency_precision) - if abs(outstanding_amount) > 0.1/10**currency_precision: + else: row = self.prepare_row(party_naming_by, args, gle, outstanding_amount, credit_note_amount) data.append(row) return data def prepare_row(self, party_naming_by, args, gle, outstanding_amount, credit_note_amount, - due_date=None, paid_amt=None, payment_term_amount=None, payment_term=None): + due_date=None, paid_amt=None, payment_term_amount=None, payment_term=None, pdc_amount=None): row = [gle.posting_date, gle.party] # customer / supplier name @@ -274,9 +282,14 @@ class ReceivablePayableReport(object): pdc = self.pdc_details.get((gle.voucher_no, gle.party), {}) - remaining_balance = outstanding_amount - flt(pdc.get("pdc_amount")) - row += [pdc.get("pdc_date"), pdc.get("pdc_ref"), - flt(pdc.get("pdc_amount")), remaining_balance] + if pdc_amount == None: + pdc_amount = flt(pdc.get("pdc_amount")) + + pdc_date = pdc.get("pdc_date") if pdc_amount else '' + pdc_ref = pdc.get("pdc_ref") if pdc_amount else '' + + remaining_balance = outstanding_amount - pdc_amount + row += [pdc_date, pdc_ref, pdc_amount, remaining_balance] <<<<<<< HEAD # customer territory / supplier group @@ -555,7 +568,7 @@ def get_pdc_details(party_type, report_date): on (pref.parent = pent.name) where - pent.docstatus < 2 and pent.posting_date > %s + pent.docstatus < 2 and pent.posting_date > %s and pent.party_type = %s group by pent.party, pref.reference_name""", (report_date, party_type), as_dict=1): pdc_details.setdefault((pdc.invoice_no, pdc.party), pdc) From f98adf2be514a4553cdbb6adabe805e4e57966e4 Mon Sep 17 00:00:00 2001 From: deepeshgarg007 Date: Tue, 13 Nov 2018 15:07:05 +0530 Subject: [PATCH 16/25] Changed columns and added currency conditions --- .../accounts_receivable.py | 53 +++++++++++-------- 1 file changed, 31 insertions(+), 22 deletions(-) diff --git a/erpnext/accounts/report/accounts_receivable/accounts_receivable.py b/erpnext/accounts/report/accounts_receivable/accounts_receivable.py index 5db186b8f5..c8f9b6f874 100755 --- a/erpnext/accounts/report/accounts_receivable/accounts_receivable.py +++ b/erpnext/accounts/report/accounts_receivable/accounts_receivable.py @@ -65,8 +65,8 @@ class ReceivablePayableReport(object): "width": 120 }) columns.append({ - "label": "Payment Term Amount", - "fieldname": "payment_term_amount", + "label": "Invoice Grand Total", + "fieldname": "invoice_grand_total", "fieldtype": "Currency", "options": "currency", "width": 120 @@ -128,14 +128,14 @@ class ReceivablePayableReport(object): "fieldname": "pdc/lc_amount", "label": _("PDC/LC Amount"), "fieldtype": "Currency", - "options": "Currency", + "options": "currency", "width": 130 }, { "fieldname": "remaining_balance", "label": _("Remaining Balance"), "fieldtype": "Currency", - "options": "Currency", + "options": "currency", "width": 130 }] @@ -166,7 +166,7 @@ class ReceivablePayableReport(object): def get_data(self, party_naming_by, args): from erpnext.accounts.utils import get_currency_precision - currency_precision = get_currency_precision() or 2 + self.currency_precision = get_currency_precision() or 2 self.dr_or_cr = "debit" if args.get("party_type") == "Customer" else "credit" future_vouchers = self.get_entries_after(self.filters.report_date, args.get("party_type")) @@ -193,8 +193,8 @@ class ReceivablePayableReport(object): for gle in gl_entries_data: if self.is_receivable_or_payable(gle, self.dr_or_cr, future_vouchers): outstanding_amount, credit_note_amount, payment_amount = self.get_outstanding_amount( - gle,self.filters.report_date, self.dr_or_cr, return_entries, currency_precision) - if abs(outstanding_amount) > 0.1/10**currency_precision: + gle,self.filters.report_date, self.dr_or_cr, return_entries) + if abs(outstanding_amount) > 0.1/10**self.currency_precision: if self.filters.based_on_payment_terms and self.payment_term_map.get(gle.voucher_no): pdc_amount = flt(self.pdc_details.get((gle.voucher_no, gle.party), {}).get("pdc_amount")) for d in self.payment_term_map.get(gle.voucher_no): @@ -210,7 +210,8 @@ class ReceivablePayableReport(object): else: pdc = pdc_amount pdc_amount = 0 - + if self.filters.get(gle.party_type): + d[1] = d[1] * d[3] row = self.prepare_row(party_naming_by, args, gle, outstanding_amount, credit_note_amount, d[0], payment_amount , d[1], d[2], pdc) payment_amount = 0 @@ -247,7 +248,9 @@ class ReceivablePayableReport(object): invoiced_amount = gle.get(self.dr_or_cr) if (gle.get(self.dr_or_cr) > 0) else 0 if self.filters.based_on_payment_terms: - row+=[payment_term, payment_term_amount] + row+=[payment_term, invoiced_amount] + if payment_term_amount: + invoiced_amount = payment_term_amount if paid_amt == None: paid_amt = invoiced_amount - outstanding_amount - credit_note_amount @@ -344,23 +347,23 @@ class ReceivablePayableReport(object): doctype = "Sales Invoice" if party_type=="Customer" else "Purchase Invoice" return [d.name for d in frappe.get_all(doctype, filters={"is_return": 1, "docstatus": 1})] - def get_outstanding_amount(self, gle, report_date, dr_or_cr, return_entries, currency_precision): + def get_outstanding_amount(self, gle, report_date, dr_or_cr, return_entries): payment_amount, credit_note_amount = 0.0, 0.0 reverse_dr_or_cr = "credit" if dr_or_cr=="debit" else "debit" for e in self.get_gl_entries_for(gle.party, gle.party_type, gle.voucher_type, gle.voucher_no): if getdate(e.posting_date) <= report_date and e.name!=gle.name: - amount = flt(e.get(reverse_dr_or_cr), currency_precision) - flt(e.get(dr_or_cr), currency_precision) + amount = flt(e.get(reverse_dr_or_cr), self.currency_precision) - flt(e.get(dr_or_cr), self.currency_precision) if e.voucher_no not in return_entries: payment_amount += amount else: credit_note_amount += amount - outstanding_amount = (flt((flt(gle.get(dr_or_cr), currency_precision) - - flt(gle.get(reverse_dr_or_cr), currency_precision) - - payment_amount - credit_note_amount), currency_precision)) + outstanding_amount = (flt((flt(gle.get(dr_or_cr), self.currency_precision) + - flt(gle.get(reverse_dr_or_cr), self.currency_precision) + - payment_amount - credit_note_amount), self.currency_precision)) - credit_note_amount = flt(credit_note_amount, currency_precision) + credit_note_amount = flt(credit_note_amount, self.currency_precision) return outstanding_amount, credit_note_amount, payment_amount @@ -498,16 +501,22 @@ class ReceivablePayableReport(object): def get_payment_term_detail(self, voucher_nos): payment_term_map = frappe._dict() - for d in frappe.db.sql(""" select si.name, si.payment_terms_template, ps.due_date, ps.payment_amount, ps.description - from `tabSales Invoice` si, `tabPayment Schedule` ps - where si.name = ps.parent and - si.docstatus = 1 and si.company = '%s' and - si.name in (%s) order by ps.due_date""" + for d in frappe.db.sql(""" select si.name, si.payment_terms_template, + party_account_currency, currency, si.conversion_rate, + ps.due_date, ps.payment_amount, ps.description + from `tabSales Invoice` si, `tabPayment Schedule` ps + where si.name = ps.parent and + si.docstatus = 1 and si.company = '%s' and + si.name in (%s) order by ps.due_date""" % (self.filters.company, ','.join(['%s'] *len(voucher_nos))), (tuple(voucher_nos)), as_dict = 1): if d.payment_terms_template: - payment_term_map.setdefault(d.name, []) - payment_term_map[d.name].append((d.due_date, d.payment_amount, d.description)) + if self.filters.get("customer") and d.currency == d.party_account_currency: + payment_term_amount = d.payment_amount + else: + payment_term_amount = flt(flt(d.payment_amount) * flt(d.conversion_rate), self.currency_precision) + payment_term_map.setdefault(d.name, []) + payment_term_map[d.name].append((d.due_date, payment_term_amount, d.description)) return payment_term_map def get_chart_data(self, columns, data): From e7a91b9526ced2702a1b0d60cc5b81af914f0a56 Mon Sep 17 00:00:00 2001 From: deepeshgarg007 Date: Thu, 6 Dec 2018 14:59:54 +0530 Subject: [PATCH 17/25] Credit note fix --- .../accounts_receivable.py | 27 +++++++++++-------- 1 file changed, 16 insertions(+), 11 deletions(-) diff --git a/erpnext/accounts/report/accounts_receivable/accounts_receivable.py b/erpnext/accounts/report/accounts_receivable/accounts_receivable.py index c8f9b6f874..b262311d4a 100755 --- a/erpnext/accounts/report/accounts_receivable/accounts_receivable.py +++ b/erpnext/accounts/report/accounts_receivable/accounts_receivable.py @@ -198,10 +198,15 @@ class ReceivablePayableReport(object): if self.filters.based_on_payment_terms and self.payment_term_map.get(gle.voucher_no): pdc_amount = flt(self.pdc_details.get((gle.voucher_no, gle.party), {}).get("pdc_amount")) for d in self.payment_term_map.get(gle.voucher_no): - if payment_amount + credit_note_amount >= d[1]: - temp = payment_amount - payment_amount = payment_amount - d[1] + credit_note_amount - credit_note_amount = credit_note_amount - d[1] + temp - payment_amount + term_outstanding_amount = 0 + if payment_amount >= d[1]: + payment_amount = payment_amount - d[1] + if credit_note_amount: + term_outstanding_amount -= credit_note_amount + row = self.prepare_row(party_naming_by, args, gle, term_outstanding_amount, + credit_note_amount, d[0], payment_amount , d[1], d[2], 0) + credit_note_amount = 0 + data.append(row) else: outstanding_amount = d[1] - payment_amount - credit_note_amount if pdc_amount > outstanding_amount: @@ -222,7 +227,7 @@ class ReceivablePayableReport(object): data.append(row) return data - def prepare_row(self, party_naming_by, args, gle, outstanding_amount, credit_note_amount, + def prepare_row(self, party_naming_by, args, gle, outstanding_amount, credit_note_amount, due_date=None, paid_amt=None, payment_term_amount=None, payment_term=None, pdc_amount=None): row = [gle.posting_date, gle.party] @@ -258,8 +263,8 @@ class ReceivablePayableReport(object): # ageing data if self.filters.ageing_based_on == "Due Date": - entry_date = due_date - elif self.filters.ageing_based_on == "Supplier Invoice Date": + entry_date = due_date + elif self.filters.ageing_based_on == "Supplier Invoice Date": entry_date = bill_date else: entry_date = gle.posting_date @@ -450,7 +455,7 @@ class ReceivablePayableReport(object): conditions.append("""party in (select name from tabCustomer where exists(select name from `tabCustomer Group` where lft >= {0} and rgt <= {1} and name=tabCustomer.customer_group))""".format(lft, rgt)) - + if self.filters.get("territory"): lft, rgt = frappe.db.get_value("Territory", self.filters.get("territory"), ["lft", "rgt"]) @@ -482,7 +487,7 @@ class ReceivablePayableReport(object): conditions.append("""party in (select name from tabSupplier where supplier_group=%s)""") values.append(self.filters.get("supplier_group")) - + return " and ".join(conditions), values def get_gl_entries_for(self, party, party_type, against_voucher_type, against_voucher): @@ -505,7 +510,7 @@ class ReceivablePayableReport(object): party_account_currency, currency, si.conversion_rate, ps.due_date, ps.payment_amount, ps.description from `tabSales Invoice` si, `tabPayment Schedule` ps - where si.name = ps.parent and + where si.name = ps.parent and si.docstatus = 1 and si.company = '%s' and si.name in (%s) order by ps.due_date""" % (self.filters.company, ','.join(['%s'] *len(voucher_nos))), (tuple(voucher_nos)), as_dict = 1): @@ -577,7 +582,7 @@ def get_pdc_details(party_type, report_date): on (pref.parent = pent.name) where - pent.docstatus < 2 and pent.posting_date > %s + pent.docstatus < 2 and pent.posting_date > %s and pent.party_type = %s group by pent.party, pref.reference_name""", (report_date, party_type), as_dict=1): pdc_details.setdefault((pdc.invoice_no, pdc.party), pdc) From 17544d7ad6885ac27aa2a22dba4d4b0088097d62 Mon Sep 17 00:00:00 2001 From: deepeshgarg007 Date: Fri, 7 Dec 2018 08:15:05 +0530 Subject: [PATCH 18/25] Refactored accounts receivable report for payment terms --- .../accounts_receivable.py | 162 ++++++++++-------- 1 file changed, 90 insertions(+), 72 deletions(-) diff --git a/erpnext/accounts/report/accounts_receivable/accounts_receivable.py b/erpnext/accounts/report/accounts_receivable/accounts_receivable.py index b262311d4a..8ff4b2db1b 100755 --- a/erpnext/accounts/report/accounts_receivable/accounts_receivable.py +++ b/erpnext/accounts/report/accounts_receivable/accounts_receivable.py @@ -4,7 +4,7 @@ from __future__ import unicode_literals import frappe, erpnext from frappe import _, scrub -from frappe.utils import getdate, nowdate, flt, cint +from frappe.utils import getdate, nowdate, flt, cint, formatdate, cstr class ReceivablePayableReport(object): def __init__(self, filters=None): @@ -112,12 +112,12 @@ class ReceivablePayableReport(object): "options": "Currency", "width": 100 }, - { - "fieldname": "pdc/lc_date", - "label": _("PDC/LC Date"), - "fieldtype": "Date", - "width": 110 - }, + # { + # "fieldname": "pdc/lc_date", + # "label": _("PDC/LC Date"), + # "fieldtype": "Date", + # "width": 110 + # }, { "fieldname": "pdc/lc_ref", "label": _("PDC/LC Ref"), @@ -195,40 +195,64 @@ class ReceivablePayableReport(object): outstanding_amount, credit_note_amount, payment_amount = self.get_outstanding_amount( gle,self.filters.report_date, self.dr_or_cr, return_entries) if abs(outstanding_amount) > 0.1/10**self.currency_precision: + pdc_list = self.pdc_details.get((gle.voucher_no, gle.party), []) if self.filters.based_on_payment_terms and self.payment_term_map.get(gle.voucher_no): - pdc_amount = flt(self.pdc_details.get((gle.voucher_no, gle.party), {}).get("pdc_amount")) for d in self.payment_term_map.get(gle.voucher_no): - term_outstanding_amount = 0 - if payment_amount >= d[1]: - payment_amount = payment_amount - d[1] - if credit_note_amount: - term_outstanding_amount -= credit_note_amount - row = self.prepare_row(party_naming_by, args, gle, term_outstanding_amount, - credit_note_amount, d[0], payment_amount , d[1], d[2], 0) - credit_note_amount = 0 - data.append(row) - else: - outstanding_amount = d[1] - payment_amount - credit_note_amount - if pdc_amount > outstanding_amount: - pdc = outstanding_amount - pdc_amount -= outstanding_amount + payment_amount, d.payment_amount = self.allocate_based_on_fifo(payment_amount, d.payment_term_amount) + + term_outstanding_amount = d.payment_term_amount - d.payment_amount + credit_note_amount, d.credit_note_amount = self.allocate_based_on_fifo(credit_note_amount, term_outstanding_amount) + + term_outstanding_amount -= d.credit_note_amount + + row_outstanding = term_outstanding_amount + d.pdc_details = [] + for pdc in pdc_list: + if row_outstanding <= pdc.pdc_amount: + d.pdc_amount += row_outstanding + pdc.pdc_amount -= row_outstanding + if row_outstanding and d.pdc_ref and d.pdc_date: + d.pdc_details.append(cstr(d.pdc_ref) + "/" + formatdate(d.pdc_date)) + row_outstanding = 0 + else: - pdc = pdc_amount - pdc_amount = 0 - if self.filters.get(gle.party_type): - d[1] = d[1] * d[3] - row = self.prepare_row(party_naming_by, args, gle, outstanding_amount, - credit_note_amount, d[0], payment_amount , d[1], d[2], pdc) - payment_amount = 0 - credit_note_amount = 0 + d.pdc_amount = pdc.pdc_amount + if pdc.pdc_amount and d.pdc_ref and d.pdc_date: + d.pdc_details.append(cstr(d.pdc_ref) + "/" + formatdate(d.pdc_date)) + pdc.pdc_amount = 0 + row_outstanding -= d.pdc_amount + + if term_outstanding_amount > 0: + row = self.prepare_row(party_naming_by, args, gle, term_outstanding_amount, + d.credit_note_amount, d.due_date, d.payment_amount , d.payment_term_amount, + d.description, d.pdc_amount, d.pdc_details) data.append(row) else: - row = self.prepare_row(party_naming_by, args, gle, outstanding_amount, credit_note_amount) + pdc_amount = 0 + pdc_details = [] + for d in pdc_list: + pdc_amount += flt(d.pdc_amount) + if pdc_amount and d.pdc_ref and d.pdc_date: + pdc_details.append(cstr(d.pdc_ref) + "/" + formatdate(d.pdc_date)) + + row = self.prepare_row(party_naming_by, args, gle, outstanding_amount, + credit_note_amount, pdc_amount=pdc_amount, pdc_details=pdc_details) data.append(row) return data + def allocate_based_on_fifo(self, total_amount, row_amount): + allocated_amount = 0 + if row_amount <= total_amount: + allocated_amount = row_amount + total_amount -= row_amount + else: + allocated_amount = total_amount + total_amount = 0 + + return total_amount, allocated_amount + def prepare_row(self, party_naming_by, args, gle, outstanding_amount, credit_note_amount, - due_date=None, paid_amt=None, payment_term_amount=None, payment_term=None, pdc_amount=None): + due_date=None, paid_amt=None, payment_term_amount=None, payment_term=None, pdc_amount=None, pdc_details=None): row = [gle.posting_date, gle.party] # customer / supplier name @@ -257,7 +281,7 @@ class ReceivablePayableReport(object): if payment_term_amount: invoiced_amount = payment_term_amount - if paid_amt == None: + if not payment_term_amount: paid_amt = invoiced_amount - outstanding_amount - credit_note_amount row += [invoiced_amount, paid_amt, credit_note_amount, outstanding_amount] @@ -288,16 +312,9 @@ class ReceivablePayableReport(object): else: row.append(self.company_currency) - pdc = self.pdc_details.get((gle.voucher_no, gle.party), {}) - - if pdc_amount == None: - pdc_amount = flt(pdc.get("pdc_amount")) - - pdc_date = pdc.get("pdc_date") if pdc_amount else '' - pdc_ref = pdc.get("pdc_ref") if pdc_amount else '' - - remaining_balance = outstanding_amount - pdc_amount - row += [pdc_date, pdc_ref, pdc_amount, remaining_balance] + remaining_balance = outstanding_amount - flt(pdc_amount) + pdc_details = ", ".join(pdc_details) + row += [pdc_details, pdc_amount, remaining_balance] <<<<<<< HEAD # customer territory / supplier group @@ -506,22 +523,27 @@ class ReceivablePayableReport(object): def get_payment_term_detail(self, voucher_nos): payment_term_map = frappe._dict() - for d in frappe.db.sql(""" select si.name, si.payment_terms_template, + payment_terms_details = frappe.db.sql(""" select si.name, party_account_currency, currency, si.conversion_rate, ps.due_date, ps.payment_amount, ps.description from `tabSales Invoice` si, `tabPayment Schedule` ps where si.name = ps.parent and si.docstatus = 1 and si.company = '%s' and - si.name in (%s) order by ps.due_date""" - % (self.filters.company, ','.join(['%s'] *len(voucher_nos))), (tuple(voucher_nos)), as_dict = 1): - if d.payment_terms_template: - if self.filters.get("customer") and d.currency == d.party_account_currency: - payment_term_amount = d.payment_amount - else: - payment_term_amount = flt(flt(d.payment_amount) * flt(d.conversion_rate), self.currency_precision) + si.name in (%s) order by ps.due_date + """ % (self.filters.company, ','.join(['%s'] *len(voucher_nos))), + (tuple(voucher_nos)), as_dict = 1) - payment_term_map.setdefault(d.name, []) - payment_term_map[d.name].append((d.due_date, payment_term_amount, d.description)) + for d in payment_terms_details: + if self.filters.get("customer") and d.currency == d.party_account_currency: + payment_term_amount = d.payment_amount + else: + payment_term_amount = flt(flt(d.payment_amount) * flt(d.conversion_rate), self.currency_precision) + + payment_term_map.setdefault(d.name, []).append(frappe._dict({ + "due_date": d.due_date, + "payment_term_amount": payment_term_amount, + "description": d.description + })) return payment_term_map def get_chart_data(self, columns, data): @@ -571,12 +593,11 @@ def get_ageing_data(first_range, second_range, third_range, age_as_on, entry_dat def get_pdc_details(party_type, report_date): pdc_details = frappe._dict() - - for pdc in frappe.db.sql(""" + pdc_via_pe = frappe.db.sql(""" select pref.reference_name as invoice_no, pent.party, pent.party_type, - max(pent.posting_date) as pdc_date, sum(ifnull(pref.allocated_amount,0)) as pdc_amount, - GROUP_CONCAT(pent.reference_no SEPARATOR ', ') as pdc_ref + pent.posting_date as pdc_date, ifnull(pref.allocated_amount,0) as pdc_amount, + pent.reference_no as pdc_ref from `tabPayment Entry` as pent inner join `tabPayment Entry Reference` as pref on @@ -584,19 +605,22 @@ def get_pdc_details(party_type, report_date): where pent.docstatus < 2 and pent.posting_date > %s and pent.party_type = %s - group by pent.party, pref.reference_name""", (report_date, party_type), as_dict=1): - pdc_details.setdefault((pdc.invoice_no, pdc.party), pdc) + """, (report_date, party_type), as_dict=1) + + for pdc in pdc_via_pe: + pdc_details.setdefault((pdc.invoice_no, pdc.party), []).append(pdc) + if scrub(party_type): amount_field = ("jea.debit_in_account_currency" if party_type == 'Supplier' else "jea.credit_in_account_currency") else: amount_field = "jea.debit + jea.credit" - for pdc in frappe.db.sql(""" + pdc_via_je = frappe.db.sql(""" select jea.reference_name as invoice_no, jea.party, jea.party_type, - max(je.posting_date) as pdc_date, sum(ifnull({0},0)) as pdc_amount, - GROUP_CONCAT(je.cheque_no SEPARATOR ', ') as pdc_ref + je.posting_date as pdc_date, ifnull({0},0) as pdc_amount, + je.cheque_no as pdc_ref from `tabJournal Entry` as je inner join `tabJournal Entry Account` as jea on @@ -604,16 +628,10 @@ def get_pdc_details(party_type, report_date): where je.docstatus < 2 and je.posting_date > %s and jea.party_type = %s - group by jea.party, jea.reference_name""".format(amount_field), (report_date, party_type), as_dict=1): - if (pdc.invoice_no, pdc.party) in pdc_details: - key = (pdc.invoice_no, pdc.party) - pdc_details[key]["pdc_amount"] += pdc.pdc_amount - if pdc.pdc_ref: - pdc_details[key]["pdc_ref"] += ", " + pdc.pdc_ref - if pdc.pdc_date: - pdc_details[key]["pdc_date"] = max(pdc_details[key]["pdc_date"], pdc.pdc_date) - else: - pdc_details.setdefault((pdc.invoice_no, pdc.party), pdc) + """.format(amount_field), (report_date, party_type), as_dict=1) + + for pdc in pdc_via_je: + pdc_details.setdefault((pdc.invoice_no, pdc.party), []).append(pdc) return pdc_details From a944f88b946b3b9a94dffbbc1cd9c9b18ad51e84 Mon Sep 17 00:00:00 2001 From: deepeshgarg007 Date: Fri, 7 Dec 2018 08:17:09 +0530 Subject: [PATCH 19/25] Removed column for pdc date --- .../report/accounts_receivable/accounts_receivable.py | 6 ------ 1 file changed, 6 deletions(-) diff --git a/erpnext/accounts/report/accounts_receivable/accounts_receivable.py b/erpnext/accounts/report/accounts_receivable/accounts_receivable.py index 8ff4b2db1b..3d20039da6 100755 --- a/erpnext/accounts/report/accounts_receivable/accounts_receivable.py +++ b/erpnext/accounts/report/accounts_receivable/accounts_receivable.py @@ -112,12 +112,6 @@ class ReceivablePayableReport(object): "options": "Currency", "width": 100 }, - # { - # "fieldname": "pdc/lc_date", - # "label": _("PDC/LC Date"), - # "fieldtype": "Date", - # "width": 110 - # }, { "fieldname": "pdc/lc_ref", "label": _("PDC/LC Ref"), From 4ac8fcf4af84e3ac3241110fcfb29c539e1acd24 Mon Sep 17 00:00:00 2001 From: deepeshgarg007 Date: Mon, 17 Dec 2018 15:13:33 +0530 Subject: [PATCH 20/25] Added test case for Accounts receivable report based on payment terms --- .../sales_invoice/test_sales_invoice.py | 32 +++---- .../accounts_receivable.py | 16 ++++ .../test_accounts_receivable.py | 84 +++++++++++++++++++ 3 files changed, 116 insertions(+), 16 deletions(-) create mode 100644 erpnext/accounts/report/accounts_receivable/test_accounts_receivable.py diff --git a/erpnext/accounts/doctype/sales_invoice/test_sales_invoice.py b/erpnext/accounts/doctype/sales_invoice/test_sales_invoice.py index 94037c7d0a..68cc500004 100644 --- a/erpnext/accounts/doctype/sales_invoice/test_sales_invoice.py +++ b/erpnext/accounts/doctype/sales_invoice/test_sales_invoice.py @@ -375,7 +375,7 @@ class TestSalesInvoice(unittest.TestCase): si.insert() self.assertEqual(si.net_total, 4600) - + self.assertEqual(si.get("taxes")[0].tax_amount, 874.0) self.assertEqual(si.get("taxes")[0].total, 5474.0) @@ -405,12 +405,12 @@ class TestSalesInvoice(unittest.TestCase): self.assertEqual(si.total, 975) self.assertEqual(si.net_total, 900) - + self.assertEqual(si.get("taxes")[0].tax_amount, 216.0) self.assertEqual(si.get("taxes")[0].total, 1116.0) self.assertEqual(si.grand_total, 1116.0) - + def test_inclusive_rate_validations(self): si = frappe.copy_doc(test_records[2]) for i, tax in enumerate(si.get("taxes")): @@ -552,7 +552,7 @@ class TestSalesInvoice(unittest.TestCase): self.assertEqual(si.grand_total, 1215.90) self.assertEqual(si.rounding_adjustment, 0.01) self.assertEqual(si.base_rounding_adjustment, 0.50) - + def test_outstanding(self): w = self.make() @@ -923,7 +923,7 @@ class TestSalesInvoice(unittest.TestCase): self.assertRaises(SerialNoWarehouseError, si.submit) def test_serial_numbers_against_delivery_note(self): - """ + """ check if the sales invoice item serial numbers and the delivery note items serial numbers are same """ @@ -1238,7 +1238,7 @@ class TestSalesInvoice(unittest.TestCase): def test_item_wise_tax_breakup_india(self): frappe.flags.country = "India" - + si = self.create_si_to_test_tax_breakup() itemised_tax, itemised_taxable_amount = get_itemised_tax_breakup_data(si) @@ -1256,12 +1256,12 @@ class TestSalesInvoice(unittest.TestCase): self.assertEqual(itemised_tax, expected_itemised_tax) self.assertEqual(itemised_taxable_amount, expected_itemised_taxable_amount) - + frappe.flags.country = None def test_item_wise_tax_breakup_outside_india(self): frappe.flags.country = "United States" - + si = self.create_si_to_test_tax_breakup() itemised_tax, itemised_taxable_amount = get_itemised_tax_breakup_data(si) @@ -1287,7 +1287,7 @@ class TestSalesInvoice(unittest.TestCase): self.assertEqual(itemised_tax, expected_itemised_tax) self.assertEqual(itemised_taxable_amount, expected_itemised_taxable_amount) - + frappe.flags.country = None def create_si_to_test_tax_breakup(self): @@ -1375,7 +1375,7 @@ class TestSalesInvoice(unittest.TestCase): shipping_rule = create_shipping_rule(shipping_rule_type = "Selling", shipping_rule_name = "Shipping Rule - Sales Invoice Test") si = frappe.copy_doc(test_records[2]) - + si.shipping_rule = shipping_rule.name si.insert() @@ -1392,14 +1392,14 @@ class TestSalesInvoice(unittest.TestCase): "cost_center": shipping_rule.cost_center, "tax_amount": shipping_amount, "description": shipping_rule.name - } + } si.append("taxes", shipping_charge) si.save() self.assertEqual(si.net_total, 1250) self.assertEqual(si.total_taxes_and_charges, 577.05) - self.assertEqual(si.grand_total, 1827.05) + self.assertEqual(si.grand_total, 1827.05) def test_create_invoice_without_terms(self): si = create_sales_invoice(do_not_save=1) @@ -1496,7 +1496,7 @@ class TestSalesInvoice(unittest.TestCase): for gle in gl_entries: self.assertEqual(expected_values[gle.account]["cost_center"], gle.cost_center) - + accounts_settings.allow_cost_center_in_entry_of_bs_account = 0 accounts_settings.save() @@ -1524,9 +1524,9 @@ def create_sales_invoice(**args): "warehouse": args.warehouse or "_Test Warehouse - _TC", "qty": args.qty or 1, "rate": args.rate or 100, - "income_account": "Sales - _TC", - "expense_account": "Cost of Goods Sold - _TC", - "cost_center": "_Test Cost Center - _TC", + "income_account": args.income_account or "Sales - _TC", + "expense_account": args.expense_account or "Cost of Goods Sold - _TC", + "cost_center": args.cost_center or "_Test Cost Center - _TC", "serial_no": args.serial_no }) diff --git a/erpnext/accounts/report/accounts_receivable/accounts_receivable.py b/erpnext/accounts/report/accounts_receivable/accounts_receivable.py index 3d20039da6..8b16ae3399 100755 --- a/erpnext/accounts/report/accounts_receivable/accounts_receivable.py +++ b/erpnext/accounts/report/accounts_receivable/accounts_receivable.py @@ -221,6 +221,22 @@ class ReceivablePayableReport(object): d.credit_note_amount, d.due_date, d.payment_amount , d.payment_term_amount, d.description, d.pdc_amount, d.pdc_details) data.append(row) + + if credit_note_amount: + outstanding_amount, credit_note_amount, payment_amount = self.get_outstanding_amount( + gle,self.filters.report_date, self.dr_or_cr, return_entries) + + pdc_amount = 0 + pdc_details = [] + for d in pdc_list: + pdc_amount += flt(d.pdc_amount) + if pdc_amount and d.pdc_ref and d.pdc_date: + pdc_details.append(cstr(d.pdc_ref) + "/" + formatdate(d.pdc_date)) + + row = self.prepare_row(party_naming_by, args, gle, outstanding_amount, + credit_note_amount, pdc_amount=pdc_amount, pdc_details=pdc_details) + data.append(row) + else: pdc_amount = 0 pdc_details = [] diff --git a/erpnext/accounts/report/accounts_receivable/test_accounts_receivable.py b/erpnext/accounts/report/accounts_receivable/test_accounts_receivable.py new file mode 100644 index 0000000000..34e6c83e01 --- /dev/null +++ b/erpnext/accounts/report/accounts_receivable/test_accounts_receivable.py @@ -0,0 +1,84 @@ +import frappe +import frappe.defaults +import unittest +from frappe.utils import today, getdate, add_days +from erpnext.accounts.report.accounts_receivable.accounts_receivable import execute +from erpnext.accounts.doctype.sales_invoice.test_sales_invoice import create_sales_invoice +from erpnext.accounts.doctype.payment_entry.payment_entry import get_payment_entry + +class TestAccountsReceivable(unittest.TestCase): + def test_accounts_receivable(self): + frappe.db.sql("delete from `tabSales Invoice` where company='_Test Company 2'") + frappe.db.sql("delete from `tabGL Entry` where company='_Test Company 2'") + + filters = { + 'company': '_Test Company 2', + 'based_on_payment_terms': 1 + } + + name = make_sales_invoice() + report = execute(filters) + + expected_data = [[100,30], [100,50], [100,20]] + + self.assertEqual(expected_data[0], report[1][0][6:8]) + self.assertEqual(expected_data[1], report[1][1][6:8]) + self.assertEqual(expected_data[2], report[1][2][6:8]) + + make_payment(name) + report = execute(filters) + + expected_data_after_payment = [[100,50], [100,20]] + + self.assertEqual(expected_data_after_payment[0], report[1][0][6:8]) + self.assertEqual(expected_data_after_payment[1], report[1][1][6:8]) + + make_credit_note(name) + report = execute(filters) + + expected_data_after_credit_note = [[100,100,30,100,-30]] + + self.assertEqual(expected_data_after_credit_note[0], report[1][0][6:11]) + + +def make_sales_invoice(): + frappe.set_user("Administrator") + + si = create_sales_invoice(company="_Test Company 2", + customer = '_Test Customer 2', + currency = 'EUR', + warehouse = 'Finished Goods - _TC2', + debit_to = 'Debtors - _TC2', + income_account = 'Sales - _TC2', + expense_account = 'Cost of Goods Sold - _TC2', + cost_center = '_Test Company 2 - _TC2', + do_not_save=1) + + si.append('payment_schedule', dict(due_date=getdate(add_days(today(), 30)), invoice_portion=30.00, payment_amount=30)) + si.append('payment_schedule', dict(due_date=getdate(add_days(today(), 60)), invoice_portion=50.00, payment_amount=50)) + si.append('payment_schedule', dict(due_date=getdate(add_days(today(), 90)), invoice_portion=20.00, payment_amount=20)) + + si.submit() + + return si.name + +def make_payment(docname): + pe = get_payment_entry("Sales Invoice", docname, bank_account="Cash - _TC2", party_amount=30) + pe.paid_from = "Debtors - _TC2" + pe.insert() + pe.submit() + + +def make_credit_note(docname): + create_sales_invoice(company="_Test Company 2", + customer = '_Test Customer 2', + currency = 'EUR', + qty = -1, + warehouse = 'Finished Goods - _TC2', + debit_to = 'Debtors - _TC2', + income_account = 'Sales - _TC2', + expense_account = 'Cost of Goods Sold - _TC2', + cost_center = '_Test Company 2 - _TC2', + is_return = 1, + return_against = docname) + From 5de603c6af8e95789480ede0c869cb5670164504 Mon Sep 17 00:00:00 2001 From: deepeshgarg007 Date: Mon, 17 Dec 2018 17:45:39 +0530 Subject: [PATCH 21/25] breaked up code into multiple functions --- .../accounts_receivable.py | 80 +++++++++++-------- 1 file changed, 46 insertions(+), 34 deletions(-) diff --git a/erpnext/accounts/report/accounts_receivable/accounts_receivable.py b/erpnext/accounts/report/accounts_receivable/accounts_receivable.py index 8b16ae3399..1fd82d9a56 100755 --- a/erpnext/accounts/report/accounts_receivable/accounts_receivable.py +++ b/erpnext/accounts/report/accounts_receivable/accounts_receivable.py @@ -189,32 +189,21 @@ class ReceivablePayableReport(object): outstanding_amount, credit_note_amount, payment_amount = self.get_outstanding_amount( gle,self.filters.report_date, self.dr_or_cr, return_entries) if abs(outstanding_amount) > 0.1/10**self.currency_precision: - pdc_list = self.pdc_details.get((gle.voucher_no, gle.party), []) if self.filters.based_on_payment_terms and self.payment_term_map.get(gle.voucher_no): for d in self.payment_term_map.get(gle.voucher_no): + # Allocate payment amount based on payment terms(FIFO order) payment_amount, d.payment_amount = self.allocate_based_on_fifo(payment_amount, d.payment_term_amount) term_outstanding_amount = d.payment_term_amount - d.payment_amount + + # Allocate credit note based on payment terms(FIFO order) credit_note_amount, d.credit_note_amount = self.allocate_based_on_fifo(credit_note_amount, term_outstanding_amount) term_outstanding_amount -= d.credit_note_amount row_outstanding = term_outstanding_amount - d.pdc_details = [] - for pdc in pdc_list: - if row_outstanding <= pdc.pdc_amount: - d.pdc_amount += row_outstanding - pdc.pdc_amount -= row_outstanding - if row_outstanding and d.pdc_ref and d.pdc_date: - d.pdc_details.append(cstr(d.pdc_ref) + "/" + formatdate(d.pdc_date)) - row_outstanding = 0 - - else: - d.pdc_amount = pdc.pdc_amount - if pdc.pdc_amount and d.pdc_ref and d.pdc_date: - d.pdc_details.append(cstr(d.pdc_ref) + "/" + formatdate(d.pdc_date)) - pdc.pdc_amount = 0 - row_outstanding -= d.pdc_amount + # Allocate PDC based on payment terms(FIFO order) + d.pdc_details, d.pdc_amount = self.allocate_pdc_amount_in_fifo(gle, row_outstanding) if term_outstanding_amount > 0: row = self.prepare_row(party_naming_by, args, gle, term_outstanding_amount, @@ -226,30 +215,53 @@ class ReceivablePayableReport(object): outstanding_amount, credit_note_amount, payment_amount = self.get_outstanding_amount( gle,self.filters.report_date, self.dr_or_cr, return_entries) - pdc_amount = 0 - pdc_details = [] - for d in pdc_list: - pdc_amount += flt(d.pdc_amount) - if pdc_amount and d.pdc_ref and d.pdc_date: - pdc_details.append(cstr(d.pdc_ref) + "/" + formatdate(d.pdc_date)) - - row = self.prepare_row(party_naming_by, args, gle, outstanding_amount, - credit_note_amount, pdc_amount=pdc_amount, pdc_details=pdc_details) + row = self.prepare_row_without_payment_terms(party_naming_by, args, gle, outstanding_amount, + credit_note_amount) data.append(row) else: - pdc_amount = 0 - pdc_details = [] - for d in pdc_list: - pdc_amount += flt(d.pdc_amount) - if pdc_amount and d.pdc_ref and d.pdc_date: - pdc_details.append(cstr(d.pdc_ref) + "/" + formatdate(d.pdc_date)) - - row = self.prepare_row(party_naming_by, args, gle, outstanding_amount, - credit_note_amount, pdc_amount=pdc_amount, pdc_details=pdc_details) + row = self.prepare_row_without_payment_terms(party_naming_by, args, gle, outstanding_amount, + credit_note_amount) data.append(row) return data + def allocate_pdc_amount_in_fifo(self, gle, row_outstanding): + pdc_list = self.pdc_details.get((gle.voucher_no, gle.party), []) + + pdc_details = [] + pdc_amount = 0 + for pdc in pdc_list: + if row_outstanding <= pdc.pdc_amount: + pdc_amount += row_outstanding + pdc.pdc_amount -= row_outstanding + if row_outstanding and pdc.pdc_ref and pdc.pdc_date: + pdc_details.append(cstr(pdc.pdc_ref) + "/" + formatdate(pdc.pdc_date)) + row_outstanding = 0 + + else: + pdc_amount = pdc.pdc_amount + if pdc.pdc_amount and pdc.pdc_ref and pdc.pdc_date: + pdc_details.append(cstr(pdc.pdc_ref) + "/" + formatdate(pdc.pdc_date)) + pdc.pdc_amount = 0 + row_outstanding -= pdc_amount + + return pdc_details, pdc_amount + + def prepare_row_without_payment_terms(self, party_naming_by, args, gle, outstanding_amount, credit_note_amount): + pdc_list = self.pdc_details.get((gle.voucher_no, gle.party), []) + pdc_amount = 0 + pdc_details = [] + for d in pdc_list: + pdc_amount += flt(d.pdc_amount) + if pdc_amount and d.pdc_ref and d.pdc_date: + pdc_details.append(cstr(d.pdc_ref) + "/" + formatdate(d.pdc_date)) + + row = self.prepare_row(party_naming_by, args, gle, outstanding_amount, + credit_note_amount, pdc_amount=pdc_amount, pdc_details=pdc_details) + + return row + + def allocate_based_on_fifo(self, total_amount, row_amount): allocated_amount = 0 if row_amount <= total_amount: From 530453e4fc1e51e98fc751be17f887075a41b27e Mon Sep 17 00:00:00 2001 From: deepeshgarg007 Date: Wed, 19 Dec 2018 18:12:58 +0530 Subject: [PATCH 22/25] Added temp variables for outstanding, credit_note_amt instead of function calling --- .../report/accounts_receivable/accounts_receivable.py | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/erpnext/accounts/report/accounts_receivable/accounts_receivable.py b/erpnext/accounts/report/accounts_receivable/accounts_receivable.py index 1fd82d9a56..161f845e4f 100755 --- a/erpnext/accounts/report/accounts_receivable/accounts_receivable.py +++ b/erpnext/accounts/report/accounts_receivable/accounts_receivable.py @@ -188,6 +188,10 @@ class ReceivablePayableReport(object): if self.is_receivable_or_payable(gle, self.dr_or_cr, future_vouchers): outstanding_amount, credit_note_amount, payment_amount = self.get_outstanding_amount( gle,self.filters.report_date, self.dr_or_cr, return_entries) + + temp_outstanding_amt = outstanding_amount + temp_credit_note_amt = credit_note_amount + if abs(outstanding_amount) > 0.1/10**self.currency_precision: if self.filters.based_on_payment_terms and self.payment_term_map.get(gle.voucher_no): for d in self.payment_term_map.get(gle.voucher_no): @@ -212,11 +216,8 @@ class ReceivablePayableReport(object): data.append(row) if credit_note_amount: - outstanding_amount, credit_note_amount, payment_amount = self.get_outstanding_amount( - gle,self.filters.report_date, self.dr_or_cr, return_entries) - - row = self.prepare_row_without_payment_terms(party_naming_by, args, gle, outstanding_amount, - credit_note_amount) + row = self.prepare_row_without_payment_terms(party_naming_by, args, gle, temp_outstanding_amt, + temp_credit_note_amt) data.append(row) else: From b645c2c75ee60dc853a7f82d484f4b8e844b6413 Mon Sep 17 00:00:00 2001 From: deepeshgarg007 Date: Wed, 19 Dec 2018 18:47:36 +0530 Subject: [PATCH 23/25] Rebase using staging-fixes and resolved conflicts --- .../accounts_receivable/accounts_receivable.py | 12 ++---------- 1 file changed, 2 insertions(+), 10 deletions(-) diff --git a/erpnext/accounts/report/accounts_receivable/accounts_receivable.py b/erpnext/accounts/report/accounts_receivable/accounts_receivable.py index 161f845e4f..a084ae986c 100755 --- a/erpnext/accounts/report/accounts_receivable/accounts_receivable.py +++ b/erpnext/accounts/report/accounts_receivable/accounts_receivable.py @@ -339,25 +339,17 @@ class ReceivablePayableReport(object): pdc_details = ", ".join(pdc_details) row += [pdc_details, pdc_amount, remaining_balance] -<<<<<<< HEAD - # customer territory / supplier group - if args.get("party_type") == "Customer": - row += [self.get_territory(gle.party), self.get_customer_group(gle.party), - voucher_details.get(gle.voucher_no, {}).get("sales_person")] - if args.get("party_type") == "Supplier": - row += [self.get_supplier_group(gle.party)] -======= if args.get('party_type') == 'Customer': # customer LPO row += [self.voucher_details.get(gle.voucher_no, {}).get("po_no")] ->>>>>>> Accounts Receivable report based on payment terms # Delivery Note row += [self.voucher_details.get(gle.voucher_no, {}).get("delivery_note")] # customer territory / supplier group if args.get("party_type") == "Customer": - row += [self.get_territory(gle.party), self.get_customer_group(gle.party)] + row += [self.get_territory(gle.party), self.get_customer_group(gle.party), + self.voucher_details.get(gle.voucher_no, {}).get("sales_person")] if args.get("party_type") == "Supplier": row += [self.get_supplier_group(gle.party)] From 0866b2b75a882d88743e550203f64380f34bb9b1 Mon Sep 17 00:00:00 2001 From: Nabin Hait Date: Thu, 20 Dec 2018 14:11:20 +0530 Subject: [PATCH 24/25] Update accounts_receivable.py --- .../accounts/report/accounts_receivable/accounts_receivable.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/erpnext/accounts/report/accounts_receivable/accounts_receivable.py b/erpnext/accounts/report/accounts_receivable/accounts_receivable.py index a084ae986c..121d5b0213 100755 --- a/erpnext/accounts/report/accounts_receivable/accounts_receivable.py +++ b/erpnext/accounts/report/accounts_receivable/accounts_receivable.py @@ -545,7 +545,7 @@ class ReceivablePayableReport(object): where si.name = ps.parent and si.docstatus = 1 and si.company = '%s' and si.name in (%s) order by ps.due_date - """ % (self.filters.company, ','.join(['%s'] *len(voucher_nos))), + """ % (frappe.db.escape(self.filters.company), ','.join(['%s'] *len(voucher_nos))), (tuple(voucher_nos)), as_dict = 1) for d in payment_terms_details: From 7067727c0c8a776e95fea482666c9debeab10742 Mon Sep 17 00:00:00 2001 From: Frappe Bot Date: Fri, 21 Dec 2018 05:46:22 +0000 Subject: [PATCH 25/25] bumped to version 11.0.3-beta.31 --- erpnext/hooks.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/erpnext/hooks.py b/erpnext/hooks.py index cf8c06d700..53ec3d6e09 100644 --- a/erpnext/hooks.py +++ b/erpnext/hooks.py @@ -12,7 +12,7 @@ app_license = "GNU General Public License (v3)" source_link = "https://github.com/frappe/erpnext" develop_version = '12.x.x-develop' -staging_version = '11.0.3-beta.30' +staging_version = '11.0.3-beta.31' error_report_email = "support@erpnext.com"