Skip to content

Commit

Permalink
Merge pull request #2 from nuxly/62-synthèse-des-temps-passés-journal…
Browse files Browse the repository at this point in the history
…ier-pour-manager

[IMP] #62 - Ajout d'une synthèse quotidienne des temps passés
  • Loading branch information
fdesmottes authored Apr 24, 2023
2 parents 5458e35 + c0a6c44 commit ddcde8d
Show file tree
Hide file tree
Showing 7 changed files with 378 additions and 1 deletion.
12 changes: 12 additions & 0 deletions timesheet_reminder_mail/data/reminder_cron.xml
Original file line number Diff line number Diff line change
Expand Up @@ -14,5 +14,17 @@
<field name="nextcall" eval="datetime.utcnow()" />
<!-- <field name="active" eval="False"/> -->
</record>
<record forcecreate="True" id="cron_timesheet_summary_manager" model="ir.cron">
<field name="name">Daily summary of time spent</field>
<field name="model_id" ref="model_timesheet_summary"/>
<field name="state">code</field>
<field name="code">model._cron_timesheet_summary_manager()</field>
<field name="user_id" ref="base.user_root" />
<field name="interval_number">1</field>
<field name="interval_type">days</field>
<field name="numbercall">-1</field>
<field eval="False" name="doall" />
<field name="nextcall" eval="datetime.utcnow()" />
</record>
</data>
</odoo>
147 changes: 147 additions & 0 deletions timesheet_reminder_mail/i18n/fr.po
Original file line number Diff line number Diff line change
@@ -0,0 +1,147 @@
# Translation of Odoo Server.
# This file contains the translation of the following modules:
# * timesheet_reminder_mail
#
msgid ""
msgstr ""
"Project-Id-Version: Odoo Server 14.0+e\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2023-03-20 09:49+0000\n"
"PO-Revision-Date: 2023-03-20 09:49+0000\n"
"Last-Translator: \n"
"Language-Team: \n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: \n"
"Plural-Forms: \n"

#. module: timesheet_reminder_mail
#: model:mail.template,body_html:timesheet_reminder_mail.mail_template_timesheet_summary_manager
msgid ""
"<div>\n"
" <p>Hello ${object.firstname or 'n/a'},</p>\n"
" <p><br/>You will find below several tables summarizing the time spent by your employees.<br/></p>\n"
" % set sum_analytic_lines = object.get_summarized_analytic_lines(object)\n"
" % for summary in sum_analytic_lines\n"
" % if summary[0]:\n"
" % set intervenants = summary[0][0]\n"
" % set projets = summary[0][1]\n"
" % set titre = summary[1]\n"
" <br/>\n"
" <h2>${titre}</h2>\n"
" <div style=\"display:table;border-top:1px solid; border-left:1px solid;\">\n"
" <div style=\"display:table-row;font-weight:bold; background-color:#A7C5D0;\">\n"
" <div style=\"display:table-cell;padding: 2px 4px; border-bottom:1px solid; border-right:1px solid;\">Project | Intervenant</div>\n"
" % for intervenant in intervenants\n"
" <div style=\"display:table-cell;padding: 2px 4px; border-bottom:1px solid; border-right:1px solid; text-align:right;\">${intervenant}</div>\n"
" % endfor\n"
" </div>\n"
" % for nom_projet in projets\n"
" % if nom_projet == 'Total':\n"
" <div style=\"display:table-row; background-color:#A7C5D0;\">\n"
" <div style=\"display:table-cell;padding: 2px 4px; border-bottom:1px solid; border-right:1px solid;font-weight:bold;\">${nom_projet}</div>\n"
" % for intervenant in intervenants\n"
" % if intervenant in projets[nom_projet]:\n"
" <div style=\"display:table-cell;padding: 2px 4px; border-bottom:1px solid; border-right:1px solid; text-align:right;\">${'{:.2f}'.format(projets[nom_projet][intervenant]).replace('.',',')}</div>\n"
" % else\n"
" <div style=\"display:table-cell;padding: 2px 4px; border-bottom:1px solid; border-right:1px solid; text-align:right;\"/>\n"
" % endif\n"
" % endfor\n"
" </div>\n"
" % elif (loop.index % 2) == 0:\n"
" <div style=\"display:table-row; background-color:#DEEBEF;\">\n"
" <div style=\"display:table-cell;padding: 2px 4px; border-bottom:1px solid; border-right:1px solid;font-weight:bold;\">${nom_projet}</div>\n"
" % for intervenant in intervenants\n"
" % if intervenant in projets[nom_projet]:\n"
" <div style=\"display:table-cell;padding: 2px 4px; border-bottom:1px solid; border-right:1px solid; text-align:right;\">${'{:.2f}'.format(projets[nom_projet][intervenant]).replace('.',',')}</div>\n"
" % else\n"
" <div style=\"display:table-cell;padding: 2px 4px; border-bottom:1px solid; border-right:1px solid; text-align:right;\"/>\n"
" % endif\n"
" % endfor\n"
" </div>\n"
" % else\n"
" <div style=\"display:table-row;\">\n"
" <div style=\"display:table-cell;padding: 2px 4px; border-bottom:1px solid; border-right:1px solid;font-weight:bold;\">${nom_projet}</div>\n"
" % for intervenant in intervenants\n"
" % if intervenant in projets[nom_projet]:\n"
" <div style=\"display:table-cell;padding: 2px 4px; border-bottom:1px solid; border-right:1px solid; text-align:right;\">${'{:.2f}'.format(projets[nom_projet][intervenant]).replace('.',',')}</div>\n"
" % else\n"
" <div style=\"display:table-cell;padding: 2px 4px; border-bottom:1px solid; border-right:1px solid; text-align:right;\"/>\n"
" % endif\n"
" % endfor\n"
" </div>\n"
" % endif\n"
" % endfor\n"
" </div><br/>\n"
" % endif\n"
" % endfor\n"
" <br/>Thank you,<br/>\n"
" % if user.signature\n"
" ${user.signature | safe}\n"
" % endif\n"
" </div>\n"
" "
msgstr ""
"<div>\n"
" <p>Bonjour ${object.firstname or 'n/a'},</p>\n"
" <p><br/>Tu trouveras ci-dessous plusieurs tableaux récapitulant le temps passé sur chaque projet par tes employés.<br/></p>\n"
" % set sum_analytic_lines = object.get_summarized_analytic_lines(object)\n"
" % for summary in sum_analytic_lines\n"
" % if summary[0]:\n"
" % set intervenants = summary[0][0]\n"
" % set projets = summary[0][1]\n"
" % set titre = summary[1]\n"
" <br/>\n"
" <h2>${titre}</h2>\n"
" <div style=\"display:table;border-top:1px solid; border-left:1px solid;\">\n"
" <div style=\"display:table-row;font-weight:bold; background-color:#A7C5D0;\">\n"
" <div style=\"display:table-cell;padding: 2px 4px; border-bottom:1px solid; border-right:1px solid;\">Projet | Intervenant</div>\n"
" % for intervenant in intervenants\n"
" <div style=\"display:table-cell;padding: 2px 4px; border-bottom:1px solid; border-right:1px solid; text-align:right;\">${intervenant}</div>\n"
" % endfor\n"
" </div>\n"
" % for nom_projet in projets\n"
" % if nom_projet == 'Total':\n"
" <div style=\"display:table-row; background-color:#A7C5D0;\">\n"
" <div style=\"display:table-cell;padding: 2px 4px; border-bottom:1px solid; border-right:1px solid;font-weight:bold;\">${nom_projet}</div>\n"
" % for intervenant in intervenants\n"
" % if intervenant in projets[nom_projet]:\n"
" <div style=\"display:table-cell;padding: 2px 4px; border-bottom:1px solid; border-right:1px solid; text-align:right;\">${'{:.2f}'.format(projets[nom_projet][intervenant]).replace('.',',')}</div>\n"
" % else\n"
" <div style=\"display:table-cell;padding: 2px 4px; border-bottom:1px solid; border-right:1px solid; text-align:right;\"/>\n"
" % endif\n"
" % endfor\n"
" </div>\n"
" % elif (loop.index % 2) == 0:\n"
" <div style=\"display:table-row; background-color:#DEEBEF;\">\n"
" <div style=\"display:table-cell;padding: 2px 4px; border-bottom:1px solid; border-right:1px solid;font-weight:bold;\">${nom_projet}</div>\n"
" % for intervenant in intervenants\n"
" % if intervenant in projets[nom_projet]:\n"
" <div style=\"display:table-cell;padding: 2px 4px; border-bottom:1px solid; border-right:1px solid; text-align:right;\">${'{:.2f}'.format(projets[nom_projet][intervenant]).replace('.',',')}</div>\n"
" % else\n"
" <div style=\"display:table-cell;padding: 2px 4px; border-bottom:1px solid; border-right:1px solid; text-align:right;\"/>\n"
" % endif\n"
" % endfor\n"
" </div>\n"
" % else\n"
" <div style=\"display:table-row;\">\n"
" <div style=\"display:table-cell;padding: 2px 4px; border-bottom:1px solid; border-right:1px solid;font-weight:bold;\">${nom_projet}</div>\n"
" % for intervenant in intervenants\n"
" % if intervenant in projets[nom_projet]:\n"
" <div style=\"display:table-cell;padding: 2px 4px; border-bottom:1px solid; border-right:1px solid; text-align:right;\">${'{:.2f}'.format(projets[nom_projet][intervenant]).replace('.',',')}</div>\n"
" % else\n"
" <div style=\"display:table-cell;padding: 2px 4px; border-bottom:1px solid; border-right:1px solid; text-align:right;\"/>\n"
" % endif\n"
" % endfor\n"
" </div>\n"
" % endif\n"
" % endfor\n"
" </div><br/>\n"
" % endif\n"
" % endfor\n"
" <br/>Merci,<br/>\n"
" % if user.signature\n"
" ${user.signature | safe}\n"
" % endif\n"
" </div>\n"
" "
4 changes: 3 additions & 1 deletion timesheet_reminder_mail/models/__init__.py
Original file line number Diff line number Diff line change
@@ -1,2 +1,4 @@
from . import reminder
from . import timesheet_reminder
from . import hr_employee
from . import timesheet_summary
from . import res_users
9 changes: 9 additions & 0 deletions timesheet_reminder_mail/models/res_users.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
from odoo import api, fields, models, _

class HrEmployeePrivate(models.Model):
_inherit = "res.users"

# Retoune les différents tableaux de temps d'un manager
def get_summarized_analytic_lines(self, manager):
summary = self.env['timesheet.summary']
return summary.get_summarized_analytic_lines(manager)
File renamed without changes.
130 changes: 130 additions & 0 deletions timesheet_reminder_mail/models/timesheet_summary.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,130 @@
from datetime import datetime, date, timedelta
from dateutil.relativedelta import relativedelta
import logging
from odoo import models

logger = logging.getLogger(__name__)


class Summary(models.TransientModel):
_name = 'timesheet.summary'

def _cron_timesheet_summary_manager(self):
managers = self.get_managers()
action_url = '%s/web#menu_id=%s&action=%s' % (
self.env['ir.config_parameter'].sudo().get_param('web.base.url'),
self.env.ref('hr_timesheet.timesheet_menu_root').id,
self.env.ref('hr_timesheet.act_hr_timesheet_line').id,
)
# send mail template to users having email address
template = self.env.ref('timesheet_reminder_mail.mail_template_timesheet_summary_manager')
template_ctx = {'action_url': action_url}
for manager in managers:
template.with_context(template_ctx).send_mail(manager.id)
logger.info("Summaries of time spent to send to the manager '%s'.", manager.name)


# Retoune les managers responsablent d'approuver les feuilles de temps
def get_managers(self):
hr_employee = self.env['hr.employee']
managers = []

# Récupération des employés aillant un manager
employees = hr_employee.search([('timesheet_manager_id', "!=", False)])

# Parcours ces employés en sortant les managers
for employee in employees:
if employee['timesheet_manager_id'] not in managers:
managers += employee['timesheet_manager_id']
return managers


# Retoune les différents tableaux de temps d'un manager
def get_summarized_analytic_lines(self, manager):
date_today = date.today()

# Récupération des temps du jour
today = date_today.strftime("%Y-%m-%d")
daily_times = self.get_analytic_lines(today, today, manager)
daily_times_summarized = self.summarize_analytic_lines(daily_times), "Temps du jour"

# Récupération des temps de la veille ouvrée
date_yesterday = date_today + relativedelta(days=-3) if date_today.weekday() == 0 else date_today + relativedelta(days=-1)
yesterday = date_yesterday.strftime("%Y-%m-%d")
yesterday_times = self.get_analytic_lines(yesterday, yesterday, manager)
yesterday_times_summarized = self.summarize_analytic_lines(yesterday_times), "Temps de la veille"

# Récupération des temps de la semaine
date_monday = (date_today - timedelta(days=date_today.weekday()+2)).strftime("%Y-%m-%d")
weekly_times = self.get_analytic_lines(date_monday, date_today, manager)
weekly_times_summarized = self.summarize_analytic_lines(weekly_times), "Cumule de la semaine"

# Récupération des temps du mois
date_start_month = date(date_today.year, date_today.month, 1).strftime("%Y-%m-%d")
monthly_times = self.get_analytic_lines(date_start_month, date_today, manager)
monthly_times_summarized = self.summarize_analytic_lines(monthly_times), "Cumule du mois"

res = daily_times_summarized, yesterday_times_summarized, weekly_times_summarized, monthly_times_summarized
return res


# Retourne les temps passés des employées en fonction d'un manager et d'un plage données
def get_analytic_lines(self, date_start, date_end, manager):
employees = self.env['hr.employee'].search([
("timesheet_manager_id", "=", manager.id
)])
employee_ids = [employee['id'] for employee in employees]

aal = self.env['account.analytic.line'].search([
("employee_id", "in", employee_ids),
("date",">=",date_start),
("date","<=",date_end)])

return aal


# Retourne une synthèse des temps passés
def summarize_analytic_lines(self, aal):
if aal:
# tpi : total par intervenant
# tpp : total par projet
tpi = tpp = "Total"
intervenants = []
projets = {}
# temps total des intervenants pour tous projets confondus
tpi_dict = {tpi: {tpp: 0}}

for line in aal:
projet = line.project_id.name
intervenant = line.employee_id.user_partner_id.firstname
temps = line.unit_amount

# Ajout de l'intervenant dans le tableau "intervenants" s'il n'existe pas déjà
if intervenant not in intervenants:
intervenants.append(intervenant)
# Ajout de le projet dans le tableau "projets" s'il n'existe pas déjà
if projet not in projets:
projets[projet] = {}
projets[projet][tpp] = 0
# Si l’intervenant est déjà sur le projet du tableau "projets" alors on additionne le temps passé au temps déjà renseigné
if intervenant in projets[projet]:
projets[projet][intervenant] += temps
tpi_dict[tpi][intervenant] += temps
projets[projet][tpp] += temps
tpi_dict[tpi][tpp] += temps
# Sinon l’intervenant est ajouté sur le projet du tableau "projets" et son temps passé est renseigné
else:
projets[projet][intervenant] = temps
if intervenant not in tpi_dict[tpi]:
tpi_dict[tpi][intervenant] = temps
else:
tpi_dict[tpi][intervenant] += temps
projets[projet][tpp] += temps
tpi_dict[tpi][tpp] += temps

# Ajout d'un intervenant "Total"
intervenants.append(tpp)
# Ajout d'une ligne de temps total des intervenants pour tous projets confondus au tableau des projets
projets.update(tpi_dict)
res = intervenants, projets
return res
Loading

0 comments on commit ddcde8d

Please sign in to comment.