Merge branch 'master' of github.com:webnotes/erpnext
diff --git a/buying/doctype/purchase_order/purchase_order.py b/buying/doctype/purchase_order/purchase_order.py
index 244bd7a..438442c 100644
--- a/buying/doctype/purchase_order/purchase_order.py
+++ b/buying/doctype/purchase_order/purchase_order.py
@@ -18,12 +18,10 @@
import webnotes
from webnotes.utils import cstr, flt
-from webnotes.model.doc import addchild
from webnotes.model.bean import getlist
from webnotes.model.code import get_obj
from webnotes import msgprint
from buying.utils import get_last_purchase_details
-from setup.utils import get_company_currency
sql = webnotes.conn.sql
@@ -35,7 +33,6 @@
self.tname = 'Purchase Order Item'
self.fname = 'po_details'
- # Validate
def validate(self):
super(DocType, self).validate()
@@ -64,6 +61,10 @@
# Check for stopped status
self.check_for_stopped_status(pc_obj)
+ # sub-contracting
+ self.validate_for_subcontracting()
+ self.update_raw_materials_supplied("po_raw_material_details")
+
def get_default_schedule_date(self):
get_obj(dt = 'Purchase Common').get_default_schedule_date(self)
@@ -79,7 +80,6 @@
def get_indent_details(self):
if self.doc.indent_no:
get_obj('DocType Mapper','Material Request-Purchase Order').dt_map('Material Request','Purchase Order',self.doc.indent_no, self.doc, self.doclist, "[['Material Request','Purchase Order'],['Material Request Item', 'Purchase Order Item']]")
- pcomm = get_obj('Purchase Common')
for d in getlist(self.doclist, 'po_details'):
if d.item_code and not d.purchase_rate:
last_purchase_details = get_last_purchase_details(d.item_code, self.doc.name)
@@ -173,8 +173,6 @@
msgprint(cstr(self.doc.doctype) +" => "+ cstr(self.doc.name) +" has been modified. Please Refresh. ")
raise Exception
- # On Close
- #-------------------------------------------------------------------------------------------------
def update_status(self, status):
self.check_modified_date()
# step 1:=> Set Status
@@ -186,8 +184,6 @@
# step 3:=> Acknowledge user
msgprint(self.doc.doctype + ": " + self.doc.name + " has been %s." % ((status == 'Submitted') and 'Unstopped' or cstr(status)))
-
- # On Submit
def on_submit(self):
purchase_controller = webnotes.get_obj("Purchase Common")
purchase_controller.is_item_table_empty(self)
@@ -207,118 +203,31 @@
# Step 6 :=> Set Status
webnotes.conn.set(self.doc,'status','Submitted')
- # On Cancel
- # -------------------------------------------------------------------------------------------------------
def on_cancel(self):
pc_obj = get_obj(dt = 'Purchase Common')
- # 1.Check if PO status is stopped
+ # Check if PO status is stopped
pc_obj.check_for_stopped_status(cstr(self.doc.doctype), cstr(self.doc.name))
self.check_for_stopped_status(pc_obj)
- # 2.Check if Purchase Receipt has been submitted against current Purchase Order
+ # Check if Purchase Receipt has been submitted against current Purchase Order
pc_obj.check_docstatus(check = 'Next', doctype = 'Purchase Receipt', docname = self.doc.name, detail_doctype = 'Purchase Receipt Item')
- # 3.Check if Purchase Invoice has been submitted against current Purchase Order
- #pc_obj.check_docstatus(check = 'Next', doctype = 'Purchase Invoice', docname = self.doc.name, detail_doctype = 'Purchase Invoice Item')
-
+ # Check if Purchase Invoice has been submitted against current Purchase Order
submitted = sql("select t1.name from `tabPurchase Invoice` t1,`tabPurchase Invoice Item` t2 where t1.name = t2.parent and t2.purchase_order = '%s' and t1.docstatus = 1" % self.doc.name)
if submitted:
msgprint("Purchase Invoice : " + cstr(submitted[0][0]) + " has already been submitted !")
raise Exception
- # 4.Set Status as Cancelled
webnotes.conn.set(self.doc,'status','Cancelled')
-
- # 5.Update Material Requests Pending Qty and accordingly it's Status
pc_obj.update_prevdoc_detail(self,is_submit = 0)
-
- # 6.Update Bin
self.update_bin( is_submit = 0, is_stopped = 0)
-
- # Step 7 :=> Update last purchase rate
pc_obj.update_last_purchase_rate(self, is_submit = 0)
-
-#----------- code for Sub-contracted Items -------------------
- #--------check for sub-contracted items and accordingly update PO raw material detail table--------
- def update_rw_material_detail(self):
- for d in getlist(self.doclist,'po_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 order to be made for subcontracting or for purchasing in 'Is Subcontracted' field .")
- raise Exception
- if self.doc.is_subcontracted == 'Yes':
- self.add_bom(d)
- else:
- self.doclist = self.doc.clear_table(self.doclist,'po_raw_material_details',1)
- self.doc.save()
- elif item_det[0][1] == 'No':
- self.add_bom(d)
- self.delete_irrelevant_raw_material()
- #---------------calculate amt in Purchase Order Item Supplied-------------
-
- 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.parent
- from `tabBOM` t1, `tabBOM Item` t2
- where t2.parent = t1.name and t1.item = %s
- and ifnull(t1.is_default,0) = 1 and t1.docstatus = 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:
- if i and not sql("select name from `tabPurchase Order 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, 'po_raw_material_details', 'Purchase Order 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.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.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 po_rmd in getlist(self.doclist, 'po_raw_material_details'):
- if i and i[6] == po_rmd.bom_detail_no and (flt(act_qty) != flt(po_rmd.required_qty) or i[1] != po_rmd.rm_item_code):
- chgd_rqd_qty.append(cstr(i[1]))
- po_rmd.main_item_code = i[0]
- po_rmd.rm_item_code = i[1]
- po_rmd.stock_uom = i[5]
- po_rmd.required_qty = flt(act_qty)
- po_rmd.rate = i and flt(i[3]) or flt(i[4])
- po_rmd.amount = flt(flt(po_rmd.consumed_qty)*flt(po_rmd.rate))
-
-
- # Delete irrelevant raw material from PR Raw material details
- #--------------------------------------------------------------
- def delete_irrelevant_raw_material(self):
- for d in getlist(self.doclist,'po_raw_material_details'):
- if not sql("select name from `tabPurchase Order 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()
-
- # On Update
- # ----------------------------------------------------------------------------------------------------
def on_update(self):
- self.update_rw_material_detail()
+ pass
-
def get_rate(self,arg):
return get_obj('Purchase Common').get_rate(arg,self)
diff --git a/buying/doctype/purchase_order/test_purchase_order.py b/buying/doctype/purchase_order/test_purchase_order.py
new file mode 100644
index 0000000..bd27f07
--- /dev/null
+++ b/buying/doctype/purchase_order/test_purchase_order.py
@@ -0,0 +1,65 @@
+# ERPNext - web based ERP (http://erpnext.com)
+# Copyright (C) 2012 Web Notes Technologies Pvt Ltd
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+
+from __future__ import unicode_literals
+import unittest
+import webnotes
+import webnotes.defaults
+from webnotes.utils import cint
+
+class TestPurchaseOrder(unittest.TestCase):
+ def test_subcontracting(self):
+ po = webnotes.bean(copy=test_records[0])
+ po.insert()
+ self.assertEquals(len(po.doclist.get({"parentfield": "po_raw_material_details"})), 2)
+
+
+test_dependencies = ["BOM"]
+
+test_records = [
+ [
+ {
+ "company": "_Test Company",
+ "conversion_rate": 1.0,
+ "currency": "INR",
+ "doctype": "Purchase Order",
+ "fiscal_year": "_Test Fiscal Year 2013",
+ "transaction_date": "2013-02-12",
+ "is_subcontracted": "Yes",
+ "supplier": "_Test Supplier",
+ "supplier_name": "_Test Supplier",
+ "net_total": 5000.0,
+ "grand_total": 5000.0,
+ "grand_total_import": 5000.0,
+
+ },
+ {
+ "conversion_factor": 1.0,
+ "description": "_Test FG Item",
+ "doctype": "Purchase Order Item",
+ "item_code": "_Test FG Item",
+ "item_name": "_Test FG Item",
+ "parentfield": "po_details",
+ "qty": 10.0,
+ "import_rate": 500.0,
+ "amount": 5000.0,
+ "warehouse": "_Test Warehouse",
+ "stock_uom": "Nos",
+ "uom": "_Test UOM",
+ }
+ ],
+]
\ No newline at end of file
diff --git a/controllers/buying_controller.py b/controllers/buying_controller.py
index 8b247cc..2f3128c 100644
--- a/controllers/buying_controller.py
+++ b/controllers/buying_controller.py
@@ -342,6 +342,67 @@
) / flt(d.conversion_factor)
else:
d.valuation_rate = 0.0
+
+ def validate_for_subcontracting(self):
+ if not self.doc.is_subcontracted and self.sub_contracted_items:
+ webnotes.msgprint(_("""Please enter whether %s is made for subcontracting or purchasing,
+ in 'Is Subcontracted' field""" % self.doc.doctype), raise_exception=1)
+
+ if self.doc.doctype == "Purchase Receipt" and self.doc.is_subcontracted=="Yes" \
+ and not self.doc.supplier_warehouse:
+ webnotes.msgprint(_("Supplier Warehouse mandatory subcontracted purchase receipt"),
+ raise_exception=1)
+
+ def update_raw_materials_supplied(self, raw_material_table):
+ self.doclist = self.doc.clear_table(self.doclist, raw_material_table)
+ if self.doc.is_subcontracted=="Yes":
+ for item in self.doclist.get({"parentfield": self.fname}):
+ if item.item_code in self.sub_contracted_items:
+ self.add_bom_items(item, raw_material_table)
+
+ def add_bom_items(self, d, raw_material_table):
+ 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)
+ rm_doclist = {
+ "parentfield": raw_material_table,
+ "doctype": self.doc.doctype + " Item Supplied",
+ "reference_name": d.name,
+ "bom_detail_no": item.name,
+ "main_item_code": d.item_code,
+ "rm_item_code": item.item_code,
+ "stock_uom": item.stock_uom,
+ "required_qty": required_qty,
+ "conversion_factor": d.conversion_factor,
+ "rate": item.rate,
+ "amount": required_qty * flt(item.rate)
+ }
+ if self.doc.doctype == "Purchase Receipt":
+ rm_doclist.update({
+ "consumed_qty": required_qty,
+ "description": item.description,
+ })
+
+ self.doclist.append(rm_doclist)
+
+ raw_materials_cost += required_qty * flt(item.rate)
+
+ if self.doc.doctype == "Purchase Receipt":
+ d.rm_supp_cost = raw_materials_cost
+
+ def get_items_from_default_bom(self, item_code):
+ # print webnotes.conn.sql("""select name from `tabBOM` where item = '_Test FG Item'""")
+ bom_items = webnotes.conn.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 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
+
@property
def precision(self):
diff --git a/selling/doctype/customer/test_customer.py b/selling/doctype/customer/test_customer.py
index 09e2f5d..551b03f 100644
--- a/selling/doctype/customer/test_customer.py
+++ b/selling/doctype/customer/test_customer.py
@@ -1,3 +1,4 @@
+
test_records = [
[{
"doctype": "Customer",
diff --git a/stock/doctype/purchase_receipt/purchase_receipt.py b/stock/doctype/purchase_receipt/purchase_receipt.py
index 2f8835f..12da0a6 100644
--- a/stock/doctype/purchase_receipt/purchase_receipt.py
+++ b/stock/doctype/purchase_receipt/purchase_receipt.py
@@ -122,7 +122,7 @@
# sub-contracting
self.validate_for_subcontracting()
- self.update_raw_materials_supplied()
+ self.update_raw_materials_supplied("pr_raw_material_details")
self.update_valuation_rate("purchase_receipt_details")
@@ -289,59 +289,6 @@
self.make_gl_entries()
- def validate_for_subcontracting(self):
- if not self.doc.is_subcontracted and self.sub_contracted_items:
- 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=="Yes" 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.doc.is_subcontracted=="Yes":
- 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 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
-
- 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 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
-
def bk_flush_supp_wh(self, is_submit):
for d in getlist(self.doclist, 'pr_raw_material_details'):
# negative quantity is passed as raw material qty has to be decreased