2009-10-20 10:52:23 +00:00
# -*- coding: utf-8 -*-
2006-12-07 13:41:40 +00:00
##############################################################################
2010-05-14 09:57:41 +00:00
#
2008-11-18 14:39:15 +00:00
# OpenERP, Open Source Management Solution
2009-10-14 12:32:15 +00:00
# Copyright (C) 2004-2009 Tiny SPRL (<http://tiny.be>).
2006-12-07 13:41:40 +00:00
#
2008-11-03 18:27:16 +00:00
# This program is free software: you can redistribute it and/or modify
2009-10-14 12:32:15 +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 18:27:16 +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 12:32:15 +00:00
# GNU Affero General Public License for more details.
2006-12-07 13:41:40 +00:00
#
2009-10-14 12:32:15 +00:00
# You should have received a copy of the GNU Affero General Public License
2010-05-14 09:57:41 +00:00
# along with this program. If not, see <http://www.gnu.org/licenses/>.
2006-12-07 13:41:40 +00:00
#
2012-03-05 07:26:18 +00:00
##############################################################################
2006-12-07 13:41:40 +00:00
2012-11-22 15:14:58 +00:00
import datetime
2012-12-10 15:27:23 +00:00
from lxml import etree
2006-12-07 13:41:40 +00:00
import math
2012-12-10 15:27:23 +00:00
import pytz
import re
2012-08-10 08:17:30 +00:00
import openerp
2012-09-18 14:14:21 +00:00
from openerp import SUPERUSER_ID
2012-12-10 15:27:23 +00:00
from openerp import pooler , tools
from openerp . osv import osv , fields
from openerp . tools . translate import _
2012-08-10 08:17:30 +00:00
2012-09-13 18:16:38 +00:00
class format_address ( object ) :
def fields_view_get_address ( self , cr , uid , arch , context = { } ) :
user_obj = self . pool . get ( ' res.users ' )
2012-09-18 14:14:21 +00:00
fmt = user_obj . browse ( cr , SUPERUSER_ID , uid , context ) . company_id . country_id
2012-09-13 18:16:38 +00:00
fmt = fmt and fmt . address_format
layouts = {
' %(city)s %(state_code)s \n %(zip)s ' : """
< div class = " address_format " >
< field name = " city " placeholder = " City " style = " width: 50 %% " / >
< field name = " state_id " class = " oe_no_button " placeholder = " State " style = " width: 47 %% " options = ' { " no_open " : true} ' / >
< br / >
< field name = " zip " placeholder = " ZIP " / >
< / div >
""" ,
' %(zip)s %(city)s ' : """
< div class = " address_format " >
< field name = " zip " placeholder = " ZIP " style = " width: 40 %% " / >
2012-09-13 18:27:36 +00:00
< field name = " city " placeholder = " City " style = " width: 57 %% " / >
2012-09-13 18:16:38 +00:00
< br / >
< field name = " state_id " class = " oe_no_button " placeholder = " State " options = ' { " no_open " : true} ' / >
< / div >
""" ,
' %(city)s \n %(state_name)s \n %(zip)s ' : """
< div class = " address_format " >
< field name = " city " placeholder = " City " / >
< field name = " state_id " class = " oe_no_button " placeholder = " State " options = ' { " no_open " : true} ' / >
< field name = " zip " placeholder = " ZIP " / >
< / div >
"""
}
for k , v in layouts . items ( ) :
if fmt and ( k in fmt ) :
doc = etree . fromstring ( arch )
for node in doc . xpath ( " //div[@class= ' address_format ' ] " ) :
tree = etree . fromstring ( v )
node . getparent ( ) . replace ( node , tree )
arch = etree . tostring ( doc )
break
return arch
2012-08-10 08:17:30 +00:00
def _tz_get ( self , cr , uid , context = None ) :
return [ ( x , x ) for x in pytz . all_timezones ]
2012-03-06 06:49:43 +00:00
2006-12-07 13:41:40 +00:00
class res_partner_category ( osv . osv ) :
2011-12-21 14:54:43 +00:00
2009-01-23 14:17:31 +00:00
def name_get ( self , cr , uid , ids , context = None ) :
2011-12-21 14:54:43 +00:00
""" Return the categories ' display name, including their direct
parent by default .
: param dict context : the ` ` partner_category_display ` ` key can be
used to select the short version of the
category name ( without the direct parent ) ,
when set to ` ` ' short ' ` ` . The default is
2012-03-06 06:49:43 +00:00
the long version . """
2011-12-15 14:56:04 +00:00
if context is None :
context = { }
2011-12-21 14:54:43 +00:00
if context . get ( ' partner_category_display ' ) == ' short ' :
return super ( res_partner_category , self ) . name_get ( cr , uid , ids , context = context )
2012-06-20 09:58:12 +00:00
if isinstance ( ids , ( int , long ) ) :
ids = [ ids ]
2012-09-07 09:22:06 +00:00
reads = self . read ( cr , uid , ids , [ ' name ' , ' parent_id ' ] , context = context )
2008-07-22 14:24:36 +00:00
res = [ ]
for record in reads :
name = record [ ' name ' ]
if record [ ' parent_id ' ] :
2012-09-07 09:22:06 +00:00
name = record [ ' parent_id ' ] [ 1 ] + ' / ' + name
2008-07-22 14:24:36 +00:00
res . append ( ( record [ ' id ' ] , name ) )
return res
2010-12-22 18:39:26 +00:00
def name_search ( self , cr , uid , name , args = None , operator = ' ilike ' , context = None , limit = 100 ) :
if not args :
2012-09-07 09:22:06 +00:00
args = [ ]
2010-12-22 18:39:26 +00:00
if not context :
2012-09-07 09:22:06 +00:00
context = { }
2010-12-22 18:39:26 +00:00
if name :
# Be sure name_search is symetric to name_get
name = name . split ( ' / ' ) [ - 1 ]
ids = self . search ( cr , uid , [ ( ' name ' , operator , name ) ] + args , limit = limit , context = context )
else :
ids = self . search ( cr , uid , args , limit = limit , context = context )
return self . name_get ( cr , uid , ids , context )
2009-01-23 14:17:31 +00:00
def _name_get_fnc ( self , cr , uid , ids , prop , unknow_none , context = None ) :
res = self . name_get ( cr , uid , ids , context = context )
2008-07-22 14:24:36 +00:00
return dict ( res )
2009-01-23 14:17:31 +00:00
2012-09-07 09:22:06 +00:00
_description = ' Partner Categories '
2008-07-22 14:24:36 +00:00
_name = ' res.partner.category '
_columns = {
2008-09-08 22:52:36 +00:00
' name ' : fields . char ( ' Category Name ' , required = True , size = 64 , translate = True ) ,
2010-12-11 00:04:50 +00:00
' parent_id ' : fields . many2one ( ' res.partner.category ' , ' Parent Category ' , select = True , ondelete = ' cascade ' ) ,
2012-01-04 13:30:27 +00:00
' complete_name ' : fields . function ( _name_get_fnc , type = " char " , string = ' Full Name ' ) ,
2009-01-26 17:40:29 +00:00
' child_ids ' : fields . one2many ( ' res.partner.category ' , ' parent_id ' , ' Child Categories ' ) ,
2012-09-07 09:22:06 +00:00
' active ' : fields . boolean ( ' Active ' , help = " The active field allows you to hide the category without removing it. " ) ,
' parent_left ' : fields . integer ( ' Left parent ' , select = True ) ,
' parent_right ' : fields . integer ( ' Right parent ' , select = True ) ,
2012-06-19 15:16:26 +00:00
' partner_ids ' : fields . many2many ( ' res.partner ' , id1 = ' category_id ' , id2 = ' partner_id ' , string = ' Partners ' ) ,
2008-07-22 14:24:36 +00:00
}
_constraints = [
2010-12-09 10:57:33 +00:00
( osv . osv . _check_recursion , ' Error ! You can not create recursive categories. ' , [ ' parent_id ' ] )
2008-07-22 14:24:36 +00:00
]
_defaults = {
2012-11-02 09:47:05 +00:00
' active ' : 1 ,
2008-07-22 14:24:36 +00:00
}
2010-12-11 00:04:50 +00:00
_parent_store = True
_parent_order = ' name '
_order = ' parent_left '
2012-03-06 06:49:43 +00:00
2006-12-07 13:41:40 +00:00
class res_partner_title ( osv . osv ) :
2008-07-22 14:24:36 +00:00
_name = ' res.partner.title '
2012-07-19 09:03:00 +00:00
_order = ' name '
2008-07-22 14:24:36 +00:00
_columns = {
' name ' : fields . char ( ' Title ' , required = True , size = 46 , translate = True ) ,
2012-07-19 09:03:00 +00:00
' shortcut ' : fields . char ( ' Abbreviation ' , size = 16 , translate = True ) ,
2012-09-07 09:22:06 +00:00
' domain ' : fields . selection ( [ ( ' partner ' , ' Partner ' ) , ( ' contact ' , ' Contact ' ) ] , ' Domain ' , required = True , size = 24 )
2008-07-22 14:24:36 +00:00
}
2012-07-19 09:03:00 +00:00
_defaults = {
' domain ' : ' contact ' ,
}
2012-03-06 06:49:43 +00:00
2011-11-07 15:19:49 +00:00
def _lang_get ( self , cr , uid , context = None ) :
2012-03-06 06:49:43 +00:00
lang_pool = self . pool . get ( ' res.lang ' )
ids = lang_pool . search ( cr , uid , [ ] , context = context )
res = lang_pool . read ( cr , uid , ids , [ ' code ' , ' name ' ] , context )
2012-10-09 06:16:40 +00:00
return [ ( r [ ' code ' ] , r [ ' name ' ] ) for r in res ]
2009-05-12 14:01:27 +00:00
2012-03-08 12:27:12 +00:00
POSTAL_ADDRESS_FIELDS = ( ' street ' , ' street2 ' , ' zip ' , ' city ' , ' state_id ' , ' country_id ' )
ADDRESS_FIELDS = POSTAL_ADDRESS_FIELDS + ( ' email ' , ' phone ' , ' fax ' , ' mobile ' , ' website ' , ' ref ' , ' lang ' )
2012-03-07 15:36:46 +00:00
2012-09-13 18:16:38 +00:00
class res_partner ( osv . osv , format_address ) :
2012-09-07 09:22:06 +00:00
_description = ' Partner '
2008-07-22 14:24:36 +00:00
_name = " res.partner "
2012-03-29 06:29:24 +00:00
def _address_display ( self , cr , uid , ids , name , args , context = None ) :
2012-09-07 09:22:06 +00:00
res = { }
2012-03-29 11:43:31 +00:00
for partner in self . browse ( cr , uid , ids , context = context ) :
2012-09-07 09:22:06 +00:00
res [ partner . id ] = self . _display_address ( cr , uid , partner , context = context )
2012-03-29 06:29:24 +00:00
return res
2012-06-27 15:57:49 +00:00
def _get_image ( self , cr , uid , ids , name , args , context = None ) :
result = dict . fromkeys ( ids , False )
for obj in self . browse ( cr , uid , ids , context = context ) :
2012-08-07 11:08:59 +00:00
result [ obj . id ] = tools . image_get_resized_images ( obj . image )
2012-06-27 15:57:49 +00:00
return result
2012-09-07 09:22:06 +00:00
2012-11-22 15:14:58 +00:00
def _get_tz_offset ( self , cr , uid , ids , name , args , context = None ) :
result = dict . fromkeys ( ids , False )
for obj in self . browse ( cr , uid , ids , context = context ) :
result [ obj . id ] = datetime . datetime . now ( pytz . timezone ( obj . tz or ' GMT ' ) ) . strftime ( ' % z ' )
return result
2012-06-27 15:57:49 +00:00
def _set_image ( self , cr , uid , id , name , value , args , context = None ) :
2012-08-07 11:08:59 +00:00
return self . write ( cr , uid , [ id ] , { ' image ' : tools . image_resize_image_big ( value ) } , context = context )
2012-06-27 15:57:49 +00:00
2012-12-21 12:06:31 +00:00
def _has_image ( self , cr , uid , ids , name , args , context = None ) :
result = { }
for obj in self . browse ( cr , uid , ids , context = context ) :
result [ obj . id ] = obj . image != False
return result
2008-07-22 14:24:36 +00:00
_order = " name "
_columns = {
2012-03-19 10:36:02 +00:00
' name ' : fields . char ( ' Name ' , size = 128 , required = True , select = True ) ,
2008-07-22 14:24:36 +00:00
' date ' : fields . date ( ' Date ' , select = 1 ) ,
2012-09-07 09:22:06 +00:00
' title ' : fields . many2one ( ' res.partner.title ' , ' Title ' ) ,
2012-10-24 08:44:09 +00:00
' parent_id ' : fields . many2one ( ' res.partner ' , ' Related Company ' ) ,
2012-02-23 11:41:12 +00:00
' child_ids ' : fields . one2many ( ' res.partner ' , ' parent_id ' , ' Contacts ' ) ,
2011-01-10 17:03:28 +00:00
' ref ' : fields . char ( ' Reference ' , size = 64 , select = 1 ) ,
2012-08-10 08:17:30 +00:00
' lang ' : fields . selection ( _lang_get , ' Language ' ,
2012-09-25 09:43:30 +00:00
help = " If the selected language is loaded in the system, all documents related to this contact will be printed in this language. If not, it will be English. " ) ,
2012-08-10 08:17:30 +00:00
' tz ' : fields . selection ( _tz_get , ' Timezone ' , size = 64 ,
help = " The partner ' s timezone, used to output proper date and time values inside printed reports. "
" It is important to set a value for this field. You should use the same timezone "
" that is otherwise used to pick and render date and time values: your computer ' s timezone. " ) ,
2012-11-29 21:00:33 +00:00
' tz_offset ' : fields . function ( _get_tz_offset , type = ' char ' , size = 5 , string = ' Timezone offset ' , invisible = True ) ,
2012-09-25 09:43:30 +00:00
' user_id ' : fields . many2one ( ' res.users ' , ' Salesperson ' , help = ' The internal user that is in charge of communicating with this contact if any. ' ) ,
' vat ' : fields . char ( ' TIN ' , size = 32 , help = " Tax Identification Number. Check the box if this contact is subjected to taxes. Used by the some of the legal statements. " ) ,
2008-07-22 14:24:36 +00:00
' bank_ids ' : fields . one2many ( ' res.partner.bank ' , ' partner_id ' , ' Banks ' ) ,
2012-09-07 09:22:06 +00:00
' website ' : fields . char ( ' Website ' , size = 64 , help = " Website of Partner or Company " ) ,
2008-07-22 14:24:36 +00:00
' comment ' : fields . text ( ' Notes ' ) ,
2012-06-19 15:16:26 +00:00
' category_id ' : fields . many2many ( ' res.partner.category ' , id1 = ' partner_id ' , id2 = ' category_id ' , string = ' Tags ' ) ,
2008-07-22 14:24:36 +00:00
' credit_limit ' : fields . float ( string = ' Credit Limit ' ) ,
' ean13 ' : fields . char ( ' EAN13 ' , size = 13 ) ,
2012-02-23 11:41:12 +00:00
' active ' : fields . boolean ( ' Active ' ) ,
2012-09-25 09:43:30 +00:00
' customer ' : fields . boolean ( ' Customer ' , help = " Check this box if this contact is a customer. " ) ,
' supplier ' : fields . boolean ( ' Supplier ' , help = " Check this box if this contact is a supplier. If it ' s not checked, purchase people will not see it when encoding a purchase order. " ) ,
' employee ' : fields . boolean ( ' Employee ' , help = " Check this box if this contact is an Employee. " ) ,
2012-06-29 13:47:39 +00:00
' function ' : fields . char ( ' Job Position ' , size = 128 ) ,
2012-09-07 09:22:06 +00:00
' type ' : fields . selection ( [ ( ' default ' , ' Default ' ) , ( ' invoice ' , ' Invoice ' ) ,
2012-10-12 07:05:25 +00:00
( ' delivery ' , ' Shipping ' ) , ( ' contact ' , ' Contact ' ) ,
2012-08-10 08:17:30 +00:00
( ' other ' , ' Other ' ) ] , ' Address Type ' ,
help = " Used to select automatically the right address according to the context in sales and purchases documents. " ) ,
2012-02-20 09:17:05 +00:00
' street ' : fields . char ( ' Street ' , size = 128 ) ,
' street2 ' : fields . char ( ' Street2 ' , size = 128 ) ,
' zip ' : fields . char ( ' Zip ' , change_default = True , size = 24 ) ,
' city ' : fields . char ( ' City ' , size = 128 ) ,
2012-08-02 13:46:48 +00:00
' state_id ' : fields . many2one ( " res.country.state " , ' State ' ) ,
2012-02-20 09:17:05 +00:00
' country_id ' : fields . many2one ( ' res.country ' , ' Country ' ) ,
2012-09-26 13:10:06 +00:00
' country ' : fields . related ( ' country_id ' , type = ' many2one ' , relation = ' res.country ' , string = ' Country ' ,
deprecated = " This field will be removed as of OpenERP 7.1, use country_id instead " ) ,
2012-06-25 13:06:52 +00:00
' email ' : fields . char ( ' Email ' , size = 240 ) ,
2012-02-20 09:17:05 +00:00
' phone ' : fields . char ( ' Phone ' , size = 64 ) ,
' fax ' : fields . char ( ' Fax ' , size = 64 ) ,
' mobile ' : fields . char ( ' Mobile ' , size = 64 ) ,
' birthdate ' : fields . char ( ' Birthdate ' , size = 64 ) ,
2012-10-24 08:44:09 +00:00
' is_company ' : fields . boolean ( ' Is a Company ' , help = " Check if the contact is a company, otherwise it is a person " ) ,
2012-03-28 05:30:40 +00:00
' use_parent_address ' : fields . boolean ( ' Use Company Address ' , help = " Select this if you want to set company ' s address information for this contact " ) ,
2012-09-07 09:22:06 +00:00
# image: all image fields are base64 encoded and PIL-supported
2012-07-30 09:51:33 +00:00
' image ' : fields . binary ( " Image " ,
2012-09-25 09:43:30 +00:00
help = " This field holds the image used as avatar for this contact, limited to 1024x1024px " ) ,
2012-06-27 15:57:49 +00:00
' image_medium ' : fields . function ( _get_image , fnct_inv = _set_image ,
2012-07-30 09:51:33 +00:00
string = " Medium-sized image " , type = " binary " , multi = " _get_image " ,
2012-09-07 09:22:06 +00:00
store = {
2012-06-27 15:57:49 +00:00
' res.partner ' : ( lambda self , cr , uid , ids , c = { } : ids , [ ' image ' ] , 10 ) ,
} ,
2012-09-25 09:43:30 +00:00
help = " Medium-sized image of this contact. It is automatically " \
2012-09-07 09:49:57 +00:00
" resized as a 128x128px image, with aspect ratio preserved. " \
2012-06-27 15:57:49 +00:00
" Use this field in form views or some kanban views. " ) ,
' image_small ' : fields . function ( _get_image , fnct_inv = _set_image ,
2012-07-30 09:51:33 +00:00
string = " Small-sized image " , type = " binary " , multi = " _get_image " ,
2012-09-07 09:22:06 +00:00
store = {
2012-06-27 15:57:49 +00:00
' res.partner ' : ( lambda self , cr , uid , ids , c = { } : ids , [ ' image ' ] , 10 ) ,
} ,
2012-09-25 09:43:30 +00:00
help = " Small-sized image of this contact. It is automatically " \
2012-09-07 09:49:57 +00:00
" resized as a 64x64px image, with aspect ratio preserved. " \
2012-06-27 15:57:49 +00:00
" Use this field anywhere a small image is required. " ) ,
2012-12-21 12:06:31 +00:00
' has_image ' : fields . function ( _has_image , type = " boolean " ) ,
2012-02-23 11:41:12 +00:00
' company_id ' : fields . many2one ( ' res.company ' , ' Company ' , select = 1 ) ,
' color ' : fields . integer ( ' Color Index ' ) ,
2012-08-20 11:32:27 +00:00
' user_ids ' : fields . one2many ( ' res.users ' , ' partner_id ' , ' Users ' ) ,
2012-03-29 11:43:31 +00:00
' contact_address ' : fields . function ( _address_display , type = ' char ' , string = ' Complete Address ' ) ,
2008-07-22 14:24:36 +00:00
}
2012-03-07 15:28:27 +00:00
2011-11-07 15:19:49 +00:00
def _default_category ( self , cr , uid , context = None ) :
if context is None :
context = { }
2012-03-07 15:28:27 +00:00
if context . get ( ' category_id ' ) :
return [ context [ ' category_id ' ] ]
2012-03-06 06:49:43 +00:00
return False
2008-11-18 12:54:32 +00:00
2012-09-03 09:55:27 +00:00
def _get_default_image ( self , cr , uid , is_company , context = None , colorize = False ) :
2012-11-06 18:15:02 +00:00
img_path = openerp . modules . get_module_resource ( ' base ' , ' static/src/img ' ,
( ' company_image.png ' if is_company else ' avatar.png ' ) )
with open ( img_path , ' rb ' ) as f :
image = f . read ( )
# colorize user avatars
if not is_company :
image = tools . image_colorize ( image )
2012-09-07 09:22:06 +00:00
return tools . image_resize_image_big ( image . encode ( ' base64 ' ) )
2012-03-05 07:26:18 +00:00
2012-09-11 16:19:26 +00:00
def fields_view_get ( self , cr , user , view_id = None , view_type = ' form ' , context = None , toolbar = False , submenu = False ) :
if ( not view_id ) and ( view_type == ' form ' ) and context and context . get ( ' force_email ' , False ) :
view_id = self . pool . get ( ' ir.model.data ' ) . get_object_reference ( cr , user , ' base ' , ' view_partner_simple_form ' ) [ 1 ]
2012-09-13 18:22:56 +00:00
res = super ( res_partner , self ) . fields_view_get ( cr , user , view_id , view_type , context , toolbar = toolbar , submenu = submenu )
2012-09-13 18:16:38 +00:00
if view_type == ' form ' :
2012-09-13 18:22:56 +00:00
res [ ' arch ' ] = self . fields_view_get_address ( cr , user , res [ ' arch ' ] , context = context )
2012-09-13 18:16:38 +00:00
return res
2012-09-11 16:19:26 +00:00
2008-07-22 14:24:36 +00:00
_defaults = {
2012-02-23 11:41:12 +00:00
' active ' : True ,
2012-09-07 09:22:06 +00:00
' lang ' : lambda self , cr , uid , ctx : ctx . get ( ' lang ' , ' en_US ' ) ,
' tz ' : lambda self , cr , uid , ctx : ctx . get ( ' tz ' , False ) ,
2012-02-23 11:41:12 +00:00
' customer ' : True ,
2008-11-18 12:54:32 +00:00
' category_id ' : _default_category ,
2012-09-07 09:22:06 +00:00
' company_id ' : lambda self , cr , uid , ctx : self . pool . get ( ' res.company ' ) . _company_default_get ( cr , uid , ' res.partner ' , context = ctx ) ,
2011-09-16 12:47:25 +00:00
' color ' : 0 ,
2012-03-07 15:19:42 +00:00
' is_company ' : False ,
2012-02-20 09:17:05 +00:00
' type ' : ' default ' ,
2012-03-07 15:19:42 +00:00
' use_parent_address ' : True ,
2012-12-21 12:06:31 +00:00
' image ' : False ,
2008-07-22 14:24:36 +00:00
}
2012-03-05 07:26:18 +00:00
2011-11-07 15:19:49 +00:00
def copy ( self , cr , uid , id , default = None , context = None ) :
if default is None :
default = { }
2011-11-21 13:33:46 +00:00
name = self . read ( cr , uid , [ id ] , [ ' name ' ] , context ) [ 0 ] [ ' name ' ]
2012-12-14 12:38:03 +00:00
default . update ( { ' name ' : _ ( ' %s (copy) ' ) % name } )
2008-07-22 14:24:36 +00:00
return super ( res_partner , self ) . copy ( cr , uid , id , default , context )
2008-09-18 11:28:57 +00:00
2012-03-07 15:19:42 +00:00
def onchange_type ( self , cr , uid , ids , is_company , context = None ) :
2012-12-21 12:06:31 +00:00
value = { }
2012-06-27 15:57:49 +00:00
value [ ' title ' ] = False
2012-03-07 15:19:42 +00:00
if is_company :
value [ ' parent_id ' ] = False
domain = { ' title ' : [ ( ' domain ' , ' = ' , ' partner ' ) ] }
else :
domain = { ' title ' : [ ( ' domain ' , ' = ' , ' contact ' ) ] }
return { ' value ' : value , ' domain ' : domain }
2012-03-06 06:49:43 +00:00
2012-02-23 14:54:26 +00:00
def onchange_address ( self , cr , uid , ids , use_parent_address , parent_id , context = None ) :
2012-03-19 10:35:11 +00:00
def value_or_id ( val ) :
""" return val or val.id if val is a browse record """
return val if isinstance ( val , ( bool , int , long , float , basestring ) ) else val . id
2012-02-23 14:54:26 +00:00
if use_parent_address and parent_id :
2012-02-23 11:41:12 +00:00
parent = self . browse ( cr , uid , parent_id , context = context )
2012-03-08 12:27:12 +00:00
return { ' value ' : dict ( ( key , value_or_id ( parent [ key ] ) ) for key in ADDRESS_FIELDS ) }
return { }
2010-05-18 15:34:22 +00:00
2012-10-25 10:23:01 +00:00
def onchange_state ( self , cr , uid , ids , state_id , context = None ) :
if state_id :
country_id = self . pool . get ( ' res.country.state ' ) . browse ( cr , uid , state_id , context ) . country_id . id
2012-11-02 09:14:49 +00:00
return { ' value ' : { ' country_id ' : country_id } }
return { }
2012-10-25 10:23:01 +00:00
2010-12-09 10:57:33 +00:00
def _check_ean_key ( self , cr , uid , ids , context = None ) :
2008-07-22 14:24:36 +00:00
for partner_o in pooler . get_pool ( cr . dbname ) . get ( ' res.partner ' ) . read ( cr , uid , ids , [ ' ean13 ' , ] ) :
thisean = partner_o [ ' ean13 ' ]
if thisean and thisean != ' ' :
if len ( thisean ) != 13 :
return False
sum = 0
for i in range ( 12 ) :
if not ( i % 2 ) :
sum + = int ( thisean [ i ] )
else :
sum + = 3 * int ( thisean [ i ] )
if math . ceil ( sum / 10.0 ) * 10 - sum != int ( thisean [ 12 ] ) :
return False
return True
2012-03-06 06:49:43 +00:00
2012-03-07 15:19:42 +00:00
# _constraints = [(_check_ean_key, 'Error: Invalid ean code', ['ean13'])]
2012-03-06 06:49:43 +00:00
2012-02-28 08:24:56 +00:00
def write ( self , cr , uid , ids , vals , context = None ) :
2012-03-08 14:03:42 +00:00
# Update parent and siblings or children records
2012-02-28 08:54:38 +00:00
if isinstance ( ids , ( int , long ) ) :
ids = [ ids ]
2012-03-19 13:07:22 +00:00
if vals . get ( ' is_company ' ) == False :
2012-03-29 06:29:24 +00:00
vals . update ( { ' child_ids ' : [ ( 5 , ) ] } )
2012-03-08 14:03:42 +00:00
for partner in self . browse ( cr , uid , ids , context = context ) :
update_ids = [ ]
if partner . is_company :
domain_children = [ ( ' parent_id ' , ' = ' , partner . id ) , ( ' use_parent_address ' , ' = ' , True ) ]
update_ids = self . search ( cr , uid , domain_children , context = context )
2012-03-27 09:13:54 +00:00
elif partner . parent_id :
if vals . get ( ' use_parent_address ' ) == True :
domain_siblings = [ ( ' parent_id ' , ' = ' , partner . parent_id . id ) , ( ' use_parent_address ' , ' = ' , True ) ]
update_ids = [ partner . parent_id . id ] + self . search ( cr , uid , domain_siblings , context = context )
if ' use_parent_address ' not in vals and partner . use_parent_address :
domain_siblings = [ ( ' parent_id ' , ' = ' , partner . parent_id . id ) , ( ' use_parent_address ' , ' = ' , True ) ]
update_ids = [ partner . parent_id . id ] + self . search ( cr , uid , domain_siblings , context = context )
2012-03-08 14:03:42 +00:00
self . update_address ( cr , uid , update_ids , vals , context )
return super ( res_partner , self ) . write ( cr , uid , ids , vals , context = context )
2012-03-06 06:49:43 +00:00
2012-02-29 09:13:45 +00:00
def create ( self , cr , uid , vals , context = None ) :
2012-03-13 06:13:38 +00:00
if context is None :
context = { }
2012-03-08 14:03:42 +00:00
# Update parent and siblings records
if vals . get ( ' parent_id ' ) and vals . get ( ' use_parent_address ' ) :
domain_siblings = [ ( ' parent_id ' , ' = ' , vals [ ' parent_id ' ] ) , ( ' use_parent_address ' , ' = ' , True ) ]
update_ids = [ vals [ ' parent_id ' ] ] + self . search ( cr , uid , domain_siblings , context = context )
self . update_address ( cr , uid , update_ids , vals , context )
return super ( res_partner , self ) . create ( cr , uid , vals , context = context )
2012-03-06 06:49:43 +00:00
2012-03-08 14:03:42 +00:00
def update_address ( self , cr , uid , ids , vals , context = None ) :
addr_vals = dict ( ( key , vals [ key ] ) for key in POSTAL_ADDRESS_FIELDS if vals . get ( key ) )
2012-08-13 15:24:13 +00:00
if addr_vals :
return super ( res_partner , self ) . write ( cr , uid , ids , addr_vals , context )
2008-07-22 14:24:36 +00:00
2011-11-07 15:19:49 +00:00
def name_get ( self , cr , uid , ids , context = None ) :
if context is None :
context = { }
2012-06-20 09:58:12 +00:00
if isinstance ( ids , ( int , long ) ) :
ids = [ ids ]
2012-03-02 12:29:17 +00:00
res = [ ]
2012-06-25 18:22:29 +00:00
for record in self . browse ( cr , uid , ids , context = context ) :
name = record . name
if record . parent_id :
name = " %s ( %s ) " % ( name , record . parent_id . name )
if context . get ( ' show_address ' ) :
name = name + " \n " + self . _display_address ( cr , uid , record , without_company = True , context = context )
name = name . replace ( ' \n \n ' , ' \n ' )
name = name . replace ( ' \n \n ' , ' \n ' )
2012-12-20 18:16:04 +00:00
if context . get ( ' show_email ' ) and record . email :
name = " %s < %s > " % ( name , record . email )
2012-06-25 18:22:29 +00:00
res . append ( ( record . id , name ) )
2008-07-22 14:24:36 +00:00
return res
2008-09-18 11:28:57 +00:00
2012-08-31 22:52:05 +00:00
def _parse_partner_name ( self , text , context = None ) :
2012-08-31 17:12:47 +00:00
""" Supported syntax:
2012-08-31 22:52:05 +00:00
- ' Raoul <raoul@grosbedon.fr> ' : will find name and email address
2012-08-31 17:12:47 +00:00
- otherwise : default , everything is set as the name """
2012-08-31 22:52:05 +00:00
match = re . search ( r ' ([^ \ s,<@]+@[^> \ s,]+) ' , text )
if match :
2012-09-18 14:14:21 +00:00
email = match . group ( 1 )
2012-08-31 22:52:05 +00:00
name = text [ : text . index ( email ) ] . replace ( ' " ' , ' ' ) . replace ( ' < ' , ' ' ) . strip ( )
else :
name , email = text , ' '
return name , email
2012-08-31 17:12:47 +00:00
2012-07-13 14:22:27 +00:00
def name_create ( self , cr , uid , name , context = None ) :
2012-07-19 14:27:59 +00:00
""" Override of orm ' s name_create method for partners. The purpose is
to handle some basic formats to create partners using the
2012-07-13 14:22:27 +00:00
name_create .
2012-08-31 17:12:47 +00:00
If only an email address is received and that the regex cannot find
a name , the name will have the email value .
If ' force_email ' key in context : must find the email address . """
2012-09-03 17:48:29 +00:00
if context is None :
context = { }
2012-08-31 22:52:05 +00:00
name , email = self . _parse_partner_name ( name , context = context )
2012-08-31 17:12:47 +00:00
if context . get ( ' force_email ' ) and not email :
2012-08-21 18:04:09 +00:00
raise osv . except_osv ( _ ( ' Warning ' ) , _ ( " Couldn ' t create contact without email address ! " ) )
2012-08-31 17:12:47 +00:00
if not name and email :
name = email
2012-08-21 18:04:09 +00:00
rec_id = self . create ( cr , uid , { self . _rec_name : name or email , ' email ' : email or False } , context = context )
return self . name_get ( cr , uid , [ rec_id ] , context ) [ 0 ]
2012-07-13 14:22:27 +00:00
2009-12-09 11:42:41 +00:00
def name_search ( self , cr , uid , name , args = None , operator = ' ilike ' , context = None , limit = 100 ) :
2008-07-22 14:24:36 +00:00
if not args :
2011-10-11 16:34:35 +00:00
args = [ ]
2012-12-20 18:16:04 +00:00
if name and operator in ( ' = ' , ' ilike ' , ' =ilike ' , ' like ' , ' =like ' ) :
2012-03-20 10:02:51 +00:00
# search on the name of the contacts and of its company
2012-12-20 18:16:04 +00:00
search_name = name
if operator in ( ' ilike ' , ' like ' ) :
search_name = ' %% %s %% ' % name
if operator in ( ' =ilike ' , ' =like ' ) :
operator = operator [ 1 : ]
query_args = { ' name ' : search_name }
2012-04-17 10:18:10 +00:00
limit_str = ' '
if limit :
2012-12-20 18:16:04 +00:00
limit_str = ' limit %(limit)s '
query_args [ ' limit ' ] = limit
2012-03-29 06:29:24 +00:00
cr . execute ( ''' SELECT partner.id FROM res_partner partner
LEFT JOIN res_partner company ON partner . parent_id = company . id
2012-12-20 18:16:04 +00:00
WHERE partner . email ''' + operator + ''' % ( name ) s
OR partner . name | | ' ( ' | | COALESCE ( company . name , ' ' ) | | ' ) '
''' + operator + ' %(name)s ' + limit_str, query_args)
2012-03-20 12:48:15 +00:00
ids = map ( lambda x : x [ 0 ] , cr . fetchall ( ) )
2012-03-20 11:32:30 +00:00
if args :
ids = self . search ( cr , uid , [ ( ' id ' , ' in ' , ids ) ] + args , limit = limit , context = context )
2011-10-11 16:34:35 +00:00
if ids :
return self . name_get ( cr , uid , ids , context )
return super ( res_partner , self ) . name_search ( cr , uid , name , args , operator = operator , context = context , limit = limit )
2008-07-22 14:24:36 +00:00
2012-09-04 15:20:02 +00:00
def find_or_create ( self , cr , uid , email , context = None ) :
""" Find a partner with the given ``email`` or use :py:method:`~.name_create`
to create one
2012-09-18 14:14:21 +00:00
2012-09-04 15:20:02 +00:00
: param str email : email - like string , which should contain at least one email ,
e . g . ` ` " Raoul Grosbedon <r.g@grosbedon.fr> " ` ` """
assert email , ' an email is required for find_or_create to work '
emails = tools . email_split ( email )
if emails :
email = emails [ 0 ]
ids = self . search ( cr , uid , [ ( ' email ' , ' ilike ' , email ) ] , context = context )
if not ids :
return self . name_create ( cr , uid , email , context = context ) [ 0 ]
return ids [ 0 ]
2008-07-22 14:24:36 +00:00
def _email_send ( self , cr , uid , ids , email_from , subject , body , on_error = None ) :
partners = self . browse ( cr , uid , ids )
for partner in partners :
2012-02-21 13:08:57 +00:00
if partner . email :
tools . email_send ( email_from , [ partner . email ] , subject , body , on_error )
2008-07-22 14:24:36 +00:00
return True
def email_send ( self , cr , uid , ids , email_from , subject , body , on_error = ' ' ) :
while len ( ids ) :
self . pool . get ( ' ir.cron ' ) . create ( cr , uid , {
' name ' : ' Send Partner Emails ' ,
' user_id ' : uid ,
' model ' : ' res.partner ' ,
' function ' : ' _email_send ' ,
' args ' : repr ( [ ids [ : 16 ] , email_from , subject , body , on_error ] )
} )
ids = ids [ 16 : ]
return True
2008-09-18 11:28:57 +00:00
2011-11-07 15:19:49 +00:00
def address_get ( self , cr , uid , ids , adr_pref = None ) :
if adr_pref is None :
adr_pref = [ ' default ' ]
2012-03-06 06:49:43 +00:00
result = { }
2012-02-23 13:53:47 +00:00
# retrieve addresses from the partner itself and its children
res = [ ]
2012-03-29 11:43:31 +00:00
# need to fix the ids ,It get False value in list like ids[False]
2012-02-27 07:05:28 +00:00
if ids and ids [ 0 ] != False :
for p in self . browse ( cr , uid , ids ) :
res . append ( ( p . type , p . id ) )
res . extend ( ( c . type , c . id ) for c in p . child_ids )
2012-03-29 11:43:31 +00:00
address_dict = dict ( reversed ( res ) )
2008-09-18 11:28:57 +00:00
# get the id of the (first) default address if there is one,
2008-07-22 14:24:36 +00:00
# otherwise get the id of the first address in the list
2012-03-06 06:49:43 +00:00
default_address = False
2008-07-22 14:24:36 +00:00
if res :
2012-03-29 11:43:31 +00:00
default_address = address_dict . get ( ' default ' , res [ 0 ] [ 1 ] )
2012-03-06 06:49:43 +00:00
for adr in adr_pref :
2012-03-29 11:43:31 +00:00
result [ adr ] = address_dict . get ( adr , default_address )
2008-07-22 14:24:36 +00:00
return result
2008-09-18 11:28:57 +00:00
2008-08-25 20:15:55 +00:00
def view_header_get ( self , cr , uid , view_id , view_type , context ) :
res = super ( res_partner , self ) . view_header_get ( cr , uid , view_id , view_type , context )
if res : return res
2012-12-14 12:38:03 +00:00
if not context . get ( ' category_id ' , False ) :
2008-08-25 20:15:55 +00:00
return False
return _ ( ' Partners: ' ) + self . pool . get ( ' res.partner.category ' ) . browse ( cr , uid , context [ ' category_id ' ] , context ) . name
2012-03-06 06:49:43 +00:00
2009-12-17 19:42:50 +00:00
def main_partner ( self , cr , uid ) :
''' Return the id of the main partner
'''
model_data = self . pool . get ( ' ir.model.data ' )
2012-03-06 06:49:43 +00:00
return model_data . browse ( cr , uid ,
model_data . search ( cr , uid , [ ( ' module ' , ' = ' , ' base ' ) ,
( ' name ' , ' = ' , ' main_partner ' ) ] ) [ 0 ] ,
) . res_id
2012-06-25 18:22:29 +00:00
def _display_address ( self , cr , uid , address , without_company = False , context = None ) :
2012-03-23 06:40:37 +00:00
2012-02-27 10:05:30 +00:00
'''
The purpose of this function is to build and return an address formatted accordingly to the
standards of the country where it belongs .
2012-12-11 18:29:34 +00:00
: param address : browse record of the res . partner to format
2012-02-27 10:05:30 +00:00
: returns : the address formatted in a display that fit its country habits ( or the default ones
if not country is specified )
: rtype : string
'''
2012-03-06 06:49:43 +00:00
2012-03-06 06:09:34 +00:00
# get the information that will be injected into the display format
2012-02-27 10:05:30 +00:00
# get the address format
address_format = address . country_id and address . country_id . address_format or \
2012-09-11 10:17:29 +00:00
" %(street)s \n %(street2)s \n %(city)s %(state_code)s %(zip)s \n %(country_name)s "
2012-02-27 10:05:30 +00:00
args = {
' state_code ' : address . state_id and address . state_id . code or ' ' ,
' state_name ' : address . state_id and address . state_id . name or ' ' ,
' country_code ' : address . country_id and address . country_id . code or ' ' ,
' country_name ' : address . country_id and address . country_id . name or ' ' ,
2012-03-05 06:34:33 +00:00
' company_name ' : address . parent_id and address . parent_id . name or ' ' ,
2012-02-27 10:05:30 +00:00
}
address_field = [ ' title ' , ' street ' , ' street2 ' , ' zip ' , ' city ' ]
for field in address_field :
args [ field ] = getattr ( address , field ) or ' '
2012-06-25 18:22:29 +00:00
if without_company :
args [ ' company_name ' ] = ' '
2012-09-11 10:17:29 +00:00
elif address . parent_id :
address_format = ' %(company_name)s \n ' + address_format
2012-02-27 10:05:30 +00:00
return address_format % args
2012-03-06 06:49:43 +00:00
2008-07-23 15:01:27 +00:00
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4: