7a6b700783353f8624890390380e87f879fb0bb2
[odoo/odoo.git] / openerp / addons / base / res / res_company.py
1 # -*- coding: utf-8 -*-
2 ##############################################################################
3 #
4 #    OpenERP, Open Source Management Solution
5 #    Copyright (C) 2004-2009 Tiny SPRL (<http://tiny.be>).
6 #
7 #    This program is free software: you can redistribute it and/or modify
8 #    it under the terms of the GNU Affero General Public License as
9 #    published by the Free Software Foundation, either version 3 of the
10 #    License, or (at your option) any later version.
11 #
12 #    This program is distributed in the hope that it will be useful,
13 #    but WITHOUT ANY WARRANTY; without even the implied warranty of
14 #    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15 #    GNU Affero General Public License for more details.
16 #
17 #    You should have received a copy of the GNU Affero General Public License
18 #    along with this program.  If not, see <http://www.gnu.org/licenses/>.
19 #
20 ##############################################################################
21
22 from osv import osv
23 from osv import fields
24 import os
25 import tools
26 from tools.translate import _
27 from tools.safe_eval import safe_eval as eval
28
29 class multi_company_default(osv.osv):
30     """
31     Manage multi company default value
32     """
33     _name = 'multi_company.default'
34     _description = 'Default multi company'
35     _order = 'company_id,sequence,id'
36
37     _columns = {
38         'sequence': fields.integer('Sequence'),
39         'name': fields.char('Name', size=256, required=True, help='Name it to easily find a record'),
40         'company_id': fields.many2one('res.company', 'Main Company', required=True,
41             help='Company where the user is connected'),
42         'company_dest_id': fields.many2one('res.company', 'Default Company', required=True,
43             help='Company to store the current record'),
44         'object_id': fields.many2one('ir.model', 'Object', required=True,
45             help='Object affected by this rule'),
46         'expression': fields.char('Expression', size=256, required=True,
47             help='Expression, must be True to match\nuse context.get or user (browse)'),
48         'field_id': fields.many2one('ir.model.fields', 'Field', help='Select field property'),
49     }
50
51     _defaults = {
52         'expression': lambda *a: 'True',
53         'sequence': lambda *a: 100,
54     }
55
56     def copy(self, cr, uid, id, default=None, context=None):
57         """
58         Add (copy) in the name when duplicate record
59         """
60         if not context:
61             context = {}
62         if not default:
63             default = {}
64         company = self.browse(cr, uid, id, context=context)
65         default = default.copy()
66         default['name'] = company.name + _(' (copy)')
67         return super(multi_company_default, self).copy(cr, uid, id, default, context=context)
68
69 multi_company_default()
70
71 class res_company(osv.osv):
72     _name = "res.company"
73     _description = 'Companies'
74     _order = 'name'
75
76     def _get_address_data(self, cr, uid, ids, field_names, arg, context=None):
77         """ Read the 'address' functional fields. """
78         result = {}
79         part_obj = self.pool.get('res.partner')
80         address_obj = self.pool.get('res.partner.address')
81         for company in self.browse(cr, uid, ids, context=context):
82             result[company.id] = {}.fromkeys(field_names, False)
83             if company.partner_id:
84                 address_data = part_obj.address_get(cr, uid, [company.partner_id.id], adr_pref=['default'])
85                 if address_data['default']:
86                     address = address_obj.read(cr, uid, address_data['default'], field_names, context=context)
87                     for field in field_names:
88                         result[company.id][field] = address[field] or False
89         return result
90
91
92     def _get_bank_data(self, cr, uid, ids, field_names, arg, context=None):
93         """ Read the 'address' functional fields. """
94         result = {}
95         for company in self.browse(cr, uid, ids, context=context):
96             r = []
97             for bank in company.bank_ids:
98                 if bank.footer:
99                     r.append(bank.name_get(context=context)[0][1])
100             result[company.id] = ' | '.join(r)
101         return result
102
103     def _set_address_data(self, cr, uid, company_id, name, value, arg, context=None):
104         """ Write the 'address' functional fields. """
105         company = self.browse(cr, uid, company_id, context=context)
106         if company.partner_id:
107             part_obj = self.pool.get('res.partner')
108             address_obj = self.pool.get('res.partner.address')
109             address_data = part_obj.address_get(cr, uid, [company.partner_id.id], adr_pref=['default'])
110             address = address_data['default']
111             if address:
112                 address_obj.write(cr, uid, [address], {name: value or False})
113             else:
114                 address_obj.create(cr, uid, {name: value or False, 'partner_id': company.partner_id.id}, context=context)
115         return True
116
117
118     _columns = {
119         'name': fields.related('partner_id', 'name', string='Company Name', size=64, required=True, store=True, type='char'),
120         'parent_id': fields.many2one('res.company', 'Parent Company', select=True),
121         'child_ids': fields.one2many('res.company', 'parent_id', 'Child Companies'),
122         'partner_id': fields.many2one('res.partner', 'Partner', required=True),
123         'rml_header1': fields.char('Report Header / Company Slogan', size=200),
124         'rml_footer1': fields.char('General Information Footer', size=200),
125         'rml_footer2': fields.function(_get_bank_data, type="char", string='Bank Accounts Footer', size=250, help="This field is computed automatically based on bank accounts defined, having the display on footer checkbox set."),
126         'rml_header': fields.text('RML Header', required=True),
127         'rml_header2': fields.text('RML Internal Header', required=True),
128         'rml_header3': fields.text('RML Internal Header', required=True),
129         'logo': fields.binary('Logo'),
130         'currency_id': fields.many2one('res.currency', 'Currency', required=True),
131         'currency_ids': fields.one2many('res.currency', 'company_id', 'Currency'),
132         'user_ids': fields.many2many('res.users', 'res_company_users_rel', 'cid', 'user_id', 'Accepted Users'),
133         'account_no':fields.char('Account No.', size=64),
134         'street': fields.function(_get_address_data, fnct_inv=_set_address_data, size=128, type='char', string="Street", multi='address'), 
135         'street2': fields.function(_get_address_data, fnct_inv=_set_address_data, size=128, type='char', string="Street2", multi='address'), 
136         'zip': fields.function(_get_address_data, fnct_inv=_set_address_data, size=24, type='char', string="Zip", multi='address'), 
137         'city': fields.function(_get_address_data, fnct_inv=_set_address_data, size=24, type='char', string="City", multi='address'),         
138         'state_id': fields.function(_get_address_data, fnct_inv=_set_address_data, type='many2one', domain="[('country_id', '=', country_id)]", relation='res.country.state', string="State", multi='address'), 
139         'bank_ids': fields.one2many('res.partner.bank','company_id', 'Bank Accounts', help='Bank accounts related to this company'),
140         'country_id': fields.function(_get_address_data, fnct_inv=_set_address_data, type='many2one', relation='res.country', string="Country", multi='address'), 
141         'email': fields.function(_get_address_data, fnct_inv=_set_address_data, size=64, type='char', string="Email", multi='address'), 
142         'phone': fields.function(_get_address_data, fnct_inv=_set_address_data, size=64, type='char', string="Phone", multi='address'), 
143         'fax': fields.function(_get_address_data, fnct_inv=_set_address_data, size=64, type='char', string="Fax", multi='address'), 
144         'website': fields.related('partner_id', 'website', string="Website", type="char", size=64), 
145         'vat': fields.related('partner_id', 'vat', string="Tax ID", type="char", size=32), 
146         'company_registry': fields.char('Company Registry', size=64),
147     }
148     _sql_constraints = [
149         ('name_uniq', 'unique (name)', 'The company name must be unique !')
150     ]
151     def on_change_header(self, cr, uid, ids, phone, email, fax, website, vat, reg=False, context=None):
152         val = []
153         if phone: val.append(_('Phone: ')+phone)
154         if fax: val.append(_('Fax: ')+fax)
155         if website: val.append(_('Website: ')+website)
156         if vat: val.append(_('VAT: ')+vat)
157         if reg: val.append(_('Reg: ')+reg)
158         return {'value': {'rml_footer1':' | '.join(val)}}
159
160
161     def _search(self, cr, uid, args, offset=0, limit=None, order=None,
162             context=None, count=False, access_rights_uid=None):
163
164         if context is None:
165             context = {}
166         user_preference = context.get('user_preference', False)
167         if user_preference:
168             # We browse as superuser. Otherwise, the user would be able to
169             # select only the currently visible companies (according to rules,
170             # which are probably to allow to see the child companies) even if
171             # she belongs to some other companies.
172             user = self.pool.get('res.users').browse(cr, 1, uid, context=context)
173             cmp_ids = list(set([user.company_id.id] + [cmp.id for cmp in user.company_ids]))
174             return cmp_ids
175         return super(res_company, self)._search(cr, uid, args, offset=offset, limit=limit, order=order,
176             context=context, count=count, access_rights_uid=access_rights_uid)
177
178     def _company_default_get(self, cr, uid, object=False, field=False, context=None):
179         """
180         Check if the object for this company have a default value
181         """
182         if not context:
183             context = {}
184         proxy = self.pool.get('multi_company.default')
185         args = [
186             ('object_id.model', '=', object),
187             ('field_id', '=', field),
188         ]
189
190         ids = proxy.search(cr, uid, args, context=context)
191         user = self.pool.get('res.users').browse(cr, uid, uid, context=context)
192         for rule in proxy.browse(cr, uid, ids, context):
193             if eval(rule.expression, {'context': context, 'user': user}):
194                 return rule.company_dest_id.id
195         return user.company_id.id
196
197     @tools.ormcache()
198     def _get_company_children(self, cr, uid=None, company=None):
199         if not company:
200             return []
201         ids =  self.search(cr, uid, [('parent_id','child_of',[company])])
202         return ids
203
204     def _get_partner_hierarchy(self, cr, uid, company_id, context=None):
205         if company_id:
206             parent_id = self.browse(cr, uid, company_id)['parent_id']
207             if parent_id:
208                 return self._get_partner_hierarchy(cr, uid, parent_id.id, context)
209             else:
210                 return self._get_partner_descendance(cr, uid, company_id, [], context)
211         return []
212
213     def _get_partner_descendance(self, cr, uid, company_id, descendance, context=None):
214         descendance.append(self.browse(cr, uid, company_id).partner_id.id)
215         for child_id in self._get_company_children(cr, uid, company_id):
216             if child_id != company_id:
217                 descendance = self._get_partner_descendance(cr, uid, child_id, descendance)
218         return descendance
219
220     #
221     # This function restart the cache on the _get_company_children method
222     #
223     def cache_restart(self, cr):
224         self._get_company_children.clear_cache(self)
225
226     def create(self, cr, uid, vals, context=None):
227         if not vals.get('name', False) or vals.get('partner_id', False):
228             self.cache_restart(cr)
229             return super(res_company, self).create(cr, uid, vals, context=context)
230         obj_partner = self.pool.get('res.partner')
231         partner_id = obj_partner.create(cr, uid, {'name': vals['name']}, context=context)
232         vals.update({'partner_id': partner_id})
233         self.cache_restart(cr)
234         company_id = super(res_company, self).create(cr, uid, vals, context=context)
235         obj_partner.write(cr, uid, partner_id, {'company_id': company_id}, context=context)
236         return company_id
237
238     def write(self, cr, *args, **argv):
239         self.cache_restart(cr)
240         return super(res_company, self).write(cr, *args, **argv)
241
242     def _get_euro(self, cr, uid, context=None):
243         try:
244             return self.pool.get('res.currency').search(cr, uid, [])[0]
245         except:
246             return False
247
248     def _get_logo(self, cr, uid, ids):
249         return open(os.path.join( tools.config['root_path'], 'addons', 'base', 'res', 'res_company_logo.png'), 'rb') .read().encode('base64')
250
251     _header = """
252 <header>
253 <pageTemplate>
254     <frame id="first" x1="28.0" y1="28.0" width="%s" height="%s"/>
255     <pageGraphics>
256         <fill color="black"/>
257         <stroke color="black"/>
258         <setFont name="DejaVu Sans" size="8"/>
259         <drawString x="%s" y="%s"> [[ formatLang(time.strftime("%%Y-%%m-%%d"), date=True) ]]  [[ time.strftime("%%H:%%M") ]]</drawString>
260         <setFont name="DejaVu Sans Bold" size="10"/>
261         <drawCentredString x="%s" y="%s">[[ company.partner_id.name ]]</drawCentredString>
262         <stroke color="#000000"/>
263         <lines>%s</lines>
264     </pageGraphics>
265 </pageTemplate>
266 </header>"""
267
268     _header2 = _header % (539, 772, "1.0cm", "28.3cm", "11.1cm", "28.3cm", "1.0cm 28.1cm 20.1cm 28.1cm")
269
270     _header3 = _header % (786, 525, 25, 555, 440, 555, "25 550 818 550")
271
272     def _get_header(self,cr,uid,ids):
273         try :
274             header_file = tools.file_open(os.path.join('base', 'report', 'corporate_rml_header.rml'))
275             try:
276                 return header_file.read()
277             finally:
278                 header_file.close()
279         except:
280             return """
281     <header>
282     <pageTemplate>
283         <frame id="first" x1="1.3cm" y1="2.5cm" height="23.0cm" width="19cm"/>
284         <pageGraphics>
285             <!-- You Logo - Change X,Y,Width and Height -->
286             <image x="1.3cm" y="27.6cm" height="40.0" >[[ company.logo or removeParentNode('image') ]]</image>
287             <setFont name="DejaVu Sans" size="8"/>
288             <fill color="black"/>
289             <stroke color="black"/>
290             <lines>1.3cm 27.7cm 20cm 27.7cm</lines>
291
292             <drawRightString x="20cm" y="27.8cm">[[ company.rml_header1 ]]</drawRightString>
293
294
295             <drawString x="1.3cm" y="27.2cm">[[ company.partner_id.name ]]</drawString>
296             <drawString x="1.3cm" y="26.8cm">[[ company.partner_id.address and company.partner_id.address[0].street or  '' ]]</drawString>
297             <drawString x="1.3cm" y="26.4cm">[[ company.partner_id.address and company.partner_id.address[0].zip or '' ]] [[ company.partner_id.address and company.partner_id.address[0].city or '' ]] - [[ company.partner_id.address and company.partner_id.address[0].country_id and company.partner_id.address[0].country_id.name  or '']]</drawString>
298             <drawString x="1.3cm" y="26.0cm">Phone:</drawString>
299             <drawRightString x="7cm" y="26.0cm">[[ company.partner_id.address and company.partner_id.address[0].phone or '' ]]</drawRightString>
300             <drawString x="1.3cm" y="25.6cm">Mail:</drawString>
301             <drawRightString x="7cm" y="25.6cm">[[ company.partner_id.address and company.partner_id.address[0].email or '' ]]</drawRightString>
302             <lines>1.3cm 25.5cm 7cm 25.5cm</lines>
303
304             <!--page bottom-->
305
306             <lines>1.2cm 2.15cm 19.9cm 2.15cm</lines>
307
308             <drawCentredString x="10.5cm" y="1.7cm">[[ company.rml_footer1 ]]</drawCentredString>
309             <drawCentredString x="10.5cm" y="1.25cm">[[ company.rml_footer2 ]]</drawCentredString>
310             <drawCentredString x="10.5cm" y="0.8cm">Contact : [[ user.name ]] - Page: <pageNumber/></drawCentredString>
311         </pageGraphics>
312     </pageTemplate>
313 </header>"""
314     _defaults = {
315         'currency_id': _get_euro,
316         'rml_header':_get_header,
317         'rml_header2': _header2,
318         'rml_header3': _header3,
319         'logo':_get_logo
320     }
321
322     _constraints = [
323         (osv.osv._check_recursion, 'Error! You can not create recursive companies.', ['parent_id'])
324     ]
325
326
327 res_company()
328
329 # vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
330