diff --git a/accounts/doctype/purchase_invoice/purchase_invoice.py b/accounts/doctype/purchase_invoice/purchase_invoice.py index 96cfc006be..01359d3ecf 100644 --- a/accounts/doctype/purchase_invoice/purchase_invoice.py +++ b/accounts/doctype/purchase_invoice/purchase_invoice.py @@ -320,6 +320,7 @@ class DocType(BuyingController): self.doc.posting_date,'Posting Date') self.validate_write_off_account() + self.update_raw_material_cost() def check_prev_docstatus(self): for d in getlist(self.doclist,'entries'): @@ -494,3 +495,16 @@ class DocType(BuyingController): def on_update(self): pass + def update_raw_material_cost(self): + if self.sub_contracted_items: + for d in self.doclist.get({"parentfield": "entries"}): + rm_cost = webnotes.conn.sql(""" select raw_material_cost / quantity + from `tabBOM` where item = %s and is_default = 1 and docstatus = 1 + and is_active = 1 """, (d.item_code,)) + rm_cost = rm_cost and flt(rm_cost[0][0]) or 0 + + d.conversion_factor = d.conversion_factor or webnotes.conn.get_value( + "UOM Conversion Detail", {"parent": d.item_code, "uom": d.uom}, + "conversion_factor") or 1 + + d.rm_supp_cost = rm_cost * flt(d.qty) * flt(d.conversion_factor) \ No newline at end of file diff --git a/accounts/doctype/purchase_invoice_item/purchase_invoice_item.txt b/accounts/doctype/purchase_invoice_item/purchase_invoice_item.txt index ecd981de69..553041e780 100755 --- a/accounts/doctype/purchase_invoice_item/purchase_invoice_item.txt +++ b/accounts/doctype/purchase_invoice_item/purchase_invoice_item.txt @@ -1,8 +1,8 @@ [ { - "creation": "2013-01-29 20:53:00", + "creation": "2013-02-11 10:54:51", "docstatus": 0, - "modified": "2013-02-08 14:06:17", + "modified": "2013-02-27 18:10:04", "modified_by": "Administrator", "owner": "Administrator" }, @@ -282,6 +282,35 @@ "search_index": 0, "width": "150px" }, + { + "doctype": "DocField", + "fieldname": "valuation_rate", + "fieldtype": "Currency", + "hidden": 1, + "label": "Valuation Rate", + "no_copy": 1, + "options": "Company:company:default_currency", + "print_hide": 1, + "read_only": 1 + }, + { + "doctype": "DocField", + "fieldname": "conversion_factor", + "fieldtype": "Float", + "label": "Conversion Factor", + "print_hide": 1 + }, + { + "doctype": "DocField", + "fieldname": "rm_supp_cost", + "fieldtype": "Currency", + "hidden": 1, + "label": "Raw Materials Supplied Cost", + "no_copy": 1, + "options": "Company:company:default_currency", + "print_hide": 1, + "read_only": 1 + }, { "allow_on_submit": 1, "doctype": "DocField", diff --git a/controllers/buying_controller.py b/controllers/buying_controller.py index bbcd4926c3..2b76ad1e9e 100644 --- a/controllers/buying_controller.py +++ b/controllers/buying_controller.py @@ -232,7 +232,7 @@ class BuyingController(AccountsController): else: self.doc.grand_total = flt(self.doc.net_total, self.precision.main.grand_total) - self.doc.grand_total_print = flt( + self.doc.grand_total_import = flt( self.doc.grand_total / self.doc.conversion_rate, self.precision.main.grand_total_import) @@ -336,3 +336,25 @@ class BuyingController(AccountsController): self._precision.tax = self.meta.get_precision_map(parentfield = \ "purchase_tax_details") return self._precision + + @property + def sub_contracted_items(self): + if not hasattr(self, "_sub_contracted_items"): + item_codes = list(set(item.item_code for item in + self.doclist.get({"parentfield": self.fname}))) + self._sub_contracted_items = [r[0] for r in webnotes.conn.sql("""select name + from `tabItem` where name in (%s) and is_sub_contracted_item='Yes'""" % \ + (", ".join((["%s"]*len(item_codes))),), item_codes)] + + return self._sub_contracted_items + + @property + def purchase_items(self): + if not hasattr(self, "_purchase_items"): + item_codes = list(set(item.item_code for item in + self.doclist.get({"parentfield": self.fname}))) + self._purchase_items = [r[0] for r in webnotes.conn.sql("""select name + from `tabItem` where name in (%s) and is_purchase_item='Yes'""" % \ + (", ".join((["%s"]*len(item_codes))),), item_codes)] + + return self._purchase_items \ No newline at end of file diff --git a/manufacturing/doctype/bom/test_bom.py b/manufacturing/doctype/bom/test_bom.py index 68d9ce85f4..e742c0c8ac 100644 --- a/manufacturing/doctype/bom/test_bom.py +++ b/manufacturing/doctype/bom/test_bom.py @@ -18,130 +18,164 @@ from __future__ import unicode_literals import unittest import webnotes -import webnotes.model -from webnotes.utils import nowdate, flt -from accounts.utils import get_fiscal_year -from webnotes.model.doclist import DocList -import copy -company = webnotes.conn.get_default("company") - - -def load_data(): - - # create default warehouse - if not webnotes.conn.exists("Warehouse", "Default Warehouse"): - webnotes.insert({"doctype": "Warehouse", - "warehouse_name": "Default Warehouse", - "warehouse_type": "Stores"}) - - # create UOM: Nos. - if not webnotes.conn.exists("UOM", "Nos"): - webnotes.insert({"doctype": "UOM", "uom_name": "Nos"}) - - from webnotes.tests import insert_test_data - # create item groups and items - insert_test_data("Item Group", - sort_fn=lambda ig: (ig[0].get('parent_item_group'), ig[0].get('name'))) - insert_test_data("Item") - -base_bom_fg = [ - {"doctype": "BOM", "item": "Android Jack D", "quantity": 1, - "is_active": "Yes", "is_default": 1, "uom": "Nos"}, - {"doctype": "BOM Operation", "operation_no": 1, "parentfield": "bom_operations", - "opn_description": "Development", "hour_rate": 10, "time_in_mins": 90}, - {"doctype": "BOM Item", "item_code": "Home Desktop 300", "operation_no": 1, - "qty": 2, "rate": 20, "stock_uom": "Nos", "parentfield": "bom_materials"}, - {"doctype": "BOM Item", "item_code": "Home Desktop 100", "operation_no": 1, - "qty": 1, "rate": 300, "stock_uom": "Nos", "parentfield": "bom_materials"}, - {"doctype": "BOM Item", "item_code": "Nebula 7", "operation_no": 1, - "qty": 5, "stock_uom": "Nos", "parentfield": "bom_materials"}, -] - -base_bom_child = [ - {"doctype": "BOM", "item": "Nebula 7", "quantity": 5, - "is_active": "Yes", "is_default": 1, "uom": "Nos"}, - {"doctype": "BOM Operation", "operation_no": 1, "parentfield": "bom_operations", - "opn_description": "Development"}, - {"doctype": "BOM Item", "item_code": "Android Jack S", "operation_no": 1, - "qty": 10, "stock_uom": "Nos", "parentfield": "bom_materials"} -] - -base_bom_grandchild = [ - {"doctype": "BOM", "item": "Android Jack S", "quantity": 1, - "is_active": "Yes", "is_default": 1, "uom": "Nos"}, - {"doctype": "BOM Operation", "operation_no": 1, "parentfield": "bom_operations", - "opn_description": "Development"}, - {"doctype": "BOM Item", "item_code": "Home Desktop 300", "operation_no": 1, - "qty": 3, "rate": 10, "stock_uom": "Nos", "parentfield": "bom_materials"} -] - - -class TestPurchaseReceipt(unittest.TestCase): - def setUp(self): - webnotes.conn.begin() - load_data() - - def test_bom_validation(self): - # show throw error bacause bom no missing for sub-assembly item - bom_fg = copy.deepcopy(base_bom_fg) - self.assertRaises(webnotes.ValidationError, webnotes.insert, DocList(bom_fg)) - - # main item is not a manufacturing item - bom_fg = copy.deepcopy(base_bom_fg) - bom_fg[0]["item"] = "Home Desktop 200" - bom_fg.pop(4) - self.assertRaises(webnotes.ValidationError, webnotes.insert, DocList(bom_fg)) - - # operation no mentioed in material table not matching with operation table - bom_fg = copy.deepcopy(base_bom_fg) - bom_fg.pop(4) - bom_fg[2]["operation_no"] = 2 - self.assertRaises(webnotes.ValidationError, webnotes.insert, DocList(bom_fg)) - - - def test_bom(self): - gc_wrapper = webnotes.insert(DocList(base_bom_grandchild)) - gc_wrapper.submit() - - bom_child = copy.deepcopy(base_bom_child) - bom_child[2]["bom_no"] = gc_wrapper.doc.name - child_wrapper = webnotes.insert(DocList(bom_child)) - child_wrapper.submit() - - bom_fg = copy.deepcopy(base_bom_fg) - bom_fg[4]["bom_no"] = child_wrapper.doc.name - fg_wrapper = webnotes.insert(DocList(bom_fg)) - fg_wrapper.load_from_db() - - self.check_bom_cost(fg_wrapper) - - self.check_flat_bom(fg_wrapper, child_wrapper, gc_wrapper) - - def check_bom_cost(self, fg_wrapper): - expected_values = { - "operating_cost": 15, - "raw_material_cost": 640, - "total_cost": 655 +test_records = [ + [ + { + "doctype": "BOM", + "item": "_Test FG Item", + "quantity": 1.0, + "is_active": 1, + "is_default": 1, + "docstatus": 1 + }, + { + "doctype": "BOM Item", + "item_code": "_Test Item", + "parentfield": "bom_materials", + "qty": 1.0, + "rate": 5000.0, + "amount": 5000.0, + "stock_uom": "No." + }, + { + "doctype": "BOM Item", + "item_code": "_Test Item Home Desktop 100", + "parentfield": "bom_materials", + "qty": 2.0, + "rate": 1000.0, + "amount": 2000.0, + "stock_uom": "No." } + ] +] - for key in expected_values: - self.assertEqual(flt(expected_values[key]), flt(fg_wrapper.doc.fields.get(key))) - - def check_flat_bom(self, fg_wrapper, child_wrapper, gc_wrapper): - expected_flat_bom_items = { - ("Home Desktop 300", fg_wrapper.doc.name): (2, 20), - ("Home Desktop 100", fg_wrapper.doc.name): (1, 300), - ("Home Desktop 300", gc_wrapper.doc.name): (30, 10) - } - - self.assertEqual(len(fg_wrapper.doclist.get({"parentfield": "flat_bom_details"})), 3) - - for key, val in expected_flat_bom_items.items(): - flat_bom = fg_wrapper.doclist.get({"parentfield": "flat_bom_details", - "item_code": key[0], "parent_bom": key[1]})[0] - self.assertEqual(val, (flat_bom.qty, flat_bom.rate)) - - - def tearDown(self): - webnotes.conn.rollback() \ No newline at end of file + + +# import webnotes.model +# from webnotes.utils import nowdate, flt +# from accounts.utils import get_fiscal_year +# from webnotes.model.doclist import DocList +# import copy +# +# company = webnotes.conn.get_default("company") +# +# +# def load_data(): +# +# # create default warehouse +# if not webnotes.conn.exists("Warehouse", "Default Warehouse"): +# webnotes.insert({"doctype": "Warehouse", +# "warehouse_name": "Default Warehouse", +# "warehouse_type": "Stores"}) +# +# # create UOM: Nos. +# if not webnotes.conn.exists("UOM", "Nos"): +# webnotes.insert({"doctype": "UOM", "uom_name": "Nos"}) +# +# from webnotes.tests import insert_test_data +# # create item groups and items +# insert_test_data("Item Group", +# sort_fn=lambda ig: (ig[0].get('parent_item_group'), ig[0].get('name'))) +# insert_test_data("Item") +# +# base_bom_fg = [ +# {"doctype": "BOM", "item": "Android Jack D", "quantity": 1, +# "is_active": "Yes", "is_default": 1, "uom": "Nos"}, +# {"doctype": "BOM Operation", "operation_no": 1, "parentfield": "bom_operations", +# "opn_description": "Development", "hour_rate": 10, "time_in_mins": 90}, +# {"doctype": "BOM Item", "item_code": "Home Desktop 300", "operation_no": 1, +# "qty": 2, "rate": 20, "stock_uom": "Nos", "parentfield": "bom_materials"}, +# {"doctype": "BOM Item", "item_code": "Home Desktop 100", "operation_no": 1, +# "qty": 1, "rate": 300, "stock_uom": "Nos", "parentfield": "bom_materials"}, +# {"doctype": "BOM Item", "item_code": "Nebula 7", "operation_no": 1, +# "qty": 5, "stock_uom": "Nos", "parentfield": "bom_materials"}, +# ] +# +# base_bom_child = [ +# {"doctype": "BOM", "item": "Nebula 7", "quantity": 5, +# "is_active": "Yes", "is_default": 1, "uom": "Nos"}, +# {"doctype": "BOM Operation", "operation_no": 1, "parentfield": "bom_operations", +# "opn_description": "Development"}, +# {"doctype": "BOM Item", "item_code": "Android Jack S", "operation_no": 1, +# "qty": 10, "stock_uom": "Nos", "parentfield": "bom_materials"} +# ] +# +# base_bom_grandchild = [ +# {"doctype": "BOM", "item": "Android Jack S", "quantity": 1, +# "is_active": "Yes", "is_default": 1, "uom": "Nos"}, +# {"doctype": "BOM Operation", "operation_no": 1, "parentfield": "bom_operations", +# "opn_description": "Development"}, +# {"doctype": "BOM Item", "item_code": "Home Desktop 300", "operation_no": 1, +# "qty": 3, "rate": 10, "stock_uom": "Nos", "parentfield": "bom_materials"} +# ] +# +# +# class TestPurchaseReceipt(unittest.TestCase): +# def setUp(self): +# webnotes.conn.begin() +# load_data() +# +# def test_bom_validation(self): +# # show throw error bacause bom no missing for sub-assembly item +# bom_fg = copy.deepcopy(base_bom_fg) +# self.assertRaises(webnotes.ValidationError, webnotes.insert, DocList(bom_fg)) +# +# # main item is not a manufacturing item +# bom_fg = copy.deepcopy(base_bom_fg) +# bom_fg[0]["item"] = "Home Desktop 200" +# bom_fg.pop(4) +# self.assertRaises(webnotes.ValidationError, webnotes.insert, DocList(bom_fg)) +# +# # operation no mentioed in material table not matching with operation table +# bom_fg = copy.deepcopy(base_bom_fg) +# bom_fg.pop(4) +# bom_fg[2]["operation_no"] = 2 +# self.assertRaises(webnotes.ValidationError, webnotes.insert, DocList(bom_fg)) +# +# +# def test_bom(self): +# gc_wrapper = webnotes.insert(DocList(base_bom_grandchild)) +# gc_wrapper.submit() +# +# bom_child = copy.deepcopy(base_bom_child) +# bom_child[2]["bom_no"] = gc_wrapper.doc.name +# child_wrapper = webnotes.insert(DocList(bom_child)) +# child_wrapper.submit() +# +# bom_fg = copy.deepcopy(base_bom_fg) +# bom_fg[4]["bom_no"] = child_wrapper.doc.name +# fg_wrapper = webnotes.insert(DocList(bom_fg)) +# fg_wrapper.load_from_db() +# +# self.check_bom_cost(fg_wrapper) +# +# self.check_flat_bom(fg_wrapper, child_wrapper, gc_wrapper) +# +# def check_bom_cost(self, fg_wrapper): +# expected_values = { +# "operating_cost": 15, +# "raw_material_cost": 640, +# "total_cost": 655 +# } +# +# for key in expected_values: +# self.assertEqual(flt(expected_values[key]), flt(fg_wrapper.doc.fields.get(key))) +# +# def check_flat_bom(self, fg_wrapper, child_wrapper, gc_wrapper): +# expected_flat_bom_items = { +# ("Home Desktop 300", fg_wrapper.doc.name): (2, 20), +# ("Home Desktop 100", fg_wrapper.doc.name): (1, 300), +# ("Home Desktop 300", gc_wrapper.doc.name): (30, 10) +# } +# +# self.assertEqual(len(fg_wrapper.doclist.get({"parentfield": "flat_bom_details"})), 3) +# +# for key, val in expected_flat_bom_items.items(): +# flat_bom = fg_wrapper.doclist.get({"parentfield": "flat_bom_details", +# "item_code": key[0], "parent_bom": key[1]})[0] +# self.assertEqual(val, (flat_bom.qty, flat_bom.rate)) +# +# +# def tearDown(self): +# webnotes.conn.rollback() \ No newline at end of file diff --git a/stock/doctype/item/test_item.py b/stock/doctype/item/test_item.py index 853283e4c6..035774b50b 100644 --- a/stock/doctype/item/test_item.py +++ b/stock/doctype/item/test_item.py @@ -17,64 +17,8 @@ from __future__ import unicode_literals import unittest import webnotes -import copy - -from webnotes.model.bean import Bean -from webnotes.model.doc import Document -from webnotes.utils import flt - -sql = webnotes.conn.sql - - -class TestItem(unittest.TestCase): - def setUp(self): - webnotes.conn.begin() - - def tearDown(self): - webnotes.conn.rollback() - - def testInsert(self): - d = Bean() - - count_before = flt(sql("select count(*) from tab"+_doctype)[0][0]) - if docok: - for i in docok: - d.doc = i - d.children = None - d.doc.fields['__islocal']=1 - d.save(1) - count_after = flt(sql("select count(*) from tab"+_doctype)[0][0]) - self.assertTrue(count_before+len(docok)==count_after) - - def testFailAssert(self): - if docnotok: - with self.assertRaises(Exception) as context: - d = Bean() - d.doc = docnotok[0] - d.children = None - d.doc.fields['__islocal']=1 - d.save(1) - -# Test Data - -tabOK = [ - {'is_purchase_item': None, 'is_pro_applicable': 'No', 'is_manufactured_item': None, 'description': 'Gel Ink', 'default_warehouse': None, 'item_name': 'Gel Ink', 'item_group': 'Ink', 'item_code': 'GELINK', 'is_sub_contracted_item': None, 'is_stock_item': 'Yes', 'stock_uom': 'Nos', 'docstatus': '0'}, - {'is_purchase_item': None, 'is_pro_applicable': 'No', 'is_manufactured_item': None, 'description': 'Gel Refill', 'default_warehouse': None, 'item_name': 'Gel Refill', 'item_group': 'Refill', 'item_code': 'GELREF', 'is_sub_contracted_item': None, 'is_stock_item': 'Yes', 'stock_uom': 'Nos', 'docstatus': '0'}, - {'is_purchase_item': None, 'is_pro_applicable': 'No', 'is_manufactured_item': None, 'description': 'Gel Pen', 'default_warehouse': None, 'item_name': 'Gel Pen', 'item_group': 'Pen', 'item_code': 'GELPEN', 'is_sub_contracted_item': None, 'is_stock_item': 'Yes', 'stock_uom': 'Nos', 'docstatus': '0'} - ] - -tabNotOK = [ - {'is_purchase_item': None, 'is_pro_applicable': None, 'is_manufactured_item': None, 'description': 'F Ink', 'default_warehouse': None, 'item_name': 'F Ink', 'item_group': 'F Ink', 'item_code': None, 'is_sub_contracted_item': None, 'is_stock_item': 'No', 'stock_uom': 'Nos', 'docstatus': '0'} - ] - -_doctype = 'Item' - -for i in tabOK: i['doctype']=_doctype -for i in tabNotOK: i['doctype']=_doctype - -docok = [Document(fielddata=r) for r in tabOK] -docnotok = [Document(fielddata=r) for r in tabNotOK] +test_ignore = ["BOM"] test_records = [ [{ @@ -164,4 +108,23 @@ test_records = [ "is_sub_contracted_item": "No", "stock_uom": "_Test UOM" }], + [{ + "doctype": "Item", + "item_code": "_Test FG Item", + "item_name": "_Test FG Item", + "description": "_Test FG Item", + "item_group": "_Test Item Group Desktops", + "is_stock_item": "Yes", + "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": "Yes", + "is_sub_contracted_item": "Yes", + "stock_uom": "_Test UOM" + }], ] \ No newline at end of file diff --git a/stock/doctype/purchase_receipt/purchase_receipt.py b/stock/doctype/purchase_receipt/purchase_receipt.py index a957468032..ef4fc3079d 100644 --- a/stock/doctype/purchase_receipt/purchase_receipt.py +++ b/stock/doctype/purchase_receipt/purchase_receipt.py @@ -18,10 +18,10 @@ from __future__ import unicode_literals import webnotes from webnotes.utils import cstr, flt, cint -from webnotes.model.doc import addchild from webnotes.model.bean import getlist from webnotes.model.code import get_obj -from webnotes import msgprint +from webnotes.model.doc import Document +from webnotes import msgprint, _ sql = webnotes.conn.sql @@ -89,8 +89,6 @@ class DocType(BuyingController): webnotes.msgprint("Another Purchase Receipt using the same Challan No. already exists.\ Please enter a valid Challan No.", raise_exception=1) - - # update valuation rate def update_valuation_rate(self): for d in self.doclist.get({"parentfield": "purchase_receipt_details"}): if d.qty: @@ -99,8 +97,6 @@ class DocType(BuyingController): else: d.valuation_rate = 0.0 - #check in manage account if purchase order required or not. - # ==================================================================================== def po_required(self): res = sql("select value from `tabSingles` where doctype = 'Global Defaults' and field = 'po_required'") if res and res[0][0]== 'Yes': @@ -109,8 +105,6 @@ class DocType(BuyingController): msgprint("Purchse Order No. required against item %s"%d.item_code) raise Exception - - # validate def validate(self): super(DocType, self).validate() @@ -136,16 +130,15 @@ class DocType(BuyingController): # update valuation rate self.update_valuation_rate() + # sub-contracting + self.validate_for_subcontracting() + self.update_raw_materials_supplied() - - # On Update - # ---------------------------------------------------------------------------------------------------- def on_update(self): if self.doc.rejected_warehouse: for d in getlist(self.doclist,'purchase_receipt_details'): d.rejected_warehouse = self.doc.rejected_warehouse - self.update_rw_material_detail() get_obj('Stock Ledger').scrub_serial_nos(self) self.scrub_rejected_serial_nos() @@ -303,118 +296,66 @@ class DocType(BuyingController): self.make_gl_entries() + def validate_for_subcontracting(self): + if self.sub_contracted_items and self.purchase_items and not self.doc.is_subcontracted: + webnotes.msgprint(_("""Please enter whether Purchase Recipt is made for subcontracting + or purchasing, in 'Is Subcontracted' field"""), raise_exception=1) + + if self.doc.is_subcontracted and not self.doc.supplier_warehouse: + webnotes.msgprint(_("Please Enter Supplier Warehouse for subcontracted Items"), + raise_exception=1) + + def update_raw_materials_supplied(self): + self.doclist = self.doc.clear_table(self.doclist, 'pr_raw_material_details') + if self.sub_contracted_items: + for item in self.doclist.get({"parentfield": "purchase_receipt_details"}): + if item.item_code in self.sub_contracted_items: + self.add_bom_items(item) - def update_rw_material_detail(self): + def add_bom_items(self, d): + bom_items = self.get_items_from_default_bom(d.item_code) + raw_materials_cost = 0 + for item in bom_items: + required_qty = flt(item.qty_consumed_per_unit) * flt(d.qty) * flt(d.conversion_factor) + self.doclist.append({ + "parentfield": "pr_raw_material_details", + "doctype": "Purchase Receipt Item Supplied", + "reference_name": d.name, + "bom_detail_no": item.name, + "main_item_code": d.item_code, + "rm_item_code": item.item_code, + "description": item.description, + "stock_uom": item.stock_uom, + "required_qty": required_qty, + "consumed_qty": required_qty, + "conversion_factor": d.conversion_factor, + "rate": item.rate, + "amount": required_qty * flt(item.rate) + }) + + raw_materials_cost += required_qty * flt(item.rate) + + d.rm_supp_cost = raw_materials_cost - for d in getlist(self.doclist,'purchase_receipt_details'): - item_det = sql("select is_sub_contracted_item, is_purchase_item from `tabItem` where name = '%s'"%(d.item_code)) - - if item_det[0][0] == 'Yes': - if item_det[0][1] == 'Yes': - if not self.doc.is_subcontracted: - msgprint("Please enter whether purchase receipt to be made for subcontracting or for purchase in 'Is Subcontracted' field .") - raise Exception - if self.doc.is_subcontracted == 'Yes': - if not self.doc.supplier_warehouse: - msgprint("Please Enter Supplier Warehouse for subcontracted Items") - raise Exception - self.add_bom(d) - else: - self.doclist = self.doc.clear_table(self.doclist,'pr_raw_material_details',1) - self.doc.save() - elif item_det[0][1] == 'No': - if not self.doc.supplier_warehouse: - msgprint("Please Enter Supplier Warehouse for subcontracted Items") - raise Exception - self.add_bom(d) - - self.delete_irrelevant_raw_material() - #---------------calculate amt in Purchase Receipt Item Supplied------------- - self.calculate_amount(d) - - - def add_bom(self, d): - #----- fetching default bom from Bill of Materials instead of Item Master -- - bom_det = sql("""select t1.item, t2.item_code, t2.qty_consumed_per_unit, - t2.moving_avg_rate, t2.value_as_per_mar, t2.stock_uom, t2.name, t2.description + def get_items_from_default_bom(self, item_code): + # print webnotes.conn.sql("""select name from `tabBOM` where item = '_Test FG Item'""") + bom_items = sql("""select t2.item_code, t2.qty_consumed_per_unit, + t2.rate, t2.stock_uom, t2.name, t2.description from `tabBOM` t1, `tabBOM Item` t2 where t2.parent = t1.name and t1.item = %s and t1.is_default = 1 - and t1.docstatus = 1 and t2.docstatus =1 and t1.is_active = 1""", d.item_code) - if not bom_det: - msgprint("No default BOM exists for item: %s" % d.item_code) - raise Exception - else: - #-------------- add child function-------------------- - chgd_rqd_qty = [] - for i in bom_det: + and t1.docstatus = 1 and t1.is_active = 1""", item_code, as_dict=1) + if not bom_items: + msgprint(_("No default BOM exists for item: ") + item_code, raise_exception=1) + + return bom_items - if i and not sql("select name from `tabPurchase Receipt Item Supplied` where reference_name = '%s' and bom_detail_no = '%s' and parent = '%s' " %(d.name, i[6], self.doc.name)): - - rm_child = addchild(self.doc, 'pr_raw_material_details', 'Purchase Receipt Item Supplied', self.doclist) - - rm_child.reference_name = d.name - rm_child.bom_detail_no = i and i[6] or '' - rm_child.main_item_code = i and i[0] or '' - rm_child.rm_item_code = i and i[1] or '' - rm_child.description = i and i[7] or '' - rm_child.stock_uom = i and i[5] or '' - rm_child.rate = i and flt(i[3]) or flt(i[4]) - rm_child.conversion_factor = d.conversion_factor - rm_child.required_qty = flt(i and flt(i[2]) or 0) * flt(d.qty) * flt(d.conversion_factor) - rm_child.consumed_qty = flt(i and flt(i[2]) or 0) * flt(d.qty) * flt(d.conversion_factor) - rm_child.amount = flt(flt(rm_child.consumed_qty)*flt(rm_child.rate)) - rm_child.save() - chgd_rqd_qty.append(cstr(i[1])) - else: - act_qty = flt(i and flt(i[2]) or 0) * flt(d.qty) * flt(d.conversion_factor) - for pr_rmd in getlist(self.doclist, 'pr_raw_material_details'): - if i and i[6] == pr_rmd.bom_detail_no and (flt(act_qty) != flt(pr_rmd.required_qty) or i[1] != pr_rmd.rm_item_code or i[7] != pr_rmd.description): - chgd_rqd_qty.append(cstr(i[1])) - pr_rmd.main_item_code = i[0] - pr_rmd.rm_item_code = i[1] - pr_rmd.description = i[7] - pr_rmd.stock_uom = i[5] - pr_rmd.required_qty = flt(act_qty) - pr_rmd.consumed_qty = flt(act_qty) - pr_rmd.rate = i and flt(i[3]) or flt(i[4]) - pr_rmd.amount = flt(flt(pr_rmd.consumed_qty)*flt(pr_rmd.rate)) - pr_rmd.save() - if chgd_rqd_qty: - msgprint("Please check consumed quantity for Raw Material Item Code: '%s'in Raw materials Detail Table" % ((len(chgd_rqd_qty) > 1 and ','.join(chgd_rqd_qty[:-1]) +' and ' + cstr(chgd_rqd_qty[-1:][0]) ) or cstr(chgd_rqd_qty[0]))) - - - # Delete irrelevant raw material from PR Raw material details - #-------------------------------------------------------------- - def delete_irrelevant_raw_material(self): - for d in getlist(self.doclist,'pr_raw_material_details'): - if not sql("select name from `tabPurchase Receipt Item` where name = '%s' and parent = '%s' and item_code = '%s'" % (d.reference_name, self.doc.name, d.main_item_code)): - d.parent = 'old_par:'+self.doc.name - d.save() - - def calculate_amount(self, d): - amt = 0 - for i in getlist(self.doclist,'pr_raw_material_details'): - - if(i.reference_name == d.name): - #if i.consumed_qty == 0: - # msgprint("consumed qty cannot be 0. Please Enter consumed qty ") - #raise Exception - i.amount = flt(i.consumed_qty)* flt(i.rate) - amt += i.amount - d.rm_supp_cost = amt - d.save() - - - # --------------- Back Flush function called on submit and on cancel from update stock def bk_flush_supp_wh(self, is_submit): for d in getlist(self.doclist, 'pr_raw_material_details'): - #--------- -ve quantity is passed as raw material qty has to be decreased when PR is submitted and it has to be increased when PR is cancelled + # negative quantity is passed as raw material qty has to be decreased + # when PR is submitted and it has to be increased when PR is cancelled consumed_qty = - flt(d.consumed_qty) self.make_sl_entry(d, self.doc.supplier_warehouse, flt(consumed_qty), 0, is_submit) - - # get current_stock - # ---------------- def get_current_stock(self): for d in getlist(self.doclist, 'pr_raw_material_details'): if self.doc.supplier_warehouse: diff --git a/stock/doctype/purchase_receipt/test_purchase_receipt.py b/stock/doctype/purchase_receipt/test_purchase_receipt.py index d833d65b2b..6c317c40d7 100644 --- a/stock/doctype/purchase_receipt/test_purchase_receipt.py +++ b/stock/doctype/purchase_receipt/test_purchase_receipt.py @@ -64,6 +64,17 @@ class TestPurchaseReceipt(unittest.TestCase): self.assertEquals(expected_values[i][2], gle.credit) webnotes.defaults.set_global_default("auto_inventory_accounting", 0) + + def test_subcontracting(self): + pr = webnotes.bean(copy=test_records[1]) + pr.run_method("calculate_taxes_and_totals") + pr.insert() + + self.assertEquals(pr.doclist[1].rm_supp_cost, 70000.0) + self.assertEquals(len(pr.doclist.get({"parentfield": "pr_raw_material_details"})), 2) + + +test_dependencies = ["BOM"] test_records = [ [ @@ -129,4 +140,36 @@ test_records = [ "tax_amount": 150.0, }, ], + [ + { + "company": "_Test Company", + "conversion_rate": 1.0, + "currency": "INR", + "doctype": "Purchase Receipt", + "fiscal_year": "_Test Fiscal Year 2013", + "posting_date": "2013-02-12", + "posting_time": "15:33:30", + "is_subcontracted": "Yes", + "supplier_warehouse": "_Test Warehouse", + "supplier": "_Test Supplier", + "net_total": 5000.0, + "grand_total": 5000.0, + }, + { + "conversion_factor": 1.0, + "description": "_Test FG Item", + "doctype": "Purchase Receipt Item", + "item_code": "_Test FG Item", + "item_name": "_Test FG Item", + "parentfield": "purchase_receipt_details", + "received_qty": 10.0, + "qty": 10.0, + "rejected_qty": 0.0, + "import_rate": 500.0, + "amount": 5000.0, + "warehouse": "_Test Warehouse", + "stock_uom": "Nos", + "uom": "_Test UOM", + } + ], ] \ No newline at end of file