sub-contracting code refactored for po

This commit is contained in:
Nabin Hait 2013-03-01 18:51:10 +05:30
parent 73b2bb6f91
commit 54d209ffb0
5 changed files with 136 additions and 153 deletions

View File

@ -18,12 +18,10 @@ from __future__ import unicode_literals
import webnotes import webnotes
from webnotes.utils import cstr, flt from webnotes.utils import cstr, flt
from webnotes.model.doc import addchild
from webnotes.model.bean import getlist from webnotes.model.bean import getlist
from webnotes.model.code import get_obj from webnotes.model.code import get_obj
from webnotes import msgprint from webnotes import msgprint
from buying.utils import get_last_purchase_details from buying.utils import get_last_purchase_details
from setup.utils import get_company_currency
sql = webnotes.conn.sql sql = webnotes.conn.sql
@ -35,7 +33,6 @@ class DocType(BuyingController):
self.tname = 'Purchase Order Item' self.tname = 'Purchase Order Item'
self.fname = 'po_details' self.fname = 'po_details'
# Validate
def validate(self): def validate(self):
super(DocType, self).validate() super(DocType, self).validate()
@ -64,6 +61,10 @@ class DocType(BuyingController):
# Check for stopped status # Check for stopped status
self.check_for_stopped_status(pc_obj) 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): def get_default_schedule_date(self):
get_obj(dt = 'Purchase Common').get_default_schedule_date(self) get_obj(dt = 'Purchase Common').get_default_schedule_date(self)
@ -79,7 +80,6 @@ class DocType(BuyingController):
def get_indent_details(self): def get_indent_details(self):
if self.doc.indent_no: 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']]") 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'): for d in getlist(self.doclist, 'po_details'):
if d.item_code and not d.purchase_rate: if d.item_code and not d.purchase_rate:
last_purchase_details = get_last_purchase_details(d.item_code, self.doc.name) last_purchase_details = get_last_purchase_details(d.item_code, self.doc.name)
@ -173,8 +173,6 @@ class DocType(BuyingController):
msgprint(cstr(self.doc.doctype) +" => "+ cstr(self.doc.name) +" has been modified. Please Refresh. ") msgprint(cstr(self.doc.doctype) +" => "+ cstr(self.doc.name) +" has been modified. Please Refresh. ")
raise Exception raise Exception
# On Close
#-------------------------------------------------------------------------------------------------
def update_status(self, status): def update_status(self, status):
self.check_modified_date() self.check_modified_date()
# step 1:=> Set Status # step 1:=> Set Status
@ -186,8 +184,6 @@ class DocType(BuyingController):
# step 3:=> Acknowledge user # step 3:=> Acknowledge user
msgprint(self.doc.doctype + ": " + self.doc.name + " has been %s." % ((status == 'Submitted') and 'Unstopped' or cstr(status))) msgprint(self.doc.doctype + ": " + self.doc.name + " has been %s." % ((status == 'Submitted') and 'Unstopped' or cstr(status)))
# On Submit
def on_submit(self): def on_submit(self):
purchase_controller = webnotes.get_obj("Purchase Common") purchase_controller = webnotes.get_obj("Purchase Common")
purchase_controller.is_item_table_empty(self) purchase_controller.is_item_table_empty(self)
@ -207,118 +203,31 @@ class DocType(BuyingController):
# Step 6 :=> Set Status # Step 6 :=> Set Status
webnotes.conn.set(self.doc,'status','Submitted') webnotes.conn.set(self.doc,'status','Submitted')
# On Cancel
# -------------------------------------------------------------------------------------------------------
def on_cancel(self): def on_cancel(self):
pc_obj = get_obj(dt = 'Purchase Common') 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)) pc_obj.check_for_stopped_status(cstr(self.doc.doctype), cstr(self.doc.name))
self.check_for_stopped_status(pc_obj) 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') 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 # 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')
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) 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: if submitted:
msgprint("Purchase Invoice : " + cstr(submitted[0][0]) + " has already been submitted !") msgprint("Purchase Invoice : " + cstr(submitted[0][0]) + " has already been submitted !")
raise Exception raise Exception
# 4.Set Status as Cancelled
webnotes.conn.set(self.doc,'status','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) pc_obj.update_prevdoc_detail(self,is_submit = 0)
# 6.Update Bin
self.update_bin( is_submit = 0, is_stopped = 0) 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) 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): def on_update(self):
self.update_rw_material_detail() pass
def get_rate(self,arg): def get_rate(self,arg):
return get_obj('Purchase Common').get_rate(arg,self) return get_obj('Purchase Common').get_rate(arg,self)

View File

@ -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",
}
],
]

View File

@ -342,6 +342,67 @@ class BuyingController(AccountsController):
) / flt(d.conversion_factor) ) / flt(d.conversion_factor)
else: else:
d.valuation_rate = 0.0 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 @property
def precision(self): def precision(self):

View File

@ -1,3 +1,4 @@
test_records = [ test_records = [
[{ [{
"doctype": "Customer", "doctype": "Customer",

View File

@ -122,7 +122,7 @@ class DocType(BuyingController):
# sub-contracting # sub-contracting
self.validate_for_subcontracting() 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") self.update_valuation_rate("purchase_receipt_details")
@ -289,59 +289,6 @@ class DocType(BuyingController):
self.make_gl_entries() 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): def bk_flush_supp_wh(self, is_submit):
for d in getlist(self.doclist, 'pr_raw_material_details'): for d in getlist(self.doclist, 'pr_raw_material_details'):
# negative quantity is passed as raw material qty has to be decreased # negative quantity is passed as raw material qty has to be decreased