update approval module (WIP)
This commit is contained in:
parent
b8024171a2
commit
16ca87bc01
@ -33,6 +33,7 @@ creates next activities for the related approvers.
|
||||
'report/approval_request_report.xml',
|
||||
'views/approval_request_views.xml',
|
||||
'views/res_users_views.xml',
|
||||
'views/approval_condition_views.xml'
|
||||
],
|
||||
'demo':[
|
||||
'data/approval_demo.xml',
|
||||
|
@ -7,3 +7,4 @@ from . import approval_product_line
|
||||
from . import approval_request
|
||||
from . import mail_activity
|
||||
from . import ir_attachment
|
||||
from . import approval_condition
|
||||
|
@ -95,6 +95,8 @@ class ApprovalCategory(models.Model):
|
||||
copy=False, check_company=True)
|
||||
|
||||
model_id = fields.Many2one('ir.model', 'Model',copy=False)
|
||||
|
||||
conditions_ids = fields.Many2many('approval.condition', 'approval_category_condition_rel', 'category_id', 'condition_id')
|
||||
# ---------------------------------------- Methods -----------------------------------------
|
||||
|
||||
def _compute_request_to_validate_count(self):
|
||||
|
77
extra-addons/approvals/models/approval_condition.py
Normal file
77
extra-addons/approvals/models/approval_condition.py
Normal file
@ -0,0 +1,77 @@
|
||||
from odoo import api, fields, models
|
||||
|
||||
class ApprovalConditions(models.Model):
|
||||
_name = 'approval.condition'
|
||||
_description = 'Approval Condition'
|
||||
_order = 'sequence, id'
|
||||
|
||||
name = fields.Char(string="Name", required=True)
|
||||
description = fields.Text(string="Description", required=True)
|
||||
|
||||
filter_pre_condition = fields.Char(
|
||||
string='Condition',
|
||||
compute='_compute_filter_pre_condition',
|
||||
readonly=False, store=True,
|
||||
help="If present, this condition must be satisfied before the update of the record. "
|
||||
"Not checked on record creation.")
|
||||
|
||||
trigger = fields.Selection(
|
||||
[
|
||||
('on_stage_set', "Stage is set to"),
|
||||
('on_user_set', "User is set"),
|
||||
('on_tag_set', "Tag is added"),
|
||||
('on_state_set', "State is set to"),
|
||||
('on_priority_set', "Priority is set to"),
|
||||
('on_archive', "On archived"),
|
||||
('on_unarchive', "On unarchived"),
|
||||
('on_create_or_write', "On save"),
|
||||
('on_create', "On creation"), # deprecated, use 'on_create_or_write' instead
|
||||
('on_write', "On update"), # deprecated, use 'on_create_or_write' instead
|
||||
('on_unlink', "On deletion"),
|
||||
('on_change', "On UI change"),
|
||||
('on_time', "Based on date field"),
|
||||
('on_time_created', "After creation"),
|
||||
('on_time_updated', "After last update"),
|
||||
("on_message_received", "On incoming message"),
|
||||
("on_message_sent", "On outgoing message"),
|
||||
('on_webhook', "On webhook"),
|
||||
], string='Trigger',
|
||||
compute='_compute_trigger', readonly=False, store=True, required=True
|
||||
)
|
||||
|
||||
trigger_field_ids = fields.Many2many(
|
||||
'ir.model.fields', string='Trigger Fields',
|
||||
compute='_compute_trigger_field_ids', readonly=False, store=True,
|
||||
help="The automation rule will be triggered if and only if one of these fields is updated."
|
||||
"If empty, all fields are watched.")
|
||||
|
||||
trg_field_ref = fields.Reference(
|
||||
selection=[('ir.model.fields', 'Field Reference')],
|
||||
string='Trigger Reference',
|
||||
readonly=False,
|
||||
store=True,
|
||||
help="Some triggers need a reference to another field. This field is used to store it."
|
||||
)
|
||||
|
||||
sequence = fields.Boolean('Approvers Sequence?', help="If checked, the approvers have to approve in sequence.")
|
||||
approval_minimum = fields.Integer(string="Minimum Approval", default=1, required=True)
|
||||
user_ids = fields.Many2many('res.users', compute='_compute_user_ids', string="Approver Users")
|
||||
approver_ids = fields.One2many('approval.category.approver', 'category_id', string="Approvers")
|
||||
@api.depends('approver_ids')
|
||||
def _compute_user_ids(self):
|
||||
for record in self:
|
||||
record.user_ids = record.approver_ids.user_id
|
||||
@api.depends('trigger', 'trigger_field_ids', 'trg_field_ref')
|
||||
def _compute_filter_pre_condition(self):
|
||||
for automation in self:
|
||||
if automation.trigger != 'on_tag_set' or len(automation.trigger_field_ids) != 1:
|
||||
automation.filter_pre_condition = False
|
||||
else:
|
||||
field = automation.trigger_field_ids.name
|
||||
value = automation.trg_field_ref
|
||||
automation.filter_pre_condition = f"[('{field}', 'not in', [{value}])]" if value else False
|
||||
|
||||
def delete_condition(self):
|
||||
for record in self:
|
||||
record.unlink()
|
||||
|
@ -13,3 +13,5 @@ access_approval_approver_user,access_approval_approver,model_approval_approver,g
|
||||
access_approval_approver_manager,access_approval_approver,model_approval_approver,group_approval_manager,1,1,1,1
|
||||
access_approval_product_line_user,access_approval_product_line,model_approval_product_line,base.group_user,1,1,1,1
|
||||
access_approval_product_line_manager,access_approval_product_line,model_approval_product_line,group_approval_manager,1,1,1,1
|
||||
access_approval_condition,access_approval_condition,model_approval_condition,base.group_user,1,1,1,1
|
||||
|
||||
|
|
@ -0,0 +1,52 @@
|
||||
.o_approvals_category_actions_field,
|
||||
.o_approvals_category_kanban_view {
|
||||
.o_kanban_ungrouped {
|
||||
padding: 0;
|
||||
|
||||
.o_kanban_record {
|
||||
width: 30%;
|
||||
margin: 0;
|
||||
|
||||
&.o_kanban_ghost {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.o_approvals_category_actions_field .o_kanban_ghost {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.o_approvals_category_kanban_view {
|
||||
.o_kanban_grouped .row {
|
||||
flex-direction: column !important;
|
||||
gap: 0.5rem !important;
|
||||
|
||||
> * {
|
||||
width: 100% !important;
|
||||
|
||||
> * {
|
||||
margin: 0 0.5rem !important;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.o_kanban_ungrouped .o_kanban_record .oe_kanban_global_click {
|
||||
border-top: 0;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
|
||||
.o_widget_web_ribbon {
|
||||
align-self: flex-start;
|
||||
}
|
||||
}
|
||||
}
|
||||
.o_form_view .o_group .o_field_widget, .o_form_view .o_inner_group .o_field_widget {
|
||||
width: 50%;
|
||||
}
|
||||
.o_approvals_category_error {
|
||||
pre {
|
||||
max-height: 25vh !important;
|
||||
}
|
||||
}
|
@ -76,39 +76,54 @@
|
||||
<field name="company_id" options="{'no_create': True}" groups="base.group_multi_company"/>
|
||||
</group>
|
||||
<notebook>
|
||||
<page string="Coditions" name="conditions">
|
||||
<group>
|
||||
<!-- <group string="Fields" name="option_settings">
|
||||
<field name="active" invisible="1"/>
|
||||
<field name="requirer_document" string="Document" widget="radio" options="{'horizontal': true}"/>
|
||||
<field name="has_partner" string="Contact" widget="radio" options="{'horizontal': true}"/>
|
||||
<field name="has_date" string="Date" widget="radio" options="{'horizontal': true}"/>
|
||||
<field name="has_period" string="Period" widget="radio" options="{'horizontal': true}"/>
|
||||
<field name="has_product" string="Product" force_save="1"
|
||||
widget="radio" options="{'horizontal': true}"/>
|
||||
<field name="has_quantity" string="Quantity" widget="radio" options="{'horizontal': true}"/>
|
||||
<field name="has_amount" string="Amount" widget="radio" options="{'horizontal': true}"/>
|
||||
<field name="has_reference" string="Reference" widget="radio" options="{'horizontal': true}"/>
|
||||
<field name="has_payment_method" string="Payment" widget="radio" options="{'horizontal': true}" invisible="1"/>
|
||||
<field name="has_location" string="Location" widget="radio" options="{'horizontal': true}"/>
|
||||
</group> -->
|
||||
<!-- <group string="Approvers" name="approvers">
|
||||
<field name="manager_approval"/>
|
||||
<separator colspan="2"/>
|
||||
<field name="approver_ids"/>
|
||||
<field name="approver_sequence" invisible="approval_minimum == 0"/>
|
||||
<field name="approval_minimum"/>
|
||||
<field name="invalid_minimum" invisible="1"/>
|
||||
<div class="text-warning" colspan="2" invisible="not invalid_minimum">
|
||||
<span class="fa fa-warning" title="Invalid minimum approvals"/><field name="invalid_minimum_warning" nolabel="1"/>
|
||||
</div>
|
||||
</group> -->
|
||||
<page string="Options">
|
||||
<!-- <group string="Fields" name="option_settings">
|
||||
<field name="active" invisible="1"/>
|
||||
<field name="requirer_document" string="Document" widget="radio" options="{'horizontal': true}"/>
|
||||
<field name="has_partner" string="Contact" widget="radio" options="{'horizontal': true}"/>
|
||||
<field name="has_date" string="Date" widget="radio" options="{'horizontal': true}"/>
|
||||
<field name="has_period" string="Period" widget="radio" options="{'horizontal': true}"/>
|
||||
<field name="has_product" string="Product" force_save="1" widget="radio" options="{'horizontal': true}"/>
|
||||
<field name="has_quantity" string="Quantity" widget="radio" options="{'horizontal': true}"/>
|
||||
<field name="has_amount" string="Amount" widget="radio" options="{'horizontal': true}"/>
|
||||
<field name="has_reference" string="Reference" widget="radio" options="{'horizontal': true}"/>
|
||||
<field name="has_payment_method" string="Payment" widget="radio" options="{'horizontal': true}" invisible="1"/>
|
||||
<field name="has_location" string="Location" widget="radio" options="{'horizontal': true}"/>
|
||||
</group> -->
|
||||
|
||||
<!-- <group string="Approvers" name="approvers">
|
||||
<field name="manager_approval"/>
|
||||
<separator colspan="2"/>
|
||||
<field name="approver_ids"/>
|
||||
<field name="approver_sequence" invisible="approval_minimum == 0"/>
|
||||
<field name="approval_minimum"/>
|
||||
<field name="invalid_minimum" invisible="1"/>
|
||||
<div class="text-warning" colspan="2" invisible="not invalid_minimum">
|
||||
<span class="fa fa-warning" title="Invalid minimum approvals"/><field name="invalid_minimum_warning" nolabel="1"/>
|
||||
</div>
|
||||
</group> -->
|
||||
<group>
|
||||
<field name="conditions_ids"
|
||||
nolabel="1"
|
||||
widget="many2many"
|
||||
class="o_approvals_category_actions_field"
|
||||
context="{'default_model_id': model_id, 'form_view_ref': 'approvals.approval_condition_view_form', 'list_view_ref': 'approvals.approval_condition_view_list'}"
|
||||
width="20%">
|
||||
<kanban>
|
||||
<control>
|
||||
<create string="Add Condition" />
|
||||
</control>
|
||||
<templates>
|
||||
<t t-name="card" class="flex-row align-items-center gap-1">
|
||||
<field name="sequence" widget="handle" class="px-1" width="10%" />
|
||||
<field name="name" class="text-truncate" />
|
||||
<button type="delete" name="delete" class="btn fa fa-trash fa-xl px-3 ms-auto" title="Delete Condition" />
|
||||
</t>
|
||||
</templates>
|
||||
</kanban>
|
||||
</field>
|
||||
</group>
|
||||
</page>
|
||||
<page string="Code">
|
||||
<field name="code" widget="code" options="{'mode': 'python'}" placeholder="Enter Python code here. Help about Python expression is available in the help tab of this document."/>
|
||||
</page>
|
||||
</notebook>
|
||||
</sheet>
|
||||
</form>
|
||||
|
44
extra-addons/approvals/views/approval_condition_views.xml
Normal file
44
extra-addons/approvals/views/approval_condition_views.xml
Normal file
@ -0,0 +1,44 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<odoo>
|
||||
<record id="approval_condition_view_form" model="ir.ui.view">
|
||||
<field name="name">approval.condition.form</field>
|
||||
<field name="model">approval.condition</field>
|
||||
<field name="arch" type="xml">
|
||||
<form>
|
||||
<sheet>
|
||||
<group string="Conditions" name="conditions">
|
||||
<!-- <field name="filter_pre_condition" widget="domain" groups="base.group_no_one"
|
||||
options="{'model': 'approval.condition', 'in_dialog': True}"
|
||||
invisible="trigger in ['on_webhook', 'on_time', 'on_time_created', 'on_time_updated']" /> -->
|
||||
</group>
|
||||
<group string="Approvers" name="approvers">
|
||||
<field name="approver_ids" widget="many2many_tags">
|
||||
<list>
|
||||
<field name="name"/>
|
||||
<field name="job_title"/>
|
||||
</list>
|
||||
</field>
|
||||
<field name="name"/>
|
||||
<field name="sequence"/>
|
||||
<field name="approval_minimum"/>
|
||||
<field name="description"/>
|
||||
</group>
|
||||
</sheet>
|
||||
</form>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<record id="approval_condition_view_list" model="ir.ui.view">
|
||||
<field name="name">approval.condition.list</field>
|
||||
<field name="model">approval.condition</field>
|
||||
<field name="arch" type="xml">
|
||||
<list>
|
||||
<field name="name"/>
|
||||
<field name="description"/>
|
||||
<field name="sequence" class="text-truncate" />
|
||||
<field name="approval_minimum" class="text-truncate" />
|
||||
<button name="delete_condition" type="object" class="btn fa fa-trash fa-xl px-3 ms-auto" title="Delete Condition" />
|
||||
</list>
|
||||
</field>
|
||||
</record>
|
||||
</odoo>
|
@ -1,5 +1,5 @@
|
||||
from odoo.exceptions import ValidationError,UserError
|
||||
from odoo import api, fields, models
|
||||
from odoo import api, fields, models, exceptions
|
||||
from datetime import date
|
||||
class HRPromote(models.Model):
|
||||
# ----------------------------------- Private Attributes ---------------------------------
|
||||
@ -71,23 +71,30 @@ class HRPromote(models.Model):
|
||||
else:
|
||||
record.name = "Promotion"
|
||||
@api.model
|
||||
def create(self, vals):
|
||||
vals['state'] = 'approval_needed'
|
||||
if 'employee_id' in vals and not vals.get('job_id'):
|
||||
employee = self.env['hr.employee'].browse(vals['employee_id'])
|
||||
vals['job_id'] = employee.job_id.id if employee.job_id else False
|
||||
def create(self, vals_list):
|
||||
# Ensure vals_list is always a list
|
||||
if isinstance(vals_list, dict):
|
||||
vals_list = [vals_list]
|
||||
|
||||
if not vals.get('job_id'):
|
||||
raise ValueError("The employee does not have a current job position.")
|
||||
promotion_record = super().create(vals)
|
||||
# Create the approval request related to the promotion
|
||||
self.env['approval.request'].create({
|
||||
'employee_id': vals['employee_id'],
|
||||
'promotion_record_id': promotion_record.id,
|
||||
'state': 'draft', # You can adjust this based on your workflow
|
||||
'approval_type': 'promotion', # Custom field for the type of approval
|
||||
})
|
||||
return promotion_record
|
||||
promotion_records = []
|
||||
for vals in vals_list:
|
||||
# Set default state
|
||||
vals['state'] = 'approval_needed'
|
||||
|
||||
# Handle employee's job_id logic
|
||||
if 'employee_id' in vals and not vals.get('job_id'):
|
||||
employee = self.env['hr.employee'].browse(vals['employee_id'])
|
||||
vals['job_id'] = employee.job_id.id if employee.job_id else False
|
||||
|
||||
# Validate job_id existence
|
||||
if not vals.get('job_id'):
|
||||
raise exceptions.ValidationError("The employee does not have a current job position.")
|
||||
|
||||
# Create the promotion record
|
||||
promotion_record = super(HRPromote, self).create(vals)
|
||||
promotion_records.append(promotion_record)
|
||||
|
||||
return self.browse([record.id for record in promotion_records])
|
||||
def action_save_and_close(self):
|
||||
return {
|
||||
'type': 'ir.actions.act_window',
|
||||
|
Loading…
Reference in New Issue
Block a user