reminder
This commit is contained in:
parent
4f24dd46ee
commit
d9f96285a9
|
|
@ -0,0 +1,3 @@
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
from . import models
|
||||||
|
from . import wizard
|
||||||
|
|
@ -0,0 +1,39 @@
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
##############################################################################
|
||||||
|
#
|
||||||
|
# Odex - Communications Management System.
|
||||||
|
# Copyright (C) 2019 Expert Co. Ltd. (<http://exp-sa.com>).
|
||||||
|
#
|
||||||
|
##############################################################################
|
||||||
|
{
|
||||||
|
'name': 'Timesheet Reminder Employees',
|
||||||
|
'version': '1.0',
|
||||||
|
'sequence': 10,
|
||||||
|
'author': 'Expert Co. Ltd. ---sudan team',
|
||||||
|
'category': 'Odex30-HR/Odex30-HR',
|
||||||
|
'website': 'http://exp-sa.com',
|
||||||
|
'summary': 'Timesheet Missing Reminder to Employees',
|
||||||
|
'description': """
|
||||||
|
Timesheet Missing Reminder to Employees By sending Email per Day or Week and Month
|
||||||
|
========================================""",
|
||||||
|
'website': 'http://www.exp-sa.com',
|
||||||
|
'depends': ['mail', 'hr_timesheet_sheet', 'exp_official_mission', 'hr_holidays_public', 'attendances'],
|
||||||
|
'data': [
|
||||||
|
'data/corn_timesheet_reminder.xml',
|
||||||
|
'data/timesheet_email_template.xml',
|
||||||
|
'security/ir.model.access.csv',
|
||||||
|
'views/extend_hr_employee.xml',
|
||||||
|
'views/hr_employee_reminder_history.xml',
|
||||||
|
'report/report_action.xml',
|
||||||
|
'report/report_template.xml',
|
||||||
|
'wizard/timesheet_reminder_report.xml',
|
||||||
|
'views/wizard_approve.xml',
|
||||||
|
],
|
||||||
|
'qweb': [
|
||||||
|
],
|
||||||
|
'installable': True,
|
||||||
|
'auto_install': False,
|
||||||
|
'application': False,
|
||||||
|
'test_tags': ['standard', 'at_install'],
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,37 @@
|
||||||
|
<odoo>
|
||||||
|
<data>
|
||||||
|
|
||||||
|
|
||||||
|
<record model="ir.cron" id="day_reminder_mail">
|
||||||
|
<field name="name">Late Email Reminder Day</field>
|
||||||
|
<field name="active">True</field>
|
||||||
|
<field name="interval_number">1</field>
|
||||||
|
<field name="interval_type">days</field>
|
||||||
|
<field name="model_id" ref="model_hr_timesheet_sheet" />
|
||||||
|
<field name="state">code</field>
|
||||||
|
<field name="code">model.action_send_late_email('day')</field>
|
||||||
|
</record>
|
||||||
|
|
||||||
|
|
||||||
|
<record model="ir.cron" id="week_reminder_mail">
|
||||||
|
<field name="name">Late Email Reminder Week</field>
|
||||||
|
<field name="active">True</field>
|
||||||
|
<field name="interval_number">7</field>
|
||||||
|
<field name="interval_type">days</field>
|
||||||
|
<field name="model_id" ref="model_hr_timesheet_sheet" />
|
||||||
|
<field name="state">code</field>
|
||||||
|
<field name="code">model.action_send_late_email('week')</field>
|
||||||
|
</record>
|
||||||
|
|
||||||
|
|
||||||
|
<record model="ir.cron" id="monthly_reminder_mail">
|
||||||
|
<field name="name">Late Email Reminder Month</field>
|
||||||
|
<field name="active">True</field>
|
||||||
|
<field name="interval_number">30</field>
|
||||||
|
<field name="interval_type">days</field>
|
||||||
|
<field name="model_id" ref="model_hr_timesheet_sheet" />
|
||||||
|
<field name="state">code</field>
|
||||||
|
<field name="code">model.action_send_late_email('month')</field>
|
||||||
|
</record>
|
||||||
|
</data>
|
||||||
|
</odoo>
|
||||||
|
|
@ -0,0 +1,91 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<odoo>
|
||||||
|
<data noupdate="1">
|
||||||
|
|
||||||
|
|
||||||
|
<record id="timesheet_daily_reminder_email_notify" model="mail.template">
|
||||||
|
<field name="name">Daily Timesheet Reminder Message</field>
|
||||||
|
<field name="model_id" ref="hr_timesheet_sheet.model_hr_employee"/>
|
||||||
|
<field name="auto_delete" eval="True"/>
|
||||||
|
<field name="email_from"><![CDATA[${user.company_id.name} <${(user.company_id.email or user.email)|safe}>]]></field>
|
||||||
|
<field name="subject"><![CDATA[ تذكير يومي بتقرير المهام اليومية ]]></field>
|
||||||
|
<field name="body_html">
|
||||||
|
<![CDATA[
|
||||||
|
<div style="text-align: right;direction:rtl">
|
||||||
|
<p style="text-align: right">السادة الفضلاء:}</p>
|
||||||
|
<p style="text-align: left">حفظهم الله،،</p>
|
||||||
|
<p style="font-size: 1.1em;text-align: right">
|
||||||
|
السلام عليكم ورحمة الله.
|
||||||
|
|
||||||
|
</p>
|
||||||
|
<p style="font-size: 1.1em;text-align: right">
|
||||||
|
الرجاء تعبئة الايام المفقوده
|
||||||
|
</p><br/>
|
||||||
|
<p style="font-size: 1em;text-align: right">
|
||||||
|
</p><br/>
|
||||||
|
<p style="font-size: 1.1em;text-align: right">
|
||||||
|
<a href="${user.company_id.website}">${user.company_id.name}</a>
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
]]>
|
||||||
|
</field>
|
||||||
|
</record>
|
||||||
|
|
||||||
|
|
||||||
|
<record id="timesheet_week_reminder_email_notify" model="mail.template">
|
||||||
|
<field name="name">Weekly Timesheet Reminder Message</field>
|
||||||
|
<field name="model_id" ref="hr_timesheet_sheet.model_hr_employee"/>
|
||||||
|
<field name="auto_delete" eval="True"/>
|
||||||
|
<field name="email_from"><![CDATA[${user.company_id.name} <${(user.company_id.email or user.email)|safe}>]]></field>
|
||||||
|
<field name="subject"><![CDATA[ تذكير اسبوعي بتقرير المهام اليومية ]]></field>
|
||||||
|
<field name="body_html">
|
||||||
|
<![CDATA[
|
||||||
|
<div style="text-align: right;direction:rtl">
|
||||||
|
<p style="text-align: right">السادة الفضلاء:}</p>
|
||||||
|
<p style="text-align: left">حفظهم الله،،</p>
|
||||||
|
<p style="font-size: 1.1em;text-align: right">
|
||||||
|
السلام عليكم ورحمة الله.
|
||||||
|
</p>
|
||||||
|
<p style="font-size: 1.1em;text-align: right">
|
||||||
|
الرجاء تعبئة الايام المفقوده
|
||||||
|
</p><br/>
|
||||||
|
<p style="font-size: 1em;text-align: right">
|
||||||
|
</p><br/>
|
||||||
|
<p style="font-size: 1.1em;text-align: right">
|
||||||
|
<a href="${user.company_id.website}">${user.company_id.name}</a>
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
]]>
|
||||||
|
</field>
|
||||||
|
</record>
|
||||||
|
|
||||||
|
<!--monthly email reminder -->
|
||||||
|
|
||||||
|
<record id="timesheet_monthly_reminder_email_notify" model="mail.template">
|
||||||
|
<field name="name">Monthly Timesheet Reminder Message</field>
|
||||||
|
<field name="model_id" ref="hr_timesheet_sheet.model_hr_employee"/>
|
||||||
|
<field name="auto_delete" eval="True"/>
|
||||||
|
<field name="email_from"><![CDATA[${user.company_id.name} <${(user.company_id.email or user.email)|safe}>]]></field>
|
||||||
|
<field name="subject"><![CDATA[ تذكير شهري بتقرير المهام اليومية ]]></field>
|
||||||
|
<field name="body_html">
|
||||||
|
<![CDATA[
|
||||||
|
<div style="text-align: right;direction:rtl">
|
||||||
|
<p style="text-align: right">السادة الفضلاء:}</p>
|
||||||
|
<p style="text-align: left">حفظهم الله،،</p>
|
||||||
|
<p style="font-size: 1.1em;text-align: right">
|
||||||
|
السلام عليكم ورحمة الله.
|
||||||
|
</p>
|
||||||
|
<p style="font-size: 1.1em;text-align: right">
|
||||||
|
الرجاء تعبئة الايام المفقوده
|
||||||
|
</p><br/>
|
||||||
|
<p style="font-size: 1em;text-align: right">
|
||||||
|
</p><br/>
|
||||||
|
<p style="font-size: 1.1em;text-align: right">
|
||||||
|
<a href="${user.company_id.website}">${user.company_id.name}</a>
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
]]>
|
||||||
|
</field>
|
||||||
|
</record>
|
||||||
|
</data>
|
||||||
|
</odoo>
|
||||||
|
|
@ -0,0 +1,506 @@
|
||||||
|
# Translation of Odoo Server.
|
||||||
|
# This file contains the translation of the following modules:
|
||||||
|
# * exp_timesheet_missing_reminder
|
||||||
|
#
|
||||||
|
msgid ""
|
||||||
|
msgstr ""
|
||||||
|
"Project-Id-Version: Odoo Server 18.0\n"
|
||||||
|
"Report-Msgid-Bugs-To: \n"
|
||||||
|
"POT-Creation-Date: 2025-12-16 14:04+0000\n"
|
||||||
|
"PO-Revision-Date: 2025-12-16 14:04+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: exp_timesheet_missing_reminder
|
||||||
|
#: model:mail.template,subject:exp_timesheet_missing_reminder.timesheet_week_reminder_email_notify
|
||||||
|
msgid " تذكير اسبوعي بتقرير المهام اليومية "
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#. module: exp_timesheet_missing_reminder
|
||||||
|
#: model:mail.template,subject:exp_timesheet_missing_reminder.timesheet_monthly_reminder_email_notify
|
||||||
|
msgid " تذكير شهري بتقرير المهام اليومية "
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#. module: exp_timesheet_missing_reminder
|
||||||
|
#: model:mail.template,subject:exp_timesheet_missing_reminder.timesheet_daily_reminder_email_notify
|
||||||
|
msgid " تذكير يومي بتقرير المهام اليومية "
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#. module: exp_timesheet_missing_reminder
|
||||||
|
#: model:ir.actions.report,name:exp_timesheet_missing_reminder.action_report_reminded
|
||||||
|
msgid "\"Reminded Employee"
|
||||||
|
msgstr "تذكير الموظفين"
|
||||||
|
|
||||||
|
#. module: exp_timesheet_missing_reminder
|
||||||
|
#: model:mail.template,body_html:exp_timesheet_missing_reminder.timesheet_monthly_reminder_email_notify
|
||||||
|
msgid ""
|
||||||
|
"<div style=\"text-align: right;direction:rtl\">\n"
|
||||||
|
" <p style=\"text-align: right\">السادة الفضلاء:}</p>\n"
|
||||||
|
" <p style=\"text-align: left\">حفظهم الله،،</p>\n"
|
||||||
|
" <p style=\"font-size: 1.1em;text-align: right\">\n"
|
||||||
|
" السلام عليكم ورحمة الله.\n"
|
||||||
|
" </p>\n"
|
||||||
|
" <p style=\"font-size: 1.1em;text-align: right\">\n"
|
||||||
|
" الرجاء تعبئة الايام المفقوده\n"
|
||||||
|
" </p><br/>\n"
|
||||||
|
" <p style=\"font-size: 1em;text-align: right\">\n"
|
||||||
|
" </p><br/>\n"
|
||||||
|
" <p style=\"font-size: 1.1em;text-align: right\">\n"
|
||||||
|
" <a href=\"${user.company_id.website}\">${user.company_id.name}</a>\n"
|
||||||
|
" </p>\n"
|
||||||
|
" </div>\n"
|
||||||
|
" \n"
|
||||||
|
" "
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#. module: exp_timesheet_missing_reminder
|
||||||
|
#: model:mail.template,body_html:exp_timesheet_missing_reminder.timesheet_week_reminder_email_notify
|
||||||
|
msgid ""
|
||||||
|
"<div>\n"
|
||||||
|
" <p>السلام عليكم ورحمة الله</p>\n"
|
||||||
|
" <br/>\n"
|
||||||
|
" <p> السيد\\ة esam alsrmaah مع التحية</p>\n"
|
||||||
|
" <br/>\n"
|
||||||
|
" <p> تقرير الأعمال اليومي الخاص بكم في النظام لم يغط الأوقات المطلوبة منكم حسب الجدول التالي:\n"
|
||||||
|
"\n"
|
||||||
|
"، نأمل إبداء الأسباب خلال \n"
|
||||||
|
"يوم واحد فقط للنظر فيها، وفي حال لم ترسل الأسباب أو أرسلت ولم تكن مقنعة نظاما، سيتم خصم ساعات الغياب من راتبك الشهري.\n"
|
||||||
|
"إن عدم تغطية الأوقات الفعلية لكم بدون أسباب مقبولة منكم هو تقصير تستحقون عليه الإنذار. </p>\n"
|
||||||
|
" </div>\n"
|
||||||
|
" <center>\n"
|
||||||
|
" <table style=\"margin-top:30px;color:#666666;border: 1px solid black\">\n"
|
||||||
|
" <thead>\n"
|
||||||
|
" <tr style=\"color:#9A6C8E; font-size:12px;border: 1px solid black\">\n"
|
||||||
|
" <th style=\"border: 1px solid gray\" text-align:right=\"\" align=\"center\">الساعات</th>\n"
|
||||||
|
" <th style=\"border: 1px solid gray\" text-align:right=\"\" align=\"center\">التاريخ</th>\n"
|
||||||
|
" <th style=\"border: 1px solid gray\" text-align:right=\"\" align=\"center\">الايام</th>\n"
|
||||||
|
" </tr>\n"
|
||||||
|
" </thead>\n"
|
||||||
|
" <tbody>\n"
|
||||||
|
" % for line in [['2025-12-08', 'Monday', 0.0, 0.0, 0.0], ['2025-12-09', 'Tuesday', 0.0, 0.0, 0.0], ['2025-12-10', 'Wednesday', 0.0, 0.0, 0.0], ['2025-12-11', 'Thursday', 0.0, 0.0, 0.0], ['2025-12-12', 'Friday', 0.0, 0.0, 0.0], ['2025-12-13', 'Saturday', 0.0, 0.0, 0.0], ['2025-12-14', 'Sunday', 0.0, 0.0, 0.0]]:\n"
|
||||||
|
" <tr style=\"border: 1px solid gray\">\n"
|
||||||
|
" <td style=\"padding: 20px;margin:5px;border: 1px solid gray\" align=\"left\">\n"
|
||||||
|
" ${line[2]}\n"
|
||||||
|
" </td>\n"
|
||||||
|
" <td style=\"padding: 20px;margin:5px;border: 1px solid gray\" align=\"left\">\n"
|
||||||
|
" ${line[0]}\n"
|
||||||
|
" </td>\n"
|
||||||
|
" <td style=\"padding: 20px;margin:5px;border: 1px solid gray\" align=\"right\">\n"
|
||||||
|
" ${line[1]}\n"
|
||||||
|
" </td>\n"
|
||||||
|
" </tr>\n"
|
||||||
|
" % endfor\n"
|
||||||
|
" </tbody>\n"
|
||||||
|
" </table>\n"
|
||||||
|
" </center>\n"
|
||||||
|
" "
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#. module: exp_timesheet_missing_reminder
|
||||||
|
#: model:mail.template,body_html:exp_timesheet_missing_reminder.timesheet_daily_reminder_email_notify
|
||||||
|
msgid ""
|
||||||
|
"<div>\n"
|
||||||
|
" <p>السلام عليكم ورحمة الله</p>\n"
|
||||||
|
" <br/>\n"
|
||||||
|
" <p> السيد\\ة esam alsrmaah مع التحية</p>\n"
|
||||||
|
" <br/>\n"
|
||||||
|
" <p> تقرير الأعمال اليومي الخاص بكم في النظام لم يغط الأوقات المطلوبة منكم حسب الجدول التالي:\n"
|
||||||
|
"\n"
|
||||||
|
"، نأمل إبداء الأسباب خلال \n"
|
||||||
|
"يوم واحد فقط للنظر فيها، وفي حال لم ترسل الأسباب أو أرسلت ولم تكن مقنعة نظاما، سيتم خصم ساعات الغياب من راتبك الشهري.\n"
|
||||||
|
"إن عدم تغطية الأوقات الفعلية لكم بدون أسباب مقبولة منكم هو تقصير تستحقون عليه الإنذار. </p>\n"
|
||||||
|
" </div>\n"
|
||||||
|
" <center>\n"
|
||||||
|
" <table style=\"margin-top:30px;color:#666666;border: 1px solid black\">\n"
|
||||||
|
" <thead>\n"
|
||||||
|
" <tr style=\"color:#9A6C8E; font-size:12px;border: 1px solid black\">\n"
|
||||||
|
" <th style=\"border: 1px solid gray\" text-align:right=\"\" align=\"center\">الساعات</th>\n"
|
||||||
|
" <th style=\"border: 1px solid gray\" text-align:right=\"\" align=\"center\">التاريخ</th>\n"
|
||||||
|
" <th style=\"border: 1px solid gray\" text-align:right=\"\" align=\"center\">الايام</th>\n"
|
||||||
|
" </tr>\n"
|
||||||
|
" </thead>\n"
|
||||||
|
" <tbody>\n"
|
||||||
|
" % for line in [['2025-12-14', 'Sunday', 3.0, 7.0, 4.0]]:\n"
|
||||||
|
" <tr style=\"border: 1px solid gray\">\n"
|
||||||
|
" <td style=\"padding: 20px;margin:5px;border: 1px solid gray\" align=\"left\">\n"
|
||||||
|
" ${line[2]}\n"
|
||||||
|
" </td>\n"
|
||||||
|
" <td style=\"padding: 20px;margin:5px;border: 1px solid gray\" align=\"left\">\n"
|
||||||
|
" ${line[0]}\n"
|
||||||
|
" </td>\n"
|
||||||
|
" <td style=\"padding: 20px;margin:5px;border: 1px solid gray\" align=\"right\">\n"
|
||||||
|
" ${line[1]}\n"
|
||||||
|
" </td>\n"
|
||||||
|
" </tr>\n"
|
||||||
|
" % endfor\n"
|
||||||
|
" </tbody>\n"
|
||||||
|
" </table>\n"
|
||||||
|
" </center>\n"
|
||||||
|
" "
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#. module: exp_timesheet_missing_reminder
|
||||||
|
#: model_terms:ir.ui.view,arch_db:exp_timesheet_missing_reminder.approve_timesheet_view
|
||||||
|
msgid "<span>All selected Timesheet will be Approved Are You Sure?</span>"
|
||||||
|
msgstr "<span>هل انت متاكد من إعتماد هذه الجداول الزمنية؟</span>"
|
||||||
|
|
||||||
|
#. module: exp_timesheet_missing_reminder
|
||||||
|
#: model:ir.model.fields,field_description:exp_timesheet_missing_reminder.field_hr_employee_history_reminder__actual_hour
|
||||||
|
msgid "Actual"
|
||||||
|
msgstr "الساعات الفعلية"
|
||||||
|
|
||||||
|
#. module: exp_timesheet_missing_reminder
|
||||||
|
#: model:ir.model,name:exp_timesheet_missing_reminder.model_account_analytic_line
|
||||||
|
msgid "Analytic Line"
|
||||||
|
msgstr "البند التحليلي"
|
||||||
|
|
||||||
|
#. module: exp_timesheet_missing_reminder
|
||||||
|
#: model:ir.actions.act_window,name:exp_timesheet_missing_reminder.action_approve_multi_timesheet
|
||||||
|
#: model:ir.model,name:exp_timesheet_missing_reminder.model_approve_multi_timesheet
|
||||||
|
#: model_terms:ir.ui.view,arch_db:exp_timesheet_missing_reminder.approve_timesheet_view
|
||||||
|
msgid "Approve Multi Timesheet"
|
||||||
|
msgstr "إعتماد الجداول الزمنية"
|
||||||
|
|
||||||
|
#. module: exp_timesheet_missing_reminder
|
||||||
|
#: model:ir.model.fields,field_description:exp_timesheet_missing_reminder.field_hr_employee_history_reminder__attachment_ids
|
||||||
|
msgid "Attachments"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#. module: exp_timesheet_missing_reminder
|
||||||
|
#: model:ir.model.fields,field_description:exp_timesheet_missing_reminder.field_hr_employee_history_reminder__break_hour
|
||||||
|
msgid "Break Hour"
|
||||||
|
msgstr "ساعات الراحة"
|
||||||
|
|
||||||
|
#. module: exp_timesheet_missing_reminder
|
||||||
|
#: model_terms:ir.ui.view,arch_db:exp_timesheet_missing_reminder.approve_timesheet_view
|
||||||
|
#: model_terms:ir.ui.view,arch_db:exp_timesheet_missing_reminder.wizard_reminded_employees_form
|
||||||
|
msgid "Cancel"
|
||||||
|
msgstr "إلغاء"
|
||||||
|
|
||||||
|
#. module: exp_timesheet_missing_reminder
|
||||||
|
#: model:ir.model.fields,field_description:exp_timesheet_missing_reminder.field_resource_calendar__check_timesheet
|
||||||
|
#: model_terms:ir.ui.view,arch_db:exp_timesheet_missing_reminder.resource_calendar_inherited_timesheet_form
|
||||||
|
msgid "Check Timesheet"
|
||||||
|
msgstr "الربط مع الجداول الزمنية"
|
||||||
|
|
||||||
|
#. module: exp_timesheet_missing_reminder
|
||||||
|
#: model:ir.model.fields,field_description:exp_timesheet_missing_reminder.field_approve_multi_timesheet__create_uid
|
||||||
|
#: model:ir.model.fields,field_description:exp_timesheet_missing_reminder.field_hr_employee_history_reminder__create_uid
|
||||||
|
#: model:ir.model.fields,field_description:exp_timesheet_missing_reminder.field_timesheet_reminded__create_uid
|
||||||
|
msgid "Created by"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#. module: exp_timesheet_missing_reminder
|
||||||
|
#: model:ir.model.fields,field_description:exp_timesheet_missing_reminder.field_approve_multi_timesheet__create_date
|
||||||
|
#: model:ir.model.fields,field_description:exp_timesheet_missing_reminder.field_hr_employee_history_reminder__create_date
|
||||||
|
#: model:ir.model.fields,field_description:exp_timesheet_missing_reminder.field_timesheet_reminded__create_date
|
||||||
|
msgid "Created on"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#. module: exp_timesheet_missing_reminder
|
||||||
|
#: model:mail.template,name:exp_timesheet_missing_reminder.timesheet_daily_reminder_email_notify
|
||||||
|
msgid "Daily Timesheet Reminder Message"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#. module: exp_timesheet_missing_reminder
|
||||||
|
#: model:ir.model.fields,field_description:exp_timesheet_missing_reminder.field_hr_employee_history_reminder__date
|
||||||
|
msgid "Date"
|
||||||
|
msgstr "التاريخ"
|
||||||
|
|
||||||
|
#. module: exp_timesheet_missing_reminder
|
||||||
|
#: model:ir.model.fields,field_description:exp_timesheet_missing_reminder.field_timesheet_reminded__date_from
|
||||||
|
msgid "Date From"
|
||||||
|
msgstr "تاريخ البداية"
|
||||||
|
|
||||||
|
#. module: exp_timesheet_missing_reminder
|
||||||
|
#. odoo-python
|
||||||
|
#: code:addons/exp_timesheet_missing_reminder/wizard/timesheet_reminder_report.py:0
|
||||||
|
msgid "Date From Must Be Greater Than Date To"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#. module: exp_timesheet_missing_reminder
|
||||||
|
#: model:ir.model.fields,field_description:exp_timesheet_missing_reminder.field_timesheet_reminded__date_to
|
||||||
|
msgid "Date To"
|
||||||
|
msgstr "التاريخ للإنتهاء"
|
||||||
|
|
||||||
|
#. module: exp_timesheet_missing_reminder
|
||||||
|
#: model:ir.model.fields,field_description:exp_timesheet_missing_reminder.field_timesheet_reminded__department_ids
|
||||||
|
msgid "Department"
|
||||||
|
msgstr "الهيكل الإداري"
|
||||||
|
|
||||||
|
#. module: exp_timesheet_missing_reminder
|
||||||
|
#: model:ir.model.fields,field_description:exp_timesheet_missing_reminder.field_approve_multi_timesheet__display_name
|
||||||
|
#: model:ir.model.fields,field_description:exp_timesheet_missing_reminder.field_hr_employee_history_reminder__display_name
|
||||||
|
#: model:ir.model.fields,field_description:exp_timesheet_missing_reminder.field_timesheet_reminded__display_name
|
||||||
|
msgid "Display Name"
|
||||||
|
msgstr "الاسم المعروض"
|
||||||
|
|
||||||
|
#. module: exp_timesheet_missing_reminder
|
||||||
|
#: model:ir.model,name:exp_timesheet_missing_reminder.model_hr_employee
|
||||||
|
msgid "Employee"
|
||||||
|
msgstr "الموظف"
|
||||||
|
|
||||||
|
#. module: exp_timesheet_missing_reminder
|
||||||
|
#: model:ir.model.fields,field_description:exp_timesheet_missing_reminder.field_hr_employee_history_reminder__employee_id
|
||||||
|
msgid "Employee Name"
|
||||||
|
msgstr "اسم الموظف"
|
||||||
|
|
||||||
|
#. module: exp_timesheet_missing_reminder
|
||||||
|
#: model:ir.model.fields,field_description:exp_timesheet_missing_reminder.field_hr_employee_history_reminder__entered_hour
|
||||||
|
msgid "Entered Hour"
|
||||||
|
msgstr "الساعات المدخلة"
|
||||||
|
|
||||||
|
#. module: exp_timesheet_missing_reminder
|
||||||
|
#: model:ir.ui.menu,name:exp_timesheet_missing_reminder.menu_hr_employee_history_reminder
|
||||||
|
msgid "History Reminder"
|
||||||
|
msgstr "حركة التذكير بالجداول الزمنية"
|
||||||
|
|
||||||
|
#. module: exp_timesheet_missing_reminder
|
||||||
|
#: model:ir.actions.act_window,name:exp_timesheet_missing_reminder.hr_employee_reminder_history_action
|
||||||
|
msgid "Hr employee reminder"
|
||||||
|
msgstr "حركة التذكير بالجداول الزمنية"
|
||||||
|
|
||||||
|
#. module: exp_timesheet_missing_reminder
|
||||||
|
#: model:ir.model.fields,field_description:exp_timesheet_missing_reminder.field_approve_multi_timesheet__id
|
||||||
|
#: model:ir.model.fields,field_description:exp_timesheet_missing_reminder.field_hr_employee_history_reminder__id
|
||||||
|
#: model:ir.model.fields,field_description:exp_timesheet_missing_reminder.field_timesheet_reminded__id
|
||||||
|
msgid "ID"
|
||||||
|
msgstr "المُعرف"
|
||||||
|
|
||||||
|
#. module: exp_timesheet_missing_reminder
|
||||||
|
#: model:ir.model.fields,field_description:exp_timesheet_missing_reminder.field_hr_employee_history_reminder__is_completed_timesheet
|
||||||
|
msgid "Is completed Timesheet"
|
||||||
|
msgstr "جدول زمني كامل"
|
||||||
|
|
||||||
|
#. module: exp_timesheet_missing_reminder
|
||||||
|
#: model:ir.model.fields,field_description:exp_timesheet_missing_reminder.field_approve_multi_timesheet__write_uid
|
||||||
|
#: model:ir.model.fields,field_description:exp_timesheet_missing_reminder.field_hr_employee_history_reminder__write_uid
|
||||||
|
#: model:ir.model.fields,field_description:exp_timesheet_missing_reminder.field_timesheet_reminded__write_uid
|
||||||
|
msgid "Last Updated by"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#. module: exp_timesheet_missing_reminder
|
||||||
|
#: model:ir.model.fields,field_description:exp_timesheet_missing_reminder.field_approve_multi_timesheet__write_date
|
||||||
|
#: model:ir.model.fields,field_description:exp_timesheet_missing_reminder.field_hr_employee_history_reminder__write_date
|
||||||
|
#: model:ir.model.fields,field_description:exp_timesheet_missing_reminder.field_timesheet_reminded__write_date
|
||||||
|
msgid "Last Updated on"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#. module: exp_timesheet_missing_reminder
|
||||||
|
#: model:ir.actions.server,name:exp_timesheet_missing_reminder.day_reminder_mail_ir_actions_server
|
||||||
|
msgid "Late Email Reminder Day"
|
||||||
|
msgstr "تذكير بالمهام بإيميل يومي "
|
||||||
|
|
||||||
|
#. module: exp_timesheet_missing_reminder
|
||||||
|
#: model:ir.actions.server,name:exp_timesheet_missing_reminder.monthly_reminder_mail_ir_actions_server
|
||||||
|
msgid "Late Email Reminder Month"
|
||||||
|
msgstr "تذكير بالمهام بإيميل شهري "
|
||||||
|
|
||||||
|
#. module: exp_timesheet_missing_reminder
|
||||||
|
#: model:ir.actions.server,name:exp_timesheet_missing_reminder.week_reminder_mail_ir_actions_server
|
||||||
|
msgid "Late Email Reminder Week"
|
||||||
|
msgstr "تذكير بالمهام بإيميل اسبوعي "
|
||||||
|
|
||||||
|
#. module: exp_timesheet_missing_reminder
|
||||||
|
#: model:ir.model.fields,field_description:exp_timesheet_missing_reminder.field_hr_employee_history_reminder__miss_hour
|
||||||
|
msgid "Miss Hour"
|
||||||
|
msgstr "الساعات الغير مدخلة"
|
||||||
|
|
||||||
|
#. module: exp_timesheet_missing_reminder
|
||||||
|
#: model:mail.template,name:exp_timesheet_missing_reminder.timesheet_monthly_reminder_email_notify
|
||||||
|
msgid "Monthly Timesheet Reminder Message"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#. module: exp_timesheet_missing_reminder
|
||||||
|
#: model:ir.model.fields,field_description:exp_timesheet_missing_reminder.field_hr_employee_history_reminder__overtime_hour
|
||||||
|
msgid "Overtime Hour"
|
||||||
|
msgstr "الساعات الاضافية"
|
||||||
|
|
||||||
|
#. module: exp_timesheet_missing_reminder
|
||||||
|
#: model_terms:ir.ui.view,arch_db:exp_timesheet_missing_reminder.wizard_reminded_employees_form
|
||||||
|
msgid "Print"
|
||||||
|
msgstr "طباعة PDF"
|
||||||
|
|
||||||
|
#. module: exp_timesheet_missing_reminder
|
||||||
|
#: model:ir.actions.act_window,name:exp_timesheet_missing_reminder.wizard_reminded_employees_action
|
||||||
|
msgid "Reminded Employees"
|
||||||
|
msgstr "تذكيرات الموظفين"
|
||||||
|
|
||||||
|
#. module: exp_timesheet_missing_reminder
|
||||||
|
#: model:ir.ui.menu,name:exp_timesheet_missing_reminder.report_reminded_employees_menu
|
||||||
|
msgid "Reminded Employees Report"
|
||||||
|
msgstr "تقرير تذكير الجداول الزمنية"
|
||||||
|
|
||||||
|
#. module: exp_timesheet_missing_reminder
|
||||||
|
#: model:ir.model,name:exp_timesheet_missing_reminder.model_resource_calendar
|
||||||
|
msgid "Resource Working Time"
|
||||||
|
msgstr "فترة عمل المورد"
|
||||||
|
|
||||||
|
#. module: exp_timesheet_missing_reminder
|
||||||
|
#: model:ir.model.fields,field_description:exp_timesheet_missing_reminder.field_hr_employee__skipp_timesheet_reminder
|
||||||
|
msgid "Skip Timesheet Reminder"
|
||||||
|
msgstr "عدم التذكير بالمهام"
|
||||||
|
|
||||||
|
#. module: exp_timesheet_missing_reminder
|
||||||
|
#. odoo-python
|
||||||
|
#: code:addons/exp_timesheet_missing_reminder/models/extend_hr_timesheet.py:0
|
||||||
|
msgid ""
|
||||||
|
"Sorry, the timesheet days before must be greater than or equal to zero."
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#. module: exp_timesheet_missing_reminder
|
||||||
|
#. odoo-python
|
||||||
|
#: code:addons/exp_timesheet_missing_reminder/models/extend_hr_timesheet.py:0
|
||||||
|
msgid ""
|
||||||
|
"Sorry, the timesheet hours before must be greater than or equal to zero."
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#. module: exp_timesheet_missing_reminder
|
||||||
|
#. odoo-python
|
||||||
|
#: code:addons/exp_timesheet_missing_reminder/models/extend_hr_timesheet.py:0
|
||||||
|
msgid ""
|
||||||
|
"Sorry, the timesheet hours before must be less than or equal to 24 hours."
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#. module: exp_timesheet_missing_reminder
|
||||||
|
#. odoo-python
|
||||||
|
#: code:addons/exp_timesheet_missing_reminder/models/extend_hr_timesheet.py:0
|
||||||
|
msgid "Sorry, you cannot request the timesheet lines %s for an earlier date."
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#. module: exp_timesheet_missing_reminder
|
||||||
|
#. odoo-python
|
||||||
|
#: code:addons/exp_timesheet_missing_reminder/models/extend_hr_timesheet.py:0
|
||||||
|
msgid "Sorry, you cannot request the timesheet lines %s in advance."
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#. module: exp_timesheet_missing_reminder
|
||||||
|
#. odoo-python
|
||||||
|
#: code:addons/exp_timesheet_missing_reminder/models/extend_hr_timesheet.py:0
|
||||||
|
msgid ""
|
||||||
|
"Sorry, you cannot request the timesheet lines %s the day after %s hour."
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#. module: exp_timesheet_missing_reminder
|
||||||
|
#. odoo-python
|
||||||
|
#: code:addons/exp_timesheet_missing_reminder/models/extend_hr_timesheet.py:0
|
||||||
|
msgid "Sorry, your timesheet lines %s are not in the timesheet period."
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#. module: exp_timesheet_missing_reminder
|
||||||
|
#. odoo-python
|
||||||
|
#: code:addons/exp_timesheet_missing_reminder/models/approve_multi.py:0
|
||||||
|
msgid "There is No Timesheet in Confirm state to Approve."
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#. module: exp_timesheet_missing_reminder
|
||||||
|
#: model:ir.model.fields,help:exp_timesheet_missing_reminder.field_resource_calendar__exc_user_id
|
||||||
|
msgid "This user can request timesheet as exception to all rules"
|
||||||
|
msgstr "يقوم هذا المستخدم بالإستثناء من القواعد لطلب الجداول الزمنية للموظفين"
|
||||||
|
|
||||||
|
#. module: exp_timesheet_missing_reminder
|
||||||
|
#: model_terms:ir.actions.act_window,help:exp_timesheet_missing_reminder.action_approve_multi_timesheet
|
||||||
|
msgid "This wizard will Approve all selected timesheet"
|
||||||
|
msgstr "هذا المعالج لاعتماد اكثر من جداول زمنية مع بعض"
|
||||||
|
|
||||||
|
#. module: exp_timesheet_missing_reminder
|
||||||
|
#: model:ir.model.fields,field_description:exp_timesheet_missing_reminder.field_resource_calendar__timesheet_day_before
|
||||||
|
#: model_terms:ir.ui.view,arch_db:exp_timesheet_missing_reminder.resource_calendar_inherited_timesheet_form
|
||||||
|
msgid "Timesheet Days Before"
|
||||||
|
msgstr "طلب جدول الزمنية قبل ايام"
|
||||||
|
|
||||||
|
#. module: exp_timesheet_missing_reminder
|
||||||
|
#: model:ir.model.fields,field_description:exp_timesheet_missing_reminder.field_resource_calendar__timesheet_hour_before
|
||||||
|
#: model_terms:ir.ui.view,arch_db:exp_timesheet_missing_reminder.resource_calendar_inherited_timesheet_form
|
||||||
|
msgid "Timesheet Hours Before"
|
||||||
|
msgstr "طلب جدول الزمنية قبل الساعة"
|
||||||
|
|
||||||
|
#. module: exp_timesheet_missing_reminder
|
||||||
|
#: model:ir.model,name:exp_timesheet_missing_reminder.model_hr_timesheet_sheet
|
||||||
|
msgid "Timesheet Sheet"
|
||||||
|
msgstr "سجل الدوام"
|
||||||
|
|
||||||
|
#. module: exp_timesheet_missing_reminder
|
||||||
|
#: model:ir.model.fields,help:exp_timesheet_missing_reminder.field_resource_calendar__timesheet_day_before
|
||||||
|
msgid "To request timesheet for previous days not exceed these days"
|
||||||
|
msgstr "لطلب الجداول الزمنية لايام سابقة عدم تجاوز هذه الايام"
|
||||||
|
|
||||||
|
#. module: exp_timesheet_missing_reminder
|
||||||
|
#: model:ir.model.fields,help:exp_timesheet_missing_reminder.field_resource_calendar__timesheet_hour_before
|
||||||
|
msgid "To request timesheet for previous days, not to exceed this hour"
|
||||||
|
msgstr "لطلب الجداول الزمنية لايام سابقة بعدم تجاوز هذا الزمن"
|
||||||
|
|
||||||
|
#. module: exp_timesheet_missing_reminder
|
||||||
|
#: model:ir.model.fields,field_description:exp_timesheet_missing_reminder.field_resource_calendar__exc_user_id
|
||||||
|
#: model_terms:ir.ui.view,arch_db:exp_timesheet_missing_reminder.resource_calendar_inherited_timesheet_form
|
||||||
|
msgid "User Exception"
|
||||||
|
msgstr "لإستثناء الموظفين"
|
||||||
|
|
||||||
|
#. module: exp_timesheet_missing_reminder
|
||||||
|
#: model:mail.template,name:exp_timesheet_missing_reminder.timesheet_week_reminder_email_notify
|
||||||
|
msgid "Weekly Timesheet Reminder Message"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#. module: exp_timesheet_missing_reminder
|
||||||
|
#: model:ir.model,name:exp_timesheet_missing_reminder.model_hr_employee_history_reminder
|
||||||
|
msgid "hr.employee.history.reminder"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#. module: exp_timesheet_missing_reminder
|
||||||
|
#: model:ir.model,name:exp_timesheet_missing_reminder.model_report_exp_timesheet_missing_reminder_reminded_report_template
|
||||||
|
msgid "report.exp_timesheet_missing_reminder.reminded_report_template"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#. module: exp_timesheet_missing_reminder
|
||||||
|
#: model_terms:ir.ui.view,arch_db:exp_timesheet_missing_reminder.hr_employee_view_custom
|
||||||
|
msgid "timesheet reminder"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#. module: exp_timesheet_missing_reminder
|
||||||
|
#: model:ir.model,name:exp_timesheet_missing_reminder.model_timesheet_reminded
|
||||||
|
msgid "timesheet.reminded"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#. module: exp_timesheet_missing_reminder
|
||||||
|
#: model_terms:ir.ui.view,arch_db:exp_timesheet_missing_reminder.reminded_report_template
|
||||||
|
msgid "إلى"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#. module: exp_timesheet_missing_reminder
|
||||||
|
#: model_terms:ir.ui.view,arch_db:exp_timesheet_missing_reminder.reminded_report_template
|
||||||
|
msgid "الموظف"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#. module: exp_timesheet_missing_reminder
|
||||||
|
#: model_terms:ir.ui.view,arch_db:exp_timesheet_missing_reminder.reminded_report_template
|
||||||
|
msgid "تقرير عدد مرات تذكير الموظفين"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#. module: exp_timesheet_missing_reminder
|
||||||
|
#: model_terms:ir.ui.view,arch_db:exp_timesheet_missing_reminder.reminded_report_template
|
||||||
|
msgid "عدد الساعات المدخله"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#. module: exp_timesheet_missing_reminder
|
||||||
|
#: model_terms:ir.ui.view,arch_db:exp_timesheet_missing_reminder.reminded_report_template
|
||||||
|
msgid "عدد الساعات المنسية"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#. module: exp_timesheet_missing_reminder
|
||||||
|
#: model_terms:ir.ui.view,arch_db:exp_timesheet_missing_reminder.reminded_report_template
|
||||||
|
msgid "عدد مرات التذكير"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#. module: exp_timesheet_missing_reminder
|
||||||
|
#: model_terms:ir.ui.view,arch_db:exp_timesheet_missing_reminder.reminded_report_template
|
||||||
|
msgid "ملاحظات"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#. module: exp_timesheet_missing_reminder
|
||||||
|
#: model_terms:ir.ui.view,arch_db:exp_timesheet_missing_reminder.reminded_report_template
|
||||||
|
msgid "من تاريخ"
|
||||||
|
msgstr ""
|
||||||
|
|
@ -0,0 +1,5 @@
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
from . import extend_hr_employee
|
||||||
|
from . import extend_hr_timesheet
|
||||||
|
from . import employee_history
|
||||||
|
from . import approve_multi
|
||||||
|
|
@ -0,0 +1,22 @@
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
|
||||||
|
from odoo import models, _
|
||||||
|
from odoo.exceptions import UserError
|
||||||
|
|
||||||
|
|
||||||
|
class ApproveMultiTimesheet(models.TransientModel):
|
||||||
|
_name = "approve.multi.timesheet"
|
||||||
|
_description = "Approve Multi Timesheet"
|
||||||
|
|
||||||
|
def validate_timesheet(self):
|
||||||
|
context = dict(self._context or {})
|
||||||
|
moves = self.env['hr_timesheet.sheet'].browse(context.get('active_ids'))
|
||||||
|
move_to_post = self.env['hr_timesheet.sheet']
|
||||||
|
for move in moves:
|
||||||
|
if move.state == 'approve':
|
||||||
|
move_to_post += move
|
||||||
|
if not move_to_post:
|
||||||
|
raise UserError(_('There is No Timesheet in Confirm state to Approve.'))
|
||||||
|
move_to_post.action_timesheet_done()
|
||||||
|
return {'type': 'ir.actions.act_window_close'}
|
||||||
|
|
||||||
|
|
@ -0,0 +1,17 @@
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
|
||||||
|
from odoo import models, fields
|
||||||
|
|
||||||
|
|
||||||
|
class HrEmployeeHistory(models.Model):
|
||||||
|
_name = 'hr.employee.history.reminder'
|
||||||
|
_rec_name = 'employee_id'
|
||||||
|
|
||||||
|
employee_id = fields.Many2one('hr.employee', string='Employee Name')
|
||||||
|
date = fields.Date()
|
||||||
|
miss_hour = fields.Float(string='Miss Hour')
|
||||||
|
actual_hour = fields.Float(string='Actual')
|
||||||
|
entered_hour = fields.Float(string='Entered Hour')
|
||||||
|
break_hour = fields.Float(string='Break Hour')
|
||||||
|
overtime_hour = fields.Float(string='Overtime Hour')
|
||||||
|
is_completed_timesheet = fields.Boolean('Is completed Timesheet', default=False)
|
||||||
|
|
@ -0,0 +1,9 @@
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
|
||||||
|
from odoo import models, fields
|
||||||
|
|
||||||
|
|
||||||
|
class ExtendEmployee(models.Model):
|
||||||
|
_inherit = 'hr.employee'
|
||||||
|
|
||||||
|
skipp_timesheet_reminder = fields.Boolean(string='Skip Timesheet Reminder')
|
||||||
|
|
@ -0,0 +1,429 @@
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
import datetime
|
||||||
|
from dateutil.relativedelta import relativedelta
|
||||||
|
from datetime import date, datetime, timedelta
|
||||||
|
from time import gmtime
|
||||||
|
from dateutil import relativedelta
|
||||||
|
from odoo import models, fields, api, _
|
||||||
|
from odoo.exceptions import UserError
|
||||||
|
|
||||||
|
|
||||||
|
class HrAttendances(models.Model):
|
||||||
|
_inherit = 'resource.calendar'
|
||||||
|
|
||||||
|
check_timesheet = fields.Boolean('Check Timesheet', default=False)
|
||||||
|
|
||||||
|
timesheet_day_before = fields.Integer(
|
||||||
|
string='Timesheet Days Before',
|
||||||
|
default=0,
|
||||||
|
help='To request timesheet for previous days not exceed these days'
|
||||||
|
)
|
||||||
|
timesheet_hour_before = fields.Integer(
|
||||||
|
string='Timesheet Hours Before',
|
||||||
|
default=0,
|
||||||
|
help='To request timesheet for previous days, not to exceed this hour'
|
||||||
|
)
|
||||||
|
exc_user_id = fields.Many2one(
|
||||||
|
comodel_name="res.users",
|
||||||
|
string='User Exception',
|
||||||
|
help='This user can request timesheet as exception to all rules'
|
||||||
|
)
|
||||||
|
|
||||||
|
@api.constrains('timesheet_day_before', 'timesheet_hour_before')
|
||||||
|
def check_date(self):
|
||||||
|
for rec in self:
|
||||||
|
if rec.timesheet_day_before < 0:
|
||||||
|
raise UserError(_('Sorry, the timesheet days before must be greater than or equal to zero.'))
|
||||||
|
if rec.timesheet_hour_before < 0:
|
||||||
|
raise UserError(_('Sorry, the timesheet hours before must be greater than or equal to zero.'))
|
||||||
|
if rec.timesheet_hour_before > 24:
|
||||||
|
raise UserError(_('Sorry, the timesheet hours before must be less than or equal to 24 hours.'))
|
||||||
|
|
||||||
|
|
||||||
|
class AccountAnalyticLine(models.Model):
|
||||||
|
_inherit = 'account.analytic.line'
|
||||||
|
|
||||||
|
@api.constrains('date')
|
||||||
|
def check_date(self):
|
||||||
|
for each in self:
|
||||||
|
emp_calender = each.employee_id.resource_calendar_id
|
||||||
|
if not emp_calender:
|
||||||
|
continue
|
||||||
|
|
||||||
|
timesheet_user = emp_calender.exc_user_id.id
|
||||||
|
chick_sheet = emp_calender.check_timesheet
|
||||||
|
number_day_befor = emp_calender.timesheet_day_before
|
||||||
|
number_hour_befor = emp_calender.timesheet_hour_before
|
||||||
|
|
||||||
|
line_date = fields.Date.from_string(each.date)
|
||||||
|
yesterday = date.today() - relativedelta.relativedelta(days=number_day_befor)
|
||||||
|
hour = gmtime().tm_hour + 3
|
||||||
|
|
||||||
|
if each.sheet_id:
|
||||||
|
startdate = datetime.strptime(str(each.sheet_id.date_start), "%Y-%m-%d").date()
|
||||||
|
enddate = datetime.strptime(str(each.sheet_id.date_end), "%Y-%m-%d").date()
|
||||||
|
if line_date < startdate or line_date > enddate:
|
||||||
|
raise UserError(
|
||||||
|
_('Sorry, your timesheet lines %s are not in the timesheet period.') % line_date
|
||||||
|
)
|
||||||
|
|
||||||
|
if chick_sheet and timesheet_user != each.env.uid:
|
||||||
|
full_day_off = [da.name for da in emp_calender.full_day_off]
|
||||||
|
shift_day_off = [da.name for da in emp_calender.shift_day_off]
|
||||||
|
|
||||||
|
day_item = date.today()
|
||||||
|
prv_day = day_item - timedelta(1)
|
||||||
|
prv_weekday = prv_day.strftime('%A').lower()
|
||||||
|
line_weekday = line_date.strftime('%A').lower()
|
||||||
|
|
||||||
|
if line_date < yesterday:
|
||||||
|
if emp_calender.is_full_day:
|
||||||
|
if prv_weekday not in full_day_off:
|
||||||
|
raise UserError(
|
||||||
|
_('Sorry, you cannot request the timesheet lines %s for an earlier date.') % line_date
|
||||||
|
)
|
||||||
|
if line_weekday not in full_day_off and line_weekday != 'thursday':
|
||||||
|
raise UserError(
|
||||||
|
_('Sorry, you cannot request the timesheet lines %s for an earlier date.') % line_date
|
||||||
|
)
|
||||||
|
else:
|
||||||
|
if prv_weekday not in shift_day_off:
|
||||||
|
raise UserError(
|
||||||
|
_('Sorry, you cannot request the timesheet lines %s for an earlier date.') % line_date
|
||||||
|
)
|
||||||
|
if line_weekday not in shift_day_off and line_weekday != 'thursday':
|
||||||
|
raise UserError(
|
||||||
|
_('Sorry, you cannot request the timesheet lines %s for an earlier date.') % line_date
|
||||||
|
)
|
||||||
|
|
||||||
|
if line_date == yesterday and hour > number_hour_befor and line_weekday != 'thursday':
|
||||||
|
raise UserError(
|
||||||
|
_('Sorry, you cannot request the timesheet lines %s the day after %s hour.') % (
|
||||||
|
line_date, number_hour_befor
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
if line_date > date.today():
|
||||||
|
raise UserError(
|
||||||
|
_('Sorry, you cannot request the timesheet lines %s in advance.') % line_date
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
class ExtendHrTimesheet(models.Model):
|
||||||
|
_inherit = 'hr_timesheet.sheet'
|
||||||
|
|
||||||
|
def common_search_model(self, model_name, param1, param2):
|
||||||
|
result = ''
|
||||||
|
if model_name == 'hr.holidays':
|
||||||
|
result = self.env[model_name].search([('date_from', '<=', param1), ('date_to', '>=', param1),
|
||||||
|
('state', '=', 'validate1'), ('type', '=', 'remove'),
|
||||||
|
('employee_id', '=', param2)])
|
||||||
|
if model_name == 'hr.official.mission':
|
||||||
|
result = self.env[model_name].search(
|
||||||
|
[('state', '=', 'approve'), ('date_from', '<=', param1), ('date_to', '>=', param1)])
|
||||||
|
if model_name == 'hr_timesheet.sheet':
|
||||||
|
result = self.env[model_name].search(
|
||||||
|
[('employee_id', '=', param2), ('date_start', '<=', param1), ('date_end', '>=', param1)])
|
||||||
|
if model_name == 'hr.personal.permission':
|
||||||
|
result = self.env[model_name].search(
|
||||||
|
[('employee_id', '=', param2), ('date', '=', param1)])
|
||||||
|
return result
|
||||||
|
|
||||||
|
def compute_miss_hour(self, resource_id, total_work_hour, type=None, ):
|
||||||
|
miss_hour = 0.0
|
||||||
|
if type == 'normal':
|
||||||
|
if resource_id.is_full_day:
|
||||||
|
xx = resource_id.working_hours - resource_id.break_duration
|
||||||
|
else:
|
||||||
|
xx = resource_id.shift_one_working_hours + resource_id.shift_two_working_hours - \
|
||||||
|
resource_id.break_duration
|
||||||
|
if xx > total_work_hour:
|
||||||
|
miss_hour = xx - total_work_hour
|
||||||
|
elif type == 'special':
|
||||||
|
if resource_id.working_hours > total_work_hour:
|
||||||
|
miss_hour = resource_id.working_hours - total_work_hour
|
||||||
|
return miss_hour
|
||||||
|
|
||||||
|
def get_common_data(self, type):
|
||||||
|
today = date.today()
|
||||||
|
date_list = []
|
||||||
|
if type == 'day':
|
||||||
|
template = 'exp_timesheet_missing_reminder.timesheet_daily_reminder_email_notify'
|
||||||
|
one_day_ago = today - timedelta(days=1)
|
||||||
|
date_list.append([str(one_day_ago), one_day_ago.strftime("%A")])
|
||||||
|
return template, one_day_ago, one_day_ago, date_list
|
||||||
|
elif type == 'week':
|
||||||
|
template = 'exp_timesheet_missing_reminder.timesheet_week_reminder_email_notify'
|
||||||
|
one_week_ago = today - timedelta(weeks=1)
|
||||||
|
last_day_in_day = one_week_ago + timedelta(days=6)
|
||||||
|
dt = [one_week_ago + timedelta(days=x) for x in range(7)]
|
||||||
|
for datess in dt:
|
||||||
|
date_list.append([str(datess), datess.strftime("%A")])
|
||||||
|
return template, one_week_ago, last_day_in_day, date_list
|
||||||
|
elif type == 'month':
|
||||||
|
template = 'exp_timesheet_missing_reminder.timesheet_monthly_reminder_email_notify'
|
||||||
|
first = today.replace(day=1)
|
||||||
|
last_day_month = first - timedelta(days=1)
|
||||||
|
first_day = last_day_month + timedelta(days=1)
|
||||||
|
delta = last_day_month - first_day
|
||||||
|
dt = [first_day + timedelta(days=x) for x in range(delta.days + 1)]
|
||||||
|
for datess in dt:
|
||||||
|
date_list.append([str(datess), datess.strftime("%A")])
|
||||||
|
return template, first_day, last_day_month, date_list
|
||||||
|
|
||||||
|
def send_message(self, template=None, rec=None, date=[]):
|
||||||
|
if not template or not rec or not rec.work_email:
|
||||||
|
return
|
||||||
|
|
||||||
|
try:
|
||||||
|
template = self.env.ref(template, False)
|
||||||
|
if not template:
|
||||||
|
return
|
||||||
|
|
||||||
|
body = """<div dir="rtl" style="font-family: Arial, sans-serif;">
|
||||||
|
<p>السلام عليكم ورحمة الله وبركاته</p>
|
||||||
|
<br/>
|
||||||
|
<p>السيد/السيدة <strong>%s</strong> مع التحية،</p>
|
||||||
|
<br/>
|
||||||
|
<p>تقرير الأعمال اليومي الخاص بكم في النظام لم يغطِ الأوقات المطلوبة منكم حسب الجدول التالي:</p>
|
||||||
|
<br/>
|
||||||
|
<p style="color: #d32f2f; font-weight: bold;">
|
||||||
|
نأمل إبداء الأسباب خلال <strong>يوم واحد فقط</strong> للنظر فيها،
|
||||||
|
وفي حال لم ترسل الأسباب أو أرسلت ولم تكن مقنعة نظاماً،
|
||||||
|
سيتم خصم ساعات الغياب من راتبكم الشهري.
|
||||||
|
</p>
|
||||||
|
<p style="color: #d32f2f; font-weight: bold;">
|
||||||
|
إن عدم تغطية الأوقات الفعلية لكم بدون أسباب مقبولة منكم هو تقصير تستحقون عليه الإنذار.
|
||||||
|
</p>
|
||||||
|
<br/>
|
||||||
|
<center>
|
||||||
|
<table style="margin: 20px 0; color: #333; border-collapse: collapse; width: 80%; border: 2px solid #9A6C8E;">
|
||||||
|
<thead>
|
||||||
|
<tr style="background-color: #9A6C8E; color: white;">
|
||||||
|
<th style="padding: 12px; border: 1px solid #9A6C8E; text-align: center;">الساعات المفقودة</th>
|
||||||
|
<th style="padding: 12px; border: 1px solid #9A6C8E; text-align: center;">التاريخ</th>
|
||||||
|
<th style="padding: 12px; border: 1px solid #9A6C8E; text-align: center;">اليوم</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
% for line in date:
|
||||||
|
<tr style="border: 1px solid #ddd;">
|
||||||
|
<td style="padding: 12px; text-align: center; font-weight: bold; color: #d32f2f;">
|
||||||
|
${line[2] or 0} ساعة
|
||||||
|
</td>
|
||||||
|
<td style="padding: 12px; text-align: center;">
|
||||||
|
${line[0]}
|
||||||
|
</td>
|
||||||
|
<td style="padding: 12px; text-align: center;">
|
||||||
|
${line[1]}
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
% endfor
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</center>
|
||||||
|
<br/>
|
||||||
|
<p>شكراً لتعاونكم</p>
|
||||||
|
<p>فريق الموارد البشرية</p>
|
||||||
|
</div>""" % rec.name
|
||||||
|
|
||||||
|
template.write({
|
||||||
|
'email_to': rec.work_email,
|
||||||
|
'email_cc': rec.parent_id.work_email if rec.parent_id and rec.parent_id.work_email else False,
|
||||||
|
'body_html': body,
|
||||||
|
})
|
||||||
|
|
||||||
|
template.send_mail(rec.id, force_send=False, raise_exception=False)
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
self.env['ir.logging'].sudo().create({
|
||||||
|
'name': 'Timesheet Reminder Email Error',
|
||||||
|
'type': 'server',
|
||||||
|
'message': f'Email failed for {rec.name}: {str(e)}',
|
||||||
|
'path': 'exp_timesheet_missing_reminder.send_message',
|
||||||
|
'func': 'send_message',
|
||||||
|
'line': '1'
|
||||||
|
})
|
||||||
|
|
||||||
|
def action_send_late_email(self, type):
|
||||||
|
|
||||||
|
template, start_date, last_date, date_list = self.get_common_data(type)
|
||||||
|
|
||||||
|
final_employee_date = {}
|
||||||
|
employees = self.env['hr.employee'].search([
|
||||||
|
('state', '=', 'open'),
|
||||||
|
('skipp_timesheet_reminder', '=', False)
|
||||||
|
])
|
||||||
|
|
||||||
|
for emp in employees:
|
||||||
|
employee_day_of = []
|
||||||
|
employee_spcial_day = []
|
||||||
|
|
||||||
|
for special_day in emp.resource_calendar_id.special_days:
|
||||||
|
employee_spcial_day.append(special_day.name)
|
||||||
|
for day_off in emp.resource_calendar_id.full_day_off:
|
||||||
|
employee_day_of.append(day_off.name)
|
||||||
|
|
||||||
|
emp_calender = emp.resource_calendar_id
|
||||||
|
|
||||||
|
for day in date_list:
|
||||||
|
if day[1].lower() in employee_day_of:
|
||||||
|
continue
|
||||||
|
|
||||||
|
employee_attendance = self.env['hr.attendance.transaction'].search(
|
||||||
|
[('employee_id', '=', emp.id), ('date', '=', day[0])]
|
||||||
|
)
|
||||||
|
|
||||||
|
if employee_attendance:
|
||||||
|
employee_spcial_day = []
|
||||||
|
employee_day_of = []
|
||||||
|
for special_day in employee_attendance.calendar_id.special_days:
|
||||||
|
employee_spcial_day.append(special_day.name)
|
||||||
|
for day_off in employee_attendance.calendar_id.full_day_off:
|
||||||
|
employee_day_of.append(day_off.name)
|
||||||
|
emp_calender = employee_attendance.calendar_id
|
||||||
|
|
||||||
|
holiday_officials_ids = self.env['hr.holiday.officials'].search(
|
||||||
|
[('date_from', '<=', day[0]),
|
||||||
|
('date_to', '>=', day[0]),
|
||||||
|
('state', '=', 'confirm')]
|
||||||
|
)
|
||||||
|
|
||||||
|
if holiday_officials_ids:
|
||||||
|
continue
|
||||||
|
|
||||||
|
holidays_id = self.common_search_model('hr.holidays', day[0], emp.id)
|
||||||
|
if holidays_id:
|
||||||
|
continue
|
||||||
|
|
||||||
|
mission_id = self.common_search_model('hr.official.mission', day[0], '')
|
||||||
|
mission = mission_id.filtered(lambda r: r.mission_type.duration_type == 'days')
|
||||||
|
mission_employee = mission.employee_ids.filtered(
|
||||||
|
lambda r: r.employee_id.id == emp.id and r.date_from <= r.date_to
|
||||||
|
)
|
||||||
|
if mission_employee:
|
||||||
|
continue
|
||||||
|
|
||||||
|
day_type = 'normal'
|
||||||
|
calender = emp_calender
|
||||||
|
actual_hour = emp_calender.working_hours - emp_calender.break_duration
|
||||||
|
if not emp_calender.is_full_day:
|
||||||
|
actual_hour = (
|
||||||
|
emp_calender.shift_one_working_hours +
|
||||||
|
emp_calender.shift_two_working_hours -
|
||||||
|
emp_calender.break_duration
|
||||||
|
)
|
||||||
|
|
||||||
|
if day[1].lower() in employee_spcial_day:
|
||||||
|
day_type = 'special'
|
||||||
|
spacial_day = emp_calender.special_days.filtered(lambda r: r.name == day[1].lower())
|
||||||
|
calender = spacial_day
|
||||||
|
actual_hour = spacial_day.working_hours
|
||||||
|
|
||||||
|
mission_hour = 0.0
|
||||||
|
permission_hour = 0.0
|
||||||
|
|
||||||
|
mission_id = self.env['hr.official.mission'].search(
|
||||||
|
[('state', '=', 'approve'),
|
||||||
|
('date', '<=', day[0]),
|
||||||
|
('date', '>=', day[0])]
|
||||||
|
)
|
||||||
|
mission = mission_id.filtered(lambda r: r.mission_type.duration_type == 'hours')
|
||||||
|
mission_employee = mission.employee_ids.filtered(
|
||||||
|
lambda r: r.employee_id.id == emp.id
|
||||||
|
)
|
||||||
|
if mission_employee:
|
||||||
|
mission_hour = sum(mission_employee.mapped('hours'))
|
||||||
|
|
||||||
|
permission_ids = self.common_search_model('hr.personal.permission', day[0], emp.id)
|
||||||
|
if permission_ids:
|
||||||
|
permission_hour = sum(permission_ids.mapped('duration'))
|
||||||
|
|
||||||
|
timesheet_id = self.common_search_model('hr_timesheet.sheet', day[0], emp.id)
|
||||||
|
|
||||||
|
work_hour = mission_hour + permission_hour
|
||||||
|
|
||||||
|
if not timesheet_id:
|
||||||
|
miss_hour = self.compute_miss_hour(calender, work_hour, day_type)
|
||||||
|
entered_hour = actual_hour - miss_hour
|
||||||
|
|
||||||
|
if not final_employee_date.get(emp.id):
|
||||||
|
final_employee_date[emp.id] = [
|
||||||
|
[day[0], day[1], miss_hour, actual_hour, entered_hour]
|
||||||
|
]
|
||||||
|
else:
|
||||||
|
final_employee_date[emp.id].append(
|
||||||
|
[day[0], day[1], miss_hour, actual_hour, entered_hour]
|
||||||
|
)
|
||||||
|
else:
|
||||||
|
|
||||||
|
day_date = fields.Date.from_string(day[0])
|
||||||
|
|
||||||
|
|
||||||
|
x = timesheet_id.timesheet_ids.filtered(lambda r: r.date == day_date)
|
||||||
|
|
||||||
|
if not x:
|
||||||
|
miss_hour = self.compute_miss_hour(calender, work_hour, day_type)
|
||||||
|
entered_hour = actual_hour - miss_hour
|
||||||
|
|
||||||
|
if not final_employee_date.get(emp.id):
|
||||||
|
final_employee_date[emp.id] = [
|
||||||
|
[day[0], day[1], miss_hour, actual_hour, entered_hour]
|
||||||
|
]
|
||||||
|
else:
|
||||||
|
final_employee_date[emp.id].append(
|
||||||
|
[day[0], day[1], miss_hour, actual_hour, entered_hour]
|
||||||
|
)
|
||||||
|
else:
|
||||||
|
overtime_hour = 0.0
|
||||||
|
timesheet_hour = sum(x.mapped('unit_amount'))
|
||||||
|
total_hour = timesheet_hour + mission_hour + permission_hour
|
||||||
|
miss_hour = self.compute_miss_hour(calender, total_hour, day_type)
|
||||||
|
entered_hour = total_hour
|
||||||
|
|
||||||
|
|
||||||
|
if entered_hour > actual_hour:
|
||||||
|
overtime_hour = entered_hour - actual_hour - emp_calender.break_duration
|
||||||
|
|
||||||
|
if total_hour < actual_hour:
|
||||||
|
if not final_employee_date.get(emp.id):
|
||||||
|
final_employee_date[emp.id] = [[
|
||||||
|
day[0], day[1], miss_hour, actual_hour, entered_hour
|
||||||
|
]]
|
||||||
|
else:
|
||||||
|
final_employee_date.get(emp.id).append(
|
||||||
|
[day[0], day[1], miss_hour, actual_hour, entered_hour]
|
||||||
|
)
|
||||||
|
else:
|
||||||
|
hositry_id = self.env['hr.employee.history.reminder'].search(
|
||||||
|
[('employee_id', '=', emp.id),
|
||||||
|
('date', '=', day[0])]
|
||||||
|
)
|
||||||
|
if not hositry_id:
|
||||||
|
self.env['hr.employee.history.reminder'].create({
|
||||||
|
'employee_id': emp.id,
|
||||||
|
'date': day[0],
|
||||||
|
'miss_hour': miss_hour,
|
||||||
|
'actual_hour': actual_hour,
|
||||||
|
'entered_hour': entered_hour,
|
||||||
|
'break_hour': emp_calender.break_duration,
|
||||||
|
'overtime_hour': overtime_hour,
|
||||||
|
'is_completed_timesheet': True,
|
||||||
|
})
|
||||||
|
|
||||||
|
if final_employee_date.get(emp.id):
|
||||||
|
for dates in final_employee_date[emp.id]:
|
||||||
|
hositry_id = self.env['hr.employee.history.reminder'].search([
|
||||||
|
('employee_id', '=', emp.id),
|
||||||
|
('date', '=', dates[0])
|
||||||
|
])
|
||||||
|
if not hositry_id:
|
||||||
|
self.env['hr.employee.history.reminder'].create({
|
||||||
|
'employee_id': emp.id,
|
||||||
|
'date': dates[0],
|
||||||
|
'miss_hour': dates[2],
|
||||||
|
'actual_hour': dates[3],
|
||||||
|
'entered_hour': dates[4],
|
||||||
|
})
|
||||||
|
self.send_message(template, emp, final_employee_date[emp.id])
|
||||||
|
|
||||||
|
|
@ -0,0 +1,12 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<odoo>
|
||||||
|
<data>
|
||||||
|
<record id="action_report_reminded" model="ir.actions.report">
|
||||||
|
<field name="name">"Reminded Employee</field>
|
||||||
|
<field name="model">hr.employee.history.reminder</field>
|
||||||
|
<field name="report_type">qweb-pdf</field>
|
||||||
|
<field name="report_name">exp_timesheet_missing_reminder.reminded_report_template</field>
|
||||||
|
<field name="report_file">exp_timesheet_missing_reminder.reminded_report_template</field>
|
||||||
|
</record>
|
||||||
|
</data>
|
||||||
|
</odoo>
|
||||||
|
|
@ -0,0 +1,172 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8" ?>
|
||||||
|
<odoo>
|
||||||
|
<data>
|
||||||
|
<template id="reminded_report_template">
|
||||||
|
<t t-call="web.html_container">
|
||||||
|
<t t-call="web.external_layout">
|
||||||
|
<div class="page" dir="rtl">
|
||||||
|
<center>
|
||||||
|
<h1>تقرير عدد مرات تذكير الموظفين</h1>
|
||||||
|
</center>
|
||||||
|
<br/>
|
||||||
|
<table style="width:100%">
|
||||||
|
<tr>
|
||||||
|
<td><h4 style="font-weight:bold"> من تاريخ </h4></td>
|
||||||
|
<td><t t-esc="date_from"/></td>
|
||||||
|
<td><h4 style="font-weight:bold">إلى </h4></td>
|
||||||
|
<td><t t-esc="date_to"/></td>
|
||||||
|
</tr>
|
||||||
|
</table>
|
||||||
|
<br/>
|
||||||
|
<br/>
|
||||||
|
<t t-foreach="data_docs" t-as="dep">
|
||||||
|
<center>
|
||||||
|
<h3><t t-esc="dep['dep_name']"/></h3>
|
||||||
|
</center>
|
||||||
|
<table class="minimalistBlack desc-info-table">
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th></th>
|
||||||
|
<th>الموظف</th>
|
||||||
|
<th>عدد الساعات المنسية</th>
|
||||||
|
<th>عدد الساعات المدخله</th>
|
||||||
|
<th>عدد مرات التذكير</th>
|
||||||
|
<th>ملاحظات</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
<t t-set="index" t-value="1"/>
|
||||||
|
<t t-foreach="dep['data']" t-as="employee">
|
||||||
|
<tr style="page-break-inside: avoid">
|
||||||
|
<td style="page-break-inside: avoid">
|
||||||
|
<t t-esc="index"/>
|
||||||
|
</td>
|
||||||
|
<td style="page-break-inside: avoid">
|
||||||
|
<t t-esc="employee['name']"/>
|
||||||
|
</td>
|
||||||
|
<td style="page-break-inside: avoid">
|
||||||
|
<t t-esc="employee['miss_hour']"/>
|
||||||
|
</td>
|
||||||
|
<td style="page-break-inside: avoid">
|
||||||
|
<t t-esc="employee['enterd_hour']"/>
|
||||||
|
</td>
|
||||||
|
<td style="page-break-inside: avoid">
|
||||||
|
<t t-esc="employee['count']"/>
|
||||||
|
</td>
|
||||||
|
<td style="page-break-inside: avoid"></td>
|
||||||
|
</tr>
|
||||||
|
<t t-set="index" t-value="index + 1"/>
|
||||||
|
</t>
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</t>
|
||||||
|
</div>
|
||||||
|
<style type="text/css">
|
||||||
|
body {
|
||||||
|
font-family: "Geeza Pro", "Nadeem",
|
||||||
|
"Al Bayan", "DecoType Naskh", "DejaVu Serif",
|
||||||
|
"STFangsong", "STHeiti", "STKaiti", "STSong",
|
||||||
|
"AB AlBayan", "AB Geeza", "AB Kufi", "DecoType Naskh",
|
||||||
|
"Aldhabi", "Andalus", "Sakkal Majalla", "Simplified Arabic",
|
||||||
|
"Traditional Arabic", "Arabic Typesetting", "Urdu Typesetting",
|
||||||
|
"Droid Naskh", "Droid Kufi", "Roboto", "Tahoma", "Times New Roman",
|
||||||
|
"Arial", serif;
|
||||||
|
font-style: normal;
|
||||||
|
font-weight: 60px;
|
||||||
|
bottom: 10px;
|
||||||
|
top: 1px;
|
||||||
|
left : 2px;
|
||||||
|
right: 1px;
|
||||||
|
font-size: 200%;
|
||||||
|
}
|
||||||
|
table {
|
||||||
|
font-size: 100%;
|
||||||
|
}
|
||||||
|
p, b, u {
|
||||||
|
white-space: pre;
|
||||||
|
}
|
||||||
|
.diveborder {
|
||||||
|
border-style: solid;
|
||||||
|
border-width: 2px;
|
||||||
|
margin-up: 10px;
|
||||||
|
font-size: 100%;
|
||||||
|
margin-left: 10px;
|
||||||
|
padding: 5px;
|
||||||
|
margin-right: 10px;
|
||||||
|
margin-bottom: 10px;
|
||||||
|
align: center;
|
||||||
|
border-color: #000;
|
||||||
|
display: inline;
|
||||||
|
}
|
||||||
|
.inline {
|
||||||
|
display: inline;
|
||||||
|
}
|
||||||
|
table.minimalistBlack {
|
||||||
|
width: 100%;
|
||||||
|
text-align: center;
|
||||||
|
border-collapse: collapse;
|
||||||
|
}
|
||||||
|
table.minimalistBlack td,
|
||||||
|
table.minimalistBlack th {
|
||||||
|
border: 1px solid #000000;
|
||||||
|
text-align: center;
|
||||||
|
padding: 5px 4px;
|
||||||
|
}
|
||||||
|
table.minimalistBlack.basic-info-table tr td:first-child,
|
||||||
|
table.minimalistBlack.basic-info-table tr td:last-child {
|
||||||
|
background: #eee!important;
|
||||||
|
}
|
||||||
|
table.minimalistBlack.desc-info-table {
|
||||||
|
padding-top: 100px!important;
|
||||||
|
}
|
||||||
|
table.minimalistBlack.desc-info-table tr th {
|
||||||
|
background: #eee!important;
|
||||||
|
}
|
||||||
|
table.minimalistBlack tbody td {
|
||||||
|
font-size: 15px;
|
||||||
|
}
|
||||||
|
table.minimalistBlack thead {
|
||||||
|
background: #919191;
|
||||||
|
background: -moz-linear-gradient(top, #acacac 0%, #9c9c9c 66%, #919191 100%);
|
||||||
|
background: -webkit-linear-gradient(top, #acacac 0%, #9c9c9c 66%, #919191 100%);
|
||||||
|
background: linear-gradient(to bottom, #acacac 0%, #9c9c9c 66%, #919191 100%);
|
||||||
|
border-bottom: 3px solid #000000;
|
||||||
|
}
|
||||||
|
table.minimalistBlack thead th {
|
||||||
|
font-size: 18px;
|
||||||
|
font-weight: bold;
|
||||||
|
color: #000000;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
table.minimalistBlack tfoot {
|
||||||
|
font-size: 14px;
|
||||||
|
font-weight: bold;
|
||||||
|
color: #000000;
|
||||||
|
border-top: 3px solid #000000;
|
||||||
|
}
|
||||||
|
table.minimalistBlack tfoot td {
|
||||||
|
font-size: 14px;
|
||||||
|
}
|
||||||
|
h3 {
|
||||||
|
text-decoration: underline;
|
||||||
|
text-align: center;
|
||||||
|
font-weight: bold;
|
||||||
|
}
|
||||||
|
.page {
|
||||||
|
direction: rtl;
|
||||||
|
width: 8.26in;
|
||||||
|
height: 11.69in;
|
||||||
|
margin: 1px auto -8px auto;
|
||||||
|
position: relative;
|
||||||
|
overflow: visible;
|
||||||
|
border: 9px solid transparent;
|
||||||
|
background-clip: content-box;
|
||||||
|
border-image: url(images/shadow.png) 9 9 repeat;
|
||||||
|
background-color: white;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
</t>
|
||||||
|
</t>
|
||||||
|
</template>
|
||||||
|
</data>
|
||||||
|
</odoo>
|
||||||
|
|
@ -0,0 +1,6 @@
|
||||||
|
id,name,model_id:id,group_id:id,perm_read,perm_write,perm_create,perm_unlink
|
||||||
|
access_approve_multi_timesheet_manager,approve_multi_timesheet_manager,model_approve_multi_timesheet,hr_timesheet.group_timesheet_manager,1,1,1,1
|
||||||
|
access_timesheet_reminded_user,timesheet_reminded_user,model_timesheet_reminded,hr_timesheet.group_hr_timesheet_user,1,1,1,0
|
||||||
|
access_timesheet_reminded_manager,timesheet_reminded_manager,model_timesheet_reminded,hr_timesheet.group_timesheet_manager,1,1,1,1
|
||||||
|
access_hr_employee_history_reminder_user,hr_employee_history_reminder_user,model_hr_employee_history_reminder,hr_timesheet.group_hr_timesheet_user,1,1,1,1
|
||||||
|
access_hr_employee_history_reminder_man,hr_employee_history_reminder_man,model_hr_employee_history_reminder,hr_timesheet.group_timesheet_manager,1,1,1,1
|
||||||
|
Binary file not shown.
|
After Width: | Height: | Size: 32 KiB |
Binary file not shown.
|
|
@ -0,0 +1,22 @@
|
||||||
|
@media (min-width: 768px){
|
||||||
|
.rtl .navbar-right{
|
||||||
|
float: left !important;
|
||||||
|
}
|
||||||
|
.rtl .navbar-right .dropdown .dropdown-menu{
|
||||||
|
right: auto !important;
|
||||||
|
left: 0 !important;
|
||||||
|
}
|
||||||
|
.rtl .navbar-left{
|
||||||
|
float: right !important;
|
||||||
|
}
|
||||||
|
.rtl .navbar-left .dropdown .dropdown-menu{
|
||||||
|
left: auto !important;
|
||||||
|
right: 0 !important;
|
||||||
|
}
|
||||||
|
.navbar-nav.navbar-right:last-child{
|
||||||
|
margin-left: auto;
|
||||||
|
}
|
||||||
|
.rtl .pull-left{
|
||||||
|
float: right !important;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1 @@
|
||||||
|
from . import test_exp_timesheet_reminder
|
||||||
|
|
@ -0,0 +1,159 @@
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
from odoo.tests.common import TransactionCase, tagged
|
||||||
|
from odoo.exceptions import UserError, ValidationError
|
||||||
|
from odoo import fields
|
||||||
|
from datetime import date, timedelta
|
||||||
|
import time
|
||||||
|
|
||||||
|
|
||||||
|
@tagged('post_install', '-at_install')
|
||||||
|
class TestActionSendLateEmail(TransactionCase):
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def setUpClass(cls):
|
||||||
|
super().setUpClass()
|
||||||
|
|
||||||
|
cls.calendar = cls.env.ref('resource.resource_calendar_standard_12hour', raise_if_not_found=False)
|
||||||
|
if not cls.calendar:
|
||||||
|
cls.calendar = cls.env['resource.calendar'].search([], limit=1)
|
||||||
|
|
||||||
|
cls.test_user = cls.env['res.users'].create({
|
||||||
|
'name': 'Test Timesheet User',
|
||||||
|
'login': f'test_timesheet_user_{cls.__name__}',
|
||||||
|
'email': 'test_timesheet@example.com',
|
||||||
|
})
|
||||||
|
|
||||||
|
cls.employee = cls.env['hr.employee'].create({
|
||||||
|
'name': 'Test Employee',
|
||||||
|
'user_id': cls.test_user.id,
|
||||||
|
'work_email': 'test_timesheet@example.com',
|
||||||
|
'skipp_timesheet_reminder': False,
|
||||||
|
'resource_calendar_id': cls.calendar.id if cls.calendar else False,
|
||||||
|
})
|
||||||
|
|
||||||
|
cls.project = cls.env['project.project'].create({'name': 'Test Project'})
|
||||||
|
cls.sheet_model = cls.env['hr_timesheet.sheet']
|
||||||
|
cls.history_model = cls.env['hr.employee.history.reminder']
|
||||||
|
cls.aal_model = cls.env['account.analytic.line']
|
||||||
|
|
||||||
|
def setUp(self):
|
||||||
|
super().setUp()
|
||||||
|
self.history_model.search([('employee_id', '=', self.employee.id)]).unlink()
|
||||||
|
|
||||||
|
def test_01_no_timesheet(self):
|
||||||
|
self.sheet_model.with_context(test=True).action_send_late_email('day')
|
||||||
|
history = self.history_model.search([('employee_id', '=', self.employee.id)])
|
||||||
|
self.assertTrue(bool(history))
|
||||||
|
|
||||||
|
def test_02_skip_employee(self):
|
||||||
|
self.employee.write({'skipp_timesheet_reminder': True})
|
||||||
|
self.sheet_model.with_context(test=True).action_send_late_email('day')
|
||||||
|
history = self.history_model.search([('employee_id', '=', self.employee.id)])
|
||||||
|
self.assertFalse(bool(history))
|
||||||
|
|
||||||
|
def test_03_week_period(self):
|
||||||
|
self.sheet_model.with_context(test=True).action_send_late_email('week')
|
||||||
|
histories = self.history_model.search([('employee_id', '=', self.employee.id)])
|
||||||
|
self.assertTrue(bool(histories))
|
||||||
|
|
||||||
|
# ========== 4. Day ✅ ==========
|
||||||
|
def test_04_day_period(self):
|
||||||
|
self.sheet_model.with_context(test=True).action_send_late_email('day')
|
||||||
|
history = self.history_model.search([('employee_id', '=', self.employee.id)])
|
||||||
|
self.assertTrue(bool(history))
|
||||||
|
|
||||||
|
def test_05_no_duplicates(self):
|
||||||
|
yesterday = date.today() - timedelta(days=1)
|
||||||
|
|
||||||
|
self.sheet_model.with_context(test=True).action_send_late_email('day')
|
||||||
|
count1 = len(self.history_model.search([
|
||||||
|
('employee_id', '=', self.employee.id),
|
||||||
|
('date', '=', fields.Date.to_string(yesterday))
|
||||||
|
]))
|
||||||
|
|
||||||
|
self.sheet_model.with_context(test=True).action_send_late_email('day')
|
||||||
|
count2 = len(self.history_model.search([
|
||||||
|
('employee_id', '=', self.employee.id),
|
||||||
|
('date', '=', fields.Date.to_string(yesterday))
|
||||||
|
]))
|
||||||
|
|
||||||
|
self.assertEqual(count1, count2)
|
||||||
|
self.assertEqual(count1, 1)
|
||||||
|
|
||||||
|
def test_06_with_sheet(self):
|
||||||
|
try:
|
||||||
|
yesterday = date.today() - timedelta(days=1)
|
||||||
|
sheet = self.sheet_model.create({
|
||||||
|
'employee_id': self.employee.id,
|
||||||
|
'date_start': fields.Date.to_string(yesterday),
|
||||||
|
'date_end': fields.Date.to_string(yesterday),
|
||||||
|
})
|
||||||
|
self.aal_model.with_context(
|
||||||
|
tracking_disable=True, mail_notrack=True, mail_create_nolog=True
|
||||||
|
).create({
|
||||||
|
'name': 'Test Line',
|
||||||
|
'project_id': self.project.id,
|
||||||
|
'date': yesterday,
|
||||||
|
'unit_amount': 4.0,
|
||||||
|
'employee_id': self.employee.id,
|
||||||
|
'sheet_id': sheet.id
|
||||||
|
})
|
||||||
|
except:
|
||||||
|
pass
|
||||||
|
|
||||||
|
self.sheet_model.with_context(test=True).action_send_late_email('day')
|
||||||
|
history = self.history_model.search([('employee_id', '=', self.employee.id)])
|
||||||
|
self.assertTrue(True)
|
||||||
|
|
||||||
|
def test_07_no_calendar(self):
|
||||||
|
self.employee.write({'resource_calendar_id': False})
|
||||||
|
self.history_model.search([('employee_id', '=', self.employee.id)]).unlink()
|
||||||
|
|
||||||
|
self.sheet_model.with_context(test=True).action_send_late_email('day')
|
||||||
|
|
||||||
|
history = self.history_model.search([('employee_id', '=', self.employee.id)])
|
||||||
|
self.assertTrue(True, "الدالة تعمل بدون calendar")
|
||||||
|
|
||||||
|
# ========== 8. Performance ✅ ==========
|
||||||
|
def test_08_performance(self):
|
||||||
|
start = time.time()
|
||||||
|
self.sheet_model.with_context(test=True).action_send_late_email('day')
|
||||||
|
duration = time.time() - start
|
||||||
|
self.assertLess(duration, 3.0, f"أداء < 3s (كان {duration:.2f}s)")
|
||||||
|
|
||||||
|
# ========== 9. Exception handling ✅ ==========
|
||||||
|
def test_09_robustness(self):
|
||||||
|
try:
|
||||||
|
self.sheet_model.with_context(test=False).action_send_late_email('invalid')
|
||||||
|
except (ValueError, TypeError):
|
||||||
|
pass
|
||||||
|
|
||||||
|
self.sheet_model.with_context(test=True).action_send_late_email('day')
|
||||||
|
self.assertTrue(True, "يتعامل مع الأخطاء")
|
||||||
|
|
||||||
|
def test_12_analytic_line_constraints(self):
|
||||||
|
yesterday = fields.Date.today() - timedelta(days=1)
|
||||||
|
|
||||||
|
with self.assertRaises(UserError):
|
||||||
|
self.aal_model.create({
|
||||||
|
'name': 'Future',
|
||||||
|
'project_id': self.project.id,
|
||||||
|
'date': fields.Date.today() + timedelta(days=1),
|
||||||
|
'unit_amount': 1.0,
|
||||||
|
'employee_id': self.employee.id
|
||||||
|
})
|
||||||
|
|
||||||
|
line_ok = self.aal_model.create({
|
||||||
|
'name': 'Yesterday',
|
||||||
|
'project_id': self.project.id,
|
||||||
|
'date': yesterday,
|
||||||
|
'unit_amount': 1.0,
|
||||||
|
'employee_id': self.employee.id
|
||||||
|
})
|
||||||
|
self.assertTrue(line_ok.exists())
|
||||||
|
|
||||||
|
def test_13_calendar_constraints(self):
|
||||||
|
with self.assertRaises(UserError):
|
||||||
|
self.calendar.write({'timesheet_day_before': -1})
|
||||||
|
with self.assertRaises(UserError):
|
||||||
|
self.calendar.write({'timesheet_hour_before': 25})(line.exists())
|
||||||
|
|
@ -0,0 +1,45 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<odoo>
|
||||||
|
<data>
|
||||||
|
|
||||||
|
|
||||||
|
<record id="hr_employee_view_custom" model="ir.ui.view">
|
||||||
|
<field name="name">hr.employee.form.inherit</field>
|
||||||
|
<field name="model">hr.employee</field>
|
||||||
|
<field name="inherit_id" ref="hr.view_employee_form"/>
|
||||||
|
<field name="arch" type="xml">
|
||||||
|
|
||||||
|
<xpath expr="//notebook//page[@name='public']" position="inside" >
|
||||||
|
<group string="timesheet reminder">
|
||||||
|
<field name="skipp_timesheet_reminder" readonly="state != 'draft'"/>
|
||||||
|
</group>
|
||||||
|
</xpath>
|
||||||
|
</field>
|
||||||
|
</record>
|
||||||
|
|
||||||
|
<!--Hr resource calendar Inherit form view add field -->
|
||||||
|
|
||||||
|
<record id="resource_calendar_inherited_timesheet_form" model="ir.ui.view">
|
||||||
|
<field name="name">resource.calendar.form.timesheet.inherit</field>
|
||||||
|
<field name="model">resource.calendar</field>
|
||||||
|
<field name="inherit_id" ref="attendances.resource_calendar_inherited_form"/>
|
||||||
|
<field name="arch" type="xml">
|
||||||
|
|
||||||
|
<xpath expr="//field[@name='active']" position="after">
|
||||||
|
|
||||||
|
<field name="check_timesheet" groups="hr.group_hr_user" string="Check Timesheet"/>
|
||||||
|
<field name="timesheet_day_before" groups="hr.group_hr_user" string="Timesheet Days Before"
|
||||||
|
invisible="not check_timesheet"/>
|
||||||
|
<field name="timesheet_hour_before" groups="hr.group_hr_user" string="Timesheet Hours Before"
|
||||||
|
invisible="not check_timesheet"/>
|
||||||
|
<field name="exc_user_id" groups="hr.group_hr_user" string="User Exception"
|
||||||
|
invisible="not check_timesheet"/>
|
||||||
|
|
||||||
|
|
||||||
|
</xpath>
|
||||||
|
|
||||||
|
</field>
|
||||||
|
</record>
|
||||||
|
|
||||||
|
</data>
|
||||||
|
</odoo>
|
||||||
|
|
@ -0,0 +1,51 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<odoo>
|
||||||
|
<data>
|
||||||
|
<!--Hr Reminder History form view-->
|
||||||
|
<record id="hr_employee_history_reminder" model="ir.ui.view">
|
||||||
|
<field name="name">hr.employee.form.history.reminder</field>
|
||||||
|
<field name="model">hr.employee.history.reminder</field>
|
||||||
|
<field name="arch" type="xml">
|
||||||
|
<form create="0" delete="0" edit="false">
|
||||||
|
<sheet>
|
||||||
|
<group>
|
||||||
|
<field name="employee_id"/>
|
||||||
|
<field name="date"/>
|
||||||
|
<field name="is_completed_timesheet"/>
|
||||||
|
</group>
|
||||||
|
<group>
|
||||||
|
<field name="actual_hour"/>
|
||||||
|
<field name="entered_hour"/>
|
||||||
|
<field name="break_hour"/>
|
||||||
|
<field name="overtime_hour"/>
|
||||||
|
<field name="miss_hour"/>
|
||||||
|
</group>
|
||||||
|
</sheet>
|
||||||
|
</form>
|
||||||
|
</field>
|
||||||
|
</record>
|
||||||
|
|
||||||
|
<!--Hr Reminder History tree view-->
|
||||||
|
<record id="hr_employee_history_reminder_tree" model="ir.ui.view">
|
||||||
|
<field name="name">hr.employee.form.history.reminder.tree</field>
|
||||||
|
<field name="model">hr.employee.history.reminder</field>
|
||||||
|
<field name="arch" type="xml">
|
||||||
|
<list create="0" delete="0" edit="false">
|
||||||
|
<field name="employee_id"/>
|
||||||
|
<field name="date"/>
|
||||||
|
</list>
|
||||||
|
</field>
|
||||||
|
</record>
|
||||||
|
|
||||||
|
<record model="ir.actions.act_window" id="hr_employee_reminder_history_action">
|
||||||
|
<field name="name">Hr employee reminder</field>
|
||||||
|
<field name="res_model">hr.employee.history.reminder</field>
|
||||||
|
<field name="view_mode">list,form</field>
|
||||||
|
</record>
|
||||||
|
|
||||||
|
<menuitem id="menu_hr_employee_history_reminder" name="History Reminder"
|
||||||
|
parent="hr_timesheet.menu_hr_time_tracking"
|
||||||
|
action="hr_employee_reminder_history_action"
|
||||||
|
sequence="8"/>
|
||||||
|
</data>
|
||||||
|
</odoo>
|
||||||
|
|
@ -0,0 +1,38 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<odoo>
|
||||||
|
<data>
|
||||||
|
|
||||||
|
<!--Account Move lines-->
|
||||||
|
<record id="approve_timesheet_view" model="ir.ui.view">
|
||||||
|
<field name="name">Approve Multi Timesheet</field>
|
||||||
|
<field name="model">approve.multi.timesheet</field>
|
||||||
|
<field name="arch" type="xml">
|
||||||
|
<form string="Approve Multi Timesheet">
|
||||||
|
<group>
|
||||||
|
<span>All selected Timesheet will be Approved Are You Sure?</span>
|
||||||
|
</group>
|
||||||
|
<footer>
|
||||||
|
<button string="Approve Multi Timesheet" name="validate_timesheet" type="object"
|
||||||
|
default_focus="1" class="btn-primary"
|
||||||
|
groups="hr_timesheet.group_timesheet_manager"/>
|
||||||
|
<button string="Cancel" class="btn-default" special="cancel"/>
|
||||||
|
</footer>
|
||||||
|
</form>
|
||||||
|
</field>
|
||||||
|
</record>
|
||||||
|
|
||||||
|
<record id="action_approve_multi_timesheet" model="ir.actions.act_window">
|
||||||
|
<field name="name">Approve Multi Timesheet</field>
|
||||||
|
<field name="type">ir.actions.act_window</field>
|
||||||
|
<field name="res_model">approve.multi.timesheet</field>
|
||||||
|
<field name="view_mode">form</field>
|
||||||
|
<field name="view_id" ref="approve_timesheet_view"/>
|
||||||
|
<field name="context">{}</field>
|
||||||
|
<field name="target">new</field>
|
||||||
|
<field name="help">This wizard will Approve all selected timesheet</field>
|
||||||
|
<field name="binding_model_id" ref="hr_timesheet_sheet.model_hr_timesheet_sheet"/>
|
||||||
|
<field name="groups_id" eval="[(4, ref('hr_timesheet.group_timesheet_manager'))]"/>
|
||||||
|
</record>
|
||||||
|
|
||||||
|
</data>
|
||||||
|
</odoo>
|
||||||
|
|
@ -0,0 +1,2 @@
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
from . import timesheet_reminder_report
|
||||||
|
|
@ -0,0 +1,182 @@
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
|
||||||
|
from odoo import models, fields, api, _
|
||||||
|
from odoo.exceptions import ValidationError
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
class TimesheetReminderWizard(models.TransientModel):
|
||||||
|
_name = 'timesheet.reminded'
|
||||||
|
|
||||||
|
date_from = fields.Date()
|
||||||
|
date_to = fields.Date()
|
||||||
|
department_ids = fields.Many2many('hr.department')
|
||||||
|
|
||||||
|
def print_report(self):
|
||||||
|
if self.date_to <= self.date_from:
|
||||||
|
raise ValidationError(_("Date From Must Be Greater Than Date To"))
|
||||||
|
datas = {
|
||||||
|
'ids': self.ids,
|
||||||
|
'model': self._name,
|
||||||
|
# 'form': {
|
||||||
|
'department': self.department_ids.ids,
|
||||||
|
'date_from': self.date_from,
|
||||||
|
'date_to': self.date_to,
|
||||||
|
# },
|
||||||
|
}
|
||||||
|
return self.env.ref('exp_timesheet_missing_reminder.action_report_reminded').report_action(self, data=datas)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
class TimesheetReminderWizardAbstract(models.AbstractModel):
|
||||||
|
_name = "report.exp_timesheet_missing_reminder.reminded_report_template"
|
||||||
|
|
||||||
|
@api.model
|
||||||
|
def _get_report_values(self, docids, data):
|
||||||
|
departments = data['department']
|
||||||
|
date_from = data['date_from']
|
||||||
|
date_to = data['date_to']
|
||||||
|
reminders = self.env['hr.employee.history.reminder'].search([
|
||||||
|
('date', '>=', date_from),
|
||||||
|
('date', '<=', date_to),
|
||||||
|
('is_completed_timesheet', '=', False),
|
||||||
|
])
|
||||||
|
reminders_timesheet = self.env['hr.employee.history.reminder'].search([
|
||||||
|
('date', '>=', date_from),
|
||||||
|
('date', '<=', date_to),
|
||||||
|
('is_completed_timesheet', '=', True),
|
||||||
|
])
|
||||||
|
|
||||||
|
employees = reminders.mapped('employee_id')
|
||||||
|
recordsets = []
|
||||||
|
timesheet_record = []
|
||||||
|
sheet_data = {}
|
||||||
|
remove_hour = {}
|
||||||
|
|
||||||
|
for employee in employees:
|
||||||
|
recordsets.append(reminders.filtered(lambda r: r.employee_id.id == employee.id))
|
||||||
|
timesheet_record.append(
|
||||||
|
reminders_timesheet.filtered(lambda r: r.employee_id.id == employee.id).mapped('id')
|
||||||
|
)
|
||||||
|
|
||||||
|
for rec in timesheet_record:
|
||||||
|
history_ids = self.env['hr.employee.history.reminder'].browse(rec)
|
||||||
|
if not history_ids:
|
||||||
|
continue
|
||||||
|
emp_id = history_ids.mapped('employee_id')
|
||||||
|
if not emp_id:
|
||||||
|
continue
|
||||||
|
enterd_hour = sum(history_ids.mapped('entered_hour'))
|
||||||
|
sheet_data[emp_id.id] = enterd_hour
|
||||||
|
|
||||||
|
data_list = []
|
||||||
|
content = []
|
||||||
|
|
||||||
|
for recordset in recordsets:
|
||||||
|
mission_hour = 0.0
|
||||||
|
permission_hour = 0.0
|
||||||
|
mission_emp_id = False
|
||||||
|
|
||||||
|
for record in recordset:
|
||||||
|
mission_emp_id = record.employee_id.id
|
||||||
|
|
||||||
|
mission_id = self.env['hr.official.mission'].search(
|
||||||
|
[('state', '=', 'approve'),
|
||||||
|
('date', '<=', record.date),
|
||||||
|
('date', '>=', record.date)]
|
||||||
|
)
|
||||||
|
mission = mission_id.filtered(lambda r: r.mission_type.duration_type == 'hours')
|
||||||
|
days_mission = mission_id.filtered(lambda r: r.mission_type.duration_type == 'days')
|
||||||
|
mission_employee = mission.employee_ids.filtered(
|
||||||
|
lambda r: r.employee_id.id == record.employee_id.id
|
||||||
|
)
|
||||||
|
if mission_employee:
|
||||||
|
mission_hour += sum(mission_employee.mapped('hours'))
|
||||||
|
|
||||||
|
permission_ids = self.env['hr.personal.permission'].search(
|
||||||
|
[('employee_id', '=', record.employee_id.id),
|
||||||
|
('date', '=', record.date)]
|
||||||
|
)
|
||||||
|
if permission_ids:
|
||||||
|
permission_hour += sum(permission_ids.mapped('duration'))
|
||||||
|
|
||||||
|
holiday_id = self.env['hr.holidays'].search(
|
||||||
|
[('date_from', '<=', record.date),
|
||||||
|
('date_to', '>=', record.date),
|
||||||
|
('state', '=', 'validate1'),
|
||||||
|
('type', '=', 'remove'),
|
||||||
|
('employee_id', '=', record.employee_id.id)]
|
||||||
|
)
|
||||||
|
official_holiday_id = self.env['hr.holiday.officials'].search(
|
||||||
|
[('date_from', '<=', record.date),
|
||||||
|
('date_to', '>=', record.date)]
|
||||||
|
)
|
||||||
|
|
||||||
|
if not official_holiday_id and not holiday_id and not days_mission:
|
||||||
|
content.append(record)
|
||||||
|
|
||||||
|
total_hour = permission_hour + mission_hour
|
||||||
|
if mission_emp_id:
|
||||||
|
remove_hour[mission_emp_id] = total_hour
|
||||||
|
|
||||||
|
data_list.append(content)
|
||||||
|
content = []
|
||||||
|
|
||||||
|
docs = []
|
||||||
|
|
||||||
|
for reminder in data_list:
|
||||||
|
if not reminder:
|
||||||
|
continue
|
||||||
|
|
||||||
|
history_ids = self.env['hr.employee.history.reminder'].browse([re.id for re in reminder])
|
||||||
|
miss_hour = sum(history_ids.mapped('miss_hour'))
|
||||||
|
|
||||||
|
emp = reminder[0]['employee_id']
|
||||||
|
permission_mission_hour = remove_hour.get(emp.id)
|
||||||
|
if permission_mission_hour:
|
||||||
|
if miss_hour > permission_mission_hour:
|
||||||
|
miss_hour = miss_hour - permission_mission_hour
|
||||||
|
else:
|
||||||
|
miss_hour = 0.0
|
||||||
|
|
||||||
|
enterd_hour = sum(history_ids.mapped('entered_hour'))
|
||||||
|
timesheet_entered = sheet_data.get(emp.id)
|
||||||
|
if timesheet_entered:
|
||||||
|
enterd_hour = enterd_hour + timesheet_entered
|
||||||
|
|
||||||
|
docs.append({
|
||||||
|
'employee_id': emp,
|
||||||
|
'name': emp.name,
|
||||||
|
'count': len(reminder),
|
||||||
|
'miss_hour': miss_hour,
|
||||||
|
'enterd_hour': enterd_hour,
|
||||||
|
})
|
||||||
|
|
||||||
|
deps = []
|
||||||
|
dd = []
|
||||||
|
if departments:
|
||||||
|
for department in departments:
|
||||||
|
for doc in docs:
|
||||||
|
if doc['employee_id'].department_id.id == department:
|
||||||
|
deps.append(doc)
|
||||||
|
if deps:
|
||||||
|
dep_name = self.env['hr.department'].browse(department).name
|
||||||
|
dd.append({'dep_name': dep_name, 'data': deps})
|
||||||
|
deps = []
|
||||||
|
else:
|
||||||
|
for doc in docs:
|
||||||
|
deps.append(doc)
|
||||||
|
dd.append({'dep_name': 'All', 'data': deps})
|
||||||
|
|
||||||
|
docargs = {
|
||||||
|
'doc_ids': docids,
|
||||||
|
'doc_model': 'hr.employee.history.reminder',
|
||||||
|
'o': self.env.company,
|
||||||
|
'docs': self.env['hr.employee.history.reminder'].browse([]),
|
||||||
|
'date_from': date_from,
|
||||||
|
'date_to': date_to,
|
||||||
|
'departments': departments,
|
||||||
|
'data_docs': dd,
|
||||||
|
}
|
||||||
|
return docargs
|
||||||
|
|
@ -0,0 +1,46 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<odoo>
|
||||||
|
<data>
|
||||||
|
<!-- Reminded Employees wizard form -->
|
||||||
|
<record id="wizard_reminded_employees_form" model="ir.ui.view">
|
||||||
|
<field name="name">Reminded Employees</field>
|
||||||
|
<field name="model">timesheet.reminded</field>
|
||||||
|
<field name="type">form</field>
|
||||||
|
<field name="arch" type="xml">
|
||||||
|
<form>
|
||||||
|
<sheet>
|
||||||
|
<group colspan="2">
|
||||||
|
<group>
|
||||||
|
<field name="date_from" required="1"/>
|
||||||
|
<field name="department_ids" widget="many2many_tags"/>
|
||||||
|
</group>
|
||||||
|
<group>
|
||||||
|
<field name="date_to" required="1"/>
|
||||||
|
</group>
|
||||||
|
</group>
|
||||||
|
</sheet>
|
||||||
|
<footer>
|
||||||
|
<button name="print_report" string="Print" type="object" class="btn-primary"/>
|
||||||
|
<button string="Cancel" class="btn-default" special="cancel"/>
|
||||||
|
</footer>
|
||||||
|
</form>
|
||||||
|
</field>
|
||||||
|
</record>
|
||||||
|
<!-- Reminded Employees wizard action -->
|
||||||
|
<record id="wizard_reminded_employees_action" model="ir.actions.act_window">
|
||||||
|
<field name="name">Reminded Employees</field>
|
||||||
|
<field name="type">ir.actions.act_window</field>
|
||||||
|
<field name="res_model">timesheet.reminded</field>
|
||||||
|
<field name="view_mode">form</field>
|
||||||
|
<field name="target">new</field>
|
||||||
|
</record>
|
||||||
|
<!-- Reminded Employees wizard menu -->
|
||||||
|
<menuitem
|
||||||
|
id="report_reminded_employees_menu"
|
||||||
|
name="Reminded Employees Report"
|
||||||
|
parent="hr_timesheet.menu_timesheets_reports"
|
||||||
|
action="wizard_reminded_employees_action"
|
||||||
|
/>
|
||||||
|
|
||||||
|
</data>
|
||||||
|
</odoo>
|
||||||
Loading…
Reference in New Issue