[IMP] document: add new field company_id in document and directory model
[odoo/odoo.git] / addons / document / document.py
1 # -*- coding: utf-8 -*-
2 ##############################################################################
3 #
4 #    OpenERP, Open Source Management Solution
5 #    Copyright (C) 2004-2010 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 import base64
23
24 from osv import osv, fields
25 import urlparse
26
27 import os
28
29 import pooler
30 import netsvc
31 #import StringIO
32
33 from psycopg2 import Binary
34 #from tools import config
35 import tools
36 from tools.translate import _
37 import nodes
38
39 DMS_ROOT_PATH = tools.config.get('document_path', os.path.join(tools.config['root_path'], 'filestore'))
40
41 class document_file(osv.osv):
42     _inherit = 'ir.attachment'
43     _rec_name = 'datas_fname'
44     def _get_filestore(self, cr):
45         return os.path.join(DMS_ROOT_PATH, cr.dbname)
46
47     def _data_get(self, cr, uid, ids, name, arg, context):
48         fbrl = self.browse(cr, uid, ids, context=context)
49         nctx = nodes.get_node_context(cr, uid, context)
50         result = {}
51         bin_size = context.get('bin_size', False)
52         for fbro in fbrl:
53                 fnode = nodes.node_file(None, None, nctx, fbro)
54                 if not bin_size:
55                         data = fnode.get_data(cr, fbro)
56                         result[fbro.id] = base64.encodestring(data or '')
57                 else:
58                         result[fbro.id] = fnode.get_data_len(cr, fbro)
59
60         return result
61
62     #
63     # This code can be improved
64     #
65     def _data_set(self, cr, uid, id, name, value, arg, context):
66         if not value:
67             return True
68         fbro = self.browse(cr, uid, id, context=context)
69         nctx = nodes.get_node_context(cr, uid, context)
70         fnode = nodes.node_file(None, None, nctx, fbro)
71         res = fnode.set_data(cr, base64.decodestring(value), fbro)
72         return res
73
74     _columns = {
75         'user_id': fields.many2one('res.users', 'Owner', select=1),
76         'group_ids': fields.many2many('res.groups', 'document_group_rel', 'item_id', 'group_id', 'Groups'),
77         # the directory id now is mandatory. It can still be computed automatically.
78         'parent_id': fields.many2one('document.directory', 'Directory', select=1),
79         'file_size': fields.integer('File Size', required=True),
80         'file_type': fields.char('Content Type', size=128),
81         # If ir.attachment contained any data before document is installed, preserve
82         # the data, don't drop the column!
83         'db_datas': fields.binary('Data', oldname='datas'),
84         'index_content': fields.text('Indexed Content'),
85         'write_date': fields.datetime('Date Modified', readonly=True),
86         'write_uid':  fields.many2one('res.users', 'Last Modification User', readonly=True),
87         'create_date': fields.datetime('Date Created', readonly=True),
88         'create_uid':  fields.many2one('res.users', 'Creator', readonly=True),
89         'store_method': fields.selection([('db', 'Database'), ('fs', 'Filesystem'), ('link', 'Link')], "Storing Method"),
90         'datas': fields.function(_data_get, method=True, fnct_inv=_data_set, string='File Content', type="binary", nodrop=True),
91         'url': fields.char('File URL',size=64),
92         'store_fname': fields.char('Stored Filename', size=200),
93         'res_model': fields.char('Attached Model', size=64), #res_model
94         'res_id': fields.integer('Attached ID'), #res_id
95         'partner_id':fields.many2one('res.partner', 'Partner', select=1),
96         'type':fields.selection([
97             ('url','URL'),
98             ('binary','Binary'),
99
100         ],'Type', help="Type is used to separate URL and binary File"),
101         'company_id': fields.many2one('res.company', 'Company'),
102     }
103
104     def __get_def_directory(self, cr, uid, context=None):
105         dirobj = self.pool.get('document.directory')
106         return dirobj._get_root_directory(cr, uid, context)
107
108     _defaults = {
109         'company_id': lambda s,cr,uid,c: s.pool.get('res.company')._company_default_get(cr, uid, 'ir.attachment', context=c),
110         'user_id': lambda self, cr, uid, ctx:uid,
111         'file_size': lambda self, cr, uid, ctx:0,
112         'store_method': lambda *args: 'db',
113         'type': 'binary',
114         'parent_id': __get_def_directory
115     }
116     _sql_constraints = [
117         ('filename_uniq', 'unique (name,parent_id,res_id,res_model)', 'The file name must be unique !')
118     ]
119     def _check_duplication(self, cr, uid, vals, ids=[], op='create'):
120         name = vals.get('name', False)
121         parent_id = vals.get('parent_id', False)
122         res_model = vals.get('res_model', False)
123         res_id = vals.get('res_id', 0)
124         if op == 'write':
125             for file in self.browse(cr, uid, ids):
126                 if not name:
127                     name = file.name
128                 if not parent_id:
129                     parent_id = file.parent_id and file.parent_id.id or False
130                 if not res_model:
131                     res_model = file.res_model and file.res_model or False
132                 if not res_id:
133                     res_id = file.res_id and file.res_id or 0
134                 res = self.search(cr, uid, [('id', '<>', file.id), ('name', '=', name), ('parent_id', '=', parent_id), ('res_model', '=', res_model), ('res_id', '=', res_id)])
135                 if len(res):
136                     return False
137         if op == 'create':
138             res = self.search(cr, uid, [('name', '=', name), ('parent_id', '=', parent_id), ('res_id', '=', res_id), ('res_model', '=', res_model)])
139             if len(res):
140                 return False
141         return True
142
143     def copy(self, cr, uid, id, default=None, context=None):
144         if not default:
145             default = {}
146         if 'name' not in default:
147             name = self.read(cr, uid, [id])[0]['name']
148             default.update({'name': name + " (copy)"})
149         return super(document_file, self).copy(cr, uid, id, default, context)
150
151     def write(self, cr, uid, ids, vals, context=None):
152         if not isinstance(ids, list):
153             ids = [ids]
154         res = self.search(cr, uid, [('id', 'in', ids)])
155         if not len(res):
156             return False
157         if not self._check_duplication(cr, uid, vals, ids, 'write'):
158             raise osv.except_osv(_('ValidateError'), _('File name must be unique!'))
159         result = super(document_file, self).write(cr, uid, ids, vals, context=context)
160         cr.commit()
161         return result
162
163     def create(self, cr, uid, vals, context=None):
164         if not context:
165             context = {}
166         vals['parent_id'] = context.get('parent_id', False) or vals.get('parent_id', False)
167         if not vals['parent_id']:
168             vals['parent_id'] = self.pool.get('document.directory')._get_root_directory(cr,uid, context)
169         if not vals.get('res_id', False) and context.get('default_res_id', False):
170             vals['res_id'] = context.get('default_res_id', False)
171         if not vals.get('res_model', False) and context.get('default_res_model', False):
172             vals['res_model'] = context.get('default_res_model', False)
173         if vals.get('res_id', False) and vals.get('res_model', False):
174             obj_model = self.pool.get(vals['res_model'])
175             result = obj_model.read(cr, uid, [vals['res_id']], ['name', 'partner_id', 'address_id'], context=context)
176             if len(result):
177                 obj = result[0]
178                 if obj_model._name == 'res.partner':
179                     vals['partner_id'] = obj['id']
180                 elif obj.get('address_id', False):
181                     if isinstance(obj['address_id'], tuple) or isinstance(obj['address_id'], list):
182                         address_id = obj['address_id'][0]
183                     else:
184                         address_id = obj['address_id']
185                     address = self.pool.get('res.partner.address').read(cr, uid, [address_id], context=context)
186                     if len(address):
187                         vals['partner_id'] = address[0]['partner_id'][0] or False
188                 elif obj.get('partner_id', False):
189                     if isinstance(obj['partner_id'], tuple) or isinstance(obj['partner_id'], list):
190                         vals['partner_id'] = obj['partner_id'][0]
191                     else:
192                         vals['partner_id'] = obj['partner_id']
193
194         datas = None
195         if vals.get('link', False) :
196             import urllib
197             datas = base64.encodestring(urllib.urlopen(vals['link']).read())
198         else:
199             datas = vals.get('datas', False)
200
201         vals['file_size'] = datas and len(datas) or 0
202         if not self._check_duplication(cr, uid, vals):
203             raise osv.except_osv(_('ValidateError'), _('File name must be unique!'))
204         result = super(document_file, self).create(cr, uid, vals, context)
205         cr.commit()
206         return result
207
208     def unlink(self, cr, uid, ids, context={}):
209         stor = self.pool.get('document.storage')
210         unres = []
211         # We have to do the unlink in 2 stages: prepare a list of actual
212         # files to be unlinked, update the db (safer to do first, can be
213         # rolled back) and then unlink the files. The list wouldn't exist
214         # after we discard the objects
215
216         for f in self.browse(cr, uid, ids, context):
217             # TODO: update the node cache
218             r = stor.prepare_unlink(cr, uid, f.parent_id.storage_id, f)
219             if r:
220                 unres.append(r)
221         res = super(document_file, self).unlink(cr, uid, ids, context)
222         stor.do_unlink(cr, uid, unres)
223         return res
224
225 document_file()
226