2009-10-13 05:58:37 +00:00
# -*- coding: utf-8 -*-
2006-12-07 13:41:40 +00:00
##############################################################################
2009-11-25 09:31:44 +00:00
#
2009-01-19 13:59:11 +00:00
# OpenERP, Open Source Management Solution
2010-01-12 09:18:39 +00:00
# Copyright (C) 2004-2010 Tiny SPRL (<http://tiny.be>).
2008-06-16 11:00:21 +00:00
#
2008-11-03 19:18:56 +00:00
# This program is free software: you can redistribute it and/or modify
2009-10-14 11:15:34 +00:00
# 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.
2006-12-07 13:41:40 +00:00
#
2008-11-03 19:18:56 +00:00
# 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
2009-10-14 11:15:34 +00:00
# GNU Affero General Public License for more details.
2006-12-07 13:41:40 +00:00
#
2009-10-14 11:15:34 +00:00
# You should have received a copy of the GNU Affero General Public License
2009-11-25 09:31:44 +00:00
# along with this program. If not, see <http://www.gnu.org/licenses/>.
2006-12-07 13:41:40 +00:00
#
##############################################################################
2010-04-29 13:30:07 +00:00
from mx import DateTime
2006-12-07 13:41:40 +00:00
import time
2010-03-01 05:13:20 +00:00
from datetime import datetime
from dateutil . relativedelta import relativedelta
2010-06-23 07:23:38 +00:00
from osv import osv , fields
import netsvc
import ir
2006-12-07 13:41:40 +00:00
import pooler
2006-12-28 09:44:56 +00:00
from tools import config
2008-07-08 08:13:12 +00:00
from tools . translate import _
2010-03-06 20:52:19 +00:00
import decimal_precision as dp
2010-03-25 08:25:11 +00:00
from osv . orm import browse_record , browse_null
2010-03-06 20:52:19 +00:00
2006-12-07 13:41:40 +00:00
#
# Model definition
#
class purchase_order ( osv . osv ) :
2008-07-22 15:11:28 +00:00
def _calc_amount ( self , cr , uid , ids , prop , unknow_none , unknow_dict ) :
res = { }
for order in self . browse ( cr , uid , ids ) :
res [ order . id ] = 0
for oline in order . order_line :
res [ order . id ] + = oline . price_unit * oline . product_qty
return res
2010-06-17 07:10:42 +00:00
def _amount_all ( self , cr , uid , ids , field_name , arg , context = None ) :
2008-07-22 15:11:28 +00:00
res = { }
cur_obj = self . pool . get ( ' res.currency ' )
for order in self . browse ( cr , uid , ids ) :
2008-12-24 15:50:06 +00:00
res [ order . id ] = {
' amount_untaxed ' : 0.0 ,
' amount_tax ' : 0.0 ,
' amount_total ' : 0.0 ,
2010-06-17 07:10:42 +00:00
}
2008-12-24 15:50:06 +00:00
val = val1 = 0.0
2010-06-17 07:10:42 +00:00
cur = order . pricelist_id . currency_id
2008-07-22 15:11:28 +00:00
for line in order . order_line :
2010-06-17 07:10:42 +00:00
val1 + = line . price_subtotal
2010-06-14 11:09:51 +00:00
for c in self . pool . get ( ' account.tax ' ) . compute_all ( cr , uid , line . taxes_id , line . price_unit , line . product_qty , order . partner_address_id . id , line . product_id . id , order . partner_id ) [ ' taxes ' ] :
2010-06-17 07:10:42 +00:00
val + = c [ ' amount ' ]
2008-12-24 15:50:06 +00:00
res [ order . id ] [ ' amount_tax ' ] = cur_obj . round ( cr , uid , cur , val )
res [ order . id ] [ ' amount_untaxed ' ] = cur_obj . round ( cr , uid , cur , val1 )
res [ order . id ] [ ' amount_total ' ] = res [ order . id ] [ ' amount_untaxed ' ] + res [ order . id ] [ ' amount_tax ' ]
2008-07-22 15:11:28 +00:00
return res
2010-06-23 07:23:38 +00:00
def _set_minimum_planned_date ( self , cr , uid , ids , name , value , arg , context = None ) :
2008-09-17 07:55:45 +00:00
if not value : return False
if type ( ids ) != type ( [ ] ) :
ids = [ ids ]
for po in self . browse ( cr , uid , ids , context ) :
cr . execute ( """ update purchase_order_line set
date_planned = % s
where
2008-12-10 14:29:55 +00:00
order_id = % s and
2008-09-17 07:55:45 +00:00
( date_planned = % s or date_planned < % s ) """ , (value,po.id,po.minimum_planned_date,value))
return True
2010-06-23 07:23:38 +00:00
def _minimum_planned_date ( self , cr , uid , ids , field_name , arg , context = None ) :
2008-08-30 09:14:15 +00:00
res = { }
purchase_obj = self . browse ( cr , uid , ids , context = context )
for purchase in purchase_obj :
2008-09-03 15:36:31 +00:00
res [ purchase . id ] = False
2008-08-30 09:14:15 +00:00
if purchase . order_line :
min_date = purchase . order_line [ 0 ] . date_planned
for line in purchase . order_line :
if line . date_planned < min_date :
min_date = line . date_planned
res [ purchase . id ] = min_date
return res
2008-08-27 11:26:37 +00:00
def _invoiced_rate ( self , cursor , user , ids , name , arg , context = None ) :
res = { }
for purchase in self . browse ( cursor , user , ids , context = context ) :
tot = 0.0
2008-08-28 23:48:43 +00:00
if purchase . invoice_id and purchase . invoice_id . state not in ( ' draft ' , ' cancel ' ) :
2008-08-27 11:26:37 +00:00
tot + = purchase . invoice_id . amount_untaxed
2008-08-28 23:48:43 +00:00
if purchase . amount_untaxed :
2008-08-27 11:26:37 +00:00
res [ purchase . id ] = tot * 100.0 / purchase . amount_untaxed
else :
res [ purchase . id ] = 0.0
return res
def _shipped_rate ( self , cr , uid , ids , name , arg , context = None ) :
if not ids : return { }
res = { }
for id in ids :
res [ id ] = [ 0.0 , 0.0 ]
cr . execute ( ''' SELECT
p . purchase_id , sum ( m . product_qty ) , m . state
FROM
stock_move m
LEFT JOIN
stock_picking p on ( p . id = m . picking_id )
WHERE
2010-06-10 13:34:19 +00:00
p . purchase_id IN % s GROUP BY m . state , p . purchase_id ''' ,(tuple(ids),))
2008-08-27 11:26:37 +00:00
for oid , nbr , state in cr . fetchall ( ) :
if state == ' cancel ' :
continue
if state == ' done ' :
res [ oid ] [ 0 ] + = nbr or 0.0
res [ oid ] [ 1 ] + = nbr or 0.0
else :
res [ oid ] [ 1 ] + = nbr or 0.0
for r in res :
if not res [ r ] [ 1 ] :
res [ r ] = 0.0
else :
res [ r ] = 100.0 * res [ r ] [ 0 ] / res [ r ] [ 1 ]
return res
2010-06-23 07:23:38 +00:00
def _get_order ( self , cr , uid , ids , context = None ) :
2008-12-24 15:50:06 +00:00
result = { }
for line in self . pool . get ( ' purchase.order.line ' ) . browse ( cr , uid , ids , context = context ) :
result [ line . order_id . id ] = True
return result . keys ( )
2009-05-05 11:00:23 +00:00
def _invoiced ( self , cursor , user , ids , name , arg , context = None ) :
res = { }
for purchase in self . browse ( cursor , user , ids , context = context ) :
if purchase . invoice_id . reconciled :
res [ purchase . id ] = purchase . invoice_id . reconciled
else :
res [ purchase . id ] = False
return res
2008-07-22 15:11:28 +00:00
_columns = {
2010-06-21 13:59:11 +00:00
' name ' : fields . char ( ' Order Reference ' , size = 64 , required = True , select = True , help = " unique number of the purchase order,computed automatically when the purchase order is created " ) ,
2010-02-09 08:31:46 +00:00
' origin ' : fields . char ( ' Source Document ' , size = 64 ,
2008-09-22 08:14:07 +00:00
help = " Reference of the document that generated this purchase order request. "
) ,
2010-06-21 21:20:55 +00:00
' partner_ref ' : fields . char ( ' Supplier Reference ' , states = { ' confirmed ' : [ ( ' readonly ' , True ) ] , ' approved ' : [ ( ' readonly ' , True ) ] , ' done ' : [ ( ' readonly ' , True ) ] } , size = 64 ) ,
2009-09-24 10:46:21 +00:00
' date_order ' : fields . date ( ' Date Ordered ' , required = True , states = { ' confirmed ' : [ ( ' readonly ' , True ) ] , ' approved ' : [ ( ' readonly ' , True ) ] } , help = " Date on which this document has been created. " ) ,
2010-06-21 13:59:11 +00:00
' date_approve ' : fields . date ( ' Date Approved ' , readonly = 1 , help = " Date on which purchase order has been approved " ) ,
2009-12-03 14:56:23 +00:00
' partner_id ' : fields . many2one ( ' res.partner ' , ' Supplier ' , required = True , states = { ' confirmed ' : [ ( ' readonly ' , True ) ] , ' approved ' : [ ( ' readonly ' , True ) ] , ' done ' : [ ( ' readonly ' , True ) ] } , change_default = True ) ,
2010-06-21 21:20:55 +00:00
' partner_address_id ' : fields . many2one ( ' res.partner.address ' , ' Address ' , required = True ,
2010-07-01 05:27:08 +00:00
states = { ' confirmed ' : [ ( ' readonly ' , True ) ] , ' approved ' : [ ( ' readonly ' , True ) ] , ' done ' : [ ( ' readonly ' , True ) ] } , domain = " [( ' partner_id ' , ' = ' , partner_id)] " ) ,
2010-06-21 21:20:55 +00:00
' dest_address_id ' : fields . many2one ( ' res.partner.address ' , ' Destination Address ' ,
states = { ' confirmed ' : [ ( ' readonly ' , True ) ] , ' approved ' : [ ( ' readonly ' , True ) ] , ' done ' : [ ( ' readonly ' , True ) ] } ,
2008-09-22 08:14:07 +00:00
help = " Put an address if you want to deliver directly from the supplier to the customer. " \
" In this case, it will remove the warehouse link and set the customer location. "
) ,
2010-06-21 21:20:55 +00:00
' warehouse_id ' : fields . many2one ( ' stock.warehouse ' , ' Warehouse ' , states = { ' confirmed ' : [ ( ' readonly ' , True ) ] , ' approved ' : [ ( ' readonly ' , True ) ] , ' done ' : [ ( ' readonly ' , True ) ] } ) ,
2010-05-10 13:54:26 +00:00
' location_id ' : fields . many2one ( ' stock.location ' , ' Destination ' , required = True , domain = [ ( ' usage ' , ' <> ' , ' view ' ) ] ) ,
2009-12-03 14:56:23 +00:00
' pricelist_id ' : fields . many2one ( ' product.pricelist ' , ' Pricelist ' , required = True , states = { ' confirmed ' : [ ( ' readonly ' , True ) ] , ' approved ' : [ ( ' readonly ' , True ) ] , ' done ' : [ ( ' readonly ' , True ) ] } , help = " The pricelist sets the currency used for this purchase order. It also computes the supplier price for the selected products/quantities. " ) ,
2009-12-21 09:50:54 +00:00
' state ' : fields . selection ( [ ( ' draft ' , ' Request for Quotation ' ) , ( ' wait ' , ' Waiting ' ) , ( ' confirmed ' , ' Waiting Supplier Ack ' ) , ( ' approved ' , ' Approved ' ) , ( ' except_picking ' , ' Shipping Exception ' ) , ( ' except_invoice ' , ' Invoice Exception ' ) , ( ' done ' , ' Done ' ) , ( ' cancel ' , ' Cancelled ' ) ] , ' State ' , readonly = True , help = " The state of the purchase order or the quotation request. A quotation is a purchase order in a ' Draft ' state. Then the order has to be confirmed by the user, the state switch to ' Confirmed ' . Then the supplier must confirm the order to change the state to ' Approved ' . When the purchase order is paid and received, the state becomes ' Done ' . If a cancel action occurs in the invoice or in the reception of goods, the state becomes in exception. " , select = True ) ,
2009-12-03 14:56:23 +00:00
' order_line ' : fields . one2many ( ' purchase.order.line ' , ' order_id ' , ' Order Lines ' , states = { ' approved ' : [ ( ' readonly ' , True ) ] , ' done ' : [ ( ' readonly ' , True ) ] } ) ,
2008-07-22 15:11:28 +00:00
' validator ' : fields . many2one ( ' res.users ' , ' Validated by ' , readonly = True ) ,
2010-06-12 18:32:16 +00:00
' notes ' : fields . text ( ' Notes ' ) ,
2010-06-21 13:59:11 +00:00
' invoice_id ' : fields . many2one ( ' account.invoice ' , ' Invoice ' , readonly = True , help = " An invoice generated for a purchase order " ) ,
2008-07-22 15:11:28 +00:00
' picking_ids ' : fields . one2many ( ' stock.picking ' , ' purchase_id ' , ' Picking List ' , readonly = True , help = " This is the list of picking list that have been generated for this purchase " ) ,
2010-06-21 13:59:11 +00:00
' shipped ' : fields . boolean ( ' Received ' , readonly = True , select = True , help = " It indicates that a picking has been done " ) ,
2010-06-13 15:53:05 +00:00
' shipped_rate ' : fields . function ( _shipped_rate , method = True , string = ' Received ' , type = ' float ' ) ,
2010-06-21 13:59:11 +00:00
' invoiced ' : fields . function ( _invoiced , method = True , string = ' Invoiced & Paid ' , type = ' boolean ' , help = " It indicates that an invoice has been paid " ) ,
2010-06-13 15:53:05 +00:00
' invoiced_rate ' : fields . function ( _invoiced_rate , method = True , string = ' Invoiced ' , type = ' float ' ) ,
2008-09-22 08:14:07 +00:00
' invoice_method ' : fields . selection ( [ ( ' manual ' , ' Manual ' ) , ( ' order ' , ' From Order ' ) , ( ' picking ' , ' From Picking ' ) ] , ' Invoicing Control ' , required = True ,
help = " From Order: a draft invoice will be pre-generated based on the purchase order. The accountant " \
" will just have to validate this invoice for control. \n " \
2009-12-21 09:50:54 +00:00
" From Picking: a draft invoice will be pre-generated based on validated receptions. \n " \
2008-09-22 08:14:07 +00:00
" Manual: no invoice will be pre-generated. The accountant will have to encode manually. "
) ,
2010-06-21 21:20:55 +00:00
' minimum_planned_date ' : fields . function ( _minimum_planned_date , fnct_inv = _set_minimum_planned_date , method = True , store = True , string = ' Expected Date ' , type = ' date ' , help = " This is computed as the minimum scheduled date of all purchase order lines ' products. " ) ,
2010-03-06 20:52:19 +00:00
' amount_untaxed ' : fields . function ( _amount_all , method = True , digits_compute = dp . get_precision ( ' Purchase Price ' ) , string = ' Untaxed Amount ' ,
2008-12-24 15:50:06 +00:00
store = {
' purchase.order.line ' : ( _get_order , None , 10 ) ,
2010-06-21 13:59:11 +00:00
} , multi = " sums " , help = " The amount without tax " ) ,
2010-03-06 20:52:19 +00:00
' amount_tax ' : fields . function ( _amount_all , method = True , digits_compute = dp . get_precision ( ' Purchase Price ' ) , string = ' Taxes ' ,
2008-12-24 15:50:06 +00:00
store = {
' purchase.order.line ' : ( _get_order , None , 10 ) ,
2010-06-21 13:59:11 +00:00
} , multi = " sums " , help = " The tax amount " ) ,
2010-03-06 20:52:19 +00:00
' amount_total ' : fields . function ( _amount_all , method = True , digits_compute = dp . get_precision ( ' Purchase Price ' ) , string = ' Total ' ,
2008-12-24 15:50:06 +00:00
store = {
' purchase.order.line ' : ( _get_order , None , 10 ) ,
2010-06-21 13:59:11 +00:00
} , multi = " sums " , help = " The total amount " ) ,
2009-10-30 12:22:28 +00:00
' fiscal_position ' : fields . many2one ( ' account.fiscal.position ' , ' Fiscal Position ' ) ,
' product_id ' : fields . related ( ' order_line ' , ' product_id ' , type = ' many2one ' , relation = ' product.product ' , string = ' Product ' ) ,
2009-11-25 09:31:44 +00:00
' create_uid ' : fields . many2one ( ' res.users ' , ' Responsible ' ) ,
2009-12-22 19:07:37 +00:00
' company_id ' : fields . many2one ( ' res.company ' , ' Company ' , required = True , select = 1 ) ,
2008-07-22 15:11:28 +00:00
}
_defaults = {
2010-06-23 07:23:38 +00:00
' date_order ' : time . strftime ( ' % Y- % m- %d ' ) ,
' state ' : ' draft ' ,
2008-07-22 15:11:28 +00:00
' name ' : lambda obj , cr , uid , context : obj . pool . get ( ' ir.sequence ' ) . get ( cr , uid , ' purchase.order ' ) ,
2010-06-23 07:23:38 +00:00
' shipped ' : 0 ,
' invoice_method ' : ' order ' ,
' invoiced ' : 0 ,
2008-07-22 15:11:28 +00:00
' partner_address_id ' : lambda self , cr , uid , context : context . get ( ' partner_id ' , False ) and self . pool . get ( ' res.partner ' ) . address_get ( cr , uid , [ context [ ' partner_id ' ] ] , [ ' default ' ] ) [ ' default ' ] ,
' pricelist_id ' : lambda self , cr , uid , context : context . get ( ' partner_id ' , False ) and self . pool . get ( ' res.partner ' ) . browse ( cr , uid , context [ ' partner_id ' ] ) . property_product_pricelist_purchase . id ,
2009-12-23 17:16:39 +00:00
' company_id ' : lambda self , cr , uid , c : self . pool . get ( ' res.company ' ) . _company_default_get ( cr , uid , ' purchase.order ' , context = c ) ,
2008-07-22 15:11:28 +00:00
}
_name = " purchase.order "
2010-05-19 18:32:32 +00:00
_description = " Purchase Order "
2008-07-22 15:11:28 +00:00
_order = " name desc "
2009-01-19 13:59:11 +00:00
2009-01-20 11:29:21 +00:00
def unlink ( self , cr , uid , ids , context = None ) :
2008-10-06 10:56:20 +00:00
purchase_orders = self . read ( cr , uid , ids , [ ' state ' ] )
unlink_ids = [ ]
for s in purchase_orders :
if s [ ' state ' ] in [ ' draft ' , ' cancel ' ] :
unlink_ids . append ( s [ ' id ' ] )
else :
raise osv . except_osv ( _ ( ' Invalid action ! ' ) , _ ( ' Cannot delete Purchase Order(s) which are in %s State! ' % s [ ' state ' ] ) )
2010-02-02 21:37:52 +00:00
2010-05-28 09:48:40 +00:00
# TODO: temporary fix in 5.0, to remove in 5.2 when subflows support
2010-02-02 21:37:52 +00:00
# automatically sending subflow.delete upon deletion
wf_service = netsvc . LocalService ( " workflow " )
for id in unlink_ids :
wf_service . trg_validate ( uid , ' purchase.order ' , id , ' purchase_cancel ' , cr )
2009-01-20 11:29:21 +00:00
return super ( purchase_order , self ) . unlink ( cr , uid , unlink_ids , context = context )
2009-01-19 13:59:11 +00:00
2008-07-22 15:11:28 +00:00
def button_dummy ( self , cr , uid , ids , context = { } ) :
return True
def onchange_dest_address_id ( self , cr , uid , ids , adr_id ) :
if not adr_id :
return { }
part_id = self . pool . get ( ' res.partner.address ' ) . read ( cr , uid , [ adr_id ] , [ ' partner_id ' ] ) [ 0 ] [ ' partner_id ' ] [ 0 ]
loc_id = self . pool . get ( ' res.partner ' ) . browse ( cr , uid , part_id ) . property_stock_customer . id
return { ' value ' : { ' location_id ' : loc_id , ' warehouse_id ' : False } }
def onchange_warehouse_id ( self , cr , uid , ids , warehouse_id ) :
if not warehouse_id :
return { }
res = self . pool . get ( ' stock.warehouse ' ) . read ( cr , uid , [ warehouse_id ] , [ ' lot_input_id ' ] ) [ 0 ] [ ' lot_input_id ' ] [ 0 ]
return { ' value ' : { ' location_id ' : res , ' dest_address_id ' : False } }
def onchange_partner_id ( self , cr , uid , ids , part ) :
2010-05-28 09:48:40 +00:00
2008-07-22 15:11:28 +00:00
if not part :
2009-01-19 13:59:11 +00:00
return { ' value ' : { ' partner_address_id ' : False , ' fiscal_position ' : False } }
2008-07-22 15:11:28 +00:00
addr = self . pool . get ( ' res.partner ' ) . address_get ( cr , uid , [ part ] , [ ' default ' ] )
2008-10-20 20:49:11 +00:00
part = self . pool . get ( ' res.partner ' ) . browse ( cr , uid , part )
pricelist = part . property_product_pricelist_purchase . id
2009-01-19 13:59:11 +00:00
fiscal_position = part . property_account_position and part . property_account_position . id or False
return { ' value ' : { ' partner_address_id ' : addr [ ' default ' ] , ' pricelist_id ' : pricelist , ' fiscal_position ' : fiscal_position } }
2008-07-22 15:11:28 +00:00
2008-10-08 14:26:04 +00:00
def wkf_approve_order ( self , cr , uid , ids , context = { } ) :
2008-07-22 15:11:28 +00:00
self . write ( cr , uid , ids , { ' state ' : ' approved ' , ' date_approve ' : time . strftime ( ' % Y- % m- %d ' ) } )
2010-06-15 04:28:11 +00:00
for ( id , name ) in self . name_get ( cr , uid , ids ) :
message = _ ( ' Purchase order ' ) + " ' " + name + " ' " + _ ( " is approved by the supplier " )
self . log ( cr , uid , id , message )
2008-07-22 15:11:28 +00:00
return True
2010-05-27 07:08:59 +00:00
#TODO: implement messages system
2008-07-22 15:11:28 +00:00
def wkf_confirm_order ( self , cr , uid , ids , context = { } ) :
2010-06-15 07:20:15 +00:00
product = [ ]
2010-04-13 10:28:22 +00:00
todo = [ ]
2008-07-22 15:11:28 +00:00
for po in self . browse ( cr , uid , ids ) :
2010-02-05 12:19:25 +00:00
if not po . order_line :
raise osv . except_osv ( _ ( ' Error ! ' ) , _ ( ' You can not confirm purchase order without Purchase Order Lines. ' ) )
2010-05-28 09:48:40 +00:00
for line in po . order_line :
2010-04-13 10:28:22 +00:00
if line . state == ' draft ' :
2010-05-28 09:48:40 +00:00
todo . append ( line . id )
2008-07-22 15:11:28 +00:00
current_name = self . name_get ( cr , uid , ids ) [ 0 ] [ 1 ]
2010-04-13 10:28:22 +00:00
self . pool . get ( ' purchase.order.line ' ) . action_confirm ( cr , uid , todo , context )
2008-07-22 15:11:28 +00:00
for id in ids :
self . write ( cr , uid , [ id ] , { ' state ' : ' confirmed ' , ' validator ' : uid } )
2010-06-15 07:20:15 +00:00
for line in po . order_line :
product . append ( line . product_id . default_code or ' ' )
params = ' , ' . join ( map ( lambda x : str ( x ) , product ) )
2010-06-15 04:28:11 +00:00
message = _ ( ' Purchase order ' ) + " ' " + po . name + " ' " + _ ( ' placed on ' ) + " ' " + po . date_order + " ' " + _ ( ' for ' ) + " ' " + params + " ' " + _ ( " is confirmed " )
2010-06-15 07:20:15 +00:00
self . log ( cr , uid , id , message )
2008-07-22 15:11:28 +00:00
return True
2008-08-27 11:26:37 +00:00
2008-07-22 15:11:28 +00:00
def wkf_warn_buyer ( self , cr , uid , ids ) :
self . write ( cr , uid , ids , { ' state ' : ' wait ' , ' validator ' : uid } )
request = pooler . get_pool ( cr . dbname ) . get ( ' res.request ' )
for po in self . browse ( cr , uid , ids ) :
managers = [ ]
for oline in po . order_line :
manager = oline . product_id . product_manager
if manager and not ( manager . id in managers ) :
managers . append ( manager . id )
for manager_id in managers :
2008-08-27 11:26:37 +00:00
request . create ( cr , uid ,
2008-07-22 15:11:28 +00:00
{ ' name ' : " Purchase amount over the limit " ,
' act_from ' : uid ,
' act_to ' : manager_id ,
' body ' : ' Somebody has just confirmed a purchase with an amount over the defined limit ' ,
' ref_partner_id ' : po . partner_id . id ,
' ref_doc1 ' : ' purchase.order, %d ' % ( po . id , ) ,
} )
2009-07-13 09:47:43 +00:00
def inv_line_create ( self , cr , uid , a , ol ) :
2008-07-22 15:11:28 +00:00
return ( 0 , False , {
2008-10-20 20:49:11 +00:00
' name ' : ol . name ,
' account_id ' : a ,
' price_unit ' : ol . price_unit or 0.0 ,
' quantity ' : ol . product_qty ,
' product_id ' : ol . product_id . id or False ,
' uos_id ' : ol . product_uom . id or False ,
' invoice_line_tax_id ' : [ ( 6 , 0 , [ x . id for x in ol . taxes_id ] ) ] ,
' account_analytic_id ' : ol . account_analytic_id . id ,
} )
2008-07-22 15:11:28 +00:00
2008-10-13 13:08:08 +00:00
def action_cancel_draft ( self , cr , uid , ids , * args ) :
if not len ( ids ) :
return False
self . write ( cr , uid , ids , { ' state ' : ' draft ' , ' shipped ' : 0 } )
wf_service = netsvc . LocalService ( " workflow " )
for p_id in ids :
2010-02-05 11:35:25 +00:00
# Deleting the existing instance of workflow for PO
2010-05-28 09:48:40 +00:00
wf_service . trg_delete ( uid , ' purchase.order ' , p_id , cr )
2008-10-13 13:08:08 +00:00
wf_service . trg_create ( uid , ' purchase.order ' , p_id , cr )
2010-06-15 04:28:11 +00:00
for ( id , name ) in self . name_get ( cr , uid , ids ) :
message = _ ( ' Purchase order ' ) + " ' " + name + " ' " + _ ( " is in the draft state " )
2010-06-15 07:20:15 +00:00
self . log ( cr , uid , id , message )
2008-10-13 13:08:08 +00:00
return True
2008-07-22 15:11:28 +00:00
def action_invoice_create ( self , cr , uid , ids , * args ) :
res = False
2010-05-28 09:48:40 +00:00
2009-01-23 08:18:01 +00:00
journal_obj = self . pool . get ( ' account.journal ' )
2008-07-22 15:11:28 +00:00
for o in self . browse ( cr , uid , ids ) :
il = [ ]
2010-04-13 10:28:22 +00:00
todo = [ ]
2008-07-22 15:11:28 +00:00
for ol in o . order_line :
2010-04-13 10:28:22 +00:00
todo . append ( ol . id )
2008-07-22 15:11:28 +00:00
if ol . product_id :
a = ol . product_id . product_tmpl_id . property_account_expense . id
if not a :
a = ol . product_id . categ_id . property_account_expense_categ . id
if not a :
raise osv . except_osv ( _ ( ' Error ! ' ) , _ ( ' There is no expense account defined for this product: " %s " (id: %d ) ' ) % ( ol . product_id . name , ol . product_id . id , ) )
else :
a = self . pool . get ( ' ir.property ' ) . get ( cr , uid , ' property_account_expense_categ ' , ' product.category ' )
2009-01-20 06:04:07 +00:00
fpos = o . fiscal_position or False
a = self . pool . get ( ' account.fiscal.position ' ) . map_account ( cr , uid , fpos , a )
2009-07-13 09:47:43 +00:00
il . append ( self . inv_line_create ( cr , uid , a , ol ) )
2008-07-22 15:11:28 +00:00
2009-02-11 13:32:54 +00:00
a = o . partner_id . property_account_payable . id
2009-12-02 11:20:06 +00:00
journal_ids = journal_obj . search ( cr , uid , [ ( ' type ' , ' = ' , ' purchase ' ) , ( ' company_id ' , ' = ' , o . company_id . id ) ] , limit = 1 )
if not journal_ids :
raise osv . except_osv ( _ ( ' Error ! ' ) ,
_ ( ' There is no purchase journal defined for this company: " %s " (id: %d ) ' ) % ( o . company_id . name , o . company_id . id ) )
2008-07-22 15:11:28 +00:00
inv = {
' name ' : o . partner_ref or o . name ,
' reference ' : " P %d PO %d " % ( o . partner_id . id , o . id ) ,
' account_id ' : a ,
' type ' : ' in_invoice ' ,
' partner_id ' : o . partner_id . id ,
' currency_id ' : o . pricelist_id . currency_id . id ,
' address_invoice_id ' : o . partner_address_id . id ,
' address_contact_id ' : o . partner_address_id . id ,
2009-01-23 08:18:01 +00:00
' journal_id ' : len ( journal_ids ) and journal_ids [ 0 ] or False ,
2008-07-22 15:11:28 +00:00
' origin ' : o . name ,
' invoice_line ' : il ,
2009-10-03 10:53:53 +00:00
' fiscal_position ' : o . partner_id . property_account_position . id ,
2009-12-01 14:54:18 +00:00
' payment_term ' : o . partner_id . property_payment_term and o . partner_id . property_payment_term . id or False ,
' company_id ' : o . company_id . id ,
2008-07-22 15:11:28 +00:00
}
inv_id = self . pool . get ( ' account.invoice ' ) . create ( cr , uid , inv , { ' type ' : ' in_invoice ' } )
self . pool . get ( ' account.invoice ' ) . button_compute ( cr , uid , [ inv_id ] , { ' type ' : ' in_invoice ' } , set_total = True )
2010-04-13 10:34:06 +00:00
self . pool . get ( ' purchase.order.line ' ) . write ( cr , uid , todo , { ' invoiced ' : True } )
2008-07-22 15:11:28 +00:00
self . write ( cr , uid , [ o . id ] , { ' invoice_id ' : inv_id } )
res = inv_id
return res
def has_stockable_product ( self , cr , uid , ids , * args ) :
for order in self . browse ( cr , uid , ids ) :
for order_line in order . order_line :
if order_line . product_id and order_line . product_id . product_tmpl_id . type in ( ' product ' , ' consu ' ) :
return True
return False
2008-10-13 13:08:08 +00:00
def action_cancel ( self , cr , uid , ids , context = { } ) :
ok = True
purchase_order_line_obj = self . pool . get ( ' purchase.order.line ' )
for purchase in self . browse ( cr , uid , ids ) :
for pick in purchase . picking_ids :
if pick . state not in ( ' draft ' , ' cancel ' ) :
raise osv . except_osv (
_ ( ' Could not cancel purchase order ! ' ) ,
2009-11-25 09:31:44 +00:00
_ ( ' You must first cancel all picking attached to this purchase order. ' ) )
2008-11-06 22:51:39 +00:00
for pick in purchase . picking_ids :
wf_service = netsvc . LocalService ( " workflow " )
wf_service . trg_validate ( uid , ' stock.picking ' , pick . id , ' button_cancel ' , cr )
inv = purchase . invoice_id
if inv and inv . state not in ( ' cancel ' , ' draft ' ) :
raise osv . except_osv (
_ ( ' Could not cancel this purchase order ! ' ) ,
_ ( ' You must first cancel all invoices attached to this purchase order. ' ) )
if inv :
wf_service = netsvc . LocalService ( " workflow " )
wf_service . trg_validate ( uid , ' account.invoice ' , inv . id , ' invoice_cancel ' , cr )
2008-10-13 13:08:08 +00:00
self . write ( cr , uid , ids , { ' state ' : ' cancel ' } )
2010-06-15 04:28:11 +00:00
message = _ ( ' Purchase order ' ) + " ' " + purchase . name + " ' " + _ ( " is cancelled " )
2010-06-15 07:20:15 +00:00
self . log ( cr , uid , id , message )
2008-10-13 13:08:08 +00:00
return True
2008-07-22 15:11:28 +00:00
def action_picking_create ( self , cr , uid , ids , * args ) :
picking_id = False
for order in self . browse ( cr , uid , ids ) :
loc_id = order . partner_id . property_stock_supplier . id
istate = ' none '
if order . invoice_method == ' picking ' :
istate = ' 2binvoiced '
2010-03-12 11:50:12 +00:00
pick_name = self . pool . get ( ' ir.sequence ' ) . get ( cr , uid , ' stock.picking.in ' )
2008-07-22 15:11:28 +00:00
picking_id = self . pool . get ( ' stock.picking ' ) . create ( cr , uid , {
2010-03-12 11:50:12 +00:00
' name ' : pick_name ,
2008-07-22 15:11:28 +00:00
' origin ' : order . name + ( ( order . origin and ( ' : ' + order . origin ) ) or ' ' ) ,
' type ' : ' in ' ,
' address_id ' : order . dest_address_id . id or order . partner_address_id . id ,
' invoice_state ' : istate ,
' purchase_id ' : order . id ,
2009-12-01 14:54:18 +00:00
' company_id ' : order . company_id . id ,
2010-07-09 14:31:07 +00:00
' move_lines ' : [ ] ,
2008-07-22 15:11:28 +00:00
} )
2010-05-12 06:31:47 +00:00
todo_moves = [ ]
2008-07-22 15:11:28 +00:00
for order_line in order . order_line :
if not order_line . product_id :
continue
if order_line . product_id . product_tmpl_id . type in ( ' product ' , ' consu ' ) :
dest = order . location_id . id
2009-12-08 08:27:33 +00:00
move = self . pool . get ( ' stock.move ' ) . create ( cr , uid , {
2008-07-22 15:11:28 +00:00
' name ' : ' PO: ' + order_line . name ,
' product_id ' : order_line . product_id . id ,
' product_qty ' : order_line . product_qty ,
' product_uos_qty ' : order_line . product_qty ,
' product_uom ' : order_line . product_uom . id ,
' product_uos ' : order_line . product_uom . id ,
' date_planned ' : order_line . date_planned ,
2010-06-13 15:53:05 +00:00
' date_expected ' : order_line . date_planned ,
2008-07-22 15:11:28 +00:00
' location_id ' : loc_id ,
' location_dest_id ' : dest ,
' picking_id ' : picking_id ,
' move_dest_id ' : order_line . move_dest_id . id ,
2009-12-08 08:27:33 +00:00
' state ' : ' draft ' ,
2008-07-22 15:11:28 +00:00
' purchase_line_id ' : order_line . id ,
2009-12-01 14:54:18 +00:00
' company_id ' : order . company_id . id ,
2008-07-22 15:11:28 +00:00
} )
if order_line . move_dest_id :
self . pool . get ( ' stock.move ' ) . write ( cr , uid , [ order_line . move_dest_id . id ] , { ' location_id ' : order . location_id . id } )
2010-05-28 09:48:40 +00:00
todo_moves . append ( move )
2010-05-12 06:31:47 +00:00
self . pool . get ( ' stock.move ' ) . action_confirm ( cr , uid , todo_moves )
self . pool . get ( ' stock.move ' ) . force_assign ( cr , uid , todo_moves )
2008-07-22 15:11:28 +00:00
wf_service = netsvc . LocalService ( " workflow " )
wf_service . trg_validate ( uid , ' stock.picking ' , picking_id , ' button_confirm ' , cr )
return picking_id
2009-12-01 14:54:18 +00:00
2008-07-22 15:11:28 +00:00
def copy ( self , cr , uid , id , default = None , context = { } ) :
if not default :
default = { }
default . update ( {
' state ' : ' draft ' ,
' shipped ' : False ,
' invoiced ' : False ,
' invoice_id ' : False ,
' picking_ids ' : [ ] ,
' name ' : self . pool . get ( ' ir.sequence ' ) . get ( cr , uid , ' purchase.order ' ) ,
} )
return super ( purchase_order , self ) . copy ( cr , uid , id , default , context )
2006-12-07 13:41:40 +00:00
2010-03-25 08:25:11 +00:00
def do_merge ( self , cr , uid , ids , context ) :
2010-05-28 09:48:40 +00:00
"""
To merge similar type of purchase orders .
Orders will only be merged if :
* Purchase Orders are in draft
* Purchase Orders belong to the same partner
2010-03-25 08:25:11 +00:00
* Purchase Orders are have same stock location , same pricelist
2010-05-28 09:48:40 +00:00
Lines will only be merged if :
* Order lines are exactly the same except for the quantity and unit
2010-03-25 08:25:11 +00:00
@param self : The object pointer .
@param cr : A database cursor
@param uid : ID of the user currently logged in
2010-05-28 09:48:40 +00:00
@param ids : the ID or list of IDs
@param context : A standard dictionary
2010-03-25 08:25:11 +00:00
@return : new purchase order id
2010-05-28 09:48:40 +00:00
"""
wf_service = netsvc . LocalService ( " workflow " )
def make_key ( br , fields ) :
2010-03-25 08:25:11 +00:00
list_key = [ ]
for field in fields :
field_val = getattr ( br , field )
if field in ( ' product_id ' , ' move_dest_id ' , ' account_analytic_id ' ) :
if not field_val :
field_val = False
if isinstance ( field_val , browse_record ) :
field_val = field_val . id
elif isinstance ( field_val , browse_null ) :
field_val = False
elif isinstance ( field_val , list ) :
field_val = ( ( 6 , 0 , tuple ( [ v . id for v in field_val ] ) ) , )
list_key . append ( ( field , field_val ) )
list_key . sort ( )
return tuple ( list_key )
# compute what the new orders should contain
2010-05-28 09:48:40 +00:00
2010-03-25 08:25:11 +00:00
new_orders = { }
2010-05-28 09:48:40 +00:00
2010-03-25 08:25:11 +00:00
for porder in [ order for order in self . browse ( cr , uid , ids ) if order . state == ' draft ' ] :
order_key = make_key ( porder , ( ' partner_id ' , ' location_id ' , ' pricelist_id ' ) )
new_order = new_orders . setdefault ( order_key , ( { } , [ ] ) )
new_order [ 1 ] . append ( porder . id )
order_infos = new_order [ 0 ]
if not order_infos :
order_infos . update ( {
' origin ' : porder . origin ,
' date_order ' : time . strftime ( ' % Y- % m- %d ' ) ,
' partner_id ' : porder . partner_id . id ,
' partner_address_id ' : porder . partner_address_id . id ,
' dest_address_id ' : porder . dest_address_id . id ,
' warehouse_id ' : porder . warehouse_id . id ,
' location_id ' : porder . location_id . id ,
' pricelist_id ' : porder . pricelist_id . id ,
' state ' : ' draft ' ,
' order_line ' : { } ,
' notes ' : ' %s ' % ( porder . notes or ' ' , ) ,
2010-05-11 05:54:09 +00:00
' fiscal_position ' : porder . fiscal_position and porder . fiscal_position . id or False ,
2010-03-25 08:25:11 +00:00
} )
else :
#order_infos['name'] += ', %s' % porder.name
if porder . notes :
order_infos [ ' notes ' ] = ( order_infos [ ' notes ' ] or ' ' ) + ( ' \n %s ' % ( porder . notes , ) )
if porder . origin :
order_infos [ ' origin ' ] = ( order_infos [ ' origin ' ] or ' ' ) + ' ' + porder . origin
for order_line in porder . order_line :
line_key = make_key ( order_line , ( ' name ' , ' date_planned ' , ' taxes_id ' , ' price_unit ' , ' notes ' , ' product_id ' , ' move_dest_id ' , ' account_analytic_id ' ) )
o_line = order_infos [ ' order_line ' ] . setdefault ( line_key , { } )
if o_line :
# merge the line with an existing line
o_line [ ' product_qty ' ] + = order_line . product_qty * order_line . product_uom . factor / o_line [ ' uom_factor ' ]
else :
# append a new "standalone" line
for field in ( ' product_qty ' , ' product_uom ' ) :
field_val = getattr ( order_line , field )
if isinstance ( field_val , browse_record ) :
field_val = field_val . id
o_line [ field ] = field_val
o_line [ ' uom_factor ' ] = order_line . product_uom and order_line . product_uom . factor or 1.0
2010-05-28 09:48:40 +00:00
2010-03-25 08:25:11 +00:00
allorders = [ ]
for order_key , ( order_data , old_ids ) in new_orders . iteritems ( ) :
# skip merges with only one order
if len ( old_ids ) < 2 :
allorders + = ( old_ids or [ ] )
continue
# cleanup order line data
for key , value in order_data [ ' order_line ' ] . iteritems ( ) :
del value [ ' uom_factor ' ]
value . update ( dict ( key ) )
order_data [ ' order_line ' ] = [ ( 0 , 0 , value ) for value in order_data [ ' order_line ' ] . itervalues ( ) ]
# create the new order
neworder_id = self . create ( cr , uid , order_data )
allorders . append ( neworder_id )
# make triggers pointing to the old orders point to the new order
for old_id in old_ids :
wf_service . trg_redirect ( uid , ' purchase.order ' , old_id , neworder_id , cr )
wf_service . trg_validate ( uid , ' purchase.order ' , old_id , ' purchase_cancel ' , cr )
return allorders
2006-12-07 13:41:40 +00:00
purchase_order ( )
class purchase_order_line ( osv . osv ) :
2010-06-05 21:39:55 +00:00
def _amount_line ( self , cr , uid , ids , prop , arg , context ) :
2008-07-22 15:11:28 +00:00
res = { }
cur_obj = self . pool . get ( ' res.currency ' )
2010-06-05 21:39:55 +00:00
tax_obj = self . pool . get ( ' account.tax ' )
for line in self . browse ( cr , uid , ids , context = context ) :
2010-06-05 22:45:14 +00:00
taxes = tax_obj . compute_all ( cr , uid , line . taxes_id , line . price_unit , line . product_qty )
2008-07-22 15:11:28 +00:00
cur = line . order_id . pricelist_id . currency_id
2010-06-05 21:39:55 +00:00
res [ line . id ] = cur_obj . round ( cr , uid , cur , taxes [ ' total ' ] )
2008-07-22 15:11:28 +00:00
return res
2008-08-27 11:26:37 +00:00
2008-07-22 15:11:28 +00:00
_columns = {
2009-07-02 15:11:59 +00:00
' name ' : fields . char ( ' Description ' , size = 256 , required = True ) ,
2008-07-22 15:11:28 +00:00
' product_qty ' : fields . float ( ' Quantity ' , required = True , digits = ( 16 , 2 ) ) ,
2010-06-21 21:20:55 +00:00
' date_planned ' : fields . date ( ' Scheduled date ' , required = True ) ,
2008-07-22 15:11:28 +00:00
' taxes_id ' : fields . many2many ( ' account.tax ' , ' purchase_order_taxe ' , ' ord_id ' , ' tax_id ' , ' Taxes ' ) ,
' product_uom ' : fields . many2one ( ' product.uom ' , ' Product UOM ' , required = True ) ,
' product_id ' : fields . many2one ( ' product.product ' , ' Product ' , domain = [ ( ' purchase_ok ' , ' = ' , True ) ] , change_default = True ) ,
2009-07-08 14:02:12 +00:00
' move_ids ' : fields . one2many ( ' stock.move ' , ' purchase_line_id ' , ' Reservation ' , readonly = True , ondelete = ' set null ' ) ,
2008-07-22 15:11:28 +00:00
' move_dest_id ' : fields . many2one ( ' stock.move ' , ' Reservation Destination ' , ondelete = ' set null ' ) ,
2010-03-06 20:52:19 +00:00
' price_unit ' : fields . float ( ' Unit Price ' , required = True , digits_compute = dp . get_precision ( ' Purchase Price ' ) ) ,
' price_subtotal ' : fields . function ( _amount_line , method = True , string = ' Subtotal ' , digits_compute = dp . get_precision ( ' Purchase Price ' ) ) ,
2010-06-12 18:32:16 +00:00
' notes ' : fields . text ( ' Notes ' ) ,
2009-12-22 09:38:41 +00:00
' order_id ' : fields . many2one ( ' purchase.order ' , ' Order Reference ' , select = True , required = True , ondelete = ' cascade ' ) ,
2008-07-22 15:11:28 +00:00
' account_analytic_id ' : fields . many2one ( ' account.analytic.account ' , ' Analytic Account ' , ) ,
2010-04-13 10:28:22 +00:00
' company_id ' : fields . related ( ' order_id ' , ' company_id ' , type = ' many2one ' , relation = ' res.company ' , string = ' Company ' ) ,
' state ' : fields . selection ( [ ( ' draft ' , ' Draft ' ) , ( ' confirmed ' , ' Confirmed ' ) , ( ' done ' , ' Done ' ) , ( ' cancel ' , ' Cancelled ' ) ] , ' State ' , required = True , readonly = True ,
help = ' * The \' Draft \' state is set automatically when purchase order in draft state. \
\n * The \' Confirmed \' state is set automatically as confirm when purchase order in confirm state. \
\n * The \' Done \' state is set automatically when purchase order is set as done. \
\n * The \' Cancelled \' state is set automatically when user cancel purchase order. ' ) ,
' invoice_lines ' : fields . many2many ( ' account.invoice.line ' , ' purchase_order_line_invoice_rel ' , ' order_line_id ' , ' invoice_id ' , ' Invoice Lines ' , readonly = True ) ,
' invoiced ' : fields . boolean ( ' Invoiced ' , readonly = True ) ,
' partner_id ' : fields . related ( ' order_id ' , ' partner_id ' , string = ' Partner ' , readonly = True , type = " many2one " , relation = " res.partner " ) ,
' date_order ' : fields . related ( ' order_id ' , ' date_order ' , string = ' Order Date ' , readonly = True , type = " date " )
2010-05-28 09:48:40 +00:00
2008-07-22 15:11:28 +00:00
}
_defaults = {
2010-04-13 10:28:22 +00:00
' product_qty ' : lambda * a : 1.0 ,
' state ' : lambda * args : ' draft ' ,
' invoiced ' : lambda * a : 0 ,
2008-07-22 15:11:28 +00:00
}
_table = ' purchase_order_line '
_name = ' purchase.order.line '
2010-05-19 18:32:32 +00:00
_description = ' Purchase Order Line '
2010-06-23 07:23:38 +00:00
2009-02-04 13:12:10 +00:00
def copy_data ( self , cr , uid , id , default = None , context = { } ) :
2008-07-22 15:11:28 +00:00
if not default :
default = { }
2010-04-13 10:28:22 +00:00
default . update ( { ' state ' : ' draft ' , ' move_ids ' : [ ] , ' invoiced ' : 0 , ' invoice_lines ' : [ ] } )
2009-02-04 13:12:10 +00:00
return super ( purchase_order_line , self ) . copy_data ( cr , uid , id , default , context )
2008-07-22 15:11:28 +00:00
def product_id_change ( self , cr , uid , ids , pricelist , product , qty , uom ,
2010-02-09 08:31:46 +00:00
partner_id , date_order = False , fiscal_position = False , date_planned = False ,
2009-11-26 13:54:00 +00:00
name = False , price_unit = False , notes = False ) :
2008-07-22 15:11:28 +00:00
if not pricelist :
2010-05-28 09:48:40 +00:00
raise osv . except_osv ( _ ( ' No Pricelist ! ' ) , _ ( ' You have to select a pricelist or a supplier in the purchase form ! \n Please set one before choosing a product. ' ) )
2009-01-23 13:45:30 +00:00
if not partner_id :
raise osv . except_osv ( _ ( ' No Partner! ' ) , _ ( ' You have to select a partner in the purchase form ! \n Please set one partner before choosing a product. ' ) )
2008-07-22 15:11:28 +00:00
if not product :
2009-11-26 13:54:00 +00:00
return { ' value ' : { ' price_unit ' : price_unit or 0.0 , ' name ' : name or ' ' ,
' notes ' : notes or ' ' , ' product_uom ' : uom or False } , ' domain ' : { ' product_uom ' : [ ] } }
2010-06-16 11:51:39 +00:00
prod = self . pool . get ( ' product.product ' ) . browse ( cr , uid , product )
2008-07-22 15:11:28 +00:00
lang = False
if partner_id :
2010-06-11 14:26:31 +00:00
lang = self . pool . get ( ' res.partner ' ) . read ( cr , uid , partner_id , [ ' lang ' ] ) [ ' lang ' ]
2008-07-22 15:11:28 +00:00
context = { ' lang ' : lang }
2008-12-16 19:35:32 +00:00
context [ ' partner_id ' ] = partner_id
2008-07-22 15:11:28 +00:00
2008-12-16 19:35:32 +00:00
prod = self . pool . get ( ' product.product ' ) . browse ( cr , uid , product , context = context )
prod_uom_po = prod . uom_po_id . id
2008-07-22 15:11:28 +00:00
if not uom :
uom = prod_uom_po
if not date_order :
date_order = time . strftime ( ' % Y- % m- %d ' )
2009-03-10 07:12:13 +00:00
qty = qty or 1.0
2008-12-16 19:35:32 +00:00
seller_delay = 0
for s in prod . seller_ids :
if s . name . id == partner_id :
seller_delay = s . delay
2009-03-17 14:02:37 +00:00
temp_qty = s . qty # supplier _qty assigned to temp
if qty < temp_qty : # If the supplier quantity is greater than entered from user, set minimal.
qty = temp_qty
2010-01-21 15:13:50 +00:00
if price_unit :
price = price_unit
else :
price = self . pool . get ( ' product.pricelist ' ) . price_get ( cr , uid , [ pricelist ] ,
product , qty or 1.0 , partner_id , {
' uom ' : uom ,
' date ' : date_order ,
} ) [ pricelist ]
2010-03-19 08:46:15 +00:00
dt = ( datetime . now ( ) + relativedelta ( days = int ( seller_delay ) or 0.0 ) ) . strftime ( ' % Y- % m- %d % H: % M: % S ' )
2009-09-24 10:46:21 +00:00
prod_name = self . pool . get ( ' product.product ' ) . name_get ( cr , uid , [ prod . id ] ) [ 0 ] [ 1 ]
2008-12-16 19:35:32 +00:00
2010-02-09 08:31:46 +00:00
res = { ' value ' : { ' price_unit ' : price , ' name ' : name or prod_name ,
2009-11-26 13:54:00 +00:00
' taxes_id ' : map ( lambda x : x . id , prod . supplier_taxes_id ) ,
' date_planned ' : date_planned or dt , ' notes ' : notes or prod . description_purchase ,
2008-12-16 19:35:32 +00:00
' product_qty ' : qty ,
' product_uom ' : uom } }
2008-07-22 15:11:28 +00:00
domain = { }
2008-10-21 16:28:19 +00:00
partner = self . pool . get ( ' res.partner ' ) . browse ( cr , uid , partner_id )
2008-12-16 19:35:32 +00:00
taxes = self . pool . get ( ' account.tax ' ) . browse ( cr , uid , map ( lambda x : x . id , prod . supplier_taxes_id ) )
2009-01-20 06:04:07 +00:00
fpos = fiscal_position and self . pool . get ( ' account.fiscal.position ' ) . browse ( cr , uid , fiscal_position ) or False
res [ ' value ' ] [ ' taxes_id ' ] = self . pool . get ( ' account.fiscal.position ' ) . map_tax ( cr , uid , fpos , taxes )
2008-08-19 19:26:29 +00:00
2008-07-22 15:11:28 +00:00
res2 = self . pool . get ( ' product.uom ' ) . read ( cr , uid , [ uom ] , [ ' category_id ' ] )
2008-12-16 19:35:32 +00:00
res3 = prod . uom_id . category_id . id
2008-07-22 15:11:28 +00:00
domain = { ' product_uom ' : [ ( ' category_id ' , ' = ' , res2 [ 0 ] [ ' category_id ' ] [ 0 ] ) ] }
2008-12-16 19:35:32 +00:00
if res2 [ 0 ] [ ' category_id ' ] [ 0 ] != res3 :
2008-07-22 15:11:28 +00:00
raise osv . except_osv ( _ ( ' Wrong Product UOM ! ' ) , _ ( ' You have to select a product UOM in the same category than the purchase UOM of the product ' ) )
res [ ' domain ' ] = domain
return res
def product_uom_change ( self , cr , uid , ids , pricelist , product , qty , uom ,
2010-04-16 10:15:19 +00:00
partner_id , date_order = False , fiscal_position = False ) :
2008-07-22 15:11:28 +00:00
res = self . product_id_change ( cr , uid , ids , pricelist , product , qty , uom ,
2010-04-16 10:15:19 +00:00
partner_id , date_order = date_order , fiscal_position = fiscal_position )
2008-07-22 15:11:28 +00:00
if ' product_uom ' in res [ ' value ' ] :
del res [ ' value ' ] [ ' product_uom ' ]
if not uom :
res [ ' value ' ] [ ' price_unit ' ] = 0.0
return res
2010-06-23 07:23:38 +00:00
2010-04-13 10:28:22 +00:00
def action_confirm ( self , cr , uid , ids , context = { } ) :
self . write ( cr , uid , ids , { ' state ' : ' confirmed ' } , context )
2010-06-15 06:06:40 +00:00
for ( id , name ) in self . name_get ( cr , uid , ids ) :
message = _ ( ' Purchase order line ' ) + " ' " + name + " ' " + _ ( " is confirmed " )
2010-06-15 07:20:15 +00:00
self . log ( cr , uid , id , message )
2010-05-28 09:48:40 +00:00
return True
2010-06-23 07:23:38 +00:00
2006-12-07 13:41:40 +00:00
purchase_order_line ( )
2008-07-23 14:41:47 +00:00
2010-05-27 12:47:06 +00:00
class procurement_order ( osv . osv ) :
_inherit = ' procurement.order '
2010-04-29 13:30:07 +00:00
_columns = {
2010-07-09 09:26:48 +00:00
' purchase_id ' : fields . many2one ( ' purchase.order ' , ' Purchase Order ' ) ,
2010-04-29 13:30:07 +00:00
}
2010-05-28 09:48:40 +00:00
2010-04-29 13:30:07 +00:00
def action_po_assign ( self , cr , uid , ids , context = { } ) :
""" This is action which call from workflow to assign purchase order to procurements
@return : True
"""
res = self . make_po ( cr , uid , ids , context = context )
res = res . values ( )
return len ( res ) and res [ 0 ] or 0 #TO CHECK: why workflow is generated error if return not integer value
def make_po ( self , cr , uid , ids , context = { } ) :
""" Make purchase order from procurement
@return : New created Purchase Orders procurement wise
"""
res = { }
company = self . pool . get ( ' res.users ' ) . browse ( cr , uid , uid , context ) . company_id
partner_obj = self . pool . get ( ' res.partner ' )
uom_obj = self . pool . get ( ' product.uom ' )
pricelist_obj = self . pool . get ( ' product.pricelist ' )
prod_obj = self . pool . get ( ' product.product ' )
acc_pos_obj = self . pool . get ( ' account.fiscal.position ' )
po_obj = self . pool . get ( ' purchase.order ' )
for procurement in self . browse ( cr , uid , ids ) :
res_id = procurement . move_id . id
2010-06-13 21:16:36 +00:00
partner = procurement . product_id . seller_ids [ 0 ] . name
partner_id = partner . id
partner_rec = procurement . product_id . seller_ids [ 0 ]
2010-04-29 13:30:07 +00:00
address_id = partner_obj . address_get ( cr , uid , [ partner_id ] , [ ' delivery ' ] ) [ ' delivery ' ]
pricelist_id = partner . property_product_pricelist_purchase . id
uom_id = procurement . product_id . uom_po_id . id
qty = uom_obj . _compute_qty ( cr , uid , procurement . product_uom . id , procurement . product_qty , uom_id )
2010-06-13 21:16:36 +00:00
if procurement . product_id . seller_ids [ 0 ] . qty :
2010-06-07 18:42:14 +00:00
qty = max ( qty , partner_rec . qty )
2010-04-29 13:30:07 +00:00
price = pricelist_obj . price_get ( cr , uid , [ pricelist_id ] , procurement . product_id . id , qty , False , { ' uom ' : uom_id } ) [ pricelist_id ]
newdate = DateTime . strptime ( procurement . date_planned , ' % Y- % m- %d % H: % M: % S ' )
newdate = newdate - DateTime . RelativeDateTime ( days = company . po_lead )
2010-06-07 18:42:14 +00:00
newdate = newdate - partner_rec . delay
2010-04-29 13:30:07 +00:00
#Passing partner_id to context for purchase order line integrity of Line name
context . update ( { ' lang ' : partner . lang , ' partner_id ' : partner_id } )
product = prod_obj . browse ( cr , uid , procurement . product_id . id , context = context )
line = {
' name ' : product . partner_ref ,
' product_qty ' : qty ,
' product_id ' : procurement . product_id . id ,
' product_uom ' : uom_id ,
' price_unit ' : price ,
' date_planned ' : newdate . strftime ( ' % Y- % m- %d % H: % M: % S ' ) ,
' move_dest_id ' : res_id ,
' notes ' : product . description_purchase ,
}
taxes_ids = procurement . product_id . product_tmpl_id . supplier_taxes_id
taxes = acc_pos_obj . map_tax ( cr , uid , partner . property_account_position , taxes_ids )
line . update ( {
' taxes_id ' : [ ( 6 , 0 , taxes ) ]
} )
purchase_id = po_obj . create ( cr , uid , {
' origin ' : procurement . origin ,
' partner_id ' : partner_id ,
' partner_address_id ' : address_id ,
' location_id ' : procurement . location_id . id ,
' pricelist_id ' : pricelist_id ,
' order_line ' : [ ( 0 , 0 , line ) ] ,
' company_id ' : procurement . company_id . id ,
' fiscal_position ' : partner . property_account_position and partner . property_account_position . id or False
} )
res [ procurement . id ] = purchase_id
2010-05-05 09:53:26 +00:00
self . write ( cr , uid , [ procurement . id ] , { ' state ' : ' running ' , ' purchase_id ' : purchase_id } )
2010-04-29 13:30:07 +00:00
return res
2010-06-23 07:23:38 +00:00
procurement_order ( )
2008-07-23 14:41:47 +00:00
2010-07-09 14:31:07 +00:00
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4: