forked from Mapan/odoo17e
163 lines
8.6 KiB
Python
163 lines
8.6 KiB
Python
# -*- coding: utf-8 -*-
|
|
# Part of Odoo. See LICENSE file for full copyright and licensing details.
|
|
|
|
import base64
|
|
|
|
from odoo import api, fields, models, tools, _
|
|
from odoo.exceptions import ValidationError
|
|
|
|
|
|
CATEGORY_SELECTION = [
|
|
('required', 'Required'),
|
|
('optional', 'Optional'),
|
|
('no', 'None')]
|
|
|
|
|
|
class ApprovalCategory(models.Model):
|
|
_name = 'approval.category'
|
|
_description = 'Approval Category'
|
|
_order = 'sequence, id'
|
|
|
|
_check_company_auto = True
|
|
|
|
def _get_default_image(self):
|
|
default_image_path = 'approvals/static/src/img/Folder.png'
|
|
return base64.b64encode(tools.misc.file_open(default_image_path, 'rb').read())
|
|
|
|
name = fields.Char(string="Name", translate=True, required=True)
|
|
company_id = fields.Many2one(
|
|
'res.company', 'Company', copy=False,
|
|
required=True, index=True, default=lambda s: s.env.company)
|
|
active = fields.Boolean(default=True)
|
|
sequence = fields.Integer(string="Sequence")
|
|
description = fields.Char(string="Description", translate=True)
|
|
image = fields.Binary(string='Image', default=_get_default_image)
|
|
has_date = fields.Selection(CATEGORY_SELECTION, string="Has Date", default="no", required=True)
|
|
has_period = fields.Selection(CATEGORY_SELECTION, string="Has Period", default="no", required=True)
|
|
has_quantity = fields.Selection(CATEGORY_SELECTION, string="Has Quantity", default="no", required=True)
|
|
has_amount = fields.Selection(CATEGORY_SELECTION, string="Has Amount", default="no", required=True)
|
|
has_reference = fields.Selection(
|
|
CATEGORY_SELECTION, string="Has Reference", default="no", required=True,
|
|
help="An additional reference that should be specified on the request.")
|
|
has_partner = fields.Selection(CATEGORY_SELECTION, string="Has Contact", default="no", required=True)
|
|
has_payment_method = fields.Selection(CATEGORY_SELECTION, string="Has Payment", default="no", required=True)
|
|
has_location = fields.Selection(CATEGORY_SELECTION, string="Has Location", default="no", required=True)
|
|
has_product = fields.Selection(
|
|
CATEGORY_SELECTION, string="Has Product", default="no", required=True,
|
|
help="Additional products that should be specified on the request.")
|
|
requirer_document = fields.Selection([('required', 'Required'), ('optional', 'Optional')], string="Documents", default="optional", required=True)
|
|
approval_minimum = fields.Integer(string="Minimum Approval", default="1", required=True)
|
|
invalid_minimum = fields.Boolean(compute='_compute_invalid_minimum')
|
|
invalid_minimum_warning = fields.Char(compute='_compute_invalid_minimum')
|
|
approval_type = fields.Selection(string="Approval Type", selection=[],
|
|
help="Allows you to define which documents you would like to create once the request has been approved")
|
|
manager_approval = fields.Selection([('approver', 'Is Approver'), ('required', 'Is Required Approver')],
|
|
string="Employee's Manager",
|
|
help="""How the employee's manager interacts with this type of approval.
|
|
|
|
Empty: do nothing
|
|
Is Approver: the employee's manager will be in the approver list
|
|
Is Required Approver: the employee's manager will be required to approve the request.
|
|
""")
|
|
user_ids = fields.Many2many('res.users', compute='_compute_user_ids', string="Approver Users")
|
|
approver_ids = fields.One2many('approval.category.approver', 'category_id', string="Approvers")
|
|
approver_sequence = fields.Boolean('Approvers Sequence?', help="If checked, the approvers have to approve in sequence (one after the other). If Employee's Manager is selected as approver, they will be the first in line.")
|
|
request_to_validate_count = fields.Integer("Number of requests to validate", compute="_compute_request_to_validate_count")
|
|
automated_sequence = fields.Boolean('Automated Sequence?',
|
|
help="If checked, the Approval Requests will have an automated generated name based on the given code.")
|
|
sequence_code = fields.Char(string="Code")
|
|
sequence_id = fields.Many2one('ir.sequence', 'Reference Sequence',
|
|
copy=False, check_company=True)
|
|
|
|
def _compute_request_to_validate_count(self):
|
|
domain = [('request_status', '=', 'pending'), ('approver_ids.user_id', '=', self.env.user.id)]
|
|
requests_data = self.env['approval.request']._read_group(domain, ['category_id'], ['__count'])
|
|
requests_mapped_data = {category.id: count for category, count in requests_data}
|
|
for category in self:
|
|
category.request_to_validate_count = requests_mapped_data.get(category.id, 0)
|
|
|
|
@api.depends_context('lang')
|
|
@api.depends('approval_minimum', 'approver_ids', 'manager_approval')
|
|
def _compute_invalid_minimum(self):
|
|
for record in self:
|
|
if record.approval_minimum > len(record.approver_ids) + int(bool(record.manager_approval)):
|
|
record.invalid_minimum = True
|
|
else:
|
|
record.invalid_minimum = False
|
|
record.invalid_minimum_warning = record.invalid_minimum and _('Your minimum approval exceeds the total of default approvers.')
|
|
|
|
@api.depends('approver_ids')
|
|
def _compute_user_ids(self):
|
|
for record in self:
|
|
record.user_ids = record.approver_ids.user_id
|
|
|
|
@api.constrains('approval_minimum', 'approver_ids')
|
|
def _constrains_approval_minimum(self):
|
|
for record in self:
|
|
if record.approval_minimum < len(record.approver_ids.filtered('required')):
|
|
raise ValidationError(_('Minimum Approval must be equal or superior to the sum of required Approvers.'))
|
|
|
|
@api.constrains('approver_ids')
|
|
def _constrains_approver_ids(self):
|
|
# There seems to be a problem with how the database is updated which doesn't let use to an sql constraint for this
|
|
# Issue is: records seem to be created before others are saved, meaning that if you originally have only user a
|
|
# change user a to user b and add a new line with user a, the second line will be created and will trigger the constraint
|
|
# before the first line will be updated which wouldn't trigger a ValidationError
|
|
for record in self:
|
|
if len(record.approver_ids) != len(record.approver_ids.user_id):
|
|
raise ValidationError(_('An user may not be in the approver list multiple times.'))
|
|
|
|
@api.constrains('approver_sequence', 'approval_minimum')
|
|
def _constrains_approver_sequence(self):
|
|
if any(a.approver_sequence and not a.approval_minimum for a in self):
|
|
raise ValidationError(_('Approver Sequence can only be activated with at least 1 minimum approver.'))
|
|
|
|
@api.model_create_multi
|
|
def create(self, vals_list):
|
|
for vals in vals_list:
|
|
if vals.get('automated_sequence'):
|
|
sequence = self.env['ir.sequence'].create({
|
|
'name': _('Sequence') + ' ' + vals['sequence_code'],
|
|
'padding': 5,
|
|
'prefix': vals['sequence_code'],
|
|
'company_id': vals.get('company_id'),
|
|
})
|
|
vals['sequence_id'] = sequence.id
|
|
return super().create(vals_list)
|
|
|
|
def write(self, vals):
|
|
if 'sequence_code' in vals:
|
|
for approval_category in self:
|
|
sequence_vals = {
|
|
'name': _('Sequence') + ' ' + vals['sequence_code'],
|
|
'padding': 5,
|
|
'prefix': vals['sequence_code'],
|
|
}
|
|
if approval_category.sequence_id:
|
|
approval_category.sequence_id.write(sequence_vals)
|
|
else:
|
|
sequence_vals['company_id'] = vals.get('company_id', approval_category.company_id.id)
|
|
sequence = self.env['ir.sequence'].create(sequence_vals)
|
|
approval_category.sequence_id = sequence
|
|
if 'company_id' in vals:
|
|
for approval_category in self:
|
|
if approval_category.sequence_id:
|
|
approval_category.sequence_id.company_id = vals.get('company_id')
|
|
return super().write(vals)
|
|
|
|
def create_request(self):
|
|
self.ensure_one()
|
|
# If category uses sequence, set next sequence as name
|
|
# (if not, set category name as default name).
|
|
return {
|
|
"type": "ir.actions.act_window",
|
|
"res_model": "approval.request",
|
|
"views": [[False, "form"]],
|
|
"context": {
|
|
'default_name': _('New') if self.automated_sequence else self.name,
|
|
'default_category_id': self.id,
|
|
'default_request_owner_id': self.env.user.id,
|
|
'default_request_status': 'new'
|
|
},
|
|
}
|