From 9aadb0d95d8961f24c5a86e45347198ddfd60e9a Mon Sep 17 00:00:00 2001 From: ankitjavalkarwork Date: Tue, 7 Oct 2014 17:38:46 +0530 Subject: [PATCH 1/3] [#2164] Add Delivered Qty to Sales Inv from Delivery Note, fix issues --- .../doctype/sales_invoice/sales_invoice.py | 10 ++++++--- erpnext/controllers/status_updater.py | 22 ++++++++++++------- .../doctype/delivery_note/delivery_note.py | 16 ++++++++++++++ .../delivery_note_item.json | 14 +++++++++++- 4 files changed, 50 insertions(+), 12 deletions(-) diff --git a/erpnext/accounts/doctype/sales_invoice/sales_invoice.py b/erpnext/accounts/doctype/sales_invoice/sales_invoice.py index 352dfabb7d..a9586b6d15 100644 --- a/erpnext/accounts/doctype/sales_invoice/sales_invoice.py +++ b/erpnext/accounts/doctype/sales_invoice/sales_invoice.py @@ -132,7 +132,9 @@ class SalesInvoice(SellingController): 'second_source_dt': 'Delivery Note Item', 'second_source_field': 'qty', 'second_join_field': 'prevdoc_detail_docname', - 'overflow_type': 'delivery' + 'overflow_type': 'delivery', + 'extra_cond': """ and exists(select name from `tabSales Invoice` + where name=`tabSales Invoice Item`.parent and ifnull(update_stock, 0) = 1)""" }) def get_portal_page(self): @@ -627,9 +629,11 @@ def make_delivery_note(source_name, target_doc=None): "Sales Invoice Item": { "doctype": "Delivery Note Item", "field_map": { - "name": "prevdoc_detail_docname", + "name": "si_detail", "parent": "against_sales_invoice", - "serial_no": "serial_no" + "serial_no": "serial_no", + "sales_order": "against_sales_order", + "so_detail": "prevdoc_detail_docname" }, "postprocess": update_item }, diff --git a/erpnext/controllers/status_updater.py b/erpnext/controllers/status_updater.py index 9825b04762..247d4ffbda 100644 --- a/erpnext/controllers/status_updater.py +++ b/erpnext/controllers/status_updater.py @@ -153,16 +153,21 @@ class StatusUpdater(Document): 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"] = "" + 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 (docstatus=1)), 0)""" % args + and (`tab%(second_source_dt)s`.docstatus=1) %(second_source_extra_cond)s), 0) """ % args if args['detail_id']: + if not args.get("extra_cond"): args["extra_cond"] = "" + 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)) %(second_source_condition)s + and (docstatus=1 %(cond)s) %(extra_cond)s) %(second_source_condition)s where name='%(detail_id)s'""" % args) # get unique transactions to update @@ -171,12 +176,13 @@ class StatusUpdater(Document): args['name'] = name # update percent complete in the parent table - 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.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) # update field if args.get('status_field'): diff --git a/erpnext/stock/doctype/delivery_note/delivery_note.py b/erpnext/stock/doctype/delivery_note/delivery_note.py index ee8dc0cce5..51413c55e0 100644 --- a/erpnext/stock/doctype/delivery_note/delivery_note.py +++ b/erpnext/stock/doctype/delivery_note/delivery_note.py @@ -34,6 +34,22 @@ class DeliveryNote(SellingController): 'percent_join_field': 'against_sales_order', 'status_field': 'delivery_status', 'keyword': 'Delivered', + 'second_source_dt': 'Sales Invoice Item', + 'second_source_field': 'qty', + 'second_join_field': 'so_detail', + 'overflow_type': 'delivery', + 'second_source_extra_cond': """ and exists(select name from `tabSales Invoice` + where name=`tabSales Invoice Item`.parent and ifnull(update_stock, 0) = 1)""" + }, + { + 'source_dt': 'Delivery Note Item', + 'target_dt': 'Sales Invoice Item', + 'join_field': 'si_detail', + 'target_field': 'delivered_qty', + 'target_parent_dt': 'Sales Invoice', + 'target_ref_field': 'qty', + 'source_field': 'qty', + 'percent_join_field': 'against_sales_invoice', 'overflow_type': 'delivery' }] 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 a5fe469d69..9fc9aae3fb 100644 --- a/erpnext/stock/doctype/delivery_note_item/delivery_note_item.json +++ b/erpnext/stock/doctype/delivery_note_item/delivery_note_item.json @@ -388,6 +388,18 @@ "search_index": 0, "width": "150px" }, + { + "fieldname": "si_detail", + "fieldtype": "Data", + "hidden": 1, + "in_filter": 1, + "label": "SI Detail", + "no_copy": 1, + "permlevel": 0, + "precision": "", + "print_hide": 1, + "read_only": 1 + }, { "fieldname": "installed_qty", "fieldtype": "Float", @@ -426,7 +438,7 @@ ], "idx": 1, "istable": 1, - "modified": "2014-09-09 05:35:37.460939", + "modified": "2014-10-07 18:18:04.375810", "modified_by": "Administrator", "module": "Stock", "name": "Delivery Note Item", From e69a6119911bb00d3eba9755d65a4db19cfa59b6 Mon Sep 17 00:00:00 2001 From: ankitjavalkarwork Date: Wed, 8 Oct 2014 12:46:02 +0530 Subject: [PATCH 2/3] [#2164] New field names in DN, fix field name refs, Patch added --- .../accounts/doctype/sales_invoice/sales_invoice.py | 4 ++-- erpnext/controllers/selling_controller.py | 6 +++--- erpnext/patches.txt | 1 + .../patches/v5_0/update_dn_against_doc_fields.py | 13 +++++++++++++ erpnext/selling/doctype/sales_order/sales_order.py | 2 +- .../selling/doctype/sales_order/test_sales_order.py | 2 +- .../stock/doctype/delivery_note/delivery_note.py | 6 +++--- .../delivery_note_item/delivery_note_item.json | 8 ++++---- 8 files changed, 28 insertions(+), 14 deletions(-) create mode 100644 erpnext/patches/v5_0/update_dn_against_doc_fields.py diff --git a/erpnext/accounts/doctype/sales_invoice/sales_invoice.py b/erpnext/accounts/doctype/sales_invoice/sales_invoice.py index a9586b6d15..5201e5e80b 100644 --- a/erpnext/accounts/doctype/sales_invoice/sales_invoice.py +++ b/erpnext/accounts/doctype/sales_invoice/sales_invoice.py @@ -131,7 +131,7 @@ class SalesInvoice(SellingController): 'keyword':'Delivered', 'second_source_dt': 'Delivery Note Item', 'second_source_field': 'qty', - 'second_join_field': 'prevdoc_detail_docname', + 'second_join_field': 'so_detail', 'overflow_type': 'delivery', 'extra_cond': """ and exists(select name from `tabSales Invoice` where name=`tabSales Invoice Item`.parent and ifnull(update_stock, 0) = 1)""" @@ -633,7 +633,7 @@ def make_delivery_note(source_name, target_doc=None): "parent": "against_sales_invoice", "serial_no": "serial_no", "sales_order": "against_sales_order", - "so_detail": "prevdoc_detail_docname" + "so_detail": "so_detail" }, "postprocess": update_item }, diff --git a/erpnext/controllers/selling_controller.py b/erpnext/controllers/selling_controller.py index d173abeb8e..5d778149df 100644 --- a/erpnext/controllers/selling_controller.py +++ b/erpnext/controllers/selling_controller.py @@ -334,8 +334,8 @@ class SellingController(StockController): # 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, d.prevdoc_detail_docname) - so_qty, reserved_warehouse = self.get_so_qty_and_warehouse(d.prevdoc_detail_docname) + d.against_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) @@ -377,7 +377,7 @@ class SellingController(StockController): def get_already_delivered_qty(self, dn, so, so_detail): qty = frappe.db.sql("""select sum(qty) from `tabDelivery Note Item` - where prevdoc_detail_docname = %s and docstatus = 1 + where so_detail = %s and docstatus = 1 and against_sales_order = %s and parent != %s""", (so_detail, so, dn)) return qty and flt(qty[0][0]) or 0.0 diff --git a/erpnext/patches.txt b/erpnext/patches.txt index 52dd66cf0f..1a45c59442 100644 --- a/erpnext/patches.txt +++ b/erpnext/patches.txt @@ -84,3 +84,4 @@ erpnext.patches.v4_2.cost_of_production_cycle erpnext.patches.v4_2.seprate_manufacture_and_repack erpnext.patches.v4_2.party_model erpnext.patches.v5_0.update_frozen_accounts_permission_role +erpnext.patches.v5_0.update_dn_against_doc_fields diff --git a/erpnext/patches/v5_0/update_dn_against_doc_fields.py b/erpnext/patches/v5_0/update_dn_against_doc_fields.py new file mode 100644 index 0000000000..e8780a7394 --- /dev/null +++ b/erpnext/patches/v5_0/update_dn_against_doc_fields.py @@ -0,0 +1,13 @@ +# Copyright (c) 2013, Web Notes Technologies Pvt. Ltd. and Contributors +# License: GNU General Public License v3. See license.txt + +import frappe + +def execute(): + frappe.reload_doc('stock', 'doctype', 'delivery_note_item') + + frappe.db.sql("""update `tabDelivery Note Item` set so_detail = prevdoc_detail_docname + where ifnull(against_sales_order, '') != ''""") + + frappe.db.sql("""update `tabDelivery Note Item` set si_detail = prevdoc_detail_docname + where ifnull(against_sales_invoice, '') != ''""") diff --git a/erpnext/selling/doctype/sales_order/sales_order.py b/erpnext/selling/doctype/sales_order/sales_order.py index b24d297b65..e59d209fd4 100644 --- a/erpnext/selling/doctype/sales_order/sales_order.py +++ b/erpnext/selling/doctype/sales_order/sales_order.py @@ -294,7 +294,7 @@ def make_delivery_note(source_name, target_doc=None): "doctype": "Delivery Note Item", "field_map": { "rate": "rate", - "name": "prevdoc_detail_docname", + "name": "so_detail", "parent": "against_sales_order", }, "postprocess": update_item, diff --git a/erpnext/selling/doctype/sales_order/test_sales_order.py b/erpnext/selling/doctype/sales_order/test_sales_order.py index c7ec8937d7..8195a1b68b 100644 --- a/erpnext/selling/doctype/sales_order/test_sales_order.py +++ b/erpnext/selling/doctype/sales_order/test_sales_order.py @@ -85,7 +85,7 @@ class TestSalesOrder(unittest.TestCase): dn = frappe.get_doc(frappe.copy_doc(dn_test_records[0])) dn.get("delivery_note_details")[0].item_code = so.get("sales_order_details")[0].item_code dn.get("delivery_note_details")[0].against_sales_order = so.name - dn.get("delivery_note_details")[0].prevdoc_detail_docname = so.get("sales_order_details")[0].name + dn.get("delivery_note_details")[0].so_detail = so.get("sales_order_details")[0].name if delivered_qty: dn.get("delivery_note_details")[0].qty = delivered_qty dn.insert() diff --git a/erpnext/stock/doctype/delivery_note/delivery_note.py b/erpnext/stock/doctype/delivery_note/delivery_note.py index 51413c55e0..67a33c9010 100644 --- a/erpnext/stock/doctype/delivery_note/delivery_note.py +++ b/erpnext/stock/doctype/delivery_note/delivery_note.py @@ -25,7 +25,7 @@ class DeliveryNote(SellingController): self.status_updater = [{ 'source_dt': 'Delivery Note Item', 'target_dt': 'Sales Order Item', - 'join_field': 'prevdoc_detail_docname', + 'join_field': 'so_detail', 'target_field': 'delivered_qty', 'target_parent_dt': 'Sales Order', 'target_parent_field': 'per_delivered', @@ -129,7 +129,7 @@ class DeliveryNote(SellingController): if cint(frappe.defaults.get_global_default('maintain_same_sales_rate')): super(DeliveryNote, self).validate_with_previous_doc(self.tname, { fn[0] + " Item": { - "ref_dn_field": "prevdoc_detail_docname", + "ref_dn_field": "so_detail", "compare_fields": [["rate", "="]], "is_child_table": True } @@ -328,7 +328,7 @@ def make_sales_invoice(source_name, target_doc=None): "field_map": { "name": "dn_detail", "parent": "delivery_note", - "prevdoc_detail_docname": "so_detail", + "so_detail": "so_detail", "against_sales_order": "sales_order", "serial_no": "serial_no" }, 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 9fc9aae3fb..57adf3f219 100644 --- a/erpnext/stock/doctype/delivery_note_item/delivery_note_item.json +++ b/erpnext/stock/doctype/delivery_note_item/delivery_note_item.json @@ -373,11 +373,11 @@ "read_only": 1 }, { - "fieldname": "prevdoc_detail_docname", + "fieldname": "so_detail", "fieldtype": "Data", "hidden": 1, "in_filter": 1, - "label": "Against Document Detail No", + "label": "Against Sales Order Item", "no_copy": 1, "oldfieldname": "prevdoc_detail_docname", "oldfieldtype": "Data", @@ -393,7 +393,7 @@ "fieldtype": "Data", "hidden": 1, "in_filter": 1, - "label": "SI Detail", + "label": "Against Sales Invoice Item", "no_copy": 1, "permlevel": 0, "precision": "", @@ -438,7 +438,7 @@ ], "idx": 1, "istable": 1, - "modified": "2014-10-07 18:18:04.375810", + "modified": "2014-10-08 11:11:59.411329", "modified_by": "Administrator", "module": "Stock", "name": "Delivery Note Item", From ad3d698fd82bf86872c96fdd0a631e2b09c54633 Mon Sep 17 00:00:00 2001 From: ankitjavalkarwork Date: Thu, 9 Oct 2014 17:31:33 +0530 Subject: [PATCH 3/3] [#2164] Add test case for delivered qty in Sales Order --- .../doctype/sales_order/test_sales_order.py | 75 ++++++++++++++++--- 1 file changed, 64 insertions(+), 11 deletions(-) diff --git a/erpnext/selling/doctype/sales_order/test_sales_order.py b/erpnext/selling/doctype/sales_order/test_sales_order.py index 8195a1b68b..f8722924cd 100644 --- a/erpnext/selling/doctype/sales_order/test_sales_order.py +++ b/erpnext/selling/doctype/sales_order/test_sales_order.py @@ -34,12 +34,10 @@ class TestSalesOrder(unittest.TestCase): self.assertRaises(frappe.ValidationError, make_delivery_note, so.name) - sales_order = frappe.get_doc("Sales Order", so.name) - sales_order.submit() - dn = make_delivery_note(so.name) + dn = self.make_next_doc_testcase(so, "Delivery Note") self.assertEquals(dn.doctype, "Delivery Note") - self.assertEquals(len(dn.get("delivery_note_details")), len(sales_order.get("sales_order_details"))) + self.assertEquals(len(dn.get("delivery_note_details")), len(so.get("sales_order_details"))) def test_make_sales_invoice(self): from erpnext.selling.doctype.sales_order.sales_order import make_sales_invoice @@ -49,22 +47,77 @@ class TestSalesOrder(unittest.TestCase): self.assertRaises(frappe.ValidationError, make_sales_invoice, so.name) - sales_order = frappe.get_doc("Sales Order", so.name) - sales_order.submit() - si = make_sales_invoice(so.name) + si = self.make_next_doc_testcase(so, "Sales Invoice") self.assertEquals(si.doctype, "Sales Invoice") - self.assertEquals(len(si.get("entries")), len(sales_order.get("sales_order_details"))) + self.assertEquals(len(si.get("entries")), len(so.get("sales_order_details"))) self.assertEquals(len(si.get("entries")), 1) - si.debit_to = "_Test Receivable - _TC" - si.posting_date = "2013-10-10" + si.set("debit_to", "_Test Receivable - _TC") + si.set("posting_date", "2013-10-10") si.insert() si.submit() - si1 = make_sales_invoice(so.name) + si1 = self.make_next_doc_testcase(so, "Sales Invoice") self.assertEquals(len(si1.get("entries")), 0) + def test_update_qty(self): + so = frappe.copy_doc(test_records[0]).insert() + + dn = self.make_next_doc_testcase(so, "Delivery Note") + + dn.get("delivery_note_details")[0].qty = 6 + dn.posting_date = "2013-10-10" + dn.insert() + + delivery_note = frappe.get_doc("Delivery Note", dn.name) + delivery_note.submit() + + sales_order = frappe.get_doc("Sales Order", so.name) + + self.assertEquals(sales_order.get("sales_order_details")[0].delivered_qty, 6) + + #Check delivered_qty after make_sales_invoice without update_stock checked + si1 = self.make_next_doc_testcase(sales_order, "Sales Invoice") + + si1.set("debit_to", "_Test Receivable - _TC") + si1.set("posting_date", "2013-10-10") + si1.get("entries")[0].qty = 1 + si1.insert() + si1.submit() + + sales_order = frappe.get_doc("Sales Order", sales_order.name) + + self.assertEquals(sales_order.get("sales_order_details")[0].delivered_qty, 6) + + #Check delivered_qty after make_sales_invoice with update_stock checked + si2 = self.make_next_doc_testcase(sales_order, "Sales Invoice") + + si2.set("debit_to", "_Test Receivable - _TC") + si2.set("posting_date", "2013-10-10") + si2.set("update_stock", 1) + si2.get("entries")[0].qty = 3 + si2.insert() + si2.submit() + + sales_order = frappe.get_doc("Sales Order", sales_order.name) + + self.assertEquals(sales_order.get("sales_order_details")[0].delivered_qty, 9) + + def make_next_doc_testcase(self, so, next_doc = None): + + if so.docstatus < 1: + so.submit() + + if next_doc == "Delivery Note": + from erpnext.selling.doctype.sales_order.sales_order import make_delivery_note + next_doc = make_delivery_note(so.name) + + if next_doc == "Sales Invoice": + from erpnext.selling.doctype.sales_order.sales_order import make_sales_invoice + next_doc = make_sales_invoice(so.name) + + return next_doc def create_so(self, so_doc = None): if not so_doc: