You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
212 lines
8.4 KiB
212 lines
8.4 KiB
# coding: utf-8
|
|
# @ 2015 Valentin CHEMIERE @ Akretion
|
|
# © @author Mourad EL HADJ MIMOUNE <mourad.elhadj.mimoune@akretion.com>
|
|
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).
|
|
|
|
from openerp import models, fields, api
|
|
import openerp
|
|
from openerp import tools
|
|
from base64 import b64encode
|
|
import os
|
|
import datetime
|
|
import logging
|
|
|
|
_logger = logging.getLogger(__name__)
|
|
|
|
|
|
try:
|
|
# We use a jinja2 sandboxed environment to render mako templates.
|
|
# Note that the rendering does not cover all the mako syntax, in particular
|
|
# arbitrary Python statements are not accepted, and not all expressions are
|
|
# allowed: only "public" attributes (not starting with '_') of objects may
|
|
# be accessed.
|
|
# This is done on purpose: it prevents incidental or malicious execution of
|
|
# Python code that may break the security of the server.
|
|
from jinja2.sandbox import SandboxedEnvironment
|
|
mako_template_env = SandboxedEnvironment(
|
|
variable_start_string="${",
|
|
variable_end_string="}",
|
|
line_statement_prefix="%",
|
|
trim_blocks=True, # do not output newline after blocks
|
|
)
|
|
mako_template_env.globals.update({
|
|
'str': str,
|
|
'datetime': datetime,
|
|
'len': len,
|
|
'abs': abs,
|
|
'min': min,
|
|
'max': max,
|
|
'sum': sum,
|
|
'filter': filter,
|
|
'reduce': reduce,
|
|
'map': map,
|
|
'round': round,
|
|
})
|
|
except ImportError:
|
|
_logger.warning("jinja2 not available, templating features will not work!")
|
|
|
|
|
|
class Task(models.Model):
|
|
_name = 'external.file.task'
|
|
_description = 'External file task'
|
|
|
|
name = fields.Char(required=True)
|
|
|
|
method_type = fields.Selection(
|
|
[('import', 'Import'), ('export', 'Export')],
|
|
required=True)
|
|
|
|
filename = fields.Char(help='File name which is imported.'
|
|
'You can use file pattern like *.txt'
|
|
'to import all txt files')
|
|
filepath = fields.Char(help='Path to imported/exported file')
|
|
|
|
location_id = fields.Many2one('external.file.location', string='Location',
|
|
required=True)
|
|
|
|
attachment_ids = fields.One2many('ir.attachment.metadata', 'task_id',
|
|
string='Attachment')
|
|
|
|
move_path = fields.Char(string='Move Path',
|
|
help='Imported File will be moved to this path')
|
|
|
|
new_name = fields.Char(string='New Name',
|
|
help='Imported File will be renamed to this name'
|
|
'Name can use mako template where obj is an '
|
|
'ir_attachement. template exemple : '
|
|
' ${obj.name}-${obj.create_date}.csv')
|
|
|
|
md5_check = fields.Boolean(help='Control file integrity after import with'
|
|
' a md5 file')
|
|
|
|
after_import = fields.Selection(selection='_get_action',
|
|
help='Action after import a file')
|
|
|
|
company_id = fields.Many2one(
|
|
'res.company', 'Company',
|
|
default=lambda self: self.env['res.company']._company_default_get(
|
|
'external.file.task'))
|
|
|
|
file_type = fields.Selection(
|
|
selection=[],
|
|
string="File Type",
|
|
help="The file type determines an import method to be used "
|
|
"to parse and transform data before their import in ERP")
|
|
|
|
active = fields.Boolean(default=True)
|
|
|
|
def _get_action(self):
|
|
return [('rename', 'Rename'),
|
|
('move', 'Move'),
|
|
('move_rename', 'Move & Rename'),
|
|
('delete', 'Delete'),
|
|
]
|
|
|
|
@api.multi
|
|
def _prepare_attachment_vals(self, datas, filename, md5_datas):
|
|
self.ensure_one()
|
|
vals = {
|
|
'name': filename,
|
|
'datas': b64encode(datas),
|
|
'datas_fname': filename,
|
|
'task_id': self.id,
|
|
'external_hash': md5_datas,
|
|
'file_type': self.file_type or False,
|
|
}
|
|
return vals
|
|
|
|
@api.model
|
|
def _template_render(self, template, record):
|
|
try:
|
|
template = mako_template_env.from_string(tools.ustr(template))
|
|
except Exception:
|
|
_logger.exception("Failed to load template %r", template)
|
|
|
|
variables = {'obj': record}
|
|
try:
|
|
render_result = template.render(variables)
|
|
except Exception:
|
|
_logger.exception(
|
|
"Failed to render template %r using values %r" %
|
|
(template, variables))
|
|
render_result = u""
|
|
if render_result == u"False":
|
|
render_result = u""
|
|
return render_result
|
|
|
|
@api.model
|
|
def run_task_scheduler(self, domain=None):
|
|
if domain is None:
|
|
domain = []
|
|
tasks = self.env['external.file.task'].search(domain)
|
|
for task in tasks:
|
|
if task.method_type == 'import':
|
|
task.run_import()
|
|
elif task.method_type == 'export':
|
|
task.run_export()
|
|
|
|
@api.multi
|
|
def run_import(self):
|
|
self.ensure_one()
|
|
protocols = self.env['external.file.location']._get_classes()
|
|
cls = protocols.get(self.location_id.protocol)[1]
|
|
attach_obj = self.env['ir.attachment.metadata']
|
|
with cls.connect(self.location_id) as conn:
|
|
md5_datas = ''
|
|
for file_name in conn.listdir(path=self.filepath,
|
|
wildcard=self.filename or '',
|
|
files_only=True):
|
|
with api.Environment.manage():
|
|
with openerp.registry(
|
|
self.env.cr.dbname).cursor() as new_cr:
|
|
new_env = api.Environment(new_cr, self.env.uid,
|
|
self.env.context)
|
|
try:
|
|
full_path = os.path.join(self.filepath, file_name)
|
|
file_data = conn.open(full_path, 'rb')
|
|
datas = file_data.read()
|
|
if self.md5_check:
|
|
md5_file = conn.open(full_path + '.md5', 'rb')
|
|
md5_datas = md5_file.read().rstrip('\r\n')
|
|
attach_vals = self._prepare_attachment_vals(
|
|
datas, file_name, md5_datas)
|
|
attachment = attach_obj.with_env(new_env).create(
|
|
attach_vals)
|
|
new_full_path = False
|
|
if self.after_import == 'rename':
|
|
new_name = self._template_render(
|
|
self.new_name, attachment)
|
|
new_full_path = os.path.join(
|
|
self.filepath, new_name)
|
|
elif self.after_import == 'move':
|
|
new_full_path = os.path.join(
|
|
self.move_path, file_name)
|
|
elif self.after_import == 'move_rename':
|
|
new_name = self._template_render(
|
|
self.new_name, attachment)
|
|
new_full_path = os.path.join(
|
|
self.move_path, new_name)
|
|
if new_full_path:
|
|
conn.rename(full_path, new_full_path)
|
|
if self.md5_check:
|
|
conn.rename(
|
|
full_path + '.md5',
|
|
new_full_path + '/md5')
|
|
if self.after_import == 'delete':
|
|
conn.remove(full_path)
|
|
if self.md5_check:
|
|
conn.remove(full_path + '.md5')
|
|
except Exception, e:
|
|
new_env.cr.rollback()
|
|
raise e
|
|
else:
|
|
new_env.cr.commit()
|
|
|
|
@api.multi
|
|
def run_export(self):
|
|
self.ensure_one()
|
|
attachment_obj = self.env['ir.attachment.metadata']
|
|
attachments = attachment_obj.search(
|
|
[('task_id', '=', self.id), ('state', '!=', 'done')])
|
|
for attachment in attachments:
|
|
attachment.run()
|