refactored code for reserved qty with testcases
This commit is contained in:
parent
c924c1ebb5
commit
87d270a5b5
@ -384,25 +384,27 @@ class DocType(TransactionBase):
|
|||||||
def get_item_list(self, obj, is_stopped=0):
|
def get_item_list(self, obj, is_stopped=0):
|
||||||
"""get item list"""
|
"""get item list"""
|
||||||
il = []
|
il = []
|
||||||
for d in getlist(obj.doclist,obj.fname):
|
for d in getlist(obj.doclist, obj.fname):
|
||||||
reserved_wh, reserved_qty = '', 0 # used for delivery note
|
reserved_warehouse = ""
|
||||||
qty = flt(d.qty)
|
reserved_qty_for_main_item = 0
|
||||||
if is_stopped:
|
|
||||||
qty = flt(d.qty) > flt(d.delivered_qty) and flt(flt(d.qty) - flt(d.delivered_qty)) or 0
|
|
||||||
|
|
||||||
if d.prevdoc_doctype == 'Sales Order':
|
if obj.doc.doctype == "Sales Order":
|
||||||
# used in delivery note to reduce reserved_qty
|
reserved_warehouse = d.reserved_warehouse
|
||||||
# Eg.: if SO qty is 10 and there is tolerance of 20%, then it will allow DN of 12.
|
if flt(d.qty) > flt(d.delivered_qty):
|
||||||
# But in this case reserved qty should only be reduced by 10 and not 12.
|
reserved_qty_for_main_item = flt(d.qty) - flt(d.delivered_qty)
|
||||||
|
|
||||||
tot_qty, max_qty, tot_amt, max_amt, reserved_wh = self.get_curr_and_ref_doc_details(d.doctype, 'prevdoc_detail_docname', d.prevdoc_detail_docname, obj.doc.name, obj.doc.doctype)
|
if obj.doc.doctype == "Delivery Note" and d.prevdoc_doctype == 'Sales Order':
|
||||||
if((flt(tot_qty) + flt(qty) > flt(max_qty))):
|
# if SO qty is 10 and there is tolerance of 20%, then it will allow DN of 12.
|
||||||
reserved_qty = -(flt(max_qty)-flt(tot_qty))
|
# But in this case reserved qty should only be reduced by 10 and not 12
|
||||||
|
|
||||||
|
already_delivered_qty = self.get_already_delivered_qty(obj.doc.name,
|
||||||
|
d.prevdoc_docname, d.prevdoc_detail_docname)
|
||||||
|
so_qty, reserved_warehouse = self.get_so_qty_and_warehouse(d.prevdoc_detail_docname)
|
||||||
|
|
||||||
|
if already_delivered_qty + d.qty > so_qty:
|
||||||
|
reserved_qty_for_main_item = -(so_qty - already_delivered_qty)
|
||||||
else:
|
else:
|
||||||
reserved_qty = - flt(qty)
|
reserved_qty_for_main_item = -flt(d.qty)
|
||||||
|
|
||||||
if obj.doc.doctype == 'Sales Order':
|
|
||||||
reserved_wh = d.reserved_warehouse
|
|
||||||
|
|
||||||
if self.has_sales_bom(d.item_code):
|
if self.has_sales_bom(d.item_code):
|
||||||
for p in getlist(obj.doclist, 'packing_details'):
|
for p in getlist(obj.doclist, 'packing_details'):
|
||||||
@ -410,10 +412,10 @@ class DocType(TransactionBase):
|
|||||||
# the packing details table's qty is already multiplied with parent's qty
|
# the packing details table's qty is already multiplied with parent's qty
|
||||||
il.append({
|
il.append({
|
||||||
'warehouse': p.warehouse,
|
'warehouse': p.warehouse,
|
||||||
'reserved_warehouse': reserved_wh,
|
'reserved_warehouse': reserved_warehouse,
|
||||||
'item_code': p.item_code,
|
'item_code': p.item_code,
|
||||||
'qty': flt(p.qty),
|
'qty': flt(p.qty),
|
||||||
'reserved_qty': (flt(p.qty)/qty)*(reserved_qty),
|
'reserved_qty': (flt(p.qty)/flt(d.qty)) * reserved_qty_for_main_item,
|
||||||
'uom': p.uom,
|
'uom': p.uom,
|
||||||
'batch_no': cstr(p.batch_no).strip(),
|
'batch_no': cstr(p.batch_no).strip(),
|
||||||
'serial_no': cstr(p.serial_no).strip(),
|
'serial_no': cstr(p.serial_no).strip(),
|
||||||
@ -422,10 +424,10 @@ class DocType(TransactionBase):
|
|||||||
else:
|
else:
|
||||||
il.append({
|
il.append({
|
||||||
'warehouse': d.warehouse,
|
'warehouse': d.warehouse,
|
||||||
'reserved_warehouse': reserved_wh,
|
'reserved_warehouse': reserved_warehouse,
|
||||||
'item_code': d.item_code,
|
'item_code': d.item_code,
|
||||||
'qty': qty,
|
'qty': d.qty,
|
||||||
'reserved_qty': reserved_qty,
|
'reserved_qty': reserved_qty_for_main_item,
|
||||||
'uom': d.stock_uom,
|
'uom': d.stock_uom,
|
||||||
'batch_no': cstr(d.batch_no).strip(),
|
'batch_no': cstr(d.batch_no).strip(),
|
||||||
'serial_no': cstr(d.serial_no).strip(),
|
'serial_no': cstr(d.serial_no).strip(),
|
||||||
@ -433,27 +435,20 @@ class DocType(TransactionBase):
|
|||||||
})
|
})
|
||||||
return il
|
return il
|
||||||
|
|
||||||
|
def get_already_delivered_qty(self, dn, so, so_detail):
|
||||||
|
qty = webnotes.conn.sql("""select sum(qty) from `tabDelivery Note Item`
|
||||||
|
where prevdoc_detail_docname = %s and docstatus = 1
|
||||||
|
and prevdoc_doctype = 'Sales Order' and prevdoc_docname = %s
|
||||||
|
and parent != %s""", (so_detail, so, dn))
|
||||||
|
return qty and flt(qty[0][0]) or 0.0
|
||||||
|
|
||||||
def get_curr_and_ref_doc_details(self, curr_doctype, ref_tab_fname, ref_tab_dn, curr_parent_name, curr_parent_doctype):
|
def get_so_qty_and_warehouse(self, so_detail):
|
||||||
""" Get qty, amount already billed or delivered against curr line item for current doctype
|
so_item = webnotes.conn.sql("""select qty, reserved_warehouse from `tabSales Order Item`
|
||||||
For Eg: SO-RV get total qty, amount from SO and also total qty, amount against that SO in RV
|
where name = %s and docstatus = 1""", so_detail, as_dict=1)
|
||||||
"""
|
so_qty = so_item and flt(so_item[0]["qty"]) or 0.0
|
||||||
#Get total qty, amt of current doctype (eg RV) except for qty, amt of this transaction
|
so_warehouse = so_item and so_item[0]["reserved_warehouse"] or ""
|
||||||
if curr_parent_doctype == 'Installation Note':
|
return so_qty, so_warehouse
|
||||||
curr_det = webnotes.conn.sql("select sum(qty) from `tab%s` where %s = '%s' and docstatus = 1 and parent != '%s'"% (curr_doctype, ref_tab_fname, ref_tab_dn, curr_parent_name))
|
|
||||||
qty, amt = curr_det and flt(curr_det[0][0]) or 0, 0
|
|
||||||
else:
|
|
||||||
curr_det = webnotes.conn.sql("select sum(qty), sum(amount) from `tab%s` where %s = '%s' and docstatus = 1 and parent != '%s'"% (curr_doctype, ref_tab_fname, ref_tab_dn, curr_parent_name))
|
|
||||||
qty, amt = curr_det and flt(curr_det[0][0]) or 0, curr_det and flt(curr_det[0][1]) or 0
|
|
||||||
|
|
||||||
# get total qty of ref doctype
|
|
||||||
so_det = webnotes.conn.sql("select qty, amount, reserved_warehouse from `tabSales Order Item` where name = '%s' and docstatus = 1"% ref_tab_dn)
|
|
||||||
max_qty, max_amt, res_wh = so_det and flt(so_det[0][0]) or 0, so_det and flt(so_det[0][1]) or 0, so_det and cstr(so_det[0][2]) or ''
|
|
||||||
return qty, max_qty, amt, max_amt, res_wh
|
|
||||||
|
|
||||||
|
|
||||||
# Make Packing List from Sales BOM
|
|
||||||
# =======================================================================
|
|
||||||
def has_sales_bom(self, item_code):
|
def has_sales_bom(self, item_code):
|
||||||
return webnotes.conn.sql("select name from `tabSales BOM` where new_item_code=%s and docstatus != 2", item_code)
|
return webnotes.conn.sql("select name from `tabSales BOM` where new_item_code=%s and docstatus != 2", item_code)
|
||||||
|
|
||||||
|
@ -320,20 +320,20 @@ class DocType(SellingController):
|
|||||||
|
|
||||||
def stop_sales_order(self):
|
def stop_sales_order(self):
|
||||||
self.check_modified_date()
|
self.check_modified_date()
|
||||||
self.update_stock_ledger(update_stock = -1,clear = 1)
|
self.update_stock_ledger(update_stock = -1,is_stopped = 1)
|
||||||
webnotes.conn.set(self.doc, 'status', 'Stopped')
|
webnotes.conn.set(self.doc, 'status', 'Stopped')
|
||||||
msgprint("""%s: %s has been Stopped. To make transactions against this Sales Order
|
msgprint("""%s: %s has been Stopped. To make transactions against this Sales Order
|
||||||
you need to Unstop it.""" % (self.doc.doctype, self.doc.name))
|
you need to Unstop it.""" % (self.doc.doctype, self.doc.name))
|
||||||
|
|
||||||
def unstop_sales_order(self):
|
def unstop_sales_order(self):
|
||||||
self.check_modified_date()
|
self.check_modified_date()
|
||||||
self.update_stock_ledger(update_stock = 1,clear = 1)
|
self.update_stock_ledger(update_stock = 1,is_stopped = 1)
|
||||||
webnotes.conn.set(self.doc, 'status', 'Submitted')
|
webnotes.conn.set(self.doc, 'status', 'Submitted')
|
||||||
msgprint("%s: %s has been Unstopped" % (self.doc.doctype, self.doc.name))
|
msgprint("%s: %s has been Unstopped" % (self.doc.doctype, self.doc.name))
|
||||||
|
|
||||||
|
|
||||||
def update_stock_ledger(self, update_stock, clear = 0):
|
def update_stock_ledger(self, update_stock, is_stopped = 0):
|
||||||
for d in self.get_item_list(clear):
|
for d in self.get_item_list(is_stopped):
|
||||||
if webnotes.conn.get_value("Item", d['item_code'], "is_stock_item") == "Yes":
|
if webnotes.conn.get_value("Item", d['item_code'], "is_stock_item") == "Yes":
|
||||||
if not d['reserved_warehouse']:
|
if not d['reserved_warehouse']:
|
||||||
msgprint("""Please enter Reserved Warehouse for item %s
|
msgprint("""Please enter Reserved Warehouse for item %s
|
||||||
@ -341,7 +341,7 @@ class DocType(SellingController):
|
|||||||
|
|
||||||
args = {
|
args = {
|
||||||
"item_code": d['item_code'],
|
"item_code": d['item_code'],
|
||||||
"reserved_qty": flt(update_stock) * flt(d['qty']),
|
"reserved_qty": flt(update_stock) * flt(d['reserved_qty']),
|
||||||
"posting_date": self.doc.transaction_date,
|
"posting_date": self.doc.transaction_date,
|
||||||
"voucher_type": self.doc.doctype,
|
"voucher_type": self.doc.doctype,
|
||||||
"voucher_no": self.doc.name,
|
"voucher_no": self.doc.name,
|
||||||
@ -350,8 +350,8 @@ class DocType(SellingController):
|
|||||||
get_obj('Warehouse', d['reserved_warehouse']).update_bin(args)
|
get_obj('Warehouse', d['reserved_warehouse']).update_bin(args)
|
||||||
|
|
||||||
|
|
||||||
def get_item_list(self, clear):
|
def get_item_list(self, is_stopped):
|
||||||
return get_obj('Sales Common').get_item_list( self, clear)
|
return get_obj('Sales Common').get_item_list( self, is_stopped)
|
||||||
|
|
||||||
def on_update(self):
|
def on_update(self):
|
||||||
pass
|
pass
|
@ -3,49 +3,218 @@ from webnotes.utils import flt
|
|||||||
import unittest
|
import unittest
|
||||||
|
|
||||||
class TestSalesOrder(unittest.TestCase):
|
class TestSalesOrder(unittest.TestCase):
|
||||||
def make(self):
|
def create_so(self, so_doclist = None):
|
||||||
w = webnotes.model_wrapper(webnotes.copy_doclist(test_records[0]))
|
if not so_doclist:
|
||||||
|
so_doclist =test_records[0]
|
||||||
|
|
||||||
|
w = webnotes.bean(copy=so_doclist)
|
||||||
w.insert()
|
w.insert()
|
||||||
w.submit()
|
w.submit()
|
||||||
return w
|
return w
|
||||||
|
|
||||||
|
def create_dn_against_so(self, so, delivered_qty=0):
|
||||||
|
from stock.doctype.delivery_note.test_delivery_note import test_records as dn_test_records
|
||||||
|
dn = webnotes.bean(webnotes.copy_doclist(dn_test_records[0]))
|
||||||
|
dn.doclist[1].item_code = so.doclist[1].item_code
|
||||||
|
dn.doclist[1].prevdoc_doctype = "Sales Order"
|
||||||
|
dn.doclist[1].prevdoc_docname = so.doc.name
|
||||||
|
dn.doclist[1].prevdoc_detail_docname = so.doclist[1].name
|
||||||
|
if delivered_qty:
|
||||||
|
dn.doclist[1].qty = delivered_qty
|
||||||
|
dn.insert()
|
||||||
|
dn.submit()
|
||||||
|
return dn
|
||||||
|
|
||||||
def get_bin_reserved_qty(self, item_code, warehouse):
|
def get_bin_reserved_qty(self, item_code, warehouse):
|
||||||
return flt(webnotes.conn.get_value("Bin", {"item_code": item_code, "warehouse": warehouse},
|
return flt(webnotes.conn.get_value("Bin", {"item_code": item_code, "warehouse": warehouse},
|
||||||
"reserved_qty"))
|
"reserved_qty"))
|
||||||
|
|
||||||
def test_reserved_qty_so_submit_cancel(self):
|
def delete_bin(self, item_code, warehouse):
|
||||||
# submit
|
bin = webnotes.conn.exists({"doctype": "Bin", "item_code": item_code,
|
||||||
so = self.make()
|
"warehouse": warehouse})
|
||||||
print self.get_bin_reserved_qty(so.doclist[1].item_code,
|
if bin:
|
||||||
so.doclist[1].reserved_warehouse)
|
webnotes.delete_doc("Bin", bin[0][0])
|
||||||
|
|
||||||
|
def check_reserved_qty(self, item_code, warehouse, qty):
|
||||||
|
bin_reserved_qty = self.get_bin_reserved_qty(item_code, warehouse)
|
||||||
|
self.assertEqual(bin_reserved_qty, qty)
|
||||||
|
|
||||||
|
def test_reserved_qty_for_so(self):
|
||||||
|
# reset bin
|
||||||
|
self.delete_bin(test_records[0][1]["item_code"], test_records[0][1]["reserved_warehouse"])
|
||||||
|
|
||||||
|
# submit
|
||||||
|
so = self.create_so()
|
||||||
|
self.check_reserved_qty(so.doclist[1].item_code, so.doclist[1].reserved_warehouse, 10.0)
|
||||||
|
|
||||||
reserved_qty = self.get_bin_reserved_qty(so.doclist[1].item_code,
|
|
||||||
so.doclist[1].reserved_warehouse)
|
|
||||||
self.assertEqual(reserved_qty, 10.0)
|
|
||||||
# cancel
|
# cancel
|
||||||
so.cancel()
|
so.cancel()
|
||||||
reserved_qty = self.get_bin_reserved_qty(so.doclist[1].item_code,
|
self.check_reserved_qty(so.doclist[1].item_code, so.doclist[1].reserved_warehouse, 0.0)
|
||||||
so.doclist[1].reserved_warehouse)
|
|
||||||
self.assertEqual(reserved_qty, 0.0)
|
|
||||||
|
|
||||||
def test_reserved_qty_dn_submit_cancel(self):
|
|
||||||
so = self.make()
|
def test_reserved_qty_for_partial_delivery(self):
|
||||||
|
# reset bin
|
||||||
|
self.delete_bin(test_records[0][1]["item_code"], test_records[0][1]["reserved_warehouse"])
|
||||||
|
|
||||||
|
# submit so
|
||||||
|
so = self.create_so()
|
||||||
|
|
||||||
# allow negative stock
|
# allow negative stock
|
||||||
webnotes.conn.set_default("allow_negative_stock", 1)
|
webnotes.conn.set_default("allow_negative_stock", 1)
|
||||||
|
|
||||||
# dn submit (against so)
|
# submit dn
|
||||||
from stock.doctype.delivery_note.test_delivery_note import test_records as dn_test_records
|
dn = self.create_dn_against_so(so)
|
||||||
dn = webnotes.model_wrapper(webnotes.copy_doclist(dn_test_records[0]))
|
|
||||||
dn.doclist[1].prevdoc_doctype = "Sales Order"
|
|
||||||
dn.doclist[1].prevdoc_docname = so.doc.name
|
|
||||||
dn.doclist[1].prevdoc_detail_docname = so.doclist[1].name
|
|
||||||
dn.insert()
|
|
||||||
dn.submit()
|
|
||||||
|
|
||||||
reserved_qty = self.get_bin_reserved_qty(so.doclist[1].item_code,
|
self.check_reserved_qty(so.doclist[1].item_code, so.doclist[1].reserved_warehouse, 6.0)
|
||||||
so.doclist[1].reserved_warehouse)
|
|
||||||
self.assertEqual(reserved_qty, 6.0)
|
# stop so
|
||||||
|
so.load_from_db()
|
||||||
|
so.obj.stop_sales_order()
|
||||||
|
self.check_reserved_qty(so.doclist[1].item_code, so.doclist[1].reserved_warehouse, 0.0)
|
||||||
|
|
||||||
|
# unstop so
|
||||||
|
so.load_from_db()
|
||||||
|
so.obj.unstop_sales_order()
|
||||||
|
self.check_reserved_qty(so.doclist[1].item_code, so.doclist[1].reserved_warehouse, 6.0)
|
||||||
|
|
||||||
|
# cancel dn
|
||||||
|
dn.cancel()
|
||||||
|
self.check_reserved_qty(so.doclist[1].item_code, so.doclist[1].reserved_warehouse, 10.0)
|
||||||
|
|
||||||
|
def test_reserved_qty_for_over_delivery(self):
|
||||||
|
# reset bin
|
||||||
|
self.delete_bin(test_records[0][1]["item_code"], test_records[0][1]["reserved_warehouse"])
|
||||||
|
|
||||||
|
# submit so
|
||||||
|
so = self.create_so()
|
||||||
|
|
||||||
|
# allow negative stock
|
||||||
|
webnotes.conn.set_default("allow_negative_stock", 1)
|
||||||
|
|
||||||
|
# set over-delivery tolerance
|
||||||
|
webnotes.conn.set_value('Item', so.doclist[1].item_code, 'tolerance', 50)
|
||||||
|
|
||||||
|
# submit dn
|
||||||
|
dn = self.create_dn_against_so(so, 15)
|
||||||
|
self.check_reserved_qty(so.doclist[1].item_code, so.doclist[1].reserved_warehouse, 0.0)
|
||||||
|
|
||||||
|
# cancel dn
|
||||||
|
dn.cancel()
|
||||||
|
self.check_reserved_qty(so.doclist[1].item_code, so.doclist[1].reserved_warehouse, 10.0)
|
||||||
|
|
||||||
|
def test_reserved_qty_for_so_with_packing_list(self):
|
||||||
|
from stock.doctype.sales_bom.test_sales_bom import test_records as sbom_test_records
|
||||||
|
|
||||||
|
# change item in test so record
|
||||||
|
test_record = test_records[0][:]
|
||||||
|
test_record[1]["item_code"] = "_Test Sales BOM Item"
|
||||||
|
|
||||||
|
# reset bin
|
||||||
|
self.delete_bin(sbom_test_records[0][1]["item_code"], test_record[1]["reserved_warehouse"])
|
||||||
|
self.delete_bin(sbom_test_records[0][2]["item_code"], test_record[1]["reserved_warehouse"])
|
||||||
|
|
||||||
|
# submit
|
||||||
|
so = self.create_so(test_record)
|
||||||
|
|
||||||
|
|
||||||
|
self.check_reserved_qty(sbom_test_records[0][1]["item_code"],
|
||||||
|
so.doclist[1].reserved_warehouse, 50.0)
|
||||||
|
self.check_reserved_qty(sbom_test_records[0][2]["item_code"],
|
||||||
|
so.doclist[1].reserved_warehouse, 20.0)
|
||||||
|
|
||||||
|
# cancel
|
||||||
|
so.cancel()
|
||||||
|
self.check_reserved_qty(sbom_test_records[0][1]["item_code"],
|
||||||
|
so.doclist[1].reserved_warehouse, 0.0)
|
||||||
|
self.check_reserved_qty(sbom_test_records[0][2]["item_code"],
|
||||||
|
so.doclist[1].reserved_warehouse, 0.0)
|
||||||
|
|
||||||
|
def test_reserved_qty_for_partial_delivery_with_packing_list(self):
|
||||||
|
from stock.doctype.sales_bom.test_sales_bom import test_records as sbom_test_records
|
||||||
|
|
||||||
|
# change item in test so record
|
||||||
|
|
||||||
|
test_record = webnotes.copy_doclist(test_records[0])
|
||||||
|
test_record[1]["item_code"] = "_Test Sales BOM Item"
|
||||||
|
|
||||||
|
# reset bin
|
||||||
|
self.delete_bin(sbom_test_records[0][1]["item_code"], test_record[1]["reserved_warehouse"])
|
||||||
|
self.delete_bin(sbom_test_records[0][2]["item_code"], test_record[1]["reserved_warehouse"])
|
||||||
|
|
||||||
|
# submit
|
||||||
|
so = self.create_so(test_record)
|
||||||
|
|
||||||
|
# allow negative stock
|
||||||
|
webnotes.conn.set_default("allow_negative_stock", 1)
|
||||||
|
|
||||||
|
# submit dn
|
||||||
|
dn = self.create_dn_against_so(so)
|
||||||
|
|
||||||
|
self.check_reserved_qty(sbom_test_records[0][1]["item_code"],
|
||||||
|
so.doclist[1].reserved_warehouse, 30.0)
|
||||||
|
self.check_reserved_qty(sbom_test_records[0][2]["item_code"],
|
||||||
|
so.doclist[1].reserved_warehouse, 12.0)
|
||||||
|
|
||||||
|
# stop so
|
||||||
|
so.load_from_db()
|
||||||
|
so.obj.stop_sales_order()
|
||||||
|
|
||||||
|
self.check_reserved_qty(sbom_test_records[0][1]["item_code"],
|
||||||
|
so.doclist[1].reserved_warehouse, 0.0)
|
||||||
|
self.check_reserved_qty(sbom_test_records[0][2]["item_code"],
|
||||||
|
so.doclist[1].reserved_warehouse, 0.0)
|
||||||
|
|
||||||
|
# unstop so
|
||||||
|
so.load_from_db()
|
||||||
|
so.obj.unstop_sales_order()
|
||||||
|
self.check_reserved_qty(sbom_test_records[0][1]["item_code"],
|
||||||
|
so.doclist[1].reserved_warehouse, 30.0)
|
||||||
|
self.check_reserved_qty(sbom_test_records[0][2]["item_code"],
|
||||||
|
so.doclist[1].reserved_warehouse, 12.0)
|
||||||
|
|
||||||
|
# cancel dn
|
||||||
|
dn.cancel()
|
||||||
|
self.check_reserved_qty(sbom_test_records[0][1]["item_code"],
|
||||||
|
so.doclist[1].reserved_warehouse, 50.0)
|
||||||
|
self.check_reserved_qty(sbom_test_records[0][2]["item_code"],
|
||||||
|
so.doclist[1].reserved_warehouse, 20.0)
|
||||||
|
|
||||||
|
def test_reserved_qty_for_over_delivery_with_packing_list(self):
|
||||||
|
from stock.doctype.sales_bom.test_sales_bom import test_records as sbom_test_records
|
||||||
|
|
||||||
|
# change item in test so record
|
||||||
|
test_record = webnotes.copy_doclist(test_records[0])
|
||||||
|
test_record[1]["item_code"] = "_Test Sales BOM Item"
|
||||||
|
|
||||||
|
# reset bin
|
||||||
|
self.delete_bin(sbom_test_records[0][1]["item_code"], test_record[1]["reserved_warehouse"])
|
||||||
|
self.delete_bin(sbom_test_records[0][2]["item_code"], test_record[1]["reserved_warehouse"])
|
||||||
|
|
||||||
|
# submit
|
||||||
|
so = self.create_so(test_record)
|
||||||
|
|
||||||
|
# allow negative stock
|
||||||
|
webnotes.conn.set_default("allow_negative_stock", 1)
|
||||||
|
|
||||||
|
# set over-delivery tolerance
|
||||||
|
webnotes.conn.set_value('Item', so.doclist[1].item_code, 'tolerance', 50)
|
||||||
|
|
||||||
|
# submit dn
|
||||||
|
dn = self.create_dn_against_so(so, 15)
|
||||||
|
|
||||||
|
self.check_reserved_qty(sbom_test_records[0][1]["item_code"],
|
||||||
|
so.doclist[1].reserved_warehouse, 0.0)
|
||||||
|
self.check_reserved_qty(sbom_test_records[0][2]["item_code"],
|
||||||
|
so.doclist[1].reserved_warehouse, 0.0)
|
||||||
|
|
||||||
|
# cancel dn
|
||||||
|
dn.cancel()
|
||||||
|
self.check_reserved_qty(sbom_test_records[0][1]["item_code"],
|
||||||
|
so.doclist[1].reserved_warehouse, 50.0)
|
||||||
|
self.check_reserved_qty(sbom_test_records[0][2]["item_code"],
|
||||||
|
so.doclist[1].reserved_warehouse, 20.0)
|
||||||
|
|
||||||
|
test_dependencies = ["Sales BOM"]
|
||||||
|
|
||||||
test_records = [
|
test_records = [
|
||||||
[
|
[
|
||||||
@ -80,5 +249,5 @@ test_records = [
|
|||||||
"amount": 500.0,
|
"amount": 500.0,
|
||||||
"reserved_warehouse": "_Test Warehouse",
|
"reserved_warehouse": "_Test Warehouse",
|
||||||
}
|
}
|
||||||
]
|
],
|
||||||
]
|
]
|
@ -319,9 +319,9 @@ class DocType(SellingController):
|
|||||||
webnotes.msgprint("%s Packing Slip(s) Cancelled" % res[0][1])
|
webnotes.msgprint("%s Packing Slip(s) Cancelled" % res[0][1])
|
||||||
|
|
||||||
|
|
||||||
def update_stock_ledger(self, update_stock, is_stopped = 0):
|
def update_stock_ledger(self, update_stock):
|
||||||
self.values = []
|
self.values = []
|
||||||
for d in self.get_item_list(is_stopped):
|
for d in self.get_item_list():
|
||||||
if webnotes.conn.get_value("Item", d['item_code'], "is_stock_item") == "Yes":
|
if webnotes.conn.get_value("Item", d['item_code'], "is_stock_item") == "Yes":
|
||||||
if not d['warehouse']:
|
if not d['warehouse']:
|
||||||
msgprint("Please enter Warehouse for item %s as it is stock item"
|
msgprint("Please enter Warehouse for item %s as it is stock item"
|
||||||
@ -344,8 +344,8 @@ class DocType(SellingController):
|
|||||||
get_obj('Stock Ledger', 'Stock Ledger').update_stock(self.values)
|
get_obj('Stock Ledger', 'Stock Ledger').update_stock(self.values)
|
||||||
|
|
||||||
|
|
||||||
def get_item_list(self, is_stopped):
|
def get_item_list(self):
|
||||||
return get_obj('Sales Common').get_item_list(self, is_stopped)
|
return get_obj('Sales Common').get_item_list(self)
|
||||||
|
|
||||||
|
|
||||||
def make_sl_entry(self, d, wh, qty, in_value, update_stock):
|
def make_sl_entry(self, d, wh, qty, in_value, update_stock):
|
||||||
|
@ -145,4 +145,23 @@ test_records = [
|
|||||||
"is_sub_contracted_item": "No",
|
"is_sub_contracted_item": "No",
|
||||||
"stock_uom": "_Test UOM"
|
"stock_uom": "_Test UOM"
|
||||||
}],
|
}],
|
||||||
|
[{
|
||||||
|
"doctype": "Item",
|
||||||
|
"item_code": "_Test Sales BOM Item",
|
||||||
|
"item_name": "_Test Sales BOM Item",
|
||||||
|
"description": "_Test Sales BOM Item",
|
||||||
|
"item_group": "_Test Item Group Desktops",
|
||||||
|
"is_stock_item": "No",
|
||||||
|
"is_asset_item": "No",
|
||||||
|
"has_batch_no": "No",
|
||||||
|
"has_serial_no": "No",
|
||||||
|
"is_purchase_item": "Yes",
|
||||||
|
"is_sales_item": "Yes",
|
||||||
|
"is_service_item": "No",
|
||||||
|
"is_sample_item": "No",
|
||||||
|
"inspection_required": "No",
|
||||||
|
"is_pro_applicable": "No",
|
||||||
|
"is_sub_contracted_item": "No",
|
||||||
|
"stock_uom": "_Test UOM"
|
||||||
|
}],
|
||||||
]
|
]
|
20
stock/doctype/sales_bom/test_sales_bom.py
Normal file
20
stock/doctype/sales_bom/test_sales_bom.py
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
test_records = [
|
||||||
|
[
|
||||||
|
{
|
||||||
|
"doctype": "Sales BOM",
|
||||||
|
"new_item_code": "_Test Sales BOM Item"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"doctype": "Sales BOM Item",
|
||||||
|
"item_code": "_Test Item",
|
||||||
|
"parentfield": "sales_bom_items",
|
||||||
|
"qty": 5.0
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"doctype": "Sales BOM Item",
|
||||||
|
"item_code": "_Test Item Home Desktop 100",
|
||||||
|
"parentfield": "sales_bom_items",
|
||||||
|
"qty": 2.0
|
||||||
|
}
|
||||||
|
],
|
||||||
|
]
|
Loading…
Reference in New Issue
Block a user