241 lines
12 KiB
Python
241 lines
12 KiB
Python
# -*- coding: utf-8 -*-
|
|
# Part of Odoo. See LICENSE file for full copyright and licensing details.
|
|
|
|
from dateutil.relativedelta import relativedelta
|
|
|
|
from odoo import api, fields, models, _, Command
|
|
from odoo.exceptions import UserError
|
|
from odoo.tools import format_list
|
|
|
|
|
|
class SignSendRequest(models.TransientModel):
|
|
_name = 'sign.send.request'
|
|
_description = 'Sign send request'
|
|
|
|
@api.model
|
|
def default_get(self, fields):
|
|
res = super(SignSendRequest, self).default_get(fields)
|
|
if res.get('template_id'):
|
|
template = self.env['sign.template'].browse(res['template_id'])
|
|
res['has_default_template'] = True
|
|
elif res.get('activity_id'):
|
|
activity = self.env['mail.activity'].browse(res['activity_id'])
|
|
if template := activity.activity_type_id.default_sign_template_id:
|
|
if not template.has_access('read'):
|
|
return res
|
|
res['template_id'] = template.id
|
|
else:
|
|
return res
|
|
else:
|
|
return res
|
|
template._check_send_ready()
|
|
if 'filename' in fields:
|
|
res['filename'] = template.display_name
|
|
if 'subject' in fields:
|
|
res['subject'] = _("Signature Request - %(file_name)s", file_name=template.attachment_id.name)
|
|
if 'signers_count' in fields or 'signer_ids' in fields or 'signer_id' in fields:
|
|
roles = template.sign_item_ids.responsible_id.sorted()
|
|
if 'signers_count' in fields:
|
|
res['signers_count'] = len(roles)
|
|
if self.env.context.get('sign_directly_without_mail'):
|
|
default_signer = res.get("signer_id") or self.env.user.partner_id.id
|
|
if not roles and 'signer_id' in fields:
|
|
res['signer_id'] = default_signer
|
|
return res
|
|
|
|
@api.model
|
|
def _default_signer_ids(self):
|
|
template = self.env['sign.template']
|
|
if self.env.context.get('active_model') == 'sign.template':
|
|
template = self.env['sign.template'].browse(self.env.context.get('active_id'))
|
|
if not template:
|
|
return []
|
|
template._check_send_ready()
|
|
default_signer = self.env.context.get("default_signer_id", self.env.user.partner_id.id)
|
|
roles = template.sign_item_ids.responsible_id.sorted()
|
|
signer_ids = []
|
|
user_role_id = self.env['ir.model.data']._xmlid_to_res_id('sign.sign_item_role_user')
|
|
for default_signing_order, role in enumerate(roles):
|
|
signer_vals = {
|
|
'role_id': role.id,
|
|
'partner_id': False,
|
|
'mail_sent_order': default_signing_order + 1 if self.set_sign_order else 1,
|
|
}
|
|
if len(roles) == 1:
|
|
# sigle signer always get the current partner default value
|
|
signer_vals['partner_id'] = default_signer
|
|
else:
|
|
if role.id == user_role_id:
|
|
signer_vals['partner_id'] = default_signer
|
|
break
|
|
signer_ids.append((0, 0, signer_vals))
|
|
return signer_ids
|
|
|
|
activity_id = fields.Many2one('mail.activity', 'Linked Activity', readonly=True)
|
|
reference_doc = fields.Char(string="Linked to", readonly=True)
|
|
has_default_template = fields.Boolean()
|
|
template_id = fields.Many2one(
|
|
'sign.template', required=True, ondelete='cascade',
|
|
default=lambda self: self.env.context.get('active_id', None),
|
|
)
|
|
signer_ids = fields.One2many('sign.send.request.signer', 'sign_send_request_id', string="Signers", default=_default_signer_ids)
|
|
set_sign_order = fields.Boolean(string="Signing Order",
|
|
help="""Specify the order for each signer. The signature request only gets sent to \
|
|
the next signers in the sequence when all signers from the previous level have \
|
|
signed the document.
|
|
""")
|
|
signer_id = fields.Many2one('res.partner', string="Send To")
|
|
signers_count = fields.Integer()
|
|
cc_partner_ids = fields.Many2many('res.partner', string="Copy to", help="Contacts in copy will be notified by email once the document is either fully signed or refused.")
|
|
is_user_signer = fields.Boolean(compute='_compute_is_user_signer')
|
|
|
|
subject = fields.Char(string="Subject", required=True)
|
|
message = fields.Html("Message", help="Message to be sent to signers of the specified document")
|
|
message_cc = fields.Html("CC Message", help="Message to be sent to contacts in copy of the signed document")
|
|
attachment_ids = fields.Many2many('ir.attachment', string='Attachments')
|
|
filename = fields.Char("Filename", required=True)
|
|
|
|
validity = fields.Date(string='Valid Until', default=lambda self: fields.Date.today() + relativedelta(months=6), help="Leave empty for requests without expiration.")
|
|
reminder_enabled = fields.Boolean(default=False)
|
|
reminder = fields.Integer(string='Reminder', default=7)
|
|
|
|
@api.onchange('validity')
|
|
def _onchange_validity(self):
|
|
if self.validity and self.validity < fields.Date.today():
|
|
raise UserError(_('Request expiration date must be set in the future.'))
|
|
|
|
@api.onchange('reminder')
|
|
def _onchange_reminder(self):
|
|
if self.reminder > 365:
|
|
self.reminder = 365
|
|
|
|
@api.onchange('template_id', 'set_sign_order')
|
|
def _onchange_template_id(self):
|
|
self.signer_id = False
|
|
self.filename = self.template_id.display_name
|
|
self.subject = _("Signature Request - %s", self.template_id.attachment_id.name or '')
|
|
roles = self.template_id.mapped('sign_item_ids.responsible_id').sorted()
|
|
if self.signer_ids and len(self.signer_ids) == len(roles):
|
|
signer_ids = [(0, 0, {
|
|
'role_id': signer.role_id,
|
|
'partner_id': signer.partner_id,
|
|
'mail_sent_order': default_signing_order + 1 if self.set_sign_order else 1
|
|
}) for default_signing_order, signer in enumerate(self.signer_ids)]
|
|
else:
|
|
signer_ids = [(0, 0, {
|
|
'role_id': role.id,
|
|
'partner_id': False,
|
|
'mail_sent_order': default_signing_order + 1 if self.set_sign_order else 1
|
|
}) for default_signing_order, role in enumerate(roles)]
|
|
if self.env.context.get('sign_directly_without_mail') or self.env.ref('sign.sign_item_role_user').id:
|
|
default_signer = self.env.context.get("default_signer_id", self.env.user.partner_id.id)
|
|
if len(roles) == 1 and signer_ids:
|
|
signer_ids[0][2]['partner_id'] = default_signer
|
|
elif not roles:
|
|
self.signer_id = default_signer
|
|
user_role = self.env.ref('sign.sign_item_role_user').id
|
|
for signer_val in signer_ids:
|
|
current_role = signer_val[2].get('role_id')
|
|
# user_role can't be deleted if already used.
|
|
if len(signer_val) == 3 and isinstance(current_role, int) and current_role == user_role:
|
|
signer_val[2]['partner_id'] = default_signer
|
|
break
|
|
self.signer_ids = [(5, 0, 0)] + signer_ids
|
|
self.signers_count = len(roles)
|
|
|
|
@api.depends('signer_ids.partner_id', 'signer_id', 'signers_count')
|
|
def _compute_is_user_signer(self):
|
|
if self.signers_count and self.env.user.partner_id in self.signer_ids.mapped('partner_id'):
|
|
self.is_user_signer = True
|
|
elif not self.signers_count and self.env.user.partner_id == self.signer_id:
|
|
self.is_user_signer = True
|
|
else:
|
|
self.is_user_signer = False
|
|
|
|
def _activity_done(self):
|
|
signatories = self.signer_id.name or format_list(self.env, self.signer_ids.partner_id.mapped('name'))
|
|
feedback = _('Signature requested for template: %(template)s\nSignatories: %(signatories)s', template=self.template_id.name, signatories=signatories)
|
|
self.activity_id._action_done(feedback=feedback)
|
|
|
|
def create_request(self):
|
|
template_id = self.template_id.id
|
|
if self.signers_count:
|
|
signers = [{'partner_id': signer.partner_id.id, 'role_id': signer.role_id.id, 'mail_sent_order': signer.mail_sent_order} for signer in self.signer_ids]
|
|
else:
|
|
signers = [{'partner_id': self.signer_id.id, 'role_id': self.env.ref('sign.sign_item_role_default').id, 'mail_sent_order': self.signer_ids.mail_sent_order}]
|
|
cc_partner_ids = self.cc_partner_ids.ids
|
|
reference = self.filename
|
|
subject = self.subject
|
|
message = self.message
|
|
message_cc = self.message_cc
|
|
attachment_ids = self.attachment_ids
|
|
sign_request = self.env['sign.request'].create({
|
|
'template_id': template_id,
|
|
'request_item_ids': [Command.create({
|
|
'partner_id': signer['partner_id'],
|
|
'role_id': signer['role_id'],
|
|
'mail_sent_order': signer['mail_sent_order'],
|
|
}) for signer in signers],
|
|
'reference': reference,
|
|
'subject': subject,
|
|
'message': message,
|
|
'message_cc': message_cc,
|
|
'attachment_ids': [Command.set(attachment_ids.ids)],
|
|
'validity': self.validity,
|
|
'reminder': self.reminder,
|
|
'reminder_enabled': self.reminder_enabled,
|
|
'reference_doc': self.reference_doc,
|
|
})
|
|
sign_request.message_subscribe(partner_ids=cc_partner_ids)
|
|
return sign_request
|
|
|
|
def send_request(self):
|
|
request = self.create_request()
|
|
self._create_request_log_note(request)
|
|
if self.activity_id:
|
|
self._activity_done()
|
|
return {'type': 'ir.actions.act_window_close'}
|
|
return request.go_to_document()
|
|
|
|
def _create_request_log_note(self, request):
|
|
if request.reference_doc:
|
|
model = request.reference_doc and self.env['ir.model']._get(request.reference_doc._name)
|
|
if model.is_mail_thread:
|
|
body = _("A signature request has been linked to this document: %s", request._get_html_link())
|
|
request.reference_doc.message_post(body=body)
|
|
body = _("%s has been linked to this sign request.", request.reference_doc._get_html_link())
|
|
request.message_post(body=body)
|
|
|
|
def sign_directly(self):
|
|
request = self.create_request()
|
|
if self.activity_id:
|
|
self._activity_done()
|
|
if self._context.get('sign_all'):
|
|
return request.go_to_signable_document(request.request_item_ids)
|
|
return request.go_to_signable_document()
|
|
|
|
|
|
class SignSendRequestSigner(models.TransientModel):
|
|
_name = "sign.send.request.signer"
|
|
_description = 'Sign send request signer'
|
|
|
|
role_id = fields.Many2one('sign.item.role', readonly=True, required=True)
|
|
partner_id = fields.Many2one('res.partner', required=True, string="Contact")
|
|
mail_sent_order = fields.Integer(string='Sign Order', default=1)
|
|
sign_send_request_id = fields.Many2one('sign.send.request')
|
|
|
|
def create(self, vals_list):
|
|
missing_roles = []
|
|
for vals in vals_list:
|
|
if not vals.get('partner_id'):
|
|
role_id = vals.get('role_id')
|
|
role = self.env['sign.item.role'].browse(role_id)
|
|
missing_roles.append(role.name)
|
|
if missing_roles:
|
|
missing_roles_str = ', '.join(missing_roles)
|
|
raise UserError(_(
|
|
'Please select recipients for the following roles: %(roles)s',
|
|
roles=missing_roles_str,
|
|
))
|
|
return super().create(vals_list)
|