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
e5bff7b4
Commit
e5bff7b4
authored
Jan 20, 2025
by
Yvon Kerdoncuff
Browse files
Options
Browse Files
Download
Plain Diff
Merge branch 'migration-v12' into refonte_espace_membre_sc
parents
550ea71e
3277594d
Pipeline
#4065
canceled with stage
Changes
6
Pipelines
2
Hide whitespace changes
Inline
Side-by-side
Showing
6 changed files
with
244 additions
and
229 deletions
+244
-229
admin.py
members/admin.py
+118
-89
models.py
members/models.py
+34
-36
views.py
members_space/views.py
+1
-1
fonctions.py
shifts/fonctions.py
+46
-3
models.py
shifts/models.py
+40
-92
views.py
shifts/views.py
+5
-8
No files found.
members/admin.py
View file @
e5bff7b4
...
...
@@ -10,6 +10,7 @@ from shifts.models import CagetteShift
from
members_space.models
import
CagetteMembersSpace
from
outils.common
import
MConfig
from
datetime
import
datetime
,
date
import
shifts.fonctions
default_msettings
=
{
'msg_accueil'
:
{
'title'
:
'Message borne accueil'
,
'type'
:
'textarea'
,
...
...
@@ -394,6 +395,38 @@ def update_members_makeups(request):
if
is_connected_user
is
True
:
members_data
=
json
.
loads
(
request
.
body
.
decode
())
# Perform checks and compute some data in a loop on members.
cs
=
CagetteShift
()
api
=
OdooAPI
()
unsubscription_limit
=
api
.
get_system_param
(
'lacagette_membership.points_limit_to_get_unsubscribed'
)
error
=
[]
for
member_data
in
members_data
:
cm
=
CagetteMember
(
int
(
member_data
[
"member_id"
]))
target_makeups_nb
=
int
(
member_data
[
"target_makeups_nb"
])
if
target_makeups_nb
<
0
:
# Prevent setting a negative number of makeups_to_do https://redmine.coopdev.fr/issues/6090
# This could happen when bdm has two screens open and clicks on minus btn on a coop line
# with exactly 1 makeup_to_do on both screens
error
[
"error"
]
=
"L'opération de rattrapage a été annulée car le nombre de rattrapage cible est négatif."
return
JsonResponse
(
error
,
status
=
400
)
makeup_change_count
=
target_makeups_nb
-
cs
.
get_member_makeups_to_do
(
cm
.
id
)
points_target
=
cm
.
get_member_points
(
"standard"
)
-
makeup_change_count
if
points_target
<=
unsubscription_limit
:
error
[
"error"
]
\
=
"L'ajout de rattrapage a été annulé car il provoquerait la désinscription d'un membre."
return
JsonResponse
(
error
,
status
=
400
)
res_exempted
=
shifts
.
fonctions
.
get_exempted_ids_from
(
api
,
[
member_data
[
"member_id"
]])
if
res_exempted
:
error
[
"error"
]
=
"L'opération de rattrapage a été annulée car le membre ciblé est exempté."
return
JsonResponse
(
error
,
status
=
400
)
if
cm
.
has_state_unsubscribed_gone_or_associated
():
error
[
"error"
]
=
(
"L'opération de rattrapage a été annulée car le membre ciblé est désinscrit, parti ou"
"associé."
)
return
JsonResponse
(
error
,
status
=
400
)
# Save computed data in member_data. It will be useful to update makeups and points.
members_data
[
member_data
[
"member_id"
]][
"points_diff"
]
=
-
makeup_change_count
# Update makeups and points
res
[
"res"
]
=
[]
update_members_makeups_core
(
members_data
,
res
)
response
=
JsonResponse
(
res
)
...
...
@@ -407,50 +440,21 @@ def update_members_makeups_core(members_data, res):
for
member_data
in
members_data
:
cm
=
CagetteMember
(
int
(
member_data
[
"member_id"
]))
res
[
"res"
]
.
append
(
cm
.
update_member_makeups
(
member_data
))
# Update member standard points, for standard members only
if
member_data
[
"member_shift_type"
]
==
"standard"
:
# Set points to minus the number of makeups to do + the makeups to come (limited to -2)
cs
=
CagetteShift
()
[
shift_data
,
is_ftop
]
=
cs
.
get_shift_partner
(
int
(
member_data
[
"member_id"
]))
target_points
=
-
int
(
member_data
[
"target_makeups_nb"
])
-
sum
(
1
for
value
in
shift_data
if
value
[
'is_makeup'
])
if
(
target_points
<
-
2
):
target_points
=
-
2
member_points
=
cm
.
get_member_points
(
"standard"
)
points_diff
=
abs
(
member_points
-
target_points
)
# Don't update if no change
if
points_diff
==
0
:
res
[
"res"
][
-
1
][
'standard_points'
]
=
member_points
continue
if
member_points
>
target_points
:
points_update
=
-
points_diff
else
:
points_update
=
points_diff
data
=
{
'name'
:
"Admin BDM - "
+
member_data
[
"description"
],
'shift_id'
:
False
,
'type'
:
member_data
[
"member_shift_type"
],
'partner_id'
:
int
(
member_data
[
"member_id"
]),
'point_qty'
:
points_update
}
# If points are added, we need to manage makeups count change here,
# otherwise this is handled automatically by odoo when points are changed
if
member_data
[
"points_diff"
]
>
0
:
res
[
"res"
]
.
append
(
cm
.
update_member_makeups
(
member_data
))
cm
.
update_member_points
(
data
)
#There are some odoo process happening here that could change the actual number of points
#so we want to fetch it again to send it back
res
[
"res"
][
-
1
][
'standard_points'
]
=
cm
.
get_member_points
(
"standard"
)
# Better to call run_process_target_status now, otherwise partner remains
# in alert until routine is called (every 5 minutes). It is a bit weird for users and
# allocation of rattrapages before the routine is executed will not trigger change to delay state !
# (the parner would have to go back to espace membre and click on "j'affecte mes rattrapage"
# even though it shows 'J'ai 0 rattrapages à effecter' for the delay state change to be eventually triggered)
api
=
OdooAPI
()
api
.
execute
(
'res.partner'
,
'run_process_target_status'
,
[])
data
=
{
'name'
:
"Admin BDM - "
+
member_data
[
"description"
],
'shift_id'
:
False
,
'type'
:
member_data
[
"member_shift_type"
],
'partner_id'
:
int
(
member_data
[
"member_id"
]),
'point_qty'
:
member_data
[
'points_diff'
]
}
cm
.
update_member_points
(
data
)
res
[
"res"
][
-
1
][
'standard_points'
]
=
cm
.
get_member_points
(
"standard"
)
def
regenerate_member_delay
(
request
):
""" From BDM admin, close existing extension if exists & recreate for 6 months """
...
...
@@ -554,23 +558,15 @@ def delete_shift_template_registration(request):
try
:
data
=
json
.
loads
(
request
.
body
.
decode
())
partner_id
=
int
(
data
[
"partner_id"
])
shift_template_id
=
int
(
data
[
"shift_template_id"
])
makeups_to_do
=
int
(
data
[
"makeups_to_do"
])
permanent_unsuscribe
=
data
[
"permanent_unsuscribe"
]
cm
=
CagetteMember
(
partner_id
)
# Get partner nb of future makeup shifts
partner_makeups
=
cm
.
get_member_selected_makeups
()
target_makeup
=
makeups_to_do
+
len
(
partner_makeups
)
if
target_makeup
>
2
:
target_makeup
=
2
# Update partner makeups to do
res
[
"update_makeups"
]
=
cm
.
update_member_makeups
({
'target_makeups_nb'
:
target_makeup
})
# Knowing that the total number of makeups will always be 2 or less,
# old code here would only increment the number of makeups...
# which is not needed as makeup increment is now handled
# by odoo.
# Delete all shift registrations & shift template registration
cm
=
CagetteMember
(
partner_id
)
res
[
"unsubscribe_member"
]
=
cm
.
unsubscribe_member
()
if
permanent_unsuscribe
is
True
:
...
...
@@ -578,10 +574,12 @@ def delete_shift_template_registration(request):
if
res
[
"set_done"
]:
""" Delete pair(s?) of partner if it is a parent to improve statistics (#4810) """
api
=
OdooAPI
()
associated_members
=
api
.
search_read
(
'res.partner'
,
[[
'parent_id'
,
'='
,
partner_id
]],
[
'id'
])
associated_members
=
api
.
search_read
(
'res.partner'
,
[[
'parent_id'
,
'='
,
partner_id
]],
[
'id'
,
'suppleant_member_id'
])
for
am
in
associated_members
:
data
=
{
"child"
:
{
"id"
:
am
[
"id"
]},
"gone"
:
[
"parent"
,
"child"
]}
delete_pair_core
(
data
)
# Do not call delete_pair_core if contact is not a binom
if
am
[
'suppleant_member_id'
]:
data
=
{
"child"
:
{
"id"
:
am
[
"id"
]},
"gone"
:
[
"parent"
,
"child"
]}
delete_pair_core
(
data
)
except
Exception
as
e
:
res
[
"error"
]
=
str
(
e
)
...
...
@@ -674,12 +672,15 @@ def shift_subscription(request):
def
lower_makeup_count_to_zero_if_moving_from_std_to_ftop
(
partner_id
,
res
):
cs
=
CagetteShift
()
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'
'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
)
...
...
@@ -707,6 +708,7 @@ def get_member_info(request, id):
'current_template_name'
,
'shift_type'
,
'parent_id'
,
'suppleant_member_id'
,
'is_associated_people'
,
'parent_name'
,
"makeups_to_do"
,
...
...
@@ -716,8 +718,9 @@ def get_member_info(request, id):
member
=
api
.
search_read
(
'res.partner'
,
cond
,
fields
)
if
member
:
member
=
member
[
0
]
parent
=
None
if
member
[
'parent_id'
]:
if
not
member
[
'suppleant_member_id'
]:
return
JsonResponse
({
"message"
:
"Accès non supporté (rattaché non suppléant)."
},
status
=
404
)
res_parent
=
api
.
search_read
(
'res.partner'
,
[[
'id'
,
'='
,
int
(
member
[
'parent_id'
][
0
])]],
[
'barcode_base'
,
'email'
])
if
res_parent
:
parent
=
res_parent
[
0
]
...
...
@@ -780,6 +783,7 @@ def create_pair(request):
"nb_associated_people"
,
"current_template_name"
,
"parent_id"
,
"suppleant_member_id"
,
"is_associated_people"
,
"makeups_to_do"
,
"final_standard_points"
,
...
...
@@ -795,28 +799,33 @@ def create_pair(request):
"final_standard_points"
,
"final_ftop_points"
,
'shift_type'
'parent_id'
])[
0
]
'parent_id'
,
'suppleant_member_id'
])[
0
]
case
=
isPartnerInvolvedInBinom
(
api
,
child
)
errors
=
[]
if
child
[
'nb_associated_people'
]
>
0
:
# le membre est déjà titulaire d'un binôme
errors
.
append
(
"Le membre suppléant sélectionné est titulaire d'un bînome"
)
if
case
==
"MEMBER_SUPPLEANT_OF_BINOM"
:
errors
.
append
(
"Le suppléant sélectionné est déjà suppléant d'un binôme."
)
elif
case
==
"CONTACT_OF_MEMBER_SUPPLEANT_OF_BINOM"
:
errors
.
append
(
"Le suppléant sélectionné est déjà (le contact d'un membre) suppléant d'un binôme."
)
elif
case
==
"TITULAIRE_OF_BINOM"
:
errors
.
append
(
"Le suppléant sélectionné est déjà titulaire d'un binôme."
)
# le membre suppléant fait parti du commité?
if
child
[
'current_template_name'
]
==
"Services des comités"
:
errors
.
append
(
"Le membre suppléant séléctionné fait parti du comité"
)
# Verifier que le suppléant n'est pas déjà en binôme soit titulaire soit suppléant
for
m
in
api
.
search_read
(
'res.partner'
,
[[
'email'
,
'='
,
child
[
'email'
]]]):
if
m
[
'is_associated_people'
]:
errors
.
append
(
'Le membre suppléant est déjà en bînome'
)
if
m
[
'child_ids'
]:
errors
.
append
(
"Le membre suppléant sélectionné est titulaire d'un binôme"
)
# le membre titulaire a déjà un/des suppléants?
if
parent
[
'nb_associated_people'
]
>=
1
:
# On récupère le/s suppléant(s)
associated_members
=
api
.
search_read
(
'res.partner'
,
[[
'parent_id'
,
'='
,
parent_id
]],
[
'id'
,
'age'
])
# le suppléant est un mineur?
for
m
in
associated_members
:
if
m
[
'age'
]
>
18
:
errors
.
append
(
"Le membre titulaire sélectionné a déjà un suppléant"
)
case
=
isPartnerInvolvedInBinom
(
api
,
parent
)
errors
=
[]
if
case
==
"MEMBER_SUPPLEANT_OF_BINOM"
:
errors
.
append
(
"Le titulaire sélectionné est déjà suppléant d'un binôme."
)
elif
case
==
"CONTACT_OF_MEMBER_SUPPLEANT_OF_BINOM"
:
errors
.
append
(
"Le titulaire sélectionné est déjà (le contact d'un membre) suppléant d'un binôme."
)
elif
case
==
"TITULAIRE_OF_BINOM"
:
errors
.
append
(
"Le titulaire sélectionné est déjà titulaire d'un binôme."
)
if
errors
:
return
JsonResponse
({
"errors"
:
errors
},
status
=
409
)
...
...
@@ -829,6 +838,8 @@ def create_pair(request):
child
[
field
]
=
False
child
[
'is_associated_people'
]
=
True
child
[
'parent_id'
]
=
parent
[
'id'
]
#Link the newly created attached suppleant contact and the suppleant member
child
[
'suppleant_member_id'
]
=
child_id
# Following lines are useful if parent or child is unsubscribed
if
not
'shift_type'
in
parent
:
parent
[
'shift_type'
]
=
'standard'
...
...
@@ -922,6 +933,27 @@ def create_pair(request):
return
JsonResponse
({
"message"
:
"Method Not Allowed"
},
status
=
405
)
def
isPartnerInvolvedInBinom
(
api
,
partner
):
# First make sure the selected partner "is not already a suppleant"
# Let's be prudent : cover both case of partner being suppleant member,
# and case of partner being the contact of a suppleant member
contact_of_partner_suppleant
=
api
.
search_read
(
'res.partner'
,
[[
'suppleant_member_id'
,
'='
,
partner
[
'id'
]]])
if
contact_of_partner_suppleant
:
# partner has a suppleant contact therefore it is a suppleant member
return
"MEMBER_SUPPLEANT_OF_BINOM"
if
partner
[
'parent_id'
]
and
partner
[
'suppleant_member_id'
]:
# partner is the contact of a suppleant member
return
"CONTACT_OF_MEMBER_SUPPLEANT_OF_BINOM"
# Second make sure the selected partner is not a titulaire
children_of_partner
=
api
.
search_read
(
'res.partner'
,
[[
'parent_id'
,
'='
,
partner
[
'id'
]]])
suppleant_of_partner
=
[
x
for
x
in
children_of_partner
if
x
[
'suppleant_member_id'
]]
if
suppleant_of_partner
:
# partner is titulaire
return
"TITULAIRE_OF_BINOM"
return
None
def
delete_pair
(
request
):
"""
Administration des binômes membres
...
...
@@ -972,17 +1004,14 @@ def delete_pair_core(data):
}
"""
api
=
OdooAPI
()
child_id
=
int
(
data
[
'child'
][
'id'
])
child
=
api
.
search_read
(
'res.partner'
,
[[
'id'
,
'='
,
child_id
]],
[
'email'
,
'id'
,
'parent_id'
])[
0
]
child_accounts
=
api
.
search_read
(
'res.partner'
,
[[
'email'
,
'='
,
child
[
'email'
]]],
[
'id'
,
'email'
])
prev_child
=
[
x
[
'id'
]
for
x
in
child_accounts
if
x
[
'id'
]
!=
child_id
]
parent
=
api
.
search_read
(
'res.partner'
,
[[
'id'
,
'='
,
child
[
'parent_id'
][
0
]]],
[
'cooperative_state'
])[
0
]
api
.
update
(
'res.partner'
,
[
child_id
],
{
"parent_id"
:
False
,
"is_associated_people"
:
False
,
"active"
:
False
,
"is_former_associated_people"
:
True
})
child_update_fields
=
{
'cooperative_state'
:
"unsubscribed"
,
"is_former_associated_people"
:
True
}
child_contact_id
=
int
(
data
[
'child'
][
'id'
])
child_contact
=
api
.
search_read
(
'res.partner'
,
[[
'id'
,
'='
,
child_contact_id
]],
[
'email'
,
'id'
,
'parent_id'
,
'suppleant_member_id'
])[
0
]
parent
=
api
.
search_read
(
'res.partner'
,
[[
'id'
,
'='
,
child_contact
[
'parent_id'
][
0
]]],
[
'cooperative_state'
])[
0
]
api
.
update
(
'res.partner'
,
[
child_contact_id
],
{
"parent_id"
:
False
,
"is_associated_people"
:
False
,
"active"
:
False
,
"is_former_associated_people"
:
True
,
"suppleant_member_id"
:
None
})
child_member_update_fields
=
{
'cooperative_state'
:
"unsubscribed"
,
"is_former_associated_people"
:
True
}
if
'gone'
in
data
and
'child'
in
data
[
'gone'
]:
child_update_fields
[
'cooperative_state'
]
=
"gone"
for
id
in
prev_child
:
api
.
update
(
"res.partner"
,
[
id
],
child_update_fields
)
child_member_update_fields
[
'cooperative_state'
]
=
"gone"
api
.
update
(
"res.partner"
,
[
child_contact
[
'suppleant_member_id'
]],
child_member_update_fields
)
if
'gone'
in
data
and
'parent'
in
data
[
'gone'
]:
api
.
update
(
"res.partner"
,
[
parent
[
'id'
]],
{
'cooperative_state'
:
"gone"
,
"is_former_associated_people"
:
True
})
members/models.py
View file @
e5bff7b4
...
...
@@ -8,6 +8,7 @@ from outils.common import CouchDB
from
outils.common
import
Verification
from
products.models
import
OFF
from
envelops.models
import
CagetteEnvelops
import
shifts.fonctions
import
sys
import
pytz
...
...
@@ -203,6 +204,7 @@ class CagetteMember(models.Model):
if
getattr
(
settings
,
'ALLOW_NON_MEMBER_TO_CONNECT'
,
False
)
is
False
:
cond
.
append
(
'|'
)
cond
.
append
([
'is_member'
,
'='
,
True
])
# TODO : consider replacing is_associated_people by suppleant_member_id to exclude mineurs rattachés
cond
.
append
([
'is_associated_people'
,
'='
,
True
])
fields
=
[
'name'
,
'email'
,
'birthdate_date'
,
'create_date'
,
'cooperative_state'
,
'is_associated_people'
,
'barcode_base'
]
...
...
@@ -212,6 +214,7 @@ class CagetteMember(models.Model):
if
(
res
and
len
(
res
)
>=
1
):
coop_id
=
None
hashed_password
=
None
# TODO : add comment to explain why there is a loop here
for
item
in
res
:
coop
=
item
if
'hashed_password'
in
item
:
...
...
@@ -219,6 +222,7 @@ class CagetteMember(models.Model):
if
item
[
"birthdate_date"
]
is
not
False
:
coop_birthdate
=
item
[
'birthdate_date'
]
coop_state
=
item
[
'cooperative_state'
]
# TODO : consider replacing is_associated_people check by suppleant_member_id to exclude mineurs rattachés
if
item
[
"is_associated_people"
]
==
True
:
coop_id
=
item
[
'id'
]
...
...
@@ -460,18 +464,12 @@ class CagetteMember(models.Model):
def
is_associated
(
id_parent
):
api
=
OdooAPI
()
cond
=
[[
'parent_id'
,
'='
,
int
(
id_parent
)]]
fields
=
[
'id'
,
'name'
,
'parent_id'
,
'birthdate_date'
]
fields
=
[
'id'
,
'name'
,
'parent_id'
,
'birthdate_date'
,
'suppleant_member_id'
]
res
=
api
.
search_read
(
'res.partner'
,
cond
,
fields
,
10
,
0
,
'id DESC'
)
already_have_adult_associated
=
False
for
partner
in
res
:
birthdate
=
partner
[
'birthdate_date'
]
if
(
birthdate
):
today
=
date
.
today
()
date1
=
datetime
.
datetime
.
strptime
(
birthdate
,
"
%
Y-
%
m-
%
d"
)
age
=
today
.
year
-
date1
.
year
-
((
today
.
month
,
today
.
day
)
<
(
date1
.
month
,
date1
.
day
))
if
age
>
17
:
already_have_adult_associated
=
True
return
already_have_adult_associated
if
partner
[
'suppleant_member_id'
]:
return
True
return
False
@staticmethod
def
finalize_coop_creation
(
post_data
):
...
...
@@ -657,7 +655,8 @@ class CagetteMember(models.Model):
'city'
:
post_data
[
'city'
],
'phone'
:
format_phone_number
(
post_data
[
'mobile'
]),
# Because list view default show Phone and people mainly gives mobile
'barcode_rule_id'
:
settings
.
ASSOCIATE_BARCODE_RULE_ID
,
'parent_id'
:
post_data
[
'parent_id'
],
'parent_id'
:
post_data
[
'parent_id'
],
'suppleant_member_id'
:
partner_id
,
'is_associated_people'
:
True
,
'function'
:
function
}
...
...
@@ -901,6 +900,7 @@ class CagetteMember(models.Model):
cond
=
[[
'name'
,
'ilike'
,
str
(
key
)]]
cond
.
append
(
'|'
)
cond
.
append
([
'is_member'
,
'='
,
True
])
#TODO : replace is_associated_people check by suppleant_member_id check to exclude mineurs rattachés
if
search_type
!=
'members'
and
search_type
!=
'envelops'
:
cond
.
append
([
'is_associated_people'
,
'='
,
True
])
else
:
...
...
@@ -953,7 +953,7 @@ class CagetteMember(models.Model):
fields
=
fields
+
[
'shift_type'
,
'makeups_to_do'
,
'display_ftop_points'
,
'display_std_points'
,
'shift_type'
]
cond
.
append
([
'shift_type'
,
'='
,
'standard'
])
res
=
api
.
search_read
(
'res.partner'
,
cond
,
fields
)
CagetteMembers
.
add_makeups_to_come_to_member_data
(
res
)
CagetteMembers
.
add_makeups_to_come_to_member_data
(
api
,
res
)
return
res
elif
search_type
==
"shift_template_data"
:
fields
=
CagetteMember
.
m_short_default_fields
...
...
@@ -1044,25 +1044,19 @@ class CagetteMember(models.Model):
res
=
{}
c
=
[[
"parent_id"
,
"="
,
self
.
id
]]
f
=
[
"id"
,
"name"
,
"barcode_base"
]
f
=
[
"id"
,
"name"
,
"barcode_base"
,
'suppleant_member_id'
]
res
=
self
.
o_api
.
search_read
(
'res.partner'
,
c
,
f
)
try
:
return
res
[
0
]
except
:
return
None
for
partner
in
res
:
if
partner
[
'suppleant_member_id'
]:
return
partner
return
None
def
update_member_makeups
(
self
,
member_data
):
api
=
OdooAPI
()
res
=
{}
# Prevent setting a negative number of makeups_to_do
# https://redmine.coopdev.fr/issues/6090
# This could happen when bdm has two screens open and clicks on minus btn on a coop line
# with exactly 1 makeup_to_do on both screens
makeups_to_do
=
max
(
0
,
int
(
member_data
[
"target_makeups_nb"
]))
f
=
{
'makeups_to_do'
:
makeups_to_do
}
makeups_to_do
=
int
(
member_data
[
"target_makeups_nb"
])
f
=
{
'makeups_to_do'
:
makeups_to_do
}
res_item
=
api
.
update
(
'res.partner'
,
[
self
.
id
],
f
)
res
=
{
'mid'
:
self
.
id
,
...
...
@@ -1164,6 +1158,12 @@ class CagetteMember(models.Model):
else
:
return
False
def
has_state_unsubscribed_gone_or_associated
(
self
):
c
=
[[
'id'
,
'='
,
self
.
id
]]
f
=
[
'cooperative_state'
]
state
=
self
.
o_api
.
search_read
(
"res.partner"
,
c
,
f
)[
0
][
"cooperative_state"
]
return
state
in
(
"unsubscribed"
,
"gone"
,
"associated"
)
class
CagetteMembers
(
models
.
Model
):
"""Class to manage operations on all members or part of them."""
...
...
@@ -1400,8 +1400,7 @@ class CagetteMembers(models.Model):
# 1 : fetching members with no makeups to do but with some makeups to come
# 2 : providing makeups to come to all members
cs
=
CagetteShift
()
makeups_to_come_per_partner
=
cs
.
get_partners_with_makeups_to_come
()
makeups_to_come_per_partner
=
shifts
.
fonctions
.
get_partners_with_makeups_to_come
(
api
)
# 1 : fetching members with no makeups to do but with some makeups to come
cond
=
[[
'makeups_to_do'
,
'='
,
0
],
[
'id'
,
'in'
,
list
(
makeups_to_come_per_partner
.
keys
())]]
...
...
@@ -1421,20 +1420,20 @@ class CagetteMembers(models.Model):
return
res
@staticmethod
def
add_makeups_to_come_to_member_data
(
res
):
def
add_makeups_to_come_to_member_data
(
api
,
res
):
if
res
:
cs
=
CagetteShift
()
for
idx
,
partner
in
enumerate
(
res
):
[
shift_data
,
is_ftop
]
=
cs
.
get_shift_partner
(
int
(
partner
[
'id'
]))
[
shift_data
,
is_ftop
]
=
shifts
.
fonctions
.
get_shift_partner
(
api
,
int
(
partner
[
'id'
]))
res
[
idx
][
'makeups_to_come'
]
=
sum
(
1
for
value
in
shift_data
if
value
[
'is_makeup'
])
@staticmethod
def
get_attached_members
():
api
=
OdooAPI
()
cond
=
[[
'is_associated_people'
,
'='
,
True
]]
fields
=
[
'id'
,
'name'
,
'parent_name'
]
cond
=
[[
'is_associated_people'
,
'='
,
True
]]
fields
=
[
'id'
,
'name'
,
'parent_name'
,
'suppleant_member_id'
]
res
=
api
.
search_read
(
'res.partner'
,
cond
,
fields
)
return
res
# Exclude mineurs rattachés
return
[
x
for
x
in
res
if
res
[
'suppleant_member_id'
]]
class
CagetteUser
(
models
.
Model
):
...
...
@@ -1524,6 +1523,4 @@ class CagetteUser(models.Model):
except
Exception
as
e
:
res
[
'error'
]
=
str
(
e
)
return
res
from
shifts.models
import
CagetteShift
return
res
\ No newline at end of file
members_space/views.py
View file @
e5bff7b4
...
...
@@ -218,7 +218,7 @@ def home(request):
if
partnerData
[
'cooperative_state'
]
==
"unsubscribed"
:
coop_can_change_shift_template
=
False
if
getattr
(
settings
,
'ASSOCIATE_PEOPLE_CAN_CHANGE_SHIFT_TEMPLE_REGISTRATION'
,
False
)
is
False
:
if
partnerData
[
'
is_associated_people'
]
is
True
:
if
partnerData
[
'
suppleant_member_id'
]
:
coop_can_change_shift_template
=
False
context
=
{
'title'
:
'Espace Membres'
,
...
...
shifts/fonctions.py
View file @
e5bff7b4
import
datetime
,
pytz
tz
=
pytz
.
timezone
(
"Europe/Paris"
)
def
dateIsoUTC
(
myDate
):
tz
=
pytz
.
timezone
(
"Europe/Paris"
)
tDate
=
tz
.
localize
(
datetime
.
datetime
.
strptime
(
myDate
,
'
%
Y-
%
m-
%
d
%
H:
%
M:
%
S'
))
return
dDate
.
isoformat
()
return
tDate
.
isoformat
()
def
get_partners_with_makeups_to_come
(
api
):
"""Returns a dictionary with : keys = the partners ids having at least one makeup to come ; values = #makeups_to_come"""
fields
=
[
'partner_id'
]
cond
=
[[
'state'
,
'='
,
'open'
],
[
'date_begin'
,
'>'
,
datetime
.
datetime
.
now
()
.
isoformat
()],
[
'is_makeup'
,
'='
,
True
]]
shift_data
=
api
.
search_read
(
'shift.registration'
,
cond
,
fields
)
count_dic
=
{}
for
value
in
shift_data
:
if
value
[
'partner_id'
][
0
]
in
count_dic
:
count_dic
[
value
[
'partner_id'
][
0
]]
=
count_dic
[
value
[
'partner_id'
][
0
]]
+
1
else
:
count_dic
[
value
[
'partner_id'
][
0
]]
=
1
return
count_dic
def
get_shift_partner
(
api
,
id
,
start_date
=
None
,
end_date
=
None
):
"""Récupère les shift du membre"""
shifts
=
[]
is_ftop
=
False
not_before
=
datetime
.
datetime
.
now
()
.
isoformat
()
if
start_date
:
not_before
=
start_date
.
isoformat
()
fields
=
[
'date_begin'
,
'date_end'
,
'shift_id'
,
'shift_type'
,
'partner_id'
,
"id"
,
"associate_registered"
,
"is_makeup"
]
# res.partner
cond
=
[[
'partner_id.id'
,
'='
,
id
],
[
'state'
,
'='
,
'open'
],
[
'date_begin'
,
'>'
,
not_before
]]
if
end_date
:
cond
.
append
([
'date_begin'
,
'<'
,
end_date
.
isoformat
()])
shiftData
=
api
.
search_read
(
'shift.registration'
,
cond
,
fields
,
order
=
"date_begin ASC"
)
for
s
in
shiftData
:
if
not
(
'Equipe volante'
in
s
[
'shift_id'
][
1
]):
shifts
.
append
(
s
)
else
:
is_ftop
=
True
return
[
shifts
,
is_ftop
]
def
get_exempted_ids_from
(
api
,
partner_ids
):
cond
=
[[
'id'
,
'in'
,
partner_ids
],
[
'cooperative_state'
,
'in'
,
[
'exempted'
]]]
fields
=
[
'id'
]
return
api
.
search_read
(
'res.partner'
,
cond
,
fields
)
\ No newline at end of file
shifts/models.py
View file @
e5bff7b4
...
...
@@ -5,6 +5,7 @@ from outils.common import OdooAPI
from
outils.common
import
Verification
from
members.models
import
CagetteMember
from
members.models
import
CagetteUser
import
shifts.fonctions
from
pytz
import
timezone
...
...
@@ -58,7 +59,7 @@ class CagetteShift(models.Model):
try
:
now
=
datetime
.
datetime
.
now
(
tz
)
# Have to retrive shifts (from now to a cycle period forward to check rules respect)
[
shift_registrations
,
is_ftop
]
=
s
elf
.
get_shift_partner
(
partner_id
,
now
+
datetime
.
timedelta
(
weeks
=
4
))
[
shift_registrations
,
is_ftop
]
=
s
hifts
.
fonctions
.
get_shift_partner
(
self
.
o_api
,
partner_id
,
now
+
datetime
.
timedelta
(
weeks
=
4
))
new_shift
=
self
.
get_shift
(
idNewShift
)
# WARNING : use date_begin_tz while shift_registrations use date_begin (UTC)
if
"successive_shifts_allowed"
in
rules
:
min_duration
=
getattr
(
settings
,
'MIN_SHIFT_DURATION'
,
2
)
...
...
@@ -76,7 +77,7 @@ class CagetteShift(models.Model):
if
'start_date'
in
cw
:
sd
=
cw
[
'start_date'
]
ed
=
cw
[
'start_date'
]
+
datetime
.
timedelta
(
weeks
=
4
)
[
cycle_shift_regs
,
is_ftop
]
=
s
elf
.
get_shift_partner
(
partner_id
,
start_date
=
sd
,
end_date
=
ed
)
[
cycle_shift_regs
,
is_ftop
]
=
s
hifts
.
fonctions
.
get_shift_partner
(
self
.
o_api
,
partner_id
,
start_date
=
sd
,
end_date
=
ed
)
if
len
(
cycle_shift_regs
)
>=
int
(
rules
[
'max_shifts_per_cycle'
]):
answer
=
False
coop_logger
.
info
(
"services max par cycle atteint pour partner_id
%
s"
,
str
(
partner_id
))
...
...
@@ -127,7 +128,7 @@ class CagetteShift(models.Model):
try
:
now
=
datetime
.
datetime
.
now
(
tz
)
# Have to retrive shifts (from now to a cycle period forward to check rules respect)
[
shift_registrations
,
is_ftop
]
=
s
elf
.
get_shift_partner
(
partner_id
,
now
+
datetime
.
timedelta
(
weeks
=
4
))
[
shift_registrations
,
is_ftop
]
=
s
hifts
.
fonctions
.
get_shift_partner
(
self
.
o_api
,
partner_id
,
now
+
datetime
.
timedelta
(
weeks
=
4
))
new_shift
=
self
.
get_shift
(
idNewShift
)
# WARNING : use date_begin_tz while shift_registrations use date_begin (UTC)
if
"successive_shifts_allowed"
in
rules
:
min_duration
=
getattr
(
settings
,
'MIN_SHIFT_DURATION'
,
2
)
...
...
@@ -145,7 +146,7 @@ class CagetteShift(models.Model):
if
'start_date'
in
cw
:
sd
=
cw
[
'start_date'
]
ed
=
cw
[
'start_date'
]
+
datetime
.
timedelta
(
weeks
=
4
)
[
cycle_shift_regs
,
is_ftop
]
=
s
elf
.
get_shift_partner
(
partner_id
,
start_date
=
sd
,
end_date
=
ed
)
[
cycle_shift_regs
,
is_ftop
]
=
s
hifts
.
fonctions
.
get_shift_partner
(
self
.
o_api
,
partner_id
,
start_date
=
sd
,
end_date
=
ed
)
if
len
(
cycle_shift_regs
)
>=
int
(
rules
[
'max_shifts_per_cycle'
]):
answer
=
False
coop_logger
.
info
(
"services max par cycle atteint pour partner_id
%
s"
,
str
(
partner_id
))
...
...
@@ -181,11 +182,11 @@ class CagetteShift(models.Model):
'cooperative_state'
,
'final_standard_point'
,
'create_date'
,
'final_ftop_point'
,
'shift_type'
,
'leave_ids'
,
'makeups_to_do'
,
'barcode_base'
,
'street'
,
'street2'
,
'zip'
,
'city'
,
'mobile'
,
'phone'
,
'function'
,
'email'
,
'is_associated_people'
,
'parent_id'
,
'extra_shift_done'
]
'is_associated_people'
,
'parent_id'
,
'
suppleant_member_id'
,
'
extra_shift_done'
]
partnerData
=
self
.
o_api
.
search_read
(
'res.partner'
,
cond
,
fields
,
1
)
if
partnerData
:
partnerData
=
partnerData
[
0
]
if
partnerData
[
'
is_associated_people
'
]:
if
partnerData
[
'
suppleant_member_id
'
]:
cond
=
[[
'id'
,
'='
,
partnerData
[
'parent_id'
][
0
]]]
fields
=
[
'create_date'
,
'makeups_to_do'
,
'date_delay_stop'
,
'extra_shift_done'
]
parentData
=
self
.
o_api
.
search_read
(
'res.partner'
,
cond
,
fields
,
1
)
...
...
@@ -198,14 +199,7 @@ class CagetteShift(models.Model):
if
partnerData
[
'shift_type'
]
==
'standard'
:
partnerData
[
'in_ftop_team'
]
=
False
# Because 'in_ftop_team' doesn't seem to be reset to False in Odoo
else
:
if
partnerData
[
'final_ftop_point'
]
<
0
and
partnerData
[
'makeups_to_do'
]
==
0
and
partnerData
[
'cooperative_state'
]
==
"suspended"
:
partnerData
[
'makeups_to_do'
]
=
int
(
abs
(
partnerData
[
'final_ftop_point'
]))
try
:
self
.
o_api
.
update
(
'res.partner'
,
[
id
],
{
'makeups_to_do'
:
partnerData
[
'makeups_to_do'
]})
except
Exception
as
e
:
coop_logger
.
error
(
"update res.partner.makeups_to_do
%
s"
,
str
(
e
))
if
partnerData
[
'is_associated_people'
]:
if
partnerData
[
'suppleant_member_id'
]:
cond
=
[[
'partner_id.id'
,
'='
,
partnerData
[
'parent_id'
][
0
]]]
else
:
cond
=
[[
'partner_id.id'
,
'='
,
id
]]
...
...
@@ -243,39 +237,6 @@ class CagetteShift(models.Model):
return
partnerData
def
get_shift_partner
(
self
,
id
,
start_date
=
None
,
end_date
=
None
):
"""Récupère les shift du membre"""
shifts
=
[]
is_ftop
=
False
not_before
=
datetime
.
datetime
.
now
()
.
isoformat
()
if
start_date
:
not_before
=
start_date
.
isoformat
()
fields
=
[
'date_begin'
,
'date_end'
,
'shift_id'
,
'shift_type'
,
'partner_id'
,
"id"
,
"associate_registered"
,
"is_makeup"
]
# res.partner
cond
=
[[
'partner_id.id'
,
'='
,
id
],[
'state'
,
'='
,
'open'
],
[
'date_begin'
,
'>'
,
not_before
]]
if
end_date
:
cond
.
append
([
'date_begin'
,
'<'
,
end_date
.
isoformat
()])
shiftData
=
self
.
o_api
.
search_read
(
'shift.registration'
,
cond
,
fields
,
order
=
"date_begin ASC"
)
for
s
in
shiftData
:
if
not
(
'Equipe volante'
in
s
[
'shift_id'
][
1
]):
shifts
.
append
(
s
)
else
:
is_ftop
=
True
return
[
shifts
,
is_ftop
]
def
get_partners_with_makeups_to_come
(
self
):
"""Returns a dictionary with : keys = the partners ids having at least one makeup to come ; values = #makeups_to_come"""
fields
=
[
'partner_id'
]
cond
=
[[
'state'
,
'='
,
'open'
],
[
'date_begin'
,
'>'
,
datetime
.
datetime
.
now
()
.
isoformat
()],
[
'is_makeup'
,
'='
,
True
]]
shift_data
=
self
.
o_api
.
search_read
(
'shift.registration'
,
cond
,
fields
)
count_dic
=
{}
for
value
in
shift_data
:
if
value
[
'partner_id'
][
0
]
in
count_dic
:
count_dic
[
value
[
'partner_id'
][
0
]]
=
count_dic
[
value
[
'partner_id'
][
0
]]
+
1
else
:
count_dic
[
value
[
'partner_id'
][
0
]]
=
1
return
count_dic
def
shift_is_makeup
(
self
,
id
):
"""vérifie si une shift est un rattrapage"""
...
...
@@ -284,7 +245,6 @@ class CagetteShift(models.Model):
shiftData
=
self
.
o_api
.
search_read
(
'shift.registration'
,
cond
,
fields
)
return
shiftData
[
0
][
"is_makeup"
]
def
get_shift_calendar
(
self
,
is_ftop
,
start
,
end
):
"""Récupère les shifts à partir de maintenant pour le calendier"""
...
...
@@ -366,10 +326,10 @@ class CagetteShift(models.Model):
# partner_id can be 'associated_people' one, which is never use as shift partner_id reference
# So, let's first retrieved data about the res.partner involved
cond
=
[[
'id'
,
'='
,
int
(
data
[
'idPartner'
])]]
fields
=
[
'parent_id'
]
fields
=
[
'parent_id'
,
'suppleant_member_id'
]
partner
=
self
.
o_api
.
search_read
(
'res.partner'
,
cond
,
fields
,
1
)
if
partner
:
if
partner
[
0
][
'
parent
_id'
]:
if
partner
[
0
][
'
suppleant_member
_id'
]:
partner_id
=
partner
[
0
][
'parent_id'
][
0
]
else
:
partner_id
=
int
(
data
[
'idPartner'
])
...
...
@@ -690,8 +650,9 @@ class CagetteServices(models.Model):
for
m
in
s
[
'members'
]:
mids
.
append
(
m
[
'partner_id'
][
0
])
cond
=
[[
'parent_id'
,
'in'
,
mids
]]
fields
=
[
'id'
,
'parent_id'
,
'name'
,
'barcode_base'
]
associated
=
api
.
search_read
(
'res.partner'
,
cond
,
fields
)
fields
=
[
'id'
,
'parent_id'
,
'name'
,
'barcode_base'
,
'suppleant_member_id'
]
attached
=
api
.
search_read
(
'res.partner'
,
cond
,
fields
)
associated
=
[
x
for
x
in
attached
if
x
[
'suppleant_member_id'
]]
if
len
(
associated
)
>
0
:
for
m
in
s
[
'members'
]:
...
...
@@ -832,32 +793,17 @@ class CagetteServices(models.Model):
[
'state'
,
'='
,
'open'
]]
fields
=
[
'state'
,
'partner_id'
,
'date_begin'
,
'shift_id'
]
res
=
api
.
search_read
(
'shift.registration'
,
cond
,
fields
)
ids
=
[]
partner_ids
=
[]
excluded_partner
=
[]
canceled_reg_ids
=
[]
# for exempted people
shift_ids
=
[]
for
r
in
res
:
partner_ids
.
append
(
int
(
r
[
'partner_id'
][
0
]))
shift_id
=
int
(
r
[
'shift_id'
][
0
])
if
shift_id
not
in
shift_ids
:
shift_ids
.
append
(
shift_id
)
cond
=
[[
'id'
,
'in'
,
partner_ids
],
[
'cooperative_state'
,
'in'
,
[
'exempted'
]]]
fields
=
[
'id'
]
res_exempted
=
api
.
search_read
(
'res.partner'
,
cond
,
fields
)
for
r
in
res_exempted
:
excluded_partner
.
append
(
int
(
r
[
'id'
]))
for
r
in
res
:
if
not
(
int
(
r
[
'partner_id'
][
0
])
in
excluded_partner
):
d_begin
=
r
[
'date_begin'
]
(
d
,
h
)
=
d_begin
.
split
(
' '
)
(
_h
,
_m
,
_s
)
=
h
.
split
(
':'
)
if
int
(
_h
)
<
21
:
ids
.
append
(
int
(
r
[
'id'
]))
else
:
canceled_reg_ids
.
append
(
int
(
r
[
'id'
]))
# coop_logger.info("Traitement absences shift_registration ids %s", ids)
#TODO : improve name of following method
canceled_reg_ids
,
excluded_partner
,
ids
=
CagetteServices
.
fetch_registrations_infos_excluding_exempted_people
(
api
,
partner_ids
,
res
)
f
=
{
'state'
:
absence_status
,
'date_closed'
:
now
.
isoformat
()}
update_shift_reg_result
=
{
'update'
:
False
,
'reg_shift'
:
res
,
'errors'
:
[]}
individual_update_result
=
{}
...
...
@@ -884,6 +830,25 @@ class CagetteServices(models.Model):
return
update_shift_reg_result
@staticmethod
def
fetch_registrations_infos_excluding_exempted_people
(
api
,
partner_ids
,
res
):
#TODO : document this method
ids
=
[]
excluded_partner
=
[]
canceled_reg_ids
=
[]
# for exempted people
res_exempted
=
shifts
.
fonctions
.
get_exempted_ids_from
(
api
,
partner_ids
)
for
r
in
res_exempted
:
excluded_partner
.
append
(
int
(
r
[
'id'
]))
for
r
in
res
:
if
not
(
int
(
r
[
'partner_id'
][
0
])
in
excluded_partner
):
d_begin
=
r
[
'date_begin'
]
(
d
,
h
)
=
d_begin
.
split
(
' '
)
(
_h
,
_m
,
_s
)
=
h
.
split
(
':'
)
if
int
(
_h
)
<
21
:
ids
.
append
(
int
(
r
[
'id'
]))
else
:
canceled_reg_ids
.
append
(
int
(
r
[
'id'
]))
return
canceled_reg_ids
,
excluded_partner
,
ids
@staticmethod
def
close_ftop_service
():
...
...
@@ -1086,30 +1051,13 @@ class CagetteService(models.Model):
[
'state'
,
'='
,
'open'
]]
fields
=
[
'state'
,
'partner_id'
,
'date_begin'
]
res
=
self
.
o_api
.
search_read
(
'shift.registration'
,
cond
,
fields
)
ids
=
[]
partner_ids
=
[]
excluded_partner
=
[]
canceled_reg_ids
=
[]
# for exempted people
for
r
in
res
:
partner_ids
.
append
(
int
(
r
[
'partner_id'
][
0
]))
cond
=
[[
'id'
,
'in'
,
partner_ids
],
[
'cooperative_state'
,
'in'
,
[
'exempted'
]]]
fields
=
[
'id'
]
res_exempted
=
self
.
o_api
.
search_read
(
'res.partner'
,
cond
,
fields
)
for
r
in
res_exempted
:
excluded_partner
.
append
(
int
(
r
[
'id'
]))
for
r
in
res
:
if
not
(
int
(
r
[
'partner_id'
][
0
])
in
excluded_partner
):
d_begin
=
r
[
'date_begin'
]
(
d
,
h
)
=
d_begin
.
split
(
' '
)
(
_h
,
_m
,
_s
)
=
h
.
split
(
':'
)
if
int
(
_h
)
<
21
:
ids
.
append
(
int
(
r
[
'id'
]))
else
:
canceled_reg_ids
.
append
(
int
(
r
[
'id'
]))
# coop_logger.info("Traitement absences shift_registration ids %s", ids)
#TODO : improve name of following method
canceled_reg_ids
,
excluded_partner
,
ids
=
CagetteServices
.
fetch_registrations_infos_excluding_exempted_people
(
api
,
partner_ids
,
res
)
f
=
{
'state'
:
absence_status
,
'date_closed'
:
now
.
isoformat
()}
update_shift_reg_result
=
{
'update'
:
self
.
o_api
.
update
(
'shift.registration'
,
ids
,
f
),
'reg_shift'
:
res
,
'errors'
:
[]}
if
update_shift_reg_result
[
'update'
]
is
True
:
...
...
shifts/views.py
View file @
e5bff7b4
...
...
@@ -4,16 +4,13 @@ from outils.common import Verification
from
shifts.models
import
CagetteShift
from
members.models
import
CagetteMember
import
shifts.fonctions
# working_state = ['up_to_date', 'alert', 'exempted', 'delay', 'suspended']
state_shift_allowed
=
[
"up_to_date"
,
"alert"
,
"delay"
]
tz
=
pytz
.
timezone
(
"Europe/Paris"
)
def
dateIsoUTC
(
myDate
):
tDate
=
tz
.
localize
(
datetime
.
datetime
.
strptime
(
myDate
,
'
%
Y-
%
m-
%
d
%
H:
%
M:
%
S'
))
return
tDate
.
isoformat
()
def
home
(
request
,
partner_id
,
hashed_date
):
import
hashlib
cs
=
CagetteShift
()
...
...
@@ -96,7 +93,7 @@ def _is_middled_filled_considered(reserved, max):
def
get_list_shift_calendar
(
request
,
partner_id
):
cs
=
CagetteShift
()
[
registerPartner
,
is_ftop
]
=
cs
.
get_shift_partner
(
partner_id
)
[
registerPartner
,
is_ftop
]
=
shifts
.
fonctions
.
get_shift_partner
(
cs
.
o_api
,
partner_id
)
use_new_members_space
=
getattr
(
settings
,
'USE_NEW_MEMBERS_SPACE'
,
False
)
remove_15_minutes_at_shift_end
=
getattr
(
settings
,
'REMOVE_15_MINUTES_AT_SHIFT_END'
,
True
)
...
...
@@ -132,12 +129,12 @@ def get_list_shift_calendar(request, partner_id):
event
[
"title"
]
=
title_prefix
+
str
(
value
[
'seats_reserved'
])
+
"/"
+
str
(
smax
)
event
[
"start"
]
=
dateIsoUTC
(
value
[
'date_begin_tz'
])
event
[
"start"
]
=
shifts
.
fonctions
.
dateIsoUTC
(
value
[
'date_begin_tz'
])
datetime_object
=
datetime
.
datetime
.
strptime
(
value
[
'date_end_tz'
],
"
%
Y-
%
m-
%
d
%
H:
%
M:
%
S"
)
-
datetime
.
timedelta
(
minutes
=
15
)
if
remove_15_minutes_at_shift_end
is
True
:
datetime_object
-=
datetime
.
timedelta
(
minutes
=
15
)
event
[
"end"
]
=
dateIsoUTC
(
datetime_object
.
strftime
(
"
%
Y-
%
m-
%
d
%
H:
%
M:
%
S"
))
event
[
"end"
]
=
shifts
.
fonctions
.
dateIsoUTC
(
datetime_object
.
strftime
(
"
%
Y-
%
m-
%
d
%
H:
%
M:
%
S"
))
if
len
(
l
)
>
0
:
if
use_new_members_space
is
True
:
...
...
@@ -178,7 +175,7 @@ def get_list_shift_calendar(request, partner_id):
def
get_list_shift_partner
(
request
,
partner_id
):
cs
=
CagetteShift
()
[
shiftData
,
is_ftop
]
=
cs
.
get_shift_partner
(
partner_id
)
[
shiftData
,
is_ftop
]
=
shifts
.
fonctions
.
get_shift_partner
(
cs
.
o_api
,
partner_id
)
for
value
in
shiftData
:
value
[
'date_begin'
]
=
value
[
'date_begin'
]
+
"Z"
...
...
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