merge
[odoo/odoo.git] / addons / document / document.py
1 # -*- encoding: utf-8 -*-
2 ##############################################################################
3 #
4 #    OpenERP, Open Source Management Solution
5 #    Copyright (C) 2004-2008 Tiny SPRL (<http://tiny.be>). All Rights Reserved
6 #    $Id$
7 #
8 #    This program is free software: you can redistribute it and/or modify
9 #    it under the terms of the GNU General Public License as published by
10 #    the Free Software Foundation, either version 3 of the License, or
11 #    (at your option) any later version.
12 #
13 #    This program is distributed in the hope that it will be useful,
14 #    but WITHOUT ANY WARRANTY; without even the implied warranty of
15 #    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16 #    GNU General Public License for more details.
17 #
18 #    You should have received a copy of the GNU General Public License
19 #    along with this program.  If not, see <http://www.gnu.org/licenses/>.
20 #
21 ##############################################################################
22
23 import base64
24
25 from osv import osv, fields
26 from osv.orm import except_orm
27 import urlparse
28
29 import os
30
31 import pooler
32 from content_index import content_index
33 import netsvc
34 import StringIO
35
36 # Unsupported WebDAV Commands:
37 #     label
38 #     search
39 #     checkin
40 #     checkout
41 #     propget
42 #     propset
43
44 #
45 # An object that represent an uri
46 #   path: the uri of the object
47 #   content: the Content it belongs to (_print.pdf)
48 #   type: content or collection
49 #       content: objct = res.partner
50 #       collection: object = directory, object2 = res.partner
51 #       file: objct = ir.attachement
52 #   root: if we are at the first directory of a ressource
53 #
54 INVALID_CHARS={'*':str(hash('*')), '|':str(hash('|')) , "\\":str(hash("\\")), '/':'__', ':':str(hash(':')), '"':str(hash('"')), '<':str(hash('<')) , '>':str(hash('>')) , '?':str(hash('?'))}
55 class node_class(object):
56     def __init__(self, cr, uid, path,object,object2=False, context={}, content=False, type='collection', root=False):
57         self.cr = cr
58         self.uid = uid
59         self.path = path
60         self.object = object
61         self.object2 = object2
62         self.context = context
63         self.content = content
64         self.type=type
65         self.root=root
66
67     def _file_get(self, nodename=False):
68         if not self.object:
69             return []
70         pool = pooler.get_pool(self.cr.dbname)
71         fobj = pool.get('ir.attachment')
72         res2 = []
73         where = []
74         if self.object2:
75             where.append( ('res_model','=',self.object2._name) )
76             where.append( ('res_id','=',self.object2.id) )
77             for content in self.object.content_ids:
78                 if self.object2 or not content.include_name:
79                     if content.include_name:
80                         test_nodename = self.object2.name + (content.suffix or '') + (content.extension or '')
81                     else:
82                         test_nodename = (content.suffix or '') + (content.extension or '')
83                     if test_nodename.find('/'):
84                         test_nodename=test_nodename.replace('/', '_')
85                     path = self.path+'/'+test_nodename
86                     #path = self.path+'/'+self.object2.name + (content.suffix or '') + (content.extension or '')
87                     if not nodename:
88                         n = node_class(self.cr, self.uid,path, self.object2, False, content=content, type='content', root=False)
89                         res2.append( n)
90                     else:
91                         if nodename == test_nodename:
92                             n = node_class(self.cr, self.uid, path, self.object2, False, content=content, type='content', root=False)
93                             res2.append(n)
94         else:
95             where.append( ('parent_id','=',self.object.id) )
96             where.append( ('res_id','=',False) )
97         if nodename:
98             where.append( (fobj._rec_name,'=',nodename) )
99         ids = fobj.search(self.cr, self.uid, where+[ ('parent_id','=',self.object and self.object.id or False) ], context=self.context)
100         if self.object and self.root and (self.object.type=='ressource'):
101             ids += fobj.search(self.cr, self.uid, where+[ ('parent_id','=',False) ], context=self.context)
102         res = fobj.browse(self.cr, self.uid, ids, context=self.context)
103         return map(lambda x: node_class(self.cr, self.uid, self.path+'/'+x.name, x, False, type='file', root=False), res) + res2
104
105     def directory_list_for_child(self,nodename,parent=False):
106         pool = pooler.get_pool(self.cr.dbname)
107         where = []
108         if nodename:
109             where.append(('name','=',nodename))
110         if (self.object and self.object.type=='directory') or not self.object2:
111             where.append(('parent_id','=',self.object and self.object.id or False))
112         else:
113             where.append(('parent_id','=',False))
114         if self.object:
115             where.append(('ressource_parent_type_id','=',self.object.ressource_type_id.id))
116         else:
117             where.append(('ressource_parent_type_id','=',False))
118
119         ids = pool.get('document.directory').search(self.cr, self.uid, where+[('ressource_id','=',0)], self.context)
120         if self.object2:
121             ids += pool.get('document.directory').search(self.cr, self.uid, where+[('ressource_id','=',self.object2.id)], self.context)
122         res = pool.get('document.directory').browse(self.cr, self.uid, ids,self.context)
123         return res
124
125     def _child_get(self, nodename=False):
126         if self.type not in ('collection','database'):
127             return []
128         res = self.directory_list_for_child(nodename)
129         result= map(lambda x: node_class(self.cr, self.uid, self.path+'/'+x.name, x, x.type=='directory' and self.object2 or False, root=self.root), res)
130         if self.type=='database':
131             pool = pooler.get_pool(self.cr.dbname)
132             fobj = pool.get('ir.attachment')
133             vargs = [('parent_id','=',False),('res_id','=',False)]
134             if nodename:
135                 vargs.append(('name','=',nodename))
136             file_ids=fobj.search(self.cr,self.uid,vargs)
137
138             res = fobj.browse(self.cr, self.uid, file_ids, context=self.context)
139             result +=map(lambda x: node_class(self.cr, self.uid, self.path+'/'+x.name, x, False, type='file', root=self.root), res)
140         if self.type=='collection' and self.object.type=="ressource":
141             where = self.object.domain and eval(self.object.domain, {'active_id':self.root}) or []
142             pool = pooler.get_pool(self.cr.dbname)
143             obj = pool.get(self.object.ressource_type_id.model)
144
145             if self.object.ressource_tree:
146                 if obj._parent_name in obj.fields_get(self.cr,self.uid):
147                     where.append((obj._parent_name,'=',self.object2 and self.object2.id or False))
148                 else :
149                     if self.object2:
150                         return result
151             else:
152                 if self.object2:
153                     return result
154
155             name_for = obj._name.split('.')[-1]
156             if nodename  and nodename.find(name_for) == 0  :
157                 id = int(nodename.replace(name_for,''))
158                 where.append(('id','=',id))
159             elif nodename:
160                 if nodename.find('__') :
161                     nodename=nodename.replace('__','/')
162                 for invalid in INVALID_CHARS:
163                     if nodename.find(INVALID_CHARS[invalid]) :
164                         nodename=nodename.replace(INVALID_CHARS[invalid],invalid)
165                 where.append(('name','=',nodename))
166             ids = obj.search(self.cr, self.uid, where, self.context)
167             res = obj.browse(self.cr, self.uid, ids,self.context)
168             for r in res:
169                 if not r.name:
170                     r.name = name_for+'%d'%r.id
171                 for invalid in INVALID_CHARS:
172                     if r.name.find(invalid) :
173                         r.name=r.name.replace(invalid,INVALID_CHARS[invalid])
174             result2 = map(lambda x: node_class(self.cr, self.uid, self.path+'/'+x.name.replace('/','__'), self.object, x, root=r.id), res)
175             if result2:
176                 result = result2
177         return result
178
179     def children(self):
180         return self._child_get() + self._file_get()
181
182     def child(self, name):
183         res = self._child_get(name)
184         if res:
185             return res[0]
186         res = self._file_get(name)
187         if res:
188             return res[0]
189         return None
190
191     def path_get(self):
192         path = self.path
193         if self.path[0]=='/':
194             path = self.path[1:]
195         return path
196
197 class document_directory(osv.osv):
198     _name = 'document.directory'
199     _description = 'Document directory'
200     _columns = {
201         'name': fields.char('Name', size=64, required=True, select=1),
202         'write_date': fields.datetime('Date Modified', readonly=True),
203         'write_uid':  fields.many2one('res.users', 'Last Modification User', readonly=True),
204         'create_date': fields.datetime('Date Created', readonly=True),
205         'create_uid':  fields.many2one('res.users', 'Creator', readonly=True),
206         'file_type': fields.char('Content Type', size=32),
207         'domain': fields.char('Domain', size=128),
208         'user_id': fields.many2one('res.users', 'Owner'),
209         'group_ids': fields.many2many('res.groups', 'document_directory_group_rel', 'item_id', 'group_id', 'Groups'),
210         'parent_id': fields.many2one('document.directory', 'Parent Item'),
211         'child_ids': fields.one2many('document.directory', 'parent_id', 'Childs'),
212         'file_ids': fields.one2many('ir.attachment', 'parent_id', 'Files'),
213         'content_ids': fields.one2many('document.directory.content', 'directory_id', 'Virtual Files'),
214         'type': fields.selection([('directory','Static Directory'),('ressource','Other Ressources')], 'Type', required=True),
215         'ressource_type_id': fields.many2one('ir.model', 'Childs Model'),
216         'ressource_parent_type_id': fields.many2one('ir.model', 'Linked Model'),
217         'ressource_id': fields.integer('Ressource ID'),
218         'ressource_tree': fields.boolean('Tree Structure'),
219     }
220     _defaults = {
221         'user_id': lambda self,cr,uid,ctx: uid,
222         'domain': lambda self,cr,uid,ctx: '[]',
223         'type': lambda *args: 'directory',
224         'ressource_id': lambda *a: 0
225     }
226     _sql_constraints = [
227         ('dirname_uniq', 'unique (name,parent_id,ressource_id,ressource_parent_type_id)', 'The directory name must be unique !')
228     ]
229
230     def get_resource_path(self,cr,uid,dir_id,res_model,res_id):
231         # this method will be used in process module
232         # to be need test and Improvement if resource dir has parent resource (link resource)
233         path=[]
234         def _parent(dir_id,path):
235             parent=self.browse(cr,uid,dir_id)
236             if parent.parent_id and not parent.ressource_parent_type_id:
237                 _parent(parent.parent_id.id,path)
238                 path.append(parent.name)
239             else:
240                 path.append(parent.name)
241                 return path
242
243         directory=self.browse(cr,uid,dir_id)
244         model_ids=self.pool.get('ir.model').search(cr,uid,[('model','=',res_model)])
245         if directory:
246             _parent(dir_id,path)
247             path.append(self.pool.get(directory.ressource_type_id.model).browse(cr,uid,res_id).name)
248             user=self.pool.get('res.users').browse(cr,uid,uid)
249             return "ftp://%s:%s@localhost:8021/%s/%s"%(user.login,user.password,cr.dbname,'/'.join(path))
250         return False
251     def _check_recursion(self, cr, uid, ids):
252         level = 100
253         while len(ids):
254             cr.execute('select distinct parent_id from document_directory where id in ('+','.join(map(str,ids))+')')
255             ids = filter(None, map(lambda x:x[0], cr.fetchall()))
256             if not level:
257                 return False
258             level -= 1
259         return True
260
261     _constraints = [
262         (_check_recursion, 'Error! You can not create recursive Directories.', ['parent_id'])
263     ]
264     def __init__(self, *args, **kwargs):
265         res = super(document_directory, self).__init__(*args, **kwargs)
266         self._cache = {}
267         return res
268
269     def onchange_content_id(self, cr, uid, ids, ressource_type_id):
270         return {}
271
272     def _get_childs(self, cr, uid, node, nodename=False, context={}):
273         where = []
274         if nodename:
275             where.append(('name','=',nodename))
276         if object:
277             where.append(('parent_id','=',object.id))
278         ids = self.search(cr, uid, where, context)
279         return self.browse(cr, uid, ids, context), False
280
281     """
282         PRE:
283             uri: of the form "Sales Order/SO001"
284         PORT:
285             uri
286             object: the object.directory or object.directory.content
287             object2: the other object linked (if object.directory.content)
288     """
289     def get_object(self, cr, uid, uri, context={}):
290         if not uri:
291             return node_class(cr, uid, '', False, type='database')
292         turi = tuple(uri)
293         if False and (turi in self._cache):
294             (path, oo, oo2, content,type,root) = self._cache[turi]
295             if oo:
296                 object = self.pool.get(oo[0]).browse(cr, uid, oo[1], context)
297             else:
298                 object = False
299             if oo2:
300                 object2 = self.pool.get(oo2[0]).browse(cr, uid, oo2[1], context)
301             else:
302                 object2 = False
303             node = node_class(cr, uid, path, object,object2, context, content, type, root)
304             return node
305
306         node = node_class(cr, uid, '/', False, type='database')
307         for path in uri[:]:
308             if path:
309                 node = node.child(path)
310                 if not node:
311                     return False
312         oo = node.object and (node.object._name, node.object.id) or False
313         oo2 = node.object2 and (node.object2._name, node.object2.id) or False
314         self._cache[turi] = (node.path, oo, oo2, node.content,node.type,node.root)
315         return node
316
317     def get_childs(self, cr, uid, uri, context={}):
318         node = self.get_object(cr, uid, uri, context)
319         if uri:
320             children = node.children()
321         else:
322             children= [node]
323         result = map(lambda node: node.path_get(), children)
324         #childs,object2 = self._get_childs(cr, uid, object, False, context)
325         #result = map(lambda x: urlparse.urljoin(path+'/',x.name), childs)
326         return result
327
328     def write(self, cr, uid, ids, vals, context=None):
329         # need to make constraints to checking duplicate
330         #if not self._check_duplication(cr,uid,vals):
331         #    raise except_orm('ValidateError', 'Directory name must be unique!')
332         return result
333
334     def copy(self, cr, uid, id, default=None, context=None):
335         if not default:
336             default ={}
337         name = self.read(cr, uid, [id])[0]['name']
338         default.update({'name': name+ " (copy)"})
339         return super(document_directory,self).copy(cr,uid,id,default,context)
340
341     def _check_duplication(self, cr, uid,vals,ids=[],op='create'):
342         name=vals.get('name',False)
343         parent_id=vals.get('parent_id',False)
344         ressource_parent_type_id=vals.get('ressource_parent_type_id',False)
345         ressource_id=vals.get('ressource_id',0)
346         if op=='write':
347            for directory in self.browse(cr,uid,ids):
348                 if not name:
349                     name=directory.name
350                 if not parent_id:
351                     parent_id=directory.parent_id and directory.parent_id.id or False
352                 if not ressource_parent_type_id:
353                     ressource_parent_type_id=directory.ressource_parent_type_id and directory.ressource_parent_type_id.id or False
354                 if not ressource_id:
355                     ressource_id=directory.ressource_id and directory.ressource_id.id or 0
356                 res=self.search(cr,uid,[('id','<>',directory.id),('name','=',name),('parent_id','=',parent_id),('ressource_parent_type_id','=',ressource_parent_type_id),('ressource_id','=',ressource_id)])
357                 if len(res):
358                         return False
359         if op=='create':
360             res=self.search(cr,uid,[('name','=',name),('parent_id','=',parent_id),('ressource_parent_type_id','=',ressource_parent_type_id),('ressource_id','=',ressource_id)])
361             if len(res):
362                 return False
363         return True
364     def write(self, cr, uid, ids, vals, context=None):
365         if not self._check_duplication(cr,uid,vals,ids,op='write'):
366             raise except_orm('ValidateError', 'Directory name must be unique!')
367         return super(document_directory,self).write(cr,uid,ids,vals,context=context)
368
369     def create(self, cr, uid, vals, context=None):
370         if not self._check_duplication(cr,uid,vals):
371             raise except_orm('ValidateError', 'Directory name must be unique!')
372         if vals.get('name',False) and (vals.get('name').find('/')+1 or vals.get('name').find('@')+1 or vals.get('name').find('$')+1 or vals.get('name').find('#')+1) :
373             raise 'Error'
374         return super(document_directory,self).create(cr, uid, vals, context)
375
376 document_directory()
377
378 class document_directory_node(osv.osv):
379     _inherit = 'process.node'
380     _columns = {
381         'directory_id':  fields.many2one('document.directory', 'Document directory', ondelete="set null"),
382     }
383 document_directory_node()
384
385 class document_directory_content_type(osv.osv):
386     _name = 'document.directory.content.type'
387     _description = 'Directory Content Type'
388     _columns = {
389         'name': fields.char('Content Type', size=64, required=True),
390         'code': fields.char('Extension', size=4),
391         'active': fields.boolean('Active'),
392     }
393     _defaults = {
394         'active': lambda *args: 1
395     }
396 document_directory_content_type()
397
398 class document_directory_content(osv.osv):
399     _name = 'document.directory.content'
400     _description = 'Directory Content'
401     _order = "sequence"
402     def _extension_get(self, cr, uid, context={}):
403         cr.execute('select code,name from document_directory_content_type where active')
404         res = cr.fetchall()
405         return res
406     _columns = {
407         'name': fields.char('Content Name', size=64, required=True),
408         'sequence': fields.integer('Sequence', size=16),
409         'suffix': fields.char('Suffix', size=16),
410         'report_id': fields.many2one('ir.actions.report.xml', 'Report'),
411         'extension': fields.selection(_extension_get, 'Document Type', required=True, size=4),
412         'include_name': fields.boolean('Include Record Name', help="Check if you cant that the name of the file start by the record name."),
413         'directory_id': fields.many2one('document.directory', 'Directory'),
414     }
415     _defaults = {
416         'extension': lambda *args: '.pdf',
417         'sequence': lambda *args: 1,
418         'include_name': lambda *args: 1,
419     }
420     def process_write_pdf(self, cr, uid, node, context={}):
421         return True
422     def process_read_pdf(self, cr, uid, node, context={}):
423         report = self.pool.get('ir.actions.report.xml').browse(cr, uid, node.content.report_id.id)
424         srv = netsvc.LocalService('report.'+report.report_name)
425         pdf,pdftype = srv.create(cr, uid, [node.object.id], {}, {})
426         s = StringIO.StringIO(pdf)
427         s.name = node
428         return s
429 document_directory_content()
430
431 class ir_action_report_xml(osv.osv):
432     _name="ir.actions.report.xml"
433     _inherit ="ir.actions.report.xml"
434
435     def _model_get(self, cr, uid, ids, name, arg, context):
436         res = {}
437         model_pool = self.pool.get('ir.model')
438         for data in self.read(cr,uid,ids,['model']):
439             model = data.get('model',False)
440             if model:
441                 model_id =model_pool.search(cr,uid,[('model','=',model)])
442                 if model_id:
443                     res[data.get('id')] = model_id[0]
444                 else:
445                     res[data.get('id')] = False
446         return res
447
448     def _model_search(self, cr, uid, obj, name, args):
449         if not len(args):
450             return []
451         model_id= args[0][2]
452         if not model_id:
453             return []
454         model = self.pool.get('ir.model').read(cr,uid,[model_id])[0]['model']
455         report_id = self.search(cr,uid,[('model','=',model)])
456         if not report_id:
457             return [('id','=','0')]
458         return [('id','in',report_id)]
459
460     _columns={
461         'model_id' : fields.function(_model_get,fnct_search=_model_search,method=True,string='Model Id'),
462     }
463
464 ir_action_report_xml()
465
466
467 import random
468 import string
469
470
471 def random_name():
472     random.seed()
473     d = [random.choice(string.letters) for x in xrange(10) ]
474     name = "".join(d)
475     return name
476
477
478 def create_directory(path):
479     dir_name = random_name()
480     path = os.path.join(path,dir_name)
481     os.makedirs(path)
482     return dir_name
483
484 class document_file(osv.osv):
485     _inherit = 'ir.attachment'
486     def _data_get(self, cr, uid, ids, name, arg, context):
487         result = {}
488         cr.execute('select id,store_method,datas,store_fname,link from ir_attachment where id in ('+','.join(map(str,ids))+')')
489         for id,m,d,r,l in cr.fetchall():
490             if m=='db':
491                 result[id] = d
492             elif m=='fs':
493                 try:
494                     path = os.path.join(os.getcwd(), 'filestore', cr.dbname)
495                     value = file(os.path.join(path,r), 'rb').read()
496                     result[id] = base64.encodestring(value)
497                 except:
498                     result[id]=''
499             else:
500                 result[id] = ''
501         return result
502
503     #
504     # This code can be improved
505     #
506     def _data_set(self, cr, obj, id, name, value, uid=None, context={}):
507         if not value:
508             return True
509         if (not context) or context.get('store_method','fs')=='fs':
510             path = os.path.join(os.getcwd(), "filestore", cr.dbname)
511             if not os.path.isdir(path):
512                 os.makedirs(path)
513             flag = None
514             # This can be improved
515             for dirs in os.listdir(path):
516                 if os.path.isdir(os.path.join(path,dirs)) and len(os.listdir(os.path.join(path,dirs)))<4000:
517                     flag = dirs
518                     break
519             flag = flag or create_directory(path)
520             filename = random_name()
521             fname = os.path.join(path, flag, filename)
522             fp = file(fname,'wb')
523             v = base64.decodestring(value)
524             fp.write(v)
525             filesize = os.stat(fname).st_size
526             cr.execute('update ir_attachment set store_fname=%s,store_method=%s,file_size=%d where id=%d', (os.path.join(flag,filename),'fs',len(v),id))
527         else:
528             cr.execute('update ir_attachment set datas=%s,store_method=%s where id=%d', (psycopg.Binary(value),'db',id))
529         return True
530
531     _columns = {
532         'user_id': fields.many2one('res.users', 'Owner', select=1),
533         'group_ids': fields.many2many('res.groups', 'document_directory_group_rel', 'item_id', 'group_id', 'Groups'),
534         'parent_id': fields.many2one('document.directory', 'Directory', select=1),
535         'file_size': fields.integer('File Size', required=True),
536         'file_type': fields.char('Content Type', size=32),
537         'index_content': fields.text('Indexed Content'),
538         'write_date': fields.datetime('Date Modified', readonly=True),
539         'write_uid':  fields.many2one('res.users', 'Last Modification User', readonly=True),
540         'create_date': fields.datetime('Date Created', readonly=True),
541         'create_uid':  fields.many2one('res.users', 'Creator', readonly=True),
542         'store_method': fields.selection([('db','Database'),('fs','Filesystem'),('link','Link')], "Storing Method"),
543         'datas': fields.function(_data_get,method=True,store=True,fnct_inv=_data_set,string='File Content',type="binary"),
544         'store_fname': fields.char('Stored Filename', size=200),
545         'res_model': fields.char('Attached Model', size=64), #res_model
546         'res_id': fields.integer('Attached ID'), #res_id
547         'partner_id':fields.many2one('res.partner', 'Partner', select=1),
548         'title': fields.char('Resource Title',size=64),
549     }
550
551     _defaults = {
552         'user_id': lambda self,cr,uid,ctx:uid,
553         'file_size': lambda self,cr,uid,ctx:0,
554         'store_method': lambda *args: 'db'
555     }
556     _sql_constraints = [
557         ('filename_uniq', 'unique (name,parent_id,res_id,res_model)', 'The file name must be unique !')
558     ]
559     def _check_duplication(self, cr, uid,vals,ids=[],op='create'):
560         name=vals.get('name',False)
561         parent_id=vals.get('parent_id',False)
562         res_model=vals.get('res_model',False)
563         res_id=vals.get('res_id',0)
564         if op=='write':
565            for file in self.browse(cr,uid,ids):
566                 if not name:
567                     name=file.name
568                 if not parent_id:
569                     parent_id=file.parent_id and file.parent_id.id or False
570                 if not res_model:
571                     res_model=file.res_model and file.res_model or False
572                 if not res_id:
573                     res_id=file.res_id and file.res_id or 0
574                 res=self.search(cr,uid,[('id','<>',file.id),('name','=',name),('parent_id','=',parent_id),('res_model','=',res_model),('res_id','=',res_id)])
575                 if len(res):
576                         return False
577         if op=='create':
578             res=self.search(cr,uid,[('name','=',name),('parent_id','=',parent_id),('res_id','=',res_id),('res_model','=',res_model)])
579             if len(res):
580                 return False
581         return True
582     def copy(self, cr, uid, id, default=None, context=None):
583         if not default:
584             default ={}
585         name = self.read(cr, uid, [id])[0]['name']
586         default.update({'name': name+ " (copy)"})
587         return super(document_file,self).copy(cr,uid,id,default,context)
588     def write(self, cr, uid, ids, vals, context=None):
589         if not self._check_duplication(cr,uid,vals,ids,'write'):
590             raise except_orm('ValidateError', 'File name must be unique!')
591         result = super(document_file,self).write(cr,uid,ids,vals,context=context)
592         cr.commit()
593         try:
594             for f in self.browse(cr, uid, ids, context=context):
595                 if 'datas' not in vals:
596                     vals['datas']=f.datas
597                 res = content_index(base64.decodestring(vals['datas']), f.datas_fname, f.file_type or None)
598                 super(document_file,self).write(cr, uid, ids, {
599                     'index_content': res
600                 })
601             cr.commit()
602         except:
603             pass
604         return result
605
606     def create(self, cr, uid, vals, context={}):
607         vals['title']=vals['name']
608         if not vals.get('res_id', False) and context.get('default_res_id',False):
609             vals['res_id']=context.get('default_res_id',False)
610         if not vals.get('res_model', False) and context.get('default_res_model',False):
611             vals['res_model']=context.get('default_res_model',False)
612         if vals.get('res_id', False) and vals.get('res_model',False):
613             obj_model=self.pool.get(vals['res_model'])
614             result = obj_model.read(cr, uid, [vals['res_id']], context=context)
615             if len(result):
616                 obj=result[0]
617                 vals['title'] = (obj['name'] or '')[:60]
618                 if obj_model._name=='res.partner':
619                     vals['partner_id']=obj['id']
620                 elif obj.get('address_id',False):
621                     if isinstance(obj['address_id'],tuple) or isinstance(obj['address_id'],list):
622                         address_id=obj['address_id'][0]
623                     else:
624                         address_id=obj['address_id']
625                     address=self.pool.get('res.partner.address').read(cr,uid,[address_id],context=context)
626                     if len(address):
627                         vals['partner_id']=address[0]['partner_id'][0] or False
628                 elif obj.get('partner_id',False):
629                     if isinstance(obj['partner_id'],tuple) or isinstance(obj['partner_id'],list):
630                         vals['partner_id']=obj['partner_id'][0]
631                     else:
632                         vals['partner_id']=obj['partner_id']
633
634         datas=None
635         if vals.get('datas',False) and vals.get('link',False) :
636             import urllib
637             datas=base64.encodestring(urllib.urlopen(vals['link']).read())
638         else:
639             datas=vals['datas']
640         vals['file_size']= len(datas)
641         if not self._check_duplication(cr,uid,vals):
642             raise except_orm('ValidateError', 'File name must be unique!')
643         result = super(document_file,self).create(cr, uid, vals, context)
644         cr.commit()
645         try:
646             res = content_index(base64.decodestring(datas), vals['datas_fname'], vals.get('content_type', None))
647             super(document_file,self).write(cr, uid, [result], {
648                 'index_content': res,
649             })
650             cr.commit()
651         except:
652             pass
653         return result
654
655     def unlink(self,cr, uid, ids, context={}):
656         for f in self.browse(cr, uid, ids, context):
657             if f.store_method=='fs':
658                 try:
659                     path = os.path.join(os.getcwd(), cr.dbname, 'filestore',f.store_fname)
660                     os.unlink(path)
661                 except:
662                     pass
663         return super(document_file, self).unlink(cr, uid, ids, context)
664 document_file()
665
666 class document_configuration_wizard(osv.osv_memory):
667     _name='document.configuration.wizard'
668     _rec_name = 'Auto Directory configuration'
669     _columns = {
670         'host': fields.char('Server Address', size=64, help="Put here the server address or IP. " \
671             "Keep localhost if you don't know what to write.", required=True)
672     }
673     _defaults = {
674         'host': lambda *args: 'localhost'
675     }
676     def action_cancel(self,cr,uid,ids,conect=None):
677         return {
678                 'view_type': 'form',
679                 "view_mode": 'form',
680                 'res_model': 'ir.actions.configuration.wizard',
681                 'type': 'ir.actions.act_window',
682                 'target':'new',
683          }
684
685     def action_config(self, cr, uid, ids, context=None):
686         conf = self.browse(cr, uid, ids[0], context)
687         obj=self.pool.get('document.directory')
688         objid=self.pool.get('ir.model.data')
689
690         if self.pool.get('sale.order'):
691             id = objid._get_id(cr, uid, 'document', 'dir_sale_order_all')
692             id = objid.browse(cr, uid, id, context=context).res_id
693             mid = self.pool.get('ir.model').search(cr, uid, [('model','=','sale.order')])
694             obj.write(cr, uid, [id], {
695                 'type':'ressource',
696                 'ressource_type_id': mid[0],
697                 'domain': '[]',
698             })
699             aid = objid._get_id(cr, uid, 'sale', 'report_sale_order')
700             aid = objid.browse(cr, uid, aid, context=context).res_id
701
702             self.pool.get('document.directory.content').create(cr, uid, {
703                 'name': "Print Order",
704                 'suffix': "_print",
705                 'report_id': aid,
706                 'extension': '.pdf',
707                 'include_name': 1,
708                 'directory_id': id,
709             })
710             id = objid._get_id(cr, uid, 'document', 'dir_sale_order_quote')
711             id = objid.browse(cr, uid, id, context=context).res_id
712             obj.write(cr, uid, [id], {
713                 'type':'ressource',
714                 'ressource_type_id': mid[0],
715                 'domain': "[('state','=','draft')]",
716             })
717
718         if self.pool.get('product.product'):
719             id = objid._get_id(cr, uid, 'document', 'dir_product')
720             id = objid.browse(cr, uid, id, context=context).res_id
721             mid = self.pool.get('ir.model').search(cr, uid, [('model','=','product.product')])
722             obj.write(cr, uid, [id], {
723                 'type':'ressource',
724                 'ressource_type_id': mid[0],
725             })
726
727         if self.pool.get('stock.location'):
728             aid = objid._get_id(cr, uid, 'stock', 'report_product_history')
729             aid = objid.browse(cr, uid, aid, context=context).res_id
730
731             self.pool.get('document.directory.content').create(cr, uid, {
732                 'name': "Product Stock",
733                 'suffix': "_stock_forecast",
734                 'report_id': aid,
735                 'extension': '.pdf',
736                 'include_name': 1,
737                 'directory_id': id,
738             })
739
740         if self.pool.get('account.analytic.account'):
741             id = objid._get_id(cr, uid, 'document', 'dir_project')
742             id = objid.browse(cr, uid, id, context=context).res_id
743             mid = self.pool.get('ir.model').search(cr, uid, [('model','=','account.analytic.account')])
744             obj.write(cr, uid, [id], {
745                 'type':'ressource',
746                 'ressource_type_id': mid[0],
747                 'domain': '[]',
748                 'ressource_tree': 1
749         })
750
751         aid = objid._get_id(cr, uid, 'document', 'action_document_browse')
752         aid = objid.browse(cr, uid, aid, context=context).res_id
753         self.pool.get('ir.actions.url').write(cr, uid, [aid], {'url': 'ftp://'+(conf.host or 'localhost')+':8021/'})
754
755         return {
756                 'view_type': 'form',
757                 "view_mode": 'form',
758                 'res_model': 'ir.actions.configuration.wizard',
759                 'type': 'ir.actions.act_window',
760                 'target':'new',
761         }
762 document_configuration_wizard()