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.
 
 
 

227 lines
8.0 KiB

# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).
import datetime
import logging
import os
import odoo
from odoo import api, fields, models, tools
from odoo.osv import expression
_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,
"map": map,
"round": round,
}
)
except ImportError:
_logger.warning("jinja2 not available, templating features will not work!")
class AttachmentSynchronizeTask(models.Model):
_name = "attachment.synchronize.task"
_description = "Attachment synchronize task"
name = fields.Char(required=True)
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")
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",
)
after_import = fields.Selection(
selection=[
("rename", "Rename"),
("move", "Move"),
("move_rename", "Move & Rename"),
("delete", "Delete"),
],
help="Action after import a file",
)
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",
)
enabled = fields.Boolean("Enabled", default=True)
check_duplicated_files = fields.Boolean(
string="Check duplicated files",
help="If checked, will avoid duplication file import",
)
emails = fields.Char(
string="Emails",
help="list of email which should be notified in case of failure "
"when excuting the files linked to this task",
)
def _prepare_attachment_vals(self, data, filename):
self.ensure_one()
vals = {
"name": filename,
"datas": data,
"datas_fname": filename,
"task_id": self.id,
"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_import_scheduler(self, domain=None):
if domain is None:
domain = []
domain = expression.AND(
[domain, [("method_type", "=", "import"), ("enabled", "=", True)]]
)
for task in self.search(domain):
task.run_import()
def run_import(self):
self.ensure_one()
attach_obj = self.env["attachment.queue"]
backend = self.backend_id
filepath = self.filepath or ""
filenames = backend._list(relative_path=filepath, pattern=self.pattern)
if self.check_duplicated_files:
filenames = self._file_to_import(filenames)
total_import = 0
for file_name in filenames:
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
)
try:
full_absolute_path = os.path.join(filepath, file_name)
data = backend._get_b64_data(full_absolute_path)
attach_vals = self._prepare_attachment_vals(
data, file_name
)
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(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:
backend._add_b64_data(new_full_path, data)
if self.after_import in (
"delete",
"rename",
"move",
"move_rename",
):
backend._delete(full_absolute_path)
total_import += 1
except Exception as e:
new_env.cr.rollback()
raise e
else:
new_env.cr.commit()
_logger.info(
"Run import complete! Imported {0} files".format(total_import)
)
def _file_to_import(self, filenames):
imported = (
self.env["attachment.queue"]
.search([("name", "in", filenames)])
.mapped("name")
)
return list(set(filenames) - set(imported))
def button_toogle_enabled(self):
for rec in self:
rec.enabled = not rec.enabled
def button_duplicate_record(self):
self.ensure_one()
record = self.copy({"enabled": False})
return {
"type": "ir.actions.act_window",
"res_model": record.backend_id._name,
"target": "current",
"view_mode": "form",
"res_id": record.backend_id.id,
}