Commit 76c6252c by Damien Moulard

Merge branch '2251-shift-screen-associate' into 'dev_cooperatic'

2251 shift screen associate

See merge request !140
parents 6aa05fdd 2c422b94
Pipeline #1921 passed with stage
in 1 minute 30 seconds
......@@ -1255,7 +1255,7 @@ class CagetteServices(models.Model):
).total_seconds() / 60 > default_acceptable_minutes_after_shift_begins
if with_members is True:
cond = [['id', 'in', s['registration_ids']], ['state', 'not in', ['cancel', 'waiting', 'draft']]]
fields = ['partner_id', 'shift_type', 'state', 'is_late']
fields = ['partner_id', 'shift_type', 'state', 'is_late', 'associate_registered']
members = api.search_read('shift.registration', cond, fields)
s['members'] = sorted(members, key=lambda x: x['partner_id'][0])
if len(s['members']) > 0:
......@@ -1264,22 +1264,27 @@ class CagetteServices(models.Model):
for m in s['members']:
mids.append(m['partner_id'][0])
cond = [['parent_id', 'in', mids]]
fields = ['parent_id', 'name']
fields = ['id', 'parent_id', 'name','barcode_base']
associated = api.search_read('res.partner', cond, fields)
if len(associated) > 0:
for m in s['members']:
for a in associated:
if int(a['parent_id'][0]) == int(m['partner_id'][0]):
m['partner_name'] = m['partner_id'][1]
m['partner_id'][1] += ' en binôme avec ' + a['name']
m['associate_name'] = str(a['barcode_base']) + ' - ' + a['name']
return services
@staticmethod
def registration_done(registration_id, overrided_date=""):
def registration_done(registration_id, overrided_date="", typeAction=""):
"""Equivalent to click present in presence form."""
api = OdooAPI()
f = {'state': 'done'}
if(typeAction != "normal" and typeAction != ""):
f['associate_registered'] = typeAction
late_mode = getattr(settings, 'ENTRANCE_WITH_LATE_MODE', False)
if late_mode is True:
# services = CagetteServices.get_services_at_time('14:28',0, with_members=False)
......@@ -1301,7 +1306,14 @@ class CagetteServices(models.Model):
return api.update('shift.registration', [int(registration_id)], f)
@staticmethod
def record_rattrapage(mid, sid, stid):
def reopen_registration(registration_id, overrided_date=""):
api = OdooAPI()
f = {'state': 'open'}
return api.update('shift.registration', [int(registration_id)], f)
@staticmethod
def record_rattrapage(mid, sid, stid, typeAction):
"""Add a shift registration for member mid.
(shift sid, shift ticket stid)
......@@ -1317,6 +1329,8 @@ class CagetteServices(models.Model):
"state": 'open'}
reg_id = api.create('shift.registration', fields)
f = {'state': 'done'}
if(typeAction != "normal" and typeAction != ""):
f['associate_registered'] = typeAction
return api.update('shift.registration', [int(reg_id)], f)
@staticmethod
......@@ -1332,6 +1346,20 @@ class CagetteServices(models.Model):
# let authorized people time to set presence for those who came in late
end_date = now - datetime.timedelta(hours=2)
api = OdooAPI()
# Let's start by adding an extra shift to associated member who came together
cond = [['date_begin', '>=', date_24h_before.isoformat()],
['date_begin', '<=', end_date.isoformat()],
['state', '=', 'done'], ['associate_registered', '=', 'both']]
fields = ['state', 'partner_id', 'date_begin']
res = api.search_read('shift.registration', cond, fields)
for r in res:
cond = [['id', '=', r['partner_id'][0]]]
fields = ['id','extra_shift_done']
res = api.search_read('res.partner', cond, fields)
f = {'extra_shift_done': res[0]['extra_shift_done'] + 1 }
api.update('res.partner', [r['partner_id'][0]], f)
absence_status = 'excused'
res_c = api.search_read('ir.config_parameter',
[['key', '=', 'lacagette_membership.absence_status']],
......
......@@ -44,8 +44,9 @@ h1 .member_name {font-weight: bold;}
.members_list {list-style: none;}
.members_list li {display:block;margin-bottom:5px;}
.members_list li.btn--inverse {background: #449d44; cursor:not-allowed; color: #FFF; }
.members_list li.btn--inverse {background: #449d44; color: #FFF; }
.members_list li.btn--inverse.late {background-color: #de9b00; color: white}
.members_list li.btn--inverse.both {background-color: #0275d8 ; color: white}
#service_entry_success {font-size: x-large;}
#service_entry_success .explanations {margin: 25px 0; font-size: 18px;}
......@@ -64,7 +65,7 @@ h1 .member_name {font-weight: bold;}
#service_en_cours .info a {line-height: 24px; font-size:14px; margin-top:15px;}
.outside_list a {margin-left:15px;}
#rattrapage_1 .advice {margin-top:15px;}
.btn.present {background:#50C878;}
.btn.present {background:#50C878; color: white !important; font-weight: bold;}
.btn.return {background: #ff3333; color:#FFF !important; margin-top:25px;}
.msg-big {font-size: xx-large; background: #fff; padding:25px; text-align: center;}
......
......@@ -31,12 +31,14 @@ var search_field = $('input[name="search_string"]');
var shift_title = $('#current_shift_title');
var shift_members = $('#current_shift_members');
var service_validation = $('#service_validation');
var associated_service_validation = $('#associated_service_validation');
var validation_last_call = 0;
var rattrapage_wanted = $('[data-next="rattrapage_1"]');
var webcam_is_attached = false;
var photo_advice = $('#photo_advice');
var photo_studio = $('#photo_studio');
var coop_info = $('.coop-info');
var service_data = null;
const missed_begin_msg = $('#missed_begin_msg').html();
......@@ -264,7 +266,7 @@ function get_simple_service_name(s) {
}
function move_service_validation_to(page) {
service_validation.find('.btn').data('stid', '0');
service_data.stid=0;
page.find('.validation_wrapper')
.append(service_validation.detach());
}
......@@ -285,10 +287,14 @@ function fill_service_entry(s) {
var li_data = "";
if (e.state == "done") {
li_data = ' data-rid="'+e.id+'" data-mid="'+e.partner_id[0]+'"';
li_class += "--inverse";
if (e.is_late == true) {
li_class += " late";
}
if (e.associate_registered=='both') {
li_class += " both";
}
} else {
li_data = ' data-rid="'+e.id+'" data-mid="'+e.partner_id[0]+'"';
}
......@@ -321,13 +327,29 @@ function clean_service_entry() {
function fill_service_validation(rid, coop_num_name, coop_id) {
var coop_name_elts = coop_num_name.split(' - ');
for (member of loaded_services[0].members) {
if (member.id ==rid) {
if (member.associate_name) {
pages.service_entry_validation.find('#service_validation').hide();
pages.service_entry_validation.find('#associated_service_validation').show();
pages.service_entry_validation.find('#associated_btn').text(member.associate_name);
pages.service_entry_validation.find('#partner_btn').text(member.partner_name);
} else {
pages.service_entry_validation.find('#associated_service_validation').hide();
pages.service_entry_validation.find('#service_validation').show();
}
}
}
service_data={
rid: rid,
sid: selected_service.id,
mid: coop_id};
pages.service_entry_validation.find('span.member_name').text(coop_name_elts[1]);
move_service_validation_to(pages.service_entry_validation);
service_validation.find('.btn')
.data('rid', rid)
.data('sid', selected_service.id)
.data('mid', coop_id);
}
function select_possible_service() {
......@@ -372,7 +394,6 @@ function get_service_entry_data() {
dataType : 'json'
})
.done(function(rData) {
//console.log(rData);
info_place.text('');
var page_title = pages.service_entry.find('h1');
......@@ -397,6 +418,7 @@ function get_service_entry_data() {
page_title.text('Quel est ton service ?');
} else {
loaded_services = rData.res;
fill_service_entry(rData.res[0]);
}
}
......@@ -443,22 +465,21 @@ function fill_service_entry_sucess(member) {
}
function record_service_presence() {
function record_service_presence(e) {
var d = new Date();
var elapsed_since_last_call = d.getTime() - validation_last_call;
if (elapsed_since_last_call > 10000) {
if (elapsed_since_last_call > 1000) {
loading2.show();
validation_last_call = d.getTime();
var clicked = service_validation.find('.btn');
var rid = clicked.data('rid');
var mid = clicked.data('mid');
var sid = clicked.data('sid');
var stid = clicked.data('stid');
var rid = service_data.rid;
var mid = service_data.mid;
var sid = service_data.sid;
var stid = service_data.stid;
post_form(
'/members/service_presence/',
{'mid': mid, 'rid': rid, 'sid': sid, 'stid' : stid},
{'mid': mid, 'rid': rid, 'sid': sid, 'stid' : stid, 'cancel': false, 'type': e.data.type},
function(err, rData) {
if (!err) {
var res = rData.res;
......@@ -480,6 +501,28 @@ function record_service_presence() {
}
}
function cancel_service_presence(mid, rid) {
var d = new Date();
var elapsed_since_last_call = d.getTime() - validation_last_call;
if (elapsed_since_last_call > 1000) {
loading2.show();
validation_last_call = d.getTime();
var sid = selected_service.id;
post_form(
'/members/service_presence/',
{'mid': mid, 'rid': rid, 'sid': sid, 'stid' : 0, 'cancel': true},
function(err) {
if (!err) {
get_service_entry_data();
}
loading2.hide();
}
);
}
}
function fill_rattrapage_2() {
pages.rattrapage_2.find('span.member_name').text(current_displayed_member.name);
var msg = "Bienvenue pour ton rattrapage !";
......@@ -494,13 +537,11 @@ function fill_rattrapage_2() {
msg = "Tu es en désincrit.e ... La situation doit être réglée avez le Bureau des Membres";
} else {
move_service_validation_to(pages.rattrapage_2);
service_validation.find('.btn')
.data('rid', 0)
.data('sid', selected_service.id)
.data('stid', shift_ticket_id)
.data('mid', current_displayed_member.id);
service_data = {
rid : 0,
sid : selected_service.id,
stid : shift_ticket_id,
mid : current_displayed_member.id};
}
pages.rattrapage_2.find('h2').text(msg);
......@@ -641,7 +682,10 @@ $('.btn[data-next]').click(function() {
});
service_validation.on("click", ".btn", record_service_presence);
service_validation.on("click", ".btn", {type:'normal'}, record_service_presence);
associated_service_validation.on("click", "#associated_btn", {type:'associate'}, record_service_presence);
associated_service_validation.on("click", "#partner_btn", {type:'partner'}, record_service_presence);
associated_service_validation.on("click", "#both_btn", {type:'both'}, record_service_presence);
shift_members.on("click", '.btn[data-rid]', function() {
var clicked = $(this);
......@@ -653,6 +697,14 @@ shift_members.on("click", '.btn[data-rid]', function() {
});
shift_members.on("click", '.btn--inverse', function() {
var clicked = $(this);
var rid = clicked.data('rid');
var mid = clicked.data('mid');
cancel_service_presence(mid, rid);
});
pages.shopping_entry.on('css', function() {
photo_advice.hide();
photo_studio.hide();
......
......@@ -283,6 +283,9 @@ def record_service_presence(request):
mid = int(request.POST.get("mid", 0)) # member id
sid = int(request.POST.get("sid", 0)) # shift id
stid = int(request.POST.get("stid", 0)) # shift_ticket_id
cancel = request.POST.get("cancel") == 'true'
typeAction = str(request.POST.get("type"))
app_env = getattr(settings, 'APP_ENV', "prod")
if (rid > -1 and mid > 0):
overrided_date = ""
......@@ -292,28 +295,31 @@ def record_service_presence(request):
if o_date:
overrided_date = re.sub(r'(%20)',' ', o_date.group(1))
# rid = 0 => C'est un rattrapage, sur le service
if sid > 0 and stid > 0:
# Add member to service and take presence into account
res['rattrapage'] = CagetteServices.record_rattrapage(mid, sid, stid)
if res['rattrapage'] is True:
res['update'] = 'ok'
else:
if (CagetteServices.registration_done(rid, overrided_date) is True):
res['update'] = 'ok'
if(not cancel):
# rid = 0 => C'est un rattrapage, sur le service
if sid > 0 and stid > 0:
# Add member to service and take presence into account
res['rattrapage'] = CagetteServices.record_rattrapage(mid, sid, stid, typeAction)
if res['rattrapage'] is True:
res['update'] = 'ok'
else:
res['update'] = 'ko'
if res['update'] == 'ok':
members = CagetteMember.search('id', mid)
m = members[0]
for k in ['image_medium', 'barcode', 'barcode_base']:
del m[k]
next_shift = {}
if len(m['shifts']) > 0:
next_shift = m['shifts'][0]
del m['shifts']
m['next_shift'] = next_shift
res['member'] = m
if (CagetteServices.registration_done(rid, overrided_date, typeAction) is True):
res['update'] = 'ok'
else:
res['update'] = 'ko'
if res['update'] == 'ok':
members = CagetteMember.search('id', mid)
m = members[0]
for k in ['image_medium', 'barcode', 'barcode_base']:
del m[k]
next_shift = {}
if len(m['shifts']) > 0:
next_shift = m['shifts'][0]
del m['shifts']
m['next_shift'] = next_shift
res['member'] = m
else: CagetteServices.reopen_registration(rid, overrided_date)
except Exception as e:
res['error'] = str(e)
return JsonResponse({'res': res})
......
......@@ -64,14 +64,39 @@
}
}
.shift_line_container {
display: flex;
flex-direction: row;
align-items: center;
flex-wrap: wrap;
}
.shift_line_extra_actions {
display: flex;
justify-content: flex-start;
flex-wrap: nowrap;
}
@media screen and (max-width:768px) {
.shift_line_container {
flex-direction: column;
}
.shift_line_extra_actions {
width: 100%;
}
.affect_associate_registered {
margin: 0.5rem 0;
}
}
.selectable_shift_line {
min-width: 325px;
display: flex;
align-items: center;
margin-left: 15px;
margin: 0.75rem 0;
border-radius: 5px;
margin-right: 15px;
}
.selectable_shift_line .checkbox {
......@@ -85,11 +110,23 @@
.affect_associate_registered {
display: flex;
align-items: center;
margin-left: 15px;
margin: 0.75rem 0;
border-radius: 5px;
}
@media screen and (min-width:768px) {
.selectable_shift_line {
margin: 0 15px;
}
.affect_associate_registered {
margin-left: 15px;
}
}
.selectable_shift{
margin: 1rem 0;
}
.delete_registration_button {
justify-content: center;
align-items: center;
......@@ -125,9 +162,9 @@
#can_delete_future_registrations_area {
display: none;
align-self: center;
justify-content: center;
align-items: center;
margin: 0 1rem 1rem 1rem;
padding: 1rem 1.25rem;
}
#can_delete_future_registrations_area button {
......@@ -240,4 +277,14 @@ td{
#calendar_explaination_button {
max-width: 60%;
margin: 2rem auto 0.5rem auto;
}
/* -- Assign shift modal */
.modal_affect_shift_buttons {
margin: 1rem 0;
}
.assign_shift_button {
margin: 0.25rem;
}
\ No newline at end of file
......@@ -331,7 +331,9 @@ function init_shifts_list() {
.attr('id', 'shift_id_'+shift.id);
if (shift.associate_registered==="both") {
shift_line_template.find('.affect_associate_registered').text("Les deux");
shift_line_template.find('.affect_associate_registered').addClass('btn--success');
} else if (shift.associate_registered==="partner") {
shift_line_template.find('.affect_associate_registered').addClass('btn--success');
if (partner_data.associated_partner_id !== "False") {
shift_line_template.find('.affect_associate_registered').text(partner_data.name);
} else {
......@@ -339,6 +341,7 @@ function init_shifts_list() {
}
} else if (shift.associate_registered==="associate") {
shift_line_template.find('.affect_associate_registered').addClass('btn--success');
if (partner_data.associated_partner_id !== "False") {
shift_line_template.find('.affect_associate_registered').text(partner_data.associated_partner_name);
} else {
......@@ -346,6 +349,7 @@ function init_shifts_list() {
}
} else {
shift_line_template.find('.affect_associate_registered').text("A déterminer");
shift_line_template.find('.affect_associate_registered').addClass('btn--danger');
}
}
......@@ -354,13 +358,15 @@ function init_shifts_list() {
if (shift_line_template.find(".delete_registration_button").length === 0) {
let delete_reg_button_template = $("#delete_registration_button_template");
shift_line_template.find(".shift_line_container").append(delete_reg_button_template.html());
shift_line_template.find(".shift_line_extra_actions").append(delete_reg_button_template.html());
}
} else {
shift_line_template.find(".delete_registration_button").remove();
}
$("#shifts_list").append(shift_line_template.html());
shift_line_template.find('.affect_associate_registered').removeClass('btn--danger');
shift_line_template.find('.affect_associate_registered').removeClass('btn--success');
}
$(".selectable_shift_line").on("click", function(e) {
......@@ -470,7 +476,7 @@ function init_calendar_page() {
if (partner_data.extra_shift_done > 0) {
$(".extra_shift_done").text(partner_data.extra_shift_done);
$("#can_delete_future_registrations_area").show();
$("#can_delete_future_registrations_area").css('display', 'flex');
$("#offer_extra_shift").on("click", () => {
openModal(
......
......@@ -7,7 +7,8 @@
.red {color:#FF0000;}
.b_red, .b_less_than_25pc {background:#ff3333 !important;}
.loading {background-image: url("/static/img/ajax-loader.gif"); background-repeat:no-repeat;}
.loading2 {display: none;}
.loading2 {display: none; position:absolute; top:-20px;}
.loading2-container {position:relative;}
body {background: #fff; margin:5px;}
a, a:active, a:focus,
......
......@@ -178,9 +178,23 @@
<section id="service_validation" class="col-6 grid-6 has-gutter">
<div class="col-2"></div>
<a class="col-2 btn present">{{CONFIRME_PRESENT_BTN|safe}}</a>
<span class="loading2"><img width="75" src="/static/img/Pedro_luis_romani_ruiz.gif" alt="Chargement en cours...." /></span>
<div class="col-2"></div>
<div class="col-2 loading2-container">
<span class="loading2"><img width="75" src="/static/img/Pedro_luis_romani_ruiz.gif" alt="Chargement en cours...." /></span>
</div>
</section>
<div id="associated_service_validation">
<p class="col-6 txtcenter">Qui est présent à ce service ?</p>
<section class="col-6 grid-5 has-gutter">
<div class="col-1"></div>
<a id="associated_btn" class=" btn present">Membre</a>
<a id="partner_btn" class=" btn present">Associé</a>
<a id="both_btn" class=" btn present">Les deux</a>
<div class="col-1 loading2-container">
<span class="loading2"><img width="75" src="/static/img/Pedro_luis_romani_ruiz.gif" alt="Chargement en cours...." /></span>
</div>
</section>
</div>
</div>
<div class="col-2"></div>
<a class="btn col-2 return" data-next="service_entry">Retour</a>
......
......@@ -36,14 +36,18 @@
</div>
<div id="selectable_shift_line_template">
<div class="d-flex shift_line_container">
<div class="d-flex shift_line_container selectable_shift">
<div class="selectable_shift_line btn--primary">
<input type="checkbox" class="checkbox">
<div class="selectable_shift_line_text">
<span class="shift_line_date"></span> - <span class="shift_line_time"></span>
</div>
</div>
<div class="affect_associate_registered button--warning"></div>
<div class="shift_line_extra_actions">
<div class="affect_associate_registered">
</div>
</div>
</div>
</div>
......@@ -53,12 +57,14 @@
<div id="modal_affect_shift">
<div>Qui sera présent.e ?</div>
<div id="shift_partner" class="btn--primary">
</div>
<div id="shift_associate" class=" btn--primary">
</div>
<div id="shift_both" class=" btn--primary">
Les deux
<div class="modal_affect_shift_buttons">
<div id="shift_partner" class="btn--primary assign_shift_button">
</div>
<div id="shift_associate" class=" btn--primary assign_shift_button">
</div>
<div id="shift_both" class=" btn--primary assign_shift_button">
Les deux
</div>
</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