Skip to content
Projects
Groups
Snippets
Help
This project
Loading...
Sign in / Register
Toggle navigation
T
third-party
Overview
Overview
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
2
Merge Requests
2
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
cooperatic-foodcoops
third-party
Commits
4decb4d2
Commit
4decb4d2
authored
Jan 22, 2025
by
Yvon Kerdoncuff
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
7351 and 7339 : huge rework of shift_subscription and unsubscribe_member methods
parent
be395be8
Pipeline
#4077
failed with stage
Changes
7
Pipelines
1
Show whitespace changes
Inline
Side-by-side
Showing
7 changed files
with
121 additions
and
120 deletions
+121
-120
admin.py
members/admin.py
+58
-61
exceptions.py
members/exceptions.py
+3
-0
models.py
members/models.py
+45
-40
manage_regular_shifts.js
members/static/js/admin/manage_regular_shifts.js
+6
-6
members-space-home.js
members_space/static/js/members-space-home.js
+4
-5
manage_regular_shifts.html
templates/members/admin/manage_regular_shifts.html
+3
-5
home.html
templates/members_space/supercoop/home.html
+2
-3
No files found.
members/admin.py
View file @
4decb4d2
...
...
@@ -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"
]
)
# 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"
]
)
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
)
# 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
...
...
members/exceptions.py
0 → 100644
View file @
4decb4d2
class
MembersAppException
(
Exception
):
"""Exception personnalisée pour l'app members."""
pass
members/models.py
View file @
4decb4d2
...
...
@@ -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
):
""" G
iven a shift template, check if the member is registered to a makeup on this
shift template """
try
:
def
get_makeup_registrations_ids_on
_shift_template
(
self
,
shift_template_id
):
""" G
et the makeup registrations that are on a
shift template """
makeup_reg_ids
=
[]
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
)
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
if
res_shift_ids
:
shift_ids
=
[
int
(
d
[
'shift_id'
][
0
])
for
d
in
res_shift_ids
]
c
=
[[
"id"
,
"in"
,
shift_ids
]]
f
=
[
'shift_template_id'
]
stis
=
self
.
o_api
.
search_read
(
"shift.shift"
,
c
,
f
)
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'
]
for
sti
in
stis
:
if
sti
[
'shift_template_id'
][
0
]
==
shift_template_id
:
return
True
except
Exception
as
e
:
print
(
str
(
e
))
return
False
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
()]
)
def
unsubscribe_member
(
self
,
changing_shift
=
False
):
""" If changing_shift, don't delete makeups registrations & don't close extension """
res
=
{}
now
=
datetime
.
datetime
.
now
()
.
isoformat
()
def
unsubscribe_member
(
self
):
return
self
.
o_api
.
execute
(
'shift.template.registration'
,
'unlink'
,
[
self
.
get_shift_template_registration_id
()]
)
# 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
:
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
)
if
changing_shift
is
False
:
# Close extensions if just unsubscribing, else keep it
res
[
"close_extensions"
]
=
self
.
close_extension
()
# 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
...
...
members/static/js/admin/manage_regular_shifts.js
View file @
4decb4d2
...
...
@@ -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
...
...
members_space/static/js/members-space-home.js
View file @
4decb4d2
...
...
@@ -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
(),
...
...
templates/members/admin/manage_regular_shifts.html
View file @
4decb4d2
...
...
@@ -64,7 +64,7 @@
</div>
</div>
</div>
</div>
</div>
<div
id=
"shifts_calendar_area"
>
{% include "members/shift_template_choice.html" %}
...
...
@@ -78,15 +78,13 @@
<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"
>
...
...
templates/members_space/supercoop/home.html
View file @
4decb4d2
...
...
@@ -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}}"
,
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment