test case for scrap item
This commit is contained in:
parent
4ae4eb0eb9
commit
8c3764a6ef
@ -86,7 +86,7 @@ var get_bom_material_detail= function(doc, cdt, cdn) {
|
|||||||
refresh_field("scrap_items");
|
refresh_field("scrap_items");
|
||||||
doc = locals[doc.doctype][doc.name];
|
doc = locals[doc.doctype][doc.name];
|
||||||
erpnext.bom.calculate_rm_cost(doc);
|
erpnext.bom.calculate_rm_cost(doc);
|
||||||
erpnext.bom.calculate_sm_cost(doc);
|
erpnext.bom.calculate_scrap_materials_cost(doc);
|
||||||
erpnext.bom.calculate_total(doc);
|
erpnext.bom.calculate_total(doc);
|
||||||
},
|
},
|
||||||
freeze: true
|
freeze: true
|
||||||
@ -137,7 +137,7 @@ erpnext.bom.calculate_rm_cost = function(doc) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
//sm : scrap material
|
//sm : scrap material
|
||||||
erpnext.bom.calculate_sm_cost = function(doc) {
|
erpnext.bom.calculate_scrap_materials_cost = function(doc) {
|
||||||
var sm = doc.scrap_items || [];
|
var sm = doc.scrap_items || [];
|
||||||
total_sm_cost = 0;
|
total_sm_cost = 0;
|
||||||
for(var i=0;i<sm.length;i++) {
|
for(var i=0;i<sm.length;i++) {
|
||||||
@ -188,7 +188,7 @@ cur_frm.fields_dict['items'].grid.get_field('bom_no').get_query = function(doc,
|
|||||||
cur_frm.cscript.validate = function(doc, dt, dn) {
|
cur_frm.cscript.validate = function(doc, dt, dn) {
|
||||||
erpnext.bom.calculate_op_cost(doc);
|
erpnext.bom.calculate_op_cost(doc);
|
||||||
erpnext.bom.calculate_rm_cost(doc);
|
erpnext.bom.calculate_rm_cost(doc);
|
||||||
erpnext.bom.calculate_sm_cost(doc);
|
erpnext.bom.calculate_scrap_materials_cost(doc);
|
||||||
erpnext.bom.calculate_total(doc);
|
erpnext.bom.calculate_total(doc);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -366,7 +366,7 @@
|
|||||||
{
|
{
|
||||||
"allow_on_submit": 0,
|
"allow_on_submit": 0,
|
||||||
"bold": 0,
|
"bold": 0,
|
||||||
"collapsible": 0,
|
"collapsible": 1,
|
||||||
"columns": 0,
|
"columns": 0,
|
||||||
"fieldname": "scrap_section",
|
"fieldname": "scrap_section",
|
||||||
"fieldtype": "Section Break",
|
"fieldtype": "Section Break",
|
||||||
@ -894,7 +894,7 @@
|
|||||||
"issingle": 0,
|
"issingle": 0,
|
||||||
"istable": 0,
|
"istable": 0,
|
||||||
"max_attachments": 0,
|
"max_attachments": 0,
|
||||||
"modified": "2016-09-26 02:27:05.092369",
|
"modified": "2016-10-24 11:26:08.751123",
|
||||||
"modified_by": "Administrator",
|
"modified_by": "Administrator",
|
||||||
"module": "Manufacturing",
|
"module": "Manufacturing",
|
||||||
"name": "BOM",
|
"name": "BOM",
|
||||||
@ -910,6 +910,7 @@
|
|||||||
"export": 0,
|
"export": 0,
|
||||||
"if_owner": 0,
|
"if_owner": 0,
|
||||||
"import": 0,
|
"import": 0,
|
||||||
|
"is_custom": 0,
|
||||||
"permlevel": 0,
|
"permlevel": 0,
|
||||||
"print": 1,
|
"print": 1,
|
||||||
"read": 1,
|
"read": 1,
|
||||||
@ -930,6 +931,7 @@
|
|||||||
"export": 0,
|
"export": 0,
|
||||||
"if_owner": 0,
|
"if_owner": 0,
|
||||||
"import": 0,
|
"import": 0,
|
||||||
|
"is_custom": 0,
|
||||||
"permlevel": 0,
|
"permlevel": 0,
|
||||||
"print": 1,
|
"print": 1,
|
||||||
"read": 1,
|
"read": 1,
|
||||||
|
@ -28,9 +28,20 @@
|
|||||||
"quantity": 1.0
|
"quantity": 1.0
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
"scrap_items":[
|
||||||
|
{
|
||||||
|
"amount": 2000.0,
|
||||||
|
"doctype": "BOM Item",
|
||||||
|
"item_code": "_Test Item Home Desktop 100",
|
||||||
|
"parentfield": "items",
|
||||||
|
"qty": 1.0,
|
||||||
|
"rate": 2000.0,
|
||||||
|
"stock_uom": "_Test UOM"
|
||||||
|
}
|
||||||
|
],
|
||||||
"items": [
|
"items": [
|
||||||
{
|
{
|
||||||
"amount": 5000.0,
|
"amount": 10000.0,
|
||||||
"doctype": "BOM Item",
|
"doctype": "BOM Item",
|
||||||
"item_code": "_Test Item",
|
"item_code": "_Test Item",
|
||||||
"parentfield": "items",
|
"parentfield": "items",
|
||||||
@ -81,7 +92,7 @@
|
|||||||
"doctype": "BOM Item",
|
"doctype": "BOM Item",
|
||||||
"item_code": "_Test Item Home Desktop Manufactured",
|
"item_code": "_Test Item Home Desktop Manufactured",
|
||||||
"parentfield": "items",
|
"parentfield": "items",
|
||||||
"qty": 2.0,
|
"qty": 3.0,
|
||||||
"rate": 1000.0,
|
"rate": 1000.0,
|
||||||
"stock_uom": "_Test UOM"
|
"stock_uom": "_Test UOM"
|
||||||
}
|
}
|
||||||
|
@ -233,6 +233,45 @@ class TestProductionOrder(unittest.TestCase):
|
|||||||
self.pro_order.reload()
|
self.pro_order.reload()
|
||||||
self.assertEqual(len(self.pro_order.required_items), 0)
|
self.assertEqual(len(self.pro_order.required_items), 0)
|
||||||
|
|
||||||
|
def test_scrap_material_qty(self):
|
||||||
|
prod_order = make_prod_order_test_record(planned_start_date=now(), qty=2)
|
||||||
|
|
||||||
|
# add raw materials to stores
|
||||||
|
test_stock_entry.make_stock_entry(item_code="_Test Item",
|
||||||
|
target="Stores - _TC", qty=10, basic_rate=5000.0)
|
||||||
|
test_stock_entry.make_stock_entry(item_code="_Test Item Home Desktop 100",
|
||||||
|
target="Stores - _TC", qty=10, basic_rate=1000.0)
|
||||||
|
|
||||||
|
s = frappe.get_doc(make_stock_entry(prod_order.name, "Material Transfer for Manufacture", 2))
|
||||||
|
for d in s.get("items"):
|
||||||
|
d.s_warehouse = "Stores - _TC"
|
||||||
|
s.insert()
|
||||||
|
s.submit()
|
||||||
|
|
||||||
|
s = frappe.get_doc(make_stock_entry(prod_order.name, "Manufacture", 2))
|
||||||
|
s.insert()
|
||||||
|
s.submit()
|
||||||
|
|
||||||
|
prod_order_details = frappe.db.get_value("Production Order", prod_order.name,
|
||||||
|
["scrap_warehouse", "qty", "produced_qty", "bom_no"], as_dict=1)
|
||||||
|
|
||||||
|
scrap_item_details = get_scrap_item_details(prod_order_details.bom_no)
|
||||||
|
|
||||||
|
self.assertEqual(prod_order_details.produced_qty, 2)
|
||||||
|
|
||||||
|
for item in s.items:
|
||||||
|
if item.bom_no and item.item_code in scrap_item_details:
|
||||||
|
self.assertEqual(prod_order_details.scrap_warehouse, item.t_warehouse)
|
||||||
|
self.assertEqual(flt(prod_order_details.qty)*flt(scrap_item_details[item.item_code]), item.qty)
|
||||||
|
|
||||||
|
def get_scrap_item_details(bom_no):
|
||||||
|
scrap_items = {}
|
||||||
|
for item in frappe.db.sql("""select item_code, qty from `tabBOM Scrap Item`
|
||||||
|
where parent = %s""", bom_no, as_dict=1):
|
||||||
|
scrap_items[item.item_code] = item.qty
|
||||||
|
|
||||||
|
return scrap_items
|
||||||
|
|
||||||
def make_prod_order_test_record(**args):
|
def make_prod_order_test_record(**args):
|
||||||
args = frappe._dict(args)
|
args = frappe._dict(args)
|
||||||
|
|
||||||
@ -243,6 +282,7 @@ def make_prod_order_test_record(**args):
|
|||||||
pro_order.qty = args.qty or 10
|
pro_order.qty = args.qty or 10
|
||||||
pro_order.wip_warehouse = args.wip_warehouse or "_Test Warehouse - _TC"
|
pro_order.wip_warehouse = args.wip_warehouse or "_Test Warehouse - _TC"
|
||||||
pro_order.fg_warehouse = args.fg_warehouse or "_Test Warehouse 1 - _TC"
|
pro_order.fg_warehouse = args.fg_warehouse or "_Test Warehouse 1 - _TC"
|
||||||
|
pro_order.scrap_warehouse = args.fg_warehouse or "_Test Scrap Warehouse - _TC"
|
||||||
pro_order.company = args.company or "_Test Company"
|
pro_order.company = args.company or "_Test Company"
|
||||||
pro_order.stock_uom = args.stock_uom or "_Test UOM"
|
pro_order.stock_uom = args.stock_uom or "_Test UOM"
|
||||||
pro_order.set_production_order_operations()
|
pro_order.set_production_order_operations()
|
||||||
|
@ -238,6 +238,7 @@ class StockEntry(StockController):
|
|||||||
d.serial_no = transferred_serial_no
|
d.serial_no = transferred_serial_no
|
||||||
|
|
||||||
def get_stock_and_rate(self):
|
def get_stock_and_rate(self):
|
||||||
|
self.set_production_order_details()
|
||||||
self.set_transfer_qty()
|
self.set_transfer_qty()
|
||||||
self.set_actual_qty()
|
self.set_actual_qty()
|
||||||
self.calculate_rate_and_amount()
|
self.calculate_rate_and_amount()
|
||||||
@ -252,6 +253,7 @@ class StockEntry(StockController):
|
|||||||
def set_basic_rate(self, force=False, update_finished_item_rate=True):
|
def set_basic_rate(self, force=False, update_finished_item_rate=True):
|
||||||
"""get stock and incoming rate on posting date"""
|
"""get stock and incoming rate on posting date"""
|
||||||
raw_material_cost = 0.0
|
raw_material_cost = 0.0
|
||||||
|
scrap_material_cost = 0.0
|
||||||
fg_basic_rate = 0.0
|
fg_basic_rate = 0.0
|
||||||
|
|
||||||
for d in self.get('items'):
|
for d in self.get('items'):
|
||||||
@ -282,17 +284,22 @@ class StockEntry(StockController):
|
|||||||
basic_rate = flt(get_incoming_rate(args), self.precision("basic_rate", d))
|
basic_rate = flt(get_incoming_rate(args), self.precision("basic_rate", d))
|
||||||
if basic_rate > 0:
|
if basic_rate > 0:
|
||||||
d.basic_rate = basic_rate
|
d.basic_rate = basic_rate
|
||||||
|
d.basic_amount = flt(flt(d.transfer_qty) * flt(d.basic_rate), d.precision("basic_amount"))
|
||||||
|
|
||||||
|
if getattr(self, "pro_doc", frappe._dict()).scrap_warehouse == d.t_warehouse:
|
||||||
|
|
||||||
|
scrap_material_cost += flt(d.basic_amount)
|
||||||
|
|
||||||
number_of_fg_items = len([t.t_warehouse for t in self.get("items") if t.t_warehouse])
|
number_of_fg_items = len([t.t_warehouse for t in self.get("items") if t.t_warehouse])
|
||||||
if (fg_basic_rate == 0.0 and number_of_fg_items == 1) or update_finished_item_rate:
|
if (fg_basic_rate == 0.0 and number_of_fg_items == 1) or update_finished_item_rate:
|
||||||
self.set_basic_rate_for_finished_goods(raw_material_cost)
|
self.set_basic_rate_for_finished_goods(raw_material_cost, scrap_material_cost)
|
||||||
|
|
||||||
def set_basic_rate_for_finished_goods(self, raw_material_cost):
|
def set_basic_rate_for_finished_goods(self, raw_material_cost, scrap_material_cost):
|
||||||
if self.purpose in ["Manufacture", "Repack"]:
|
if self.purpose in ["Manufacture", "Repack"]:
|
||||||
for d in self.get("items"):
|
for d in self.get("items"):
|
||||||
if (d.bom_no or d.t_warehouse) and (getattr(self, "pro_doc", frappe._dict()).scrap_warehouse != d.t_warehouse):
|
if (d.bom_no or d.t_warehouse) and (getattr(self, "pro_doc", frappe._dict()).scrap_warehouse != d.t_warehouse):
|
||||||
d.basic_rate = flt(raw_material_cost / flt(d.transfer_qty), d.precision("basic_rate"))
|
d.basic_rate = flt((raw_material_cost - scrap_material_cost) / flt(d.transfer_qty), d.precision("basic_rate"))
|
||||||
d.basic_amount = flt(raw_material_cost, d.precision("basic_amount"))
|
d.basic_amount = flt((raw_material_cost - scrap_material_cost), d.precision("basic_amount"))
|
||||||
|
|
||||||
def distribute_additional_costs(self):
|
def distribute_additional_costs(self):
|
||||||
if self.purpose == "Material Issue":
|
if self.purpose == "Material Issue":
|
||||||
@ -355,14 +362,14 @@ class StockEntry(StockController):
|
|||||||
|
|
||||||
def validate_bom(self):
|
def validate_bom(self):
|
||||||
for d in self.get('items'):
|
for d in self.get('items'):
|
||||||
if d.bom_no and (d.t_warehouse != self.pro_doc.scrap_warehouse):
|
if d.bom_no and (d.t_warehouse != getattr(self, "pro_doc", frappe._dict()).scrap_warehouse):
|
||||||
validate_bom_no(d.item_code, d.bom_no)
|
validate_bom_no(d.item_code, d.bom_no)
|
||||||
|
|
||||||
def validate_finished_goods(self):
|
def validate_finished_goods(self):
|
||||||
"""validation: finished good quantity should be same as manufacturing quantity"""
|
"""validation: finished good quantity should be same as manufacturing quantity"""
|
||||||
items_with_target_warehouse = []
|
items_with_target_warehouse = []
|
||||||
for d in self.get('items'):
|
for d in self.get('items'):
|
||||||
if d.bom_no and flt(d.transfer_qty) != flt(self.fg_completed_qty) and (d.t_warehouse != self.pro_doc.scrap_warehouse):
|
if d.bom_no and flt(d.transfer_qty) != flt(self.fg_completed_qty) and (d.t_warehouse != getattr(self, "pro_doc", frappe._dict()).scrap_warehouse):
|
||||||
frappe.throw(_("Quantity in row {0} ({1}) must be same as manufactured quantity {2}"). \
|
frappe.throw(_("Quantity in row {0} ({1}) must be same as manufactured quantity {2}"). \
|
||||||
format(d.idx, d.transfer_qty, self.fg_completed_qty))
|
format(d.idx, d.transfer_qty, self.fg_completed_qty))
|
||||||
|
|
||||||
@ -526,19 +533,7 @@ class StockEntry(StockController):
|
|||||||
if not self.posting_date or not self.posting_time:
|
if not self.posting_date or not self.posting_time:
|
||||||
frappe.throw(_("Posting date and posting time is mandatory"))
|
frappe.throw(_("Posting date and posting time is mandatory"))
|
||||||
|
|
||||||
if not getattr(self, "pro_doc", None):
|
self.set_production_order_details()
|
||||||
self.pro_doc = None
|
|
||||||
|
|
||||||
if self.production_order:
|
|
||||||
# common validations
|
|
||||||
if not self.pro_doc:
|
|
||||||
self.pro_doc = frappe.get_doc('Production Order', self.production_order)
|
|
||||||
|
|
||||||
if self.pro_doc:
|
|
||||||
self.bom_no = self.pro_doc.bom_no
|
|
||||||
else:
|
|
||||||
# invalid production order
|
|
||||||
self.production_order = None
|
|
||||||
|
|
||||||
if self.bom_no:
|
if self.bom_no:
|
||||||
if self.purpose in ["Material Issue", "Material Transfer", "Manufacture", "Repack",
|
if self.purpose in ["Material Issue", "Material Transfer", "Manufacture", "Repack",
|
||||||
@ -584,6 +579,21 @@ class StockEntry(StockController):
|
|||||||
self.set_actual_qty()
|
self.set_actual_qty()
|
||||||
self.calculate_rate_and_amount()
|
self.calculate_rate_and_amount()
|
||||||
|
|
||||||
|
def set_production_order_details(self):
|
||||||
|
if not getattr(self, "pro_doc", None):
|
||||||
|
self.pro_doc = None
|
||||||
|
|
||||||
|
if self.production_order:
|
||||||
|
# common validations
|
||||||
|
if not self.pro_doc:
|
||||||
|
self.pro_doc = frappe.get_doc('Production Order', self.production_order)
|
||||||
|
|
||||||
|
if self.pro_doc:
|
||||||
|
self.bom_no = self.pro_doc.bom_no
|
||||||
|
else:
|
||||||
|
# invalid production order
|
||||||
|
self.production_order = None
|
||||||
|
|
||||||
def load_items_from_bom(self):
|
def load_items_from_bom(self):
|
||||||
if self.production_order:
|
if self.production_order:
|
||||||
item_code = self.pro_doc.production_item
|
item_code = self.pro_doc.production_item
|
||||||
|
@ -6,6 +6,13 @@
|
|||||||
"warehouse_name": "_Test Warehouse",
|
"warehouse_name": "_Test Warehouse",
|
||||||
"is_group": 0
|
"is_group": 0
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"company": "_Test Company",
|
||||||
|
"create_account_under": "Stock Assets - _TC",
|
||||||
|
"doctype": "Warehouse",
|
||||||
|
"warehouse_name": "_Test Scrap Warehouse",
|
||||||
|
"is_group": 0
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"company": "_Test Company",
|
"company": "_Test Company",
|
||||||
"create_account_under": "Stock Assets - _TC",
|
"create_account_under": "Stock Assets - _TC",
|
||||||
|
Loading…
x
Reference in New Issue
Block a user