Test cases for batch no
This commit is contained in:
parent
87c4b06437
commit
059890ecef
@ -257,10 +257,10 @@ def get_batches(item_code, warehouse, qty=1, throw=False):
|
|||||||
'on (`tabBatch`.batch_id = `tabStock Ledger Entry`.batch_no )'
|
'on (`tabBatch`.batch_id = `tabStock Ledger Entry`.batch_no )'
|
||||||
'where `tabStock Ledger Entry`.item_code = %s and `tabStock Ledger Entry`.warehouse = %s '
|
'where `tabStock Ledger Entry`.item_code = %s and `tabStock Ledger Entry`.warehouse = %s '
|
||||||
'and (`tabBatch`.expiry_date >= CURDATE() or `tabBatch`.expiry_date IS NULL)'
|
'and (`tabBatch`.expiry_date >= CURDATE() or `tabBatch`.expiry_date IS NULL)'
|
||||||
'group by batch_id having qty > 0'
|
'group by batch_id '
|
||||||
'order by `tabBatch`.expiry_date ASC, `tabBatch`.creation ASC',
|
'order by `tabBatch`.expiry_date ASC, `tabBatch`.creation ASC',
|
||||||
(item_code, warehouse),
|
(item_code, warehouse),
|
||||||
as_dict=True, debug=1
|
as_dict=True
|
||||||
)
|
)
|
||||||
|
|
||||||
return batches
|
return batches
|
||||||
|
@ -423,7 +423,6 @@ def update_serial_nos_after_submit(controller, parentfield):
|
|||||||
else d.stock_qty)
|
else d.stock_qty)
|
||||||
|
|
||||||
for sle in stock_ledger_entries:
|
for sle in stock_ledger_entries:
|
||||||
print(accepted_serial_nos_updated, qty, sle.actual_qty)
|
|
||||||
if sle.voucher_detail_no==d.name:
|
if sle.voucher_detail_no==d.name:
|
||||||
if not accepted_serial_nos_updated and qty and abs(sle.actual_qty)==qty \
|
if not accepted_serial_nos_updated and qty and abs(sle.actual_qty)==qty \
|
||||||
and sle.warehouse == warehouse and sle.serial_no != d.serial_no:
|
and sle.warehouse == warehouse and sle.serial_no != d.serial_no:
|
||||||
|
@ -153,6 +153,7 @@ frappe.ui.form.on("Stock Reconciliation Item", {
|
|||||||
barcode: function(frm, cdt, cdn) {
|
barcode: function(frm, cdt, cdn) {
|
||||||
frm.events.set_item_code(frm, cdt, cdn);
|
frm.events.set_item_code(frm, cdt, cdn);
|
||||||
},
|
},
|
||||||
|
|
||||||
warehouse: function(frm, cdt, cdn) {
|
warehouse: function(frm, cdt, cdn) {
|
||||||
var child = locals[cdt][cdn];
|
var child = locals[cdt][cdn];
|
||||||
if (child.batch_no) {
|
if (child.batch_no) {
|
||||||
@ -161,22 +162,35 @@ frappe.ui.form.on("Stock Reconciliation Item", {
|
|||||||
|
|
||||||
frm.events.set_valuation_rate_and_qty(frm, cdt, cdn);
|
frm.events.set_valuation_rate_and_qty(frm, cdt, cdn);
|
||||||
},
|
},
|
||||||
|
|
||||||
item_code: function(frm, cdt, cdn) {
|
item_code: function(frm, cdt, cdn) {
|
||||||
var child = locals[cdt][cdn];
|
var child = locals[cdt][cdn];
|
||||||
if (child.batch_no) {
|
if (child.batch_no) {
|
||||||
frappe.model.set_value(child.cdt, child.cdn, "batch_no", "");
|
frappe.model.set_value(cdt, cdn, "batch_no", "");
|
||||||
}
|
}
|
||||||
|
|
||||||
frm.events.set_valuation_rate_and_qty(frm, cdt, cdn);
|
frm.events.set_valuation_rate_and_qty(frm, cdt, cdn);
|
||||||
},
|
},
|
||||||
|
|
||||||
batch_no: function(frm, cdt, cdn) {
|
batch_no: function(frm, cdt, cdn) {
|
||||||
frm.events.set_valuation_rate_and_qty(frm, cdt, cdn);
|
frm.events.set_valuation_rate_and_qty(frm, cdt, cdn);
|
||||||
},
|
},
|
||||||
|
|
||||||
qty: function(frm, cdt, cdn) {
|
qty: function(frm, cdt, cdn) {
|
||||||
frm.events.set_amount_quantity(frm, cdt, cdn);
|
frm.events.set_amount_quantity(frm, cdt, cdn);
|
||||||
},
|
},
|
||||||
|
|
||||||
valuation_rate: function(frm, cdt, cdn) {
|
valuation_rate: function(frm, cdt, cdn) {
|
||||||
frm.events.set_amount_quantity(frm, cdt, cdn);
|
frm.events.set_amount_quantity(frm, cdt, cdn);
|
||||||
|
},
|
||||||
|
|
||||||
|
serial_no: function(frm, cdt, cdn) {
|
||||||
|
var child = locals[cdt][cdn];
|
||||||
|
|
||||||
|
if (child.serial_no) {
|
||||||
|
const serial_nos = child.serial_no.trim().split('\n');
|
||||||
|
frappe.model.set_value(cdt, cdn, "qty", serial_nos.length);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
});
|
});
|
||||||
|
@ -32,6 +32,9 @@ class StockReconciliation(StockController):
|
|||||||
self.validate_expense_account()
|
self.validate_expense_account()
|
||||||
self.set_total_qty_and_amount()
|
self.set_total_qty_and_amount()
|
||||||
|
|
||||||
|
if self._action=="submit":
|
||||||
|
self.make_batches('warehouse')
|
||||||
|
|
||||||
def on_submit(self):
|
def on_submit(self):
|
||||||
self.update_stock_ledger()
|
self.update_stock_ledger()
|
||||||
self.make_gl_entries()
|
self.make_gl_entries()
|
||||||
@ -50,16 +53,16 @@ class StockReconciliation(StockController):
|
|||||||
item_dict = get_stock_balance_for(item.item_code, item.warehouse,
|
item_dict = get_stock_balance_for(item.item_code, item.warehouse,
|
||||||
self.posting_date, self.posting_time, batch_no=item.batch_no)
|
self.posting_date, self.posting_time, batch_no=item.batch_no)
|
||||||
|
|
||||||
if ((item.qty==None or item.qty==item_dict.get("qty"))
|
if (((item.qty is None or item.qty==item_dict.get("qty")) and
|
||||||
and (item.valuation_rate==None or item.valuation_rate==item_dict.get("rate"))
|
(item.valuation_rate is None or item.valuation_rate==item_dict.get("rate")) and not item.serial_no)
|
||||||
and item.serial_no == item_dict.get("serial_nos")):
|
or (item.serial_no and item.serial_no == item_dict.get("serial_nos"))):
|
||||||
return False
|
return False
|
||||||
else:
|
else:
|
||||||
# set default as current rates
|
# set default as current rates
|
||||||
if item.qty==None:
|
if item.qty is None:
|
||||||
item.qty = item_dict.get("qty")
|
item.qty = item_dict.get("qty")
|
||||||
|
|
||||||
if item.valuation_rate==None:
|
if item.valuation_rate is None:
|
||||||
item.valuation_rate = item_dict.get("rate")
|
item.valuation_rate = item_dict.get("rate")
|
||||||
|
|
||||||
if item_dict.get("serial_nos"):
|
if item_dict.get("serial_nos"):
|
||||||
@ -162,15 +165,12 @@ class StockReconciliation(StockController):
|
|||||||
|
|
||||||
# item should not be serialized
|
# item should not be serialized
|
||||||
if item.has_serial_no and not row.serial_no and not item.serial_no_series:
|
if item.has_serial_no and not row.serial_no and not item.serial_no_series:
|
||||||
raise frappe.ValidationError(_("Serial nos are required for serialized item {0}").format(item_code))
|
raise frappe.ValidationError(_("Serial no(s) required for serialized item {0}").format(item_code))
|
||||||
|
|
||||||
# item managed batch-wise not allowed
|
# item managed batch-wise not allowed
|
||||||
if item.has_batch_no and not row.batch_no and not item.create_new_batch:
|
if item.has_batch_no and not row.batch_no and not item.create_new_batch:
|
||||||
raise frappe.ValidationError(_("Batch no is required for batched item {0}").format(item_code))
|
raise frappe.ValidationError(_("Batch no is required for batched item {0}").format(item_code))
|
||||||
|
|
||||||
if self._action=="submit" and item.create_new_batch:
|
|
||||||
self.make_batches('warehouse')
|
|
||||||
|
|
||||||
# docstatus should be < 2
|
# docstatus should be < 2
|
||||||
validate_cancelled_item(item_code, item.docstatus, verbose=0)
|
validate_cancelled_item(item_code, item.docstatus, verbose=0)
|
||||||
|
|
||||||
@ -203,7 +203,7 @@ class StockReconciliation(StockController):
|
|||||||
row.valuation_rate = previous_sle.get("valuation_rate", 0)
|
row.valuation_rate = previous_sle.get("valuation_rate", 0)
|
||||||
|
|
||||||
if row.qty and not row.valuation_rate:
|
if row.qty and not row.valuation_rate:
|
||||||
frappe.throw(_("Valuation Rate required for Item in row {0}").format(row.idx))
|
frappe.throw(_("Valuation Rate required for Item {0} at row {1}").format(row.item_code, row.idx))
|
||||||
|
|
||||||
if ((previous_sle and row.qty == previous_sle.get("qty_after_transaction")
|
if ((previous_sle and row.qty == previous_sle.get("qty_after_transaction")
|
||||||
and (row.valuation_rate == previous_sle.get("valuation_rate") or row.qty == 0))
|
and (row.valuation_rate == previous_sle.get("valuation_rate") or row.qty == 0))
|
||||||
@ -270,7 +270,7 @@ class StockReconciliation(StockController):
|
|||||||
|
|
||||||
sl_entries.append(args)
|
sl_entries.append(args)
|
||||||
|
|
||||||
if self.docstatus == 1 and not row.remove_serial_no_from_stock:
|
if self.docstatus == 1 and row.qty:
|
||||||
args = self.get_sle_for_items(row)
|
args = self.get_sle_for_items(row)
|
||||||
|
|
||||||
args.update({
|
args.update({
|
||||||
@ -332,7 +332,7 @@ class StockReconciliation(StockController):
|
|||||||
|
|
||||||
sl_entries = []
|
sl_entries = []
|
||||||
for row in self.items:
|
for row in self.items:
|
||||||
if row.serial_no or row.batch_no:
|
if row.serial_no or row.batch_no or row.current_serial_no:
|
||||||
self.get_sle_for_serialized_items(row, sl_entries)
|
self.get_sle_for_serialized_items(row, sl_entries)
|
||||||
|
|
||||||
if sl_entries:
|
if sl_entries:
|
||||||
|
@ -13,7 +13,7 @@ from erpnext.stock.stock_ledger import get_previous_sle, update_entries_after
|
|||||||
from erpnext.stock.doctype.stock_reconciliation.stock_reconciliation import EmptyStockReconciliationItemsError, get_items
|
from erpnext.stock.doctype.stock_reconciliation.stock_reconciliation import EmptyStockReconciliationItemsError, get_items
|
||||||
from erpnext.stock.doctype.warehouse.test_warehouse import create_warehouse
|
from erpnext.stock.doctype.warehouse.test_warehouse import create_warehouse
|
||||||
from erpnext.stock.doctype.item.test_item import create_item
|
from erpnext.stock.doctype.item.test_item import create_item
|
||||||
from erpnext.stock.utils import get_stock_balance, get_incoming_rate, get_available_serial_nos
|
from erpnext.stock.utils import get_stock_balance, get_incoming_rate, get_available_serial_nos, get_stock_value_on
|
||||||
from erpnext.stock.doctype.serial_no.serial_no import get_serial_nos
|
from erpnext.stock.doctype.serial_no.serial_no import get_serial_nos
|
||||||
|
|
||||||
class TestStockReconciliation(unittest.TestCase):
|
class TestStockReconciliation(unittest.TestCase):
|
||||||
@ -169,10 +169,62 @@ class TestStockReconciliation(unittest.TestCase):
|
|||||||
if frappe.db.exists("Serial No", d):
|
if frappe.db.exists("Serial No", d):
|
||||||
frappe.delete_doc("Serial No", d)
|
frappe.delete_doc("Serial No", d)
|
||||||
|
|
||||||
|
def test_stock_reco_for_batch_item(self):
|
||||||
|
set_perpetual_inventory()
|
||||||
|
|
||||||
|
to_delete_records = []
|
||||||
|
to_delete_serial_nos = []
|
||||||
|
|
||||||
|
# Add new serial nos
|
||||||
|
item_code = "Stock-Reco-batch-Item-1"
|
||||||
|
warehouse = "_Test Warehouse for Stock Reco2 - _TC"
|
||||||
|
|
||||||
|
sr = create_stock_reconciliation(item_code=item_code,
|
||||||
|
warehouse = warehouse, qty=5, rate=200, do_not_submit=1)
|
||||||
|
sr.save(ignore_permissions=True)
|
||||||
|
sr.submit()
|
||||||
|
|
||||||
|
self.assertTrue(sr.items[0].batch_no)
|
||||||
|
to_delete_records.append(sr.name)
|
||||||
|
|
||||||
|
sr1 = create_stock_reconciliation(item_code=item_code,
|
||||||
|
warehouse = warehouse, qty=6, rate=300, batch_no=sr.items[0].batch_no)
|
||||||
|
|
||||||
|
args = {
|
||||||
|
"item_code": item_code,
|
||||||
|
"warehouse": warehouse,
|
||||||
|
"posting_date": nowdate(),
|
||||||
|
"posting_time": nowtime(),
|
||||||
|
}
|
||||||
|
|
||||||
|
valuation_rate = get_incoming_rate(args)
|
||||||
|
self.assertEqual(valuation_rate, 300)
|
||||||
|
to_delete_records.append(sr1.name)
|
||||||
|
|
||||||
|
|
||||||
|
sr2 = create_stock_reconciliation(item_code=item_code,
|
||||||
|
warehouse = warehouse, qty=0, rate=0, batch_no=sr.items[0].batch_no)
|
||||||
|
|
||||||
|
stock_value = get_stock_value_on(warehouse, nowdate(), item_code)
|
||||||
|
self.assertEqual(stock_value, 0)
|
||||||
|
to_delete_records.append(sr2.name)
|
||||||
|
|
||||||
|
to_delete_records.reverse()
|
||||||
|
for d in to_delete_records:
|
||||||
|
stock_doc = frappe.get_doc("Stock Reconciliation", d)
|
||||||
|
stock_doc.cancel()
|
||||||
|
|
||||||
|
frappe.delete_doc("Batch", sr.items[0].batch_no)
|
||||||
|
for d in to_delete_records:
|
||||||
|
frappe.delete_doc("Stock Reconciliation", d)
|
||||||
|
|
||||||
def create_batch_or_serial_no_items():
|
def create_batch_or_serial_no_items():
|
||||||
create_warehouse("_Test Warehouse for Stock Reco1",
|
create_warehouse("_Test Warehouse for Stock Reco1",
|
||||||
{"is_group": 0, "parent_warehouse": "_Test Warehouse Group - _TC"})
|
{"is_group": 0, "parent_warehouse": "_Test Warehouse Group - _TC"})
|
||||||
|
|
||||||
|
create_warehouse("_Test Warehouse for Stock Reco2",
|
||||||
|
{"is_group": 0, "parent_warehouse": "_Test Warehouse Group - _TC"})
|
||||||
|
|
||||||
serial_item_doc = create_item("Stock-Reco-Serial-Item-1", is_stock_item=1)
|
serial_item_doc = create_item("Stock-Reco-Serial-Item-1", is_stock_item=1)
|
||||||
if not serial_item_doc.has_serial_no:
|
if not serial_item_doc.has_serial_no:
|
||||||
serial_item_doc.has_serial_no = 1
|
serial_item_doc.has_serial_no = 1
|
||||||
@ -202,12 +254,12 @@ def create_stock_reconciliation(**args):
|
|||||||
"qty": args.qty,
|
"qty": args.qty,
|
||||||
"valuation_rate": args.rate,
|
"valuation_rate": args.rate,
|
||||||
"serial_no": args.serial_no,
|
"serial_no": args.serial_no,
|
||||||
"batch_no": args.batch_no,
|
"batch_no": args.batch_no
|
||||||
"remove_serial_no_from_stock": args.remove_serial_no_from_stock or 0
|
|
||||||
})
|
})
|
||||||
|
|
||||||
try:
|
try:
|
||||||
sr.submit()
|
if not args.do_not_submit:
|
||||||
|
sr.submit()
|
||||||
except EmptyStockReconciliationItemsError:
|
except EmptyStockReconciliationItemsError:
|
||||||
pass
|
pass
|
||||||
return sr
|
return sr
|
||||||
|
@ -15,7 +15,6 @@
|
|||||||
"amount",
|
"amount",
|
||||||
"serial_no_and_batch_section",
|
"serial_no_and_batch_section",
|
||||||
"serial_no",
|
"serial_no",
|
||||||
"remove_serial_no_from_stock",
|
|
||||||
"column_break_11",
|
"column_break_11",
|
||||||
"batch_no",
|
"batch_no",
|
||||||
"section_break_3",
|
"section_break_3",
|
||||||
@ -110,6 +109,7 @@
|
|||||||
"label": "Before reconciliation"
|
"label": "Before reconciliation"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
"default": "0",
|
||||||
"fieldname": "current_qty",
|
"fieldname": "current_qty",
|
||||||
"fieldtype": "Float",
|
"fieldtype": "Float",
|
||||||
"label": "Current Qty",
|
"label": "Current Qty",
|
||||||
@ -166,16 +166,10 @@
|
|||||||
"fieldtype": "Link",
|
"fieldtype": "Link",
|
||||||
"label": "Batch No",
|
"label": "Batch No",
|
||||||
"options": "Batch"
|
"options": "Batch"
|
||||||
},
|
|
||||||
{
|
|
||||||
"default": "0",
|
|
||||||
"fieldname": "remove_serial_no_from_stock",
|
|
||||||
"fieldtype": "Check",
|
|
||||||
"label": "Remove Serial No from Stock"
|
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"istable": 1,
|
"istable": 1,
|
||||||
"modified": "2019-06-01 03:16:38.459307",
|
"modified": "2019-06-14 17:10:53.188305",
|
||||||
"modified_by": "Administrator",
|
"modified_by": "Administrator",
|
||||||
"module": "Stock",
|
"module": "Stock",
|
||||||
"name": "Stock Reconciliation Item",
|
"name": "Stock Reconciliation Item",
|
||||||
|
Loading…
Reference in New Issue
Block a user