|
@ -20,82 +20,96 @@ try: |
|
|
# This is done on purpose: it prevents incidental or malicious execution of |
|
|
# This is done on purpose: it prevents incidental or malicious execution of |
|
|
# Python code that may break the security of the server. |
|
|
# Python code that may break the security of the server. |
|
|
from jinja2.sandbox import SandboxedEnvironment |
|
|
from jinja2.sandbox import SandboxedEnvironment |
|
|
|
|
|
|
|
|
mako_template_env = SandboxedEnvironment( |
|
|
mako_template_env = SandboxedEnvironment( |
|
|
variable_start_string="${", |
|
|
variable_start_string="${", |
|
|
variable_end_string="}", |
|
|
variable_end_string="}", |
|
|
line_statement_prefix="%", |
|
|
line_statement_prefix="%", |
|
|
trim_blocks=True, # do not output newline after blocks |
|
|
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, |
|
|
|
|
|
'map': map, |
|
|
|
|
|
'round': round, |
|
|
|
|
|
}) |
|
|
|
|
|
|
|
|
mako_template_env.globals.update( |
|
|
|
|
|
{ |
|
|
|
|
|
"str": str, |
|
|
|
|
|
"datetime": datetime, |
|
|
|
|
|
"len": len, |
|
|
|
|
|
"abs": abs, |
|
|
|
|
|
"min": min, |
|
|
|
|
|
"max": max, |
|
|
|
|
|
"sum": sum, |
|
|
|
|
|
"filter": filter, |
|
|
|
|
|
"map": map, |
|
|
|
|
|
"round": round, |
|
|
|
|
|
} |
|
|
|
|
|
) |
|
|
except ImportError: |
|
|
except ImportError: |
|
|
_logger.warning("jinja2 not available, templating features will not work!") |
|
|
_logger.warning("jinja2 not available, templating features will not work!") |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class AttachmentSynchronizeTask(models.Model): |
|
|
class AttachmentSynchronizeTask(models.Model): |
|
|
_name = 'attachment.synchronize.task' |
|
|
|
|
|
_description = 'Attachment synchronize task' |
|
|
|
|
|
|
|
|
_name = "attachment.synchronize.task" |
|
|
|
|
|
_description = "Attachment synchronize task" |
|
|
|
|
|
|
|
|
name = fields.Char(required=True) |
|
|
name = fields.Char(required=True) |
|
|
method_type = fields.Selection( |
|
|
method_type = fields.Selection( |
|
|
[('import', 'Import'), ('export', 'Export')], |
|
|
|
|
|
required=True) |
|
|
|
|
|
pattern = fields.Char(help='File name which is imported.' |
|
|
|
|
|
'The system will check if the remote file at ' |
|
|
|
|
|
'least contains the pattern in its name. ' |
|
|
|
|
|
'Leave it empty to import all files') |
|
|
|
|
|
filepath = fields.Char(help='Path to imported/exported file') |
|
|
|
|
|
|
|
|
[("import", "Import"), ("export", "Export")], required=True |
|
|
|
|
|
) |
|
|
|
|
|
pattern = fields.Char( |
|
|
|
|
|
help="File name which is imported." |
|
|
|
|
|
"The system will check if the remote file at " |
|
|
|
|
|
"least contains the pattern in its name. " |
|
|
|
|
|
"Leave it empty to import all files" |
|
|
|
|
|
) |
|
|
|
|
|
filepath = fields.Char(help="Path to imported/exported file") |
|
|
backend_id = fields.Many2one( |
|
|
backend_id = fields.Many2one( |
|
|
'storage.backend', string='Backend', required=True) |
|
|
|
|
|
attachment_ids = fields.One2many('attachment.queue', '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\n' |
|
|
|
|
|
'Name can use mako template where obj is an ' |
|
|
|
|
|
'ir_attachement. template exemple : ' |
|
|
|
|
|
' ${obj.name}-${obj.create_date}.csv') |
|
|
|
|
|
|
|
|
"storage.backend", string="Backend", required=True |
|
|
|
|
|
) |
|
|
|
|
|
attachment_ids = fields.One2many( |
|
|
|
|
|
"attachment.queue", "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\n" |
|
|
|
|
|
"Name can use mako template where obj is an " |
|
|
|
|
|
"ir_attachement. template exemple : " |
|
|
|
|
|
" ${obj.name}-${obj.create_date}.csv", |
|
|
|
|
|
) |
|
|
after_import = fields.Selection( |
|
|
after_import = fields.Selection( |
|
|
selection=[ |
|
|
selection=[ |
|
|
('rename', 'Rename'), |
|
|
|
|
|
('move', 'Move'), |
|
|
|
|
|
('move_rename', 'Move & Rename'), |
|
|
|
|
|
('delete', 'Delete'), |
|
|
|
|
|
], help='Action after import a file') |
|
|
|
|
|
|
|
|
("rename", "Rename"), |
|
|
|
|
|
("move", "Move"), |
|
|
|
|
|
("move_rename", "Move & Rename"), |
|
|
|
|
|
("delete", "Delete"), |
|
|
|
|
|
], |
|
|
|
|
|
help="Action after import a file", |
|
|
|
|
|
) |
|
|
file_type = fields.Selection( |
|
|
file_type = fields.Selection( |
|
|
selection=[], |
|
|
selection=[], |
|
|
string="File Type", |
|
|
string="File Type", |
|
|
help="The file type determines an import method to be used " |
|
|
help="The file type determines an import method to be used " |
|
|
"to parse and transform data before their import in ERP") |
|
|
|
|
|
enabled = fields.Boolean('Enabled', default=True) |
|
|
|
|
|
|
|
|
"to parse and transform data before their import in ERP", |
|
|
|
|
|
) |
|
|
|
|
|
enabled = fields.Boolean("Enabled", default=True) |
|
|
check_duplicated_files = fields.Boolean( |
|
|
check_duplicated_files = fields.Boolean( |
|
|
string='Check duplicated files', |
|
|
|
|
|
help='If checked, will avoid duplication file import') |
|
|
|
|
|
|
|
|
string="Check duplicated files", |
|
|
|
|
|
help="If checked, will avoid duplication file import", |
|
|
|
|
|
) |
|
|
emails = fields.Char( |
|
|
emails = fields.Char( |
|
|
string="Emails", |
|
|
string="Emails", |
|
|
help="list of email which should be notified in case of failure " |
|
|
help="list of email which should be notified in case of failure " |
|
|
"when excuting the files linked to this task") |
|
|
|
|
|
|
|
|
"when excuting the files linked to this task", |
|
|
|
|
|
) |
|
|
|
|
|
|
|
|
@api.multi |
|
|
|
|
|
def _prepare_attachment_vals(self, datas, filename): |
|
|
def _prepare_attachment_vals(self, datas, filename): |
|
|
self.ensure_one() |
|
|
self.ensure_one() |
|
|
vals = { |
|
|
vals = { |
|
|
'name': filename, |
|
|
|
|
|
'datas': datas, |
|
|
|
|
|
'datas_fname': filename, |
|
|
|
|
|
'task_id': self.id, |
|
|
|
|
|
'file_type': self.file_type or False, |
|
|
|
|
|
|
|
|
"name": filename, |
|
|
|
|
|
"datas": datas, |
|
|
|
|
|
"datas_fname": filename, |
|
|
|
|
|
"task_id": self.id, |
|
|
|
|
|
"file_type": self.file_type or False, |
|
|
} |
|
|
} |
|
|
return vals |
|
|
return vals |
|
|
|
|
|
|
|
@ -106,13 +120,14 @@ class AttachmentSynchronizeTask(models.Model): |
|
|
except Exception: |
|
|
except Exception: |
|
|
_logger.exception("Failed to load template %r", template) |
|
|
_logger.exception("Failed to load template %r", template) |
|
|
|
|
|
|
|
|
variables = {'obj': record} |
|
|
|
|
|
|
|
|
variables = {"obj": record} |
|
|
try: |
|
|
try: |
|
|
render_result = template.render(variables) |
|
|
render_result = template.render(variables) |
|
|
except Exception: |
|
|
except Exception: |
|
|
_logger.exception( |
|
|
_logger.exception( |
|
|
"Failed to render template %r using values %r" % |
|
|
|
|
|
(template, variables)) |
|
|
|
|
|
|
|
|
"Failed to render template %r using values %r" |
|
|
|
|
|
% (template, variables) |
|
|
|
|
|
) |
|
|
render_result = u"" |
|
|
render_result = u"" |
|
|
if render_result == u"False": |
|
|
if render_result == u"False": |
|
|
render_result = u"" |
|
|
render_result = u"" |
|
@ -122,17 +137,15 @@ class AttachmentSynchronizeTask(models.Model): |
|
|
def run_task_import_scheduler(self, domain=None): |
|
|
def run_task_import_scheduler(self, domain=None): |
|
|
if domain is None: |
|
|
if domain is None: |
|
|
domain = [] |
|
|
domain = [] |
|
|
domain = expression.AND([domain, [ |
|
|
|
|
|
('method_type', '=', 'import'), |
|
|
|
|
|
('enabled', '=', True), |
|
|
|
|
|
]]) |
|
|
|
|
|
|
|
|
domain = expression.AND( |
|
|
|
|
|
[domain, [("method_type", "=", "import"), ("enabled", "=", True)]] |
|
|
|
|
|
) |
|
|
for task in self.search(domain): |
|
|
for task in self.search(domain): |
|
|
task.run_import() |
|
|
task.run_import() |
|
|
|
|
|
|
|
|
@api.multi |
|
|
|
|
|
def run_import(self): |
|
|
def run_import(self): |
|
|
self.ensure_one() |
|
|
self.ensure_one() |
|
|
attach_obj = self.env['attachment.queue'] |
|
|
|
|
|
|
|
|
attach_obj = self.env["attachment.queue"] |
|
|
backend = self.backend_id |
|
|
backend = self.backend_id |
|
|
filepath = self.filepath or "" |
|
|
filepath = self.filepath or "" |
|
|
filenames = backend._list(relative_path=filepath, pattern=self.pattern) |
|
|
filenames = backend._list(relative_path=filepath, pattern=self.pattern) |
|
@ -141,34 +154,43 @@ class AttachmentSynchronizeTask(models.Model): |
|
|
total_import = 0 |
|
|
total_import = 0 |
|
|
for file_name in filenames: |
|
|
for file_name in filenames: |
|
|
with api.Environment.manage(): |
|
|
with api.Environment.manage(): |
|
|
with odoo.registry( |
|
|
|
|
|
self.env.cr.dbname).cursor() as new_cr: |
|
|
|
|
|
new_env = api.Environment(new_cr, self.env.uid, |
|
|
|
|
|
self.env.context) |
|
|
|
|
|
|
|
|
with odoo.registry(self.env.cr.dbname).cursor() as new_cr: |
|
|
|
|
|
new_env = api.Environment( |
|
|
|
|
|
new_cr, self.env.uid, self.env.context |
|
|
|
|
|
) |
|
|
try: |
|
|
try: |
|
|
full_absolute_path = os.path.join(filepath, file_name) |
|
|
full_absolute_path = os.path.join(filepath, file_name) |
|
|
datas = backend._get_b64_data(full_absolute_path) |
|
|
datas = backend._get_b64_data(full_absolute_path) |
|
|
attach_vals = self._prepare_attachment_vals( |
|
|
attach_vals = self._prepare_attachment_vals( |
|
|
datas, file_name) |
|
|
|
|
|
|
|
|
datas, file_name |
|
|
|
|
|
) |
|
|
attachment = attach_obj.with_env(new_env).create( |
|
|
attachment = attach_obj.with_env(new_env).create( |
|
|
attach_vals) |
|
|
|
|
|
|
|
|
attach_vals |
|
|
|
|
|
) |
|
|
new_full_path = False |
|
|
new_full_path = False |
|
|
if self.after_import == 'rename': |
|
|
|
|
|
|
|
|
if self.after_import == "rename": |
|
|
new_name = self._template_render( |
|
|
new_name = self._template_render( |
|
|
self.new_name, attachment) |
|
|
|
|
|
|
|
|
self.new_name, attachment |
|
|
|
|
|
) |
|
|
new_full_path = os.path.join(filepath, new_name) |
|
|
new_full_path = os.path.join(filepath, new_name) |
|
|
elif self.after_import == 'move': |
|
|
|
|
|
|
|
|
elif self.after_import == "move": |
|
|
new_full_path = os.path.join( |
|
|
new_full_path = os.path.join( |
|
|
self.move_path, file_name) |
|
|
|
|
|
elif self.after_import == 'move_rename': |
|
|
|
|
|
|
|
|
self.move_path, file_name |
|
|
|
|
|
) |
|
|
|
|
|
elif self.after_import == "move_rename": |
|
|
new_name = self._template_render( |
|
|
new_name = self._template_render( |
|
|
self.new_name, attachment) |
|
|
|
|
|
|
|
|
self.new_name, attachment |
|
|
|
|
|
) |
|
|
new_full_path = os.path.join( |
|
|
new_full_path = os.path.join( |
|
|
self.move_path, new_name) |
|
|
|
|
|
|
|
|
self.move_path, new_name |
|
|
|
|
|
) |
|
|
if new_full_path: |
|
|
if new_full_path: |
|
|
backend._add_b64_data(new_full_path, datas) |
|
|
backend._add_b64_data(new_full_path, datas) |
|
|
if self.after_import in ( |
|
|
if self.after_import in ( |
|
|
'delete', 'rename', 'move', 'move_rename' |
|
|
|
|
|
|
|
|
"delete", |
|
|
|
|
|
"rename", |
|
|
|
|
|
"move", |
|
|
|
|
|
"move_rename", |
|
|
): |
|
|
): |
|
|
backend._delete(full_absolute_path) |
|
|
backend._delete(full_absolute_path) |
|
|
total_import += 1 |
|
|
total_import += 1 |
|
@ -177,8 +199,12 @@ class AttachmentSynchronizeTask(models.Model): |
|
|
raise e |
|
|
raise e |
|
|
else: |
|
|
else: |
|
|
new_env.cr.commit() |
|
|
new_env.cr.commit() |
|
|
_logger.info('Run import complete! Imported {0} files'.format(total_import)) |
|
|
|
|
|
|
|
|
_logger.info( |
|
|
|
|
|
"Run import complete! Imported {0} files".format(total_import) |
|
|
|
|
|
) |
|
|
|
|
|
|
|
|
def _file_to_import(self, filenames): |
|
|
def _file_to_import(self, filenames): |
|
|
imported = self.attachment_ids.filtered(lambda r: r.name in filenames).mapped('name') |
|
|
|
|
|
|
|
|
imported = self.attachment_ids.filtered( |
|
|
|
|
|
lambda r: r.name in filenames |
|
|
|
|
|
).mapped("name") |
|
|
return list(set(filenames) - set(imported)) |
|
|
return list(set(filenames) - set(imported)) |