Commit 5575d2f8 by François C.

Add shift absence process for any datetime (for test purpose)

parent ddcbb3a0
Pipeline #2338 passed with stage
in 2 minutes 12 seconds
...@@ -1339,7 +1339,7 @@ class CagetteServices(models.Model): ...@@ -1339,7 +1339,7 @@ class CagetteServices(models.Model):
@staticmethod @staticmethod
def get_services_at_time(time, tz_offset, with_members=True): def get_services_at_time(time, tz_offset, with_members=True):
"""Retrieve present services with member linked.""" """Retrieve present services with members linked."""
default_acceptable_minutes_after_shift_begins = getattr(settings, 'ACCEPTABLE_ENTRANCE_MINUTES_AFTER_SHIFT_BEGINS', 15) default_acceptable_minutes_after_shift_begins = getattr(settings, 'ACCEPTABLE_ENTRANCE_MINUTES_AFTER_SHIFT_BEGINS', 15)
minutes_before_shift_starts_delay = getattr(settings, 'ACCEPTABLE_ENTRANCE_MINUTES_BEFORE_SHIFT', 15) minutes_before_shift_starts_delay = getattr(settings, 'ACCEPTABLE_ENTRANCE_MINUTES_BEFORE_SHIFT', 15)
...@@ -1360,7 +1360,7 @@ class CagetteServices(models.Model): ...@@ -1360,7 +1360,7 @@ class CagetteServices(models.Model):
fields = ['name', 'week_number', 'registration_ids', fields = ['name', 'week_number', 'registration_ids',
'standard_registration_ids', 'standard_registration_ids',
'shift_template_id', 'shift_ticket_ids', 'shift_template_id', 'shift_ticket_ids',
'date_begin_tz', 'date_end_tz'] 'date_begin_tz', 'date_end_tz', 'state']
services = api.search_read('shift.shift', cond, fields,order ="date_begin_tz ASC") services = api.search_read('shift.shift', cond, fields,order ="date_begin_tz ASC")
for s in services: for s in services:
if (len(s['registration_ids']) > 0): if (len(s['registration_ids']) > 0):
...@@ -1510,13 +1510,18 @@ class CagetteServices(models.Model): ...@@ -1510,13 +1510,18 @@ class CagetteServices(models.Model):
cond = [['date_begin', '>=', date_24h_before.isoformat()], cond = [['date_begin', '>=', date_24h_before.isoformat()],
['date_begin', '<=', end_date.isoformat()], ['date_begin', '<=', end_date.isoformat()],
['state', '=', 'open']] ['state', '=', 'open']]
fields = ['state', 'partner_id', 'date_begin'] fields = ['state', 'partner_id', 'date_begin', 'shift_id']
res = api.search_read('shift.registration', cond, fields) res = api.search_read('shift.registration', cond, fields)
ids = [] ids = []
partner_ids = [] partner_ids = []
excluded_partner = [] excluded_partner = []
canceled_reg_ids = [] # for exempted people
shift_ids = []
for r in res: for r in res:
partner_ids.append(int(r['partner_id'][0])) partner_ids.append(int(r['partner_id'][0]))
shift_id = int(r['shift_id'][0])
if shift_id not in shift_ids:
shift_ids.append(shift_id)
cond = [['id', 'in', partner_ids], cond = [['id', 'in', partner_ids],
['cooperative_state', 'in', ['exempted']]] ['cooperative_state', 'in', ['exempted']]]
fields = ['id'] fields = ['id']
...@@ -1530,13 +1535,28 @@ class CagetteServices(models.Model): ...@@ -1530,13 +1535,28 @@ class CagetteServices(models.Model):
(_h, _m, _s) = h.split(':') (_h, _m, _s) = h.split(':')
if int(_h) < 21: if int(_h) < 21:
ids.append(int(r['id'])) ids.append(int(r['id']))
else:
canceled_reg_ids.append(int(r['id']))
# coop_logger.info("Traitement absences shift_registration ids %s", ids) # coop_logger.info("Traitement absences shift_registration ids %s", ids)
f = {'state': absence_status, 'date_closed': now.isoformat()} f = {'state': absence_status, 'date_closed': now.isoformat()}
update_shift_reg_result = {'update': api.update('shift.registration', ids, f), 'reg_shift': res} update_shift_reg_result = {'update': api.update('shift.registration', ids, f), 'reg_shift': res, 'errors': []}
if update_shift_reg_result['update'] is True: if update_shift_reg_result['update'] is True:
update_shift_reg_result['process_status_res'] = api.execute('res.partner','run_process_target_status', []) update_shift_reg_result['process_status_res'] = api.execute('res.partner','run_process_target_status', [])
# change shift state by triggering button_done method for all related shifts
if len(canceled_reg_ids) > 0:
f = {'state': 'cancel', 'date_closed': now.isoformat()}
api.update('shift.registration', canceled_reg_ids, f)
for sid in shift_ids:
try:
api.execute('shift.shift', 'button_done', sid)
except Exception as e:
marshal_none_error = 'cannot marshal None unless allow_none is enabled'
if not (marshal_none_error in str(e)):
update_shift_reg_result['errors'].append({'shift_id': sid, 'msg' :str(e)})
return update_shift_reg_result return update_shift_reg_result
@staticmethod @staticmethod
def close_ftop_service(): def close_ftop_service():
"""Called by cron script""" """Called by cron script"""
...@@ -1670,6 +1690,104 @@ class CagetteServices(models.Model): ...@@ -1670,6 +1690,104 @@ class CagetteServices(models.Model):
coop_logger.error("easy_validate_shift_presence : %s %s", str(coop_id), str(e)) coop_logger.error("easy_validate_shift_presence : %s %s", str(coop_id), str(e))
return res return res
class CagetteService(models.Model):
"""Class to handle cagette Odoo service."""
def __init__(self, id):
"""Init with odoo id."""
self.id = int(id)
self.o_api = OdooAPI()
def _process_associated_people_extra_shift_done(self):
cond = [['shift_id', '=', self.id],
['state', '=', 'done'],
['associate_registered', '=', 'both'],
['should_increment_extra_shift_done', '=', True]]
fields = ['id', 'state', 'partner_id', 'date_begin']
res = self.o_api.search_read('shift.registration', cond, fields)
extra_shift_done_incremented_srids = [] # shift registration ids
for r in res:
cond = [['id', '=', r['partner_id'][0]]]
fields = ['id','extra_shift_done']
res_partner = self.o_api.search_read('res.partner', cond, fields)
f = {'extra_shift_done': res_partner[0]['extra_shift_done'] + 1 }
self.o_api.update('res.partner', [r['partner_id'][0]], f)
extra_shift_done_incremented_srids.append(int(r['id']))
# Make sure the counter isn't incremented twice
f = {'should_increment_extra_shift_done': False}
self.o_api.update('shift.registration', extra_shift_done_incremented_srids, f)
def _process_related_shift_registrations(self):
now = datetime.datetime.now()
absence_status = 'excused'
res_c = self.o_api.search_read('ir.config_parameter',
[['key', '=', 'lacagette_membership.absence_status']],
['value'])
if len(res_c) == 1:
absence_status = res_c[0]['value']
cond = [['shift_id', '=', self.id],
['state', '=', 'open']]
fields = ['state', 'partner_id', 'date_begin']
res = self.o_api.search_read('shift.registration', cond, fields)
ids = []
partner_ids = []
excluded_partner = []
canceled_reg_ids = [] # for exempted people
for r in res:
partner_ids.append(int(r['partner_id'][0]))
cond = [['id', 'in', partner_ids],
['cooperative_state', 'in', ['exempted']]]
fields = ['id']
res_exempted = self.o_api.search_read('res.partner', cond, fields)
for r in res_exempted:
excluded_partner.append(int(r['id']))
for r in res:
if not (int(r['partner_id'][0]) in excluded_partner):
d_begin = r['date_begin']
(d, h) = d_begin.split(' ')
(_h, _m, _s) = h.split(':')
if int(_h) < 21:
ids.append(int(r['id']))
else:
canceled_reg_ids.append(int(r['id']))
# coop_logger.info("Traitement absences shift_registration ids %s", ids)
f = {'state': absence_status, 'date_closed': now.isoformat()}
update_shift_reg_result = {'update': self.o_api.update('shift.registration', ids, f), 'reg_shift': res, 'errors': []}
if update_shift_reg_result['update'] is True:
update_shift_reg_result['process_status_res'] = self.o_api.execute('res.partner','run_process_target_status', [])
# change shift state by triggering button_done method for all related shifts
if len(canceled_reg_ids) > 0:
f = {'state': 'cancel', 'date_closed': now.isoformat()}
self.o_api.update('shift.registration', canceled_reg_ids, f)
try:
self.o_api.execute('shift.shift', 'button_done', self.id)
except Exception as e:
marshal_none_error = 'cannot marshal None unless allow_none is enabled'
if not (marshal_none_error in str(e)):
update_shift_reg_result['errors'].append({'shift_id': sid, 'msg' :str(e)})
return update_shift_reg_result
def record_absences(self, request):
"""Can only been executed if an Odoo user is beeing connected."""
res = {}
try:
if CagetteUser.are_credentials_ok(request) is True:
self._process_associated_people_extra_shift_done()
res = self._process_related_shift_registrations()
else:
res['error'] = 'Forbidden'
except Exception as e:
coop_logger.error("CagetteService.record_absences : %s %s", str(self.id), str(e))
res['error'] = str(e)
return res
class CagetteUser(models.Model): class CagetteUser(models.Model):
@staticmethod @staticmethod
......
...@@ -49,6 +49,7 @@ h1 .member_name {font-weight: bold;} ...@@ -49,6 +49,7 @@ h1 .member_name {font-weight: bold;}
.members_list li.btn--inverse.late {background-color: #de9b00; color: white} .members_list li.btn--inverse.late {background-color: #de9b00; color: white}
.members_list li.btn--inverse.both {background-color: #0275d8 ; color: white} .members_list li.btn--inverse.both {background-color: #0275d8 ; color: white}
.members_list.done li.btn {pointer-events: none;}
#service_entry_success {font-size: x-large;} #service_entry_success {font-size: x-large;}
#service_entry_success .explanations {margin: 25px 0; font-size: 18px;} #service_entry_success .explanations {margin: 25px 0; font-size: 18px;}
#service_entry_success .points, #service_entry_success .points,
......
...@@ -41,6 +41,7 @@ var coop_info = $('.coop-info'); ...@@ -41,6 +41,7 @@ var coop_info = $('.coop-info');
var service_data = null; var service_data = null;
const missed_begin_msg = $('#missed_begin_msg').html(); const missed_begin_msg = $('#missed_begin_msg').html();
const current_shift_process_data_actions = $('#current_shift_process_data_actions');
let no_pict_msg = $('#no-picture-msg'); let no_pict_msg = $('#no-picture-msg');
...@@ -70,6 +71,12 @@ var html_elts = { ...@@ -70,6 +71,12 @@ var html_elts = {
var chars = []; //input chars buffer var chars = []; //input chars buffer
var reset_shift_process_actions_zone = function() {
current_shift_process_data_actions.off('click', 'a');
current_shift_process_data_actions.hide();
current_shift_process_data_actions.empty();
}
function fill_member_slide(member) { function fill_member_slide(member) {
no_pict_msg.hide(); no_pict_msg.hide();
current_displayed_member = member; current_displayed_member = member;
...@@ -282,6 +289,9 @@ function fill_service_entry(s) { ...@@ -282,6 +289,9 @@ function fill_service_entry(s) {
// if (typeof s.late != "undefined" && s.late == true) { // if (typeof s.late != "undefined" && s.late == true) {
// m_list = '<ul class="members_list late">'; // m_list = '<ul class="members_list late">';
// } // }
if (s.state == 'done') {
m_list = '<ul class="members_list done">';
}
$.each(s.members, function(i, e) { $.each(s.members, function(i, e) {
var li_class = "btn"; var li_class = "btn";
var li_data = ""; var li_data = "";
...@@ -304,6 +314,9 @@ function fill_service_entry(s) { ...@@ -304,6 +314,9 @@ function fill_service_entry(s) {
} else { } else {
li_data = ' data-rid="'+e.id+'" data-mid="'+e.partner_id[0]+'"'; li_data = ' data-rid="'+e.id+'" data-mid="'+e.partner_id[0]+'"';
} }
if (s.state == 'done') {
li_data += ' disabled ';
}
m_list += '<li class="'+li_class+'" '+li_data+'>'; m_list += '<li class="'+li_class+'" '+li_data+'>';
m_list += e.partner_id[1]; m_list += e.partner_id[1];
m_list += '</li>'; m_list += '</li>';
...@@ -311,6 +324,40 @@ function fill_service_entry(s) { ...@@ -311,6 +324,40 @@ function fill_service_entry(s) {
m_list += '</ul>'; m_list += '</ul>';
} }
if (coop_is_connected()) {
// Add shift process data
reset_shift_process_actions_zone();
if (s.state == 'draft' || s.state == 'confirm') {
let btn = $('<a>').addClass('btn btn--primary txtcenter')
.text('Enregistrer les absences / présences')
.attr('id','record_shift_absences');
current_shift_process_data_actions.append(btn);
current_shift_process_data_actions.on('click', '#record_shift_absences', function(){
msg = "<p>Lancer le traitement des présences et absences de ce service</p>";
openModal(msg, function() {
try {
$.ajax({
url: '/members/record_shift_absences/' + s.id,
dataType : 'json'
})
.done(function(rData) {
if (typeof rData.update !== "undefined" && rData.update == true) {
enqueue_message_for_next_loading("Données de présences traitées.");
location.reload();
}
});
} catch (e) {
console.log(e);
}
}, 'Confirmer');
});
} else {
current_shift_process_data_actions.append("<em>Traitement des présences : " + s.state + "</em>");
}
current_shift_process_data_actions.show();
}
rattrapage_ou_volant = null; rattrapage_ou_volant = null;
shift_members.html(m_list); shift_members.html(m_list);
rattrapage_wanted.show(); rattrapage_wanted.show();
...@@ -401,6 +448,8 @@ function get_service_entry_data() { ...@@ -401,6 +448,8 @@ function get_service_entry_data() {
}) })
.done(function(rData) { .done(function(rData) {
info_place.text(''); info_place.text('');
reset_shift_process_actions_zone();
var page_title = pages.service_entry.find('h1'); var page_title = pages.service_entry.find('h1');
page_title.text('Qui es-tu ?'); page_title.text('Qui es-tu ?');
......
...@@ -43,6 +43,7 @@ urlpatterns = [ ...@@ -43,6 +43,7 @@ urlpatterns = [
url(r'^services_at_time/([0-9TZ\-\: \.]+)/([0-9\-]+)$', views.services_at_time), url(r'^services_at_time/([0-9TZ\-\: \.]+)/([0-9\-]+)$', views.services_at_time),
url(r'^service_presence/$', views.record_service_presence), url(r'^service_presence/$', views.record_service_presence),
url(r'^record_absences/?([0-9\-\ \:]*)$', views.record_absences), url(r'^record_absences/?([0-9\-\ \:]*)$', views.record_absences),
url(r'^record_shift_absences/?([0-9]+)$', views.record_shift_absences),
url(r'^close_ftop_service$', views.close_ftop_service), url(r'^close_ftop_service$', views.close_ftop_service),
url(r'^get_credentials$', views.get_credentials), url(r'^get_credentials$', views.get_credentials),
url(r'^remove_data_from_couchdb$', views.remove_data_from_CouchDB), url(r'^remove_data_from_couchdb$', views.remove_data_from_CouchDB),
......
...@@ -5,7 +5,7 @@ from outils.for_view_imports import * ...@@ -5,7 +5,7 @@ from outils.for_view_imports import *
from members.models import CagetteMember from members.models import CagetteMember
from members.models import CagetteUser from members.models import CagetteUser
from members.models import CagetteMembers from members.models import CagetteMembers
from members.models import CagetteServices from members.models import CagetteServices, CagetteService
from outils.forms import GenericExportMonthForm from outils.forms import GenericExportMonthForm
import datetime import datetime
...@@ -347,6 +347,10 @@ def easy_validate_shift_presence(request): ...@@ -347,6 +347,10 @@ def easy_validate_shift_presence(request):
def record_absences(request, date): def record_absences(request, date):
return JsonResponse({'res': CagetteServices.record_absences(date)}) return JsonResponse({'res': CagetteServices.record_absences(date)})
def record_shift_absences(request, id):
shift = CagetteService(id)
return JsonResponse({'res': shift.record_absences(request)})
def close_ftop_service(request): def close_ftop_service(request):
"""Close the closest past FTOP service""" """Close the closest past FTOP service"""
return JsonResponse({'res': CagetteServices.close_ftop_service()}) return JsonResponse({'res': CagetteServices.close_ftop_service()})
......
...@@ -141,7 +141,9 @@ ...@@ -141,7 +141,9 @@
<div class="col-2 row-2"> <div class="col-2 row-2">
<a class="btn btn--primary" data-next="first_page" >Retour accueil</a> <a class="btn btn--primary" data-next="first_page" >Retour accueil</a>
</div> </div>
<div class="col-2 row-2"></div> <div class="col-2 row-2 txtcenter">
<div id="current_shift_process_data_actions" style="display:none;"></div>
</div>
<div class="col-2 row-2 login_area"> <div class="col-2 row-2 login_area">
{% include "common/conn_admin.html" %} {% include "common/conn_admin.html" %}
</div> </div>
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment