Commit 76290dbe by Yvon

Merge branch 'dev_cooperatic' into…

Merge branch 'dev_cooperatic' into 3880-3881-explication-ajout-suppression-rattrapage-depuis-gestion-des-rattrapages
parents e097f04a 326486b1
Pipeline #2440 passed with stage
in 1 minute 24 seconds
......@@ -8,7 +8,7 @@ from members.models import CagetteMember
from shifts.models import CagetteServices
from shifts.models import CagetteShift
from outils.common import MConfig
from datetime import datetime
from datetime import datetime, date
default_msettings = {'msg_accueil': {'title': 'Message borne accueil',
'type': 'textarea',
......@@ -415,6 +415,66 @@ def update_members_makeups(request):
response = JsonResponse(res, status=403)
return response
def regenerate_member_delay(request):
""" From BDM admin, close existing extension if exists & recreate for 6 months """
res = {}
is_connected_user = CagetteUser.are_credentials_ok(request)
if is_connected_user is True:
raw_data = json.loads(request.body.decode())
# Close extension if has one
member_id = int(raw_data["member_id"])
cm = CagetteMember(member_id)
cm.close_extension()
# Recreate starting now
cs = CagetteShift()
data = {
"idPartner": member_id,
"start_date": date.today().isoformat()
}
duration = raw_data["duration"]
ext_name = "Délai étendue depuis l'admin BDM"
res["create_delay"] = cs.create_delay(data=data, duration=duration, ext_name=ext_name)
if (res["create_delay"]):
try:
# Add 0 pt to counter so odoo updates member status
data = {
'name': "Forcer l'entrée en délai",
'shift_id': False,
'type': "standard",
'partner_id': member_id,
'point_qty': 0
}
cm.update_member_points(data)
data = {
'name': "Forcer l'entrée en délai",
'shift_id': False,
'type': "ftop",
'partner_id': member_id,
'point_qty': 0
}
cm.update_member_points(data)
res["force_entry_delay"] = True
except Exception as e:
print(str(e))
else:
coop_logger.error("regenerate_member_delay: %s, %s", str(res["create_delay"]), str(data))
return HttpResponseServerError()
res["member_data"] = CagetteMembers.get_makeups_members([member_id])[0]
response = JsonResponse(res, safe=False)
else:
res["message"] = "Unauthorized"
response = JsonResponse(res, status=403)
return response
# --- Gestion des créneaux
......
......@@ -1007,14 +1007,7 @@ class CagetteMember(models.Model):
if changing_shift is False:
# Close extensions if just unsubscribing, else keep it
c = [['partner_id', '=', self.id], ['date_start', '<=', now], ['date_stop', '>=', now]]
f = ['id']
res_ids = self.o_api.search_read("shift.extension", c, f)
ids = [d['id'] for d in res_ids]
if ids:
f = {'date_stop': now}
res["close_extensions"] = self.o_api.update('shift.extension', ids, f)
res["close_extensions"] = self.close_extension()
return res
......@@ -1035,6 +1028,20 @@ class CagetteMember(models.Model):
return res
def close_extension(self):
now = datetime.datetime.now().isoformat()
c = [['partner_id', '=', self.id], ['date_start', '<=', now], ['date_stop', '>=', now]]
f = ['id']
res_ids = self.o_api.search_read("shift.extension", c, f)
ids = [d['id'] for d in res_ids]
if ids:
f = {'date_stop': now}
return self.o_api.update('shift.extension', ids, f)
else:
return False
class CagetteMembers(models.Model):
"""Class to manage operations on all members or part of them."""
......@@ -1257,10 +1264,14 @@ class CagetteMembers(models.Model):
return res
@staticmethod
def get_makeups_members():
def get_makeups_members(ids=[]):
api = OdooAPI()
cond = [['makeups_to_do','>', 0]]
fields = ['id', 'name', 'display_std_points', 'display_ftop_points', 'shift_type', 'makeups_to_do']
if len(ids) > 0:
cond.append(['id','in', ids])
fields = ['id', 'name', 'display_std_points', 'display_ftop_points', 'shift_type', 'makeups_to_do', 'date_delay_stop']
res = api.search_read('res.partner', cond, fields)
return res
......
......@@ -67,4 +67,13 @@
.btn_possible_member {
margin: 0 1rem;
}
.member_name {
font-weight: bold;
}
.title_center {
display: flex;
justify-content: center;
}
\ No newline at end of file
......@@ -56,7 +56,7 @@ function display_makeups_members() {
columns: [
{
data: "id",
title: '',
title: "",
className: "dt-body-center",
orderable: false,
render: function (data) {
......@@ -69,10 +69,29 @@ function display_makeups_members() {
title: "Nom"
},
{
data: "shift_type",
title: "Nb de points",
data: "id",
title: "",
className: "dt-body-center",
orderable: false,
width: "10%",
render: function (data, type, row) {
return `<button class="btn--primary extend_delay_button" data-member-id="${row.id}">Augmenter le délai</button>`;
}
},
{
data: "date_delay_stop",
title: "<div class='title_center'>Limite du délai</div>",
className: "dt-body-center",
width: "10%",
render: function (data) {
return (data === false) ? "Pas de délai en cours" : new Date(data).toLocaleDateString();
}
},
{
data: "shift_type",
title: "<div class='title_center'>Nb de points</div>",
className: "dt-body-center",
width: "5%",
render: function (data, type, row) {
if (data == 'ftop') {
return row.display_ftop_points;
......@@ -85,7 +104,7 @@ function display_makeups_members() {
},
{
data: "makeups_to_do",
title: "Nb rattrapages",
title: "<div class='title_center'>Nb rattrapages</div>",
className: "dt-body-center",
width: "10%",
render: function (data, type, full) {
......@@ -232,6 +251,24 @@ function display_makeups_members() {
.hide();
}
});
$('#makeups_members_table').on('click', 'tbody td .extend_delay_button', function () {
const member_id = this.dataset.memberId;
const member = makeups_members.find(m => m.id == member_id);
let modal = $("#modal_extend_delay_template");
modal.find(".member_name").text(member.name);
openModal(
modal.html(),
() => {
extend_member_delay(member);
},
"Confirmer",
false
);
});
}
/**
......@@ -298,10 +335,57 @@ function update_members_makeups(member_ids, action, description) {
if (typeof data.responseJSON != 'undefined' && typeof data.responseJSON.error != 'undefined') {
err.msg += ' : ' + data.responseJSON.error;
}
report_JS_error(err, 'members_admin');
report_JS_error(err, 'members_admin-manage_makeups');
closeModal();
alert('Erreur serveur pour décrémenter les rattrapages. Veuillez contacer le service informatique.');
}
});
}
/**
* Send request to extend the member's delay, or create one if none open.
* @param {Object} member
*/
function extend_member_delay(member) {
openModal();
let today = new Date();
let today_plus_six_month = new Date();
today_plus_six_month.setMonth(today_plus_six_month.getMonth()+6);
const diff_time = Math.abs(today_plus_six_month - today);
const diff_days = Math.ceil(diff_time / (1000 * 60 * 60 * 24));
let data = {
member_id: member.id,
duration: diff_days
};
$.ajax({
type: 'POST',
url: "/members/admin/regenerate_member_delay",
data: JSON.stringify(data),
dataType:"json",
traditional: true,
contentType: "application/json; charset=utf-8",
success: function(result) {
let i = makeups_members.findIndex(m => m.id == result.member_data.id);
makeups_members[i].date_delay_stop = result.member_data.date_delay_stop;
display_makeups_members();
closeModal();
},
error: function(data) {
err = {msg: "erreur serveur pour créer un délai", ctx: 'extend_member_delay'};
if (typeof data.responseJSON != 'undefined' && typeof data.responseJSON.error != 'undefined') {
err.msg += ' : ' + data.responseJSON.error;
}
report_JS_error(err, 'members_admin-manage_makeups');
closeModal();
alert('Erreur serveur pour décrémenter les rattrapages. Ré-essayez plus tard.');
alert('Erreur serveur pour créer un délai. Veuillez contacer le service informatique.');
}
});
}
......
......@@ -188,39 +188,39 @@ function set_subscription_area() {
retrieve_and_draw_shift_tempates({shift_listener: false});
$("#shifts_calendar_area").show();
// Cancel listeners from subscription page & set custom listeners
$(document).off("click", "#shifts_calendar_area button[data-select='Volant']");
$(document).on("click", "#shifts_calendar_area button[data-select='Volant']", function() {
// Subscribe to comitee/ftop shift
msg = (has_committe_shift === "True")
? `Inscrire ${selected_member.name} au service des Comités ?`
: `Inscrire ${selected_member.name} en Volant ?`;
openModal(
msg,
() => {
shift_subscrition(2);
},
"Confirmer",
false
);
});
$(document).off("click", ".shift");
$(document).on("click", ".shift", function() {
// Subscribe to shift template
let shift_template_id = select_shift_among_compact(null, this, false); // method from common.js
let shift_template_data = shift_templates[shift_template_id].data;// shift_templates: var from common.js
let shift_template_name = get_shift_name(shift_template_data);
openModal(
`Inscrire ${selected_member.name} au créneau ${shift_template_name} ?`,
() => {
shift_subscrition(1, parseInt(shift_template_id), shift_template_name);
},
"Confirmer",
false
);
});
// Cancel listeners from subscription page & set custom listeners
$(document).off("click", "#shifts_calendar_area button[data-select='Volant']");
$(document).on("click", "#shifts_calendar_area button[data-select='Volant']", function() {
// Subscribe to comitee/ftop shift
msg = (has_committe_shift === "True")
? `Inscrire ${selected_member.name} au service des Comités ?`
: `Inscrire ${selected_member.name} en Volant ?`;
openModal(
msg,
() => {
shift_subscrition(2);
},
"Confirmer",
false
);
});
$(document).off("click", ".shift");
$(document).on("click", ".shift", function() {
// Subscribe to shift template
let shift_template_id = select_shift_among_compact(null, this, false); // method from common.js
let shift_template_data = shift_templates[shift_template_id].data;// shift_templates: var from common.js
let shift_template_name = get_shift_name(shift_template_data);
openModal(
`Inscrire ${selected_member.name} au créneau ${shift_template_name} ?`,
() => {
shift_subscrition(1, parseInt(shift_template_id), shift_template_name);
},
"Confirmer",
false
);
});
}
......
......@@ -127,7 +127,7 @@ function create_new_coop() {
$('.chosen_associate_area').hide();
$('.member_choice').removeClass('choice_active');
$(".remove_binome_icon").on("click", hide_chosen_associate);
$('input[name="binome"]').prop('checked',false);
$('input[name="binome"]').prop('checked', false);
local_in_process = getLocalInProcess();
if (getLocalInProcess().length > 0) {
empty_waiting_local_processes();
......@@ -270,7 +270,7 @@ function store_new_coop(event) {
}
if ($('#associate_area').is(':visible')) {
// If user choose yes for binome, a type of association must be selected
// If user choose yes for binome, a type of association must be selected
let associated_data_selected = false;
if (
......
......@@ -66,6 +66,7 @@ urlpatterns = [
url(r'^delete_shift_template_registration$', admin.delete_shift_template_registration),
url(r'^shift_subscription$', admin.shift_subscription),
url(r'^admin/manage_attached$', admin.manage_attached),
url(r'^admin/regenerate_member_delay$', admin.regenerate_member_delay),
url(r'^admin/manage_attached/create_pair$', admin.create_pair),
url(r'^admin/manage_attached/delete_pair$', admin.delete_pair),
url(r'^get_makeups_members$', admin.get_makeups_members),
......
......@@ -350,3 +350,11 @@ body {
.attached-unblocked {
display: none;
}
.block_service_exchange {
display: none;
}
.free_service_exchange {
display: none;
}
\ No newline at end of file
......@@ -18,6 +18,7 @@ function init_faq() {
$(".ask_bdm_form_link").prop("href", request_form_link);
display_messages_for_attached_people();
display_messages_for_service_exchange_24h_before();
}
$(document).on('click', "#shift_exchange_btn", () => {
......@@ -46,3 +47,5 @@ function display_messages_for_attached_people() {
$(".attached-blocked").show();
}
}
......@@ -157,4 +157,6 @@ function init_home() {
load_partner_shifts(partner_data.concerned_partner_id)
.then(init_my_shifts_tile);
}
display_messages_for_service_exchange_24h_before();
}
\ No newline at end of file
......@@ -355,3 +355,11 @@ $(document).ready(function() {
};
})(jQuery, 'smartresize');
function display_messages_for_service_exchange_24h_before() {
if (block_service_exchange_24h_before === "False") {
$(".free_service_exchange").show();
} else {
$(".block_service_exchange").show();
}
}
......@@ -31,6 +31,7 @@ def index(request, exception=None):
'COMPANY_LOGO': getattr(settings, 'COMPANY_LOGO', None),
'block_actions_for_attached_people' : getattr(settings, 'BLOCK_ACTIONS_FOR_ATTACHED_PEOPLE', True),
'permanent_message': getattr(settings, 'PERMANENT_MESSAGE_BELOW_CONNECTION_FIELDS', None),
'block_service_exchange_24h_before' : getattr(settings, 'BLOCK_SERVICE_EXCHANGE_24H_BEFORE', True),
}
template = loader.get_template('members_space/index.html')
......
......@@ -1085,6 +1085,7 @@ function set_supplier_shortage(row, product, from_processed = false) {
product.old_qty = product.product_qty;
}
product.product_qty = 0;
product.package_qty = 0;
// Step 2: for consistency purposes, updated products need these fields to be set
} else {
if (!from_processed) {
......
......@@ -1230,52 +1230,6 @@ function init() {
$(this).off('wheel.disableScroll');
});
// client-side validation of numeric inputs, optionally replacing separator sign(s).
$("input.number").on("keydown", function (e) {
// allow function keys and decimal separators
if (
// backspace, delete, tab, escape, enter, comma and .
$.inArray(e.keyCode, [
46,
8,
9,
27,
13,
110,
188,
190
]) !== -1 ||
// Ctrl/cmd+A, Ctrl/cmd+C, Ctrl/cmd+X
($.inArray(e.keyCode, [
65,
67,
88
]) !== -1 && (e.ctrlKey === true || e.metaKey === true)) ||
// home, end, left, right
(e.keyCode >= 35 && e.keyCode <= 39)) {
/*
// optional: replace commas with dots in real-time (for en-US locals)
if (e.keyCode === 188) {
e.preventDefault();
$(this).val($(this).val() + ".");
}
// optional: replace decimal points (num pad) and dots with commas in real-time (for EU locals)
if (e.keyCode === 110 || e.keyCode === 190) {
e.preventDefault();
$(this).val($(this).val() + ",");
}
*/
return;
}
// block any non-number
if ((e.shiftKey || (e.keyCode < 48 || e.keyCode > 57)) && (e.keyCode < 96 || e.keyCode > 105)) {
e.preventDefault();
}
});
// Manual and textual input
$('#search_input').keypress(function(e) {
if (e.which >= 48 && e.which <= 57) { // figures [0-9]
......
......@@ -318,7 +318,7 @@ class CagetteShift(models.Model):
coop_logger.error("Reopen shift : %s", str(e))
return response
def create_delay(self, data, duration=28):
def create_delay(self, data, duration=28, ext_name="Extension créée depuis l'espace membre"):
"""
Create a delay for a member.
If no duration is specified, a delay is by default 28 days from the given start_date.
......@@ -327,14 +327,16 @@ class CagetteShift(models.Model):
Else, create a 28 days delay.
Args:
idPartner: int
start_date: string date at iso format (eg. "2019-11-19")
Date from which the delay end date is calculated
(optionnal) extension_beginning: string date at iso format
If specified, will be the actual starting date of the extension.
Should be inferior than start_date.
(at creation only: odoo ignores delays if today's not inside)
data
idPartner: int
start_date: string date at iso format (eg. "2019-11-19")
Date from which the delay end date is calculated
(optionnal) extension_beginning: string date at iso format
If specified, will be the actual starting date of the extension.
Should be inferior than start_date.
(at creation only: odoo ignores delays if today's not inside)
duration: nb of days
ext_name: will be displayed in odoo extensions list
"""
action = 'create'
......@@ -392,7 +394,7 @@ class CagetteShift(models.Model):
"type_id": ext_type_id,
"date_start": starting_date.isoformat(),
"date_stop": ending_date.isoformat(),
"name": "Extension créée depuis l'espace membre"
"name": ext_name
}
response = self.o_api.create('shift.extension', fields)
......
......@@ -54,23 +54,31 @@
</div>
</div>
</div>
<div id="templates" style="display:none;">
<div id="modal_incr_makeup_counter">
<p>Ajouter un rattrapage à <span class="member_name"></span> ?</p>
<br><label for="incr-explanation">Explication : </label><input class="" type="text" id="incr-explanation">
<br><br><label for="incr-signature">Signature : </label><input class="" type="text" id="incr-signature">
</div>
<div id="modal_decr_makeup_counter">
<p>Enlever un rattrapage à <span class="member_name"></span> ?</p>
<br><label for="decr-explanation">Explication : </label><input class="" type="text" id="decr-explanation">
<br><br><label for="decr-signature">Signature : </label><input class="" type="text" id="decr-signature">
</div>
<div id="modal_decr_selected_makeup_counter">
<p>Enlever un rattrapage aux membres sélectionnés ?</p>
<br><label for="decr-explanation-selected">Explication : </label><input class="" type="text" id="decr-explanation-selected">
<br><br><label for="decr-signature-selected">Signature : </label><input class="" type="text" id="decr-signature-selected">
</div>
<div id="modal_extend_delay_template">
<p>
Vous vous apprêtez à rallonger le délai de
<span class="member_name"></span>
pour une durée de 6 mois à partir d'aujourd'hui.
</p>
</div>
<div id="modal_incr_makeup_counter">
<p>Ajouter un rattrapage à <span class="member_name"></span> ?</p>
<br><label for="incr-explanation">Explication : </label><input class="" type="text" id="incr-explanation">
<br><br><label for="incr-signature">Signature : </label><input class="" type="text" id="incr-signature">
</div>
<div id="modal_decr_makeup_counter">
<p>Enlever un rattrapage à <span class="member_name"></span> ?</p>
<br><label for="decr-explanation">Explication : </label><input class="" type="text" id="decr-explanation">
<br><br><label for="decr-signature">Signature : </label><input class="" type="text" id="decr-signature">
</div>
<div id="modal_decr_selected_makeup_counter">
<p>Enlever un rattrapage aux membres sélectionnés ?</p>
<br><label for="decr-explanation-selected">Explication : </label><input class="" type="text" id="decr-explanation-selected">
<br><br><label for="decr-signature-selected">Signature : </label><input class="" type="text" id="decr-signature-selected">
</div>
</div>
</div>
......
......@@ -488,18 +488,21 @@
</div>
</div>
<button type="button" class="accordion btn_faq">
<span class="full_width" >009 Faire une autre demande au BDM: seulement si les autres formulaires ne correspondent pas à ma demande </span>
<span class="full_width" >009 Faire une autre demande au BDM : seulement si les autres formulaires ne correspondent pas à ma demande </span>
</button>
<div class="input-container panel">
<div class="grp_text">
<br>
Nous avons créé des formulaires spécifiques pour la plupart des problèmes rencontrés par les membres. Changer de créneau, créer un binôme, ajouter un produit à la gamme, partir en vacances... <br />
Cela dit, nous en découvrons de nouveaux tous les jours.<br />
Si tu n'as pas su quel formulaire remplir, tu es au bon endroit. <br />
Vas-y dit nous tout !<br /><br />
Attention : si tu souhaites contacter le BDM pour prévenir que tu seras absent-e à ton service cela ne sert à rien! Il te faut déplacer ton service via ton espace membre. Il n'est cependant pas possible d'échanger un service qui commence dans moins de 24h pour des raisons de logistiques. Si tu ne peux pas venir tu seras donc comptabilisé-e absent-e. Tu basculeras en statut "Rattrapage" et ne pourras plus faire tes courses. Il te faudra sélectionner dans ton espace membre un rattrapage à faire dans les 6 prochains mois pour basculer en statut "Délai" et pouvoir faire de nouveau tes courses.<br />
Merci de ne pas contacter le Bureau des membres pour cela, il te donnera exactement la même réponse.<br />
<div>
Nous avons créé des formulaires spécifiques pour la plupart des problèmes rencontrés par les membres. Changer de créneau, créer un binôme, ajouter un produit à la gamme, partir en vacances... <br />
Cela dit, nous en découvrons de nouveaux tous les jours.<br />
Si tu n'as pas su quel formulaire remplir, tu es au bon endroit. <br />
Vas-y dit nous tout !<br /><br />
</div>
<div class="block_service_exchange">
Attention : si tu souhaites contacter le BDM pour prévenir que tu seras absent-e à ton service cela ne sert à rien ! Il te faut déplacer ton service via ton espace membre. Il n'est cependant pas possible d'échanger un service qui commence dans moins de 24h pour des raisons de logistiques. Si tu ne peux pas venir tu seras donc comptabilisé-e absent-e. Tu basculeras en statut "Rattrapage" et ne pourras plus faire tes courses. Il te faudra sélectionner dans ton espace membre un rattrapage à faire dans les 6 prochains mois pour basculer en statut "Délai" et pouvoir faire de nouveau tes courses.<br />
Merci de ne pas contacter le Bureau des membres pour cela, il te donnera exactement la même réponse.<br />
</div>
<div class="faq_link_button_area">
<a
href="javascript:void(0);"
......
......@@ -70,9 +70,12 @@
Échange de services
</div>
<div class="tile_content">
<div>
<div class="block_service_exchange">
Un empêchement ? J'anticipe et déplace mes services jusqu'à 24h avant leur début !
</div>
<div class="free_service_exchange">
Un empêchement ? J'anticipe et déplace mon service le plus tôt possible !
</div>
<div class="home_link_button_area">
<button type="button" class="btn--primary home_link_button" id="go_to_shifts_calendar">
Accéder au calendrier d'échange de services
......
......@@ -154,6 +154,7 @@
"extra_shift_done": parseInt("{{partnerData.extra_shift_done}}", 10)
};
var block_actions_for_attached_people = '{{block_actions_for_attached_people}}';
var block_service_exchange_24h_before = '{{block_service_exchange_24h_before}}';
const canAddShift = {{canAddShift}};
</script>
<script src="{% static "js/all_common.js" %}?v=1651853225"></script>
......
......@@ -59,7 +59,7 @@
</div>
<div class="col-3 center">
<label for="edition_input" id="edition_input_label">Qté : </label>
<input type="text" class="number input_small" id="edition_input" autocomplete="off" required>
<input type="number" class="input_small" id="edition_input" autocomplete="off" required>
<span id="product_uom"></span>
<i class="fa fa-undo" id="reset_to_previous_qty" style="display:none;"></i>
</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