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