Files
public/mklab_dms_document/models/document.py

295 lines
16 KiB
Python
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# -*- coding: utf-8 -*-
import logging
from odoo import api, fields, models, tools, exceptions
import datetime
from dateutil.relativedelta import relativedelta
from werkzeug import urls
import functools
import base64
_logger = logging.getLogger(__name__)
try:
from jinja2.sandbox import SandboxedEnvironment
mako_template_env = SandboxedEnvironment(
block_start_string="<%",
block_end_string="%>",
variable_start_string="${",
variable_end_string="}",
comment_start_string="<%doc>",
comment_end_string="</%doc>",
line_statement_prefix="%",
line_comment_prefix="##",
trim_blocks=True, # do not output newline after blocks
autoescape=True, # XML/HTML automatic escaping
)
mako_template_env.globals.update({
'str': str,
'quote': urls.url_quote,
'urlencode': urls.url_encode,
'datetime': datetime,
'len': len,
'abs': abs,
'min': min,
'max': max,
'sum': sum,
'filter': filter,
'reduce': functools.reduce,
'map': map,
'round': round,
'relativedelta': lambda *a, **kw: relativedelta(*a, **kw),
})
except ImportError:
_logger.warning("jinja2 not available, templating features will not work!")
class DmsDocumentChoiseTemplate(models.TransientModel):
_name = 'dms.choise_template'
_description = 'mklab_dms_document_choise_template'
temp_id = fields.Many2one(comodel_name='dms.template', string='Шаблон', domain="['|', ('company_id', '=', False), ('company_id', '=', company_id)]")
doc_id = fields.Many2one(comodel_name='dms.document', string='Документ')
company_id = fields.Many2one(comodel_name='res.company', string='Компания', required=True, index=True, default=lambda self: self.env.company)
def get_choise(self):
for s in self:
if s.temp_id:
s.doc_id.text = s.temp_id.text
class DmsDocumentTemplate(models.Model):
_name = 'dms.template'
_description = 'mklab_dms_document_template'
name = fields.Char(string='Номер', required='1', tracking=True) # Номер — для исходящих с использованием нумератора, для входящих вносится вручную
text = fields.Html(string='Текст', required='1', tracking=True) # Текст — hmtl
company_id = fields.Many2one(comodel_name='res.company', string='Компания', required=True, index=True, default=lambda self: self.env.company, tracking=True)
class DmsDocument(models.Model):
_name = 'dms.document'
_description = 'Документы'
_inherit = ['portal.mixin', 'mail.thread', 'mail.activity.mixin', 'utm.mixin']
_description = 'mklab_dms_document'
def create_pdf(self):
report_action = self.env.ref('mklab_dms_document.action_report_dms_document').sudo()
for s in self:
if s.type_document=='outgoing':
pdf, _ = report_action._render_qweb_pdf(report_action.report_name, [s.id])
s.incoming_file = base64.b64encode(pdf)
s.incoming_file_type = 'pdf'
if not s.incoming_file and s.incoming_file_type == 'pdf':
raise exceptions.UserError('Не указан файл для сохранения')
if not s.incoming_file_other and s.incoming_file_type != 'pdf':
raise exceptions.UserError('Не указан файл для сохранения')
if not s.directory_id:
raise exceptions.UserError('Не указана директория для сохранения файла')
content = s.incoming_file if s.incoming_file_type == 'pdf' else s.incoming_file_other
save_file = self.env['dms.file'].sudo().create({
'name': s.name,
'directory_id': s.directory_id.id,
'content': content,
})
s.file = save_file
s.state = 'done'
def open_choise_template(self):
company_id = False
if self.company_id:
company_id = self.company_id.id
return {
'type': 'ir.actions.act_window',
'name': "Выберите шаблон",
'res_model': 'dms.choise_template',
'target': 'new',
'view_mode': 'form',
'context': {'default_doc_id': self.id, 'company_id': company_id},
}
def unlink(self):
for s in self:
if s.state=='done':
raise exceptions.ValidationError('Нельзя удалить документ, записанный в хранилище')
res = super().unlink()
return res
def get_number(self):
type_document = str(self.env.context.get('default_type_document'))
if self.type_document:
type_document = self.type_document
if type_document == 'incoming':
self.name = self.env['ir.sequence'].next_by_code('dms.document_number')
return self.env['ir.sequence'].next_by_code('dms.document_number')
elif type_document == 'outgoing':
self.name = self.env['ir.sequence'].next_by_code('dms.document_number_out')
return self.env['ir.sequence'].next_by_code('dms.document_number_out')
elif type_document == 'internal':
self.name = self.env['ir.sequence'].next_by_code('dms.document_number_internal')
return self.env['ir.sequence'].next_by_code('dms.document_number_internal')
type_document = fields.Selection([('incoming','Входящий документ'),('outgoing','Исходящий документ'),('internal','Внутренний документ')], string='Тип', required="1", tracking=True) # Тип — список выбора (входящее, исходящее, внутреннее)
name = fields.Char(string='Номер', default=lambda r: r.get_number(), tracking=True) # Номер — для исходящих с использованием нумератора, для входящих вносится вручную
partner_id = fields.Many2one(comodel_name='res.partner', string='Контакт', required="1", domain="['|', ('company_id', '=', False), ('company_id', '=', company_id)]", tracking=True) # Контакт — от или для кого
date = fields.Date(string='Дата документа', default=lambda r: datetime.datetime.today(), required="1", tracking=True) # Дата документа
text = fields.Html(string='Текст') # Текст — hmtl
incoming_file = fields.Binary(string='Входящий файл (PDF)')
incoming_file_other = fields.Binary(string='Входящий файл')
incoming_file_type = fields.Selection([('pdf','PDF'),('other','Другой')], string='Тип входящего файла', default='pdf',tracking=True)
text_str = fields.Text(string='Текст') # Текст — hmtl
text_render = fields.Html(string='Текст render') # Текст — hmtl
file = fields.Many2one(comodel_name='dms.file', string='Связанный файл', domain="['|', ('company_id', '=', False), ('company_id', '=', company_id)]", tracking=True) # Связанный dms.file
link_model = fields.Many2one(comodel_name='ir.model', string='Связанная модель', tracking=True) # Связанная модель (не обязательно)
res_id = fields.Integer(string='ID документа в связанной модели', tracking=True) # ID документа в связанной модели (res_id, не обязательно)
# Эти поля потребуются только для заполнения переменных внутри текста
print_head = fields.Boolean(string='Печатать шапку', default=False, tracking=True) # Признак печати шапки - булево
state = fields.Selection([('draft','Черновик'),('done','Записано в хранилище')], string='Статус', default='draft', tracking=True) # Статус — черновик, записано в хранилище
parent_id = fields.Many2one(comodel_name='dms.document', string='Ссылка на родительский документ', domain="[('id', '!=', id),'|',('partner_id', '=', partner_id),('partner_id.parent_id', '=', partner_id),'|', ('company_id', '=', False), ('company_id', '=', company_id)]", tracking=True) #Ссылка на другой (родительский) документ
child_ids = fields.One2many(comodel_name='dms.document', inverse_name='parent_id', string='Direct subordinates')
subordinate_ids = fields.One2many(comodel_name='dms.document', string='Subordinates', compute='_compute_subordinates', compute_sudo=True)
company_id = fields.Many2one(comodel_name='res.company', string='Компания', required=True, index=True, default=lambda self: self.env.company, tracking=True)
directory_id = fields.Many2one(
comodel_name="dms.directory",
string="Директория хранения",
domain="[('permission_create', '=', True), '|', ('company_id', '=', False), ('company_id', '=', company_id)]",
context={'dms_directory_show_path': True},
ondelete="restrict",
auto_join=True,
index=True,
tracking=True
#domain="['|', ('company_id', '=', False), ('company_id', '=', company_id)]"
)
child_all_count = fields.Integer(string='Indirect Surbordinates Count', compute='_compute_subordinates', store=False, compute_sudo=True)
def _get_subordinates(self, parents=None):
if not parents:
parents = self.env[self._name]
indirect_subordinates = self.env[self._name]
parents |= self
direct_subordinates = self.child_ids - parents
for child in direct_subordinates:
child_subordinate = child._get_subordinates(parents=parents)
indirect_subordinates |= child_subordinate
return indirect_subordinates | direct_subordinates
@api.depends('child_ids', 'child_ids.child_all_count')
def _compute_subordinates(self):
for doc in self:
doc.subordinate_ids = doc._get_subordinates()
doc.child_all_count = len(doc.subordinate_ids)
def render_template(self):
for s in self:
template = s.text
template_new = s.text
model = s.link_model.model
res_id = s.res_id
render_result = 'Не удалось обработать текст'
substrstart = "${"
substrend = "}"
substr_new_start = "<"
substr_new_end = ">"
flag = True
start = 0
s.text_str = ''
end = len(template)-1
while flag:
try: #search for the item
index = template.index(substrstart,start,end)
start = index+len(substrstart)
indexend = template.index(substrend,start,end)
substr = template[index:indexend+1]
substr_new_str = substr
#s.text_str += str(substr)+ '; '
if substr.find(substr_new_start)>0 and substr.find(substr_new_end)>0:
new_flag = True
start_new = 0
end_new = len(substr)-1
while new_flag:
try: #search for the item
index_new = substr.index(substr_new_start,start_new,end_new)
start_new = index_new+len(substr_new_start)
indexend_new = substr.index(substr_new_end,start_new,end_new)
substr_new = substr[index_new:indexend_new+1]
#s.text_str += str(index_new) + '-' + str(indexend_new) +':'+str(substr_new)+ '; '
substr_new_str = substr_new_str.replace(substr_new,'')
except ValueError:
new_flag=False
template_new = template_new.replace(substr,substr_new_str)
except ValueError:
flag = False
parent = ''
if s.parent_id:
type_doc_parent = dict(self._fields['type_document'].selection).get(s.parent_id.type_document)
parent = ' В ответ на {} {} от {}.'.format(type_doc_parent, s.parent_id.name,s.parent_id.date.strftime('%d.%m.%Y'))
type_doc = dict(self._fields['type_document'].selection).get(s.type_document)
s.text_str = '{} {} от {}.{}'.format(type_doc, s.name,s.date.strftime('%d.%m.%Y'), parent)
template = template_new
#res = re.findall(r"(${})", template)
try:
template = mako_template_env.from_string(tools.ustr(template))
except:
template = mako_template_env.from_string(tools.ustr(''))
user = self.env.user
variables = {
'user': user
}
if model and res_id:
record = self.env[model].browse(res_id)
variables['object'] = record
try:
render_result = template.render(variables)
except Exception:
_logger.error("Failed to render template %r using values %r" % (template, variables))
render_result = u""
if render_result == u"False":
render_result = u""
s.text_render = render_result
return render_result
# @api.model
# def create(self, vals):
# if 'name' in vals and 'type_document' in vals:
# if vals.get('name', ('New')) == '/' or vals['name'] == '' or vals['name'] == False:
# if vals['type_document'] == 'incoming':
# vals['name'] = self.env['ir.sequence'].next_by_code('dms.document_number')
# if vals['type_document'] == 'outgoing':
# vals['name'] = self.env['ir.sequence'].next_by_code('dms.document_number_out')
# if vals['type_document'] == 'internal':
# vals['name'] = self.env['ir.sequence'].next_by_code('dms.document_number_internal')
# for s in self:
# if not s.name:
# if s.type_document == 'incoming':
# raise exceptions.ValidationError(self.env['ir.sequence'].next_by_code('dms.document_number'))
# s.name = self.env['ir.sequence'].next_by_code('dms.document_number')
# if s.type_document == 'outgoing':
# s.name = self.env['ir.sequence'].next_by_code('dms.document_number_out')
# if s.type_document == 'internal':
# s.name = self.env['ir.sequence'].next_by_code('dms.document_number_internal')
# res = super(mklab_dms_document, self).create(vals)
# return res
# def write(self, vals):
# if 'name' in vals and 'type_document' in vals:
# if vals.get('name', ('New')) == '/' or vals['name'] == '' or vals['name'] == False:
# if vals['type_document'] == 'incoming':
# vals['name'] = self.env['ir.sequence'].next_by_code('dms.document_number')
# if vals['type_document'] == 'outgoing':
# vals['name'] = self.env['ir.sequence'].next_by_code('dms.document_number_out')
# if vals['type_document'] == 'internal':
# vals['name'] = self.env['ir.sequence'].next_by_code('dms.document_number_internal')
# if not self.name:
# if self.type_document == 'incoming':
# raise exceptions.ValidationError(self.env['ir.sequence'].next_by_code('dms.document_number'))
# self.name = self.env['ir.sequence'].next_by_code('dms.document_number')
# if self.type_document == 'outgoing':
# self.name = self.env['ir.sequence'].next_by_code('dms.document_number_out')
# if self.type_document == 'internal':
# self.name = self.env['ir.sequence'].next_by_code('dms.document_number_internal')
# res = super(mklab_dms_document, self).write(vals)
# return res