2010-04-29 13:30:07 +00:00
# -*- coding: utf-8 -*-
##############################################################################
#
# OpenERP, Open Source Management Solution
# Copyright (C) 2004-2010 Tiny SPRL (<http://tiny.be>).
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero 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 Affero General Public License for more details.
#
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
##############################################################################
from osv import osv , fields
from tools . translate import _
import netsvc
import time
2011-10-31 11:38:30 +00:00
import decimal_precision as dp
2010-04-29 13:30:07 +00:00
# Procurement
# ------------------------------------------------------------------
#
# Produce, Buy or Find products and place a move
# then wizard for picking lists & move
#
2010-07-07 11:45:16 +00:00
class mrp_property_group ( osv . osv ) :
"""
Group of mrp properties .
"""
_name = ' mrp.property.group '
_description = ' Property Group '
_columns = {
' name ' : fields . char ( ' Property Group ' , size = 64 , required = True ) ,
' description ' : fields . text ( ' Description ' ) ,
}
mrp_property_group ( )
class mrp_property ( osv . osv ) :
"""
Properties of mrp .
"""
_name = ' mrp.property '
_description = ' Property '
_columns = {
' name ' : fields . char ( ' Name ' , size = 64 , required = True ) ,
' composition ' : fields . selection ( [ ( ' min ' , ' min ' ) , ( ' max ' , ' max ' ) , ( ' plus ' , ' plus ' ) ] , ' Properties composition ' , required = True , help = " Not used in computations, for information purpose only. " ) ,
' group_id ' : fields . many2one ( ' mrp.property.group ' , ' Property Group ' , required = True ) ,
' description ' : fields . text ( ' Description ' ) ,
}
_defaults = {
' composition ' : lambda * a : ' min ' ,
}
mrp_property ( )
2010-09-01 09:13:08 +00:00
class StockMove ( osv . osv ) :
_inherit = ' stock.move '
_columns = {
' procurements ' : fields . one2many ( ' procurement.order ' , ' move_id ' , ' Procurements ' ) ,
}
2010-11-15 09:36:28 +00:00
2010-09-01 09:13:08 +00:00
def copy ( self , cr , uid , id , default = None , context = None ) :
default = default or { }
default [ ' procurements ' ] = [ ]
2010-11-22 10:37:53 +00:00
return super ( StockMove , self ) . copy ( cr , uid , id , default , context = context )
2010-09-01 09:13:08 +00:00
StockMove ( )
2010-05-27 12:47:06 +00:00
class procurement_order ( osv . osv ) :
2010-04-29 13:30:07 +00:00
"""
Procurement Orders
"""
2010-05-27 12:47:06 +00:00
_name = " procurement.order "
2010-04-29 13:30:07 +00:00
_description = " Procurement "
2010-05-19 20:02:36 +00:00
_order = ' priority,date_planned desc '
2012-05-07 10:43:44 +00:00
_inherit = [ ' mail.thread ' ]
2010-05-19 20:02:36 +00:00
_log_create = False
2010-04-29 13:30:07 +00:00
_columns = {
' name ' : fields . char ( ' Reason ' , size = 64 , required = True , help = ' Procurement name. ' ) ,
' origin ' : fields . char ( ' Source Document ' , size = 64 ,
help = " Reference of the document that created this Procurement. \n "
2010-08-10 11:35:06 +00:00
" This is automatically completed by OpenERP. " ) ,
2011-12-09 06:03:08 +00:00
' priority ' : fields . selection ( [ ( ' 0 ' , ' Not urgent ' ) , ( ' 1 ' , ' Normal ' ) , ( ' 2 ' , ' Urgent ' ) , ( ' 3 ' , ' Very Urgent ' ) ] , ' Priority ' , required = True , select = True ) ,
' date_planned ' : fields . datetime ( ' Scheduled date ' , required = True , select = True ) ,
2010-04-29 13:30:07 +00:00
' date_close ' : fields . datetime ( ' Date Closed ' ) ,
' product_id ' : fields . many2one ( ' product.product ' , ' Product ' , required = True , states = { ' draft ' : [ ( ' readonly ' , False ) ] } , readonly = True ) ,
2012-04-25 11:29:50 +00:00
' product_qty ' : fields . float ( ' Quantity ' , digits_compute = dp . get_precision ( ' Product Unit of Measure ' ) , required = True , states = { ' draft ' : [ ( ' readonly ' , False ) ] } , readonly = True ) ,
' product_uom ' : fields . many2one ( ' product.uom ' , ' Product Unit of Measure ' , required = True , states = { ' draft ' : [ ( ' readonly ' , False ) ] } , readonly = True ) ,
2010-04-29 13:30:07 +00:00
' product_uos_qty ' : fields . float ( ' UoS Quantity ' , states = { ' draft ' : [ ( ' readonly ' , False ) ] } , readonly = True ) ,
' product_uos ' : fields . many2one ( ' product.uom ' , ' Product UoS ' , states = { ' draft ' : [ ( ' readonly ' , False ) ] } , readonly = True ) ,
' move_id ' : fields . many2one ( ' stock.move ' , ' Reservation ' , ondelete = ' set null ' ) ,
' close_move ' : fields . boolean ( ' Close Move at end ' , required = True ) ,
' location_id ' : fields . many2one ( ' stock.location ' , ' Location ' , required = True , states = { ' draft ' : [ ( ' readonly ' , False ) ] } , readonly = True ) ,
' procure_method ' : fields . selection ( [ ( ' make_to_stock ' , ' from stock ' ) , ( ' make_to_order ' , ' on order ' ) ] , ' Procurement Method ' , states = { ' draft ' : [ ( ' readonly ' , False ) ] , ' confirmed ' : [ ( ' readonly ' , False ) ] } ,
readonly = True , required = True , help = " If you encode manually a Procurement, you probably want to use " \
" a make to order method. " ) ,
' note ' : fields . text ( ' Note ' ) ,
2012-05-15 05:52:22 +00:00
' message ' : fields . char ( ' Latest error ' , size = 124 , help = " Exception occurred while computing procurement orders. " ) ,
2010-04-29 13:30:07 +00:00
' state ' : fields . selection ( [
( ' draft ' , ' Draft ' ) ,
2012-05-04 11:03:05 +00:00
( ' cancel ' , ' Cancelled ' ) ,
2010-04-29 13:30:07 +00:00
( ' confirmed ' , ' Confirmed ' ) ,
( ' exception ' , ' Exception ' ) ,
( ' running ' , ' Running ' ) ,
( ' ready ' , ' Ready ' ) ,
( ' done ' , ' Done ' ) ,
2012-05-04 11:57:48 +00:00
( ' waiting ' , ' Waiting ' ) ] , ' Status ' , required = True ,
2010-04-29 13:30:07 +00:00
help = ' When a procurement is created the state is set to \' Draft \' . \n If the procurement is confirmed, the state is set to \' Confirmed \' . \
\nAfter confirming the state is set to \' Running \' . \n If any exception arises in the order then the state is set to \' Exception \' . \n Once the exception is removed the state becomes \' Ready \' . \n It is in \' Waiting \' . state when the procurement is waiting for another one to finish. ' ) ,
' note ' : fields . text ( ' Note ' ) ,
' company_id ' : fields . many2one ( ' res.company ' , ' Company ' , required = True ) ,
}
_defaults = {
2010-12-07 17:53:42 +00:00
' state ' : ' draft ' ,
' priority ' : ' 1 ' ,
2010-04-29 13:30:07 +00:00
' date_planned ' : lambda * a : time . strftime ( ' % Y- % m- %d % H: % M: % S ' ) ,
2010-12-07 17:53:42 +00:00
' close_move ' : 0 ,
' procure_method ' : ' make_to_order ' ,
2010-05-27 12:47:06 +00:00
' company_id ' : lambda self , cr , uid , c : self . pool . get ( ' res.company ' ) . _company_default_get ( cr , uid , ' procurement.order ' , context = c )
2010-04-29 13:30:07 +00:00
}
def unlink ( self , cr , uid , ids , context = None ) :
2010-12-13 06:43:09 +00:00
procurements = self . read ( cr , uid , ids , [ ' state ' ] , context = context )
2010-04-29 13:30:07 +00:00
unlink_ids = [ ]
for s in procurements :
if s [ ' state ' ] in [ ' draft ' , ' cancel ' ] :
unlink_ids . append ( s [ ' id ' ] )
else :
2012-08-07 11:06:16 +00:00
raise osv . except_osv ( _ ( ' Invalid Action! ' ) ,
_ ( ' Cannot delete Procurement Order(s) which are in %s state. ' ) % \
2010-09-07 07:49:46 +00:00
s [ ' state ' ] )
2010-04-29 13:30:07 +00:00
return osv . osv . unlink ( self , cr , uid , unlink_ids , context = context )
2010-11-19 13:48:01 +00:00
def onchange_product_id ( self , cr , uid , ids , product_id , context = None ) :
2010-04-29 13:30:07 +00:00
""" Finds UoM and UoS of changed product.
@param product_id : Changed id of product .
@return : Dictionary of values .
"""
if product_id :
2010-11-19 13:48:01 +00:00
w = self . pool . get ( ' product.product ' ) . browse ( cr , uid , product_id , context = context )
2010-04-29 13:30:07 +00:00
v = {
' product_uom ' : w . uom_id . id ,
' product_uos ' : w . uos_id and w . uos_id . id or w . uom_id . id
}
return { ' value ' : v }
return { }
2011-12-14 10:31:44 +00:00
def check_product ( self , cr , uid , ids , context = None ) :
2010-04-29 13:30:07 +00:00
""" Checks product type.
2010-05-14 13:24:15 +00:00
@return : True or False
2010-04-29 13:30:07 +00:00
"""
2011-12-16 10:31:25 +00:00
return all ( proc . product_id . type in ( ' product ' , ' consu ' ) for proc in self . browse ( cr , uid , ids , context = context ) )
2010-04-29 13:30:07 +00:00
2010-11-19 13:48:01 +00:00
def check_move_cancel ( self , cr , uid , ids , context = None ) :
2010-04-29 13:30:07 +00:00
""" Checks if move is cancelled or not.
2010-05-14 13:24:15 +00:00
@return : True or False .
2010-04-29 13:30:07 +00:00
"""
2010-11-19 13:48:01 +00:00
return all ( procurement . move_id . state == ' cancel ' for procurement in self . browse ( cr , uid , ids , context = context ) )
2010-04-29 13:30:07 +00:00
2012-08-07 10:23:26 +00:00
#This Function is create to avoid a server side Error Like 'ERROR:tests.mrp:name 'check_move' is not defined'
2011-08-04 13:17:05 +00:00
def check_move ( self , cr , uid , ids , context = None ) :
pass
2010-11-22 12:38:00 +00:00
def check_move_done ( self , cr , uid , ids , context = None ) :
2010-04-29 13:30:07 +00:00
""" Checks if move is done or not.
2010-05-14 13:24:15 +00:00
@return : True or False .
2010-04-29 13:30:07 +00:00
"""
2011-12-16 10:31:25 +00:00
return all ( proc . product_id . type == ' service ' or ( proc . move_id and proc . move_id . state == ' done ' ) \
for proc in self . browse ( cr , uid , ids , context = context ) )
2010-04-29 13:30:07 +00:00
#
2010-05-27 12:47:06 +00:00
# This method may be overrided by objects that override procurement.order
2010-04-29 13:30:07 +00:00
# for computing their own purpose
#
2010-11-19 13:48:01 +00:00
def _quantity_compute_get ( self , cr , uid , proc , context = None ) :
2010-04-29 13:30:07 +00:00
""" Finds sold quantity of product.
@param proc : Current procurement .
@return : Quantity or False .
"""
2010-08-31 10:20:45 +00:00
if proc . product_id . type == ' product ' and proc . move_id :
2010-04-29 13:30:07 +00:00
if proc . move_id . product_uos :
return proc . move_id . product_uos_qty
return False
2010-11-19 13:48:01 +00:00
def _uom_compute_get ( self , cr , uid , proc , context = None ) :
2010-05-14 13:24:15 +00:00
""" Finds UoS if product is Stockable Product.
2010-04-29 13:30:07 +00:00
@param proc : Current procurement .
@return : UoS or False .
"""
2010-08-31 10:20:45 +00:00
if proc . product_id . type == ' product ' and proc . move_id :
2010-04-29 13:30:07 +00:00
if proc . move_id . product_uos :
return proc . move_id . product_uos . id
return False
#
2010-06-02 07:13:39 +00:00
# Return the quantity of product shipped/produced/served, which may be
2010-04-29 13:30:07 +00:00
# different from the planned quantity
#
2010-11-19 13:48:01 +00:00
def quantity_get ( self , cr , uid , id , context = None ) :
2010-04-29 13:30:07 +00:00
""" Finds quantity of product used in procurement.
2010-05-14 13:24:15 +00:00
@return : Quantity of product .
2010-04-29 13:30:07 +00:00
"""
2010-11-19 13:48:01 +00:00
proc = self . browse ( cr , uid , id , context = context )
result = self . _quantity_compute_get ( cr , uid , proc , context = context )
2010-04-29 13:30:07 +00:00
if not result :
result = proc . product_qty
return result
def uom_get ( self , cr , uid , id , context = None ) :
""" Finds UoM of product used in procurement.
2010-05-14 13:24:15 +00:00
@return : UoM of product .
2010-04-29 13:30:07 +00:00
"""
2010-11-22 10:37:53 +00:00
proc = self . browse ( cr , uid , id , context = context )
result = self . _uom_compute_get ( cr , uid , proc , context = context )
2010-04-29 13:30:07 +00:00
if not result :
result = proc . product_uom . id
return result
2010-11-23 07:05:05 +00:00
def check_waiting ( self , cr , uid , ids , context = None ) :
2010-04-29 13:30:07 +00:00
""" Checks state of move.
2010-05-14 13:24:15 +00:00
@return : True or False
2010-04-29 13:30:07 +00:00
"""
for procurement in self . browse ( cr , uid , ids , context = context ) :
if procurement . move_id and procurement . move_id . state == ' auto ' :
return True
return False
2010-11-22 10:37:53 +00:00
def check_produce_service ( self , cr , uid , procurement , context = None ) :
2010-07-10 05:16:19 +00:00
return False
2010-04-29 13:30:07 +00:00
2010-11-22 10:37:53 +00:00
def check_produce_product ( self , cr , uid , procurement , context = None ) :
2010-04-29 13:30:07 +00:00
""" Finds BoM of a product if not found writes exception message.
@param procurement : Current procurement .
@return : True or False .
"""
return True
2010-11-19 13:48:01 +00:00
def check_make_to_stock ( self , cr , uid , ids , context = None ) :
2010-04-29 13:30:07 +00:00
""" Checks product type.
2010-05-14 13:24:15 +00:00
@return : True or False
2010-04-29 13:30:07 +00:00
"""
ok = True
for procurement in self . browse ( cr , uid , ids , context = context ) :
if procurement . product_id . type == ' service ' :
ok = ok and self . _check_make_to_stock_service ( cr , uid , procurement , context )
else :
ok = ok and self . _check_make_to_stock_product ( cr , uid , procurement , context )
return ok
2010-11-19 13:48:01 +00:00
def check_produce ( self , cr , uid , ids , context = None ) :
2010-04-29 13:30:07 +00:00
""" Checks product type.
2011-12-16 10:31:25 +00:00
@return : True or False
2010-04-29 13:30:07 +00:00
"""
2010-11-19 13:48:01 +00:00
user = self . pool . get ( ' res.users ' ) . browse ( cr , uid , uid , context = context )
for procurement in self . browse ( cr , uid , ids , context = context ) :
2011-12-13 13:29:04 +00:00
product = procurement . product_id
#TOFIX: if product type is 'service' but supply_method is 'buy'.
if product . supply_method < > ' produce ' :
supplier = product . seller_id
if supplier and user . company_id and user . company_id . partner_id :
if supplier . id == user . company_id . partner_id . id :
2011-12-16 10:31:25 +00:00
continue
2010-04-29 13:30:07 +00:00
return False
2011-12-14 06:32:09 +00:00
if product . type == ' service ' :
2011-12-16 10:31:25 +00:00
res = self . check_produce_service ( cr , uid , procurement , context )
2010-04-29 13:30:07 +00:00
else :
2011-12-16 10:31:25 +00:00
res = self . check_produce_product ( cr , uid , procurement , context )
2010-04-29 13:30:07 +00:00
if not res :
return False
2011-12-16 10:31:25 +00:00
return True
2012-08-07 10:23:26 +00:00
2010-04-29 13:30:07 +00:00
def check_buy ( self , cr , uid , ids ) :
""" Checks product type.
@return : True or Product Id .
"""
user = self . pool . get ( ' res.users ' ) . browse ( cr , uid , uid )
partner_obj = self . pool . get ( ' res.partner ' )
for procurement in self . browse ( cr , uid , ids ) :
if procurement . product_id . product_tmpl_id . supply_method < > ' buy ' :
return False
if not procurement . product_id . seller_ids :
2012-05-29 08:39:41 +00:00
message = _ ( ' No supplier defined for this product ! ' )
2012-06-01 14:59:24 +00:00
self . message_append_note ( cr , uid , [ procurement . id ] , body = message )
2012-05-29 08:39:41 +00:00
cr . execute ( ' update procurement_order set message= %s where id= %s ' , ( message , procurement . id ) )
2010-04-29 13:30:07 +00:00
return False
2010-07-23 13:17:30 +00:00
partner = procurement . product_id . seller_id #Taken Main Supplier of Product of Procurement.
2010-06-07 18:42:14 +00:00
2011-03-10 09:52:41 +00:00
if not partner :
2012-05-29 08:39:41 +00:00
message = _ ( ' No default supplier defined for this product ' )
2012-06-01 14:59:24 +00:00
self . message_append_note ( cr , uid , [ procurement . id ] , body = message )
2012-05-29 08:39:41 +00:00
cr . execute ( ' update procurement_order set message= %s where id= %s ' , ( message , procurement . id ) )
2011-03-10 09:52:41 +00:00
return False
2010-04-29 13:30:07 +00:00
if user . company_id and user . company_id . partner_id :
if partner . id == user . company_id . partner_id . id :
return False
2011-03-10 09:52:41 +00:00
2010-04-29 13:30:07 +00:00
address_id = partner_obj . address_get ( cr , uid , [ partner . id ] , [ ' delivery ' ] ) [ ' delivery ' ]
if not address_id :
2012-05-29 08:39:41 +00:00
message = _ ( ' No address defined for the supplier ' )
2012-06-01 14:59:24 +00:00
self . message_append_note ( cr , uid , [ procurement . id ] , body = message )
2012-05-29 08:39:41 +00:00
cr . execute ( ' update procurement_order set message= %s where id= %s ' , ( message , procurement . id ) )
2010-04-29 13:30:07 +00:00
return False
return True
2012-06-01 14:40:59 +00:00
2010-04-29 13:30:07 +00:00
def test_cancel ( self , cr , uid , ids ) :
2010-05-14 13:24:15 +00:00
""" Tests whether state of move is cancelled or not.
2010-04-29 13:30:07 +00:00
@return : True or False
"""
for record in self . browse ( cr , uid , ids ) :
if record . move_id and record . move_id . state == ' cancel ' :
return True
return False
2012-07-20 12:36:23 +00:00
2012-07-26 06:08:36 +00:00
#Initialize get_phantom_bom_id method as it is raising an error from yml of mrp_jit
#when one install first mrp and after that, mrp_jit. get_phantom_bom_id defined in mrp module
#which is not dependent for mrp_jit.
def get_phantom_bom_id ( self , cr , uid , ids , context = None ) :
return False
2010-11-19 13:48:01 +00:00
def action_confirm ( self , cr , uid , ids , context = None ) :
2010-04-29 13:30:07 +00:00
""" Confirms procurement and writes exception message if any.
@return : True
"""
move_obj = self . pool . get ( ' stock.move ' )
2010-11-19 13:48:01 +00:00
for procurement in self . browse ( cr , uid , ids , context = context ) :
2010-04-29 13:30:07 +00:00
if procurement . product_qty < = 0.00 :
2012-08-07 10:23:26 +00:00
raise osv . except_osv ( _ ( ' Insufficient Data! ' ) ,
2012-08-07 11:06:16 +00:00
_ ( ' Quantity in procurement order(s) must be greater than 0. ' ) )
2010-04-29 13:30:07 +00:00
if procurement . product_id . type in ( ' product ' , ' consu ' ) :
if not procurement . move_id :
source = procurement . location_id . id
if procurement . procure_method == ' make_to_order ' :
source = procurement . product_id . product_tmpl_id . property_stock_procurement . id
id = move_obj . create ( cr , uid , {
2010-10-11 21:57:06 +00:00
' name ' : procurement . name ,
2010-04-29 13:30:07 +00:00
' location_id ' : source ,
' location_dest_id ' : procurement . location_id . id ,
' product_id ' : procurement . product_id . id ,
' product_qty ' : procurement . product_qty ,
' product_uom ' : procurement . product_uom . id ,
2010-10-05 12:50:28 +00:00
' date_expected ' : procurement . date_planned ,
2010-05-19 20:54:46 +00:00
' state ' : ' draft ' ,
2010-04-29 13:30:07 +00:00
' company_id ' : procurement . company_id . id ,
2010-10-11 19:16:13 +00:00
' auto_validate ' : True ,
2010-04-29 13:30:07 +00:00
} )
2010-05-19 20:54:46 +00:00
move_obj . action_confirm ( cr , uid , [ id ] , context = context )
2010-04-29 13:30:07 +00:00
self . write ( cr , uid , [ procurement . id ] , { ' move_id ' : id , ' close_move ' : 1 } )
self . write ( cr , uid , ids , { ' state ' : ' confirmed ' , ' message ' : ' ' } )
2012-04-27 08:54:40 +00:00
self . confirm_send_note ( cr , uid , ids , context )
2010-04-29 13:30:07 +00:00
return True
2010-11-19 13:48:01 +00:00
def action_move_assigned ( self , cr , uid , ids , context = None ) :
2010-04-29 13:30:07 +00:00
""" Changes procurement state to Running and writes message.
2010-05-14 13:24:15 +00:00
@return : True
2010-04-29 13:30:07 +00:00
"""
2012-06-01 14:40:59 +00:00
message = _ ( ' From stock: products assigned. ' )
2010-11-15 09:36:28 +00:00
self . write ( cr , uid , ids , { ' state ' : ' running ' ,
2012-06-01 14:40:59 +00:00
' message ' : message } , context = context )
2012-08-07 10:23:26 +00:00
self . message_append_note ( cr , uid , ids , body = message , context = context )
2012-06-01 14:40:59 +00:00
self . running_send_note ( cr , uid , ids , context = context )
2010-04-29 13:30:07 +00:00
return True
2010-11-19 13:48:01 +00:00
def _check_make_to_stock_service ( self , cr , uid , procurement , context = None ) :
2010-07-10 05:16:19 +00:00
"""
This method may be overrided by objects that override procurement . order
for computing their own purpose
@return : True """
2010-04-29 13:30:07 +00:00
return True
2010-11-19 13:48:01 +00:00
def _check_make_to_stock_product ( self , cr , uid , procurement , context = None ) :
2010-04-29 13:30:07 +00:00
""" Checks procurement move state.
@param procurement : Current procurement .
@return : True or move id .
"""
ok = True
if procurement . move_id :
2011-01-05 06:20:12 +00:00
message = False
2010-04-29 13:30:07 +00:00
id = procurement . move_id . id
if not ( procurement . move_id . state in ( ' done ' , ' assigned ' , ' cancel ' ) ) :
ok = ok and self . pool . get ( ' stock.move ' ) . action_assign ( cr , uid , [ id ] )
2011-09-16 13:24:42 +00:00
order_point_id = self . pool . get ( ' stock.warehouse.orderpoint ' ) . search ( cr , uid , [ ( ' product_id ' , ' = ' , procurement . product_id . id ) ] , context = context )
2011-09-16 13:01:50 +00:00
if not order_point_id and not ok :
2011-01-05 06:20:12 +00:00
message = _ ( " Not enough stock and no minimum orderpoint rule defined. " )
2011-09-16 13:01:50 +00:00
elif not order_point_id :
2011-01-05 06:49:55 +00:00
message = _ ( " No minimum orderpoint rule defined. " )
2011-01-05 06:20:12 +00:00
elif not ok :
2011-01-05 06:49:55 +00:00
message = _ ( " Not enough stock. " )
2011-01-05 06:20:12 +00:00
if message :
2012-05-09 05:46:21 +00:00
message = _ ( " Procurement ' %s ' is in exception: " ) % ( procurement . name ) + message
2011-01-05 06:20:12 +00:00
cr . execute ( ' update procurement_order set message= %s where id= %s ' , ( message , procurement . id ) )
2012-08-07 10:23:26 +00:00
self . message_append_note ( cr , uid , [ procurement . id ] , body = message , context = context )
2010-04-29 13:30:07 +00:00
return ok
2010-11-19 13:48:01 +00:00
def action_produce_assign_service ( self , cr , uid , ids , context = None ) :
2010-04-29 13:30:07 +00:00
""" Changes procurement state to Running.
2010-05-14 13:24:15 +00:00
@return : True
2010-04-29 13:30:07 +00:00
"""
2010-11-19 13:48:01 +00:00
for procurement in self . browse ( cr , uid , ids , context = context ) :
2010-04-29 13:30:07 +00:00
self . write ( cr , uid , [ procurement . id ] , { ' state ' : ' running ' } )
2012-04-27 08:54:40 +00:00
self . running_send_note ( cr , uid , ids , context = None )
2010-04-29 13:30:07 +00:00
return True
2010-11-19 13:48:01 +00:00
def action_produce_assign_product ( self , cr , uid , ids , context = None ) :
2010-04-29 13:30:07 +00:00
""" This is action which call from workflow to assign production order to procurements
@return : True
"""
return 0
2010-05-14 13:24:15 +00:00
2010-11-19 13:48:01 +00:00
def action_po_assign ( self , cr , uid , ids , context = None ) :
2010-04-29 13:30:07 +00:00
""" This is action which call from workflow to assign purchase order to procurements
@return : True
"""
return 0
def action_cancel ( self , cr , uid , ids ) :
""" Cancels procurement and writes move state to Assigned.
2010-05-14 13:24:15 +00:00
@return : True
2010-04-29 13:30:07 +00:00
"""
todo = [ ]
todo2 = [ ]
move_obj = self . pool . get ( ' stock.move ' )
for proc in self . browse ( cr , uid , ids ) :
2010-08-31 10:20:45 +00:00
if proc . close_move and proc . move_id :
2010-04-29 13:30:07 +00:00
if proc . move_id . state not in ( ' done ' , ' cancel ' ) :
todo2 . append ( proc . move_id . id )
else :
if proc . move_id and proc . move_id . state == ' waiting ' :
todo . append ( proc . move_id . id )
if len ( todo2 ) :
move_obj . action_cancel ( cr , uid , todo2 )
if len ( todo ) :
move_obj . write ( cr , uid , todo , { ' state ' : ' assigned ' } )
self . write ( cr , uid , ids , { ' state ' : ' cancel ' } )
2012-04-27 08:54:40 +00:00
self . cancel_send_note ( cr , uid , ids , context = None )
2010-04-29 13:30:07 +00:00
wf_service = netsvc . LocalService ( " workflow " )
for id in ids :
2010-05-27 12:47:06 +00:00
wf_service . trg_trigger ( uid , ' procurement.order ' , id , cr )
2010-04-29 13:30:07 +00:00
return True
2010-09-15 11:58:12 +00:00
def action_check_finished ( self , cr , uid , ids ) :
2010-04-29 13:30:07 +00:00
return self . check_move_done ( cr , uid , ids )
def action_check ( self , cr , uid , ids ) :
2010-05-14 13:24:15 +00:00
""" Checks procurement move state whether assigned or done.
@return : True
2010-04-29 13:30:07 +00:00
"""
ok = False
for procurement in self . browse ( cr , uid , ids ) :
2010-08-31 10:20:45 +00:00
if procurement . move_id and procurement . move_id . state == ' assigned ' or procurement . move_id . state == ' done ' :
2010-04-29 13:30:07 +00:00
self . action_done ( cr , uid , [ procurement . id ] )
ok = True
return ok
def action_ready ( self , cr , uid , ids ) :
""" Changes procurement state to Ready.
2010-05-14 13:24:15 +00:00
@return : True
2010-04-29 13:30:07 +00:00
"""
res = self . write ( cr , uid , ids , { ' state ' : ' ready ' } )
2012-04-27 08:54:40 +00:00
self . ready_send_note ( cr , uid , ids , context = None )
2010-04-29 13:30:07 +00:00
return res
def action_done ( self , cr , uid , ids ) :
""" Changes procurement state to Done and writes Closed date.
2010-05-14 13:24:15 +00:00
@return : True
2010-04-29 13:30:07 +00:00
"""
move_obj = self . pool . get ( ' stock.move ' )
for procurement in self . browse ( cr , uid , ids ) :
if procurement . move_id :
if procurement . close_move and ( procurement . move_id . state < > ' done ' ) :
move_obj . action_done ( cr , uid , [ procurement . move_id . id ] )
res = self . write ( cr , uid , ids , { ' state ' : ' done ' , ' date_close ' : time . strftime ( ' % Y- % m- %d ' ) } )
2012-04-27 08:54:40 +00:00
self . done_send_note ( cr , uid , ids , context = None )
2010-04-29 13:30:07 +00:00
wf_service = netsvc . LocalService ( " workflow " )
for id in ids :
2010-05-27 12:47:06 +00:00
wf_service . trg_trigger ( uid , ' procurement.order ' , id , cr )
2010-04-29 13:30:07 +00:00
return res
2012-04-20 10:29:12 +00:00
# ----------------------------------------
# OpenChatter methods and notifications
# ----------------------------------------
def create ( self , cr , uid , vals , context = None ) :
obj_id = super ( procurement_order , self ) . create ( cr , uid , vals , context )
2012-04-27 08:54:40 +00:00
self . create_send_note ( cr , uid , [ obj_id ] , context = context )
2012-04-20 10:29:12 +00:00
return obj_id
2012-04-27 08:54:40 +00:00
def create_send_note ( self , cr , uid , ids , context = None ) :
2012-05-15 05:25:22 +00:00
self . message_append_note ( cr , uid , ids , body = _ ( " Procurement has been <b>created</b>. " ) , context = context )
2012-04-20 10:29:12 +00:00
2012-04-27 08:54:40 +00:00
def confirm_send_note ( self , cr , uid , ids , context = None ) :
2012-05-15 05:25:22 +00:00
self . message_append_note ( cr , uid , ids , body = _ ( " Procurement has been <b>confirmed</b>. " ) , context = context )
2012-04-27 08:54:40 +00:00
def running_send_note ( self , cr , uid , ids , context = None ) :
2012-05-15 05:25:22 +00:00
self . message_append_note ( cr , uid , ids , body = _ ( " Procurement has been set to <b>running</b>. " ) , context = context )
2012-04-27 08:54:40 +00:00
def ready_send_note ( self , cr , uid , ids , context = None ) :
2012-05-15 06:11:11 +00:00
self . message_append_note ( cr , uid , ids , body = _ ( " Procurement has been set to <b>ready</b>. " ) , context = context )
2012-04-27 08:54:40 +00:00
def cancel_send_note ( self , cr , uid , ids , context = None ) :
2012-05-15 05:25:22 +00:00
self . message_append_note ( cr , uid , ids , body = _ ( " Procurement has been <b>cancelled</b>. " ) , context = context )
2012-04-27 08:54:40 +00:00
def done_send_note ( self , cr , uid , ids , context = None ) :
2012-05-15 05:25:22 +00:00
self . message_append_note ( cr , uid , ids , body = _ ( " Procurement has been <b>done</b>. " ) , context = context )
2012-04-20 10:29:12 +00:00
2010-05-27 12:47:06 +00:00
procurement_order ( )
2010-04-29 13:30:07 +00:00
2010-09-01 09:13:08 +00:00
class StockPicking ( osv . osv ) :
_inherit = ' stock.picking '
2010-09-15 11:58:12 +00:00
def test_finished ( self , cursor , user , ids ) :
2010-09-01 09:13:08 +00:00
wf_service = netsvc . LocalService ( " workflow " )
2010-09-15 11:58:12 +00:00
res = super ( StockPicking , self ) . test_finished ( cursor , user , ids )
2010-09-01 09:13:08 +00:00
for picking in self . browse ( cursor , user , ids ) :
for move in picking . move_lines :
if move . state == ' done ' and move . procurements :
for procurement in move . procurements :
wf_service . trg_validate ( user , ' procurement.order ' ,
2011-12-16 09:58:11 +00:00
procurement . id , ' button_check ' , cursor )
2010-09-01 09:13:08 +00:00
return res
2010-11-15 09:36:28 +00:00
2010-09-01 09:13:08 +00:00
StockPicking ( )
2010-04-29 13:30:07 +00:00
class stock_warehouse_orderpoint ( osv . osv ) :
"""
Defines Minimum stock rules .
"""
_name = " stock.warehouse.orderpoint "
2010-05-27 12:47:06 +00:00
_description = " Minimum Inventory Rule "
2010-08-10 11:35:06 +00:00
2010-12-07 10:48:11 +00:00
def _get_draft_procurements ( self , cr , uid , ids , field_name , arg , context = None ) :
2010-11-24 12:33:32 +00:00
if context is None :
context = { }
result = { }
procurement_obj = self . pool . get ( ' procurement.order ' )
2010-12-07 10:48:11 +00:00
for orderpoint in self . browse ( cr , uid , ids , context = context ) :
procurement_ids = procurement_obj . search ( cr , uid , [ ( ' state ' , ' = ' , ' draft ' ) , ( ' product_id ' , ' = ' , orderpoint . product_id . id ) , ( ' location_id ' , ' = ' , orderpoint . location_id . id ) ] )
result [ orderpoint . id ] = procurement_ids
2010-11-24 12:33:32 +00:00
return result
2010-04-29 13:30:07 +00:00
_columns = {
' name ' : fields . char ( ' Name ' , size = 32 , required = True ) ,
2010-11-15 13:15:55 +00:00
' active ' : fields . boolean ( ' Active ' , help = " If the active field is set to False, it will allow you to hide the orderpoint without removing it. " ) ,
2010-04-29 13:30:07 +00:00
' logic ' : fields . selection ( [ ( ' max ' , ' Order to Max ' ) , ( ' price ' , ' Best price (not yet active!) ' ) ] , ' Reordering Mode ' , required = True ) ,
2010-05-27 12:47:06 +00:00
' warehouse_id ' : fields . many2one ( ' stock.warehouse ' , ' Warehouse ' , required = True , ondelete = " cascade " ) ,
' location_id ' : fields . many2one ( ' stock.location ' , ' Location ' , required = True , ondelete = " cascade " ) ,
2010-04-30 06:01:15 +00:00
' product_id ' : fields . many2one ( ' product.product ' , ' Product ' , required = True , ondelete = ' cascade ' , domain = [ ( ' type ' , ' = ' , ' product ' ) ] ) ,
2012-04-25 11:29:50 +00:00
' product_uom ' : fields . many2one ( ' product.uom ' , ' Product Unit of Measure ' , required = True ) ,
2012-06-11 09:59:14 +00:00
' product_min_qty ' : fields . float ( ' Minimum Quantity ' , required = True ,
2011-04-20 06:13:48 +00:00
help = " When the virtual stock goes below the Min Quantity specified for this field, OpenERP generates " \
2010-04-29 13:30:07 +00:00
" a procurement to bring the virtual stock to the Max Quantity. " ) ,
2012-06-11 09:59:14 +00:00
' product_max_qty ' : fields . float ( ' Maximum Quantity ' , required = True ,
2011-04-20 06:13:48 +00:00
help = " When the virtual stock goes below the Min Quantity, OpenERP generates " \
" a procurement to bring the virtual stock to the Quantity specified as Max Quantity. " ) ,
2010-04-29 13:30:07 +00:00
' qty_multiple ' : fields . integer ( ' Qty Multiple ' , required = True ,
2011-04-15 08:43:11 +00:00
help = " The procurement quantity will be rounded up to this multiple. " ) ,
2010-05-27 12:47:06 +00:00
' procurement_id ' : fields . many2one ( ' procurement.order ' , ' Latest procurement ' , ondelete = " set null " ) ,
2010-04-29 13:30:07 +00:00
' company_id ' : fields . many2one ( ' res.company ' , ' Company ' , required = True ) ,
2011-07-01 23:41:24 +00:00
' procurement_draft_ids ' : fields . function ( _get_draft_procurements , type = ' many2many ' , relation = " procurement.order " , \
2010-11-24 12:33:32 +00:00
string = " Related Procurement Orders " , help = " Draft procurement of the product and location of that orderpoint " ) ,
2010-04-29 13:30:07 +00:00
}
_defaults = {
' active ' : lambda * a : 1 ,
' logic ' : lambda * a : ' max ' ,
' qty_multiple ' : lambda * a : 1 ,
2010-05-28 10:44:30 +00:00
' name ' : lambda x , y , z , c : x . pool . get ( ' ir.sequence ' ) . get ( y , z , ' stock.orderpoint ' ) or ' ' ,
2010-04-29 13:30:07 +00:00
' product_uom ' : lambda sel , cr , uid , context : context . get ( ' product_uom ' , False ) ,
' company_id ' : lambda self , cr , uid , c : self . pool . get ( ' res.company ' ) . _company_default_get ( cr , uid , ' stock.warehouse.orderpoint ' , context = c )
}
2010-05-27 12:47:06 +00:00
_sql_constraints = [
2010-12-15 16:03:04 +00:00
( ' qty_multiple_check ' , ' CHECK( qty_multiple > 0 ) ' , ' Qty Multiple must be greater than zero. ' ) ,
2010-08-10 11:35:06 +00:00
]
2012-05-14 14:40:41 +00:00
def default_get ( self , cr , uid , fields , context = None ) :
res = super ( stock_warehouse_orderpoint , self ) . default_get ( cr , uid , fields , context )
# default 'warehouse_id' and 'location_id'
if ' warehouse_id ' not in res :
warehouse = self . pool . get ( ' ir.model.data ' ) . get_object ( cr , uid , ' stock ' , ' warehouse0 ' , context )
res [ ' warehouse_id ' ] = warehouse . id
if ' location_id ' not in res :
warehouse = self . pool . get ( ' stock.warehouse ' ) . browse ( cr , uid , res [ ' warehouse_id ' ] , context )
res [ ' location_id ' ] = warehouse . lot_stock_id . id
return res
2010-11-19 13:48:01 +00:00
def onchange_warehouse_id ( self , cr , uid , ids , warehouse_id , context = None ) :
2010-04-29 13:30:07 +00:00
""" Finds location id for changed warehouse.
@param warehouse_id : Changed id of warehouse .
@return : Dictionary of values .
"""
if warehouse_id :
2010-11-22 10:37:53 +00:00
w = self . pool . get ( ' stock.warehouse ' ) . browse ( cr , uid , warehouse_id , context = context )
2010-04-29 13:30:07 +00:00
v = { ' location_id ' : w . lot_stock_id . id }
return { ' value ' : v }
return { }
2010-11-15 09:36:28 +00:00
2010-11-19 13:48:01 +00:00
def onchange_product_id ( self , cr , uid , ids , product_id , context = None ) :
2010-04-29 13:30:07 +00:00
""" Finds UoM for changed product.
@param product_id : Changed id of product .
@return : Dictionary of values .
"""
if product_id :
2010-11-19 13:48:01 +00:00
prod = self . pool . get ( ' product.product ' ) . browse ( cr , uid , product_id , context = context )
2010-04-29 13:30:07 +00:00
v = { ' product_uom ' : prod . uom_id . id }
return { ' value ' : v }
return { }
2012-08-07 10:23:26 +00:00
2010-11-19 13:48:01 +00:00
def copy ( self , cr , uid , id , default = None , context = None ) :
2010-04-29 13:30:07 +00:00
if not default :
default = { }
default . update ( {
2010-05-28 10:44:30 +00:00
' name ' : self . pool . get ( ' ir.sequence ' ) . get ( cr , uid , ' stock.orderpoint ' ) or ' ' ,
2010-04-29 13:30:07 +00:00
} )
2010-11-22 10:37:53 +00:00
return super ( stock_warehouse_orderpoint , self ) . copy ( cr , uid , id , default , context = context )
2012-08-07 10:23:26 +00:00
2010-04-29 13:30:07 +00:00
stock_warehouse_orderpoint ( )
2012-01-04 06:38:07 +00:00
class product_product ( osv . osv ) :
_inherit = " product.product "
_columns = {
2012-05-14 08:36:57 +00:00
' orderpoint_ids ' : fields . one2many ( ' stock.warehouse.orderpoint ' , ' product_id ' , ' Minimum Stock Rules ' ) ,
2012-01-04 06:38:07 +00:00
}
2012-05-14 08:36:57 +00:00
2012-01-04 06:38:07 +00:00
product_product ( )
2010-04-29 13:30:07 +00:00
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4: