Add card to dashboard to show average response time per employee for incoming transactions

This commit is contained in:
younes 2025-05-22 21:22:24 +01:00
parent e25105dc45
commit 8f820c1b59
8 changed files with 128 additions and 20 deletions

View File

@ -3637,3 +3637,57 @@ msgid ""
"You Can Not This Delete Subject Type, Because There is a Related "
"Transaction."
msgstr ".لا يمكنك حذف نوع المعاملة، لأنه توجد معاملات ذات صلة"
#. module: exp_transaction_documents
#: model:ir.model.fields,field_description:exp_transaction_documents.field_internal_transaction__last_response_date
msgid "Last Response Date"
msgstr "تاريخ آخر استجابة"
#. module: exp_transaction_documents
#: model:ir.model.fields,field_description:exp_transaction_documents.field_internal_transaction__response_time_str
msgid "Response Time"
msgstr "فترة إنجاز"
#. module: exp_transaction_documents
#: model:ir.model.fields,field_description:exp_transaction_documents.field_internal_transaction__response_days
msgid "Response Days"
msgstr "فترة الإنجاز (أيام)"
#. module: exp_transaction_documents
#: model:ir.model.fields,field_description:exp_transaction_documents.field_internal_transaction__response_hours
msgid "Response Hours"
msgstr "فترة الإنجاز (ساعات)"
#. module: exp_transaction_documents
#: model:ir.model.fields,field_description:exp_transaction_documents.field_internal_transaction__response_minutes
msgid "Response Minutes"
msgstr "فترة الإنجاز (دقائق)"
#. module: exp_transaction_documents
#: model:ir.model.fields,field_description:exp_transaction_documents.field_internal_transaction__response_seconds
msgid "Response Seconds"
msgstr "فترة الإنجاز (ثواني)"
#. module: exp_transaction_documents
#: code:addons/exp_transaction_documents/models/internal_transaction.py:0
#, python-format
msgid "%s day"
msgstr "%s يوم"
#. module: exp_transaction_documents
#: code:addons/exp_transaction_documents/models/internal_transaction.py:0
#, python-format
msgid "%s hour"
msgstr "%s ساعة"
#. module: exp_transaction_documents
#: code:addons/exp_transaction_documents/models/internal_transaction.py:0
#, python-format
msgid "%s minute"
msgstr "%s دقيقة"
#. module: exp_transaction_documents
#: code:addons/exp_transaction_documents/models/internal_transaction.py:0
#, python-format
msgid "%s second"
msgstr "%s ثانية"

View File

@ -1,7 +1,9 @@
# -*- coding: utf-8 -*-
from datetime import datetime
from datetime import datetime, timedelta
from odoo import models, api, fields, _
from odoo.exceptions import ValidationError
class InternalTransaction(models.Model):
_name = 'internal.transaction'
_inherit = ['transaction.transaction', 'mail.thread']
@ -22,37 +24,76 @@ class InternalTransaction(models.Model):
('employee', 'Employee'),
],
required=False, default='unit')
last_response_date = fields.Datetime(string="Last Response Date")
response_time_str = fields.Char(string="Response Time", compute="_compute_response_time_str", store=True)
response_days = fields.Integer(string="Response Days", compute="_compute_response_time", store=True ,group_operator='avg')
response_hours = fields.Integer(string="Response Hours", compute="_compute_response_time", store=True, group_operator='avg')
response_minutes = fields.Integer(string="Response Minutes", compute="_compute_response_time", store=True, group_operator='avg')
response_seconds = fields.Integer(string="Response Seconds", compute="_compute_response_time", store=True, group_operator='avg')
@api.depends('last_response_date', 'create_date')
def _compute_response_time(self):
for rec in self:
if rec.create_date and rec.last_response_date:
delta = rec.last_response_date - rec.create_date
total_seconds = int(delta.total_seconds())
rec.response_days = total_seconds // 86400
remainder = total_seconds % 86400
rec.response_hours = remainder // 3600
remainder = remainder % 3600
rec.response_minutes = remainder // 60
rec.response_seconds = remainder % 60
parts = []
if rec.response_days:
parts.append(_("%s day") % rec.response_days)
if rec.response_hours:
parts.append(_("%s hour") % rec.response_hours)
if rec.response_minutes:
parts.append(_("%s minute") % rec.response_minutes)
if rec.response_seconds or not parts:
parts.append(_("%s second") % rec.response_seconds)
rec.response_time_str = ", ".join(parts)
else:
rec.response_time_str = ""
rec.response_days = 0
rec.response_hours = 0
rec.response_minutes = 0
rec.response_seconds = 0
# to_ids = fields.Many2one(comodel_name='cm.entity', string='Send To')
# delegate_employee_id = fields.Many2one('cm.entity', related='to_ids.delegate_employee_id',store=True)
# from_date = fields.Datetime(string='Delegation From Date', related='to_ids.from_date')
# to_date = fields.Datetime(string='Delegation To Date', related='to_ids.to_date')
# to_delegate = fields.Boolean(string='To Delegate?', related='to_ids.to_delegate')
@api.onchange('type_sender')
def _onchange_type_sender(self):
self.ensure_one()
self.ensure_one()
if self.type_sender == 'unit' and self.to_ids and self.to_ids.type != 'unit':
self.to_ids = False
self.partner_id = False
elif self.type_sender == 'employee' and self.to_ids and self.to_ids.type != 'employee':
self.to_ids = False
self.partner_id = False
partner_id = fields.Many2one('res.partner', string='Partner', readonly=True,
related='to_ids.secretary_id.partner_id')
cc_ids = fields.Many2many(comodel_name='cm.entity', relation='internal_entity_cc_rel',
column1='internal_id', column2='entity_id', string='CC To')
to_users = fields.Many2many(comodel_name='res.users', string="To Users",relation='your_int_to_users_rel',column1='your_int_id',column2='user_id3',)
cc_users = fields.Many2many(comodel_name='res.users', string="CC Users",relation='your_intr_to_users_rel',column1='your_inte_id',column2='user_id4',)
to_users = fields.Many2many(comodel_name='res.users', string="To Users", relation='your_int_to_users_rel',
column1='your_int_id', column2='user_id3', )
cc_users = fields.Many2many(comodel_name='res.users', string="CC Users", relation='your_intr_to_users_rel',
column1='your_inte_id', column2='user_id4', )
project_domain = fields.Many2many('project.project', string='Project Domain')
processing_ids = fields.Many2many(comodel_name='internal.transaction', relation='transaction_internal_rel',
column1='transaction_id', column2='internal_id', string='Process Transactions')
def _normalize_arabic_text(self, text):
translation_map = str.maketrans({
# Define a dictionary to replace different forms of characters
@ -67,7 +108,6 @@ class InternalTransaction(models.Model):
})
return text.translate(translation_map)
@api.model
def search(self, args, offset=0, limit=None, order=None, count=False):
# Normalize the search arguments for 'name' field
@ -118,17 +158,17 @@ class InternalTransaction(models.Model):
sent = 'waite'
record.trace_create_ids('internal_transaction_id', record, sent)
partner_ids = []
if record.to_ids.type == 'unit':
partner_ids.append(record.to_ids.secretary_id.user_id.partner_id.id)
record.forward_user_id = record.to_ids.secretary_id.user_id.id
elif record.to_ids.type == 'employee':
partner_ids.append(record.to_ids.user_id.partner_id.id)
record.forward_user_id = record.to_ids.user_id.id
if record.to_user_have_leave:
record.forward_user_id = record.receive_id.user_id.id
record.send_message(template=template)
subj = _('Message Has been sent!')
msg = _(u'{} ← {}').format(record.employee_id.name, record.to_ids.name)
@ -140,7 +180,7 @@ class InternalTransaction(models.Model):
if company_id.sms_active:
message = f"There is a transaction that needs to {self.procedure_id.name if self.procedure_id else ''} with the number {self.name}"
request = company_id.send_sms(str(record.employee_id.employee_id.phone), message if message else "")
return res
# def action_draft(self):
@ -185,11 +225,11 @@ class InternalTransaction(models.Model):
template = 'exp_transaction_documents.internal_notify_send_send_email'
self.send_message(template=template)
employee = self.current_employee()
to_id = self.to_ids.id
if self.to_ids.type != 'employee':
to_id = self.to_ids.secretary_id.id
self.trace_ids.create({
'action': 'sent',
'to_id': to_id,
@ -197,7 +237,7 @@ class InternalTransaction(models.Model):
'procedure_id': self.procedure_id.id or False,
'internal_transaction_id': self.id
})
subj = _('Message Has been approved!')
msg = _(u'{} ← {}').format(self.preparation_id.manager_id.name, self.to_ids.name)
msg = u'{}<br /><b>{}</b> {}.<br />{}'.format(msg,
@ -207,7 +247,6 @@ class InternalTransaction(models.Model):
partner_ids = [self.employee_id.user_id.partner_id.id, self.to_ids.user_id.partner_id.id]
self.action_send_notification(subj, msg, partner_ids)
return res
# def action_approve(self):
# res = super(InternalTransaction, self).action_approve()

View File

@ -187,7 +187,7 @@
(0, 0, {'view_mode': 'tree','view_id':ref('exp_transaction_documents.common_transaction_internal_tree')}),
(0, 0, {'view_mode': 'form', 'view_id': ref('exp_transaction_documents.common_transaction_form')})]"/>
<field name="search_view_id" ref="view_internal_transaction_filter"/>
<field name="context">{}</field>
<field name="context">{'show_response_fields': True}</field>
</record>
<menuitem id="incoming_internal_tran_menu" name="Incoming Transaction"
parent="income_internal_tran_menu" sequence="0" action="incoming_internal_tran_action"/>

View File

@ -54,6 +54,9 @@
<field name="create_uid" string="Send From"/>
<field name="to_ids"/>
<field name="due_date"/>
<field name="response_time_str" invisible="not context.get('show_response_fields', False)" optional="hide"/>
<field name="response_days" invisible="not context.get('show_response_fields', False)"/>
<!--avg="avg response_days"-->
<field name="state" optional="show"/>
<field name="is_favorite" string=" " widget="priority"/>
<field name="is_reade" invisible="1"/>
@ -114,6 +117,14 @@
</xpath>
<xpath expr="//field[@name='need_approve']" position="after">
<field name="current_is_forward_user" invisible="1"/>
</xpath>
<xpath expr="//field[@name='transaction_date_hijri']" position="after">
<field name="last_response_date" invisible="1"/>
<field name="response_time_str"/>
<field name="response_days"/>
<field name="response_hours" invisible="1"/>
<field name="response_minutes" invisible="1"/>
<field name="response_seconds" invisible="1"/>
</xpath>
<xpath expr="//field[@name='tran_tag']" position="after">
<field name="to_delegate" readonly="1" force_save="1"/>

View File

@ -47,4 +47,5 @@ class ArchiveTransactionWizard(models.TransientModel):
partner_ids = [transaction.employee_id.user_id.partner_id.id]
transaction.action_send_notification(subj, msg, partner_ids)
if self.internal_transaction_id:
transaction.last_response_date = fields.Datetime.now()
transaction.action_send_close()

View File

@ -47,6 +47,7 @@ class ForwardTransactionWizard(models.TransientModel):
if self.internal_transaction_id:
transaction = self.internal_transaction_id
name = 'internal_transaction_id'
transaction.last_response_date = fields.Datetime.now()
elif self.incoming_transaction_id:
transaction = self.incoming_transaction_id
name = 'incoming_transaction_id'

View File

@ -91,5 +91,6 @@ class TransactionReturnWizard(models.TransientModel):
transaction.action_send_notification(subj, msg, partner_ids)
if self.internal_transaction_id:
transaction.last_response_date = fields.Datetime.now()
transaction.action_send_reply()

View File

@ -17,6 +17,7 @@ class ForwardTransactionWizard(models.TransientModel):
if self.internal_transaction_id:
transaction = self.internal_transaction_id
name = 'internal_transaction_id'
transaction.last_response_date = fields.Datetime.now()
elif self.incoming_transaction_id:
transaction = self.incoming_transaction_id
name = 'incoming_transaction_id'