From 3061fc92fd57dd15138f45b4fa06bda5ebb20fb9 Mon Sep 17 00:00:00 2001 From: tundebabzy Date: Mon, 4 Dec 2017 06:53:21 +0100 Subject: [PATCH] Batch Stock Items, having serial number can't be moved without inserting Serial Number (#11792) (#11813) * if doctype is batch, add extra information to args * automatically fetch serial numbers if possible * take advantage of changes in make_stock_entry * code clean up * PEP 8 compliance * fix bug that clears serial number --- erpnext/stock/doctype/batch/batch.js | 57 +++++++++++-------- .../purchase_receipt/test_purchase_receipt.py | 5 +- .../doctype/stock_entry/stock_entry_utils.py | 29 ++++++++++ 3 files changed, 65 insertions(+), 26 deletions(-) diff --git a/erpnext/stock/doctype/batch/batch.js b/erpnext/stock/doctype/batch/batch.js index 1822a06fec..d299ed1b66 100644 --- a/erpnext/stock/doctype/batch/batch.js +++ b/erpnext/stock/doctype/batch/batch.js @@ -65,31 +65,38 @@ frappe.ui.form.on('Batch', { // move - ask for target warehouse and make stock entry rows.find('.btn-move').on('click', function() { var $btn = $(this); - frappe.prompt({ - fieldname: 'to_warehouse', - label: __('To Warehouse'), - fieldtype: 'Link', - options: 'Warehouse' - }, - (data) => { - frappe.call({ - method: 'erpnext.stock.doctype.stock_entry.stock_entry_utils.make_stock_entry', - args: { - item_code: frm.doc.item, - batch_no: frm.doc.name, - qty: $btn.attr('data-qty'), - from_warehouse: $btn.attr('data-warehouse'), - to_warehouse: data.to_warehouse - }, - callback: (r) => { - frappe.show_alert(__('Stock Entry {0} created', - ['' + r.message.name+ ''])); - frm.refresh(); - }, - }); - }, - __('Select Target Warehouse'), - __('Move') + const fields = [ + { + fieldname: 'to_warehouse', + label: __('To Warehouse'), + fieldtype: 'Link', + options: 'Warehouse' + } + ]; + + frappe.prompt( + fields, + (data) => { + frappe.call({ + method: 'erpnext.stock.doctype.stock_entry.stock_entry_utils.make_stock_entry', + args: { + item_code: frm.doc.item, + batch_no: frm.doc.name, + qty: $btn.attr('data-qty'), + from_warehouse: $btn.attr('data-warehouse'), + to_warehouse: data.to_warehouse, + source_document: frm.doc.reference_name, + reference_doctype: frm.doc.reference_doctype + }, + callback: (r) => { + frappe.show_alert(__('Stock Entry {0} created', + ['' + r.message.name+ ''])); + frm.refresh(); + }, + }); + }, + __('Select Target Warehouse'), + __('Move') ); }); diff --git a/erpnext/stock/doctype/purchase_receipt/test_purchase_receipt.py b/erpnext/stock/doctype/purchase_receipt/test_purchase_receipt.py index 6af8c09568..b656c3f0dc 100644 --- a/erpnext/stock/doctype/purchase_receipt/test_purchase_receipt.py +++ b/erpnext/stock/doctype/purchase_receipt/test_purchase_receipt.py @@ -12,6 +12,7 @@ from erpnext import set_perpetual_inventory from erpnext.stock.doctype.serial_no.serial_no import SerialNoDuplicateError from erpnext.accounts.doctype.account.test_account import get_inventory_account + class TestPurchaseReceipt(unittest.TestCase): def setUp(self): frappe.db.set_value("Buying Settings", None, "allow_multiple_items", 1) @@ -259,7 +260,7 @@ class TestPurchaseReceipt(unittest.TestCase): item_code = frappe.db.get_value('Item', {'has_serial_no': 1}) if not item_code: - item = make_item("Test Serial Item 1", dict(has_serial_no = 1)) + item = make_item("Test Serial Item 1", dict(has_serial_no=1)) item_code = item.name serial_no = random_string(5) @@ -273,11 +274,13 @@ class TestPurchaseReceipt(unittest.TestCase): serial_no=serial_no, basic_rate=100, do_not_submit=True) self.assertRaises(SerialNoDuplicateError, se.submit) + def get_gl_entries(voucher_type, voucher_no): return frappe.db.sql("""select account, debit, credit from `tabGL Entry` where voucher_type=%s and voucher_no=%s order by account desc""", (voucher_type, voucher_no), as_dict=1) + def make_purchase_receipt(**args): frappe.db.set_value("Buying Settings", None, "allow_multiple_items", 1) pr = frappe.new_doc("Purchase Receipt") diff --git a/erpnext/stock/doctype/stock_entry/stock_entry_utils.py b/erpnext/stock/doctype/stock_entry/stock_entry_utils.py index e1ec3ee9f3..446f718f59 100644 --- a/erpnext/stock/doctype/stock_entry/stock_entry_utils.py +++ b/erpnext/stock/doctype/stock_entry/stock_entry_utils.py @@ -20,6 +20,16 @@ def make_stock_entry(**args): :do_not_save: Optional flag :do_not_submit: Optional flag ''' + + def process_serial_numbers(serial_nos_list): + serial_nos_list = [ + '\n'.join(serial_num['serial_no'] for serial_num in serial_nos_list) + ] + + uniques = list(set(serial_nos_list[0].split('\n'))) + + return '\n'.join(uniques) + s = frappe.new_doc("Stock Entry") args = frappe._dict(args) @@ -77,6 +87,25 @@ def make_stock_entry(**args): if not args.cost_center: args.cost_center = frappe.get_value('Company', s.company, 'cost_center') + if not args.expense_account: + args.expense_account = frappe.get_value('Company', s.company, 'stock_adjustment_account') + + # We can find out the serial number using the batch source document + serial_number = args.serial_no + + if not args.serial_no and args.qty and args.batch_no: + serial_number_list = frappe.get_list( + doctype='Stock Ledger Entry', + fields=['serial_no'], + filters={ + 'batch_no': args.batch_no, + 'warehouse': args.from_warehouse + } + ) + serial_number = process_serial_numbers(serial_number_list) + + args.serial_no = serial_number + s.append("items", { "item_code": args.item, "s_warehouse": args.source,