From a20157af172a07b20fe9487eac2c57f4dac77511 Mon Sep 17 00:00:00 2001 From: Shreya Date: Fri, 13 Apr 2018 12:03:42 +0530 Subject: [PATCH] on item, warehouse and batch triggers, fetch serial nos based on batch --- erpnext/public/js/controllers/transaction.js | 1 - erpnext/selling/sales_common.js | 77 +++++----- .../delivery_note_item.json | 132 +++++++++++++----- erpnext/stock/get_item_details.py | 47 ++++++- 4 files changed, 187 insertions(+), 70 deletions(-) diff --git a/erpnext/public/js/controllers/transaction.js b/erpnext/public/js/controllers/transaction.js index 1551b1dfc3..3da28a88cf 100644 --- a/erpnext/public/js/controllers/transaction.js +++ b/erpnext/public/js/controllers/transaction.js @@ -296,7 +296,6 @@ erpnext.TransactionController = erpnext.taxes_and_totals.extend({ var me = this; var item = frappe.get_doc(cdt, cdn); var update_stock = 0, show_batch_dialog = 0; - if(['Sales Invoice'].includes(this.frm.doc.doctype)) { update_stock = cint(me.frm.doc.update_stock); show_batch_dialog = update_stock; diff --git a/erpnext/selling/sales_common.js b/erpnext/selling/sales_common.js index aa5b3ba498..d6f4677f8e 100644 --- a/erpnext/selling/sales_common.js +++ b/erpnext/selling/sales_common.js @@ -186,25 +186,32 @@ erpnext.selling.SellingController = erpnext.TransactionController.extend({ warehouse: function(doc, cdt, cdn) { var me = this; var item = frappe.get_doc(cdt, cdn); - - if(item.item_code && item.warehouse) { - return this.frm.call({ - method: "erpnext.stock.get_item_details.get_bin_details_and_serial_nos", - child: item, - args: { - item_code: item.item_code, - warehouse: item.warehouse, - stock_qty: item.stock_qty, - serial_no: item.serial_no || "" - }, - callback:function(r){ - if (in_list(['Delivery Note', 'Sales Invoice'], doc.doctype)) { - me.set_batch_number(cdt, cdn); - me.batch_no(doc, cdt, cdn); - } - } - }); + if (item.serial_no && !item.batch_no) { + item.serial_no = null; } + var has_batch_no; + frappe.db.get_value('Item', {'item_code': item.item_code}, 'has_batch_no', (r) => { + has_batch_no = r && r.has_batch_no; + if(item.item_code && item.warehouse) { + return this.frm.call({ + method: "erpnext.stock.get_item_details.get_bin_details_and_serial_nos", + child: item, + args: { + item_code: item.item_code, + warehouse: item.warehouse, + has_batch_no: has_batch_no, + stock_qty: item.stock_qty, + serial_no: item.serial_no || "", + }, + callback:function(r){ + if (in_list(['Delivery Note', 'Sales Invoice'], doc.doctype)) { + me.set_batch_number(cdt, cdn); + me.batch_no(doc, cdt, cdn); + } + } + }); + } + }) }, toggle_editable_price_list_rate: function() { @@ -245,19 +252,25 @@ erpnext.selling.SellingController = erpnext.TransactionController.extend({ batch_no: function(doc, cdt, cdn) { var me = this; var item = frappe.get_doc(cdt, cdn); - - if(item.warehouse && item.item_code && item.batch_no) { - return this.frm.call({ - method: "erpnext.stock.get_item_details.get_batch_qty", - child: item, - args: { - "batch_no": item.batch_no, - "warehouse": item.warehouse, - "item_code": item.item_code - }, - "fieldname": "actual_batch_qty" - }); - } + item.serial_no = null; + var has_serial_no; + frappe.db.get_value('Item', {'item_code': item.item_code}, 'has_serial_no', (r) => { + has_serial_no = r && r.has_serial_no; + if(item.warehouse && item.item_code && item.batch_no) { + return this.frm.call({ + method: "erpnext.stock.get_item_details.get_batch_qty_and_serial_no", + child: item, + args: { + "batch_no": item.batch_no, + "stock_qty": item.stock_qty, + "warehouse": item.warehouse, + "item_code": item.item_code, + "has_serial_no": has_serial_no + }, + "fieldname": "actual_batch_qty" + }); + } + }) }, set_dynamic_labels: function() { @@ -348,7 +361,7 @@ erpnext.selling.SellingController = erpnext.TransactionController.extend({ }, qty: function(doc, cdt, cdn) { - this._super(doc, cdt, cdn); + this._super(doc, cdt, cdn); this.set_batch_number(cdt, cdn); }, 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 5487193284..ebf7ea170e 100644 --- a/erpnext/stock/doctype/delivery_note_item/delivery_note_item.json +++ b/erpnext/stock/doctype/delivery_note_item/delivery_note_item.json @@ -40,6 +40,7 @@ "reqd": 0, "search_index": 0, "set_only_once": 0, + "translatable": 0, "unique": 0 }, { @@ -73,6 +74,7 @@ "reqd": 1, "search_index": 1, "set_only_once": 0, + "translatable": 0, "unique": 0, "width": "150px" }, @@ -106,6 +108,7 @@ "reqd": 1, "search_index": 0, "set_only_once": 0, + "translatable": 0, "unique": 0, "width": "150px" }, @@ -135,6 +138,7 @@ "reqd": 0, "search_index": 0, "set_only_once": 0, + "translatable": 0, "unique": 0 }, { @@ -164,6 +168,7 @@ "reqd": 0, "search_index": 0, "set_only_once": 0, + "translatable": 0, "unique": 0 }, { @@ -194,6 +199,7 @@ "reqd": 0, "search_index": 0, "set_only_once": 0, + "translatable": 0, "unique": 0 }, { @@ -226,6 +232,7 @@ "reqd": 1, "search_index": 0, "set_only_once": 0, + "translatable": 0, "unique": 0, "width": "300px" }, @@ -256,6 +263,7 @@ "reqd": 0, "search_index": 0, "set_only_once": 0, + "translatable": 0, "unique": 0 }, { @@ -286,6 +294,7 @@ "reqd": 0, "search_index": 0, "set_only_once": 0, + "translatable": 0, "unique": 0 }, { @@ -317,6 +326,7 @@ "reqd": 0, "search_index": 0, "set_only_once": 0, + "translatable": 0, "unique": 0 }, { @@ -346,6 +356,7 @@ "reqd": 0, "search_index": 0, "set_only_once": 0, + "translatable": 0, "unique": 0 }, { @@ -378,6 +389,7 @@ "reqd": 1, "search_index": 0, "set_only_once": 0, + "translatable": 0, "unique": 0, "width": "100px" }, @@ -412,6 +424,7 @@ "reqd": 1, "search_index": 0, "set_only_once": 0, + "translatable": 0, "unique": 0, "width": "50px" }, @@ -441,6 +454,7 @@ "reqd": 0, "search_index": 0, "set_only_once": 0, + "translatable": 0, "unique": 0 }, { @@ -472,6 +486,7 @@ "reqd": 1, "search_index": 0, "set_only_once": 0, + "translatable": 0, "unique": 0 }, { @@ -502,6 +517,7 @@ "reqd": 1, "search_index": 0, "set_only_once": 0, + "translatable": 0, "unique": 0 }, { @@ -532,6 +548,7 @@ "reqd": 0, "search_index": 0, "set_only_once": 0, + "translatable": 0, "unique": 0 }, { @@ -561,6 +578,7 @@ "reqd": 0, "search_index": 0, "set_only_once": 0, + "translatable": 0, "unique": 0 }, { @@ -594,6 +612,7 @@ "reqd": 0, "search_index": 0, "set_only_once": 0, + "translatable": 0, "unique": 0, "width": "100px" }, @@ -628,6 +647,7 @@ "reqd": 0, "search_index": 0, "set_only_once": 0, + "translatable": 0, "unique": 0, "width": "100px" }, @@ -659,6 +679,7 @@ "reqd": 0, "search_index": 0, "set_only_once": 0, + "translatable": 0, "unique": 0 }, { @@ -691,6 +712,7 @@ "reqd": 0, "search_index": 0, "set_only_once": 0, + "translatable": 0, "unique": 0 }, { @@ -722,6 +744,7 @@ "reqd": 0, "search_index": 0, "set_only_once": 0, + "translatable": 0, "unique": 0 }, { @@ -754,6 +777,7 @@ "reqd": 0, "search_index": 0, "set_only_once": 0, + "translatable": 0, "unique": 0 }, { @@ -783,6 +807,7 @@ "reqd": 0, "search_index": 0, "set_only_once": 0, + "translatable": 0, "unique": 0 }, { @@ -816,6 +841,7 @@ "reqd": 0, "search_index": 0, "set_only_once": 0, + "translatable": 0, "unique": 0, "width": "100px" }, @@ -849,6 +875,7 @@ "reqd": 0, "search_index": 0, "set_only_once": 0, + "translatable": 0, "unique": 0 }, { @@ -877,6 +904,7 @@ "reqd": 0, "search_index": 0, "set_only_once": 0, + "translatable": 0, "unique": 0 }, { @@ -910,6 +938,7 @@ "reqd": 0, "search_index": 0, "set_only_once": 0, + "translatable": 0, "unique": 0, "width": "150px" }, @@ -944,6 +973,7 @@ "reqd": 0, "search_index": 0, "set_only_once": 0, + "translatable": 0, "unique": 0, "width": "100px" }, @@ -973,6 +1003,7 @@ "reqd": 0, "search_index": 0, "set_only_once": 0, + "translatable": 0, "unique": 0 }, { @@ -1006,6 +1037,7 @@ "reqd": 0, "search_index": 0, "set_only_once": 0, + "translatable": 0, "unique": 0, "width": "150px" }, @@ -1040,6 +1072,7 @@ "reqd": 0, "search_index": 0, "set_only_once": 0, + "translatable": 0, "unique": 0, "width": "100px" }, @@ -1071,6 +1104,7 @@ "reqd": 0, "search_index": 0, "set_only_once": 0, + "translatable": 0, "unique": 0 }, { @@ -1100,6 +1134,7 @@ "reqd": 0, "search_index": 0, "set_only_once": 0, + "translatable": 0, "unique": 0 }, { @@ -1131,6 +1166,7 @@ "reqd": 0, "search_index": 0, "set_only_once": 0, + "translatable": 0, "unique": 0 }, { @@ -1162,6 +1198,7 @@ "reqd": 0, "search_index": 0, "set_only_once": 0, + "translatable": 0, "unique": 0 }, { @@ -1191,6 +1228,7 @@ "reqd": 0, "search_index": 0, "set_only_once": 0, + "translatable": 0, "unique": 0 }, { @@ -1222,6 +1260,7 @@ "reqd": 0, "search_index": 0, "set_only_once": 0, + "translatable": 0, "unique": 0 }, { @@ -1253,6 +1292,7 @@ "reqd": 0, "search_index": 0, "set_only_once": 0, + "translatable": 0, "unique": 0 }, { @@ -1283,6 +1323,7 @@ "reqd": 0, "search_index": 0, "set_only_once": 0, + "translatable": 0, "unique": 0 }, { @@ -1313,6 +1354,7 @@ "reqd": 0, "search_index": 0, "set_only_once": 0, + "translatable": 0, "unique": 0 }, { @@ -1343,6 +1385,7 @@ "reqd": 0, "search_index": 0, "set_only_once": 0, + "translatable": 0, "unique": 0 }, { @@ -1372,6 +1415,7 @@ "reqd": 0, "search_index": 0, "set_only_once": 0, + "translatable": 0, "unique": 0 }, { @@ -1403,6 +1447,7 @@ "reqd": 0, "search_index": 0, "set_only_once": 0, + "translatable": 0, "unique": 0 }, { @@ -1432,6 +1477,7 @@ "reqd": 0, "search_index": 0, "set_only_once": 0, + "translatable": 0, "unique": 0 }, { @@ -1465,6 +1511,7 @@ "reqd": 0, "search_index": 0, "set_only_once": 0, + "translatable": 0, "unique": 0, "width": "100px" }, @@ -1499,6 +1546,7 @@ "reqd": 0, "search_index": 0, "set_only_once": 0, + "translatable": 0, "unique": 0 }, { @@ -1531,6 +1579,7 @@ "reqd": 0, "search_index": 0, "set_only_once": 0, + "translatable": 0, "unique": 0 }, { @@ -1560,37 +1609,7 @@ "reqd": 0, "search_index": 0, "set_only_once": 0, - "unique": 0 - }, - { - "allow_bulk_edit": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fieldname": "serial_no", - "fieldtype": "Text", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 1, - "in_standard_filter": 0, - "label": "Serial No", - "length": 0, - "no_copy": 1, - "oldfieldname": "serial_no", - "oldfieldtype": "Text", - "permlevel": 0, - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, + "translatable": 0, "unique": 0 }, { @@ -1623,6 +1642,7 @@ "reqd": 0, "search_index": 0, "set_only_once": 0, + "translatable": 0, "unique": 0 }, { @@ -1655,6 +1675,7 @@ "reqd": 0, "search_index": 0, "set_only_once": 0, + "translatable": 0, "unique": 0, "width": "150px" }, @@ -1688,9 +1709,42 @@ "reqd": 0, "search_index": 0, "set_only_once": 0, + "translatable": 0, "unique": 0, "width": "150px" }, + { + "allow_bulk_edit": 0, + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "columns": 0, + "fieldname": "serial_no", + "fieldtype": "Text", + "hidden": 0, + "ignore_user_permissions": 0, + "ignore_xss_filter": 0, + "in_filter": 0, + "in_global_search": 0, + "in_list_view": 1, + "in_standard_filter": 0, + "label": "Serial No", + "length": 0, + "no_copy": 1, + "oldfieldname": "serial_no", + "oldfieldtype": "Text", + "permlevel": 0, + "print_hide": 0, + "print_hide_if_no_value": 0, + "read_only": 0, + "remember_last_selected_value": 0, + "report_hide": 0, + "reqd": 0, + "search_index": 0, + "set_only_once": 0, + "translatable": 0, + "unique": 0 + }, { "allow_bulk_edit": 0, "allow_on_submit": 0, @@ -1722,6 +1776,7 @@ "reqd": 0, "search_index": 0, "set_only_once": 0, + "translatable": 0, "unique": 0 }, { @@ -1755,6 +1810,7 @@ "reqd": 0, "search_index": 0, "set_only_once": 0, + "translatable": 0, "unique": 0, "width": "150px" }, @@ -1787,6 +1843,7 @@ "reqd": 0, "search_index": 0, "set_only_once": 0, + "translatable": 0, "unique": 0 }, { @@ -1815,6 +1872,7 @@ "reqd": 0, "search_index": 0, "set_only_once": 0, + "translatable": 0, "unique": 0 }, { @@ -1845,6 +1903,7 @@ "reqd": 0, "search_index": 0, "set_only_once": 0, + "translatable": 0, "unique": 0, "width": "120px" }, @@ -1877,6 +1936,7 @@ "reqd": 0, "search_index": 0, "set_only_once": 0, + "translatable": 0, "unique": 0, "width": "120px" }, @@ -1908,6 +1968,7 @@ "reqd": 0, "search_index": 0, "set_only_once": 0, + "translatable": 0, "unique": 0 }, { @@ -1938,6 +1999,7 @@ "reqd": 0, "search_index": 0, "set_only_once": 0, + "translatable": 0, "unique": 0 }, { @@ -1968,6 +2030,7 @@ "reqd": 0, "search_index": 0, "set_only_once": 0, + "translatable": 0, "unique": 0 }, { @@ -2000,6 +2063,7 @@ "reqd": 0, "search_index": 1, "set_only_once": 0, + "translatable": 0, "unique": 0, "width": "150px" }, @@ -2031,6 +2095,7 @@ "reqd": 0, "search_index": 0, "set_only_once": 0, + "translatable": 0, "unique": 0 }, { @@ -2063,6 +2128,7 @@ "reqd": 0, "search_index": 0, "set_only_once": 0, + "translatable": 0, "unique": 0, "width": "150px" }, @@ -2095,6 +2161,7 @@ "reqd": 0, "search_index": 0, "set_only_once": 0, + "translatable": 0, "unique": 0 }, { @@ -2126,6 +2193,7 @@ "reqd": 0, "search_index": 0, "set_only_once": 0, + "translatable": 0, "unique": 0 } ], @@ -2139,7 +2207,7 @@ "issingle": 0, "istable": 1, "max_attachments": 0, - "modified": "2017-11-30 14:07:12.217563", + "modified": "2018-04-11 14:05:39.905947", "modified_by": "Administrator", "module": "Stock", "name": "Delivery Note Item", diff --git a/erpnext/stock/get_item_details.py b/erpnext/stock/get_item_details.py index 7e456dd3d3..e3617111bc 100644 --- a/erpnext/stock/get_item_details.py +++ b/erpnext/stock/get_item_details.py @@ -81,14 +81,14 @@ def get_item_details(args): (args.get("doctype") == "Sales Invoice" and args.get('update_stock'))) \ and out.warehouse and out.stock_qty > 0: - if out.has_serial_no: - out.serial_no = get_serial_no(out, args.serial_no) - if out.has_batch_no and not args.get("batch_no"): out.batch_no = get_batch_no(out.item_code, out.warehouse, out.qty) actual_batch_qty = get_batch_qty(out.batch_no, out.warehouse, out.item_code) if actual_batch_qty: out.update(actual_batch_qty) + + if out.has_serial_no: + out.serial_no = get_serial_no(out, args.serial_no) if args.transaction_date and item.lead_time_days: out.schedule_date = out.lead_time_date = add_days(args.transaction_date, @@ -465,6 +465,17 @@ def get_serial_nos_by_fifo(args): "qty": abs(cint(args.stock_qty)) })) +def get_serial_no_batchwise(args): + if frappe.db.get_single_value("Stock Settings", "automatically_set_serial_nos_based_on_fifo"): + return "\n".join(frappe.db.sql_list("""select name from `tabSerial No` + where item_code=%(item_code)s and warehouse=%(warehouse)s and batch_no=%(batch_no)s + order by timestamp(purchase_date, purchase_time) asc limit %(qty)s""", { + "item_code": args.item_code, + "warehouse": args.warehouse, + "batch_no": args.batch_no, + "qty": abs(cint(args.stock_qty)) + })) + @frappe.whitelist() def get_conversion_factor(item_code, uom): variant_of = frappe.db.get_value("Item", item_code, "variant_of") @@ -492,13 +503,30 @@ def get_serial_no_details(item_code, warehouse, stock_qty, serial_no): return {'serial_no': serial_no} @frappe.whitelist() -def get_bin_details_and_serial_nos(item_code, warehouse, stock_qty=None, serial_no=None): +def get_bin_details_and_serial_nos(item_code, warehouse, has_batch_no, stock_qty=None, serial_no=None): bin_details_and_serial_nos = {} bin_details_and_serial_nos.update(get_bin_details(item_code, warehouse)) if stock_qty > 0: + if has_batch_no: + args = frappe._dict({"item_code":item_code, "warehouse":warehouse, "stock_qty":stock_qty}) + serial_no = get_serial_no(args) + bin_details_and_serial_nos.update({'serial_no': serial_no}) + return bin_details_and_serial_nos + bin_details_and_serial_nos.update(get_serial_no_details(item_code, warehouse, stock_qty, serial_no)) return bin_details_and_serial_nos +@frappe.whitelist() +def get_batch_qty_and_serial_no(batch_no, stock_qty, warehouse, item_code, has_serial_no): + batch_qty_and_serial_no = {} + batch_qty_and_serial_no.update(get_batch_qty(batch_no, warehouse, item_code)) + + if (flt(batch_qty_and_serial_no.get('actual_batch_qty')) >= flt(stock_qty)) and has_serial_no: + args = frappe._dict({"item_code":item_code, "warehouse":warehouse, "stock_qty":stock_qty, "batch_no":batch_no}) + serial_no = get_serial_no(args) + batch_qty_and_serial_no.update({'serial_no': serial_no}) + return batch_qty_and_serial_no + @frappe.whitelist() def get_batch_qty(batch_no, warehouse, item_code): from erpnext.stock.doctype.batch import batch @@ -659,8 +687,17 @@ def get_serial_no(args, serial_nos=None): return "" if args.get('warehouse') and args.get('stock_qty') and args.get('item_code'): + has_serial_no = frappe.get_value('Item', {'item_code': args.item_code}, "has_serial_no") - if frappe.get_value('Item', {'item_code': args.item_code}, "has_serial_no") == 1: + if args.get('batch_no') and has_serial_no == 1: + return get_serial_no_batchwise(args) + # elif (args.get('has_batch_no') == 1) and has_serial_no == 1 and not args.get(batch_no): + # args.batch_no = get_batch_no(args.item_code, args.warehouse, args.qty) + # actual_batch_qty = get_batch_qty(out.batch_no, out.warehouse, out.item_code) + # if actual_batch_qty: + # out.update(actual_batch_qty) + # return get_serial_no_batchwise(args) + elif has_serial_no == 1: args = json.dumps({"item_code": args.get('item_code'),"warehouse": args.get('warehouse'),"stock_qty": args.get('stock_qty')}) args = process_args(args) serial_no = get_serial_nos_by_fifo(args)