Commit 4decb4d2 by Yvon Kerdoncuff

7351 and 7339 : huge rework of shift_subscription and unsubscribe_member methods

parent be395be8
Pipeline #4077 failed with stage
......@@ -11,6 +11,7 @@ from members_space.models import CagetteMembersSpace
from outils.common import MConfig
from datetime import datetime, date
import shifts.fonctions
from .exceptions import MembersAppException
default_msettings = {'msg_accueil': {'title': 'Message borne accueil',
'type': 'textarea',
......@@ -594,7 +595,7 @@ def shift_subscription(request):
"""
Register a member to a shift template.
If the member was already subscribed to a shift template, unsubscribe him.her first
and delete all existing shifts EXCEPT makeups.
and delete all existing shifts EXCEPT SOME makeups (the ones that we can keep).
"""
res = {}
data = json.loads(request.body.decode())
......@@ -606,58 +607,37 @@ def shift_subscription(request):
is_allowed = True
if is_allowed is True:
api = OdooAPI()
partner_id = int(data["partner_id"])
shift_type = data["shift_type"]
moving_from_std_to_ftop = False
if shift_type == 1:
# 1 = standard
shift_template_id = int(data["shift_template_id"])
elif shift_type == 2:
# 2 = ftop
# First try to get committees shift
shift_template_id = CagetteServices.get_committees_shift_id()
# If None, no committees shift, get the first ftop shift
if shift_template_id is None:
shift_template_id = CagetteServices.get_first_ftop_shift_id()
c = [['id', '=', partner_id]]
f = ['shift_type']
moving_from_std_to_ftop = api.search_read('res.partner', c, f)[0]['shift_type'] == 'standard'
else:
# 3 = exempté
# Get exemptions shift
shift_template_id = CagetteServices.get_exemptions_shift_id()
m = CagetteMember(partner_id)
unsubscribe_first = data["unsubscribe_first"]
if unsubscribe_first is True:
# If the member is registered to a shift on the shift template, registering to this shift template will fail.
has_makeups_in_new_shift = m.is_member_registered_to_makeup_shift_template(shift_template_id)
if has_makeups_in_new_shift is True:
return JsonResponse(
{
"message": "A makeup is registered on this shift template",
"code": "makeup_found"
},
status=409
try:
curated_data = analyse_shift_subscription_request(api, data, partner_id)
except MembersAppException as e:
return JsonResponse({"message": str(e)}, status=409)
if curated_data["unsubscribe_first"]:
if res["moving_from_standard_to_ftop"]:
# Hard unsubscribe (unselecting all makeups)
m.unsubscribe_member()
else:
# Unselect makeups on target shift_template
# (they would prevent new subscription)
api.execute(
'shift.registration',
'unselect',
curated_data["makeups_reg_on_target_shift_template"]
)
changing_shift = not moving_from_std_to_ftop
res["unsubscribe_member"] = m.unsubscribe_member(changing_shift)
if moving_from_std_to_ftop:
lower_makeup_count_to_zero_if_moving_from_std_to_ftop(partner_id, res)
reg_id = m.create_coop_shift_subscription(shift_template_id, shift_type)
# Perform soft unsubscribe that only unselect
# makeups of shift_template to cancel (and
# not makeups that are not linked to it)
m.unsubscribe_member_but_exogenous_makeups()
reg_id = m.create_coop_shift_subscription(
curated_data["target_shift_template_id"],
curated_data["shift_type"]
)
# Return necessary data
if reg_id is not None:
c = [['id', '=', shift_template_id]]
c = [['id', '=', curated_data["target_shift_template_id"]]]
f = ['id', 'name']
res["shift_template"] = api.search_read('shift.template', c, f)[0]
c = [['id', '=', partner_id]]
f = ['cooperative_state']
res["cooperative_state"] = api.search_read('res.partner', c, f)[0]['cooperative_state']
......@@ -667,25 +647,42 @@ def shift_subscription(request):
response = JsonResponse({"message": "Subscription failed"}, status=500)
else:
response = JsonResponse({"message": "Unauthorized"}, status=403)
return response
def lower_makeup_count_to_zero_if_moving_from_std_to_ftop(partner_id, res):
cs = CagetteShift()
def analyse_shift_subscription_request(api, data, partner_id):
cm = CagetteMember(partner_id)
members_data = []
members_data.append({
'member_id': partner_id,
'member_shift_type': 'standard',
'target_makeups_nb': 0,
'description': 'reset automatique du compteur rattrapages suite changement créneau standard vers non standard',
'points_diff': cs.get_member_makeups_to_do(cm.id)
})
res["res"] = []
update_members_makeups_core(members_data, res)
if res["res"][0]["update"]:
res["makeups_to_do"] = 0
cs = CagetteServices()
res = {}
shift_type = data["shift_type"]
res["moving_from_std_to_ftop"] = False
if shift_type == 1:
res["target_shift_type"] = "standard"
shift_template_id = int(data["shift_template_id"])
elif shift_type == 2:
res["target_shift_type"] = "ftop"
# First try to get committees shift
shift_template_id = cs.get_committees_shift_id()
# If None, no committees shift, get the first ftop shift
if shift_template_id is None:
shift_template_id = cs.get_first_ftop_shift_id()
c = [['id', '=', partner_id]]
f = ['shift_type']
res["moving_from_std_to_ftop"] = api.search_read('res.partner', c, f)[0]['shift_type'] == 'standard'
else:
raise MembersAppException("Le service cible n'est ni standard ni ftop."
"L'exemption via un service spécial n'est plus supportée par l'application.")
res["target_shift_template_id"] = shift_template_id
# Make sure unsubscribe_first data sent by js is still consistent with bdd
if data["unsubscribe_first"] == cm.has_state_unsubscribed_gone_or_associated():
raise MembersAppException("Les informations affichées sont périmées."
"Veuillez recharger la page avant de poursuivre.")
if data["unsubscribe_first"]:
res["makeups_reg_on_target_shift_template"] = cm.get_makeup_registrations_ids_on_shift_template(
res["target_shift_template_id"]
)
res["unsubscribe_first"] = data["unsubscribe_first"]
return res
# --- Gestion des binômes
......
class MembersAppException(Exception):
"""Exception personnalisée pour l'app members."""
pass
......@@ -1073,57 +1073,62 @@ class CagetteMember(models.Model):
res = self.o_api.search_read("shift.registration", c, f)
return res
def is_member_registered_to_makeup_shift_template(self, shift_template_id):
""" Given a shift template, check if the member is registered to a makeup on this shift template """
try:
c = [["partner_id", "=", self.id], ["is_makeup", "=", True], ["state", "=", "open"]]
f=['shift_id']
res_shift_ids = self.o_api.search_read("shift.registration", c, f)
if res_shift_ids:
shift_ids = [int(d['shift_id'][0]) for d in res_shift_ids]
def get_makeup_registrations_ids_on_shift_template(self, shift_template_id):
""" Get the makeup registrations that are on a shift template """
makeup_reg_ids = []
c = [["partner_id", "=", self.id], ["is_makeup", "=", True], ["state", "=", "open"]]
f = ['id', 'shift_id']
res_shift_ids = self.o_api.search_read("shift.registration", c, f)
for shift_reg in res_shift_ids:
c = [["id", "=", int(shift_reg['shift_id'][0])]]
f = ['shift_template_id']
shift = self.o_api.search_read("shift.shift", c, f)[0]
if shift['shift_template_id'][0] == shift_template_id:
makeup_reg_ids.append(shift_reg["id"])
return makeup_reg_ids
def get_shift_template_registration_id(self):
c = [['partner_id', '=', self.id]]
f = ['id']
return self.o_api.search_read("shift.template.registration", c, f)[0]['id']
c = [["id", "in", shift_ids]]
f=['shift_template_id']
stis = self.o_api.search_read("shift.shift", c, f)
for sti in stis:
if sti['shift_template_id'][0] == shift_template_id:
return True
except Exception as e:
print(str(e))
def unsubscribe_member_but_exogenous_makeups(self):
return self.o_api.execute(
'shift.template.registration',
'unlink_but_exogenous_makeups',
[self.get_shift_template_registration_id()]
)
return False
def unsubscribe_member(self, changing_shift = False):
""" If changing_shift, don't delete makeups registrations & don't close extension """
res = {}
def unsubscribe_member(self):
return self.o_api.execute(
'shift.template.registration',
'unlink',
[self.get_shift_template_registration_id()]
)
now = datetime.datetime.now().isoformat()
# Get and then delete shift template registration
c = [['partner_id', '=', self.id]]
f = ['id']
res_ids = self.o_api.search_read("shift.template.registration", c, f)
ids = [d['id'] for d in res_ids]
if ids:
res["delete_shift_template_reg"] = self.o_api.execute('shift.template.registration', 'unlink', ids)
# Get and then delete shift registrations
c = [['partner_id', '=', self.id], ['date_begin', '>', now]]
if changing_shift is True:
c.append(['is_makeup', '!=', True])
f = ['id']
res_ids = self.o_api.search_read("shift.registration", c, f)
ids = [d['id'] for d in res_ids]
if ids:
res["delete_shifts_reg"] = self.o_api.execute('shift.registration', 'unlink', ids)
if changing_shift is False:
# Close extensions if just unsubscribing, else keep it
res["close_extensions"] = self.close_extension()
def unselect_makeup_registrations(self, ids):
# Il faut d'abord traiter le shift_registration,
# soit en le supprimant (comme le fait unsubscribe_member)
# soit le marquant cancel (comme le fait delete_shift_registration)
# Attention, en l'état, la première solution ne permet pas d'indiquer
# la raison de l'opération. On opte pourtant pour cette solution ici.
res = {}
res["delete_shifts_reg"] = self.o_api.execute('shift.registration', 'unlink', ids)
# Odoo gère bien l'ajout d'un point consécutif à cette opération quand il s'agit d'un rattrapage.
# Il faut maintenant corriger cette situation en retirant un point,
# (qui va conduire odoo à ajouter un rattrapage)
fields = {
'name': "Admin BDM (déchoisissement de rattrapage par une annulation de présence) - " + cancellation_description,
'shift_id': False,
'type': data["member_shift_type"],
'partner_id': member_id,
'point_qty': 1
}
res["update_counter"] = m.update_counter_event(fields)
return res
......
......@@ -111,16 +111,16 @@ function shift_subscrition(shift_type, shift_template_id = null, shift_template_
if (
err_data.status == 409
&& typeof (err_data.responseJSON) != "undefined"
&& err_data.responseJSON.code === "makeup_found"
) {
let modal_template = $("#modal_error_change_shift_template");
modal_template.find(".shift_template_name").text(shift_template_name);
let modal_template = $("#modal_generic_error_change_shift_template");
modal_template.find(".modal_generic_error_change_shift_template_text").text(
err_data.responseJSON.message
);
closeModal();
openModal(
modal_template.html(),
() => {},
() => {
},
"Compris !",
true,
false
......
......@@ -73,12 +73,11 @@ function process_asked_shift_template_change(shift_t_id) {
if (
err_data.status == 409
&& typeof (err_data.responseJSON) != "undefined"
&& err_data.responseJSON.code === "makeup_found"
) {
let modal_template = $("#modal_error_change_shift_template");
modal_template.find(".shift_template_name").text(shift_template_name);
let modal_template = $("#modal_generic_error_change_shift_template");
modal_template.find(".modal_generic_error_change_shift_template_text").text(
err_data.responseJSON.message
);
closeModal();
openModal(
modal_template.html(),
......
......@@ -62,10 +62,10 @@
Réinscrire à un créneau
</button>
</div>
</div>
</div>
</div>
</div>
<div id="shifts_calendar_area">
{% include "members/shift_template_choice.html" %}
</div>
......@@ -78,16 +78,14 @@
<label for="permanent_unsuscribe">Désinscription définitive</label>
</div>
</div>
<div id="modal_error_change_shift_template">
<div id="modal_generic_error_change_shift_template">
<h3 class="error_modal_title">Action impossible</h3>
<p>
Le ou la membre est inscrit.e à un rattrapage sur le créneau choisi (<span class="shift_template_name"></span>), cela empêche de l'inscrire sur ce créneau.
<span class="modal_generic_error_change_shift_template_text"></span>
</p>
<p>Vous pouvez essayer de l'inscrire sur ce créneau une autre semaine.</p>
</div>
</div>
</div>
<script src="{% static "js/pouchdb.min.js" %}"></script>
<script type="text/javascript">
var type = 2;
......
......@@ -134,12 +134,11 @@
{% include "members/shift_template_calendar.html" %}
</div>
</div>
<div id="modal_error_change_shift_template" style="display:none;">
<div id="modal_generic_error_change_shift_template" style="display:none;">
<h3 class="error_modal_title">Action impossible</h3>
<p>
Il y a un rattrapage sur le créneau choisi (<span class="shift_template_name"></span>), cela empêche de s'inscrire sur ce créneau.
<span class="modal_generic_error_change_shift_template_text"></span>
</p>
<p>Vous pouvez essayer ce créneau une autre semaine.</p>
</div>
<script>
var max_begin_hour = "{{max_begin_hour}}",
......
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