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):
@staticmethod
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)
minutes_before_shift_starts_delay = getattr(settings, 'ACCEPTABLE_ENTRANCE_MINUTES_BEFORE_SHIFT', 15)
......@@ -1360,7 +1360,7 @@ class CagetteServices(models.Model):
fields = ['name', 'week_number', 'registration_ids',
'standard_registration_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")
for s in services:
if (len(s['registration_ids']) > 0):
......@@ -1510,13 +1510,18 @@ class CagetteServices(models.Model):
cond = [['date_begin', '>=', date_24h_before.isoformat()],
['date_begin', '<=', end_date.isoformat()],
['state', '=', 'open']]
fields = ['state', 'partner_id', 'date_begin']
fields = ['state', 'partner_id', 'date_begin', 'shift_id']
res = api.search_read('shift.registration', cond, fields)
ids = []
partner_ids = []
excluded_partner = []
canceled_reg_ids = [] # for exempted people
shift_ids = []
for r in res:
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],
['cooperative_state', 'in', ['exempted']]]
fields = ['id']
......@@ -1530,13 +1535,28 @@ class CagetteServices(models.Model):
(_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': 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:
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
@staticmethod
def close_ftop_service():
"""Called by cron script"""
......@@ -1670,6 +1690,104 @@ class CagetteServices(models.Model):
coop_logger.error("easy_validate_shift_presence : %s %s", str(coop_id), str(e))
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):
@staticmethod
......
......@@ -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.both {background-color: #0275d8 ; color: white}
.members_list.done li.btn {pointer-events: none;}
#service_entry_success {font-size: x-large;}
#service_entry_success .explanations {margin: 25px 0; font-size: 18px;}
#service_entry_success .points,
......
......@@ -41,6 +41,7 @@ var coop_info = $('.coop-info');
var service_data = null;
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');
......@@ -70,6 +71,12 @@ var html_elts = {
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) {
no_pict_msg.hide();
current_displayed_member = member;
......@@ -282,6 +289,9 @@ function fill_service_entry(s) {
// if (typeof s.late != "undefined" && s.late == true) {
// m_list = '<ul class="members_list late">';
// }
if (s.state == 'done') {
m_list = '<ul class="members_list done">';
}
$.each(s.members, function(i, e) {
var li_class = "btn";
var li_data = "";
......@@ -304,6 +314,9 @@ function fill_service_entry(s) {
} else {
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 += e.partner_id[1];
m_list += '</li>';
......@@ -311,6 +324,40 @@ function fill_service_entry(s) {
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;
shift_members.html(m_list);
rattrapage_wanted.show();
......@@ -401,6 +448,8 @@ function get_service_entry_data() {
})
.done(function(rData) {
info_place.text('');
reset_shift_process_actions_zone();
var page_title = pages.service_entry.find('h1');
page_title.text('Qui es-tu ?');
......
......@@ -43,6 +43,7 @@ urlpatterns = [
url(r'^services_at_time/([0-9TZ\-\: \.]+)/([0-9\-]+)$', views.services_at_time),
url(r'^service_presence/$', views.record_service_presence),
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'^get_credentials$', views.get_credentials),
url(r'^remove_data_from_couchdb$', views.remove_data_from_CouchDB),
......
......@@ -5,7 +5,7 @@ from outils.for_view_imports import *
from members.models import CagetteMember
from members.models import CagetteUser
from members.models import CagetteMembers
from members.models import CagetteServices
from members.models import CagetteServices, CagetteService
from outils.forms import GenericExportMonthForm
import datetime
......@@ -347,6 +347,10 @@ def easy_validate_shift_presence(request):
def record_absences(request, 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):
"""Close the closest past FTOP service"""
return JsonResponse({'res': CagetteServices.close_ftop_service()})
......
......@@ -141,7 +141,9 @@
<div class="col-2 row-2">
<a class="btn btn--primary" data-next="first_page" >Retour accueil</a>
</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">
{% include "common/conn_admin.html" %}
</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