1 # -*- coding: utf-8 -*-
2 ##############################################################################
4 # OpenERP, Open Source Management Solution
5 # Copyright (C) 2004-2009 Tiny SPRL (<http://tiny.be>).
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.
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.
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/>.
20 ##############################################################################
24 from osv import osv, fields
25 from osv.orm import except_orm
31 from content_index import content_index
37 from psycopg2 import Binary
38 from tools import config
40 from tools.translate import _
44 d = [random.choice(string.ascii_letters) for x in xrange(10) ]
49 # Unsupported WebDAV Commands:
58 # An object that represent an uri
59 # path: the uri of the object
60 # content: the Content it belongs to (_print.pdf)
61 # type: content or collection
62 # content: objct = res.partner
63 # collection: object = directory, object2 = res.partner
64 # file: objct = ir.attachement
65 # root: if we are at the first directory of a ressource
67 INVALID_CHARS={'*':str(hash('*')), '|':str(hash('|')) , "\\":str(hash("\\")), '/':'__', ':':str(hash(':')), '"':str(hash('"')), '<':str(hash('<')) , '>':str(hash('>')) , '?':str(hash('?'))}
70 class node_class(object):
71 def __init__(self, cr, uid, path, object, object2=False, context={}, content=False, type='collection', root=False):
76 self.object2 = object2
77 self.context = context
78 self.content = content
82 def _file_get(self, nodename=False):
85 pool = pooler.get_pool(self.cr.dbname)
86 fobj = pool.get('ir.attachment')
90 where.append( ('res_model','=',self.object2._name) )
91 where.append( ('res_id','=',self.object2.id) )
93 where.append( ('parent_id','=',self.object.id) )
94 where.append( ('res_id','=',False) )
96 where.append( (fobj._rec_name,'=',nodename) )
97 for content in self.object.content_ids:
98 if self.object2 or not content.include_name:
99 if content.include_name:
100 content_name = self.object2.name
101 obj = pool.get(self.object.ressource_type_id.model)
102 name_for = obj._name.split('.')[-1]
103 if content_name and content_name.find(name_for) == 0 :
104 content_name = content_name.replace(name_for,'')
105 test_nodename = content_name + (content.suffix or '') + (content.extension or '')
107 test_nodename = (content.suffix or '') + (content.extension or '')
108 if test_nodename.find('/'):
109 test_nodename=test_nodename.replace('/', '_')
110 path = self.path+'/'+test_nodename
112 n = node_class(self.cr, self.uid,path, self.object2, False, context=self.context, content=content, type='content', root=False)
115 if nodename == test_nodename:
116 n = node_class(self.cr, self.uid, path, self.object2, False, context=self.context, content=content, type='content', root=False)
119 ids = fobj.search(self.cr, self.uid, where+[ ('parent_id','=',self.object and self.object.id or False) ])
120 if self.object and self.root and (self.object.type=='ressource'):
121 ids += fobj.search(self.cr, self.uid, where+[ ('parent_id','=',False) ])
122 res = fobj.browse(self.cr, self.uid, ids, context=self.context)
123 return map(lambda x: node_class(self.cr, self.uid, self.path+'/'+eval('x.'+fobj._rec_name), x, False, context=self.context, type='file', root=False), res) + res2
125 def get_translation(self,value,lang):
127 #TODO : to get translation term
130 def directory_list_for_child(self,nodename,parent=False):
131 pool = pooler.get_pool(self.cr.dbname)
134 nodename = self.get_translation(nodename, self.context['lang'])
135 where.append(('name','=',nodename))
136 if (self.object and self.object.type=='directory') or not self.object2:
137 where.append(('parent_id','=',self.object and self.object.id or False))
139 where.append(('parent_id','=',False))
141 where.append(('ressource_parent_type_id','=',self.object.ressource_type_id.id))
143 where.append(('ressource_parent_type_id','=',False))
145 ids = pool.get('document.directory').search(self.cr, self.uid, where+[('ressource_id','=',0)])
147 ids += pool.get('document.directory').search(self.cr, self.uid, where+[('ressource_id','=',self.object2.id)])
148 res = pool.get('document.directory').browse(self.cr, self.uid, ids, self.context)
151 def _child_get(self, nodename=False):
152 if self.type not in ('collection','database'):
154 res = self.directory_list_for_child(nodename)
155 result= map(lambda x: node_class(self.cr, self.uid, self.path+'/'+x.name, x, x.type=='directory' and self.object2 or False, context=self.context, root=self.root), res)
156 if self.type=='database':
157 pool = pooler.get_pool(self.cr.dbname)
158 fobj = pool.get('ir.attachment')
159 vargs = [('parent_id','=',False),('res_id','=',False)]
161 vargs.append((fobj._rec_name,'=',nodename))
162 file_ids=fobj.search(self.cr,self.uid,vargs)
164 res = fobj.browse(self.cr, self.uid, file_ids, context=self.context)
165 result +=map(lambda x: node_class(self.cr, self.uid, self.path+'/'+eval('x.'+fobj._rec_name), x, False, context=self.context, type='file', root=self.root), res)
166 if self.type=='collection' and self.object.type=="ressource":
167 where = self.object.domain and eval(self.object.domain, {'active_id':self.root, 'uid':self.uid}) or []
168 pool = pooler.get_pool(self.cr.dbname)
169 obj = pool.get(self.object.ressource_type_id.model)
170 _dirname_field = obj._rec_name
171 if len(obj.fields_get(self.cr, self.uid, ['dirname'])):
172 _dirname_field = 'dirname'
174 name_for = obj._name.split('.')[-1]
175 if nodename and nodename.find(name_for) == 0 :
176 id = int(nodename.replace(name_for,''))
177 where.append(('id','=',id))
179 if nodename.find('__') :
180 nodename=nodename.replace('__','/')
181 for invalid in INVALID_CHARS:
182 if nodename.find(INVALID_CHARS[invalid]) :
183 nodename=nodename.replace(INVALID_CHARS[invalid],invalid)
184 nodename = self.get_translation(nodename, self.context['lang'])
185 where.append((_dirname_field,'=',nodename))
187 if self.object.ressource_tree:
188 if obj._parent_name in obj.fields_get(self.cr,self.uid):
189 where.append((obj._parent_name,'=',self.object2 and self.object2.id or False))
190 ids = obj.search(self.cr, self.uid, where)
191 res = obj.browse(self.cr, self.uid, ids,self.context)
192 result+= map(lambda x: node_class(self.cr, self.uid, self.path+'/'+x.name.replace('/','__'), self.object, x, context=self.context, root=x.id), res)
202 ids = obj.search(self.cr, self.uid, where)
203 res = obj.browse(self.cr, self.uid, ids,self.context)
205 if len(obj.fields_get(self.cr, self.uid, [_dirname_field])):
206 r.name = eval('r.'+_dirname_field)
210 r.name = name_for + '%d'%r.id
211 for invalid in INVALID_CHARS:
212 if r.name.find(invalid) :
213 r.name = r.name.replace(invalid,INVALID_CHARS[invalid])
214 result2 = map(lambda x: node_class(self.cr, self.uid, self.path+'/'+x.name.replace('/','__'), self.object, x, context=self.context, root=x.id), res)
216 if self.object.ressource_tree:
223 return self._child_get() + self._file_get()
225 def child(self, name):
226 res = self._child_get(name)
229 res = self._file_get(name)
236 if self.path[0]=='/':
240 class document_directory(osv.osv):
241 _name = 'document.directory'
242 _description = 'Document directory'
244 'name': fields.char('Name', size=64, required=True, select=1),
245 'company_id': fields.many2one('res.company', 'Company'),
246 'write_date': fields.datetime('Date Modified', readonly=True),
247 'write_uid': fields.many2one('res.users', 'Last Modification User', readonly=True),
248 'create_date': fields.datetime('Date Created', readonly=True),
249 'create_uid': fields.many2one('res.users', 'Creator', readonly=True),
250 'file_type': fields.char('Content Type', size=32),
251 'domain': fields.char('Domain', size=128, help="Use a domain if you want to apply an automatic filter on visible resources."),
252 'user_id': fields.many2one('res.users', 'Owner'),
253 'group_ids': fields.many2many('res.groups', 'document_directory_group_rel', 'item_id', 'group_id', 'Groups'),
254 'parent_id': fields.many2one('document.directory', 'Parent Item'),
255 'child_ids': fields.one2many('document.directory', 'parent_id', 'Children'),
256 'file_ids': fields.one2many('ir.attachment', 'parent_id', 'Files'),
257 'content_ids': fields.one2many('document.directory.content', 'directory_id', 'Virtual Files'),
258 'type': fields.selection([('directory','Static Directory'),('ressource','Other Resources')], 'Type', required=True),
259 'ressource_type_id': fields.many2one('ir.model', 'Directories Mapped to Objects',
260 help="Select an object here and Open ERP will create a mapping for each of these " \
261 "objects, using the given domain, when browsing through FTP."),
262 'ressource_parent_type_id': fields.many2one('ir.model', 'Parent Model',
263 help="If you put an object here, this directory template will appear bellow all of these objects. " \
264 "Don't put a parent directory if you select a parent model."),
265 'ressource_id': fields.integer('Resource ID'),
266 'ressource_tree': fields.boolean('Tree Structure',
267 help="Check this if you want to use the same tree structure as the object selected in the system."),
270 'user_id': lambda self,cr,uid,ctx: uid,
271 'domain': lambda self,cr,uid,ctx: '[]',
272 'type': lambda *args: 'directory',
273 'company_id': lambda self,cr,uid,c: self.pool.get('res.company')._company_default_get(cr, uid, 'document.directory', c),
274 'ressource_id': lambda *a: 0
277 ('dirname_uniq', 'unique (name,parent_id,ressource_id,ressource_parent_type_id)', 'The directory name must be unique !')
280 def get_resource_path(self,cr,uid,dir_id,res_model,res_id):
281 # this method will be used in process module
282 # to be need test and Improvement if resource dir has parent resource (link resource)
284 def _parent(dir_id,path):
285 parent=self.browse(cr,uid,dir_id)
286 if parent.parent_id and not parent.ressource_parent_type_id:
287 _parent(parent.parent_id.id,path)
288 path.append(parent.name)
290 path.append(parent.name)
293 directory=self.browse(cr,uid,dir_id)
294 model_ids=self.pool.get('ir.model').search(cr,uid,[('model','=',res_model)])
298 path.append(self.pool.get(directory.ressource_type_id.model).browse(cr,uid,res_id).name)
299 user=self.pool.get('res.users').browse(cr,uid,uid)
300 return "ftp://%s:%s@localhost:%s/%s/%s"%(user.login,user.password,config.get('ftp_server_port',8021),cr.dbname,'/'.join(path))
303 def _check_recursion(self, cr, uid, ids):
306 cr.execute('select distinct parent_id from document_directory where id in ('+','.join(map(str, ids))+')')
307 ids = filter(None, map(lambda x:x[0], cr.fetchall()))
314 (_check_recursion, 'Error! You can not create recursive Directories.', ['parent_id'])
316 def __init__(self, *args, **kwargs):
317 res = super(document_directory, self).__init__(*args, **kwargs)
320 def onchange_content_id(self, cr, uid, ids, ressource_type_id):
323 def _get_childs(self, cr, uid, node, nodename=False, context={}):
326 nodename = self.get_translation(nodename, self.context['lang'])
327 where.append(('name','=',nodename))
329 where.append(('parent_id','=',object.id))
330 ids = self.search(cr, uid, where, context)
331 return self.browse(cr, uid, ids, context), False
335 uri: of the form "Sales Order/SO001"
338 object: the object.directory or object.directory.content
339 object2: the other object linked (if object.directory.content)
341 def get_object(self, cr, uid, uri, context={}):
342 #TODO : set user's context_lang in context
343 context.update({'lang':False})
345 return node_class(cr, uid, '', False, context=context, type='database')
347 if False and (turi in self._cache):
348 (path, oo, oo2, context, content,type,root) = self._cache[turi]
350 object = self.pool.get(oo[0]).browse(cr, uid, oo[1], context)
354 object2 = self.pool.get(oo2[0]).browse(cr, uid, oo2[1], context)
357 node = node_class(cr, uid, '/', False, context=context, type='database')
360 node = node_class(cr, uid, '/', False, context=context, type='database')
363 node = node.child(path)
366 oo = node.object and (node.object._name, node.object.id) or False
367 oo2 = node.object2 and (node.object2._name, node.object2.id) or False
368 self._cache[turi] = (node.path, oo, oo2, node.context, node.content,node.type,node.root)
371 def get_childs(self, cr, uid, uri, context={}):
372 node = self.get_object(cr, uid, uri, context)
374 children = node.children()
377 result = map(lambda node: node.path_get(), children)
378 #childs,object2 = self._get_childs(cr, uid, object, False, context)
379 #result = map(lambda x: urlparse.urljoin(path+'/',x.name), childs)
382 def copy(self, cr, uid, id, default=None, context=None):
385 name = self.read(cr, uid, [id])[0]['name']
386 default.update({'name': name+ " (copy)"})
387 return super(document_directory,self).copy(cr,uid,id,default,context)
389 def _check_duplication(self, cr, uid,vals,ids=[],op='create'):
390 name=vals.get('name',False)
391 parent_id=vals.get('parent_id',False)
392 ressource_parent_type_id=vals.get('ressource_parent_type_id',False)
393 ressource_id=vals.get('ressource_id',0)
395 for directory in self.browse(cr,uid,ids):
399 parent_id=directory.parent_id and directory.parent_id.id or False
400 if not ressource_parent_type_id:
401 ressource_parent_type_id=directory.ressource_parent_type_id and directory.ressource_parent_type_id.id or False
403 ressource_id=directory.ressource_id and directory.ressource_id or 0
404 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)])
408 res=self.search(cr,uid,[('name','=',name),('parent_id','=',parent_id),('ressource_parent_type_id','=',ressource_parent_type_id),('ressource_id','=',ressource_id)])
412 def write(self, cr, uid, ids, vals, context=None):
413 if not self._check_duplication(cr,uid,vals,ids,op='write'):
414 raise osv.except_osv(_('ValidateError'), _('Directory name must be unique!'))
415 return super(document_directory,self).write(cr,uid,ids,vals,context=context)
417 def create(self, cr, uid, vals, context=None):
418 if not self._check_duplication(cr,uid,vals):
419 raise osv.except_osv(_('ValidateError'), _('Directory name must be unique!'))
420 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) :
421 raise osv.except_osv(_('ValidateError'), _('Directory name contains special characters!'))
422 return super(document_directory,self).create(cr, uid, vals, context)
426 class document_directory_node(osv.osv):
427 _inherit = 'process.node'
429 'directory_id': fields.many2one('document.directory', 'Document directory', ondelete="set null"),
431 document_directory_node()
433 class document_directory_content_type(osv.osv):
434 _name = 'document.directory.content.type'
435 _description = 'Directory Content Type'
437 'name': fields.char('Content Type', size=64, required=True),
438 'code': fields.char('Extension', size=4),
439 'active': fields.boolean('Active'),
442 'active': lambda *args: 1
444 document_directory_content_type()
446 class document_directory_content(osv.osv):
447 _name = 'document.directory.content'
448 _description = 'Directory Content'
450 def _extension_get(self, cr, uid, context={}):
451 cr.execute('select code,name from document_directory_content_type where active')
455 'name': fields.char('Content Name', size=64, required=True),
456 'sequence': fields.integer('Sequence', size=16),
457 'suffix': fields.char('Suffix', size=16),
458 'report_id': fields.many2one('ir.actions.report.xml', 'Report'),
459 'extension': fields.selection(_extension_get, 'Document Type', required=True, size=4),
460 'include_name': fields.boolean('Include Record Name', help="Check this field if you want that the name of the file start by the record name."),
461 'directory_id': fields.many2one('document.directory', 'Directory'),
464 'extension': lambda *args: '.pdf',
465 'sequence': lambda *args: 1,
466 'include_name': lambda *args: 1,
468 def process_write_pdf(self, cr, uid, node, context={}):
470 def process_read_pdf(self, cr, uid, node, context={}):
471 report = self.pool.get('ir.actions.report.xml').browse(cr, uid, node.content.report_id.id)
472 srv = netsvc.LocalService('report.'+report.report_name)
473 pdf,pdftype = srv.create(cr, uid, [node.object.id], {}, {})
474 s = StringIO.StringIO(pdf)
477 document_directory_content()
479 class ir_action_report_xml(osv.osv):
480 _name="ir.actions.report.xml"
481 _inherit ="ir.actions.report.xml"
483 def _model_get(self, cr, uid, ids, name, arg, context):
485 model_pool = self.pool.get('ir.model')
486 for data in self.read(cr,uid,ids,['model']):
487 model = data.get('model',False)
489 model_id =model_pool.search(cr,uid,[('model','=',model)])
491 res[data.get('id')] = model_id[0]
493 res[data.get('id')] = False
496 def _model_search(self, cr, uid, obj, name, args):
502 model = self.pool.get('ir.model').read(cr,uid,[model_id])[0]['model']
503 report_id = self.search(cr,uid,[('model','=',model)])
505 return [('id','=','0')]
506 return [('id','in',report_id)]
509 'model_id' : fields.function(_model_get,fnct_search=_model_search,method=True,string='Model Id'),
512 ir_action_report_xml()
514 def create_directory(path):
515 dir_name = random_name()
516 path = os.path.join(path,dir_name)
520 class document_file(osv.osv):
521 _inherit = 'ir.attachment'
522 _rec_name = 'datas_fname'
523 def _get_filestore(self, cr):
524 return os.path.join(tools.config['root_path'], 'filestore', cr.dbname)
526 def _data_get(self, cr, uid, ids, name, arg, context):
528 cr.execute('select id,store_fname,link from ir_attachment where id in ('+','.join(map(str, ids))+')')
529 for id,r,l in cr.fetchall():
531 value = file(os.path.join(self._get_filestore(cr), r), 'rb').read()
532 result[id] = base64.encodestring(value)
535 # if context.get('bin_size', False):
536 # result[id] = tools.human_size(result[id])
540 # This code can be improved
542 def _data_set(self, cr, uid, id, name, value, args=None, context={}):
544 filename = self.browse(cr, uid, id, context).store_fname
546 os.unlink(os.path.join(self._get_filestore(cr), filename))
549 cr.execute('update ir_attachment set store_fname=NULL WHERE id=%s', (id,) )
551 #if (not context) or context.get('store_method','fs')=='fs':
553 path = self._get_filestore(cr)
554 if not os.path.isdir(path):
558 raise except_orm(_('Permission Denied !'), _('You do not permissions to write on the server side.'))
561 # This can be improved
562 for dirs in os.listdir(path):
563 if os.path.isdir(os.path.join(path,dirs)) and len(os.listdir(os.path.join(path,dirs)))<4000:
566 flag = flag or create_directory(path)
567 filename = random_name()
568 fname = os.path.join(path, flag, filename)
569 fp = file(fname,'wb')
570 v = base64.decodestring(value)
572 filesize = os.stat(fname).st_size
573 cr.execute('update ir_attachment set store_fname=%s,store_method=%s,file_size=%s where id=%s', (os.path.join(flag,filename),'fs',len(v),id))
576 raise except_orm(_('Error!'), str(e))
579 'user_id': fields.many2one('res.users', 'Owner', select=1),
580 'group_ids': fields.many2many('res.groups', 'document_directory_group_rel', 'item_id', 'group_id', 'Groups'),
581 'parent_id': fields.many2one('document.directory', 'Directory', select=1),
582 'file_size': fields.integer('File Size', required=True),
583 'file_type': fields.char('Content Type', size=32),
584 'index_content': fields.text('Indexed Content'),
585 'write_date': fields.datetime('Date Modified', readonly=True),
586 'write_uid': fields.many2one('res.users', 'Last Modification User', readonly=True),
587 'create_date': fields.datetime('Date Created', readonly=True),
588 'create_uid': fields.many2one('res.users', 'Creator', readonly=True),
589 'store_method': fields.selection([('db','Database'),('fs','Filesystem'),('link','Link')], "Storing Method"),
590 'datas': fields.function(_data_get,method=True,fnct_inv=_data_set,string='File Content',type="binary"),
591 'store_fname': fields.char('Stored Filename', size=200),
592 'res_model': fields.char('Attached Model', size=64), #res_model
593 'res_id': fields.integer('Attached ID'), #res_id
594 'partner_id':fields.many2one('res.partner', 'Partner', select=1),
595 'title': fields.char('Resource Title',size=64),
599 'user_id': lambda self,cr,uid,ctx:uid,
600 'file_size': lambda self,cr,uid,ctx:0,
601 'store_method': lambda *args: 'db'
604 ('filename_uniq', 'unique (name,parent_id,res_id,res_model)', 'The file name must be unique !')
606 def _check_duplication(self, cr, uid,vals,ids=[],op='create'):
607 name=vals.get('name',False)
608 parent_id=vals.get('parent_id',False)
609 res_model=vals.get('res_model',False)
610 res_id=vals.get('res_id',0)
612 for file in self.browse(cr,uid,ids):
616 parent_id=file.parent_id and file.parent_id.id or False
618 res_model=file.res_model and file.res_model or False
620 res_id=file.res_id and file.res_id or 0
621 res=self.search(cr,uid,[('id','<>',file.id),('name','=',name),('parent_id','=',parent_id),('res_model','=',res_model),('res_id','=',res_id)])
625 res=self.search(cr,uid,[('name','=',name),('parent_id','=',parent_id),('res_id','=',res_id),('res_model','=',res_model)])
629 def copy(self, cr, uid, id, default=None, context=None):
632 name = self.read(cr, uid, [id])[0]['name']
633 default.update({'name': name+ " (copy)"})
634 return super(document_file,self).copy(cr,uid,id,default,context)
635 def write(self, cr, uid, ids, vals, context=None):
636 res=self.search(cr,uid,[('id','in',ids)])
639 if not self._check_duplication(cr,uid,vals,ids,'write'):
640 raise except_orm(_('ValidateError'), _('File name must be unique!'))
641 result = super(document_file,self).write(cr,uid,ids,vals,context=context)
644 for f in self.browse(cr, uid, ids, context=context):
645 #if 'datas' not in vals:
646 # vals['datas']=f.datas
647 res = content_index(base64.decodestring(vals['datas']), f.datas_fname, f.file_type or None)
648 super(document_file,self).write(cr, uid, ids, {
656 def create(self, cr, uid, vals, context={}):
657 vals['title']=vals['name']
658 vals['parent_id'] = context.get('parent_id',False) or vals.get('parent_id',False)
659 if not vals.get('res_id', False) and context.get('default_res_id',False):
660 vals['res_id']=context.get('default_res_id',False)
661 if not vals.get('res_model', False) and context.get('default_res_model',False):
662 vals['res_model']=context.get('default_res_model',False)
663 if vals.get('res_id', False) and vals.get('res_model',False):
664 obj_model=self.pool.get(vals['res_model'])
665 result = obj_model.read(cr, uid, [vals['res_id']], context=context)
668 if obj.get('name',False):
669 vals['title'] = (obj.get('name',''))[:60]
670 if obj_model._name=='res.partner':
671 vals['partner_id']=obj['id']
672 elif obj.get('address_id',False):
673 if isinstance(obj['address_id'],tuple) or isinstance(obj['address_id'],list):
674 address_id=obj['address_id'][0]
676 address_id=obj['address_id']
677 address=self.pool.get('res.partner.address').read(cr,uid,[address_id],context=context)
679 vals['partner_id']=address[0]['partner_id'][0] or False
680 elif obj.get('partner_id',False):
681 if isinstance(obj['partner_id'],tuple) or isinstance(obj['partner_id'],list):
682 vals['partner_id']=obj['partner_id'][0]
684 vals['partner_id']=obj['partner_id']
687 if vals.get('link',False) :
689 datas=base64.encodestring(urllib.urlopen(vals['link']).read())
691 datas = vals.get('datas',False)
693 vals['file_size']= datas and len(datas) or 0
694 if not self._check_duplication(cr,uid,vals):
695 raise except_orm(_('ValidateError'), _('File name must be unique!'))
696 result = super(document_file,self).create(cr, uid, vals, context)
699 res = content_index(base64.decodestring(datas), vals['datas_fname'], vals.get('content_type', None))
700 super(document_file,self).write(cr, uid, [result], {
701 'index_content': res,
708 def unlink(self,cr, uid, ids, context={}):
709 for f in self.browse(cr, uid, ids, context):
710 #if f.store_method=='fs':
712 os.unlink(os.path.join(self._get_filestore(cr), f.store_fname))
715 return super(document_file, self).unlink(cr, uid, ids, context)
718 class document_configuration_wizard(osv.osv_memory):
719 _name='document.configuration.wizard'
720 _description = 'Auto Directory configuration'
721 _inherit = 'res.config'
724 'host': fields.char('Address', size=64,
725 help="Server address or IP.", required=True),
726 'port': fields.char('Port', size=5, help="Server port. " \
727 "Leave 8021 if you don't know what to write.", required=True)
730 def get_ftp_server_address(self, cr, uid, context=None):
731 default_address = config.get('ftp_server_address', None)
732 if default_address is None:
733 default_address = tools.misc.detect_ip_addr()
735 return default_address
737 def get_ftp_server_port(self, cr, uid, context=None):
738 return config.get('ftp_server_port', 8021)
741 'host': get_ftp_server_address,
742 'port': get_ftp_server_port,
745 def execute(self, cr, uid, ids, context=None):
746 conf = self.browse(cr, uid, ids[0], context)
747 obj=self.pool.get('document.directory')
748 objid=self.pool.get('ir.model.data')
750 if self.pool.get('sale.order'):
751 id = objid._get_id(cr, uid, 'document', 'dir_sale_order_all')
752 id = objid.browse(cr, uid, id, context=context).res_id
753 mid = self.pool.get('ir.model').search(cr, uid, [('model','=','sale.order')])
754 obj.write(cr, uid, [id], {
756 'ressource_type_id': mid[0],
759 aid = objid._get_id(cr, uid, 'sale', 'report_sale_order')
760 aid = objid.browse(cr, uid, aid, context=context).res_id
762 self.pool.get('document.directory.content').create(cr, uid, {
763 'name': "Print Order",
770 id = objid._get_id(cr, uid, 'document', 'dir_sale_order_quote')
771 id = objid.browse(cr, uid, id, context=context).res_id
772 obj.write(cr, uid, [id], {
774 'ressource_type_id': mid[0],
775 'domain': "[('state','=','draft')]",
778 if self.pool.get('product.product'):
779 id = objid._get_id(cr, uid, 'document', 'dir_product')
780 id = objid.browse(cr, uid, id, context=context).res_id
781 mid = self.pool.get('ir.model').search(cr, uid, [('model','=','product.product')])
782 obj.write(cr, uid, [id], {
784 'ressource_type_id': mid[0],
787 if self.pool.get('stock.location'):
788 aid = objid._get_id(cr, uid, 'stock', 'report_product_history')
789 aid = objid.browse(cr, uid, aid, context=context).res_id
791 self.pool.get('document.directory.content').create(cr, uid, {
792 'name': "Product Stock",
793 'suffix': "_stock_forecast",
800 if self.pool.get('account.analytic.account'):
801 id = objid._get_id(cr, uid, 'document', 'dir_project')
802 id = objid.browse(cr, uid, id, context=context).res_id
803 mid = self.pool.get('ir.model').search(cr, uid, [('model','=','account.analytic.account')])
804 obj.write(cr, uid, [id], {
806 'ressource_type_id': mid[0],
811 aid = objid._get_id(cr, uid, 'document', 'action_document_browse')
812 aid = objid.browse(cr, uid, aid, context=context).res_id
813 self.pool.get('ir.actions.url').write(cr, uid, [aid], {'url': 'ftp://'+(conf.host or 'localhost')+':'+conf.port+'/'})
815 config['ftp_server_address'] = conf.host
816 config['ftp_server_port'] = conf.port
818 document_configuration_wizard()
821 class document_configuration_ftpserver_wizard(osv.osv_memory):
822 _name='document.configuration.ftp_server.wizard'
823 _rec_name = 'Configure FTP server address'
825 'host': fields.char('Address', size=64, help="Put here the server address or IP. " \
826 "Keep localhost if you don't know what to write.", required=True),
827 'port': fields.char('Port', size=5, help="Put here the server port. " \
828 "Keep 8021 if you don't know what to write.", required=True)
831 def get_ftp_server_address(self, cr, uid, context=None):
832 default_address = tools.misc.detect_ip_addr()
833 return config.get('ftp_server_address', default_address)
835 def get_ftp_server_port(self, cr, uid, context=None):
836 return config.get('ftp_server_port', '8021')
839 'host': get_ftp_server_address,
840 'port': get_ftp_server_port,
843 def action_cancel(self,cr,uid,ids,conect=None):
846 def action_config(self, cr, uid, ids, context=None):
847 conf = self.browse(cr, uid, ids[0], context)
848 obj = self.pool.get('ir.model.data')
850 aid = obj._get_id(cr, uid, 'document', 'action_document_browse')
851 aid = obj.browse(cr, uid, aid, context=context).res_id
852 self.pool.get('ir.actions.url').write(cr, uid, [aid], {'url': 'ftp://'+(conf.host or 'localhost')+':'+conf.port+'/'})
854 config['ftp_server_address'] = conf.host
855 config['ftp_server_port'] = conf.port
860 document_configuration_ftpserver_wizard()