From 7a6f0489284d0dc739fb3458ec0dbb3d682d10e5 Mon Sep 17 00:00:00 2001 From: Neil Trini Lasrado Date: Mon, 24 Aug 2015 14:37:17 +0530 Subject: [PATCH 01/21] Fixed issue while creating item variants with decimal values (precision error) --- erpnext/stock/doctype/item/item.py | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/erpnext/stock/doctype/item/item.py b/erpnext/stock/doctype/item/item.py index f9b41f1657..379da18934 100644 --- a/erpnext/stock/doctype/item/item.py +++ b/erpnext/stock/doctype/item/item.py @@ -516,9 +516,6 @@ def validate_item_variant_attributes(item, args): numeric_attributes = frappe._dict((t.name, t) for t in frappe.get_list("Item Attribute", filters={"numeric_values":1, "name": ["in", args.keys()]}, fields=["name", "from_range", "to_range", "increment"])) - template_item = frappe.get_doc("Item", item) - template_item_attributes = frappe._dict((d.attribute, d) for d in template_item.attributes) - for attribute, value in args.items(): if attribute in numeric_attributes: @@ -531,10 +528,17 @@ def validate_item_variant_attributes(item, args): if increment == 0: # defensive validation to prevent ZeroDivisionError frappe.throw(_("Increment for Attribute {0} cannot be 0").format(attribute)) + + is_in_range = from_range <= flt(value) <= to_range + precision = len(cstr(increment).split(".")[-1].rstrip("0")) + #avoid precision error by rounding the remainder + remainder = flt((flt(value) - from_range) % increment, precision) + is_incremental = remainder==0 or remainder==0 or remainder==increment - if not ( (from_range <= flt(value) <= to_range) and (flt(value) - from_range) % increment == 0 ): - frappe.throw(_("Value for Attribute {0} must be within the range of {1} to {2} in the increments of {3}").format(attribute, from_range, to_range, increment), InvalidItemAttributeValueError) + if not (is_in_range and is_incremental): + frappe.throw(_("Value for Attribute {0} must be within the range of {1} to {2} in the increments of {3}")\ + .format(attribute, from_range, to_range, increment), InvalidItemAttributeValueError) elif value not in attribute_values[attribute]: frappe.throw(_("Value {0} for Attribute {1} does not exist in the list of valid Item Attribute Values").format( From 4c614bd59a6f34743545004d6ff49e9098adbc7f Mon Sep 17 00:00:00 2001 From: Neil Trini Lasrado Date: Mon, 24 Aug 2015 15:12:34 +0530 Subject: [PATCH 02/21] Fixed validation for numeric variants to check with values from template instead of master --- erpnext/stock/doctype/item/item.py | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/erpnext/stock/doctype/item/item.py b/erpnext/stock/doctype/item/item.py index 379da18934..659fb1b5f5 100644 --- a/erpnext/stock/doctype/item/item.py +++ b/erpnext/stock/doctype/item/item.py @@ -513,9 +513,10 @@ def validate_item_variant_attributes(item, args): filters={"parent": ["in", args.keys()]}): (attribute_values.setdefault(t.parent, [])).append(t.attribute_value) - numeric_attributes = frappe._dict((t.name, t) for t in frappe.get_list("Item Attribute", filters={"numeric_values":1, - "name": ["in", args.keys()]}, fields=["name", "from_range", "to_range", "increment"])) - + numeric_attributes = frappe._dict((t.attribute, t) for t in \ + frappe.db.sql("""select attribute, from_range, to_range, increment from `tabItem Variant Attribute` + where parent = %s and numeric_values=1""", (item), as_dict=1)) + for attribute, value in args.items(): if attribute in numeric_attributes: From 72e4cdcb251a6e4b7905abfbb3e52bce5c21fa8d Mon Sep 17 00:00:00 2001 From: Neil Trini Lasrado Date: Fri, 21 Aug 2015 18:06:15 +0530 Subject: [PATCH 03/21] Added default WIP Warehouse and FG Warehouse to Manufacturing Settings Fetch default WIP Warehouse and FG Warehouse on load of Production Order --- .../manufacturing_settings.json | 409 +++++++++++++----- .../production_order/production_order.js | 15 +- .../production_order/production_order.py | 6 + 3 files changed, 323 insertions(+), 107 deletions(-) diff --git a/erpnext/manufacturing/doctype/manufacturing_settings/manufacturing_settings.json b/erpnext/manufacturing/doctype/manufacturing_settings/manufacturing_settings.json index 8be16b2153..e2da87948d 100644 --- a/erpnext/manufacturing/doctype/manufacturing_settings/manufacturing_settings.json +++ b/erpnext/manufacturing/doctype/manufacturing_settings/manufacturing_settings.json @@ -1,123 +1,320 @@ { - "allow_copy": 0, - "allow_import": 0, - "allow_rename": 0, - "creation": "2014-11-27 14:12:07.542534", - "custom": 0, - "docstatus": 0, - "doctype": "DocType", - "document_type": "Master", + "allow_copy": 0, + "allow_import": 0, + "allow_rename": 0, + "creation": "2014-11-27 14:12:07.542534", + "custom": 0, + "docstatus": 0, + "doctype": "DocType", + "document_type": "Document", "fields": [ { - "fieldname": "capacity_planning", - "fieldtype": "Section Break", - "label": "Capacity Planning", - "permlevel": 0, - "precision": "" - }, + "allow_on_submit": 0, + "fieldname": "capacity_planning", + "fieldtype": "Section Break", + "hidden": 0, + "ignore_user_permissions": 0, + "in_filter": 0, + "in_list_view": 0, + "label": "Capacity Planning", + "no_copy": 0, + "permlevel": 0, + "precision": "", + "print_hide": 0, + "read_only": 0, + "report_hide": 0, + "reqd": 0, + "search_index": 0, + "set_only_once": 0, + "unique": 0 + }, { - "description": "Disables creation of time logs against Production Orders.\nOperations shall not be tracked against Production Order", - "fieldname": "disable_capacity_planning", - "fieldtype": "Check", - "label": "Disable Capacity Planning and Time Tracking", - "permlevel": 0, - "precision": "" - }, + "allow_on_submit": 0, + "description": "Disables creation of time logs against Production Orders.\nOperations shall not be tracked against Production Order", + "fieldname": "disable_capacity_planning", + "fieldtype": "Check", + "hidden": 0, + "ignore_user_permissions": 0, + "in_filter": 0, + "in_list_view": 0, + "label": "Disable Capacity Planning and Time Tracking", + "no_copy": 0, + "permlevel": 0, + "precision": "", + "print_hide": 0, + "read_only": 0, + "report_hide": 0, + "reqd": 0, + "search_index": 0, + "set_only_once": 0, + "unique": 0 + }, { - "description": "Plan time logs outside Workstation Working Hours.", - "fieldname": "allow_overtime", - "fieldtype": "Check", - "label": "Allow Overtime", - "permlevel": 0, - "precision": "" - }, + "allow_on_submit": 0, + "description": "Plan time logs outside Workstation Working Hours.", + "fieldname": "allow_overtime", + "fieldtype": "Check", + "hidden": 0, + "ignore_user_permissions": 0, + "in_filter": 0, + "in_list_view": 0, + "label": "Allow Overtime", + "no_copy": 0, + "permlevel": 0, + "precision": "", + "print_hide": 0, + "read_only": 0, + "report_hide": 0, + "reqd": 0, + "search_index": 0, + "set_only_once": 0, + "unique": 0 + }, { - "default": "", - "fieldname": "allow_production_on_holidays", - "fieldtype": "Check", - "in_list_view": 1, - "label": "Allow Production on Holidays", - "options": "", - "permlevel": 0, - "precision": "" - }, + "allow_on_submit": 0, + "default": "", + "fieldname": "allow_production_on_holidays", + "fieldtype": "Check", + "hidden": 0, + "ignore_user_permissions": 0, + "in_filter": 0, + "in_list_view": 1, + "label": "Allow Production on Holidays", + "no_copy": 0, + "options": "", + "permlevel": 0, + "precision": "", + "print_hide": 0, + "read_only": 0, + "report_hide": 0, + "reqd": 0, + "search_index": 0, + "set_only_once": 0, + "unique": 0 + }, { - "default": "BOM", - "fieldname": "backflush_raw_materials_based_on", - "fieldtype": "Select", - "label": "Backflush Raw Materials Based On", - "options": "BOM\nMaterial Transferred for Manufacture", - "permlevel": 0, - "precision": "" - }, + "allow_on_submit": 0, + "fieldname": "column_break_3", + "fieldtype": "Column Break", + "hidden": 0, + "ignore_user_permissions": 0, + "in_filter": 0, + "in_list_view": 0, + "no_copy": 0, + "permlevel": 0, + "precision": "", + "print_hide": 0, + "read_only": 0, + "report_hide": 0, + "reqd": 0, + "search_index": 0, + "set_only_once": 0, + "unique": 0 + }, { - "fieldname": "column_break_3", - "fieldtype": "Column Break", - "permlevel": 0, - "precision": "" - }, + "allow_on_submit": 0, + "default": "30", + "description": "Try planning operations for X days in advance.", + "fieldname": "capacity_planning_for_days", + "fieldtype": "Int", + "hidden": 0, + "ignore_user_permissions": 0, + "in_filter": 0, + "in_list_view": 0, + "label": "Capacity Planning For (Days)", + "no_copy": 0, + "permlevel": 0, + "precision": "", + "print_hide": 0, + "read_only": 0, + "report_hide": 0, + "reqd": 0, + "search_index": 0, + "set_only_once": 0, + "unique": 0 + }, { - "default": "30", - "description": "Try planning operations for X days in advance.", - "fieldname": "capacity_planning_for_days", - "fieldtype": "Int", - "label": "Capacity Planning For (Days)", - "permlevel": 0, - "precision": "" - }, + "allow_on_submit": 0, + "description": "Default 10 mins", + "fieldname": "mins_between_operations", + "fieldtype": "Int", + "hidden": 0, + "ignore_user_permissions": 0, + "in_filter": 0, + "in_list_view": 0, + "label": "Time Between Operations (in mins)", + "no_copy": 0, + "permlevel": 0, + "precision": "", + "print_hide": 0, + "read_only": 0, + "report_hide": 0, + "reqd": 0, + "search_index": 0, + "set_only_once": 0, + "unique": 0 + }, { - "description": "Default 10 mins", - "fieldname": "mins_between_operations", - "fieldtype": "Int", - "label": "Time Between Operations (in mins)", - "permlevel": 0, - "precision": "" - }, + "allow_on_submit": 0, + "fieldname": "section_break_6", + "fieldtype": "Section Break", + "hidden": 0, + "ignore_user_permissions": 0, + "in_filter": 0, + "in_list_view": 0, + "no_copy": 0, + "permlevel": 0, + "precision": "", + "print_hide": 0, + "read_only": 0, + "report_hide": 0, + "reqd": 0, + "search_index": 0, + "set_only_once": 0, + "unique": 0 + }, { - "fieldname": "over_production_allowance_percentage", - "fieldtype": "Percent", - "label": "Over Production Allowance Percentage", - "permlevel": 0, - "precision": "" + "allow_on_submit": 0, + "fieldname": "over_production_allowance_percentage", + "fieldtype": "Percent", + "hidden": 0, + "ignore_user_permissions": 0, + "in_filter": 0, + "in_list_view": 0, + "label": "Over Production Allowance Percentage", + "no_copy": 0, + "permlevel": 0, + "precision": "", + "print_hide": 0, + "read_only": 0, + "report_hide": 0, + "reqd": 0, + "search_index": 0, + "set_only_once": 0, + "unique": 0 + }, + { + "allow_on_submit": 0, + "default": "BOM", + "fieldname": "backflush_raw_materials_based_on", + "fieldtype": "Select", + "hidden": 0, + "ignore_user_permissions": 0, + "in_filter": 0, + "in_list_view": 0, + "label": "Backflush Raw Materials Based On", + "no_copy": 0, + "options": "BOM\nMaterial Transferred for Manufacture", + "permlevel": 0, + "precision": "", + "print_hide": 0, + "read_only": 0, + "report_hide": 0, + "reqd": 0, + "search_index": 0, + "set_only_once": 0, + "unique": 0 + }, + { + "allow_on_submit": 0, + "fieldname": "column_break_11", + "fieldtype": "Column Break", + "hidden": 0, + "ignore_user_permissions": 0, + "in_filter": 0, + "in_list_view": 0, + "no_copy": 0, + "permlevel": 0, + "precision": "", + "print_hide": 0, + "read_only": 0, + "report_hide": 0, + "reqd": 0, + "search_index": 0, + "set_only_once": 0, + "unique": 0 + }, + { + "allow_on_submit": 0, + "fieldname": "default_wip_warehouse", + "fieldtype": "Link", + "hidden": 0, + "ignore_user_permissions": 0, + "in_filter": 0, + "in_list_view": 0, + "label": "Default Work In Progress Warehouse", + "no_copy": 0, + "options": "Warehouse", + "permlevel": 0, + "precision": "", + "print_hide": 0, + "read_only": 0, + "report_hide": 0, + "reqd": 0, + "search_index": 0, + "set_only_once": 0, + "unique": 0 + }, + { + "allow_on_submit": 0, + "fieldname": "default_fg_warehouse", + "fieldtype": "Link", + "hidden": 0, + "ignore_user_permissions": 0, + "in_filter": 0, + "in_list_view": 0, + "label": "Default Finished Goods Warehouse", + "no_copy": 0, + "options": "Warehouse", + "permlevel": 0, + "precision": "", + "print_hide": 0, + "read_only": 0, + "report_hide": 0, + "reqd": 0, + "search_index": 0, + "set_only_once": 0, + "unique": 0 } - ], - "hide_heading": 0, - "hide_toolbar": 0, - "icon": "icon-wrench", - "in_create": 0, - "in_dialog": 0, - "is_submittable": 0, - "issingle": 1, - "istable": 0, - "modified": "2015-08-12 08:12:33.889753", - "modified_by": "Administrator", - "module": "Manufacturing", - "name": "Manufacturing Settings", - "name_case": "", - "owner": "Administrator", + ], + "hide_heading": 0, + "hide_toolbar": 0, + "icon": "icon-wrench", + "in_create": 0, + "in_dialog": 0, + "is_submittable": 0, + "issingle": 1, + "istable": 0, + "modified": "2015-08-21 08:27:03.794133", + "modified_by": "Administrator", + "module": "Manufacturing", + "name": "Manufacturing Settings", + "name_case": "", + "owner": "Administrator", "permissions": [ { - "amend": 0, - "apply_user_permissions": 0, - "cancel": 0, - "create": 1, - "delete": 0, - "email": 0, - "export": 0, - "import": 0, - "permlevel": 0, - "print": 0, - "read": 1, - "report": 0, - "role": "Manufacturing Manager", - "set_user_permissions": 0, - "share": 1, - "submit": 0, + "amend": 0, + "apply_user_permissions": 0, + "cancel": 0, + "create": 1, + "delete": 0, + "email": 0, + "export": 0, + "if_owner": 0, + "import": 0, + "permlevel": 0, + "print": 0, + "read": 1, + "report": 0, + "role": "Manufacturing Manager", + "set_user_permissions": 0, + "share": 1, + "submit": 0, "write": 1 } - ], - "read_only": 0, - "read_only_onload": 0, - "sort_field": "modified", + ], + "read_only": 0, + "read_only_onload": 0, + "sort_field": "modified", "sort_order": "DESC" -} +} \ No newline at end of file diff --git a/erpnext/manufacturing/doctype/production_order/production_order.js b/erpnext/manufacturing/doctype/production_order/production_order.js index 04fcaa5c01..cf02a3a747 100644 --- a/erpnext/manufacturing/doctype/production_order/production_order.js +++ b/erpnext/manufacturing/doctype/production_order/production_order.js @@ -17,6 +17,7 @@ frappe.ui.form.on("Production Order", "onload", function(frm) { erpnext.production_order.set_custom_buttons(frm); erpnext.production_order.setup_company_filter(frm); erpnext.production_order.setup_bom_filter(frm); + erpnext.production_order.set_default_warehouse(frm); }); frappe.ui.form.on("Production Order", "refresh", function(frm) { @@ -138,10 +139,22 @@ erpnext.production_order = { } } else msgprint(__("Please enter Production Item first")); }); + }, + + set_default_warehouse: function(frm) { + frappe.call({ + method: "erpnext.manufacturing.doctype.production_order.production_order.get_default_warehouse", + + callback: function(r) { + if(!r.exe) { + frm.set_value("wip_warehouse", r.message[0]); + frm.set_value("fg_warehouse", r.message[1]) + } + } + }); } } - $.extend(cur_frm.cscript, { before_submit: function() { cur_frm.toggle_reqd(["fg_warehouse", "wip_warehouse"], true); diff --git a/erpnext/manufacturing/doctype/production_order/production_order.py b/erpnext/manufacturing/doctype/production_order/production_order.py index 2039d93659..182f306c11 100644 --- a/erpnext/manufacturing/doctype/production_order/production_order.py +++ b/erpnext/manufacturing/doctype/production_order/production_order.py @@ -422,3 +422,9 @@ def make_time_log(name, operation, from_time=None, to_time=None, qty=None, proj if from_time and to_time : time_log.calculate_total_hours() return time_log + +@frappe.whitelist() +def get_default_warehouse(): + wip_warehouse = frappe.db.get_single_value("Manufacturing Settings", "default_wip_warehouse") + fg_warehouse = frappe.db.get_single_value("Manufacturing Settings", "default_fg_warehouse") + return wip_warehouse, fg_warehouse \ No newline at end of file From 75d90b1c00b039e03fa848e26f5ad029c4486cdb Mon Sep 17 00:00:00 2001 From: Neil Trini Lasrado Date: Fri, 21 Aug 2015 18:22:43 +0530 Subject: [PATCH 04/21] Fixed Produciton Planning Tool --- .../production_planning_tool/production_planning_tool.py | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/erpnext/manufacturing/doctype/production_planning_tool/production_planning_tool.py b/erpnext/manufacturing/doctype/production_planning_tool/production_planning_tool.py index e302cc782b..3f08b1beae 100644 --- a/erpnext/manufacturing/doctype/production_planning_tool/production_planning_tool.py +++ b/erpnext/manufacturing/doctype/production_planning_tool/production_planning_tool.py @@ -200,14 +200,16 @@ class ProductionPlanningTool(Document): def create_production_order(self, items): """Create production order. Called from Production Planning Tool""" - from erpnext.manufacturing.doctype.production_order.production_order import OverProductionError - + from erpnext.manufacturing.doctype.production_order.production_order import OverProductionError, get_default_warehouse + warehouse = get_default_warehouse() pro_list = [] for key in items: pro = frappe.new_doc("Production Order") pro.update(items[key]) pro.set_production_order_operations() - + if warehouse: + pro.wip_warehouse = warehouse[0] + pro.fg_warehouse = warehouse[1] frappe.flags.mute_messages = True try: pro.insert() From 92a3dbb5d335929b05600430ee6d1568df226575 Mon Sep 17 00:00:00 2001 From: Neil Trini Lasrado Date: Mon, 24 Aug 2015 15:52:27 +0530 Subject: [PATCH 05/21] Fixes in Default Warehouse --- .../doctype/production_order/production_order.js | 6 +++--- .../doctype/production_order/production_order.py | 2 +- .../production_planning_tool/production_planning_tool.py | 7 ++++--- 3 files changed, 8 insertions(+), 7 deletions(-) diff --git a/erpnext/manufacturing/doctype/production_order/production_order.js b/erpnext/manufacturing/doctype/production_order/production_order.js index cf02a3a747..00eac9ad7a 100644 --- a/erpnext/manufacturing/doctype/production_order/production_order.js +++ b/erpnext/manufacturing/doctype/production_order/production_order.js @@ -12,12 +12,12 @@ frappe.ui.form.on("Production Order", "onload", function(frm) { "actual_start_date": "", "actual_end_date": "" }); + erpnext.production_order.set_default_warehouse(frm); } erpnext.production_order.set_custom_buttons(frm); erpnext.production_order.setup_company_filter(frm); erpnext.production_order.setup_bom_filter(frm); - erpnext.production_order.set_default_warehouse(frm); }); frappe.ui.form.on("Production Order", "refresh", function(frm) { @@ -147,8 +147,8 @@ erpnext.production_order = { callback: function(r) { if(!r.exe) { - frm.set_value("wip_warehouse", r.message[0]); - frm.set_value("fg_warehouse", r.message[1]) + frm.set_value("wip_warehouse", r.message.wip_warehouse); + frm.set_value("fg_warehouse", r.message.fg_warehouse) } } }); diff --git a/erpnext/manufacturing/doctype/production_order/production_order.py b/erpnext/manufacturing/doctype/production_order/production_order.py index 182f306c11..6299736d95 100644 --- a/erpnext/manufacturing/doctype/production_order/production_order.py +++ b/erpnext/manufacturing/doctype/production_order/production_order.py @@ -427,4 +427,4 @@ def make_time_log(name, operation, from_time=None, to_time=None, qty=None, proj def get_default_warehouse(): wip_warehouse = frappe.db.get_single_value("Manufacturing Settings", "default_wip_warehouse") fg_warehouse = frappe.db.get_single_value("Manufacturing Settings", "default_fg_warehouse") - return wip_warehouse, fg_warehouse \ No newline at end of file + return {"wip_warehouse": wip_warehouse, "fg_warehouse": fg_warehouse} \ No newline at end of file diff --git a/erpnext/manufacturing/doctype/production_planning_tool/production_planning_tool.py b/erpnext/manufacturing/doctype/production_planning_tool/production_planning_tool.py index 3f08b1beae..254b5a58fa 100644 --- a/erpnext/manufacturing/doctype/production_planning_tool/production_planning_tool.py +++ b/erpnext/manufacturing/doctype/production_planning_tool/production_planning_tool.py @@ -208,9 +208,11 @@ class ProductionPlanningTool(Document): pro.update(items[key]) pro.set_production_order_operations() if warehouse: - pro.wip_warehouse = warehouse[0] - pro.fg_warehouse = warehouse[1] + pro.wip_warehouse = warehouse.get('wip_warehouse') + if not pro.fg_warehouse: + pro.fg_warehouse = warehouse.get('fg_warehouse') frappe.flags.mute_messages = True + try: pro.insert() pro_list.append(pro.name) @@ -218,7 +220,6 @@ class ProductionPlanningTool(Document): pass frappe.flags.mute_messages = False - return pro_list def download_raw_materials(self): From b69eb84936d2389118a293f84c9d50ab6cd0ea33 Mon Sep 17 00:00:00 2001 From: Nabin Hait Date: Mon, 24 Aug 2015 16:55:02 +0530 Subject: [PATCH 06/21] [fix] Stock Entry additional costs patch fix for v4 accounts --- .../patches/v5_4/stock_entry_additional_costs.py | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/erpnext/patches/v5_4/stock_entry_additional_costs.py b/erpnext/patches/v5_4/stock_entry_additional_costs.py index 325d6cf4a4..3a98deb918 100644 --- a/erpnext/patches/v5_4/stock_entry_additional_costs.py +++ b/erpnext/patches/v5_4/stock_entry_additional_costs.py @@ -10,12 +10,6 @@ def execute(): frappe.reload_doctype("Stock Entry Detail") frappe.reload_doctype("Landed Cost Taxes and Charges") - frappe.db.sql("""update `tabStock Entry Detail` sed, `tabStock Entry` se - set sed.valuation_rate=sed.incoming_rate, sed.basic_rate=sed.incoming_rate, sed.basic_amount=sed.amount - where sed.parent = se.name - and (se.purpose not in ('Manufacture', 'Repack') or ifnull(additional_operating_cost, 0)=0) - """) - stock_entry_db_columns = frappe.db.get_table_columns("Stock Entry") if "additional_operating_cost" in stock_entry_db_columns: operating_cost_fieldname = "additional_operating_cost" @@ -25,6 +19,13 @@ def execute(): return + frappe.db.sql("""update `tabStock Entry Detail` sed, `tabStock Entry` se + set sed.valuation_rate=sed.incoming_rate, sed.basic_rate=sed.incoming_rate, sed.basic_amount=sed.amount + where sed.parent = se.name + and (se.purpose not in ('Manufacture', 'Repack') or ifnull({0}, 0)=0) + """.format(operating_cost_fieldname)) + + stock_entries = frappe.db.sql_list("""select name from `tabStock Entry` where purpose in ('Manufacture', 'Repack') and ifnull({0}, 0)!=0 and docstatus < 2""".format(operating_cost_fieldname)) From db189d7f19272723dcdcc277c327c19a75482470 Mon Sep 17 00:00:00 2001 From: Neil Trini Lasrado Date: Mon, 24 Aug 2015 16:59:24 +0530 Subject: [PATCH 07/21] Fixed test case for Item Variants --- erpnext/stock/doctype/item/test_item.py | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/erpnext/stock/doctype/item/test_item.py b/erpnext/stock/doctype/item/test_item.py index f7c0f40efa..916101516f 100644 --- a/erpnext/stock/doctype/item/test_item.py +++ b/erpnext/stock/doctype/item/test_item.py @@ -6,9 +6,8 @@ import unittest import frappe from frappe.test_runner import make_test_records -from erpnext.stock.doctype.item.item import (WarehouseNotSet, ItemTemplateCannotHaveStock, create_variant, +from erpnext.stock.doctype.item.item import (WarehouseNotSet, create_variant, ItemVariantExistsError, InvalidItemAttributeValueError) -from erpnext.stock.doctype.stock_entry.test_stock_entry import make_stock_entry test_ignore = ["BOM"] test_dependencies = ["Warehouse"] @@ -129,8 +128,16 @@ class TestItem(unittest.TestCase): # make template item make_item("_Test Numeric Template Item", { "attributes": [ - {"attribute": "Test Size"}, - {"attribute": "Test Item Length"} + { + "attribute": "Test Size" + }, + { + "attribute": "Test Item Length", + "numeric_values": 1, + "from_range": 0.0, + "to_range": 100.0, + "increment": 0.5 + } ], "default_warehouse": "_Test Warehouse - _TC" }) From 3a990d946d503f17243658f42df0f2cf463cda79 Mon Sep 17 00:00:00 2001 From: Nabin Hait Date: Mon, 24 Aug 2015 17:21:01 +0530 Subject: [PATCH 08/21] [fix] In general ledger report, consider cost center in group by voucher --- erpnext/accounts/report/general_ledger/general_ledger.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/erpnext/accounts/report/general_ledger/general_ledger.py b/erpnext/accounts/report/general_ledger/general_ledger.py index 35c839f786..1cc9f4fc35 100644 --- a/erpnext/accounts/report/general_ledger/general_ledger.py +++ b/erpnext/accounts/report/general_ledger/general_ledger.py @@ -61,7 +61,7 @@ def get_result(filters, account_details): return result def get_gl_entries(filters): - group_by_condition = "group by voucher_type, voucher_no, account" \ + group_by_condition = "group by voucher_type, voucher_no, account, cost_center" \ if filters.get("group_by_voucher") else "group by name" gl_entries = frappe.db.sql("""select posting_date, account, party_type, party, From a7c013c0301751fb7a81463ddd148ba2de8a4ec4 Mon Sep 17 00:00:00 2001 From: Nabin Hait Date: Mon, 24 Aug 2015 18:43:09 +0530 Subject: [PATCH 09/21] [fix] Print Delivery Note without amount --- erpnext/stock/doctype/delivery_note/delivery_note.json | 6 +++--- erpnext/stock/doctype/delivery_note/delivery_note.py | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/erpnext/stock/doctype/delivery_note/delivery_note.json b/erpnext/stock/doctype/delivery_note/delivery_note.json index 7afac6de96..15d5c3e27e 100644 --- a/erpnext/stock/doctype/delivery_note/delivery_note.json +++ b/erpnext/stock/doctype/delivery_note/delivery_note.json @@ -7,7 +7,7 @@ "custom": 0, "docstatus": 0, "doctype": "DocType", - "document_type": "Transaction", + "document_type": "Document", "fields": [ { "allow_on_submit": 0, @@ -1080,7 +1080,7 @@ "options": "\nGrand Total\nNet Total", "permlevel": 0, "precision": "", - "print_hide": 0, + "print_hide": 1, "read_only": 0, "report_hide": 0, "reqd": 0, @@ -2179,7 +2179,7 @@ "is_submittable": 1, "issingle": 0, "istable": 0, - "modified": "2015-08-04 11:56:59.782517", + "modified": "2015-08-24 09:09:59.298127", "modified_by": "Administrator", "module": "Stock", "name": "Delivery Note", diff --git a/erpnext/stock/doctype/delivery_note/delivery_note.py b/erpnext/stock/doctype/delivery_note/delivery_note.py index 5e11962ea5..6435834518 100644 --- a/erpnext/stock/doctype/delivery_note/delivery_note.py +++ b/erpnext/stock/doctype/delivery_note/delivery_note.py @@ -66,7 +66,7 @@ class DeliveryNote(SellingController): item_meta = frappe.get_meta("Delivery Note Item") print_hide_fields = { - "parent": ["grand_total", "rounded_total", "in_words", "currency", "net_total"], + "parent": ["grand_total", "rounded_total", "in_words", "currency", "total", "taxes"], "items": ["rate", "amount", "price_list_rate", "discount_percentage"] } From ddd79f43d2480839b8edecc017559a43298b03c9 Mon Sep 17 00:00:00 2001 From: Rushabh Mehta Date: Tue, 25 Aug 2015 14:03:43 +0530 Subject: [PATCH 10/21] [fix] [hot] erpnext contact page --- erpnext/templates/utils.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/erpnext/templates/utils.py b/erpnext/templates/utils.py index b0e8ae21e0..6f4f4ee3ad 100644 --- a/erpnext/templates/utils.py +++ b/erpnext/templates/utils.py @@ -21,3 +21,5 @@ def send_message(subject="Website Query", message="", sender="", status="Open"): "sent_or_received": "Received" }) comm.insert(ignore_permissions=True) + + return "okay" From 1f94fa25a86b7f9b744267b58c3415cbc7732f90 Mon Sep 17 00:00:00 2001 From: Nabin Hait Date: Mon, 24 Aug 2015 14:32:38 +0530 Subject: [PATCH 11/21] Update delivered / ordered qty in sales/purchase order from return entry Reserved Qty logic cleaned up --- .../doctype/sales_invoice/sales_invoice.py | 50 ++++++----------- .../doctype/purchase_order/purchase_order.py | 19 ++----- .../controllers/sales_and_purchase_return.py | 17 +++++- erpnext/controllers/selling_controller.py | 29 +--------- erpnext/controllers/stock_controller.py | 55 +++++++++++++------ .../doctype/sales_order/sales_order.py | 45 ++++++++------- .../doctype/delivery_note/delivery_note.py | 30 ++-------- .../material_request/material_request.py | 19 ++----- .../purchase_receipt/purchase_receipt.py | 16 +++--- 9 files changed, 117 insertions(+), 163 deletions(-) diff --git a/erpnext/accounts/doctype/sales_invoice/sales_invoice.py b/erpnext/accounts/doctype/sales_invoice/sales_invoice.py index f82590a609..20c766aaa9 100644 --- a/erpnext/accounts/doctype/sales_invoice/sales_invoice.py +++ b/erpnext/accounts/doctype/sales_invoice/sales_invoice.py @@ -81,9 +81,13 @@ class SalesInvoice(SellingController): self.check_prev_docstatus() + if self.is_return: + self.status_updater = [] + + self.update_status_updater_args() + self.update_prevdoc_status() + if not self.is_return: - self.update_status_updater_args() - self.update_prevdoc_status() self.update_billing_status_for_zero_amount_refdoc("Sales Order") self.check_credit_limit() @@ -107,9 +111,13 @@ class SalesInvoice(SellingController): from erpnext.accounts.utils import remove_against_link_from_jv remove_against_link_from_jv(self.doctype, self.name) + if self.is_return: + self.status_updater = [] + + self.update_status_updater_args() + self.update_prevdoc_status() + if not self.is_return: - self.update_status_updater_args() - self.update_prevdoc_status() self.update_billing_status_for_zero_amount_refdoc("Sales Order") self.validate_c_form_on_cancel() @@ -294,8 +302,6 @@ class SalesInvoice(SellingController): def so_dn_required(self): """check in manage account if sales order / delivery note required or not.""" - if self.is_return: - return dic = {'Sales Order':'so_required','Delivery Note':'dn_required'} for i in dic: if frappe.db.get_value('Selling Settings', None, dic[i]) == 'Yes': @@ -408,35 +414,11 @@ class SalesInvoice(SellingController): def check_prev_docstatus(self): for d in self.get('items'): - if d.sales_order: - submitted = frappe.db.sql("""select name from `tabSales Order` - where docstatus = 1 and name = %s""", d.sales_order) - if not submitted: - frappe.throw(_("Sales Order {0} is not submitted").format(d.sales_order)) + if d.sales_order and frappe.db.get_value("Sales Order", d.sales_order, "docstatus") != 1: + frappe.throw(_("Sales Order {0} is not submitted").format(d.sales_order)) - if d.delivery_note: - submitted = frappe.db.sql("""select name from `tabDelivery Note` - where docstatus = 1 and name = %s""", d.delivery_note) - if not submitted: - throw(_("Delivery Note {0} is not submitted").format(d.delivery_note)) - - def update_stock_ledger(self): - sl_entries = [] - for d in self.get_item_list(): - if frappe.db.get_value("Item", d.item_code, "is_stock_item") == 1 and d.warehouse and flt(d['qty']): - self.update_reserved_qty(d) - - incoming_rate = 0 - if cint(self.is_return) and self.return_against and self.docstatus==1: - incoming_rate = self.get_incoming_rate_for_sales_return(d.item_code, - self.return_against) - - sl_entries.append(self.get_sl_entries(d, { - "actual_qty": -1*flt(d.qty), - "stock_uom": frappe.db.get_value("Item", d.item_code, "stock_uom"), - "incoming_rate": incoming_rate - })) - self.make_sl_entries(sl_entries) + if d.delivery_note and frappe.db.get_value("Delivery Note", d.delivery_note, "docstatus") != 1: + throw(_("Delivery Note {0} is not submitted").format(d.delivery_note)) def make_gl_entries(self, repost_future_gle=True): gl_entries = self.get_gl_entries() diff --git a/erpnext/buying/doctype/purchase_order/purchase_order.py b/erpnext/buying/doctype/purchase_order/purchase_order.py index 9887ddb416..b1c0a58a77 100644 --- a/erpnext/buying/doctype/purchase_order/purchase_order.py +++ b/erpnext/buying/doctype/purchase_order/purchase_order.py @@ -9,6 +9,7 @@ from frappe import msgprint, _, throw from frappe.model.mapper import get_mapped_doc from erpnext.controllers.buying_controller import BuyingController from erpnext.stock.doctype.item.item import get_last_purchase_details +from erpnext.utilities.repost_stock import update_bin_qty, get_ordered_qty form_grid_templates = { @@ -136,20 +137,6 @@ class PurchaseOrder(BuyingController): def update_ordered_qty(self, po_item_rows=None): """update requested qty (before ordered_qty is updated)""" - from erpnext.stock.utils import get_bin - - def _update_ordered_qty(item_code, warehouse): - ordered_qty = frappe.db.sql(""" - select sum((po_item.qty - ifnull(po_item.received_qty, 0))*po_item.conversion_factor) - from `tabPurchase Order Item` po_item, `tabPurchase Order` po - where po_item.item_code=%s and po_item.warehouse=%s - and po_item.qty > ifnull(po_item.received_qty, 0) and po_item.parent=po.name - and po.status!='Stopped' and po.docstatus=1""", (item_code, warehouse)) - - bin_doc = get_bin(item_code, warehouse) - bin_doc.ordered_qty = flt(ordered_qty[0][0]) if ordered_qty else 0 - bin_doc.save() - item_wh_list = [] for d in self.get("items"): if (not po_item_rows or d.name in po_item_rows) and [d.item_code, d.warehouse] not in item_wh_list \ @@ -157,7 +144,9 @@ class PurchaseOrder(BuyingController): item_wh_list.append([d.item_code, d.warehouse]) for item_code, warehouse in item_wh_list: - _update_ordered_qty(item_code, warehouse) + update_bin_qty(item_code, warehouse, { + "ordered_qty": get_ordered_qty(item_code, warehouse) + }) def check_modified_date(self): mod_db = frappe.db.sql("select modified from `tabPurchase Order` where name = %s", diff --git a/erpnext/controllers/sales_and_purchase_return.py b/erpnext/controllers/sales_and_purchase_return.py index f429c67983..2e4ecaa8c1 100644 --- a/erpnext/controllers/sales_and_purchase_return.py +++ b/erpnext/controllers/sales_and_purchase_return.py @@ -137,9 +137,24 @@ def make_return_doc(doctype, source_name, target_doc=None): target_doc.qty = -1* source_doc.qty if doctype == "Purchase Receipt": target_doc.received_qty = -1* source_doc.qty + target_doc.prevdoc_doctype = source_doc.prevdoc_doctype + target_doc.prevdoc_docname = source_doc.prevdoc_docname + target_doc.prevdoc_detail_docname = source_doc.prevdoc_detail_docname elif doctype == "Purchase Invoice": + target_doc.purchase_order = source_doc.purchase_order target_doc.purchase_receipt = source_doc.purchase_receipt + target_doc.po_detail = source_doc.po_detail target_doc.pr_detail = source_doc.pr_detail + elif doctype == "Delivery Note": + target_doc.against_sales_order = source_doc.against_sales_order + target_doc.against_sales_invoice = source_doc.against_sales_invoice + target_doc.so_detail = source_doc.so_detail + target_doc.si_detail = source_doc.si_detail + elif doctype == "Sales Invoice": + target_doc.sales_order = source_doc.sales_order + target_doc.delivery_note = source_doc.delivery_note + target_doc.so_detail = source_doc.so_detail + target_doc.dn_detail = source_doc.dn_detail doclist = get_mapped_doc(doctype, source_name, { doctype: { @@ -152,8 +167,6 @@ def make_return_doc(doctype, source_name, target_doc=None): doctype +" Item": { "doctype": doctype + " Item", "field_map": { - "purchase_order": "purchase_order", - "purchase_receipt": "purchase_receipt", "serial_no": "serial_no", "batch_no": "batch_no" }, diff --git a/erpnext/controllers/selling_controller.py b/erpnext/controllers/selling_controller.py index 9e2bf1d76b..569bb82afe 100644 --- a/erpnext/controllers/selling_controller.py +++ b/erpnext/controllers/selling_controller.py @@ -163,42 +163,17 @@ class SellingController(StockController): def get_item_list(self): il = [] for d in self.get("items"): - reserved_warehouse = "" - reserved_qty_for_main_item = 0 - if d.qty is None: frappe.throw(_("Row {0}: Qty is mandatory").format(d.idx)) - - if self.doctype == "Sales Order": - reserved_warehouse = d.warehouse - if flt(d.qty) > flt(d.delivered_qty): - reserved_qty_for_main_item = flt(d.qty) - flt(d.delivered_qty) - - elif (((self.doctype == "Delivery Note" and d.against_sales_order) - or (self.doctype == "Sales Invoice" and d.sales_order and self.update_stock)) - and not self.is_return): - # if SO qty is 10 and there is tolerance of 20%, then it will allow DN of 12. - # But in this case reserved qty should only be reduced by 10 and not 12 - - already_delivered_qty = self.get_already_delivered_qty(self.name, - d.against_sales_order if self.doctype=="Delivery Note" else d.sales_order, d.so_detail) - so_qty, reserved_warehouse = self.get_so_qty_and_warehouse(d.so_detail) - - if already_delivered_qty + d.qty > so_qty: - reserved_qty_for_main_item = -(so_qty - already_delivered_qty) - else: - reserved_qty_for_main_item = -flt(d.qty) - + if self.has_product_bundle(d.item_code): for p in self.get("packed_items"): if p.parent_detail_docname == d.name and p.parent_item == d.item_code: # the packing details table's qty is already multiplied with parent's qty il.append(frappe._dict({ 'warehouse': p.warehouse, - 'reserved_warehouse': reserved_warehouse, 'item_code': p.item_code, 'qty': flt(p.qty), - 'reserved_qty': (flt(p.qty)/flt(d.qty)) * reserved_qty_for_main_item, 'uom': p.uom, 'batch_no': cstr(p.batch_no).strip(), 'serial_no': cstr(p.serial_no).strip(), @@ -207,10 +182,8 @@ class SellingController(StockController): else: il.append(frappe._dict({ 'warehouse': d.warehouse, - 'reserved_warehouse': reserved_warehouse, 'item_code': d.item_code, 'qty': d.qty, - 'reserved_qty': reserved_qty_for_main_item, 'uom': d.stock_uom, 'stock_uom': d.stock_uom, 'batch_no': cstr(d.get("batch_no")).strip(), diff --git a/erpnext/controllers/stock_controller.py b/erpnext/controllers/stock_controller.py index cfde04b572..396d088a53 100644 --- a/erpnext/controllers/stock_controller.py +++ b/erpnext/controllers/stock_controller.py @@ -6,11 +6,9 @@ import frappe from frappe.utils import cint, flt, cstr from frappe import msgprint, _ import frappe.defaults +from erpnext.accounts.general_ledger import make_gl_entries, delete_gl_entries, process_gl_map from erpnext.controllers.accounts_controller import AccountsController -from erpnext.accounts.general_ledger import make_gl_entries, delete_gl_entries, process_gl_map -from erpnext.stock.utils import update_bin - class StockController(AccountsController): def make_gl_entries(self, repost_future_gle=True): @@ -229,23 +227,44 @@ class StockController(AccountsController): incoming_rate = incoming_rate[0][0] if incoming_rate else 0.0 return incoming_rate + + def update_reserved_qty(self): + so_map = {} + for d in self.get("items"): + if d.so_detail: + if self.doctype == "Delivery Note" and d.against_sales_order: + so_map.setdefault(d.against_sales_order, []).append(d.so_detail) + elif self.doctype == "Sales Invoice" and d.sales_order and self.update_stock: + so_map.setdefault(d.sales_order, []).append(d.so_detail) - def update_reserved_qty(self, d): - if d['reserved_qty'] < 0 : - # Reduce reserved qty from reserved warehouse mentioned in so - if not d["reserved_warehouse"]: - frappe.throw(_("Delivery Warehouse is missing in Sales Order")) + for so, so_item_rows in so_map.items(): + if so and so_item_rows: + sales_order = frappe.get_doc("Sales Order", so) - args = { - "item_code": d['item_code'], - "warehouse": d["reserved_warehouse"], - "voucher_type": self.doctype, - "voucher_no": self.name, - "reserved_qty": (self.docstatus==1 and 1 or -1)*flt(d['reserved_qty']), - "posting_date": self.posting_date, - "is_amended": self.amended_from and 'Yes' or 'No' - } - update_bin(args) + if sales_order.status in ["Stopped", "Cancelled"]: + frappe.throw(_("Sales Order {0} is cancelled or stopped").format(so), frappe.InvalidStatusError) + + sales_order.update_reserved_qty(so_item_rows) + + def update_stock_ledger(self): + self.update_reserved_qty() + + sl_entries = [] + for d in self.get_item_list(): + if frappe.db.get_value("Item", d.item_code, "is_stock_item") == 1 \ + and d.warehouse and flt(d['qty']): + + incoming_rate = 0 + if cint(self.is_return) and self.return_against and self.docstatus==1: + incoming_rate = self.get_incoming_rate_for_sales_return(d.item_code, self.return_against) + + sl_entries.append(self.get_sl_entries(d, { + "actual_qty": -1*flt(d['qty']), + "stock_uom": frappe.db.get_value("Item", d.item_code, "stock_uom"), + "incoming_rate": incoming_rate + })) + + self.make_sl_entries(sl_entries) def update_gl_entries_after(posting_date, posting_time, for_warehouses=None, for_items=None, warehouse_account=None): diff --git a/erpnext/selling/doctype/sales_order/sales_order.py b/erpnext/selling/doctype/sales_order/sales_order.py index b05c009fa0..2e57a11535 100644 --- a/erpnext/selling/doctype/sales_order/sales_order.py +++ b/erpnext/selling/doctype/sales_order/sales_order.py @@ -8,6 +8,7 @@ import frappe.utils from frappe.utils import cstr, flt, getdate, comma_and from frappe import _ from frappe.model.mapper import get_mapped_doc +from erpnext.utilities.repost_stock import update_bin_qty, get_reserved_qty from erpnext.controllers.selling_controller import SellingController @@ -151,7 +152,7 @@ class SalesOrder(SellingController): super(SalesOrder, self).on_submit() self.check_credit_limit() - self.update_stock_ledger(update_stock = 1) + self.update_reserved_qty() frappe.get_doc('Authorization Control').validate_approving_authority(self.doctype, self.base_grand_total, self) @@ -164,7 +165,7 @@ class SalesOrder(SellingController): frappe.throw(_("Stopped order cannot be cancelled. Unstop to cancel.")) self.check_nextdoc_docstatus() - self.update_stock_ledger(update_stock = -1) + self.update_reserved_qty() self.update_prevdoc_status('cancel') @@ -213,32 +214,38 @@ class SalesOrder(SellingController): def stop_sales_order(self): self.check_modified_date() - self.update_stock_ledger(-1) + self.update_reserved_qty() frappe.db.set(self, 'status', 'Stopped') frappe.msgprint(_("{0} {1} status is Stopped").format(self.doctype, self.name)) self.notify_modified() def unstop_sales_order(self): self.check_modified_date() - self.update_stock_ledger(1) + self.update_reserved_qty() frappe.db.set(self, 'status', 'Submitted') frappe.msgprint(_("{0} {1} status is Unstopped").format(self.doctype, self.name)) + + def update_reserved_qty(self, so_item_rows=None): + """update requested qty (before ordered_qty is updated)""" + item_wh_list = [] + def _valid_for_reserve(item_code, warehouse): + if item_code and warehouse and [item_code, warehouse] not in item_wh_list \ + and frappe.db.get_value("Item", item_code, "is_stock_item"): + item_wh_list.append([item_code, warehouse]) + + for d in self.get("items"): + if (not so_item_rows or d.name in so_item_rows): + _valid_for_reserve(d.item_code, d.warehouse) + + if self.has_product_bundle(d.item_code): + for p in self.get("packed_items"): + if p.parent_detail_docname == d.name and p.parent_item == d.item_code: + _valid_for_reserve(p.item_code, p.warehouse) - - def update_stock_ledger(self, update_stock): - from erpnext.stock.utils import update_bin - for d in self.get_item_list(): - if frappe.db.get_value("Item", d['item_code'], "is_stock_item")==1: - args = { - "item_code": d['item_code'], - "warehouse": d['reserved_warehouse'], - "reserved_qty": flt(update_stock) * flt(d['reserved_qty']), - "posting_date": self.transaction_date, - "voucher_type": self.doctype, - "voucher_no": self.name, - "is_amended": self.amended_from and 'Yes' or 'No' - } - update_bin(args) + for item_code, warehouse in item_wh_list: + update_bin_qty(item_code, warehouse, { + "reserved_qty": get_reserved_qty(item_code, warehouse) + }) def on_update(self): pass diff --git a/erpnext/stock/doctype/delivery_note/delivery_note.py b/erpnext/stock/doctype/delivery_note/delivery_note.py index 5e11962ea5..201546e457 100644 --- a/erpnext/stock/doctype/delivery_note/delivery_note.py +++ b/erpnext/stock/doctype/delivery_note/delivery_note.py @@ -83,7 +83,7 @@ class DeliveryNote(SellingController): def so_required(self): """check in manage account if sales order required or not""" - if not self.is_return and frappe.db.get_value("Selling Settings", None, 'so_required') == 'Yes': + if frappe.db.get_value("Selling Settings", None, 'so_required') == 'Yes': for d in self.get('items'): if not d.against_sales_order: frappe.throw(_("Sales Order required for Item {0}").format(d.item_code)) @@ -174,10 +174,10 @@ class DeliveryNote(SellingController): # Check for Approving Authority frappe.get_doc('Authorization Control').validate_approving_authority(self.doctype, self.company, self.base_grand_total, self) + # update delivered qty in sales order + self.update_prevdoc_status() + if not self.is_return: - # update delivered qty in sales order - self.update_prevdoc_status() - self.check_credit_limit() self.update_stock_ledger() @@ -190,8 +190,7 @@ class DeliveryNote(SellingController): self.check_stop_sales_order("against_sales_order") self.check_next_docstatus() - if not self.is_return: - self.update_prevdoc_status() + self.update_prevdoc_status() self.update_stock_ledger() @@ -242,25 +241,6 @@ class DeliveryNote(SellingController): ps.cancel() frappe.msgprint(_("Packing Slip(s) cancelled")) - - def update_stock_ledger(self): - sl_entries = [] - for d in self.get_item_list(): - if frappe.db.get_value("Item", d.item_code, "is_stock_item") == 1 \ - and d.warehouse and flt(d['qty']): - self.update_reserved_qty(d) - - incoming_rate = 0 - if cint(self.is_return) and self.return_against and self.docstatus==1: - incoming_rate = self.get_incoming_rate_for_sales_return(d.item_code, self.return_against) - - sl_entries.append(self.get_sl_entries(d, { - "actual_qty": -1*flt(d['qty']), - "incoming_rate": incoming_rate - })) - - self.make_sl_entries(sl_entries) - def get_list_context(context=None): from erpnext.controllers.website_list_for_contact import get_list_context list_context = get_list_context(context) diff --git a/erpnext/stock/doctype/material_request/material_request.py b/erpnext/stock/doctype/material_request/material_request.py index fd6f943a95..03af0722a3 100644 --- a/erpnext/stock/doctype/material_request/material_request.py +++ b/erpnext/stock/doctype/material_request/material_request.py @@ -10,9 +10,11 @@ import frappe from frappe.utils import cstr, flt, getdate from frappe import _ from frappe.model.mapper import get_mapped_doc +from erpnext.utilities.repost_stock import update_bin_qty, get_indented_qty from erpnext.controllers.buying_controller import BuyingController + form_grid_templates = { "items": "templates/form_grid/material_request_grid.html" } @@ -136,19 +138,6 @@ class MaterialRequest(BuyingController): def update_requested_qty(self, mr_item_rows=None): """update requested qty (before ordered_qty is updated)""" - from erpnext.stock.utils import get_bin - - def _update_requested_qty(item_code, warehouse): - requested_qty = frappe.db.sql("""select sum(mr_item.qty - ifnull(mr_item.ordered_qty, 0)) - from `tabMaterial Request Item` mr_item, `tabMaterial Request` mr - where mr_item.item_code=%s and mr_item.warehouse=%s - and mr_item.qty > ifnull(mr_item.ordered_qty, 0) and mr_item.parent=mr.name - and mr.status!='Stopped' and mr.docstatus=1""", (item_code, warehouse)) - - bin_doc = get_bin(item_code, warehouse) - bin_doc.indented_qty = flt(requested_qty[0][0]) if requested_qty else 0 - bin_doc.save() - item_wh_list = [] for d in self.get("items"): if (not mr_item_rows or d.name in mr_item_rows) and [d.item_code, d.warehouse] not in item_wh_list \ @@ -156,7 +145,9 @@ class MaterialRequest(BuyingController): item_wh_list.append([d.item_code, d.warehouse]) for item_code, warehouse in item_wh_list: - _update_requested_qty(item_code, warehouse) + update_bin_qty(item_code, warehouse, { + "indented_qty": get_indented_qty(item_code, warehouse) + }) def update_completed_and_requested_qty(stock_entry, method): if stock_entry.doctype == "Stock Entry": diff --git a/erpnext/stock/doctype/purchase_receipt/purchase_receipt.py b/erpnext/stock/doctype/purchase_receipt/purchase_receipt.py index 2979c12452..f4273b27ed 100644 --- a/erpnext/stock/doctype/purchase_receipt/purchase_receipt.py +++ b/erpnext/stock/doctype/purchase_receipt/purchase_receipt.py @@ -117,7 +117,7 @@ class PurchaseReceipt(BuyingController): self.validate_rate_with_reference_doc([["Purchase Order", "prevdoc_docname", "prevdoc_detail_docname"]]) def po_required(self): - if not self.is_return and frappe.db.get_value("Buying Settings", None, "po_required") == 'Yes': + if frappe.db.get_value("Buying Settings", None, "po_required") == 'Yes': for d in self.get('items'): if not d.prevdoc_docname: frappe.throw(_("Purchase Order number required for Item {0}").format(d.item_code)) @@ -221,9 +221,10 @@ class PurchaseReceipt(BuyingController): # Set status as Submitted frappe.db.set(self, 'status', 'Submitted') + self.update_prevdoc_status() + self.update_ordered_qty() + if not self.is_return: - self.update_prevdoc_status() - self.update_ordered_qty() purchase_controller.update_last_purchase_rate(self, 1) self.update_stock_ledger() @@ -257,12 +258,11 @@ class PurchaseReceipt(BuyingController): self.update_stock_ledger() + self.update_prevdoc_status() + # Must be called after updating received qty in PO + self.update_ordered_qty() + if not self.is_return: - self.update_prevdoc_status() - - # Must be called after updating received qty in PO - self.update_ordered_qty() - pc_obj.update_last_purchase_rate(self, 0) self.make_gl_entries_on_cancel() From 047ecd1eb9b78278d8d16e6d943f1b24ec1b5e0c Mon Sep 17 00:00:00 2001 From: Nabin Hait Date: Mon, 24 Aug 2015 16:10:43 +0530 Subject: [PATCH 12/21] Update order reference in return entries and repost reserved / ordered qty --- erpnext/patches.txt | 1 + ...pdate_order_reference_in_return_entries.py | 76 +++++++++++++++++++ .../doctype/sales_order/sales_order.py | 4 +- 3 files changed, 79 insertions(+), 2 deletions(-) create mode 100644 erpnext/patches/v5_7/update_order_reference_in_return_entries.py diff --git a/erpnext/patches.txt b/erpnext/patches.txt index 21656c6d65..ea10054d52 100644 --- a/erpnext/patches.txt +++ b/erpnext/patches.txt @@ -193,3 +193,4 @@ execute:frappe.db.sql("update `tabProduction Order` pro set description = (selec erpnext.patches.v5_7.item_template_attributes erpnext.patches.v4_2.repost_reserved_qty #2015-08-20 erpnext.patches.v5_4.update_purchase_cost_against_project +erpnext.patches.v5_7.update_order_reference_in_return_entries \ No newline at end of file diff --git a/erpnext/patches/v5_7/update_order_reference_in_return_entries.py b/erpnext/patches/v5_7/update_order_reference_in_return_entries.py new file mode 100644 index 0000000000..c957242260 --- /dev/null +++ b/erpnext/patches/v5_7/update_order_reference_in_return_entries.py @@ -0,0 +1,76 @@ +# Copyright (c) 2013, Web Notes Technologies Pvt. Ltd. and Contributors +# License: GNU General Public License v3. See license.txt + +from __future__ import unicode_literals +import frappe + +def execute(): + # sales return + return_entries = list(frappe.db.sql(""" + select dn.name as name, dn_item.name as row_id, dn.return_against, + dn_item.item_code, "Delivery Note" as doctype + from `tabDelivery Note Item` dn_item, `tabDelivery Note` dn + where dn_item.parent=dn.name and dn.is_return=1 and dn.docstatus < 2 + """, as_dict=1)) + + return_entries += list(frappe.db.sql(""" + select si.name as name, si_item.name as row_id, si.return_against, + si_item.item_code, "Sales Invoice" as doctype + from `tabSales Invoice Item` si_item, `tabSales Invoice` si + where si_item.parent=si.name and si.is_return=1 and si.update_stock=1 and si.docstatus < 2 + """, as_dict=1)) + + for d in return_entries: + ref_field = "against_sales_order" if d.doctype == "Delivery Note" else "sales_order" + order_details = frappe.db.sql(""" + select {0} as sales_order, so_detail + from `tab{1} Item` item + where + parent=%s and item_code=%s + and ifnull(so_detail, '') !='' + order by + (select transaction_date from `tabSales Order` where name=item.{3}) DESC + """.format(ref_field, d.doctype, ref_field, ref_field), (d.return_against, d.item_code), as_dict=1) + + if order_details: + frappe.db.sql(""" + update `tab{0} Item` + set {1}=%s, so_detail=%s + where name=%s + """.format(d.doctype, ref_field), + (order_details[0].sales_order, order_details[0].so_detail, d.row_id)) + + doc = frappe.get_doc(d.doctype, d.name) + doc.update_reserved_qty() + + + #-------------------------- + # purchase return + return_entries = frappe.db.sql(""" + select pr.name as name, pr_item.name as row_id, pr.return_against, pr_item.item_code + from `tabPurchase Receipt Item` pr_item, `tabPurchase Receipt` pr + where pr_item.parent=pr.name and pr.is_return=1 and pr.docstatus < 2 + """, as_dict=1) + + for d in return_entries: + order_details = frappe.db.sql(""" + select prevdoc_docname as purchase_order, prevdoc_detail_docname as po_detail + from `tabPurchase Receipt Item` item + where + parent=%s and item_code=%s + and ifnull(prevdoc_detail_docname, '') !='' + and ifnull(prevdoc_doctype, '') = 'Purchase Order' and ifnull(prevdoc_detail_docname, '') != '' + order by + (select transaction_date from `tabPurchase Order` where name=item.prevdoc_detail_docname) DESC + """, (d.return_against, d.item_code), as_dict=1) + + if order_details: + frappe.db.sql(""" + update `tabPurchase Receipt Item` + set prevdoc_doctype='Purchase Order', prevdoc_docname=%s, prevdoc_detail_docname=%s + where name=%s + """, (order_details[0].purchase_order, order_details[0].po_detail, d.row_id)) + + pr = frappe.get_doc("Purchase Receipt", d.name) + pr.update_ordered_qty() + \ No newline at end of file diff --git a/erpnext/selling/doctype/sales_order/sales_order.py b/erpnext/selling/doctype/sales_order/sales_order.py index 2e57a11535..4f9d54dfbf 100644 --- a/erpnext/selling/doctype/sales_order/sales_order.py +++ b/erpnext/selling/doctype/sales_order/sales_order.py @@ -214,15 +214,15 @@ class SalesOrder(SellingController): def stop_sales_order(self): self.check_modified_date() - self.update_reserved_qty() frappe.db.set(self, 'status', 'Stopped') + self.update_reserved_qty() frappe.msgprint(_("{0} {1} status is Stopped").format(self.doctype, self.name)) self.notify_modified() def unstop_sales_order(self): self.check_modified_date() - self.update_reserved_qty() frappe.db.set(self, 'status', 'Submitted') + self.update_reserved_qty() frappe.msgprint(_("{0} {1} status is Unstopped").format(self.doctype, self.name)) def update_reserved_qty(self, so_item_rows=None): From 3f321ebfde946d0e18df555e2ca9119922c1e964 Mon Sep 17 00:00:00 2001 From: Nabin Hait Date: Mon, 24 Aug 2015 16:16:29 +0530 Subject: [PATCH 13/21] utilities/repost_stock file renamed to stock/stock_balance --- erpnext/buying/doctype/purchase_order/purchase_order.py | 2 +- .../patches/repair_tools/set_stock_balance_as_per_serial_no.py | 2 +- erpnext/patches/v4_2/fix_gl_entries_for_stock_transactions.py | 2 +- erpnext/patches/v4_2/repost_reserved_qty.py | 2 +- erpnext/patches/v4_2/update_requested_and_ordered_qty.py | 2 +- erpnext/patches/v5_0/repost_requested_qty.py | 2 +- .../patches/v5_4/fix_reserved_qty_and_sle_for_packed_items.py | 2 +- erpnext/selling/doctype/sales_order/sales_order.py | 2 +- erpnext/stock/doctype/item/item.py | 2 +- erpnext/stock/doctype/material_request/material_request.py | 2 +- erpnext/stock/doctype/warehouse/warehouse.py | 2 +- erpnext/{utilities/repost_stock.py => stock/stock_balance.py} | 0 12 files changed, 11 insertions(+), 11 deletions(-) rename erpnext/{utilities/repost_stock.py => stock/stock_balance.py} (100%) diff --git a/erpnext/buying/doctype/purchase_order/purchase_order.py b/erpnext/buying/doctype/purchase_order/purchase_order.py index b1c0a58a77..58b1d1938d 100644 --- a/erpnext/buying/doctype/purchase_order/purchase_order.py +++ b/erpnext/buying/doctype/purchase_order/purchase_order.py @@ -9,7 +9,7 @@ from frappe import msgprint, _, throw from frappe.model.mapper import get_mapped_doc from erpnext.controllers.buying_controller import BuyingController from erpnext.stock.doctype.item.item import get_last_purchase_details -from erpnext.utilities.repost_stock import update_bin_qty, get_ordered_qty +from erpnext.stock.stock_balance import update_bin_qty, get_ordered_qty form_grid_templates = { diff --git a/erpnext/patches/repair_tools/set_stock_balance_as_per_serial_no.py b/erpnext/patches/repair_tools/set_stock_balance_as_per_serial_no.py index 4a4266e7fd..5a421d146f 100644 --- a/erpnext/patches/repair_tools/set_stock_balance_as_per_serial_no.py +++ b/erpnext/patches/repair_tools/set_stock_balance_as_per_serial_no.py @@ -5,7 +5,7 @@ from __future__ import unicode_literals import frappe def execute(): - from erpnext.utilities.repost_stock import set_stock_balance_as_per_serial_no + from erpnext.stock.stock_balance import set_stock_balance_as_per_serial_no frappe.db.auto_commit_on_many_writes = 1 set_stock_balance_as_per_serial_no() diff --git a/erpnext/patches/v4_2/fix_gl_entries_for_stock_transactions.py b/erpnext/patches/v4_2/fix_gl_entries_for_stock_transactions.py index 73a56a8e98..0df5801c42 100644 --- a/erpnext/patches/v4_2/fix_gl_entries_for_stock_transactions.py +++ b/erpnext/patches/v4_2/fix_gl_entries_for_stock_transactions.py @@ -6,7 +6,7 @@ import frappe from frappe.utils import flt def execute(): - from erpnext.utilities.repost_stock import repost + from erpnext.stock.stock_balance import repost repost(allow_zero_rate=True, only_actual=True) frappe.reload_doctype("Account") diff --git a/erpnext/patches/v4_2/repost_reserved_qty.py b/erpnext/patches/v4_2/repost_reserved_qty.py index a2cd4d8ad6..74f4b79f93 100644 --- a/erpnext/patches/v4_2/repost_reserved_qty.py +++ b/erpnext/patches/v4_2/repost_reserved_qty.py @@ -3,7 +3,7 @@ from __future__ import unicode_literals import frappe -from erpnext.utilities.repost_stock import update_bin_qty, get_reserved_qty +from erpnext.stock.stock_balance import update_bin_qty, get_reserved_qty def execute(): repost_for = frappe.db.sql(""" diff --git a/erpnext/patches/v4_2/update_requested_and_ordered_qty.py b/erpnext/patches/v4_2/update_requested_and_ordered_qty.py index 240b11dae5..7bb49e64df 100644 --- a/erpnext/patches/v4_2/update_requested_and_ordered_qty.py +++ b/erpnext/patches/v4_2/update_requested_and_ordered_qty.py @@ -5,7 +5,7 @@ from __future__ import unicode_literals import frappe def execute(): - from erpnext.utilities.repost_stock import update_bin_qty, get_indented_qty, get_ordered_qty + from erpnext.stock.stock_balance import update_bin_qty, get_indented_qty, get_ordered_qty count=0 for item_code, warehouse in frappe.db.sql("""select distinct item_code, warehouse from diff --git a/erpnext/patches/v5_0/repost_requested_qty.py b/erpnext/patches/v5_0/repost_requested_qty.py index 8c1d6f7fbb..6af71f3fc4 100644 --- a/erpnext/patches/v5_0/repost_requested_qty.py +++ b/erpnext/patches/v5_0/repost_requested_qty.py @@ -5,7 +5,7 @@ from __future__ import unicode_literals import frappe def execute(): - from erpnext.utilities.repost_stock import update_bin_qty, get_indented_qty + from erpnext.stock.stock_balance import update_bin_qty, get_indented_qty count=0 for item_code, warehouse in frappe.db.sql("""select distinct item_code, warehouse diff --git a/erpnext/patches/v5_4/fix_reserved_qty_and_sle_for_packed_items.py b/erpnext/patches/v5_4/fix_reserved_qty_and_sle_for_packed_items.py index 251dd56acb..6eb3994c7c 100644 --- a/erpnext/patches/v5_4/fix_reserved_qty_and_sle_for_packed_items.py +++ b/erpnext/patches/v5_4/fix_reserved_qty_and_sle_for_packed_items.py @@ -3,7 +3,7 @@ from __future__ import unicode_literals import frappe -from erpnext.utilities.repost_stock import repost_actual_qty +from erpnext.stock.stock_balance import repost_actual_qty def execute(): cancelled_invoices = frappe.db.sql_list("""select name from `tabSales Invoice` diff --git a/erpnext/selling/doctype/sales_order/sales_order.py b/erpnext/selling/doctype/sales_order/sales_order.py index 4f9d54dfbf..dd21f0553e 100644 --- a/erpnext/selling/doctype/sales_order/sales_order.py +++ b/erpnext/selling/doctype/sales_order/sales_order.py @@ -8,7 +8,7 @@ import frappe.utils from frappe.utils import cstr, flt, getdate, comma_and from frappe import _ from frappe.model.mapper import get_mapped_doc -from erpnext.utilities.repost_stock import update_bin_qty, get_reserved_qty +from erpnext.stock.stock_balance import update_bin_qty, get_reserved_qty from erpnext.controllers.selling_controller import SellingController diff --git a/erpnext/stock/doctype/item/item.py b/erpnext/stock/doctype/item/item.py index 659fb1b5f5..08350afa72 100644 --- a/erpnext/stock/doctype/item/item.py +++ b/erpnext/stock/doctype/item/item.py @@ -269,7 +269,7 @@ class Item(WebsiteGenerator): frappe.db.set_value("Item", newdn, "last_purchase_rate", last_purchase_rate) def recalculate_bin_qty(self, newdn): - from erpnext.utilities.repost_stock import repost_stock + from erpnext.stock.stock_balance import repost_stock frappe.db.auto_commit_on_many_writes = 1 existing_allow_negative_stock = frappe.db.get_value("Stock Settings", None, "allow_negative_stock") frappe.db.set_value("Stock Settings", None, "allow_negative_stock", 1) diff --git a/erpnext/stock/doctype/material_request/material_request.py b/erpnext/stock/doctype/material_request/material_request.py index 03af0722a3..e4183669bf 100644 --- a/erpnext/stock/doctype/material_request/material_request.py +++ b/erpnext/stock/doctype/material_request/material_request.py @@ -10,7 +10,7 @@ import frappe from frappe.utils import cstr, flt, getdate from frappe import _ from frappe.model.mapper import get_mapped_doc -from erpnext.utilities.repost_stock import update_bin_qty, get_indented_qty +from erpnext.stock.stock_balance import update_bin_qty, get_indented_qty from erpnext.controllers.buying_controller import BuyingController diff --git a/erpnext/stock/doctype/warehouse/warehouse.py b/erpnext/stock/doctype/warehouse/warehouse.py index 5a3976399f..610c7b88a3 100644 --- a/erpnext/stock/doctype/warehouse/warehouse.py +++ b/erpnext/stock/doctype/warehouse/warehouse.py @@ -140,7 +140,7 @@ class Warehouse(Document): self.recalculate_bin_qty(newdn) def recalculate_bin_qty(self, newdn): - from erpnext.utilities.repost_stock import repost_stock + from erpnext.stock.stock_balance import repost_stock frappe.db.auto_commit_on_many_writes = 1 existing_allow_negative_stock = frappe.db.get_value("Stock Settings", None, "allow_negative_stock") frappe.db.set_value("Stock Settings", None, "allow_negative_stock", 1) diff --git a/erpnext/utilities/repost_stock.py b/erpnext/stock/stock_balance.py similarity index 100% rename from erpnext/utilities/repost_stock.py rename to erpnext/stock/stock_balance.py From b719c469c81496d7598302a7e9e2e449168eee61 Mon Sep 17 00:00:00 2001 From: Nabin Hait Date: Mon, 24 Aug 2015 16:46:00 +0530 Subject: [PATCH 14/21] Allow different rate in Return Entry --- erpnext/controllers/sales_and_purchase_return.py | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/erpnext/controllers/sales_and_purchase_return.py b/erpnext/controllers/sales_and_purchase_return.py index 2e4ecaa8c1..bb3b63cdd3 100644 --- a/erpnext/controllers/sales_and_purchase_return.py +++ b/erpnext/controllers/sales_and_purchase_return.py @@ -83,9 +83,10 @@ def validate_returned_items(doc): elif abs(d.qty) > max_return_qty: frappe.throw(_("Row # {0}: Cannot return more than {1} for Item {2}") .format(d.idx, ref.qty, d.item_code), StockOverReturnError) - elif ref.rate and flt(d.rate) != ref.rate: - frappe.throw(_("Row # {0}: Rate must be same as {1} {2}") - .format(d.idx, doc.doctype, doc.return_against)) + elif ref.rate and (doc.doctype in ("Delivery Note", "Purchase Receipt") \ + or (doc.doctype=="Sales Invoice" and doc.update_stock==1)) and flt(d.rate) > ref.rate: + frappe.throw(_("Row # {0}: Rate cannot be greater than {1} {2}") + .format(d.idx, doc.doctype, doc.return_against)) elif ref.batch_no and d.batch_no != ref.batch_no: frappe.throw(_("Row # {0}: Batch No must be same as {1} {2}") .format(d.idx, doc.doctype, doc.return_against)) From fe13bfed441df49e82c71332c85dde158ea7b6bc Mon Sep 17 00:00:00 2001 From: Anand Doshi Date: Tue, 25 Aug 2015 12:49:40 +0530 Subject: [PATCH 15/21] Fixes to Return Improvements pull request - Added "Returned Qty" in Sales and Purchase Order - Map Expense Account in Return Delivery Note - Defined some No Copy fields - Added "Credit Note" and "Debit Note" Print Headings - Fixed patch --- .../purchase_invoice/purchase_invoice.py | 2 +- .../purchase_invoice/purchase_invoice_list.js | 2 +- .../doctype/sales_invoice/sales_invoice.js | 1 + .../doctype/sales_invoice/sales_invoice.py | 30 +++-- .../sales_invoice/sales_invoice_list.js | 2 +- .../__init__.py | 0 .../credit_note___negative_invoice.json | 17 --- .../purchase_order_item.json | 23 +++- .../current/sales_purchase_return.md | 3 + .../controllers/sales_and_purchase_return.py | 76 ++++++------ erpnext/controllers/status_updater.py | 109 +++++++++++------- erpnext/patches.txt | 6 +- .../patches/v5_7/item_template_attributes.py | 3 - erpnext/patches/v5_8/__init__.py | 1 + .../v5_8/add_credit_note_print_heading.py | 14 +++ ...pdate_order_reference_in_return_entries.py | 73 +++++++----- erpnext/public/js/controllers/transaction.js | 17 +++ .../sales_order_item/sales_order_item.json | 23 +++- .../page/setup_wizard/install_fixtures.py | 12 +- .../doctype/delivery_note/delivery_note.py | 21 +++- .../delivery_note/delivery_note_list.js | 2 +- .../delivery_note_item.json | 6 +- .../purchase_receipt/purchase_receipt.py | 27 +++-- .../purchase_receipt/purchase_receipt_list.js | 2 +- erpnext/stock/doctype/serial_no/serial_no.py | 4 +- erpnext/stock/get_item_details.py | 4 + 26 files changed, 313 insertions(+), 167 deletions(-) delete mode 100644 erpnext/accounts/print_format/credit_note___negative_invoice/__init__.py delete mode 100644 erpnext/accounts/print_format/credit_note___negative_invoice/credit_note___negative_invoice.json create mode 100644 erpnext/change_log/current/sales_purchase_return.md create mode 100644 erpnext/patches/v5_8/__init__.py create mode 100644 erpnext/patches/v5_8/add_credit_note_print_heading.py rename erpnext/patches/{v5_7 => v5_8}/update_order_reference_in_return_entries.py (66%) diff --git a/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.py b/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.py index 132cb1027d..22089373b1 100644 --- a/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.py +++ b/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.py @@ -127,7 +127,7 @@ class PurchaseInvoice(BuyingController): } }) - if cint(frappe.db.get_single_value('Buying Settings', 'maintain_same_rate')): + if cint(frappe.db.get_single_value('Buying Settings', 'maintain_same_rate')) and not self.is_return: self.validate_rate_with_reference_doc([ ["Purchase Order", "purchase_order", "po_detail"], ["Purchase Receipt", "purchase_receipt", "pr_detail"] diff --git a/erpnext/accounts/doctype/purchase_invoice/purchase_invoice_list.js b/erpnext/accounts/doctype/purchase_invoice/purchase_invoice_list.js index ccad5ce2ad..afcd61f228 100644 --- a/erpnext/accounts/doctype/purchase_invoice/purchase_invoice_list.js +++ b/erpnext/accounts/doctype/purchase_invoice/purchase_invoice_list.js @@ -7,7 +7,7 @@ frappe.listview_settings['Purchase Invoice'] = { "currency", "is_return"], get_indicator: function(doc) { if(cint(doc.is_return)==1) { - return [__("Return"), "darkgrey", "is_return,=,1"]; + return [__("Return"), "darkgrey", "is_return,=,Yes"]; } else if(flt(doc.outstanding_amount) > 0 && doc.docstatus==1) { if(frappe.datetime.get_diff(doc.due_date) < 0) { return [__("Overdue"), "red", "outstanding_amount,>,0|due_date,<,Today"]; diff --git a/erpnext/accounts/doctype/sales_invoice/sales_invoice.js b/erpnext/accounts/doctype/sales_invoice/sales_invoice.js index 734684f69d..5e59078d75 100644 --- a/erpnext/accounts/doctype/sales_invoice/sales_invoice.js +++ b/erpnext/accounts/doctype/sales_invoice/sales_invoice.js @@ -64,6 +64,7 @@ erpnext.accounts.SalesInvoiceController = erpnext.selling.SellingController.exte if(doc.outstanding_amount!=0 && !cint(doc.is_return)) { cur_frm.add_custom_button(__('Payment'), cur_frm.cscript.make_bank_entry).addClass("btn-primary"); } + } // Show buttons only when pos view is active diff --git a/erpnext/accounts/doctype/sales_invoice/sales_invoice.py b/erpnext/accounts/doctype/sales_invoice/sales_invoice.py index 20c766aaa9..12740160de 100644 --- a/erpnext/accounts/doctype/sales_invoice/sales_invoice.py +++ b/erpnext/accounts/doctype/sales_invoice/sales_invoice.py @@ -82,11 +82,12 @@ class SalesInvoice(SellingController): self.check_prev_docstatus() if self.is_return: + # NOTE status updating bypassed for is_return self.status_updater = [] - + self.update_status_updater_args() self.update_prevdoc_status() - + if not self.is_return: self.update_billing_status_for_zero_amount_refdoc("Sales Order") self.check_credit_limit() @@ -112,11 +113,12 @@ class SalesInvoice(SellingController): remove_against_link_from_jv(self.doctype, self.name) if self.is_return: + # NOTE status updating bypassed for is_return self.status_updater = [] - + self.update_status_updater_args() self.update_prevdoc_status() - + if not self.is_return: self.update_billing_status_for_zero_amount_refdoc("Sales Order") @@ -126,7 +128,7 @@ class SalesInvoice(SellingController): def update_status_updater_args(self): if cint(self.update_stock): - self.status_updater.append({ + self.status_updater.extend([{ 'source_dt':'Sales Invoice Item', 'target_dt':'Sales Order Item', 'target_parent_dt':'Sales Order', @@ -144,7 +146,21 @@ class SalesInvoice(SellingController): 'overflow_type': 'delivery', 'extra_cond': """ and exists(select name from `tabSales Invoice` where name=`tabSales Invoice Item`.parent and ifnull(update_stock, 0) = 1)""" - }) + }, + { + 'source_dt': 'Sales Invoice Item', + 'target_dt': 'Sales Order Item', + 'join_field': 'so_detail', + 'target_field': 'returned_qty', + 'target_parent_dt': 'Sales Order', + # 'target_parent_field': 'per_delivered', + # 'target_ref_field': 'qty', + 'source_field': '-1 * qty', + # 'percent_join_field': 'sales_order', + # 'overflow_type': 'delivery', + 'extra_cond': """ and exists (select name from `tabSales Invoice` where name=`tabSales Invoice Item`.parent and update_stock=1 and is_return=1)""" + } + ]) def set_missing_values(self, for_validate=False): pos = self.set_pos_fields(for_validate) @@ -281,7 +297,7 @@ class SalesInvoice(SellingController): }, }) - if cint(frappe.db.get_single_value('Selling Settings', 'maintain_same_sales_rate')): + if cint(frappe.db.get_single_value('Selling Settings', 'maintain_same_sales_rate')) and not self.is_return: self.validate_rate_with_reference_doc([ ["Sales Order", "sales_order", "so_detail"], ["Delivery Note", "delivery_note", "dn_detail"] diff --git a/erpnext/accounts/doctype/sales_invoice/sales_invoice_list.js b/erpnext/accounts/doctype/sales_invoice/sales_invoice_list.js index 11c9789195..55e8b211b9 100644 --- a/erpnext/accounts/doctype/sales_invoice/sales_invoice_list.js +++ b/erpnext/accounts/doctype/sales_invoice/sales_invoice_list.js @@ -7,7 +7,7 @@ frappe.listview_settings['Sales Invoice'] = { "currency", "is_return"], get_indicator: function(doc) { if(cint(doc.is_return)==1) { - return [__("Return"), "darkgrey", "is_return,=,1"]; + return [__("Return"), "darkgrey", "is_return,=,Yes"]; } else if(flt(doc.outstanding_amount)==0) { return [__("Paid"), "green", "outstanding_amount,=,0"] } else if (flt(doc.outstanding_amount) > 0 && doc.due_date > frappe.datetime.get_today()) { diff --git a/erpnext/accounts/print_format/credit_note___negative_invoice/__init__.py b/erpnext/accounts/print_format/credit_note___negative_invoice/__init__.py deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/erpnext/accounts/print_format/credit_note___negative_invoice/credit_note___negative_invoice.json b/erpnext/accounts/print_format/credit_note___negative_invoice/credit_note___negative_invoice.json deleted file mode 100644 index e7d7eabaff..0000000000 --- a/erpnext/accounts/print_format/credit_note___negative_invoice/credit_note___negative_invoice.json +++ /dev/null @@ -1,17 +0,0 @@ -{ - "creation": "2015-07-22 17:45:22.220567", - "custom_format": 1, - "disabled": 0, - "doc_type": "Sales Invoice", - "docstatus": 0, - "doctype": "Print Format", - "font": "Default", - "html": "\n\n

\n\t{{ doc.company }}
\n\t{{ doc.select_print_heading or _(\"Credit Note\") }}
\n

\n\n
\n\n{%- for label, value in (\n (_(\"Receipt No\"), doc.name),\n (_(\"Date\"), doc.get_formatted(\"posting_date\")),\n\t(_(\"Customer\"), doc.customer_name),\n (_(\"Amount\"), \"\" + doc.get_formatted(\"grand_total\", absolute_value=True) + \"
\" + (doc.in_words or \"\")),\n\t(_(\"Against\"), doc.return_against),\n (_(\"Remarks\"), doc.remarks)\n) -%}\n\n\t\t
\n\t\t
\n\t\t
{{ value }}
\n\t\t
\n{%- endfor -%}\n\n
\n
\n

\n {{ _(\"For\") }} {{ doc.company }},
\n
\n
\n
\n {{ _(\"Authorized Signatory\") }}\n

", - "modified": "2015-07-22 17:45:22.220567", - "modified_by": "Administrator", - "name": "Credit Note - Negative Invoice", - "owner": "Administrator", - "print_format_builder": 0, - "print_format_type": "Server", - "standard": "Yes" -} \ No newline at end of file diff --git a/erpnext/buying/doctype/purchase_order_item/purchase_order_item.json b/erpnext/buying/doctype/purchase_order_item/purchase_order_item.json index bd862852cd..7faa2f388a 100755 --- a/erpnext/buying/doctype/purchase_order_item/purchase_order_item.json +++ b/erpnext/buying/doctype/purchase_order_item/purchase_order_item.json @@ -1002,6 +1002,27 @@ "set_only_once": 0, "unique": 0 }, + { + "allow_on_submit": 0, + "depends_on": "returned_qty", + "fieldname": "returned_qty", + "fieldtype": "Float", + "hidden": 0, + "ignore_user_permissions": 0, + "in_filter": 0, + "in_list_view": 0, + "label": "Returned Qty", + "no_copy": 1, + "permlevel": 0, + "precision": "", + "print_hide": 1, + "read_only": 1, + "report_hide": 0, + "reqd": 0, + "search_index": 0, + "set_only_once": 0, + "unique": 0 + }, { "allow_on_submit": 0, "fieldname": "billed_amt", @@ -1074,7 +1095,7 @@ "is_submittable": 0, "issingle": 0, "istable": 1, - "modified": "2015-08-19 12:46:32.384796", + "modified": "2015-08-25 06:42:00.898647", "modified_by": "Administrator", "module": "Buying", "name": "Purchase Order Item", diff --git a/erpnext/change_log/current/sales_purchase_return.md b/erpnext/change_log/current/sales_purchase_return.md new file mode 100644 index 0000000000..0152d57855 --- /dev/null +++ b/erpnext/change_log/current/sales_purchase_return.md @@ -0,0 +1,3 @@ +- Fixes in Sales and Purchase Return + - Update Delivered, Ordered and Returned Quantity based on Return transaction + - Allow different Rate in Return transaction diff --git a/erpnext/controllers/sales_and_purchase_return.py b/erpnext/controllers/sales_and_purchase_return.py index bb3b63cdd3..f4895ca649 100644 --- a/erpnext/controllers/sales_and_purchase_return.py +++ b/erpnext/controllers/sales_and_purchase_return.py @@ -11,10 +11,10 @@ class StockOverReturnError(frappe.ValidationError): pass def validate_return(doc): if not doc.meta.get_field("is_return") or not doc.is_return: return - + validate_return_against(doc) validate_returned_items(doc) - + def validate_return_against(doc): if not doc.return_against: frappe.throw(_("{0} is mandatory for Return").format(doc.meta.get_label("return_against"))) @@ -24,49 +24,49 @@ def validate_return_against(doc): filters["customer"] = doc.customer elif doc.meta.get_field("supplier"): filters["supplier"] = doc.supplier - + if not frappe.db.exists(filters): frappe.throw(_("Invalid {0}: {1}") .format(doc.meta.get_label("return_against"), doc.return_against)) else: ref_doc = frappe.get_doc(doc.doctype, doc.return_against) - + # validate posting date time return_posting_datetime = "%s %s" % (doc.posting_date, doc.get("posting_time") or "00:00:00") ref_posting_datetime = "%s %s" % (ref_doc.posting_date, ref_doc.get("posting_time") or "00:00:00") - + if get_datetime(return_posting_datetime) < get_datetime(ref_posting_datetime): frappe.throw(_("Posting timestamp must be after {0}").format(format_datetime(ref_posting_datetime))) - + # validate same exchange rate if doc.conversion_rate != ref_doc.conversion_rate: frappe.throw(_("Exchange Rate must be same as {0} {1} ({2})") .format(doc.doctype, doc.return_against, ref_doc.conversion_rate)) - + # validate update stock if doc.doctype == "Sales Invoice" and doc.update_stock and not ref_doc.update_stock: frappe.throw(_("'Update Stock' can not be checked because items are not delivered via {0}") .format(doc.return_against)) - + def validate_returned_items(doc): from erpnext.stock.doctype.serial_no.serial_no import get_serial_nos - + valid_items = frappe._dict() - + select_fields = "item_code, sum(qty) as qty, rate" if doc.doctype=="Purchase Invoice" \ else "item_code, sum(qty) as qty, rate, serial_no, batch_no" - - for d in frappe.db.sql("""select {0} from `tab{1} Item` where parent = %s + + for d in frappe.db.sql("""select {0} from `tab{1} Item` where parent = %s group by item_code""".format(select_fields, doc.doctype), doc.return_against, as_dict=1): - valid_items.setdefault(d.item_code, d) - + valid_items.setdefault(d.item_code, d) + if doc.doctype in ("Delivery Note", "Sales Invoice"): - for d in frappe.db.sql("""select item_code, sum(qty) as qty, serial_no, batch_no from `tabPacked Item` + for d in frappe.db.sql("""select item_code, sum(qty) as qty, serial_no, batch_no from `tabPacked Item` where parent = %s group by item_code""".format(doc.doctype), doc.return_against, as_dict=1): valid_items.setdefault(d.item_code, d) - + already_returned_items = get_already_returned_items(doc) - + items_returned = False for d in doc.get("items"): if flt(d.qty) < 0: @@ -77,16 +77,12 @@ def validate_returned_items(doc): ref = valid_items.get(d.item_code, frappe._dict()) already_returned_qty = flt(already_returned_items.get(d.item_code)) max_return_qty = flt(ref.qty) - already_returned_qty - + if already_returned_qty >= ref.qty: frappe.throw(_("Item {0} has already been returned").format(d.item_code), StockOverReturnError) elif abs(d.qty) > max_return_qty: frappe.throw(_("Row # {0}: Cannot return more than {1} for Item {2}") .format(d.idx, ref.qty, d.item_code), StockOverReturnError) - elif ref.rate and (doc.doctype in ("Delivery Note", "Purchase Receipt") \ - or (doc.doctype=="Sales Invoice" and doc.update_stock==1)) and flt(d.rate) > ref.rate: - frappe.throw(_("Row # {0}: Rate cannot be greater than {1} {2}") - .format(d.idx, doc.doctype, doc.return_against)) elif ref.batch_no and d.batch_no != ref.batch_no: frappe.throw(_("Row # {0}: Batch No must be same as {1} {2}") .format(d.idx, doc.doctype, doc.return_against)) @@ -100,24 +96,24 @@ def validate_returned_items(doc): if s not in ref_serial_nos: frappe.throw(_("Row # {0}: Serial No {1} does not match with {2} {3}") .format(d.idx, s, doc.doctype, doc.return_against)) - + items_returned = True - + if not items_returned: frappe.throw(_("Atleast one item should be entered with negative quantity in return document")) - + def get_already_returned_items(doc): return frappe._dict(frappe.db.sql(""" - select + select child.item_code, sum(abs(child.qty)) as qty - from - `tab{0} Item` child, `tab{1}` par - where + from + `tab{0} Item` child, `tab{1}` par + where child.parent = par.name and par.docstatus = 1 - and ifnull(par.is_return, 0) = 1 and par.return_against = %s and child.qty < 0 + and ifnull(par.is_return, 0) = 1 and par.return_against = %s and child.qty < 0 group by item_code """.format(doc.doctype, doc.doctype), doc.return_against)) - + def make_return_doc(doctype, source_name, target_doc=None): from frappe.model.mapper import get_mapped_doc def set_missing_values(source, target): @@ -127,13 +123,21 @@ def make_return_doc(doctype, source_name, target_doc=None): doc.ignore_pricing_rule = 1 if doctype == "Sales Invoice": doc.is_pos = 0 - + + # look for Print Heading "Credit Note" + if not doc.select_print_heading: + doc.select_print_heading = frappe.db.get_value("Print Heading", _("Credit Note")) + + elif doctype == "Purchase Invoice": + # look for Print Heading "Debit Note" + doc.select_print_heading = frappe.db.get_value("Print Heading", _("Debit Note")) + for tax in doc.get("taxes"): if tax.charge_type == "Actual": tax.tax_amount = -1 * tax.tax_amount - + doc.run_method("calculate_taxes_and_totals") - + def update_item(source_doc, target_doc, source_parent): target_doc.qty = -1* source_doc.qty if doctype == "Purchase Receipt": @@ -151,16 +155,18 @@ def make_return_doc(doctype, source_name, target_doc=None): target_doc.against_sales_invoice = source_doc.against_sales_invoice target_doc.so_detail = source_doc.so_detail target_doc.si_detail = source_doc.si_detail + target_doc.expense_account = source_doc.expense_account elif doctype == "Sales Invoice": target_doc.sales_order = source_doc.sales_order target_doc.delivery_note = source_doc.delivery_note target_doc.so_detail = source_doc.so_detail target_doc.dn_detail = source_doc.dn_detail + target_doc.expense_account = source_doc.expense_account doclist = get_mapped_doc(doctype, source_name, { doctype: { "doctype": doctype, - + "validation": { "docstatus": ["=", 1], } diff --git a/erpnext/controllers/status_updater.py b/erpnext/controllers/status_updater.py index c7d24396af..9c67e9a1b8 100644 --- a/erpnext/controllers/status_updater.py +++ b/erpnext/controllers/status_updater.py @@ -90,6 +90,10 @@ class StatusUpdater(Document): self.global_tolerance = None for args in self.status_updater: + if "target_ref_field" not in args: + # if target_ref_field is not specified, the programmer does not want to validate qty / amount + continue + # get unique transactions to update for d in self.get_all_children(): if d.doctype == args['source_dt'] and d.get(args["join_field"]): @@ -140,8 +144,9 @@ class StatusUpdater(Document): .format(_(item["target_ref_field"].title()), item["reduce_by"])) def update_qty(self, change_modified=True): - """ - Updates qty at row level + """Updates qty or amount at row level + + :param change_modified: If true, updates `modified` and `modified_by` for target parent doc """ for args in self.status_updater: # condition to include current record (if submit or no if cancel) @@ -150,58 +155,74 @@ class StatusUpdater(Document): else: args['cond'] = ' and parent!="%s"' % self.name.replace('"', '\"') - args['modified_cond'] = '' + args['set_modified'] = '' if change_modified: - args['modified_cond'] = ', modified = now()' + args['set_modified'] = ', modified = now(), modified_by = "{0}"'\ + .format(frappe.db.escape(frappe.session.user)) - # update quantities in child table - for d in self.get_all_children(): - if d.doctype == args['source_dt']: - # updates qty in the child table - args['detail_id'] = d.get(args['join_field']) + self._update_children(args) - args['second_source_condition'] = "" - if args.get('second_source_dt') and args.get('second_source_field') \ - and args.get('second_join_field'): - if not args.get("second_source_extra_cond"): - args["second_source_extra_cond"] = "" + if "percent_join_field" in args: + self._update_percent_field(args) - args['second_source_condition'] = """ + ifnull((select sum(%(second_source_field)s) - from `tab%(second_source_dt)s` - where `%(second_join_field)s`="%(detail_id)s" - and (`tab%(second_source_dt)s`.docstatus=1) %(second_source_extra_cond)s), 0) """ % args + def _update_children(self, args): + """Update quantities or amount in child table""" + for d in self.get_all_children(): + if d.doctype != args['source_dt']: + continue - if args['detail_id']: - if not args.get("extra_cond"): args["extra_cond"] = "" + # updates qty in the child table + args['detail_id'] = d.get(args['join_field']) - frappe.db.sql("""update `tab%(target_dt)s` - set %(target_field)s = (select sum(%(source_field)s) - from `tab%(source_dt)s` where `%(join_field)s`="%(detail_id)s" - and (docstatus=1 %(cond)s) %(extra_cond)s) %(second_source_condition)s - where name='%(detail_id)s'""" % args) + args['second_source_condition'] = "" + if args.get('second_source_dt') and args.get('second_source_field') \ + and args.get('second_join_field'): + if not args.get("second_source_extra_cond"): + args["second_source_extra_cond"] = "" - # get unique transactions to update - for name in set([d.get(args['percent_join_field']) for d in self.get_all_children(args['source_dt'])]): - if name: - args['name'] = name + args['second_source_condition'] = """ + ifnull((select sum(%(second_source_field)s) + from `tab%(second_source_dt)s` + where `%(second_join_field)s`="%(detail_id)s" + and (`tab%(second_source_dt)s`.docstatus=1) %(second_source_extra_cond)s), 0) """ % args - # update percent complete in the parent table - if args.get('target_parent_field'): - frappe.db.sql("""update `tab%(target_parent_dt)s` - set %(target_parent_field)s = (select sum(if(%(target_ref_field)s > - ifnull(%(target_field)s, 0), %(target_field)s, - %(target_ref_field)s))/sum(%(target_ref_field)s)*100 - from `tab%(target_dt)s` where parent="%(name)s") %(modified_cond)s - where name='%(name)s'""" % args) + if args['detail_id']: + if not args.get("extra_cond"): args["extra_cond"] = "" - # update field - if args.get('status_field'): - frappe.db.sql("""update `tab%(target_parent_dt)s` - set %(status_field)s = if(ifnull(%(target_parent_field)s,0)<0.001, - 'Not %(keyword)s', if(%(target_parent_field)s>=99.99, - 'Fully %(keyword)s', 'Partly %(keyword)s')) - where name='%(name)s'""" % args) + frappe.db.sql("""update `tab%(target_dt)s` + set %(target_field)s = (select sum(%(source_field)s) + from `tab%(source_dt)s` where `%(join_field)s`="%(detail_id)s" + and (docstatus=1 %(cond)s) %(extra_cond)s) %(second_source_condition)s + where name='%(detail_id)s'""" % args) + def _update_percent_field(self, args): + """Update percent field in parent transaction""" + unique_transactions = set([d.get(args['percent_join_field']) for d in self.get_all_children(args['source_dt'])]) + + for name in unique_transactions: + if not name: + continue + + args['name'] = name + + # update percent complete in the parent table + if args.get('target_parent_field'): + frappe.db.sql("""update `tab%(target_parent_dt)s` + set %(target_parent_field)s = (select sum(if(%(target_ref_field)s > + ifnull(%(target_field)s, 0), %(target_field)s, + %(target_ref_field)s))/sum(%(target_ref_field)s)*100 + from `tab%(target_dt)s` where parent="%(name)s") %(set_modified)s + where name='%(name)s'""" % args) + + # update field + if args.get('status_field'): + frappe.db.sql("""update `tab%(target_parent_dt)s` + set %(status_field)s = if(ifnull(%(target_parent_field)s,0)<0.001, + 'Not %(keyword)s', if(%(target_parent_field)s>=99.99, + 'Fully %(keyword)s', 'Partly %(keyword)s')) + where name='%(name)s'""" % args) + + if args.get("set_modified"): + frappe.get_doc(args["target_parent_dt"], name).notify_modified() def update_billing_status_for_zero_amount_refdoc(self, ref_dt): ref_fieldname = ref_dt.lower().replace(" ", "_") diff --git a/erpnext/patches.txt b/erpnext/patches.txt index ea10054d52..80518410cb 100644 --- a/erpnext/patches.txt +++ b/erpnext/patches.txt @@ -191,6 +191,10 @@ erpnext.patches.v5_4.stock_entry_additional_costs erpnext.patches.v5_4.cleanup_journal_entry #2015-08-14 execute:frappe.db.sql("update `tabProduction Order` pro set description = (select description from tabItem where name=pro.production_item) where ifnull(description, '') = ''") erpnext.patches.v5_7.item_template_attributes +execute:frappe.delete_doc_if_exists("DocType", "Manage Variants") +execute:frappe.delete_doc_if_exists("DocType", "Manage Variants Item") erpnext.patches.v4_2.repost_reserved_qty #2015-08-20 erpnext.patches.v5_4.update_purchase_cost_against_project -erpnext.patches.v5_7.update_order_reference_in_return_entries \ No newline at end of file +erpnext.patches.v5_8.update_order_reference_in_return_entries +erpnext.patches.v5_8.add_credit_note_print_heading +execute:frappe.delete_doc_if_exists("Print Format", "Credit Note - Negative Invoice") diff --git a/erpnext/patches/v5_7/item_template_attributes.py b/erpnext/patches/v5_7/item_template_attributes.py index e93bfe45a4..c0e68516cf 100644 --- a/erpnext/patches/v5_7/item_template_attributes.py +++ b/erpnext/patches/v5_7/item_template_attributes.py @@ -55,9 +55,6 @@ def migrate_manage_variants(): template.set('attributes', attributes) template.save() - frappe.delete_doc("DocType", "Manage Variants") - frappe.delete_doc("DocType", "Manage Variants Item") - # patch old style def migrate_item_variants(): for item in frappe.get_all("Item", filters={"has_variants": 1}): diff --git a/erpnext/patches/v5_8/__init__.py b/erpnext/patches/v5_8/__init__.py new file mode 100644 index 0000000000..baffc48825 --- /dev/null +++ b/erpnext/patches/v5_8/__init__.py @@ -0,0 +1 @@ +from __future__ import unicode_literals diff --git a/erpnext/patches/v5_8/add_credit_note_print_heading.py b/erpnext/patches/v5_8/add_credit_note_print_heading.py new file mode 100644 index 0000000000..476cbc8956 --- /dev/null +++ b/erpnext/patches/v5_8/add_credit_note_print_heading.py @@ -0,0 +1,14 @@ +# Copyright (c) 2013, Web Notes Technologies Pvt. Ltd. and Contributors +# License: GNU General Public License v3. See license.txt + +from __future__ import unicode_literals +import frappe +from frappe import _ + +def execute(): + for print_heading in (_("Credit Note"), _("Debit Note")): + if not frappe.db.exists("Print Heading", print_heading): + frappe.get_doc({ + "doctype": "Print Heading", + "print_heading": print_heading + }).insert() diff --git a/erpnext/patches/v5_7/update_order_reference_in_return_entries.py b/erpnext/patches/v5_8/update_order_reference_in_return_entries.py similarity index 66% rename from erpnext/patches/v5_7/update_order_reference_in_return_entries.py rename to erpnext/patches/v5_8/update_order_reference_in_return_entries.py index c957242260..c6cfceb6da 100644 --- a/erpnext/patches/v5_7/update_order_reference_in_return_entries.py +++ b/erpnext/patches/v5_8/update_order_reference_in_return_entries.py @@ -7,43 +7,50 @@ import frappe def execute(): # sales return return_entries = list(frappe.db.sql(""" - select dn.name as name, dn_item.name as row_id, dn.return_against, + select dn.name as name, dn_item.name as row_id, dn.return_against, dn_item.item_code, "Delivery Note" as doctype from `tabDelivery Note Item` dn_item, `tabDelivery Note` dn where dn_item.parent=dn.name and dn.is_return=1 and dn.docstatus < 2 """, as_dict=1)) - + return_entries += list(frappe.db.sql(""" - select si.name as name, si_item.name as row_id, si.return_against, - si_item.item_code, "Sales Invoice" as doctype + select si.name as name, si_item.name as row_id, si.return_against, + si_item.item_code, "Sales Invoice" as doctype, update_stock from `tabSales Invoice Item` si_item, `tabSales Invoice` si - where si_item.parent=si.name and si.is_return=1 and si.update_stock=1 and si.docstatus < 2 + where si_item.parent=si.name and si.is_return=1 and si.docstatus < 2 """, as_dict=1)) - + for d in return_entries: ref_field = "against_sales_order" if d.doctype == "Delivery Note" else "sales_order" order_details = frappe.db.sql(""" - select {0} as sales_order, so_detail - from `tab{1} Item` item - where - parent=%s and item_code=%s + select {ref_field} as sales_order, so_detail, + (select transaction_date from `tabSales Order` where name=item.{ref_field}) as sales_order_date + from `tab{doctype} Item` item + where + parent=%s + and item_code=%s and ifnull(so_detail, '') !='' - order by - (select transaction_date from `tabSales Order` where name=item.{3}) DESC - """.format(ref_field, d.doctype, ref_field, ref_field), (d.return_against, d.item_code), as_dict=1) - + order by sales_order_date DESC limit 1 + """.format(ref_field=ref_field, doctype=d.doctype), (d.return_against, d.item_code), as_dict=1) + if order_details: frappe.db.sql(""" - update `tab{0} Item` - set {1}=%s, so_detail=%s + update `tab{doctype} Item` + set {ref_field}=%s, so_detail=%s where name=%s - """.format(d.doctype, ref_field), + """.format(doctype=d.doctype, ref_field=ref_field), (order_details[0].sales_order, order_details[0].so_detail, d.row_id)) - - doc = frappe.get_doc(d.doctype, d.name) - doc.update_reserved_qty() - - + + if (d.doctype=="Sales Invoice" and d.update_stock) or d.doctype=="Delivery Note": + doc = frappe.get_doc(d.doctype, d.name) + doc.update_reserved_qty() + + if d.doctype=="Sales Invoice": + doc.status_updater = [] + doc.update_status_updater_args() + + doc.update_prevdoc_status() + #-------------------------- # purchase return return_entries = frappe.db.sql(""" @@ -51,26 +58,28 @@ def execute(): from `tabPurchase Receipt Item` pr_item, `tabPurchase Receipt` pr where pr_item.parent=pr.name and pr.is_return=1 and pr.docstatus < 2 """, as_dict=1) - + for d in return_entries: order_details = frappe.db.sql(""" - select prevdoc_docname as purchase_order, prevdoc_detail_docname as po_detail + select prevdoc_docname as purchase_order, prevdoc_detail_docname as po_detail, + (select transaction_date from `tabPurchase Order` where name=item.prevdoc_detail_docname) as purchase_order_date from `tabPurchase Receipt Item` item - where - parent=%s and item_code=%s - and ifnull(prevdoc_detail_docname, '') !='' + where + parent=%s + and item_code=%s + and ifnull(prevdoc_detail_docname, '') !='' and ifnull(prevdoc_doctype, '') = 'Purchase Order' and ifnull(prevdoc_detail_docname, '') != '' - order by - (select transaction_date from `tabPurchase Order` where name=item.prevdoc_detail_docname) DESC + order by purchase_order_date DESC limit 1 """, (d.return_against, d.item_code), as_dict=1) - + if order_details: frappe.db.sql(""" update `tabPurchase Receipt Item` set prevdoc_doctype='Purchase Order', prevdoc_docname=%s, prevdoc_detail_docname=%s where name=%s """, (order_details[0].purchase_order, order_details[0].po_detail, d.row_id)) - + pr = frappe.get_doc("Purchase Receipt", d.name) pr.update_ordered_qty() - \ No newline at end of file + pr.update_prevdoc_status() + diff --git a/erpnext/public/js/controllers/transaction.js b/erpnext/public/js/controllers/transaction.js index ba10702bd9..66794c90af 100644 --- a/erpnext/public/js/controllers/transaction.js +++ b/erpnext/public/js/controllers/transaction.js @@ -88,6 +88,7 @@ erpnext.TransactionController = erpnext.taxes_and_totals.extend({ this.set_dynamic_labels(); erpnext.pos.make_pos_btn(this.frm); this.setup_sms(); + this.make_show_payments_btn(); }, apply_default_taxes: function() { @@ -123,6 +124,22 @@ erpnext.TransactionController = erpnext.taxes_and_totals.extend({ var sms_man = new SMSManager(this.frm.doc); }, + make_show_payments_btn: function() { + var me = this; + if (in_list(["Purchase Invoice", "Sales Invoice"], this.frm.doctype)) { + if(this.frm.doc.outstanding_amount !== this.frm.doc.base_grand_total) { + this.frm.add_custom_button(__("Show Payments"), function() { + frappe.route_options = { + "Journal Entry Account.reference_type": me.frm.doc.doctype, + "Journal Entry Account.reference_name": me.frm.doc.name + }; + + frappe.set_route("List", "Journal Entry"); + }); + } + } + }, + hide_currency_and_price_list: function() { if(this.frm.doc.conversion_rate == 1 && this.frm.doc.docstatus > 0) { hide_field("currency_and_price_list"); diff --git a/erpnext/selling/doctype/sales_order_item/sales_order_item.json b/erpnext/selling/doctype/sales_order_item/sales_order_item.json index 0d0d50dc33..af80617824 100644 --- a/erpnext/selling/doctype/sales_order_item/sales_order_item.json +++ b/erpnext/selling/doctype/sales_order_item/sales_order_item.json @@ -840,6 +840,27 @@ "unique": 0, "width": "100px" }, + { + "allow_on_submit": 0, + "depends_on": "returned_qty", + "fieldname": "returned_qty", + "fieldtype": "Float", + "hidden": 0, + "ignore_user_permissions": 0, + "in_filter": 0, + "in_list_view": 0, + "label": "Returned Qty", + "no_copy": 1, + "permlevel": 0, + "precision": "", + "print_hide": 1, + "read_only": 1, + "report_hide": 0, + "reqd": 0, + "search_index": 0, + "set_only_once": 0, + "unique": 0 + }, { "allow_on_submit": 0, "fieldname": "billed_amt", @@ -960,7 +981,7 @@ "is_submittable": 0, "issingle": 0, "istable": 1, - "modified": "2015-08-19 12:46:32.930498", + "modified": "2015-08-25 06:42:11.062909", "modified_by": "Administrator", "module": "Selling", "name": "Sales Order Item", diff --git a/erpnext/setup/page/setup_wizard/install_fixtures.py b/erpnext/setup/page/setup_wizard/install_fixtures.py index dd3ec3a2e6..6ecd9ffa77 100644 --- a/erpnext/setup/page/setup_wizard/install_fixtures.py +++ b/erpnext/setup/page/setup_wizard/install_fixtures.py @@ -41,15 +41,15 @@ def install(country=None): {'doctype': 'Expense Claim Type', 'name': _('Travel'), 'expense_type': _('Travel')}, # leave type - {'doctype': 'Leave Type', 'leave_type_name': _('Casual Leave'), 'name': _('Casual Leave'), + {'doctype': 'Leave Type', 'leave_type_name': _('Casual Leave'), 'name': _('Casual Leave'), 'is_encash': 1, 'is_carry_forward': 1, 'max_days_allowed': '3', 'include_holiday': 1}, - {'doctype': 'Leave Type', 'leave_type_name': _('Compensatory Off'), 'name': _('Compensatory Off'), + {'doctype': 'Leave Type', 'leave_type_name': _('Compensatory Off'), 'name': _('Compensatory Off'), 'is_encash': 0, 'is_carry_forward': 0, 'include_holiday': 1}, - {'doctype': 'Leave Type', 'leave_type_name': _('Sick Leave'), 'name': _('Sick Leave'), + {'doctype': 'Leave Type', 'leave_type_name': _('Sick Leave'), 'name': _('Sick Leave'), 'is_encash': 0, 'is_carry_forward': 0, 'include_holiday': 1}, - {'doctype': 'Leave Type', 'leave_type_name': _('Privilege Leave'), 'name': _('Privilege Leave'), + {'doctype': 'Leave Type', 'leave_type_name': _('Privilege Leave'), 'name': _('Privilege Leave'), 'is_encash': 0, 'is_carry_forward': 0, 'include_holiday': 1}, - {'doctype': 'Leave Type', 'leave_type_name': _('Leave Without Pay'), 'name': _('Leave Without Pay'), + {'doctype': 'Leave Type', 'leave_type_name': _('Leave Without Pay'), 'name': _('Leave Without Pay'), 'is_encash': 0, 'is_carry_forward': 0, 'is_lwp':1, 'include_holiday': 1}, # Employment Type @@ -173,6 +173,8 @@ def install(country=None): {"doctype": "Offer Term", "offer_term": _("Notice Period")}, {"doctype": "Offer Term", "offer_term": _("Incentives")}, + {'doctype': "Print Heading", 'print_heading': _("Credit Note")}, + {'doctype': "Print Heading", 'print_heading': _("Debit Note")} ] from erpnext.setup.page.setup_wizard.fixtures import industry_type diff --git a/erpnext/stock/doctype/delivery_note/delivery_note.py b/erpnext/stock/doctype/delivery_note/delivery_note.py index 201546e457..1ac1cf47fe 100644 --- a/erpnext/stock/doctype/delivery_note/delivery_note.py +++ b/erpnext/stock/doctype/delivery_note/delivery_note.py @@ -47,6 +47,19 @@ class DeliveryNote(SellingController): 'source_field': 'qty', 'percent_join_field': 'against_sales_invoice', 'overflow_type': 'delivery' + }, + { + 'source_dt': 'Delivery Note Item', + 'target_dt': 'Sales Order Item', + 'join_field': 'so_detail', + 'target_field': 'returned_qty', + 'target_parent_dt': 'Sales Order', + # 'target_parent_field': 'per_delivered', + # 'target_ref_field': 'qty', + 'source_field': '-1 * qty', + # 'percent_join_field': 'against_sales_order', + # 'overflow_type': 'delivery', + 'extra_cond': """ and exists (select name from `tabDelivery Note` where name=`tabDelivery Note Item`.parent and is_return=1)""" }] def onload(self): @@ -118,7 +131,7 @@ class DeliveryNote(SellingController): }, }) - if cint(frappe.db.get_single_value('Selling Settings', 'maintain_same_sales_rate')): + if cint(frappe.db.get_single_value('Selling Settings', 'maintain_same_sales_rate')) and not self.is_return: self.validate_rate_with_reference_doc([["Sales Order", "sales_order", "so_detail"], ["Sales Invoice", "sales_invoice", "si_detail"]]) @@ -176,7 +189,7 @@ class DeliveryNote(SellingController): # update delivered qty in sales order self.update_prevdoc_status() - + if not self.is_return: self.check_credit_limit() @@ -354,8 +367,8 @@ def make_packing_slip(source_name, target_doc=None): return doclist - + @frappe.whitelist() def make_sales_return(source_name, target_doc=None): from erpnext.controllers.sales_and_purchase_return import make_return_doc - return make_return_doc("Delivery Note", source_name, target_doc) \ No newline at end of file + return make_return_doc("Delivery Note", source_name, target_doc) diff --git a/erpnext/stock/doctype/delivery_note/delivery_note_list.js b/erpnext/stock/doctype/delivery_note/delivery_note_list.js index dce6863441..d79015e566 100644 --- a/erpnext/stock/doctype/delivery_note/delivery_note_list.js +++ b/erpnext/stock/doctype/delivery_note/delivery_note_list.js @@ -3,7 +3,7 @@ frappe.listview_settings['Delivery Note'] = { "transporter_name", "grand_total", "is_return"], get_indicator: function(doc) { if(cint(doc.is_return)==1) { - return [__("Return"), "darkgrey", "is_return,=,1"]; + return [__("Return"), "darkgrey", "is_return,=,Yes"]; } } }; diff --git a/erpnext/stock/doctype/delivery_note_item/delivery_note_item.json b/erpnext/stock/doctype/delivery_note_item/delivery_note_item.json index 18138c003a..e764b6ab9b 100644 --- a/erpnext/stock/doctype/delivery_note_item/delivery_note_item.json +++ b/erpnext/stock/doctype/delivery_note_item/delivery_note_item.json @@ -912,7 +912,7 @@ "in_filter": 0, "in_list_view": 1, "label": "Against Sales Order", - "no_copy": 0, + "no_copy": 1, "options": "Sales Order", "permlevel": 0, "print_hide": 1, @@ -932,7 +932,7 @@ "in_filter": 0, "in_list_view": 0, "label": "Against Sales Invoice", - "no_copy": 0, + "no_copy": 1, "options": "Sales Invoice", "permlevel": 0, "print_hide": 1, @@ -1039,7 +1039,7 @@ "is_submittable": 0, "issingle": 0, "istable": 1, - "modified": "2015-08-19 12:46:31.447022", + "modified": "2015-08-25 07:15:19.811365", "modified_by": "Administrator", "module": "Stock", "name": "Delivery Note Item", diff --git a/erpnext/stock/doctype/purchase_receipt/purchase_receipt.py b/erpnext/stock/doctype/purchase_receipt/purchase_receipt.py index f4273b27ed..58f165c040 100644 --- a/erpnext/stock/doctype/purchase_receipt/purchase_receipt.py +++ b/erpnext/stock/doctype/purchase_receipt/purchase_receipt.py @@ -29,6 +29,19 @@ class PurchaseReceipt(BuyingController): 'source_field': 'qty', 'percent_join_field': 'prevdoc_docname', 'overflow_type': 'receipt' + }, + { + 'source_dt': 'Purchase Receipt Item', + 'target_dt': 'Purchase Order Item', + 'join_field': 'prevdoc_detail_docname', + 'target_field': 'returned_qty', + 'target_parent_dt': 'Purchase Order', + # 'target_parent_field': 'per_received', + # 'target_ref_field': 'qty', + 'source_field': '-1 * qty', + # 'percent_join_field': 'prevdoc_docname', + # 'overflow_type': 'receipt', + 'extra_cond': """ and exists (select name from `tabPurchase Receipt` where name=`tabPurchase Receipt Item`.parent and is_return=1)""" }] def onload(self): @@ -68,12 +81,12 @@ class PurchaseReceipt(BuyingController): from `tabLanded Cost Item` where docstatus = 1 and purchase_receipt_item = %s""", d.name) d.landed_cost_voucher_amount = lc_voucher_amount[0][0] if lc_voucher_amount else 0.0 - + def validate_purchase_return(self): for d in self.get("items"): if self.is_return and flt(d.rejected_qty) != 0: frappe.throw(_("Row #{0}: Rejected Qty can not be entered in Purchase Return").format(d.idx)) - + # validate rate with ref PR def validate_rejected_warehouse(self): @@ -113,7 +126,7 @@ class PurchaseReceipt(BuyingController): } }) - if cint(frappe.db.get_single_value('Buying Settings', 'maintain_same_rate')): + if cint(frappe.db.get_single_value('Buying Settings', 'maintain_same_rate')) and not self.is_return: self.validate_rate_with_reference_doc([["Purchase Order", "prevdoc_docname", "prevdoc_detail_docname"]]) def po_required(self): @@ -223,7 +236,7 @@ class PurchaseReceipt(BuyingController): self.update_prevdoc_status() self.update_ordered_qty() - + if not self.is_return: purchase_controller.update_last_purchase_rate(self, 1) @@ -261,7 +274,7 @@ class PurchaseReceipt(BuyingController): self.update_prevdoc_status() # Must be called after updating received qty in PO self.update_ordered_qty() - + if not self.is_return: pc_obj.update_last_purchase_rate(self, 0) @@ -291,7 +304,7 @@ class PurchaseReceipt(BuyingController): if warehouse_account.get(d.warehouse): val_rate_db_precision = 6 if cint(d.precision("valuation_rate")) <= 6 else 9 - + # warehouse account gl_entries.append(self.get_gl_dict({ "account": warehouse_account[d.warehouse], @@ -466,4 +479,4 @@ def get_invoiced_qty_map(purchase_receipt): @frappe.whitelist() def make_purchase_return(source_name, target_doc=None): from erpnext.controllers.sales_and_purchase_return import make_return_doc - return make_return_doc("Purchase Receipt", source_name, target_doc) \ No newline at end of file + return make_return_doc("Purchase Receipt", source_name, target_doc) diff --git a/erpnext/stock/doctype/purchase_receipt/purchase_receipt_list.js b/erpnext/stock/doctype/purchase_receipt/purchase_receipt_list.js index 64d5456bfe..838fbb03a1 100644 --- a/erpnext/stock/doctype/purchase_receipt/purchase_receipt_list.js +++ b/erpnext/stock/doctype/purchase_receipt/purchase_receipt_list.js @@ -3,7 +3,7 @@ frappe.listview_settings['Purchase Receipt'] = { "transporter_name", "is_return"], get_indicator: function(doc) { if(cint(doc.is_return)==1) { - return [__("Return"), "darkgrey", "is_return,=,1"]; + return [__("Return"), "darkgrey", "is_return,=,Yes"]; } } }; diff --git a/erpnext/stock/doctype/serial_no/serial_no.py b/erpnext/stock/doctype/serial_no/serial_no.py index fb15195291..0df0ba2a52 100644 --- a/erpnext/stock/doctype/serial_no/serial_no.py +++ b/erpnext/stock/doctype/serial_no/serial_no.py @@ -33,7 +33,7 @@ class SerialNo(StockController): self.validate_warehouse() self.validate_item() self.on_stock_ledger_entry() - + def set_maintenance_status(self): if not self.warranty_expiry_date and not self.amc_expiry_date: self.maintenance_status = None @@ -209,7 +209,7 @@ def validate_serial_no(sle, item_det): frappe.throw(_("Serial No {0} quantity {1} cannot be a fraction").format(sle.item_code, sle.actual_qty)) if len(serial_nos) and len(serial_nos) != abs(cint(sle.actual_qty)): - frappe.throw(_("{0} Serial Numbers required for Item {0}. Only {0} provided.").format(sle.actual_qty, sle.item_code, len(serial_nos)), + frappe.throw(_("{0} Serial Numbers required for Item {1}. You have provided {2}.").format(sle.actual_qty, sle.item_code, len(serial_nos)), SerialNoQtyError) if len(serial_nos) != len(set(serial_nos)): diff --git a/erpnext/stock/get_item_details.py b/erpnext/stock/get_item_details.py index d08c63c255..0cec77b4ef 100644 --- a/erpnext/stock/get_item_details.py +++ b/erpnext/stock/get_item_details.py @@ -257,6 +257,10 @@ def validate_price_list(args): def validate_conversion_rate(args, meta): from erpnext.controllers.accounts_controller import validate_conversion_rate + if (not args.conversion_rate + and args.currency==frappe.db.get_value("Company", args.company, "default_currency")): + args.conversion_rate = 1.0 + # validate currency conversion rate validate_conversion_rate(args.currency, args.conversion_rate, meta.get_label("conversion_rate"), args.company) From b6398be232067a6507588c8f355fe7b1d36601e2 Mon Sep 17 00:00:00 2001 From: Rushabh Mehta Date: Wed, 26 Aug 2015 10:50:16 +0530 Subject: [PATCH 16/21] [minor] [fix] project query --- erpnext/controllers/queries.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/erpnext/controllers/queries.py b/erpnext/controllers/queries.py index 801f6f28ed..04c12f7803 100644 --- a/erpnext/controllers/queries.py +++ b/erpnext/controllers/queries.py @@ -205,10 +205,10 @@ def get_project_name(doctype, txt, searchfield, start, page_len, filters): return frappe.db.sql("""select `tabProject`.name from `tabProject` where `tabProject`.status not in ("Completed", "Cancelled") - and %(cond)s `tabProject`.name like "%(txt)s" %(mcond)s + and {cond} `tabProject`.name like %s {match_cond} order by `tabProject`.name asc - limit %(start)s, %(page_len)s """ % {'cond': cond,'txt': "%%%s%%" % frappe.db.escape(txt), - 'mcond':get_match_cond(doctype),'start': start, 'page_len': page_len}) + limit {start}, {page_len}""".format(cond=cond, match_cond=get_match_cond(doctype), + start=start, page_len=page_len), "%{0}%".format(txt)) def get_delivery_notes_to_be_billed(doctype, txt, searchfield, start, page_len, filters): return frappe.db.sql("""select `tabDelivery Note`.name, `tabDelivery Note`.customer_name @@ -232,7 +232,7 @@ def get_batch_no(doctype, txt, searchfield, start, page_len, filters): cond = "" if filters.get("posting_date"): cond = "and (ifnull(batch.expiry_date, '')='' or batch.expiry_date >= %(posting_date)s)" - + batch_nos = None args = { 'item_code': filters.get("item_code"), From 755f1f68419c8e44a5e16460613e698104296a84 Mon Sep 17 00:00:00 2001 From: Neil Trini Lasrado Date: Wed, 26 Aug 2015 12:59:29 +0530 Subject: [PATCH 17/21] Fixed validation to prevent duplication of Item Variants in case of Numeric Attributes --- erpnext/stock/doctype/item/item.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/erpnext/stock/doctype/item/item.py b/erpnext/stock/doctype/item/item.py index 08350afa72..d445582f72 100644 --- a/erpnext/stock/doctype/item/item.py +++ b/erpnext/stock/doctype/item/item.py @@ -572,7 +572,7 @@ def find_variant(item, args): for attribute, value in args.items(): for row in variant.attributes: - if row.attribute==attribute and row.attribute_value==value: + if row.attribute==attribute and row.attribute_value== cstr(value): # this row matches match_count += 1 break From cb3a4caa445a8eac904b72ab52b2c97ff3205546 Mon Sep 17 00:00:00 2001 From: Anand Doshi Date: Wed, 26 Aug 2015 14:48:58 +0530 Subject: [PATCH 18/21] [fix] removed validate due date in Journal Entry --- .../doctype/journal_entry/journal_entry.py | 15 --------------- 1 file changed, 15 deletions(-) diff --git a/erpnext/accounts/doctype/journal_entry/journal_entry.py b/erpnext/accounts/doctype/journal_entry/journal_entry.py index 4b25a88112..f5f22dccac 100644 --- a/erpnext/accounts/doctype/journal_entry/journal_entry.py +++ b/erpnext/accounts/doctype/journal_entry/journal_entry.py @@ -32,7 +32,6 @@ class JournalEntry(AccountsController): self.set_against_account() self.create_remarks() self.set_print_format_fields() - self.check_due_date() self.validate_expense_claim() self.validate_credit_debit_note() self.validate_empty_accounts_table() @@ -83,20 +82,6 @@ class JournalEntry(AccountsController): for customer in customers: check_credit_limit(customer, self.company) - def check_due_date(self): - if self.cheque_date: - for d in self.get("accounts"): - if d.party_type and d.party and d.get("credit" if d.party_type=="Customer" else "debit") > 0: - due_date = None - if d.reference_type in ("Sales Invoice", "Purchase Invoice"): - due_date = frappe.db.get_value(d.reference_type, d.reference_name, "due_date") - - if due_date and getdate(self.cheque_date) > getdate(due_date): - diff = date_diff(self.cheque_date, due_date) - if diff > 0: - msgprint(_("Note: Reference Date exceeds invoice due date by {0} days for {1} {2}") - .format(diff, d.party_type, d.party)) - def validate_cheque_info(self): if self.voucher_type in ['Bank Entry']: if not self.cheque_no or not self.cheque_date: From f29628072fa67fe6b4ec417eae95f01199cd9d6d Mon Sep 17 00:00:00 2001 From: Anand Doshi Date: Wed, 26 Aug 2015 14:49:14 +0530 Subject: [PATCH 19/21] [change-log] --- .../{current/sales_purchase_return.md => v5/v5_8_0.md} | 2 ++ 1 file changed, 2 insertions(+) rename erpnext/change_log/{current/sales_purchase_return.md => v5/v5_8_0.md} (51%) diff --git a/erpnext/change_log/current/sales_purchase_return.md b/erpnext/change_log/v5/v5_8_0.md similarity index 51% rename from erpnext/change_log/current/sales_purchase_return.md rename to erpnext/change_log/v5/v5_8_0.md index 0152d57855..239731ab54 100644 --- a/erpnext/change_log/current/sales_purchase_return.md +++ b/erpnext/change_log/v5/v5_8_0.md @@ -1,3 +1,5 @@ - Fixes in Sales and Purchase Return - Update Delivered, Ordered and Returned Quantity based on Return transaction - Allow different Rate in Return transaction +- Set default Finished Goods and Work-in-Progress Warehouse in Manufacturing Settings +- Fixed range validation for numeric attributes in Item Variants From 7fa8fb984e12c40f83e99ebc96a3e37064fb098f Mon Sep 17 00:00:00 2001 From: Anand Doshi Date: Wed, 26 Aug 2015 16:48:41 +0530 Subject: [PATCH 20/21] [fix] Show write off account --- .../doctype/sales_invoice/sales_invoice.json | 1597 +++++++++++++++-- 1 file changed, 1477 insertions(+), 120 deletions(-) diff --git a/erpnext/accounts/doctype/sales_invoice/sales_invoice.json b/erpnext/accounts/doctype/sales_invoice/sales_invoice.json index cd70a46c5d..a2944ad978 100644 --- a/erpnext/accounts/doctype/sales_invoice/sales_invoice.json +++ b/erpnext/accounts/doctype/sales_invoice/sales_invoice.json @@ -1,22 +1,43 @@ { + "allow_copy": 0, "allow_import": 1, + "allow_rename": 0, "autoname": "naming_series:", "creation": "2013-05-24 19:29:05", + "custom": 0, "default_print_format": "Standard", "docstatus": 0, "doctype": "DocType", - "document_type": "Transaction", + "document_type": "Document", "fields": [ { + "allow_on_submit": 0, "fieldname": "customer_section", "fieldtype": "Section Break", + "hidden": 0, + "ignore_user_permissions": 0, + "in_filter": 0, + "in_list_view": 0, "label": "", + "no_copy": 0, "options": "icon-user", - "permlevel": 0 + "permlevel": 0, + "print_hide": 0, + "read_only": 0, + "report_hide": 0, + "reqd": 0, + "search_index": 0, + "set_only_once": 0, + "unique": 0 }, { + "allow_on_submit": 0, "fieldname": "naming_series", "fieldtype": "Select", + "hidden": 0, + "ignore_user_permissions": 0, + "in_filter": 0, + "in_list_view": 0, "label": "Series", "no_copy": 1, "oldfieldname": "naming_series", @@ -25,12 +46,20 @@ "permlevel": 0, "print_hide": 1, "read_only": 0, - "reqd": 1 + "report_hide": 0, + "reqd": 1, + "search_index": 0, + "set_only_once": 0, + "unique": 0 }, { + "allow_on_submit": 0, "fieldname": "customer", "fieldtype": "Link", "hidden": 0, + "ignore_user_permissions": 0, + "in_filter": 0, + "in_list_view": 0, "label": "Customer", "no_copy": 0, "oldfieldname": "customer", @@ -39,89 +68,181 @@ "permlevel": 0, "print_hide": 1, "read_only": 0, - "search_index": 1 + "report_hide": 0, + "reqd": 0, + "search_index": 1, + "set_only_once": 0, + "unique": 0 }, { + "allow_on_submit": 0, "depends_on": "customer", "fieldname": "customer_name", "fieldtype": "Data", "hidden": 0, + "ignore_user_permissions": 0, + "in_filter": 0, "in_list_view": 0, "label": "Customer Name", + "no_copy": 0, "oldfieldname": "customer_name", "oldfieldtype": "Data", "permlevel": 0, - "read_only": 1 + "print_hide": 0, + "read_only": 1, + "report_hide": 0, + "reqd": 0, + "search_index": 0, + "set_only_once": 0, + "unique": 0 }, { + "allow_on_submit": 0, "fieldname": "address_display", "fieldtype": "Small Text", "hidden": 1, + "ignore_user_permissions": 0, + "in_filter": 0, + "in_list_view": 0, "label": "Address", + "no_copy": 0, "permlevel": 0, - "read_only": 1 + "print_hide": 0, + "read_only": 1, + "report_hide": 0, + "reqd": 0, + "search_index": 0, + "set_only_once": 0, + "unique": 0 }, { + "allow_on_submit": 0, "fieldname": "contact_display", "fieldtype": "Small Text", "hidden": 1, + "ignore_user_permissions": 0, + "in_filter": 0, + "in_list_view": 0, "label": "Contact", + "no_copy": 0, "permlevel": 0, - "read_only": 1 + "print_hide": 0, + "read_only": 1, + "report_hide": 0, + "reqd": 0, + "search_index": 0, + "set_only_once": 0, + "unique": 0 }, { + "allow_on_submit": 0, "fieldname": "contact_mobile", "fieldtype": "Small Text", "hidden": 1, + "ignore_user_permissions": 0, + "in_filter": 0, + "in_list_view": 0, "label": "Mobile No", + "no_copy": 0, "permlevel": 0, - "read_only": 1 + "print_hide": 0, + "read_only": 1, + "report_hide": 0, + "reqd": 0, + "search_index": 0, + "set_only_once": 0, + "unique": 0 }, { + "allow_on_submit": 0, "fieldname": "contact_email", "fieldtype": "Small Text", "hidden": 1, + "ignore_user_permissions": 0, + "in_filter": 0, + "in_list_view": 0, "label": "Contact Email", + "no_copy": 0, "permlevel": 0, "print_hide": 1, - "read_only": 1 + "read_only": 1, + "report_hide": 0, + "reqd": 0, + "search_index": 0, + "set_only_once": 0, + "unique": 0 }, { + "allow_on_submit": 0, "fieldname": "mode_of_payment", "fieldtype": "Link", + "hidden": 0, + "ignore_user_permissions": 0, + "in_filter": 0, + "in_list_view": 0, "label": "Mode of Payment", "no_copy": 0, "oldfieldname": "mode_of_payment", "oldfieldtype": "Select", "options": "Mode of Payment", "permlevel": 0, - "read_only": 0 + "print_hide": 0, + "read_only": 0, + "report_hide": 0, + "reqd": 0, + "search_index": 0, + "set_only_once": 0, + "unique": 0 }, { + "allow_on_submit": 0, "fieldname": "column_break1", "fieldtype": "Column Break", + "hidden": 0, + "ignore_user_permissions": 0, + "in_filter": 0, + "in_list_view": 0, + "no_copy": 0, "oldfieldtype": "Column Break", "permlevel": 0, - "read_only": 0 + "print_hide": 0, + "read_only": 0, + "report_hide": 0, + "reqd": 0, + "search_index": 0, + "set_only_once": 0, + "unique": 0 }, { + "allow_on_submit": 0, "fieldname": "company", "fieldtype": "Link", + "hidden": 0, + "ignore_user_permissions": 0, "in_filter": 1, + "in_list_view": 0, "label": "Company", + "no_copy": 0, "oldfieldname": "company", "oldfieldtype": "Link", "options": "Company", "permlevel": 0, "print_hide": 1, "read_only": 0, + "report_hide": 0, "reqd": 1, - "search_index": 0 + "search_index": 0, + "set_only_once": 0, + "unique": 0 }, { + "allow_on_submit": 0, "fieldname": "amended_from", "fieldtype": "Link", + "hidden": 0, "ignore_user_permissions": 1, + "in_filter": 0, + "in_list_view": 0, "label": "Amended From", "no_copy": 1, "oldfieldname": "amended_from", @@ -129,13 +250,22 @@ "options": "Sales Invoice", "permlevel": 0, "print_hide": 1, - "read_only": 1 + "read_only": 1, + "report_hide": 0, + "reqd": 0, + "search_index": 0, + "set_only_once": 0, + "unique": 0 }, { + "allow_on_submit": 0, "default": "Today", "fieldname": "posting_date", "fieldtype": "Date", + "hidden": 0, + "ignore_user_permissions": 0, "in_filter": 1, + "in_list_view": 0, "label": "Date", "no_copy": 1, "oldfieldname": "posting_date", @@ -143,498 +273,1068 @@ "permlevel": 0, "print_hide": 0, "read_only": 0, + "report_hide": 0, "reqd": 1, - "search_index": 1 + "search_index": 1, + "set_only_once": 0, + "unique": 0 }, { + "allow_on_submit": 0, "fieldname": "due_date", "fieldtype": "Date", + "hidden": 0, + "ignore_user_permissions": 0, "in_filter": 1, + "in_list_view": 0, "label": "Payment Due Date", "no_copy": 1, "oldfieldname": "due_date", "oldfieldtype": "Date", "permlevel": 0, + "print_hide": 0, "read_only": 0, + "report_hide": 0, "reqd": 0, - "search_index": 0 + "search_index": 0, + "set_only_once": 0, + "unique": 0 }, { + "allow_on_submit": 0, "fieldname": "is_pos", "fieldtype": "Check", + "hidden": 0, + "ignore_user_permissions": 0, + "in_filter": 0, + "in_list_view": 0, "label": "Is POS", + "no_copy": 0, "oldfieldname": "is_pos", "oldfieldtype": "Check", "permlevel": 0, "print_hide": 1, - "read_only": 0 + "read_only": 0, + "report_hide": 0, + "reqd": 0, + "search_index": 0, + "set_only_once": 0, + "unique": 0 }, { + "allow_on_submit": 0, "fieldname": "is_return", "fieldtype": "Check", + "hidden": 0, + "ignore_user_permissions": 0, + "in_filter": 0, + "in_list_view": 0, "label": "Is Return", "no_copy": 0, "permlevel": 0, "precision": "", "print_hide": 1, - "read_only": 1 + "read_only": 1, + "report_hide": 0, + "reqd": 0, + "search_index": 0, + "set_only_once": 0, + "unique": 0 }, { + "allow_on_submit": 0, "depends_on": "is_return", "fieldname": "return_against", "fieldtype": "Link", + "hidden": 0, + "ignore_user_permissions": 0, + "in_filter": 0, + "in_list_view": 0, "label": "Return Against Sales Invoice", "no_copy": 0, "options": "Sales Invoice", "permlevel": 0, "precision": "", "print_hide": 1, - "read_only": 1 + "read_only": 1, + "report_hide": 0, + "reqd": 0, + "search_index": 0, + "set_only_once": 0, + "unique": 0 }, { + "allow_on_submit": 0, "fieldname": "shipping_address_name", "fieldtype": "Link", "hidden": 1, + "ignore_user_permissions": 0, "in_filter": 1, + "in_list_view": 0, "label": "Shipping Address Name", + "no_copy": 0, "options": "Address", "permlevel": 0, "precision": "", - "print_hide": 1 + "print_hide": 1, + "read_only": 0, + "report_hide": 0, + "reqd": 0, + "search_index": 0, + "set_only_once": 0, + "unique": 0 }, { + "allow_on_submit": 0, "fieldname": "shipping_address", "fieldtype": "Small Text", "hidden": 1, + "ignore_user_permissions": 0, + "in_filter": 0, + "in_list_view": 0, "label": "Shipping Address", + "no_copy": 0, "permlevel": 0, "precision": "", "print_hide": 1, - "read_only": 1 + "read_only": 1, + "report_hide": 0, + "reqd": 0, + "search_index": 0, + "set_only_once": 0, + "unique": 0 }, { + "allow_on_submit": 0, "fieldname": "currency_and_price_list", "fieldtype": "Section Break", + "hidden": 0, + "ignore_user_permissions": 0, + "in_filter": 0, + "in_list_view": 0, "label": "", + "no_copy": 0, "options": "icon-tag", "permlevel": 0, - "read_only": 0 + "print_hide": 0, + "read_only": 0, + "report_hide": 0, + "reqd": 0, + "search_index": 0, + "set_only_once": 0, + "unique": 0 }, { + "allow_on_submit": 0, "fieldname": "currency", "fieldtype": "Link", + "hidden": 0, + "ignore_user_permissions": 0, + "in_filter": 0, + "in_list_view": 0, "label": "Currency", + "no_copy": 0, "oldfieldname": "currency", "oldfieldtype": "Select", "options": "Currency", "permlevel": 0, "print_hide": 1, "read_only": 0, - "reqd": 1 + "report_hide": 0, + "reqd": 1, + "search_index": 0, + "set_only_once": 0, + "unique": 0 }, { + "allow_on_submit": 0, "description": "Rate at which Customer Currency is converted to customer's base currency", "fieldname": "conversion_rate", "fieldtype": "Float", + "hidden": 0, + "ignore_user_permissions": 0, + "in_filter": 0, + "in_list_view": 0, "label": "Exchange Rate", + "no_copy": 0, "oldfieldname": "conversion_rate", "oldfieldtype": "Currency", "permlevel": 0, "precision": "9", "print_hide": 1, "read_only": 0, - "reqd": 1 + "report_hide": 0, + "reqd": 1, + "search_index": 0, + "set_only_once": 0, + "unique": 0 }, { + "allow_on_submit": 0, "fieldname": "column_break2", "fieldtype": "Column Break", + "hidden": 0, + "ignore_user_permissions": 0, + "in_filter": 0, + "in_list_view": 0, + "no_copy": 0, "permlevel": 0, + "print_hide": 0, "read_only": 0, + "report_hide": 0, + "reqd": 0, + "search_index": 0, + "set_only_once": 0, + "unique": 0, "width": "50%" }, { + "allow_on_submit": 0, "fieldname": "selling_price_list", "fieldtype": "Link", + "hidden": 0, + "ignore_user_permissions": 0, + "in_filter": 0, + "in_list_view": 0, "label": "Price List", + "no_copy": 0, "oldfieldname": "price_list_name", "oldfieldtype": "Select", "options": "Price List", "permlevel": 0, "print_hide": 1, "read_only": 0, - "reqd": 1 + "report_hide": 0, + "reqd": 1, + "search_index": 0, + "set_only_once": 0, + "unique": 0 }, { + "allow_on_submit": 0, "fieldname": "price_list_currency", "fieldtype": "Link", + "hidden": 0, + "ignore_user_permissions": 0, + "in_filter": 0, + "in_list_view": 0, "label": "Price List Currency", + "no_copy": 0, "options": "Currency", "permlevel": 0, "print_hide": 1, "read_only": 1, - "reqd": 1 + "report_hide": 0, + "reqd": 1, + "search_index": 0, + "set_only_once": 0, + "unique": 0 }, { + "allow_on_submit": 0, "description": "Rate at which Price list currency is converted to customer's base currency", "fieldname": "plc_conversion_rate", "fieldtype": "Float", + "hidden": 0, + "ignore_user_permissions": 0, + "in_filter": 0, + "in_list_view": 0, "label": "Price List Exchange Rate", "no_copy": 0, "permlevel": 0, "precision": "9", "print_hide": 1, "read_only": 0, - "reqd": 1 + "report_hide": 0, + "reqd": 1, + "search_index": 0, + "set_only_once": 0, + "unique": 0 }, { + "allow_on_submit": 0, "fieldname": "ignore_pricing_rule", "fieldtype": "Check", + "hidden": 0, + "ignore_user_permissions": 0, + "in_filter": 0, + "in_list_view": 0, "label": "Ignore Pricing Rule", "no_copy": 1, "permlevel": 1, - "print_hide": 1 + "print_hide": 1, + "read_only": 0, + "report_hide": 0, + "reqd": 0, + "search_index": 0, + "set_only_once": 0, + "unique": 0 }, { + "allow_on_submit": 0, "fieldname": "items_section", "fieldtype": "Section Break", + "hidden": 0, + "ignore_user_permissions": 0, + "in_filter": 0, + "in_list_view": 0, "label": "", + "no_copy": 0, "oldfieldtype": "Section Break", "options": "icon-shopping-cart", "permlevel": 0, - "read_only": 0 + "print_hide": 0, + "read_only": 0, + "report_hide": 0, + "reqd": 0, + "search_index": 0, + "set_only_once": 0, + "unique": 0 }, { + "allow_on_submit": 0, "fieldname": "update_stock", "fieldtype": "Check", + "hidden": 0, + "ignore_user_permissions": 0, + "in_filter": 0, + "in_list_view": 0, "label": "Update Stock", + "no_copy": 0, "oldfieldname": "update_stock", "oldfieldtype": "Check", "permlevel": 0, "print_hide": 1, - "read_only": 0 + "read_only": 0, + "report_hide": 0, + "reqd": 0, + "search_index": 0, + "set_only_once": 0, + "unique": 0 }, { "allow_on_submit": 1, "fieldname": "items", "fieldtype": "Table", + "hidden": 0, + "ignore_user_permissions": 0, + "in_filter": 0, + "in_list_view": 0, "label": "Items", + "no_copy": 0, "oldfieldname": "entries", "oldfieldtype": "Table", "options": "Sales Invoice Item", "permlevel": 0, + "print_hide": 0, "read_only": 0, - "reqd": 1 + "report_hide": 0, + "reqd": 1, + "search_index": 0, + "set_only_once": 0, + "unique": 0 }, { + "allow_on_submit": 0, "fieldname": "packing_list", "fieldtype": "Section Break", + "hidden": 0, + "ignore_user_permissions": 0, + "in_filter": 0, + "in_list_view": 0, "label": "Packing List", + "no_copy": 0, "options": "icon-suitcase", "permlevel": 0, "print_hide": 1, - "read_only": 0 + "read_only": 0, + "report_hide": 0, + "reqd": 0, + "search_index": 0, + "set_only_once": 0, + "unique": 0 }, { + "allow_on_submit": 0, "fieldname": "packed_items", "fieldtype": "Table", + "hidden": 0, + "ignore_user_permissions": 0, + "in_filter": 0, + "in_list_view": 0, "label": "Packed Items", + "no_copy": 0, "options": "Packed Item", "permlevel": 0, "print_hide": 1, - "read_only": 0 + "read_only": 0, + "report_hide": 0, + "reqd": 0, + "search_index": 0, + "set_only_once": 0, + "unique": 0 }, { + "allow_on_submit": 0, "fieldname": "product_bundle_help", "fieldtype": "HTML", + "hidden": 0, + "ignore_user_permissions": 0, + "in_filter": 0, + "in_list_view": 0, "label": "Product Bundle Help", + "no_copy": 0, "permlevel": 0, "print_hide": 1, - "read_only": 0 + "read_only": 0, + "report_hide": 0, + "reqd": 0, + "search_index": 0, + "set_only_once": 0, + "unique": 0 }, { + "allow_on_submit": 0, "fieldname": "section_break_30", "fieldtype": "Section Break", - "permlevel": 0 + "hidden": 0, + "ignore_user_permissions": 0, + "in_filter": 0, + "in_list_view": 0, + "no_copy": 0, + "permlevel": 0, + "print_hide": 0, + "read_only": 0, + "report_hide": 0, + "reqd": 0, + "search_index": 0, + "set_only_once": 0, + "unique": 0 }, { + "allow_on_submit": 0, "fieldname": "base_total", "fieldtype": "Currency", + "hidden": 0, + "ignore_user_permissions": 0, + "in_filter": 0, + "in_list_view": 0, "label": "Total (Company Currency)", + "no_copy": 0, "options": "Company:company:default_currency", "permlevel": 0, "precision": "", "print_hide": 1, - "read_only": 1 + "read_only": 1, + "report_hide": 0, + "reqd": 0, + "search_index": 0, + "set_only_once": 0, + "unique": 0 }, { + "allow_on_submit": 0, "fieldname": "base_net_total", "fieldtype": "Currency", + "hidden": 0, + "ignore_user_permissions": 0, + "in_filter": 0, + "in_list_view": 0, "label": "Net Total (Company Currency)", + "no_copy": 0, "oldfieldname": "net_total", "oldfieldtype": "Currency", "options": "Company:company:default_currency", "permlevel": 0, "print_hide": 1, "read_only": 1, - "reqd": 1 + "report_hide": 0, + "reqd": 1, + "search_index": 0, + "set_only_once": 0, + "unique": 0 }, { + "allow_on_submit": 0, "fieldname": "column_break_32", "fieldtype": "Column Break", - "permlevel": 0 + "hidden": 0, + "ignore_user_permissions": 0, + "in_filter": 0, + "in_list_view": 0, + "no_copy": 0, + "permlevel": 0, + "print_hide": 0, + "read_only": 0, + "report_hide": 0, + "reqd": 0, + "search_index": 0, + "set_only_once": 0, + "unique": 0 }, { + "allow_on_submit": 0, "fieldname": "total", "fieldtype": "Currency", + "hidden": 0, + "ignore_user_permissions": 0, + "in_filter": 0, + "in_list_view": 0, "label": "Total", + "no_copy": 0, "options": "currency", "permlevel": 0, "precision": "", "print_hide": 0, - "read_only": 1 + "read_only": 1, + "report_hide": 0, + "reqd": 0, + "search_index": 0, + "set_only_once": 0, + "unique": 0 }, { + "allow_on_submit": 0, "fieldname": "net_total", "fieldtype": "Currency", + "hidden": 0, + "ignore_user_permissions": 0, + "in_filter": 0, + "in_list_view": 0, "label": "Net Total", + "no_copy": 0, "options": "currency", "permlevel": 0, "print_hide": 1, - "read_only": 1 + "read_only": 1, + "report_hide": 0, + "reqd": 0, + "search_index": 0, + "set_only_once": 0, + "unique": 0 }, { + "allow_on_submit": 0, "fieldname": "taxes_section", "fieldtype": "Section Break", + "hidden": 0, + "ignore_user_permissions": 0, + "in_filter": 0, + "in_list_view": 0, "label": "Taxes and Charges", + "no_copy": 0, "oldfieldtype": "Section Break", "options": "icon-money", "permlevel": 0, - "read_only": 0 + "print_hide": 0, + "read_only": 0, + "report_hide": 0, + "reqd": 0, + "search_index": 0, + "set_only_once": 0, + "unique": 0 }, { + "allow_on_submit": 0, "fieldname": "taxes_and_charges", "fieldtype": "Link", + "hidden": 0, + "ignore_user_permissions": 0, + "in_filter": 0, + "in_list_view": 0, "label": "Taxes and Charges", + "no_copy": 0, "oldfieldname": "charge", "oldfieldtype": "Link", "options": "Sales Taxes and Charges Template", "permlevel": 0, "print_hide": 1, - "read_only": 0 + "read_only": 0, + "report_hide": 0, + "reqd": 0, + "search_index": 0, + "set_only_once": 0, + "unique": 0 }, { + "allow_on_submit": 0, "fieldname": "column_break_38", "fieldtype": "Column Break", - "permlevel": 0 + "hidden": 0, + "ignore_user_permissions": 0, + "in_filter": 0, + "in_list_view": 0, + "no_copy": 0, + "permlevel": 0, + "print_hide": 0, + "read_only": 0, + "report_hide": 0, + "reqd": 0, + "search_index": 0, + "set_only_once": 0, + "unique": 0 }, { + "allow_on_submit": 0, "fieldname": "shipping_rule", "fieldtype": "Link", + "hidden": 0, + "ignore_user_permissions": 0, + "in_filter": 0, + "in_list_view": 0, "label": "Shipping Rule", + "no_copy": 0, "oldfieldtype": "Button", "options": "Shipping Rule", "permlevel": 0, "print_hide": 1, - "read_only": 0 + "read_only": 0, + "report_hide": 0, + "reqd": 0, + "search_index": 0, + "set_only_once": 0, + "unique": 0 }, { + "allow_on_submit": 0, "fieldname": "section_break_40", "fieldtype": "Section Break", - "permlevel": 0 + "hidden": 0, + "ignore_user_permissions": 0, + "in_filter": 0, + "in_list_view": 0, + "no_copy": 0, + "permlevel": 0, + "print_hide": 0, + "read_only": 0, + "report_hide": 0, + "reqd": 0, + "search_index": 0, + "set_only_once": 0, + "unique": 0 }, { "allow_on_submit": 1, "fieldname": "taxes", "fieldtype": "Table", + "hidden": 0, + "ignore_user_permissions": 0, + "in_filter": 0, + "in_list_view": 0, "label": "Sales Taxes and Charges", + "no_copy": 0, "oldfieldname": "other_charges", "oldfieldtype": "Table", "options": "Sales Taxes and Charges", "permlevel": 0, - "read_only": 0 + "print_hide": 0, + "read_only": 0, + "report_hide": 0, + "reqd": 0, + "search_index": 0, + "set_only_once": 0, + "unique": 0 }, { + "allow_on_submit": 0, "fieldname": "other_charges_calculation", "fieldtype": "HTML", + "hidden": 0, + "ignore_user_permissions": 0, + "in_filter": 0, + "in_list_view": 0, "label": "Taxes and Charges Calculation", + "no_copy": 0, "oldfieldtype": "HTML", "permlevel": 0, "print_hide": 1, - "read_only": 0 + "read_only": 0, + "report_hide": 0, + "reqd": 0, + "search_index": 0, + "set_only_once": 0, + "unique": 0 }, { + "allow_on_submit": 0, "fieldname": "section_break_43", "fieldtype": "Section Break", - "permlevel": 0 + "hidden": 0, + "ignore_user_permissions": 0, + "in_filter": 0, + "in_list_view": 0, + "no_copy": 0, + "permlevel": 0, + "print_hide": 0, + "read_only": 0, + "report_hide": 0, + "reqd": 0, + "search_index": 0, + "set_only_once": 0, + "unique": 0 }, { + "allow_on_submit": 0, "fieldname": "base_total_taxes_and_charges", "fieldtype": "Currency", + "hidden": 0, + "ignore_user_permissions": 0, + "in_filter": 0, + "in_list_view": 0, "label": "Total Taxes and Charges (Company Currency)", + "no_copy": 0, "oldfieldname": "other_charges_total", "oldfieldtype": "Currency", "options": "Company:company:default_currency", "permlevel": 0, "print_hide": 1, - "read_only": 1 + "read_only": 1, + "report_hide": 0, + "reqd": 0, + "search_index": 0, + "set_only_once": 0, + "unique": 0 }, { + "allow_on_submit": 0, "fieldname": "column_break_47", "fieldtype": "Column Break", + "hidden": 0, + "ignore_user_permissions": 0, + "in_filter": 0, + "in_list_view": 0, + "no_copy": 0, "permlevel": 0, - "precision": "" + "precision": "", + "print_hide": 0, + "read_only": 0, + "report_hide": 0, + "reqd": 0, + "search_index": 0, + "set_only_once": 0, + "unique": 0 }, { + "allow_on_submit": 0, "fieldname": "total_taxes_and_charges", "fieldtype": "Currency", + "hidden": 0, + "ignore_user_permissions": 0, + "in_filter": 0, + "in_list_view": 0, "label": "Total Taxes and Charges", + "no_copy": 0, "options": "currency", "permlevel": 0, "print_hide": 1, - "read_only": 1 + "read_only": 1, + "report_hide": 0, + "reqd": 0, + "search_index": 0, + "set_only_once": 0, + "unique": 0 }, { + "allow_on_submit": 0, "fieldname": "section_break_49", "fieldtype": "Section Break", + "hidden": 0, + "ignore_user_permissions": 0, + "in_filter": 0, + "in_list_view": 0, + "no_copy": 0, "permlevel": 0, - "precision": "" + "precision": "", + "print_hide": 0, + "read_only": 0, + "report_hide": 0, + "reqd": 0, + "search_index": 0, + "set_only_once": 0, + "unique": 0 }, { + "allow_on_submit": 0, "default": "Grand Total", "fieldname": "apply_discount_on", "fieldtype": "Select", + "hidden": 0, + "ignore_user_permissions": 0, + "in_filter": 0, + "in_list_view": 0, "label": "Apply Additional Discount On", + "no_copy": 0, "options": "\nGrand Total\nNet Total", "permlevel": 0, "precision": "", - "print_hide": 1 + "print_hide": 1, + "read_only": 0, + "report_hide": 0, + "reqd": 0, + "search_index": 0, + "set_only_once": 0, + "unique": 0 }, { + "allow_on_submit": 0, "fieldname": "column_break_51", "fieldtype": "Column Break", - "permlevel": 0 + "hidden": 0, + "ignore_user_permissions": 0, + "in_filter": 0, + "in_list_view": 0, + "no_copy": 0, + "permlevel": 0, + "print_hide": 0, + "read_only": 0, + "report_hide": 0, + "reqd": 0, + "search_index": 0, + "set_only_once": 0, + "unique": 0 }, { + "allow_on_submit": 0, "fieldname": "discount_amount", "fieldtype": "Currency", + "hidden": 0, + "ignore_user_permissions": 0, + "in_filter": 0, + "in_list_view": 0, "label": "Additional Discount Amount", + "no_copy": 0, "options": "currency", "permlevel": 0, - "print_hide": 1 + "print_hide": 1, + "read_only": 0, + "report_hide": 0, + "reqd": 0, + "search_index": 0, + "set_only_once": 0, + "unique": 0 }, { + "allow_on_submit": 0, "fieldname": "base_discount_amount", "fieldtype": "Currency", + "hidden": 0, + "ignore_user_permissions": 0, + "in_filter": 0, + "in_list_view": 0, "label": "Additional Discount Amount (Company Currency)", + "no_copy": 0, "options": "Company:company:default_currency", "permlevel": 0, "precision": "", "print_hide": 1, - "read_only": 1 + "read_only": 1, + "report_hide": 0, + "reqd": 0, + "search_index": 0, + "set_only_once": 0, + "unique": 0 }, { + "allow_on_submit": 0, "fieldname": "totals", "fieldtype": "Section Break", + "hidden": 0, + "ignore_user_permissions": 0, + "in_filter": 0, + "in_list_view": 0, "label": "", + "no_copy": 0, "oldfieldtype": "Section Break", "options": "icon-money", "permlevel": 0, "print_hide": 1, - "read_only": 0 + "read_only": 0, + "report_hide": 0, + "reqd": 0, + "search_index": 0, + "set_only_once": 0, + "unique": 0 }, { + "allow_on_submit": 0, "fieldname": "base_grand_total", "fieldtype": "Currency", + "hidden": 0, + "ignore_user_permissions": 0, "in_filter": 1, + "in_list_view": 0, "label": "Grand Total (Company Currency)", + "no_copy": 0, "oldfieldname": "grand_total", "oldfieldtype": "Currency", "options": "Company:company:default_currency", "permlevel": 0, "print_hide": 1, "read_only": 1, + "report_hide": 0, "reqd": 1, - "search_index": 0 + "search_index": 0, + "set_only_once": 0, + "unique": 0 }, { + "allow_on_submit": 0, "fieldname": "base_rounded_total", "fieldtype": "Currency", + "hidden": 0, + "ignore_user_permissions": 0, + "in_filter": 0, + "in_list_view": 0, "label": "Rounded Total (Company Currency)", + "no_copy": 0, "oldfieldname": "rounded_total", "oldfieldtype": "Currency", "options": "Company:company:default_currency", "permlevel": 0, "print_hide": 1, - "read_only": 1 + "read_only": 1, + "report_hide": 0, + "reqd": 0, + "search_index": 0, + "set_only_once": 0, + "unique": 0 }, { + "allow_on_submit": 0, "description": "In Words will be visible once you save the Sales Invoice.", "fieldname": "base_in_words", "fieldtype": "Data", + "hidden": 0, + "ignore_user_permissions": 0, + "in_filter": 0, + "in_list_view": 0, "label": "In Words (Company Currency)", + "no_copy": 0, "oldfieldname": "in_words", "oldfieldtype": "Data", "permlevel": 0, "print_hide": 1, - "read_only": 1 + "read_only": 1, + "report_hide": 0, + "reqd": 0, + "search_index": 0, + "set_only_once": 0, + "unique": 0 }, { + "allow_on_submit": 0, "fieldname": "column_break5", "fieldtype": "Column Break", + "hidden": 0, + "ignore_user_permissions": 0, + "in_filter": 0, + "in_list_view": 0, + "no_copy": 0, "oldfieldtype": "Column Break", "permlevel": 0, "print_hide": 1, "read_only": 0, + "report_hide": 0, + "reqd": 0, + "search_index": 0, + "set_only_once": 0, + "unique": 0, "width": "50%" }, { + "allow_on_submit": 0, "fieldname": "grand_total", "fieldtype": "Currency", + "hidden": 0, + "ignore_user_permissions": 0, + "in_filter": 0, "in_list_view": 1, "label": "Grand Total", + "no_copy": 0, "oldfieldname": "grand_total_export", "oldfieldtype": "Currency", "options": "currency", "permlevel": 0, "print_hide": 0, "read_only": 1, - "reqd": 1 + "report_hide": 0, + "reqd": 1, + "search_index": 0, + "set_only_once": 0, + "unique": 0 }, { + "allow_on_submit": 0, "fieldname": "rounded_total", "fieldtype": "Currency", + "hidden": 0, + "ignore_user_permissions": 0, + "in_filter": 0, + "in_list_view": 0, "label": "Rounded Total", + "no_copy": 0, "oldfieldname": "rounded_total_export", "oldfieldtype": "Currency", "options": "currency", "permlevel": 0, "print_hide": 0, - "read_only": 1 + "read_only": 1, + "report_hide": 0, + "reqd": 0, + "search_index": 0, + "set_only_once": 0, + "unique": 0 }, { + "allow_on_submit": 0, "fieldname": "in_words", "fieldtype": "Data", + "hidden": 0, + "ignore_user_permissions": 0, + "in_filter": 0, + "in_list_view": 0, "label": "In Words", + "no_copy": 0, "oldfieldname": "in_words_export", "oldfieldtype": "Data", "permlevel": 0, "print_hide": 0, - "read_only": 1 + "read_only": 1, + "report_hide": 0, + "reqd": 0, + "search_index": 0, + "set_only_once": 0, + "unique": 0 }, { + "allow_on_submit": 0, "fieldname": "total_advance", "fieldtype": "Currency", + "hidden": 0, + "ignore_user_permissions": 0, + "in_filter": 0, + "in_list_view": 0, "label": "Total Advance", + "no_copy": 0, "oldfieldname": "total_advance", "oldfieldtype": "Currency", "options": "Company:company:default_currency", "permlevel": 0, "print_hide": 1, - "read_only": 1 + "read_only": 1, + "report_hide": 0, + "reqd": 0, + "search_index": 0, + "set_only_once": 0, + "unique": 0 }, { + "allow_on_submit": 0, "fieldname": "outstanding_amount", "fieldtype": "Currency", + "hidden": 0, + "ignore_user_permissions": 0, + "in_filter": 0, "in_list_view": 0, "label": "Outstanding Amount", "no_copy": 1, @@ -643,52 +1343,107 @@ "options": "Company:company:default_currency", "permlevel": 0, "print_hide": 1, - "read_only": 1 + "read_only": 1, + "report_hide": 0, + "reqd": 0, + "search_index": 0, + "set_only_once": 0, + "unique": 0 }, { + "allow_on_submit": 0, "fieldname": "advances_section", "fieldtype": "Section Break", + "hidden": 0, + "ignore_user_permissions": 0, + "in_filter": 0, + "in_list_view": 0, "label": "Advances", + "no_copy": 0, "oldfieldtype": "Section Break", "options": "icon-money", "permlevel": 0, "print_hide": 1, - "read_only": 0 + "read_only": 0, + "report_hide": 0, + "reqd": 0, + "search_index": 0, + "set_only_once": 0, + "unique": 0 }, { + "allow_on_submit": 0, "fieldname": "get_advances_received", "fieldtype": "Button", + "hidden": 0, + "ignore_user_permissions": 0, + "in_filter": 0, + "in_list_view": 0, "label": "Get Advances Received", + "no_copy": 0, "oldfieldtype": "Button", "options": "get_advances", "permlevel": 0, "print_hide": 1, - "read_only": 0 + "read_only": 0, + "report_hide": 0, + "reqd": 0, + "search_index": 0, + "set_only_once": 0, + "unique": 0 }, { + "allow_on_submit": 0, "fieldname": "advances", "fieldtype": "Table", + "hidden": 0, + "ignore_user_permissions": 0, + "in_filter": 0, + "in_list_view": 0, "label": "Advances", + "no_copy": 0, "oldfieldname": "advance_adjustment_details", "oldfieldtype": "Table", "options": "Sales Invoice Advance", "permlevel": 0, "print_hide": 1, - "read_only": 0 + "read_only": 0, + "report_hide": 0, + "reqd": 0, + "search_index": 0, + "set_only_once": 0, + "unique": 0 }, { + "allow_on_submit": 0, "depends_on": "eval:doc.is_pos===1||(doc.advances && doc.advances.length>0)", "fieldname": "payments_section", "fieldtype": "Section Break", + "hidden": 0, + "ignore_user_permissions": 0, + "in_filter": 0, + "in_list_view": 0, "label": "Payments", + "no_copy": 0, "options": "icon-money", "permlevel": 0, - "read_only": 0 + "print_hide": 0, + "read_only": 0, + "report_hide": 0, + "reqd": 0, + "search_index": 0, + "set_only_once": 0, + "unique": 0 }, { + "allow_on_submit": 0, "depends_on": "is_pos", "fieldname": "paid_amount", "fieldtype": "Currency", + "hidden": 0, + "ignore_user_permissions": 0, + "in_filter": 0, + "in_list_view": 0, "label": "Paid Amount", "no_copy": 1, "oldfieldname": "paid_amount", @@ -696,298 +1451,608 @@ "options": "Company:company:default_currency", "permlevel": 0, "print_hide": 1, - "read_only": 0 + "read_only": 0, + "report_hide": 0, + "reqd": 0, + "search_index": 0, + "set_only_once": 0, + "unique": 0 }, { + "allow_on_submit": 0, "depends_on": "is_pos", "fieldname": "column_break3", "fieldtype": "Column Break", + "hidden": 0, + "ignore_user_permissions": 0, + "in_filter": 0, + "in_list_view": 0, + "no_copy": 0, "permlevel": 0, + "print_hide": 0, "read_only": 0, + "report_hide": 0, + "reqd": 0, + "search_index": 0, + "set_only_once": 0, + "unique": 0, "width": "50%" }, { + "allow_on_submit": 0, "depends_on": "is_pos", "fieldname": "cash_bank_account", "fieldtype": "Link", + "hidden": 0, + "ignore_user_permissions": 0, + "in_filter": 0, + "in_list_view": 0, "label": "Cash/Bank Account", + "no_copy": 0, "oldfieldname": "cash_bank_account", "oldfieldtype": "Link", "options": "Account", "permlevel": 0, "print_hide": 1, - "read_only": 0 + "read_only": 0, + "report_hide": 0, + "reqd": 0, + "search_index": 0, + "set_only_once": 0, + "unique": 0 }, { + "allow_on_submit": 0, "depends_on": "grand_total", "fieldname": "column_break4", "fieldtype": "Section Break", + "hidden": 0, + "ignore_user_permissions": 0, + "in_filter": 0, + "in_list_view": 0, "label": "", + "no_copy": 0, "permlevel": 0, + "print_hide": 0, "read_only": 0, + "report_hide": 0, + "reqd": 0, + "search_index": 0, + "set_only_once": 0, + "unique": 0, "width": "50%" }, { + "allow_on_submit": 0, "depends_on": "", "fieldname": "write_off_amount", "fieldtype": "Currency", + "hidden": 0, + "ignore_user_permissions": 0, + "in_filter": 0, + "in_list_view": 0, "label": "Write Off Amount", "no_copy": 1, "options": "Company:company:default_currency", "permlevel": 0, "print_hide": 1, - "read_only": 0 + "read_only": 0, + "report_hide": 0, + "reqd": 0, + "search_index": 0, + "set_only_once": 0, + "unique": 0 }, { - "depends_on": "", + "allow_on_submit": 0, + "depends_on": "is_pos", "fieldname": "write_off_outstanding_amount_automatically", "fieldtype": "Check", + "hidden": 0, + "ignore_user_permissions": 0, + "in_filter": 0, + "in_list_view": 0, "label": "Write Off Outstanding Amount", + "no_copy": 0, "permlevel": 0, "print_hide": 1, - "read_only": 0 + "read_only": 0, + "report_hide": 0, + "reqd": 0, + "search_index": 0, + "set_only_once": 0, + "unique": 0 }, { - "depends_on": "eval:doc.is_pos===1||(doc.advances && doc.advances.length>0)", + "allow_on_submit": 0, + "depends_on": "", "fieldname": "column_break_74", "fieldtype": "Column Break", + "hidden": 0, + "ignore_user_permissions": 0, + "in_filter": 0, + "in_list_view": 0, + "no_copy": 0, "permlevel": 0, - "precision": "" + "precision": "", + "print_hide": 0, + "read_only": 0, + "report_hide": 0, + "reqd": 0, + "search_index": 0, + "set_only_once": 0, + "unique": 0 }, { + "allow_on_submit": 0, "depends_on": "", "fieldname": "write_off_account", "fieldtype": "Link", + "hidden": 0, + "ignore_user_permissions": 0, + "in_filter": 0, + "in_list_view": 0, "label": "Write Off Account", + "no_copy": 0, "options": "Account", "permlevel": 0, "print_hide": 1, - "read_only": 0 + "read_only": 0, + "report_hide": 0, + "reqd": 0, + "search_index": 0, + "set_only_once": 0, + "unique": 0 }, { + "allow_on_submit": 0, "depends_on": "", "fieldname": "write_off_cost_center", "fieldtype": "Link", + "hidden": 0, + "ignore_user_permissions": 0, + "in_filter": 0, + "in_list_view": 0, "label": "Write Off Cost Center", + "no_copy": 0, "options": "Cost Center", "permlevel": 0, "print_hide": 1, - "read_only": 0 + "read_only": 0, + "report_hide": 0, + "reqd": 0, + "search_index": 0, + "set_only_once": 0, + "unique": 0 }, { + "allow_on_submit": 0, "fieldname": "fold", "fieldtype": "Fold", - "permlevel": 0 + "hidden": 0, + "ignore_user_permissions": 0, + "in_filter": 0, + "in_list_view": 0, + "no_copy": 0, + "permlevel": 0, + "print_hide": 0, + "read_only": 0, + "report_hide": 0, + "reqd": 0, + "search_index": 0, + "set_only_once": 0, + "unique": 0 }, { + "allow_on_submit": 0, "fieldname": "terms_section_break", "fieldtype": "Section Break", + "hidden": 0, + "ignore_user_permissions": 0, + "in_filter": 0, + "in_list_view": 0, "label": "", + "no_copy": 0, "oldfieldtype": "Section Break", "options": "icon-legal", "permlevel": 0, - "read_only": 0 + "print_hide": 0, + "read_only": 0, + "report_hide": 0, + "reqd": 0, + "search_index": 0, + "set_only_once": 0, + "unique": 0 }, { + "allow_on_submit": 0, "fieldname": "tc_name", "fieldtype": "Link", + "hidden": 0, + "ignore_user_permissions": 0, + "in_filter": 0, + "in_list_view": 0, "label": "Terms", + "no_copy": 0, "oldfieldname": "tc_name", "oldfieldtype": "Link", "options": "Terms and Conditions", "permlevel": 0, "print_hide": 1, - "read_only": 0 + "read_only": 0, + "report_hide": 0, + "reqd": 0, + "search_index": 0, + "set_only_once": 0, + "unique": 0 }, { + "allow_on_submit": 0, "fieldname": "terms", "fieldtype": "Text Editor", + "hidden": 0, + "ignore_user_permissions": 0, + "in_filter": 0, + "in_list_view": 0, "label": "Terms and Conditions Details", + "no_copy": 0, "oldfieldname": "terms", "oldfieldtype": "Text Editor", "permlevel": 0, - "read_only": 0 + "print_hide": 0, + "read_only": 0, + "report_hide": 0, + "reqd": 0, + "search_index": 0, + "set_only_once": 0, + "unique": 0 }, { + "allow_on_submit": 0, "depends_on": "customer", "fieldname": "contact_section", "fieldtype": "Section Break", "hidden": 0, + "ignore_user_permissions": 0, + "in_filter": 0, + "in_list_view": 0, "label": "", + "no_copy": 0, "options": "icon-bullhorn", "permlevel": 0, - "read_only": 0 + "print_hide": 0, + "read_only": 0, + "report_hide": 0, + "reqd": 0, + "search_index": 0, + "set_only_once": 0, + "unique": 0 }, { + "allow_on_submit": 0, "description": "", "fieldname": "territory", "fieldtype": "Link", + "hidden": 0, + "ignore_user_permissions": 0, "in_filter": 1, + "in_list_view": 0, "label": "Territory", + "no_copy": 0, "options": "Territory", "permlevel": 0, "print_hide": 1, "read_only": 0, + "report_hide": 0, "reqd": 1, - "search_index": 0 + "search_index": 0, + "set_only_once": 0, + "unique": 0 }, { + "allow_on_submit": 0, "description": "", "fieldname": "customer_group", "fieldtype": "Link", + "hidden": 0, + "ignore_user_permissions": 0, "in_filter": 1, + "in_list_view": 0, "label": "Customer Group", + "no_copy": 0, "options": "Customer Group", "permlevel": 0, "print_hide": 1, "read_only": 0, - "search_index": 0 + "report_hide": 0, + "reqd": 0, + "search_index": 0, + "set_only_once": 0, + "unique": 0 }, { + "allow_on_submit": 0, "fieldname": "col_break23", "fieldtype": "Column Break", + "hidden": 0, + "ignore_user_permissions": 0, + "in_filter": 0, + "in_list_view": 0, + "no_copy": 0, "permlevel": 0, + "print_hide": 0, "read_only": 0, + "report_hide": 0, + "reqd": 0, + "search_index": 0, + "set_only_once": 0, + "unique": 0, "width": "50%" }, { + "allow_on_submit": 0, "fieldname": "customer_address", "fieldtype": "Link", + "hidden": 0, + "ignore_user_permissions": 0, + "in_filter": 0, + "in_list_view": 0, "label": "Customer Address", + "no_copy": 0, "options": "Address", "permlevel": 0, "print_hide": 1, - "read_only": 0 + "read_only": 0, + "report_hide": 0, + "reqd": 0, + "search_index": 0, + "set_only_once": 0, + "unique": 0 }, { + "allow_on_submit": 0, "fieldname": "contact_person", "fieldtype": "Link", + "hidden": 0, + "ignore_user_permissions": 0, + "in_filter": 0, + "in_list_view": 0, "label": "Contact Person", + "no_copy": 0, "options": "Contact", "permlevel": 0, "print_hide": 1, - "read_only": 0 + "read_only": 0, + "report_hide": 0, + "reqd": 0, + "search_index": 0, + "set_only_once": 0, + "unique": 0 }, { + "allow_on_submit": 0, "fieldname": "more_info", "fieldtype": "Section Break", + "hidden": 0, + "ignore_user_permissions": 0, + "in_filter": 0, + "in_list_view": 0, "label": "", + "no_copy": 0, "oldfieldtype": "Section Break", "options": "icon-file-text", "permlevel": 0, "print_hide": 1, - "read_only": 0 + "read_only": 0, + "report_hide": 0, + "reqd": 0, + "search_index": 0, + "set_only_once": 0, + "unique": 0 }, { + "allow_on_submit": 0, "description": "Customer (Receivable) Account", "fieldname": "debit_to", "fieldtype": "Link", + "hidden": 0, + "ignore_user_permissions": 0, "in_filter": 1, + "in_list_view": 0, "label": "Debit To", + "no_copy": 0, "oldfieldname": "debit_to", "oldfieldtype": "Link", "options": "Account", "permlevel": 0, "print_hide": 1, "read_only": 0, + "report_hide": 0, "reqd": 1, - "search_index": 1 + "search_index": 1, + "set_only_once": 0, + "unique": 0 }, { + "allow_on_submit": 0, "fieldname": "project_name", "fieldtype": "Link", + "hidden": 0, + "ignore_user_permissions": 0, "in_filter": 1, + "in_list_view": 0, "label": "Project Name", + "no_copy": 0, "oldfieldname": "project_name", "oldfieldtype": "Link", "options": "Project", "permlevel": 0, + "print_hide": 0, "read_only": 0, - "search_index": 0 + "report_hide": 0, + "reqd": 0, + "search_index": 0, + "set_only_once": 0, + "unique": 0 }, { + "allow_on_submit": 0, "depends_on": "eval:doc.source == 'Campaign'", "fieldname": "campaign", "fieldtype": "Link", + "hidden": 0, + "ignore_user_permissions": 0, + "in_filter": 0, + "in_list_view": 0, "label": "Campaign", + "no_copy": 0, "oldfieldname": "campaign", "oldfieldtype": "Link", "options": "Campaign", "permlevel": 0, "print_hide": 1, - "read_only": 0 + "read_only": 0, + "report_hide": 0, + "reqd": 0, + "search_index": 0, + "set_only_once": 0, + "unique": 0 }, { + "allow_on_submit": 0, "fieldname": "source", "fieldtype": "Select", + "hidden": 0, + "ignore_user_permissions": 0, + "in_filter": 0, + "in_list_view": 0, "label": "Source", + "no_copy": 0, "oldfieldname": "source", "oldfieldtype": "Select", "options": "\nExisting Customer\nReference\nAdvertisement\nCold Calling\nExhibition\nSupplier Reference\nMass Mailing\nCustomer's Vendor\nCampaign", "permlevel": 0, "print_hide": 1, - "read_only": 0 + "read_only": 0, + "report_hide": 0, + "reqd": 0, + "search_index": 0, + "set_only_once": 0, + "unique": 0 }, { + "allow_on_submit": 0, "default": "No", "description": "Considered as an Opening Balance", "fieldname": "is_opening", "fieldtype": "Select", + "hidden": 0, + "ignore_user_permissions": 0, "in_filter": 1, + "in_list_view": 0, "label": "Is Opening Entry", + "no_copy": 0, "oldfieldname": "is_opening", "oldfieldtype": "Select", "options": "No\nYes", "permlevel": 0, "print_hide": 1, "read_only": 0, - "search_index": 0 + "report_hide": 0, + "reqd": 0, + "search_index": 0, + "set_only_once": 0, + "unique": 0 }, { + "allow_on_submit": 0, "fieldname": "c_form_applicable", "fieldtype": "Select", + "hidden": 0, + "ignore_user_permissions": 0, + "in_filter": 0, + "in_list_view": 0, "label": "C-Form Applicable", "no_copy": 1, "options": "No\nYes", "permlevel": 0, "print_hide": 1, "read_only": 0, - "report_hide": 0 + "report_hide": 0, + "reqd": 0, + "search_index": 0, + "set_only_once": 0, + "unique": 0 }, { + "allow_on_submit": 0, "fieldname": "c_form_no", "fieldtype": "Link", + "hidden": 0, + "ignore_user_permissions": 0, + "in_filter": 0, + "in_list_view": 0, "label": "C-Form No", "no_copy": 1, "options": "C-Form", "permlevel": 0, "print_hide": 1, - "read_only": 1 + "read_only": 1, + "report_hide": 0, + "reqd": 0, + "search_index": 0, + "set_only_once": 0, + "unique": 0 }, { + "allow_on_submit": 0, "fieldname": "column_break8", "fieldtype": "Column Break", + "hidden": 0, + "ignore_user_permissions": 0, + "in_filter": 0, + "in_list_view": 0, + "no_copy": 0, "oldfieldtype": "Column Break", "permlevel": 0, "print_hide": 1, - "read_only": 0 + "read_only": 0, + "report_hide": 0, + "reqd": 0, + "search_index": 0, + "set_only_once": 0, + "unique": 0 }, { "allow_on_submit": 1, "fieldname": "letter_head", "fieldtype": "Link", + "hidden": 0, + "ignore_user_permissions": 0, + "in_filter": 0, + "in_list_view": 0, "label": "Letter Head", + "no_copy": 0, "oldfieldname": "letter_head", "oldfieldtype": "Select", "options": "Letter Head", "permlevel": 0, "print_hide": 1, - "read_only": 0 + "read_only": 0, + "report_hide": 0, + "reqd": 0, + "search_index": 0, + "set_only_once": 0, + "unique": 0 }, { "allow_on_submit": 1, "fieldname": "select_print_heading", "fieldtype": "Link", + "hidden": 0, + "ignore_user_permissions": 0, + "in_filter": 0, + "in_list_view": 0, "label": "Print Heading", "no_copy": 1, "oldfieldname": "select_print_heading", @@ -996,23 +2061,41 @@ "permlevel": 0, "print_hide": 1, "read_only": 0, - "report_hide": 1 + "report_hide": 1, + "reqd": 0, + "search_index": 0, + "set_only_once": 0, + "unique": 0 }, { + "allow_on_submit": 0, "fieldname": "posting_time", "fieldtype": "Time", + "hidden": 0, + "ignore_user_permissions": 0, + "in_filter": 0, + "in_list_view": 0, "label": "Posting Time", "no_copy": 1, "oldfieldname": "posting_time", "oldfieldtype": "Time", "permlevel": 0, "print_hide": 1, - "read_only": 0 + "read_only": 0, + "report_hide": 0, + "reqd": 0, + "search_index": 0, + "set_only_once": 0, + "unique": 0 }, { + "allow_on_submit": 0, "fieldname": "fiscal_year", "fieldtype": "Link", + "hidden": 0, + "ignore_user_permissions": 0, "in_filter": 1, + "in_list_view": 0, "label": "Fiscal Year", "no_copy": 0, "oldfieldname": "fiscal_year", @@ -1021,12 +2104,20 @@ "permlevel": 0, "print_hide": 1, "read_only": 0, + "report_hide": 0, "reqd": 1, - "search_index": 0 + "search_index": 0, + "set_only_once": 0, + "unique": 0 }, { + "allow_on_submit": 0, "fieldname": "remarks", "fieldtype": "Small Text", + "hidden": 0, + "ignore_user_permissions": 0, + "in_filter": 0, + "in_list_view": 0, "label": "Remarks", "no_copy": 1, "oldfieldname": "remarks", @@ -1034,103 +2125,216 @@ "permlevel": 0, "print_hide": 1, "read_only": 0, - "reqd": 0 + "report_hide": 0, + "reqd": 0, + "search_index": 0, + "set_only_once": 0, + "unique": 0 }, { + "allow_on_submit": 0, "fieldname": "sales_team_section_break", "fieldtype": "Section Break", + "hidden": 0, + "ignore_user_permissions": 0, + "in_filter": 0, + "in_list_view": 0, "label": "", + "no_copy": 0, "oldfieldtype": "Section Break", "options": "icon-group", "permlevel": 0, "print_hide": 1, - "read_only": 0 + "read_only": 0, + "report_hide": 0, + "reqd": 0, + "search_index": 0, + "set_only_once": 0, + "unique": 0 }, { + "allow_on_submit": 0, "fieldname": "column_break9", "fieldtype": "Column Break", + "hidden": 0, + "ignore_user_permissions": 0, + "in_filter": 0, + "in_list_view": 0, + "no_copy": 0, "oldfieldtype": "Column Break", "permlevel": 0, "print_hide": 1, "read_only": 0, + "report_hide": 0, + "reqd": 0, + "search_index": 0, + "set_only_once": 0, + "unique": 0, "width": "50%" }, { + "allow_on_submit": 0, "fieldname": "sales_partner", "fieldtype": "Link", + "hidden": 0, + "ignore_user_permissions": 0, "in_filter": 1, + "in_list_view": 0, "label": "Sales Partner", + "no_copy": 0, "oldfieldname": "sales_partner", "oldfieldtype": "Link", "options": "Sales Partner", "permlevel": 0, "print_hide": 1, - "read_only": 0 + "read_only": 0, + "report_hide": 0, + "reqd": 0, + "search_index": 0, + "set_only_once": 0, + "unique": 0 }, { + "allow_on_submit": 0, "fieldname": "column_break10", "fieldtype": "Column Break", + "hidden": 0, + "ignore_user_permissions": 0, + "in_filter": 0, + "in_list_view": 0, + "no_copy": 0, "oldfieldtype": "Column Break", "permlevel": 0, "print_hide": 1, "read_only": 0, + "report_hide": 0, + "reqd": 0, + "search_index": 0, + "set_only_once": 0, + "unique": 0, "width": "50%" }, { + "allow_on_submit": 0, "fieldname": "commission_rate", "fieldtype": "Float", + "hidden": 0, + "ignore_user_permissions": 0, + "in_filter": 0, + "in_list_view": 0, "label": "Commission Rate (%)", + "no_copy": 0, "oldfieldname": "commission_rate", "oldfieldtype": "Currency", "permlevel": 0, "print_hide": 1, - "read_only": 0 + "read_only": 0, + "report_hide": 0, + "reqd": 0, + "search_index": 0, + "set_only_once": 0, + "unique": 0 }, { + "allow_on_submit": 0, "fieldname": "total_commission", "fieldtype": "Currency", + "hidden": 0, + "ignore_user_permissions": 0, + "in_filter": 0, + "in_list_view": 0, "label": "Total Commission", + "no_copy": 0, "oldfieldname": "total_commission", "oldfieldtype": "Currency", "options": "Company:company:default_currency", "permlevel": 0, "print_hide": 1, - "read_only": 0 + "read_only": 0, + "report_hide": 0, + "reqd": 0, + "search_index": 0, + "set_only_once": 0, + "unique": 0 }, { + "allow_on_submit": 0, "fieldname": "section_break2", "fieldtype": "Section Break", + "hidden": 0, + "ignore_user_permissions": 0, + "in_filter": 0, + "in_list_view": 0, + "no_copy": 0, "permlevel": 0, "print_hide": 1, - "read_only": 0 + "read_only": 0, + "report_hide": 0, + "reqd": 0, + "search_index": 0, + "set_only_once": 0, + "unique": 0 }, { + "allow_on_submit": 0, "fieldname": "sales_team", "fieldtype": "Table", + "hidden": 0, + "ignore_user_permissions": 0, + "in_filter": 0, + "in_list_view": 0, "label": "Sales Team1", + "no_copy": 0, "oldfieldname": "sales_team", "oldfieldtype": "Table", "options": "Sales Team", "permlevel": 0, "print_hide": 1, - "read_only": 0 + "read_only": 0, + "report_hide": 0, + "reqd": 0, + "search_index": 0, + "set_only_once": 0, + "unique": 0 }, { + "allow_on_submit": 0, "depends_on": "eval:doc.docstatus<2", "fieldname": "recurring_invoice", "fieldtype": "Section Break", + "hidden": 0, + "ignore_user_permissions": 0, + "in_filter": 0, + "in_list_view": 0, "label": "Recurring Invoice", + "no_copy": 0, "options": "icon-time", "permlevel": 0, "print_hide": 1, - "read_only": 0 + "read_only": 0, + "report_hide": 0, + "reqd": 0, + "search_index": 0, + "set_only_once": 0, + "unique": 0 }, { + "allow_on_submit": 0, "fieldname": "column_break11", "fieldtype": "Column Break", + "hidden": 0, + "ignore_user_permissions": 0, + "in_filter": 0, + "in_list_view": 0, + "no_copy": 0, "permlevel": 0, "print_hide": 1, "read_only": 0, + "report_hide": 0, + "reqd": 0, + "search_index": 0, + "set_only_once": 0, + "unique": 0, "width": "50%" }, { @@ -1139,11 +2343,20 @@ "description": "Check if recurring invoice, uncheck to stop recurring or put proper End Date", "fieldname": "is_recurring", "fieldtype": "Check", + "hidden": 0, + "ignore_user_permissions": 0, + "in_filter": 0, + "in_list_view": 0, "label": "Is Recurring", "no_copy": 1, "permlevel": 0, "print_hide": 1, - "read_only": 0 + "read_only": 0, + "report_hide": 0, + "reqd": 0, + "search_index": 0, + "set_only_once": 0, + "unique": 0 }, { "allow_on_submit": 1, @@ -1151,12 +2364,21 @@ "description": "Select the period when the invoice will be generated automatically", "fieldname": "recurring_type", "fieldtype": "Select", + "hidden": 0, + "ignore_user_permissions": 0, + "in_filter": 0, + "in_list_view": 0, "label": "Recurring Type", "no_copy": 1, "options": "\nMonthly\nQuarterly\nHalf-yearly\nYearly", "permlevel": 0, "print_hide": 1, - "read_only": 0 + "read_only": 0, + "report_hide": 0, + "reqd": 0, + "search_index": 0, + "set_only_once": 0, + "unique": 0 }, { "allow_on_submit": 1, @@ -1164,11 +2386,20 @@ "description": "Start date of current invoice's period", "fieldname": "from_date", "fieldtype": "Date", + "hidden": 0, + "ignore_user_permissions": 0, + "in_filter": 0, + "in_list_view": 0, "label": "From Date", "no_copy": 1, "permlevel": 0, "print_hide": 0, - "read_only": 0 + "read_only": 0, + "report_hide": 0, + "reqd": 0, + "search_index": 0, + "set_only_once": 0, + "unique": 0 }, { "allow_on_submit": 1, @@ -1176,11 +2407,20 @@ "description": "End date of current invoice's period", "fieldname": "to_date", "fieldtype": "Date", + "hidden": 0, + "ignore_user_permissions": 0, + "in_filter": 0, + "in_list_view": 0, "label": "To Date", "no_copy": 1, "permlevel": 0, "print_hide": 0, - "read_only": 0 + "read_only": 0, + "report_hide": 0, + "reqd": 0, + "search_index": 0, + "set_only_once": 0, + "unique": 0 }, { "allow_on_submit": 1, @@ -1188,11 +2428,20 @@ "description": "The day of the month on which auto invoice will be generated e.g. 05, 28 etc ", "fieldname": "repeat_on_day_of_month", "fieldtype": "Int", + "hidden": 0, + "ignore_user_permissions": 0, + "in_filter": 0, + "in_list_view": 0, "label": "Repeat on Day of Month", "no_copy": 1, "permlevel": 0, "print_hide": 1, - "read_only": 0 + "read_only": 0, + "report_hide": 0, + "reqd": 0, + "search_index": 0, + "set_only_once": 0, + "unique": 0 }, { "allow_on_submit": 1, @@ -1200,42 +2449,81 @@ "description": "The date on which recurring invoice will be stop", "fieldname": "end_date", "fieldtype": "Date", + "hidden": 0, + "ignore_user_permissions": 0, + "in_filter": 0, + "in_list_view": 0, "label": "End Date", "no_copy": 1, "permlevel": 0, "print_hide": 1, - "read_only": 0 + "read_only": 0, + "report_hide": 0, + "reqd": 0, + "search_index": 0, + "set_only_once": 0, + "unique": 0 }, { + "allow_on_submit": 0, "fieldname": "column_break12", "fieldtype": "Column Break", + "hidden": 0, + "ignore_user_permissions": 0, + "in_filter": 0, + "in_list_view": 0, "no_copy": 0, "permlevel": 0, "print_hide": 1, "read_only": 0, + "report_hide": 0, + "reqd": 0, + "search_index": 0, + "set_only_once": 0, + "unique": 0, "width": "50%" }, { + "allow_on_submit": 0, "depends_on": "eval:doc.is_recurring==1", "description": "The date on which next invoice will be generated. It is generated on submit.\n", "fieldname": "next_date", "fieldtype": "Date", + "hidden": 0, + "ignore_user_permissions": 0, + "in_filter": 0, + "in_list_view": 0, "label": "Next Date", "no_copy": 1, "permlevel": 0, "print_hide": 1, - "read_only": 1 + "read_only": 1, + "report_hide": 0, + "reqd": 0, + "search_index": 0, + "set_only_once": 0, + "unique": 0 }, { + "allow_on_submit": 0, "depends_on": "eval:doc.is_recurring==1", "description": "The unique id for tracking all recurring invoices.\u00a0It is generated on submit.", "fieldname": "recurring_id", "fieldtype": "Data", + "hidden": 0, + "ignore_user_permissions": 0, + "in_filter": 0, + "in_list_view": 0, "label": "Recurring Id", "no_copy": 1, "permlevel": 0, "print_hide": 1, - "read_only": 1 + "read_only": 1, + "report_hide": 0, + "reqd": 0, + "search_index": 0, + "set_only_once": 0, + "unique": 0 }, { "allow_on_submit": 1, @@ -1243,25 +2531,51 @@ "description": "Enter email id separated by commas, invoice will be mailed automatically on particular date", "fieldname": "notification_email_address", "fieldtype": "Small Text", + "hidden": 0, + "ignore_user_permissions": 0, + "in_filter": 0, + "in_list_view": 0, "label": "Notification Email Address", "no_copy": 1, "permlevel": 0, "print_hide": 1, - "read_only": 0 + "read_only": 0, + "report_hide": 0, + "reqd": 0, + "search_index": 0, + "set_only_once": 0, + "unique": 0 }, { + "allow_on_submit": 0, "depends_on": "eval:doc.is_recurring==1", "fieldname": "recurring_print_format", "fieldtype": "Link", + "hidden": 0, + "ignore_user_permissions": 0, + "in_filter": 0, + "in_list_view": 0, "label": "Recurring Print Format", + "no_copy": 0, "options": "Print Format", "permlevel": 0, - "precision": "" + "precision": "", + "print_hide": 0, + "read_only": 0, + "report_hide": 0, + "reqd": 0, + "search_index": 0, + "set_only_once": 0, + "unique": 0 }, { + "allow_on_submit": 0, "fieldname": "against_income_account", "fieldtype": "Small Text", "hidden": 1, + "ignore_user_permissions": 0, + "in_filter": 0, + "in_list_view": 0, "label": "Against Income Account", "no_copy": 1, "oldfieldname": "against_income_account", @@ -1269,13 +2583,23 @@ "permlevel": 0, "print_hide": 1, "read_only": 0, - "report_hide": 1 + "report_hide": 1, + "reqd": 0, + "search_index": 0, + "set_only_once": 0, + "unique": 0 } ], + "hide_heading": 0, + "hide_toolbar": 0, "icon": "icon-file-text", "idx": 1, + "in_create": 0, + "in_dialog": 0, "is_submittable": 1, - "modified": "2015-07-24 11:48:07.544569", + "issingle": 0, + "istable": 0, + "modified": "2015-08-26 07:17:36.890961", "modified_by": "Administrator", "module": "Accounts", "name": "Sales Invoice", @@ -1283,15 +2607,20 @@ "permissions": [ { "amend": 1, + "apply_user_permissions": 0, "cancel": 1, "create": 1, "delete": 1, "email": 1, + "export": 0, + "if_owner": 0, + "import": 0, "permlevel": 0, "print": 1, "read": 1, "report": 1, "role": "Accounts Manager", + "set_user_permissions": 0, "share": 1, "submit": 1, "write": 1 @@ -1303,33 +2632,61 @@ "create": 1, "delete": 0, "email": 1, + "export": 0, + "if_owner": 0, + "import": 0, "permlevel": 0, "print": 1, "read": 1, "report": 1, "role": "Accounts User", + "set_user_permissions": 0, "share": 1, "submit": 1, "write": 1 }, { + "amend": 0, "apply_user_permissions": 1, "cancel": 0, + "create": 0, "delete": 0, "email": 1, + "export": 0, + "if_owner": 0, + "import": 0, "permlevel": 0, "print": 1, "read": 1, "report": 1, - "role": "Customer" + "role": "Customer", + "set_user_permissions": 0, + "share": 0, + "submit": 0, + "write": 0 }, { + "amend": 0, + "apply_user_permissions": 0, + "cancel": 0, + "create": 0, + "delete": 0, + "email": 0, + "export": 0, + "if_owner": 0, + "import": 0, "permlevel": 1, + "print": 0, "read": 1, + "report": 0, "role": "Accounts Manager", + "set_user_permissions": 0, + "share": 0, + "submit": 0, "write": 1 } ], + "read_only": 0, "read_only_onload": 1, "search_fields": "posting_date, due_date, customer, fiscal_year, base_grand_total, outstanding_amount", "sort_field": "modified", From 8ca72d8883f769ceb3ff916c2066a51043189c93 Mon Sep 17 00:00:00 2001 From: Anand Doshi Date: Wed, 26 Aug 2015 17:25:08 +0600 Subject: [PATCH 21/21] bumped to version 5.8.0 --- erpnext/__version__.py | 2 +- erpnext/hooks.py | 2 +- setup.py | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/erpnext/__version__.py b/erpnext/__version__.py index cfdd2f7fd0..dd1a9e5bca 100644 --- a/erpnext/__version__.py +++ b/erpnext/__version__.py @@ -1,2 +1,2 @@ from __future__ import unicode_literals -__version__ = '5.7.7' +__version__ = '5.8.0' diff --git a/erpnext/hooks.py b/erpnext/hooks.py index 2a2d7c18ef..ff6e4e6874 100644 --- a/erpnext/hooks.py +++ b/erpnext/hooks.py @@ -27,7 +27,7 @@ blogs. """ app_icon = "icon-th" app_color = "#e74c3c" -app_version = "5.7.7" +app_version = "5.8.0" github_link = "https://github.com/frappe/erpnext" error_report_email = "support@erpnext.com" diff --git a/setup.py b/setup.py index 9ed46de3ec..21b5940f33 100644 --- a/setup.py +++ b/setup.py @@ -1,6 +1,6 @@ from setuptools import setup, find_packages -version = "5.7.7" +version = "5.8.0" with open("requirements.txt", "r") as f: install_requires = f.readlines()