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
diff --git a/erpnext/stock/doctype/batch/batch.js b/erpnext/stock/doctype/batch/batch.js
index 1822a06..d299ed1 100644
--- a/erpnext/stock/doctype/batch/batch.js
+++ b/erpnext/stock/doctype/batch/batch.js
@@ -65,31 +65,38 @@
// 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',
- ['<a href="#Form/Stock Entry/'+r.message.name+'">' + r.message.name+ '</a>']));
- 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',
+ ['<a href="#Form/Stock Entry/'+r.message.name+'">' + r.message.name+ '</a>']));
+ 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 6af8c09..b656c3f 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.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 @@
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 @@
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 e1ec3ee..446f718 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 @@
: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 @@
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,