Browse Source
[REF] Refactoring of shift module
[REF] Refactoring of shift module
Move counter specific and cooperator status specific to a module call beesdoo_worker_status Remove dependency of beesdoo_base to beesdoo_shift beesdoo_worker_status depends on beesdoo_base Move all attendance sheet related code to a new module attendance sheet Leave empty interface on beesdoo_shift to be implemented in other module to define specific behavior of the counter and the status of the cooperatorpull/143/head
Thibault Francois
5 years ago
44 changed files with 1315 additions and 763 deletions
-
48beesdoo_base/demo/cooperators.xml
-
1beesdoo_base/views/partner.xml
-
10beesdoo_shift/__manifest__.py
-
27beesdoo_shift/data/cron.xml
-
110beesdoo_shift/data/mail_template.xml
-
12beesdoo_shift/data/system_parameter.xml
-
84beesdoo_shift/demo/cooperators.xml
-
6beesdoo_shift/demo/templates.xml
-
89beesdoo_shift/demo/workers.xml
-
2beesdoo_shift/models/__init__.py
-
396beesdoo_shift/models/cooperative_status.py
-
2beesdoo_shift/models/planning.py
-
121beesdoo_shift/models/task.py
-
19beesdoo_shift/security/group.xml
-
15beesdoo_shift/security/ir.model.access.csv
-
28beesdoo_shift/views/cooperative_status.xml
-
2beesdoo_shift/wizard/__init__.py
-
2beesdoo_shift_atttendance/__init__.py
-
36beesdoo_shift_atttendance/__manifest__.py
-
29beesdoo_shift_atttendance/data/cron.xml
-
117beesdoo_shift_atttendance/data/mail_template.xml
-
14beesdoo_shift_atttendance/data/system_parameter.xml
-
2beesdoo_shift_atttendance/models/__init__.py
-
4beesdoo_shift_atttendance/models/attendance_sheet.py
-
61beesdoo_shift_atttendance/models/res_config_settings.py
-
11beesdoo_shift_atttendance/security/group.xml
-
12beesdoo_shift_atttendance/security/ir.model.access.csv
-
0beesdoo_shift_atttendance/tests/__init__.py
-
94beesdoo_shift_atttendance/tests/test_beesdoo_shift.py
-
0beesdoo_shift_atttendance/views/attendance_sheet.xml
-
0beesdoo_shift_atttendance/views/res_config_settings_view.xml
-
1beesdoo_shift_atttendance/wizard/__init__.py
-
0beesdoo_shift_atttendance/wizard/validate_attendance_sheet.py
-
0beesdoo_shift_atttendance/wizard/validate_attendance_sheet.xml
-
3beesdoo_website_shift/controllers/main.py
-
54beesdoo_website_shift/views/my_shift_website_templates.xml
-
8beesdoo_website_shift/views/shift_website_templates.xml
-
0beesdoo_worker_status/__init__.py
-
26beesdoo_worker_status/__manifest__.py
-
1beesdoo_worker_status/models/__init__.py
-
266beesdoo_worker_status/models/cooperative_status.py
-
81beesdoo_worker_status/models/task.py
-
1beesdoo_worker_status/tests/__init__.py
-
247beesdoo_worker_status/tests/test_beesdoo_shift.py
@ -0,0 +1,84 @@ |
|||||
|
<?xml version="1.0" encoding="utf-8"?> |
||||
|
<!-- |
||||
|
Copyright 2019 Coop IT Easy |
||||
|
License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). |
||||
|
--> |
||||
|
<odoo> |
||||
|
<record id="res_partner_cooperator_1_demo" model="res.partner"> |
||||
|
<field name="name">Fernand Peso</field> |
||||
|
<field name="customer" eval="True"/> |
||||
|
<field name="is_company" eval="False"/> |
||||
|
<field name="email">fernand_peso@demo.net</field> |
||||
|
<field name="street">Avenue des Bas-de-Callanques, 15</field> |
||||
|
<field name="city">Etterbeek</field> |
||||
|
<field name="zip">1040</field> |
||||
|
<field name="country_id" ref="base.be"/> |
||||
|
<field name="working_mode">regular</field> |
||||
|
<field name="is_worker" eval="True" /> |
||||
|
</record> |
||||
|
|
||||
|
<record id="res_partner_cooperator_2_demo" model="res.partner"> |
||||
|
<field name="name">Dupont Dupont</field> |
||||
|
<field name="customer" eval="True"/> |
||||
|
<field name="is_company" eval="False"/> |
||||
|
<field name="email">d_dupont@demo.net</field> |
||||
|
<field name="street">Rue des sables, 20</field> |
||||
|
<field name="city">Bruxelles</field> |
||||
|
<field name="zip">10000</field> |
||||
|
<field name="country_id" ref="base.be"/> |
||||
|
<field name="working_mode">irregular</field> |
||||
|
<field name="is_worker" eval="True" /> |
||||
|
</record> |
||||
|
|
||||
|
<record id="res_partner_cooperator_3_demo" model="res.partner"> |
||||
|
<field name="name">Ronan Le Gall</field> |
||||
|
<field name="customer" eval="True"/> |
||||
|
<field name="is_company" eval="False"/> |
||||
|
<field name="email">ronan_gall@demo.net</field> |
||||
|
<field name="street">Rue des pecheurs, 23</field> |
||||
|
<field name="city">Landudec</field> |
||||
|
<field name="zip">29710</field> |
||||
|
<field name="country_id" ref="base.fr"/> |
||||
|
<field name="working_mode">regular</field> |
||||
|
<field name="is_worker" eval="True" /> |
||||
|
</record> |
||||
|
|
||||
|
<record id="res_partner_cooperator_4_demo" model="res.partner"> |
||||
|
<field name="name">Elouan Bees</field> |
||||
|
<field name="customer" eval="True"/> |
||||
|
<field name="is_company" eval="False"/> |
||||
|
<field name="email">elouan_bees@demo.net</field> |
||||
|
<field name="street">Rue Wéry, 15</field> |
||||
|
<field name="city">Ixelles</field> |
||||
|
<field name="zip">1050</field> |
||||
|
<field name="country_id" ref="base.be"/> |
||||
|
<field name="working_mode">irregular</field> |
||||
|
<field name="is_worker" eval="True" /> |
||||
|
</record> |
||||
|
|
||||
|
<record id="res_partner_cooperator_5_demo" model="res.partner"> |
||||
|
<field name="name">Anne de Marchalo</field> |
||||
|
<field name="customer" eval="True"/> |
||||
|
<field name="is_company" eval="False"/> |
||||
|
<field name="email">anne_marchalo@demo.net</field> |
||||
|
<field name="street">Rue du Wels, 6</field> |
||||
|
<field name="city">Nantes</field> |
||||
|
<field name="zip">44000</field> |
||||
|
<field name="country_id" ref="base.fr"/> |
||||
|
<field name="working_mode">regular</field> |
||||
|
<field name="is_worker" eval="True" /> |
||||
|
</record> |
||||
|
|
||||
|
<record id="res_partner_cooperator_6_demo" model="res.partner"> |
||||
|
<field name="name">Jean Beaumont</field> |
||||
|
<field name="customer" eval="True"/> |
||||
|
<field name="is_company" eval="False"/> |
||||
|
<field name="email">jean_beaumont@demo.net</field> |
||||
|
<field name="street">Rue de la Jungle, 8</field> |
||||
|
<field name="city">St-Gilles</field> |
||||
|
<field name="zip">1060</field> |
||||
|
<field name="country_id" ref="base.be"/> |
||||
|
<field name="working_mode">regular</field> |
||||
|
<field name="is_worker" eval="True" /> |
||||
|
</record> |
||||
|
</odoo> |
@ -1,6 +1,4 @@ |
|||||
# -*- coding: utf-8 -*- |
# -*- coding: utf-8 -*- |
||||
from . import task |
from . import task |
||||
from . import attendance_sheet |
|
||||
from . import planning |
from . import planning |
||||
from . import res_config_settings |
|
||||
from . import cooperative_status |
from . import cooperative_status |
@ -0,0 +1,2 @@ |
|||||
|
from . import models |
||||
|
from . import wizard |
@ -0,0 +1,36 @@ |
|||||
|
{ |
||||
|
'name': "Beescoop Shift Attendance Sheet", |
||||
|
|
||||
|
'summary': """ |
||||
|
Volonteer Timetable Management |
||||
|
Attendance Sheet""", |
||||
|
|
||||
|
'description': """ |
||||
|
|
||||
|
""", |
||||
|
|
||||
|
'author': "Elouan Le Bars, Coop It Easy", |
||||
|
'website': "https://github.com/beescoop/Obeesdoo", |
||||
|
|
||||
|
'category': 'Cooperative management', |
||||
|
'version': '12.0.1.0.0', |
||||
|
|
||||
|
'depends': [ |
||||
|
'beesdoo_shift', |
||||
|
'beesdoo_worker_status', #TODO move the part that require beesdoo_worker_status in beesdoo_worker status or another module |
||||
|
'mail', |
||||
|
'barcodes', |
||||
|
], |
||||
|
|
||||
|
'data': [ |
||||
|
"data/system_parameter.xml", |
||||
|
"data/cron.xml", |
||||
|
"data/mail_template.xml", |
||||
|
"security/group.xml", |
||||
|
"security/ir.model.access.csv", |
||||
|
"views/res_config_settings_view.xml", |
||||
|
"wizard/validate_attendance_sheet.xml", |
||||
|
"views/attendance_sheet.xml", |
||||
|
], |
||||
|
'demo': [] |
||||
|
} |
@ -0,0 +1,29 @@ |
|||||
|
<odoo> |
||||
|
<data noupdate="1"> |
||||
|
<record id="ir_cron_generate_attendance_sheet" model="ir.cron"> |
||||
|
<field name="name">Generate Attendance Sheets</field> |
||||
|
<field name="model_id" ref="model_beesdoo_shift_sheet" /> |
||||
|
<field name="state">code</field> |
||||
|
<field name="code">model._generate_attendance_sheet()</field> |
||||
|
<field name="user_id" ref="base.user_root" /> |
||||
|
<field name="interval_number">4</field> |
||||
|
<field name="interval_type">minutes</field> |
||||
|
<field name="numbercall">-1</field> |
||||
|
<field name="doall" eval="False" /> |
||||
|
<field name="active" eval="False" /> |
||||
|
</record> |
||||
|
|
||||
|
<record id="ir_cron_check_non_validated_sheet" model="ir.cron"> |
||||
|
<field name="name">Check for non-validated sheets</field> |
||||
|
<field name="model_id" ref="model_beesdoo_shift_sheet" /> |
||||
|
<field name="state">code</field> |
||||
|
<field name="code">model._cron_non_validated_sheets()</field> |
||||
|
<field name="interval_number">1</field> |
||||
|
<field name="interval_type">days</field> |
||||
|
<field name="numbercall">-1</field> |
||||
|
<field name="doall" eval="False" /> |
||||
|
<field name="nextcall" eval="datetime.now().replace(hour=00, minute=00, second=10)" /> |
||||
|
<field name="active" eval="False" /> |
||||
|
</record> |
||||
|
</data> |
||||
|
</odoo> |
@ -0,0 +1,117 @@ |
|||||
|
<?xml version="1.0" encoding="utf-8"?> |
||||
|
<odoo> |
||||
|
<!-- Mail template are declared in a NOUPDATE block |
||||
|
so users can freely customize/delete them --> |
||||
|
<data noupdate="1"> |
||||
|
<record id="email_template_non_attendance" model="mail.template"> |
||||
|
<field name="name">Shift Non-attendance</field> |
||||
|
<field name="subject">Non-attendance to your last shift.</field> |
||||
|
<field name="partner_to">${object.replaced_id.id or object.worker_id.id|safe}</field> |
||||
|
<field name="model_id" ref="model_beesdoo_shift_shift"/> |
||||
|
<field name="auto_delete" eval="True"/> |
||||
|
<field name="lang">${object.worker_id.lang}</field> |
||||
|
<field name="body_html"><![CDATA[ |
||||
|
<div style="font-family: 'Lucica Grande', Ubuntu, Arial, Verdana, sans-serif; font-size: 12px; color: rgb(34, 34, 34); background-color: #FFF; "> |
||||
|
|
||||
|
% if object.replaced_id: |
||||
|
<p>Hello ${object.replaced_id.name}, |
||||
|
|
||||
|
<br><br>You have been recorded as non-attended during your last shift (${format_tz(object.start_time,object.replaced_id.tz or 'Europe/Brussels','%d.%m.%Y - %H:%M')}), |
||||
|
and you were supposed to replace ${object.worker_id.name}. |
||||
|
% endif |
||||
|
|
||||
|
% if not object.replaced_id: |
||||
|
</p><p>Hello ${object.worker_id.name},</p> |
||||
|
|
||||
|
<p>You have been recorded as non-attended during your last shift (${format_tz(object.start_time,object.worker_id.tz or 'Europe/Brussels','%d.%m.%Y - %H:%M')}). |
||||
|
% endif |
||||
|
|
||||
|
% if object.worker_id.working_mode == 'regular': |
||||
|
% if object.state == 'absent_0': |
||||
|
<br><br>Super-cooperator assigned you 0 compensation, so you won't have any additionnal shift to do before your next regular shift. |
||||
|
% endif |
||||
|
% if object.state == 'absent_1': |
||||
|
<br><br>Super-cooperator assigned you 1 compensation, so you have to attend one additionnal shift before your next regular shift. |
||||
|
% endif |
||||
|
% if object.state == 'absent_2': |
||||
|
<br><br>Super-cooperator assigned you 2 compensations, so you have to attend two additionnal shifts before your next regular shift. |
||||
|
% endif |
||||
|
|
||||
|
% if object.replaced_id: |
||||
|
You were supposed to replace ${object.worker_id.name}. |
||||
|
You have to do ${(object.replaced_id.cooperative_status_ids.sr + object.replaced_id.cooperative_status_ids.sc) * -1 } shifts before your next regular shift.<br> |
||||
|
% else: |
||||
|
You have to do ${(object.worker_id.cooperative_status_ids.sr + object.worker_id.cooperative_status_ids.sc) * -1 } shifts before your next regular shift.<br> |
||||
|
% endif |
||||
|
% endif |
||||
|
|
||||
|
% if object.worker_id.working_mode == 'irregular': |
||||
|
Your shift counter is at ${object.worker_id.cooperative_status_ids.sr}. |
||||
|
|
||||
|
% if object.worker_id.cooperative_status_ids.future_alert_date: |
||||
|
It should be superior or equal to 1 before the |
||||
|
${object.worker_id.cooperative_status_ids.future_alert_date}. |
||||
|
% endif |
||||
|
<br> |
||||
|
% endif |
||||
|
|
||||
|
% if object.replaced_id: |
||||
|
Your current status is "${object.replaced_id.cooperative_status_ids.get_status_value()}". |
||||
|
% else: |
||||
|
<br><br>Your current status is "${object.worker_id.cooperative_status_ids.get_status_value()}". |
||||
|
% endif |
||||
|
|
||||
|
<br>If you have any question regarding this non-attendance, just answer this e-mail. |
||||
|
</p> |
||||
|
<br> |
||||
|
<p>Cooperatively yours,<br> |
||||
|
The Members' office volunteers</p> |
||||
|
<p>${object.worker_id.company_id.name}.</p> |
||||
|
|
||||
|
% if object.worker_id.company_id.street: |
||||
|
${object.worker_id.company_id.street} |
||||
|
% endif |
||||
|
% if object.worker_id.company_id.street2: |
||||
|
${object.worker_id.company_id.street2}<br> |
||||
|
% endif |
||||
|
% if object.worker_id.company_id.city or object.worker_id.company_id.zip: |
||||
|
${object.worker_id.company_id.zip} ${object.worker_id.company_id.city}<br> |
||||
|
% endif |
||||
|
% if object.worker_id.company_id.country_id: |
||||
|
${object.worker_id.company_id.state_id and ('%s, ' % object.worker_id.company_id.state_id.name) or ''} ${object.worker_id.company_id.country_id.name or ''}<br> |
||||
|
% endif |
||||
|
% if object.worker_id.company_id.phone: |
||||
|
Phone: ${object.worker_id.company_id.phone} |
||||
|
% endif |
||||
|
|
||||
|
% if object.worker_id.company_id.website: |
||||
|
<div> |
||||
|
Web : <a href="${object.worker_id.company_id.website}">${object.worker_id.company_id.website}</a> |
||||
|
</div> |
||||
|
%endif |
||||
|
% if object.worker_id.company_id.logo_url: |
||||
|
<div> |
||||
|
<img src="${object.worker_id.company_id.logo_url}"> |
||||
|
</div> |
||||
|
%endif |
||||
|
</div> |
||||
|
]]></field> |
||||
|
</record> |
||||
|
<record id="email_template_non_validated_sheet" model="mail.template"> |
||||
|
<field name="name">Non-validated sheet</field> |
||||
|
<field name="subject">[${object.day}] Non-validated sheet ${object.time_slot}</field> |
||||
|
<field name="model_id" ref="model_beesdoo_shift_sheet"/> |
||||
|
<field name="auto_delete" eval="True"/> |
||||
|
<field name="body_html"><![CDATA[ |
||||
|
<div style="font-family: 'Lucica Grande', Ubuntu, Arial, Verdana, sans-serif; font-size: 12px; color: rgb(34, 34, 34); background-color: #FFF; "> |
||||
|
|
||||
|
<p>${object.day} |
||||
|
<br/><br/>The attendance sheet for ${object.time_slot} is not validated. |
||||
|
<br/><br/>Please, do it as soon as possible so as to update workers' status. |
||||
|
</p> |
||||
|
|
||||
|
</div> |
||||
|
]]></field> |
||||
|
</record> |
||||
|
</data> |
||||
|
</odoo> |
@ -0,0 +1,14 @@ |
|||||
|
<odoo noupdate="1"> |
||||
|
<record id="beesdoo_shift.card_support" model="ir.config_parameter"> |
||||
|
<field name="key">beesdoo_shift.card_support</field> |
||||
|
<field name="value">False</field> |
||||
|
</record> |
||||
|
<record id="beesdoo_shift.attendance_sheet_generation_interval" model="ir.config_parameter"> |
||||
|
<field name="key">beesdoo_shift.attendance_sheet_generation_interval</field> |
||||
|
<field name="value">15</field> |
||||
|
</record> |
||||
|
<record id="beesdoo_shift.default_task_type_id" model="ir.config_parameter"> |
||||
|
<field name="key">beesdoo_shift.default_task_type_id</field> |
||||
|
<field name="value">1</field> |
||||
|
</record> |
||||
|
</odoo> |
@ -0,0 +1,2 @@ |
|||||
|
from . import attendance_sheet |
||||
|
from . import res_config_settings |
@ -0,0 +1,61 @@ |
|||||
|
# Copyright 2019-2020 Elouan Le Bars <elouan@coopiteasy.be> |
||||
|
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). |
||||
|
|
||||
|
import ast |
||||
|
|
||||
|
from odoo import fields, models, api |
||||
|
|
||||
|
|
||||
|
class ResConfigSettings(models.TransientModel): |
||||
|
_inherit = "res.config.settings" |
||||
|
|
||||
|
card_support = fields.Boolean( |
||||
|
string="Scan cooperators cards instead of login for sheets validation", |
||||
|
config_parameter="beesdoo_shift.card_support", |
||||
|
) |
||||
|
task_type_default_id = fields.Many2one( |
||||
|
"beesdoo.shift.type", |
||||
|
string="Default Task Type", |
||||
|
help="Default task type for attendance sheet pre-filling", |
||||
|
required=True, |
||||
|
default=False, |
||||
|
) |
||||
|
attendance_sheet_generation_interval = fields.Integer( |
||||
|
string="Time interval for attendance sheet generation", |
||||
|
help="Time interval expressed in minutes", |
||||
|
required=True, |
||||
|
config_parameter="beesdoo_shift.attendance_sheet_generation_interval", |
||||
|
) |
||||
|
|
||||
|
@api.multi |
||||
|
def set_values(self): |
||||
|
super(ResConfigSettings, self).set_values() |
||||
|
parameters = self.env["ir.config_parameter"].sudo() |
||||
|
parameters.set_param( |
||||
|
"beesdoo_shift.card_support", str(self.card_support), |
||||
|
) |
||||
|
parameters.set_param( |
||||
|
"beesdoo_shift.task_type_default_id", |
||||
|
str(self.task_type_default_id.id), |
||||
|
) |
||||
|
parameters.set_param( |
||||
|
"beesdoo_shift.attendance_sheet_generation_interval", |
||||
|
str(self.attendance_sheet_generation_interval), |
||||
|
) |
||||
|
|
||||
|
@api.multi |
||||
|
def get_values(self): |
||||
|
res = super(ResConfigSettings, self).get_values() |
||||
|
res.update( |
||||
|
card_support=ast.literal_eval( |
||||
|
self.env["ir.config_parameter"].get_param( |
||||
|
"beesdoo_shift.card_support" |
||||
|
), |
||||
|
), |
||||
|
task_type_default_id=int( |
||||
|
self.env["ir.config_parameter"].get_param( |
||||
|
"beesdoo_shift.task_type_default_id" |
||||
|
) |
||||
|
), |
||||
|
) |
||||
|
return res |
@ -0,0 +1,11 @@ |
|||||
|
<odoo> |
||||
|
<record id="group_shift_attendance_sheet" model="res.groups"> |
||||
|
<field name="name">Attendance Sheet Generic Access</field> |
||||
|
<field name="category_id" |
||||
|
ref="base.module_category_cooperative_management"/> |
||||
|
</record> |
||||
|
<record id="beesdoo_shift.group_shift_attendance" model="res.groups"> |
||||
|
<field name="implied_ids" |
||||
|
eval="[(4, ref('group_shift_attendance_sheet'))]"/> |
||||
|
</record> |
||||
|
</odoo> |
@ -0,0 +1,12 @@ |
|||||
|
id,name,model_id/id,group_id/id,perm_read,perm_write,perm_create,perm_unlink |
||||
|
create_beesdoo_shift_shift,create_edit_beesdoo_shift_shift,model_beesdoo_shift_shift,group_shift_attendance_sheet,1,1,1,0 |
||||
|
read_beesdoo_shift_sheet_shift,read_beesdoo_shift_sheet_shift,model_beesdoo_shift_sheet_shift,group_shift_attendance_sheet,1,0,0,0 |
||||
|
create_beesdoo_shift_sheet_shift,create_beesdoo_shift_sheet_shift,model_beesdoo_shift_sheet_shift,group_shift_attendance_sheet,1,1,1,0 |
||||
|
create_beesdoo_shift_sheet_expected,create_beesdoo_shift_sheet_expected,model_beesdoo_shift_sheet_expected,group_shift_attendance_sheet,1,1,1,0 |
||||
|
manage_beesdoo_shift_sheet_added,manage_beesdoo_shift_sheet_added,model_beesdoo_shift_sheet_added,group_shift_attendance_sheet,1,1,1,1 |
||||
|
create_beesdoo_shift_sheet,create_beesdoo_shift_sheet,model_beesdoo_shift_sheet,group_shift_attendance_sheet,1,1,1,0 |
||||
|
sheet_access_beesdoo_shift_template,sheet_access_beesdoo_shift_template,model_beesdoo_shift_template,group_shift_attendance_sheet,1,0,0,0 |
||||
|
sheet_access_beesdoo_shift_type,sheet_access_beesdoo_shift_type,model_beesdoo_shift_type,group_shift_attendance_sheet,1,0,0,0 |
||||
|
access_beesdoo_shift_daynumber,access_beesdoo_shift_daynumber,model_beesdoo_shift_daynumber,group_shift_attendance_sheet,1,0,0,0 |
||||
|
manage_beesdoo_shift_sheet_shift,beesdoo_shift_sheet_shift,model_beesdoo_shift_sheet_shift,group_shift_attendance,1,1,1,1 |
||||
|
manage_beesdoo_shift_sheet_expected,manage_beesdoo_shift_sheet_expected,model_beesdoo_shift_sheet_expected,group_shift_attendance,1,1,1,1 |
@ -0,0 +1 @@ |
|||||
|
from . import validate_attendance_sheet |
@ -0,0 +1,26 @@ |
|||||
|
{ |
||||
|
'name': "Beescoop Worker Status manager", |
||||
|
|
||||
|
'summary': """ |
||||
|
Worker status management specific to beescoop""", |
||||
|
|
||||
|
'description': """ |
||||
|
|
||||
|
""", |
||||
|
|
||||
|
'author': "Thibault Francois, Elouan Le Bars, Coop It Easy", |
||||
|
'website': "https://github.com/beescoop/Obeesdoo", |
||||
|
|
||||
|
'category': 'Cooperative management', |
||||
|
'version': '12.0.1.0.0', |
||||
|
|
||||
|
'depends': [ |
||||
|
'beesdoo_base', |
||||
|
'beesdoo_shift', |
||||
|
], |
||||
|
|
||||
|
'data': [ |
||||
|
], |
||||
|
'demo': [ |
||||
|
] |
||||
|
} |
@ -0,0 +1 @@ |
|||||
|
from . import cooperative_status |
@ -0,0 +1,266 @@ |
|||||
|
from odoo import models, fields, api, _ |
||||
|
from odoo.exceptions import ValidationError, UserError |
||||
|
|
||||
|
from datetime import timedelta, datetime |
||||
|
import logging |
||||
|
|
||||
|
class CooperativeStatus(models.Model): |
||||
|
_inherit = 'cooperative.status' |
||||
|
_period = 28 |
||||
|
|
||||
|
###################################################### |
||||
|
# # |
||||
|
# Override of method to define status behavior # |
||||
|
# # |
||||
|
###################################################### |
||||
|
|
||||
|
future_alert_date = fields.Date(compute='_compute_future_alert_date') |
||||
|
next_countdown_date = fields.Date(compute='_compute_next_countdown_date') |
||||
|
|
||||
|
|
||||
|
@api.depends('today', 'irregular_start_date', 'sr', 'holiday_start_time', |
||||
|
'holiday_end_time', 'temporary_exempt_start_date', |
||||
|
'temporary_exempt_end_date') |
||||
|
def _compute_future_alert_date(self): |
||||
|
"""Compute date before which the worker is up to date""" |
||||
|
for rec in self: |
||||
|
# Only for irregular worker |
||||
|
if rec.working_mode != 'irregular' and not rec.irregular_start_date: |
||||
|
rec.future_alert_date = False |
||||
|
# Alert start time already set |
||||
|
elif rec.alert_start_time: |
||||
|
rec.future_alert_date = False |
||||
|
# Holidays are not set properly |
||||
|
elif bool(rec.holiday_start_time) != bool(rec.holiday_end_time): |
||||
|
rec.future_alert_date = False |
||||
|
# Exemption have not a start and end time |
||||
|
elif (bool(rec.temporary_exempt_start_date) |
||||
|
!= bool(rec.temporary_exempt_end_date)): |
||||
|
rec.future_alert_date = False |
||||
|
else: |
||||
|
date = rec.today |
||||
|
counter = rec.sr |
||||
|
# Simulate the countdown |
||||
|
while counter > 0: |
||||
|
date = add_days_delta(date, 1) |
||||
|
date = self._next_countdown_date(rec.irregular_start_date, |
||||
|
date) |
||||
|
# Check holidays |
||||
|
if (rec.holiday_start_time and rec.holiday_end_time |
||||
|
and date >= rec.holiday_start_time |
||||
|
and date <= rec.holiday_end_time): |
||||
|
continue |
||||
|
# Check temporary exemption |
||||
|
elif (rec.temporary_exempt_start_date |
||||
|
and rec.temporary_exempt_end_date |
||||
|
and date >= rec.temporary_exempt_start_date |
||||
|
and date <= rec.temporary_exempt_end_date): |
||||
|
continue |
||||
|
else: |
||||
|
counter -= 1 |
||||
|
rec.future_alert_date = self._next_countdown_date( |
||||
|
rec.irregular_start_date, date |
||||
|
) |
||||
|
|
||||
|
@api.depends('today', 'irregular_start_date', 'holiday_start_time', |
||||
|
'holiday_end_time', 'temporary_exempt_start_date', |
||||
|
'temporary_exempt_end_date') |
||||
|
def _compute_next_countdown_date(self): |
||||
|
""" |
||||
|
Compute the following countdown date. This date is the date when |
||||
|
the worker will see his counter changed du to the cron. This |
||||
|
date is like the birthday date of the worker that occurred each |
||||
|
PERIOD. |
||||
|
""" |
||||
|
for rec in self: |
||||
|
# Only for irregular worker |
||||
|
if rec.working_mode != 'irregular' and not rec.irregular_start_date: |
||||
|
rec.next_countdown_date = False |
||||
|
# Holidays are not set properly |
||||
|
elif bool(rec.holiday_start_time) != bool(rec.holiday_end_time): |
||||
|
rec.next_countdown_date = False |
||||
|
# Exemption have not a start and end time |
||||
|
elif (bool(rec.temporary_exempt_start_date) |
||||
|
!= bool(rec.temporary_exempt_end_date)): |
||||
|
rec.next_countdown_date = False |
||||
|
else: |
||||
|
date = rec.today |
||||
|
next_countdown_date = False |
||||
|
while not next_countdown_date: |
||||
|
date = self._next_countdown_date(rec.irregular_start_date, date) |
||||
|
# Check holidays |
||||
|
if (rec.holiday_start_time and rec.holiday_end_time |
||||
|
and date >= rec.holiday_start_time |
||||
|
and date <= rec.holiday_end_time): |
||||
|
date = add_days_delta(date, 1) |
||||
|
continue |
||||
|
# Check temporary exemption |
||||
|
elif (rec.temporary_exempt_start_date |
||||
|
and rec.temporary_exempt_end_date |
||||
|
and date >= rec.temporary_exempt_start_date |
||||
|
and date <= rec.temporary_exempt_end_date): |
||||
|
date = add_days_delta(date, 1) |
||||
|
continue |
||||
|
else: |
||||
|
next_countdown_date = date |
||||
|
rec.next_countdown_date = next_countdown_date |
||||
|
|
||||
|
|
||||
|
##################################### |
||||
|
# Status Change implementation # |
||||
|
##################################### |
||||
|
def _set_regular_status(self, grace_delay, alert_delay): |
||||
|
self.ensure_one() |
||||
|
counter_unsubscribe = int(self.env['ir.config_parameter'].get_param('regular_counter_to_unsubscribe', -4)) |
||||
|
ok = self.sr >= 0 and self.sc >= 0 |
||||
|
grace_delay = grace_delay + self.time_extension |
||||
|
|
||||
|
if (self.sr + self.sc) <= counter_unsubscribe or self.unsubscribed: |
||||
|
return 'unsubscribed' |
||||
|
#Check if exempted. Exempt end date is not required. |
||||
|
if self.temporary_exempt_start_date and self.today >= self.temporary_exempt_start_date: |
||||
|
if not self.temporary_exempt_end_date or self.today <= self.temporary_exempt_end_date: |
||||
|
return 'exempted' |
||||
|
|
||||
|
#Transition to alert sr < 0 or stay in alert sr < 0 or sc < 0 and thus alert time is defined |
||||
|
if not ok and self.alert_start_time and self.extension_start_time and self.today <= add_days_delta(self.extension_start_time, grace_delay): |
||||
|
return 'extension' |
||||
|
if not ok and self.alert_start_time and self.extension_start_time and self.today > add_days_delta(self.extension_start_time, grace_delay): |
||||
|
return 'suspended' |
||||
|
if not ok and self.alert_start_time and self.today > add_days_delta(self.alert_start_time, alert_delay): |
||||
|
return 'suspended' |
||||
|
if (self.sr < 0) or (not ok and self.alert_start_time): |
||||
|
return 'alert' |
||||
|
|
||||
|
if ( |
||||
|
self.holiday_start_time |
||||
|
and self.holiday_end_time |
||||
|
and self.today >= self.holiday_start_time |
||||
|
and self.today <= self.holiday_end_time |
||||
|
): |
||||
|
|
||||
|
return 'holiday' |
||||
|
elif ok or (not self.alert_start_time and self.sr >= 0): |
||||
|
return 'ok' |
||||
|
|
||||
|
def _set_irregular_status(self, grace_delay, alert_delay): |
||||
|
counter_unsubscribe = int(self.env['ir.config_parameter'].get_param('irregular_counter_to_unsubscribe', -3)) |
||||
|
self.ensure_one() |
||||
|
ok = self.sr >= 0 |
||||
|
grace_delay = grace_delay + self.time_extension |
||||
|
if self.sr <= counter_unsubscribe or self.unsubscribed: |
||||
|
return 'unsubscribed' |
||||
|
#Check if exempted. Exempt end date is not required. |
||||
|
elif self.temporary_exempt_start_date and self.today >= self.temporary_exempt_start_date: |
||||
|
if not self.temporary_exempt_end_date or self.today <= self.temporary_exempt_end_date: |
||||
|
return 'exempted' |
||||
|
#Transition to alert sr < 0 or stay in alert sr < 0 or sc < 0 and thus alert time is defined |
||||
|
elif not ok and self.alert_start_time and self.extension_start_time and self.today <= add_days_delta(self.extension_start_time, grace_delay): |
||||
|
return 'extension' |
||||
|
elif not ok and self.alert_start_time and self.extension_start_time and self.today > add_days_delta(self.extension_start_time, grace_delay): |
||||
|
return 'suspended' |
||||
|
elif not ok and self.alert_start_time and self.today > add_days_delta(self.alert_start_time, alert_delay): |
||||
|
return 'suspended' |
||||
|
elif (self.sr < 0) or (not ok and self.alert_start_time): |
||||
|
return 'alert' |
||||
|
|
||||
|
elif ( |
||||
|
self.holiday_start_time |
||||
|
and self.holiday_end_time |
||||
|
and self.today >= self.holiday_start_time |
||||
|
and self.today <= self.holiday_end_time |
||||
|
): |
||||
|
return 'holiday' |
||||
|
elif ok or (not self.alert_start_time and self.sr >= 0): |
||||
|
return 'ok' |
||||
|
|
||||
|
def _state_change(self, new_state): |
||||
|
self.ensure_one() |
||||
|
if new_state == 'alert': |
||||
|
self.write({'alert_start_time': self.today, 'extension_start_time': False, 'time_extension': 0}) |
||||
|
if new_state == 'ok': |
||||
|
data = {'extension_start_time': False, 'time_extension': 0} |
||||
|
data['alert_start_time'] = False |
||||
|
self.write(data) |
||||
|
if new_state == 'unsubscribed' or new_state == 'resigning': |
||||
|
# Remove worker from task_templates |
||||
|
self.cooperator_id.sudo().write( |
||||
|
{'subscribed_shift_ids': [(5, 0, 0)]}) |
||||
|
# Remove worker from supercoop in task_templates |
||||
|
task_tpls = self.env['beesdoo.shift.template'].search( |
||||
|
[('super_coop_id', 'in', self.cooperator_id.user_ids.ids)] |
||||
|
) |
||||
|
task_tpls.write({'super_coop_id': False}) |
||||
|
# Remove worker for future tasks (remove also supercoop) |
||||
|
self.env['beesdoo.shift.shift'].sudo().unsubscribe_from_today( |
||||
|
[self.cooperator_id.id], now=fields.Datetime.now() |
||||
|
) |
||||
|
|
||||
|
def _change_counter(self, data): |
||||
|
""" |
||||
|
Call when a shift state is changed |
||||
|
use data generated by _get_counter_date_state_change |
||||
|
""" |
||||
|
self.sc += data.get('sc', 0) |
||||
|
self.sr += data.get('sr', 0) |
||||
|
self.irregular_absence_counter += data.get('irregular_absence_counter', 0) |
||||
|
self.irregular_absence_date = data.get('irregular_absence_date', False) |
||||
|
|
||||
|
############################################### |
||||
|
###### Irregular Cron implementation ########## |
||||
|
############################################### |
||||
|
|
||||
|
def _get_irregular_worker_domain(self): |
||||
|
return ['&', |
||||
|
'&', |
||||
|
'&', |
||||
|
('status', 'not in', ['unsubscribed', 'exempted']), |
||||
|
('working_mode', '=', 'irregular'), |
||||
|
('irregular_start_date', '!=', False), |
||||
|
'|', |
||||
|
'|', ('holiday_start_time', '=', False), ('holiday_end_time', '=', False), |
||||
|
'|', ('holiday_start_time', '>', today), ('holiday_end_time', '<', today), |
||||
|
] |
||||
|
|
||||
|
def _change_irregular_counter(self): |
||||
|
if self.sr > 0: |
||||
|
self.sr -= 1 |
||||
|
elif self.alert_start_time: |
||||
|
self.sr -= 1 |
||||
|
else: |
||||
|
self.sr -= 2 |
||||
|
|
||||
|
################################## |
||||
|
# Internal Implementation # |
||||
|
################################## |
||||
|
def _next_countdown_date(self, irregular_start_date, today=False): |
||||
|
""" |
||||
|
Return the next countdown date given irregular_start_date and |
||||
|
today dates. |
||||
|
This does not take holiday and other status into account. |
||||
|
""" |
||||
|
today = today or fields.Date.today() |
||||
|
|
||||
|
delta = (today - irregular_start_date).days |
||||
|
if not delta % PERIOD: |
||||
|
return today |
||||
|
return add_days_delta(today, PERIOD - (delta % PERIOD)) |
||||
|
|
||||
|
|
||||
|
class ResPartner(models.Model): |
||||
|
_inherit = 'res.partner' |
||||
|
""" |
||||
|
Override is_worker definition |
||||
|
You need have subscribe to a A Share |
||||
|
""" |
||||
|
is_worker = fields.Boolean(compute="_is_worker", search="_search_worker") |
||||
|
|
||||
|
def _is_worker(self): |
||||
|
for rec in self: |
||||
|
rec.is_worker = rec.cooperator_type == 'share_a' |
||||
|
|
||||
|
def _search_worker(self, operator, value): |
||||
|
if (operator == '=' and value) or (operator == '!=' and not value): |
||||
|
return [('cooperator_type', '=', 'share_a')] |
||||
|
else: |
||||
|
return [('cooperator_type', '!=', 'share_a')] |
@ -0,0 +1,81 @@ |
|||||
|
import json |
||||
|
from datetime import datetime, timedelta |
||||
|
|
||||
|
from odoo import _, api, fields, models |
||||
|
from odoo.exceptions import UserError, ValidationError |
||||
|
|
||||
|
|
||||
|
|
||||
|
class Task(models.Model): |
||||
|
_inherit = 'beesdoo.shift.shift' |
||||
|
|
||||
|
################################# |
||||
|
# State Definition # |
||||
|
################################# |
||||
|
|
||||
|
def _get_selection_status(self): |
||||
|
return [ |
||||
|
("open","Confirmed"), |
||||
|
("done","Attended"), |
||||
|
("absent_2","Absent - 2 compensations"), |
||||
|
("absent_1","Absent - 1 compensation"), |
||||
|
("absent_0","Absent - 0 compensation"), |
||||
|
("cancel","Cancelled") |
||||
|
] |
||||
|
|
||||
|
def _get_color_mapping(state): |
||||
|
return { |
||||
|
"draft": 0, |
||||
|
"open": 1, |
||||
|
"done": 5, |
||||
|
"absent_2": 2, |
||||
|
"absent_1": 7, |
||||
|
"absent_0": 3, |
||||
|
"cancel": 9, |
||||
|
}[state] |
||||
|
|
||||
|
def _get_final_state(): |
||||
|
return ["done", "absent_2", "absent_1", "absent_0"] |
||||
|
|
||||
|
|
||||
|
############################################## |
||||
|
# Change counter when state change # |
||||
|
############################################## |
||||
|
def _get_counter_date_state_change(self, new_state): |
||||
|
data = {} |
||||
|
if self.worker_id.working_mode == 'regular': |
||||
|
|
||||
|
if not self.replaced_id: #No replacement case |
||||
|
status = self.worker_id.cooperative_status_ids[0] |
||||
|
else: |
||||
|
status = self.replaced_id.cooperative_status_ids[0] |
||||
|
|
||||
|
if new_state == "done" and not self.is_regular: |
||||
|
# Regular counter is always updated first |
||||
|
if status.sr < 0: |
||||
|
data['sr'] = 1 |
||||
|
elif status.sc < 0: |
||||
|
data['sc'] = 1 |
||||
|
# Bonus shift case |
||||
|
else: |
||||
|
data['sr'] = 1 |
||||
|
|
||||
|
if new_state == "absent_2": |
||||
|
data['sr'] = -1 |
||||
|
data['sc'] = -1 |
||||
|
|
||||
|
if new_state == "absent_1": |
||||
|
data['sr'] = -1 |
||||
|
|
||||
|
elif self.worker_id.working_mode == 'irregular': |
||||
|
status = self.worker_id.cooperative_status_ids[0] |
||||
|
if new_state == "done" or new_state == "absent_0": |
||||
|
data['sr'] = 1 |
||||
|
data['irregular_absence_date'] = False |
||||
|
data['irregular_absence_counter'] = 1 if status.irregular_absence_counter < 0 else 0 |
||||
|
if new_state == "absent_2" or new_state == "absent_1": |
||||
|
if new_state == "absent_2": |
||||
|
data['sr'] = -1 |
||||
|
data['irregular_absence_date'] = self.start_time.date() |
||||
|
data['irregular_absence_counter'] = -1 |
||||
|
return data |
@ -0,0 +1 @@ |
|||||
|
from . import test_beesdoo_shift |
@ -0,0 +1,247 @@ |
|||||
|
# Copyright 2019 - Today Coop IT Easy SCRLfs (<http://www.coopiteasy.be>) |
||||
|
# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl.html). |
||||
|
|
||||
|
import time |
||||
|
from datetime import datetime, timedelta |
||||
|
|
||||
|
from odoo import exceptions, fields |
||||
|
from odoo.exceptions import UserError, ValidationError |
||||
|
from odoo.tests.common import TransactionCase |
||||
|
|
||||
|
|
||||
|
class TestBeesdooShift(TransactionCase): |
||||
|
def setUp(self): |
||||
|
super(TestBeesdooShift, self).setUp() |
||||
|
self.shift_model = self.env["beesdoo.shift.shift"] |
||||
|
self.shift_template_model = self.env["beesdoo.shift.template"] |
||||
|
self.attendance_sheet_model = self.env["beesdoo.shift.sheet"] |
||||
|
self.attendance_sheet_shift_model = self.env[ |
||||
|
"beesdoo.shift.sheet.shift" |
||||
|
] |
||||
|
self.shift_expected_model = self.env["beesdoo.shift.sheet.expected"] |
||||
|
self.shift_added_model = self.env["beesdoo.shift.sheet.added"] |
||||
|
self.task_type_default_id = self.env["ir.config_parameter"].sudo().get_param( |
||||
|
"beesdoo_shift.task_type_default_id" |
||||
|
) |
||||
|
|
||||
|
self.current_time = datetime.now() |
||||
|
self.user_admin = self.env.ref("base.user_root") |
||||
|
self.user_generic = self.env.ref( |
||||
|
"beesdoo_base.beesdoo_shift_user_1_demo" |
||||
|
) |
||||
|
self.user_permanent = self.env.ref( |
||||
|
"beesdoo_base.beesdoo_shift_user_2_demo" |
||||
|
) |
||||
|
|
||||
|
self.setting_wizard = self.env["beesdoo.shift.config.settings"].sudo( |
||||
|
self.user_admin |
||||
|
) |
||||
|
|
||||
|
self.worker_regular_1 = self.env.ref( |
||||
|
"beesdoo_base.res_partner_cooperator_6_demo" |
||||
|
) |
||||
|
self.worker_regular_2 = self.env.ref( |
||||
|
"beesdoo_base.res_partner_cooperator_5_demo" |
||||
|
) |
||||
|
self.worker_regular_3 = self.env.ref( |
||||
|
"beesdoo_base.res_partner_cooperator_3_demo" |
||||
|
) |
||||
|
self.worker_regular_super_1 = self.env.ref( |
||||
|
"beesdoo_base.res_partner_cooperator_1_demo" |
||||
|
) |
||||
|
self.worker_irregular_1 = self.env.ref( |
||||
|
"beesdoo_base.res_partner_cooperator_2_demo" |
||||
|
) |
||||
|
self.worker_irregular_2 = self.env.ref( |
||||
|
"beesdoo_base.res_partner_cooperator_4_demo" |
||||
|
) |
||||
|
|
||||
|
self.task_type_1 = self.env.ref( |
||||
|
"beesdoo_shift.beesdoo_shift_task_type_1_demo" |
||||
|
) |
||||
|
self.task_type_2 = self.env.ref( |
||||
|
"beesdoo_shift.beesdoo_shift_task_type_2_demo" |
||||
|
) |
||||
|
self.task_type_3 = self.env.ref( |
||||
|
"beesdoo_shift.beesdoo_shift_task_type_3_demo" |
||||
|
) |
||||
|
|
||||
|
self.task_template_1 = self.env.ref( |
||||
|
"beesdoo_shift.beesdoo_shift_task_template_1_demo" |
||||
|
) |
||||
|
self.task_template_2 = self.env.ref( |
||||
|
"beesdoo_shift.beesdoo_shift_task_template_2_demo" |
||||
|
) |
||||
|
|
||||
|
# Set time in and out of generation interval parameter |
||||
|
self.start_in_1 = self.current_time + timedelta(seconds=2) |
||||
|
self.end_in_1 = self.current_time + timedelta(minutes=10) |
||||
|
self.start_in_2 = self.current_time + timedelta(minutes=9) |
||||
|
self.end_in_2 = self.current_time + timedelta(minutes=21) |
||||
|
self.start_out_1 = self.current_time - timedelta(minutes=50) |
||||
|
self.end_out_1 = self.current_time - timedelta(minutes=20) |
||||
|
self.start_out_2 = self.current_time + timedelta(minutes=40) |
||||
|
self.end_out_2 = self.current_time + timedelta(minutes=50) |
||||
|
|
||||
|
self.shift_regular_regular_1 = self.shift_model.create( |
||||
|
{ |
||||
|
"task_template_id": self.task_template_1.id, |
||||
|
"task_type_id": self.task_type_1.id, |
||||
|
"worker_id": self.worker_regular_1.id, |
||||
|
"start_time": self.start_in_1, |
||||
|
"end_time": self.end_in_1, |
||||
|
"is_regular": True, |
||||
|
"is_compensation": False, |
||||
|
} |
||||
|
) |
||||
|
self.shift_regular_regular_2 = self.shift_model.create( |
||||
|
{ |
||||
|
"task_type_id": self.task_type_2.id, |
||||
|
"worker_id": self.worker_regular_2.id, |
||||
|
"start_time": self.start_out_1, |
||||
|
"end_time": self.end_out_1, |
||||
|
"is_regular": True, |
||||
|
"is_compensation": False, |
||||
|
} |
||||
|
) |
||||
|
self.shift_regular_regular_replaced_1 = self.shift_model.create( |
||||
|
{ |
||||
|
"task_template_id": self.task_template_1.id, |
||||
|
"task_type_id": self.task_type_3.id, |
||||
|
"worker_id": self.worker_regular_3.id, |
||||
|
"start_time": self.start_in_1, |
||||
|
"end_time": self.end_in_1, |
||||
|
"is_regular": True, |
||||
|
"is_compensation": False, |
||||
|
"replaced_id": self.worker_regular_2.id, |
||||
|
} |
||||
|
) |
||||
|
future_shift_regular = self.shift_model.create( |
||||
|
{ |
||||
|
"task_template_id": self.task_template_2.id, |
||||
|
"task_type_id": self.task_type_1.id, |
||||
|
"worker_id": self.worker_regular_super_1.id, |
||||
|
"start_time": self.start_in_2, |
||||
|
"end_time": self.end_in_2, |
||||
|
"is_regular": False, |
||||
|
"is_compensation": True, |
||||
|
} |
||||
|
) |
||||
|
self.shift_irregular_1 = self.shift_model.create( |
||||
|
{ |
||||
|
"task_template_id": self.task_template_1.id, |
||||
|
"task_type_id": self.task_type_2.id, |
||||
|
"worker_id": self.worker_irregular_1.id, |
||||
|
"start_time": self.start_in_1, |
||||
|
"end_time": self.end_in_1, |
||||
|
} |
||||
|
) |
||||
|
self.shift_irregular_2 = self.shift_model.create( |
||||
|
{ |
||||
|
"task_type_id": self.task_type_3.id, |
||||
|
"worker_id": self.worker_irregular_2.id, |
||||
|
"start_time": self.start_out_2, |
||||
|
"end_time": self.end_out_2, |
||||
|
} |
||||
|
) |
||||
|
self.shift_empty_1 = self.shift_model.create( |
||||
|
{ |
||||
|
"task_template_id": self.task_template_1.id, |
||||
|
"task_type_id": self.task_type_1.id, |
||||
|
"start_time": self.start_in_1, |
||||
|
"end_time": self.end_in_1, |
||||
|
} |
||||
|
) |
||||
|
|
||||
|
def test_shift_counters(self): |
||||
|
"Test shift counters calculation and cooperative status update" |
||||
|
|
||||
|
status_1 = self.worker_regular_1.cooperative_status_ids |
||||
|
status_2 = self.worker_regular_3.cooperative_status_ids |
||||
|
status_3 = self.worker_irregular_1.cooperative_status_ids |
||||
|
|
||||
|
shift_regular = self.shift_model.create( |
||||
|
{ |
||||
|
"task_template_id": self.task_template_1.id, |
||||
|
"task_type_id": self.task_type_1.id, |
||||
|
"worker_id": self.worker_regular_1.id, |
||||
|
"start_time": datetime.now() - timedelta(minutes=50), |
||||
|
"end_time": datetime.now() - timedelta(minutes=40), |
||||
|
"is_regular": True, |
||||
|
"is_compensation": False, |
||||
|
} |
||||
|
) |
||||
|
future_shift_regular = self.shift_model.create( |
||||
|
{ |
||||
|
"task_template_id": self.task_template_2.id, |
||||
|
"task_type_id": self.task_type_2.id, |
||||
|
"worker_id": self.worker_regular_1.id, |
||||
|
"start_time": datetime.now() + timedelta(minutes=20), |
||||
|
"end_time": datetime.now() + timedelta(minutes=30), |
||||
|
"is_regular": True, |
||||
|
"is_compensation": False, |
||||
|
} |
||||
|
) |
||||
|
shift_irregular = self.shift_model.create( |
||||
|
{ |
||||
|
"task_template_id": self.task_template_2.id, |
||||
|
"task_type_id": self.task_type_3.id, |
||||
|
"worker_id": self.worker_irregular_1.id, |
||||
|
"start_time": datetime.now() - timedelta(minutes=15), |
||||
|
"end_time": datetime.now() - timedelta(minutes=10), |
||||
|
} |
||||
|
) |
||||
|
|
||||
|
# For a regular worker |
||||
|
status_1.sr = 0 |
||||
|
status_1.sc = 0 |
||||
|
self.assertEqual(status_1.status, "ok") |
||||
|
shift_regular.state = "absent_1" |
||||
|
self.assertEqual(status_1.sr, -1) |
||||
|
self.assertEqual(status_1.status, "alert") |
||||
|
shift_regular.state = "done" |
||||
|
self.assertEquals(status_1.sr, 0) |
||||
|
self.assertEquals(status_1.sc, 0) |
||||
|
shift_regular.state = "open" |
||||
|
shift_regular.write({"is_regular": False, "is_compensation": True}) |
||||
|
shift_regular.state = "done" |
||||
|
self.assertEquals(status_1.sr, 1) |
||||
|
self.assertEquals(status_1.sc, 0) |
||||
|
|
||||
|
# Check unsubscribed status |
||||
|
status_1.sr = -1 |
||||
|
status_1.sc = -1 |
||||
|
|
||||
|
# Subscribe him to another future shift |
||||
|
future_shift_regular.worker_id = self.worker_regular_1 |
||||
|
with self.assertRaises(ValidationError) as e: |
||||
|
future_shift_regular.state = "absent_2" |
||||
|
self.assertIn("future", str(e.exception)) |
||||
|
status_1.sr = -2 |
||||
|
status_1.sc = -2 |
||||
|
self.assertEquals(status_1.status, "unsubscribed") |
||||
|
|
||||
|
# Should be unsubscribed from future shift |
||||
|
self.assertFalse(future_shift_regular.worker_id) |
||||
|
|
||||
|
# With replacement worker (self.worker_regular_3) |
||||
|
shift_regular.state = "open" |
||||
|
status_1.sr = 0 |
||||
|
status_1.sc = 0 |
||||
|
status_2.sr = 0 |
||||
|
status_2.sc = 0 |
||||
|
shift_regular.replaced_id = self.worker_regular_3 |
||||
|
shift_regular.state = "absent_2" |
||||
|
self.assertEqual(status_1.sr, 0) |
||||
|
self.assertEqual(status_1.sc, 0) |
||||
|
self.assertEqual(status_2.sr, -1) |
||||
|
self.assertEqual(status_2.sc, -1) |
||||
|
|
||||
|
# For an irregular worker |
||||
|
status_3.sr = 0 |
||||
|
status_3.sc = 0 |
||||
|
self.assertEqual(status_3.status, "ok") |
||||
|
shift_irregular.state = "done" |
||||
|
self.assertEqual(status_3.sr, 1) |
||||
|
shift_irregular.state = "absent_2" |
||||
|
self.assertEqual(status_3.sr, -1) |
Write
Preview
Loading…
Cancel
Save
Reference in new issue