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
dba4831f
Commit
dba4831f
authored
Oct 03, 2022
by
Damien Moulard
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
change Services & Service models to shifts module
parent
9479e21d
Pipeline
#2398
passed with stage
in 1 minute 23 seconds
Changes
6
Pipelines
1
Show whitespace changes
Inline
Side-by-side
Showing
6 changed files
with
527 additions
and
526 deletions
+527
-526
admin.py
members/admin.py
+1
-1
models.py
members/models.py
+0
-522
views.py
members/views.py
+1
-1
models.py
members_space/models.py
+1
-1
config.md
outils/config.md
+1
-1
models.py
shifts/models.py
+523
-0
No files found.
members/admin.py
View file @
dba4831f
...
@@ -5,7 +5,7 @@ from outils.common import OdooAPI
...
@@ -5,7 +5,7 @@ from outils.common import OdooAPI
from
members.models
import
CagetteUser
from
members.models
import
CagetteUser
from
members.models
import
CagetteMembers
from
members.models
import
CagetteMembers
from
members.models
import
CagetteMember
from
members.models
import
CagetteMember
from
member
s.models
import
CagetteServices
from
shift
s.models
import
CagetteServices
from
shifts.models
import
CagetteShift
from
shifts.models
import
CagetteShift
from
outils.common
import
MConfig
from
outils.common
import
MConfig
from
datetime
import
datetime
from
datetime
import
datetime
...
...
members/models.py
View file @
dba4831f
...
@@ -1272,528 +1272,6 @@ class CagetteMembers(models.Model):
...
@@ -1272,528 +1272,6 @@ class CagetteMembers(models.Model):
res
=
api
.
search_read
(
'res.partner'
,
cond
,
fields
)
res
=
api
.
search_read
(
'res.partner'
,
cond
,
fields
)
return
res
return
res
class
CagetteServices
(
models
.
Model
):
"""Class to handle cagette Odoo services."""
@staticmethod
def
get_all_shift_templates
():
"""Return all recorded shift templates recorded in Odoo database."""
creneaux
=
{}
try
:
api
=
OdooAPI
()
f
=
[
'name'
,
'week_number'
,
'start_datetime_tz'
,
'end_datetime_tz'
,
'seats_reserved'
,
'shift_type_id'
,
'seats_max'
,
'seats_available'
,
'registration_qty'
]
c
=
[[
'active'
,
'='
,
True
]]
shift_templates
=
api
.
search_read
(
'shift.template'
,
c
,
f
)
# Get count of active registrations for each shift template
# shift_templates_active_count = api.execute('lacagette_shifts', 'get_active_shifts', [])
# With LGDS tests, seats_reserved reflects better what's shown in Odoo ...
title
=
re
.
compile
(
r"^(\w{1})(\w{3})\. - (\d{2}:\d{2}) ?-? ?(\w*)"
)
for
l
in
shift_templates
:
# nb_reserved = 0
# for stac in shift_templates_active_count:
# if stac['shift_template_id'] == l['id']:
# nb_reserved = stac['seats_active_registration']
line
=
{}
end
=
time
.
strptime
(
l
[
'end_datetime_tz'
],
"
%
Y-
%
m-
%
d
%
H:
%
M:
%
S"
)
end_min
=
str
(
end
.
tm_min
)
if
end_min
==
'0'
:
end_min
=
'00'
line
[
'end'
]
=
str
(
end
.
tm_hour
)
+
':'
+
end_min
line
[
'max'
]
=
l
[
'seats_max'
]
# line['reserved'] = nb_reserved
#line['reserved'] = l['seats_reserved']
line
[
'reserved'
]
=
l
[
'registration_qty'
]
line
[
'week'
]
=
l
[
'week_number'
]
line
[
'id'
]
=
l
[
'id'
]
line
[
'type'
]
=
l
[
'shift_type_id'
][
0
]
t_elts
=
title
.
search
(
l
[
'name'
])
if
t_elts
:
line
[
'day'
]
=
t_elts
.
group
(
2
)
line
[
'begin'
]
=
t_elts
.
group
(
3
)
line
[
'place'
]
=
t_elts
.
group
(
4
)
creneaux
[
str
(
l
[
'id'
])]
=
{
'data'
:
line
}
except
Exception
as
e
:
coop_logger
.
error
(
str
(
e
))
return
creneaux
@staticmethod
def
get_shift_templates_next_shift
(
id
):
"""Retrieve next shift template shift."""
api
=
OdooAPI
()
c
=
[[
'shift_template_id.id'
,
'='
,
id
],
[
'date_begin'
,
'>='
,
datetime
.
datetime
.
now
()
.
isoformat
()]]
f
=
[
'date_begin'
]
# c = [['id','=',2149]]
shift
=
{}
res
=
api
.
search_read
(
'shift.shift'
,
c
,
f
,
1
,
0
,
'date_begin ASC'
)
if
(
res
and
res
[
0
]):
locale
.
setlocale
(
locale
.
LC_ALL
,
'fr_FR.utf8'
)
local_tz
=
pytz
.
timezone
(
'Europe/Paris'
)
date
,
t
=
res
[
0
][
'date_begin'
]
.
split
(
' '
)
year
,
month
,
day
=
date
.
split
(
'-'
)
start
=
datetime
.
datetime
(
int
(
year
),
int
(
month
),
int
(
day
),
0
,
0
,
0
,
tzinfo
=
pytz
.
utc
)
start_date
=
start
.
astimezone
(
local_tz
)
shift
[
'date_begin'
]
=
start_date
.
strftime
(
"
%
A
%
d
%
B
%
Y"
)
return
shift
@staticmethod
def
get_services_at_time
(
time
,
tz_offset
,
with_members
=
True
):
"""Retrieve present services with members linked."""
default_acceptable_minutes_after_shift_begins
=
getattr
(
settings
,
'ACCEPTABLE_ENTRANCE_MINUTES_AFTER_SHIFT_BEGINS'
,
15
)
minutes_before_shift_starts_delay
=
getattr
(
settings
,
'ACCEPTABLE_ENTRANCE_MINUTES_BEFORE_SHIFT'
,
15
)
minutes_after_shift_starts_delay
=
default_acceptable_minutes_after_shift_begins
late_mode
=
getattr
(
settings
,
'ENTRANCE_WITH_LATE_MODE'
,
False
)
max_duration
=
getattr
(
settings
,
'MAX_DURATION'
,
180
)
if
late_mode
is
True
:
minutes_after_shift_starts_delay
=
getattr
(
settings
,
'ENTRANCE_VALIDATION_GRACE_DELAY'
,
60
)
api
=
OdooAPI
()
now
=
dateutil
.
parser
.
parse
(
time
)
-
datetime
.
timedelta
(
minutes
=
tz_offset
)
start1
=
now
+
datetime
.
timedelta
(
minutes
=
minutes_before_shift_starts_delay
)
start2
=
now
-
datetime
.
timedelta
(
minutes
=
minutes_after_shift_starts_delay
)
end
=
start1
+
datetime
.
timedelta
(
minutes
=
max_duration
)
cond
=
[[
'date_end_tz'
,
'<='
,
end
.
isoformat
()]]
cond
.
append
(
'|'
)
cond
.
append
([
'date_begin_tz'
,
'>='
,
start1
.
isoformat
()])
cond
.
append
([
'date_begin_tz'
,
'>='
,
start2
.
isoformat
()])
fields
=
[
'name'
,
'week_number'
,
'registration_ids'
,
'standard_registration_ids'
,
'shift_template_id'
,
'shift_ticket_ids'
,
'date_begin_tz'
,
'date_end_tz'
,
'state'
]
services
=
api
.
search_read
(
'shift.shift'
,
cond
,
fields
,
order
=
"date_begin_tz ASC"
)
for
s
in
services
:
if
(
len
(
s
[
'registration_ids'
])
>
0
):
if
late_mode
is
True
:
s
[
'late'
]
=
(
now
.
replace
(
tzinfo
=
None
)
-
dateutil
.
parser
.
parse
(
s
[
'date_begin_tz'
])
.
replace
(
tzinfo
=
None
)
)
.
total_seconds
()
/
60
>
default_acceptable_minutes_after_shift_begins
if
with_members
is
True
:
cond
=
[[
'id'
,
'in'
,
s
[
'registration_ids'
]],
[
'state'
,
'not in'
,
[
'cancel'
,
'waiting'
,
'draft'
]]]
fields
=
[
'partner_id'
,
'shift_type'
,
'state'
,
'is_late'
,
'associate_registered'
]
members
=
api
.
search_read
(
'shift.registration'
,
cond
,
fields
)
s
[
'members'
]
=
sorted
(
members
,
key
=
lambda
x
:
x
[
'partner_id'
][
0
])
if
len
(
s
[
'members'
])
>
0
:
# search for associated people linked to these members
mids
=
[]
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
)
if
len
(
associated
)
>
0
:
for
m
in
s
[
'members'
]:
for
a
in
associated
:
if
int
(
a
[
'parent_id'
][
0
])
==
int
(
m
[
'partner_id'
][
0
]):
m
[
'partner_name'
]
=
m
[
'partner_id'
][
1
]
m
[
'partner_id'
][
1
]
+=
' en binôme avec '
+
a
[
'name'
]
m
[
'associate_name'
]
=
str
(
a
[
'barcode_base'
])
+
' - '
+
a
[
'name'
]
return
services
@staticmethod
def
registration_done
(
registration_id
,
overrided_date
=
""
,
typeAction
=
""
):
"""Equivalent to click present in presence form."""
api
=
OdooAPI
()
f
=
{
'state'
:
'done'
}
if
(
typeAction
!=
"normal"
and
typeAction
!=
""
):
f
[
'associate_registered'
]
=
typeAction
if
typeAction
==
"both"
:
f
[
'should_increment_extra_shift_done'
]
=
True
else
:
f
[
'should_increment_extra_shift_done'
]
=
False
late_mode
=
getattr
(
settings
,
'ENTRANCE_WITH_LATE_MODE'
,
False
)
if
late_mode
is
True
:
# services = CagetteServices.get_services_at_time('14:28',0, with_members=False)
if
len
(
overrided_date
)
>
0
and
getattr
(
settings
,
'APP_ENV'
,
"prod"
)
!=
"prod"
:
now
=
overrided_date
else
:
local_tz
=
pytz
.
timezone
(
'Europe/Paris'
)
now
=
datetime
.
datetime
.
utcnow
()
.
replace
(
tzinfo
=
pytz
.
utc
)
.
astimezone
(
local_tz
)
.
strftime
(
"
%
H:
%
MZ"
)
# coop_logger.info("Maintenant = %s (overrided %s) %s", now, overrided_date)
services
=
CagetteServices
.
get_services_at_time
(
now
,
0
,
with_members
=
False
)
if
len
(
services
)
>
0
:
# Notice : Despite is_late is defined as boolean in Odoo, 0 or 1 is needed for api call
is_late
=
0
if
services
[
0
][
'late'
]
is
True
:
is_late
=
1
f
[
'is_late'
]
=
is_late
else
:
return
False
return
api
.
update
(
'shift.registration'
,
[
int
(
registration_id
)],
f
)
@staticmethod
def
reopen_registration
(
registration_id
,
overrided_date
=
""
):
api
=
OdooAPI
()
f
=
{
'state'
:
'open'
}
return
api
.
update
(
'shift.registration'
,
[
int
(
registration_id
)],
f
)
@staticmethod
def
record_rattrapage
(
mid
,
sid
,
stid
,
typeAction
):
"""Add a shift registration for member mid.
(shift sid, shift ticket stid)
Once created, shift presence is confirmed.
"""
api
=
OdooAPI
()
fields
=
{
"partner_id"
:
mid
,
"shift_id"
:
sid
,
"shift_ticket_id"
:
stid
,
"shift_type"
:
"standard"
,
# ou ftop -> voir condition
"related_shift_state"
:
'confirm'
,
"state"
:
'open'
}
reg_id
=
api
.
create
(
'shift.registration'
,
fields
)
f
=
{
'state'
:
'done'
}
if
(
typeAction
!=
"normal"
and
typeAction
!=
""
):
f
[
'associate_registered'
]
=
typeAction
if
typeAction
==
"both"
:
f
[
'should_increment_extra_shift_done'
]
=
True
else
:
f
[
'should_increment_extra_shift_done'
]
=
False
return
api
.
update
(
'shift.registration'
,
[
int
(
reg_id
)],
f
)
@staticmethod
def
record_absences
(
date
):
"""Called by cron script."""
import
dateutil.parser
if
len
(
date
)
>
0
:
now
=
dateutil
.
parser
.
parse
(
date
)
else
:
now
=
datetime
.
datetime
.
now
()
# now = dateutil.parser.parse('2020-09-15T15:00:00Z')
date_24h_before
=
now
-
datetime
.
timedelta
(
hours
=
24
)
# let authorized people time to set presence for those who came in late
end_date
=
now
-
datetime
.
timedelta
(
hours
=
2
)
api
=
OdooAPI
()
# Let's start by adding an extra shift to associated member who came together
cond
=
[[
'date_begin'
,
'>='
,
date_24h_before
.
isoformat
()],
[
'date_begin'
,
'<='
,
end_date
.
isoformat
()],
[
'state'
,
'='
,
'done'
],
[
'associate_registered'
,
'='
,
'both'
],
[
'should_increment_extra_shift_done'
,
'='
,
True
]]
fields
=
[
'id'
,
'state'
,
'partner_id'
,
'date_begin'
]
res
=
api
.
search_read
(
'shift.registration'
,
cond
,
fields
)
extra_shift_done_incremented_srids
=
[]
# shift registration ids
for
r
in
res
:
cond
=
[[
'id'
,
'='
,
r
[
'partner_id'
][
0
]]]
fields
=
[
'id'
,
'extra_shift_done'
]
res_partner
=
api
.
search_read
(
'res.partner'
,
cond
,
fields
)
f
=
{
'extra_shift_done'
:
res_partner
[
0
][
'extra_shift_done'
]
+
1
}
api
.
update
(
'res.partner'
,
[
r
[
'partner_id'
][
0
]],
f
)
extra_shift_done_incremented_srids
.
append
(
int
(
r
[
'id'
]))
# Make sure the counter isn't incremented twice
f
=
{
'should_increment_extra_shift_done'
:
False
}
api
.
update
(
'shift.registration'
,
extra_shift_done_incremented_srids
,
f
)
absence_status
=
'excused'
res_c
=
api
.
search_read
(
'ir.config_parameter'
,
[[
'key'
,
'='
,
'lacagette_membership.absence_status'
]],
[
'value'
])
if
len
(
res_c
)
==
1
:
absence_status
=
res_c
[
0
][
'value'
]
cond
=
[[
'date_begin'
,
'>='
,
date_24h_before
.
isoformat
()],
[
'date_begin'
,
'<='
,
end_date
.
isoformat
()],
[
'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)
f
=
{
'state'
:
absence_status
,
'date_closed'
:
now
.
isoformat
()}
update_shift_reg_result
=
{
'update'
:
api
.
update
(
'shift.registration'
,
ids
,
f
),
'reg_shift'
:
res
,
'errors'
:
[]}
if
update_shift_reg_result
[
'update'
]
is
True
:
update_shift_reg_result
[
'process_status_res'
]
=
api
.
execute
(
'res.partner'
,
'run_process_target_status'
,
[])
# change shift state by triggering button_done method for all related shifts
if
len
(
canceled_reg_ids
)
>
0
:
f
=
{
'state'
:
'cancel'
,
'date_closed'
:
now
.
isoformat
()}
api
.
update
(
'shift.registration'
,
canceled_reg_ids
,
f
)
for
sid
in
shift_ids
:
try
:
api
.
execute
(
'shift.shift'
,
'button_done'
,
sid
)
except
Exception
as
e
:
marshal_none_error
=
'cannot marshal None unless allow_none is enabled'
if
not
(
marshal_none_error
in
str
(
e
)):
update_shift_reg_result
[
'errors'
]
.
append
({
'shift_id'
:
sid
,
'msg'
:
str
(
e
)})
return
update_shift_reg_result
@staticmethod
def
close_ftop_service
():
"""Called by cron script"""
# Retrieve the latest past FTOP service
import
dateutil.parser
now
=
datetime
.
datetime
.
now
()
# now = dateutil.parser.parse('2019-10-20T00:00:00Z')
cond
=
[[
'shift_type_id'
,
'='
,
2
],[
'date_end'
,
'<='
,
now
.
isoformat
()],[
'state'
,
'='
,
'draft'
],
[
'active'
,
'='
,
True
]]
fields
=
[
'name'
]
api
=
OdooAPI
()
res
=
api
.
search_read
(
'shift.shift'
,
cond
,
fields
,
order
=
"date_end ASC"
,
limit
=
1
)
# return res[0]['id']
result
=
{}
if
res
and
len
(
res
)
>
0
:
result
[
'service_found'
]
=
True
# Exceptions are due to the fact API returns None whereas the action is really done !...
marshal_none_error
=
'cannot marshal None unless allow_none is enabled'
actual_errors
=
0
try
:
api
.
execute
(
'shift.shift'
,
'button_confirm'
,
[
res
[
0
][
'id'
]])
except
Exception
as
e
:
if
not
(
marshal_none_error
in
str
(
e
)):
result
[
'exeption_confirm'
]
=
str
(
e
)
actual_errors
+=
1
try
:
api
.
execute
(
'shift.shift'
,
'button_makeupok'
,
[
res
[
0
][
'id'
]])
except
Exception
as
e
:
if
not
(
marshal_none_error
in
str
(
e
)):
result
[
'exeption_makeupok'
]
=
str
(
e
)
actual_errors
+=
1
try
:
api
.
execute
(
'shift.shift'
,
'button_done'
,
[
res
[
0
][
'id'
]])
except
Exception
as
e
:
if
not
(
marshal_none_error
in
str
(
e
)):
result
[
'exeption_done'
]
=
str
(
e
)
actual_errors
+=
1
if
actual_errors
==
0
:
result
[
'done'
]
=
True
else
:
result
[
'done'
]
=
False
result
[
'actual_errors'
]
=
actual_errors
else
:
result
[
'service_found'
]
=
False
return
result
@staticmethod
def
get_committees_shift_id
():
shift_id
=
None
try
:
api
=
OdooAPI
()
res
=
api
.
search_read
(
'ir.config_parameter'
,
[[
'key'
,
'='
,
'lacagette_membership.committees_shift_id'
]],
[
'value'
])
if
len
(
res
)
>
0
:
try
:
shift_id
=
int
(
res
[
0
][
'value'
])
except
:
pass
except
:
pass
return
shift_id
@staticmethod
def
get_first_ftop_shift_id
():
shift_id
=
None
try
:
api
=
OdooAPI
()
res
=
api
.
search_read
(
'shift.template'
,
[[
'shift_type_id'
,
'='
,
2
]],
[
'id'
,
'registration_qty'
])
# Get the ftop shift template with the max registrations: most likely the one in use
ftop_shift
=
{
'id'
:
None
,
'registration_qty'
:
0
}
for
shift_reg
in
res
:
if
shift_reg
[
"registration_qty"
]
>
ftop_shift
[
"registration_qty"
]:
ftop_shift
=
shift_reg
try
:
shift_id
=
int
(
ftop_shift
[
'id'
])
except
:
pass
except
:
pass
return
shift_id
@staticmethod
def
easy_validate_shift_presence
(
coop_id
):
"""Add a presence point if the request is valid."""
res
=
{}
try
:
committees_shift_id
=
CagetteServices
.
get_committees_shift_id
()
api
=
OdooAPI
()
# let verify coop_id is corresponding to a ftop subscriber
cond
=
[[
'id'
,
'='
,
coop_id
]]
fields
=
[
'tmpl_reg_line_ids'
]
coop
=
api
.
search_read
(
'res.partner'
,
cond
,
fields
)
if
coop
:
if
len
(
coop
[
0
][
'tmpl_reg_line_ids'
])
>
0
:
cond
=
[[
'id'
,
'='
,
coop
[
0
][
'tmpl_reg_line_ids'
][
0
]]]
fields
=
[
'shift_template_id'
]
shift_templ_res
=
api
.
search_read
(
'shift.template.registration.line'
,
cond
,
fields
)
if
(
len
(
shift_templ_res
)
>
0
and
shift_templ_res
[
0
][
'shift_template_id'
][
0
]
==
committees_shift_id
):
evt_name
=
getattr
(
settings
,
'ENTRANCE_ADD_PT_EVENT_NAME'
,
'Validation service comité'
)
c
=
[[
'partner_id'
,
'='
,
coop_id
],
[
'name'
,
'='
,
evt_name
]]
f
=
[
'create_date'
]
last_point_mvts
=
api
.
search_read
(
'shift.counter.event'
,
c
,
f
,
order
=
"create_date DESC"
,
limit
=
1
)
ok_for_adding_pt
=
False
if
len
(
last_point_mvts
):
now
=
datetime
.
datetime
.
now
()
past
=
datetime
.
datetime
.
strptime
(
last_point_mvts
[
0
][
'create_date'
],
'
%
Y-
%
m-
%
d
%
H:
%
M:
%
S'
)
if
(
now
-
past
)
.
total_seconds
()
>=
3600
*
24
:
ok_for_adding_pt
=
True
else
:
ok_for_adding_pt
=
True
if
ok_for_adding_pt
is
True
:
res
[
'evt_id'
]
=
CagetteMember
(
coop_id
)
.
add_pts
(
'ftop'
,
1
,
evt_name
)
else
:
res
[
'error'
]
=
"One point has been added less then 24 hours ago"
else
:
res
[
'error'
]
=
"Unallowed coop"
else
:
res
[
'error'
]
=
"Unregistred coop"
else
:
res
[
'error'
]
=
"Invalid coop id"
except
Exception
as
e
:
coop_logger
.
error
(
"easy_validate_shift_presence :
%
s
%
s"
,
str
(
coop_id
),
str
(
e
))
return
res
class
CagetteService
(
models
.
Model
):
"""Class to handle cagette Odoo service."""
def
__init__
(
self
,
id
):
"""Init with odoo id."""
self
.
id
=
int
(
id
)
self
.
o_api
=
OdooAPI
()
def
_process_associated_people_extra_shift_done
(
self
):
cond
=
[[
'shift_id'
,
'='
,
self
.
id
],
[
'state'
,
'='
,
'done'
],
[
'associate_registered'
,
'='
,
'both'
],
[
'should_increment_extra_shift_done'
,
'='
,
True
]]
fields
=
[
'id'
,
'state'
,
'partner_id'
,
'date_begin'
]
res
=
self
.
o_api
.
search_read
(
'shift.registration'
,
cond
,
fields
)
extra_shift_done_incremented_srids
=
[]
# shift registration ids
for
r
in
res
:
cond
=
[[
'id'
,
'='
,
r
[
'partner_id'
][
0
]]]
fields
=
[
'id'
,
'extra_shift_done'
]
res_partner
=
self
.
o_api
.
search_read
(
'res.partner'
,
cond
,
fields
)
f
=
{
'extra_shift_done'
:
res_partner
[
0
][
'extra_shift_done'
]
+
1
}
self
.
o_api
.
update
(
'res.partner'
,
[
r
[
'partner_id'
][
0
]],
f
)
extra_shift_done_incremented_srids
.
append
(
int
(
r
[
'id'
]))
# Make sure the counter isn't incremented twice
f
=
{
'should_increment_extra_shift_done'
:
False
}
self
.
o_api
.
update
(
'shift.registration'
,
extra_shift_done_incremented_srids
,
f
)
def
_process_related_shift_registrations
(
self
):
now
=
datetime
.
datetime
.
now
()
absence_status
=
'excused'
res_c
=
self
.
o_api
.
search_read
(
'ir.config_parameter'
,
[[
'key'
,
'='
,
'lacagette_membership.absence_status'
]],
[
'value'
])
if
len
(
res_c
)
==
1
:
absence_status
=
res_c
[
0
][
'value'
]
cond
=
[[
'shift_id'
,
'='
,
self
.
id
],
[
'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)
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
:
update_shift_reg_result
[
'process_status_res'
]
=
self
.
o_api
.
execute
(
'res.partner'
,
'run_process_target_status'
,
[])
# change shift state by triggering button_done method for all related shifts
if
len
(
canceled_reg_ids
)
>
0
:
f
=
{
'state'
:
'cancel'
,
'date_closed'
:
now
.
isoformat
()}
self
.
o_api
.
update
(
'shift.registration'
,
canceled_reg_ids
,
f
)
try
:
self
.
o_api
.
execute
(
'shift.shift'
,
'button_done'
,
self
.
id
)
except
Exception
as
e
:
marshal_none_error
=
'cannot marshal None unless allow_none is enabled'
if
not
(
marshal_none_error
in
str
(
e
)):
update_shift_reg_result
[
'errors'
]
.
append
({
'shift_id'
:
self
.
id
,
'msg'
:
str
(
e
)})
return
update_shift_reg_result
def
record_absences
(
self
,
request
):
"""Can only been executed if an Odoo user is beeing connected."""
res
=
{}
try
:
if
CagetteUser
.
are_credentials_ok
(
request
)
is
True
:
self
.
_process_associated_people_extra_shift_done
()
res
=
self
.
_process_related_shift_registrations
()
else
:
res
[
'error'
]
=
'Forbidden'
except
Exception
as
e
:
coop_logger
.
error
(
"CagetteService.record_absences :
%
s
%
s"
,
str
(
self
.
id
),
str
(
e
))
res
[
'error'
]
=
str
(
e
)
return
res
class
CagetteUser
(
models
.
Model
):
class
CagetteUser
(
models
.
Model
):
@staticmethod
@staticmethod
...
...
members/views.py
View file @
dba4831f
...
@@ -5,7 +5,7 @@ from outils.for_view_imports import *
...
@@ -5,7 +5,7 @@ from outils.for_view_imports import *
from
members.models
import
CagetteMember
from
members.models
import
CagetteMember
from
members.models
import
CagetteUser
from
members.models
import
CagetteUser
from
members.models
import
CagetteMembers
from
members.models
import
CagetteMembers
from
member
s.models
import
CagetteServices
,
CagetteService
from
shift
s.models
import
CagetteServices
,
CagetteService
from
outils.forms
import
GenericExportMonthForm
from
outils.forms
import
GenericExportMonthForm
import
datetime
import
datetime
...
...
members_space/models.py
View file @
dba4831f
from
django.db
import
models
from
django.db
import
models
from
outils.common_imports
import
*
from
outils.common_imports
import
*
from
member
s.models
import
CagetteServices
from
shift
s.models
import
CagetteServices
from
outils.common
import
OdooAPI
from
outils.common
import
OdooAPI
...
...
outils/config.md
View file @
dba4831f
...
@@ -133,7 +133,7 @@
...
@@ -133,7 +133,7 @@
-
CAN_CREATE_BINOME = True (by default)
-
CAN_CREATE_BINOME = True (by default)
If set to
Fals
e, in new member creation form, a member can be selected to be associated with.
If set to
Tru
e, in new member creation form, a member can be selected to be associated with.
-
ASSOCIATE_MEMBER_SHIFT = ''
-
ASSOCIATE_MEMBER_SHIFT = ''
...
...
shifts/models.py
View file @
dba4831f
...
@@ -464,3 +464,526 @@ class CagetteShift(models.Model):
...
@@ -464,3 +464,526 @@ class CagetteShift(models.Model):
def
update_counter_event
(
self
,
fields
):
def
update_counter_event
(
self
,
fields
):
""" Add/remove points """
""" Add/remove points """
return
self
.
o_api
.
create
(
'shift.counter.event'
,
fields
)
return
self
.
o_api
.
create
(
'shift.counter.event'
,
fields
)
class
CagetteServices
(
models
.
Model
):
"""Class to handle cagette Odoo services."""
@staticmethod
def
get_all_shift_templates
():
"""Return all recorded shift templates recorded in Odoo database."""
creneaux
=
{}
try
:
api
=
OdooAPI
()
f
=
[
'name'
,
'week_number'
,
'start_datetime_tz'
,
'end_datetime_tz'
,
'seats_reserved'
,
'shift_type_id'
,
'seats_max'
,
'seats_available'
,
'registration_qty'
]
c
=
[[
'active'
,
'='
,
True
]]
shift_templates
=
api
.
search_read
(
'shift.template'
,
c
,
f
)
# Get count of active registrations for each shift template
# shift_templates_active_count = api.execute('lacagette_shifts', 'get_active_shifts', [])
# With LGDS tests, seats_reserved reflects better what's shown in Odoo ...
title
=
re
.
compile
(
r"^(\w{1})(\w{3})\. - (\d{2}:\d{2}) ?-? ?(\w*)"
)
for
l
in
shift_templates
:
# nb_reserved = 0
# for stac in shift_templates_active_count:
# if stac['shift_template_id'] == l['id']:
# nb_reserved = stac['seats_active_registration']
line
=
{}
end
=
time
.
strptime
(
l
[
'end_datetime_tz'
],
"
%
Y-
%
m-
%
d
%
H:
%
M:
%
S"
)
end_min
=
str
(
end
.
tm_min
)
if
end_min
==
'0'
:
end_min
=
'00'
line
[
'end'
]
=
str
(
end
.
tm_hour
)
+
':'
+
end_min
line
[
'max'
]
=
l
[
'seats_max'
]
# line['reserved'] = nb_reserved
#line['reserved'] = l['seats_reserved']
line
[
'reserved'
]
=
l
[
'registration_qty'
]
line
[
'week'
]
=
l
[
'week_number'
]
line
[
'id'
]
=
l
[
'id'
]
line
[
'type'
]
=
l
[
'shift_type_id'
][
0
]
t_elts
=
title
.
search
(
l
[
'name'
])
if
t_elts
:
line
[
'day'
]
=
t_elts
.
group
(
2
)
line
[
'begin'
]
=
t_elts
.
group
(
3
)
line
[
'place'
]
=
t_elts
.
group
(
4
)
creneaux
[
str
(
l
[
'id'
])]
=
{
'data'
:
line
}
except
Exception
as
e
:
coop_logger
.
error
(
str
(
e
))
return
creneaux
@staticmethod
def
get_shift_templates_next_shift
(
id
):
"""Retrieve next shift template shift."""
api
=
OdooAPI
()
c
=
[[
'shift_template_id.id'
,
'='
,
id
],
[
'date_begin'
,
'>='
,
datetime
.
datetime
.
now
()
.
isoformat
()]]
f
=
[
'date_begin'
]
# c = [['id','=',2149]]
shift
=
{}
res
=
api
.
search_read
(
'shift.shift'
,
c
,
f
,
1
,
0
,
'date_begin ASC'
)
if
(
res
and
res
[
0
]):
locale
.
setlocale
(
locale
.
LC_ALL
,
'fr_FR.utf8'
)
local_tz
=
pytz
.
timezone
(
'Europe/Paris'
)
date
,
t
=
res
[
0
][
'date_begin'
]
.
split
(
' '
)
year
,
month
,
day
=
date
.
split
(
'-'
)
start
=
datetime
.
datetime
(
int
(
year
),
int
(
month
),
int
(
day
),
0
,
0
,
0
,
tzinfo
=
pytz
.
utc
)
start_date
=
start
.
astimezone
(
local_tz
)
shift
[
'date_begin'
]
=
start_date
.
strftime
(
"
%
A
%
d
%
B
%
Y"
)
return
shift
@staticmethod
def
get_services_at_time
(
time
,
tz_offset
,
with_members
=
True
):
"""Retrieve present services with members linked."""
default_acceptable_minutes_after_shift_begins
=
getattr
(
settings
,
'ACCEPTABLE_ENTRANCE_MINUTES_AFTER_SHIFT_BEGINS'
,
15
)
minutes_before_shift_starts_delay
=
getattr
(
settings
,
'ACCEPTABLE_ENTRANCE_MINUTES_BEFORE_SHIFT'
,
15
)
minutes_after_shift_starts_delay
=
default_acceptable_minutes_after_shift_begins
late_mode
=
getattr
(
settings
,
'ENTRANCE_WITH_LATE_MODE'
,
False
)
max_duration
=
getattr
(
settings
,
'MAX_DURATION'
,
180
)
if
late_mode
is
True
:
minutes_after_shift_starts_delay
=
getattr
(
settings
,
'ENTRANCE_VALIDATION_GRACE_DELAY'
,
60
)
api
=
OdooAPI
()
now
=
dateutil
.
parser
.
parse
(
time
)
-
datetime
.
timedelta
(
minutes
=
tz_offset
)
start1
=
now
+
datetime
.
timedelta
(
minutes
=
minutes_before_shift_starts_delay
)
start2
=
now
-
datetime
.
timedelta
(
minutes
=
minutes_after_shift_starts_delay
)
end
=
start1
+
datetime
.
timedelta
(
minutes
=
max_duration
)
cond
=
[[
'date_end_tz'
,
'<='
,
end
.
isoformat
()]]
cond
.
append
(
'|'
)
cond
.
append
([
'date_begin_tz'
,
'>='
,
start1
.
isoformat
()])
cond
.
append
([
'date_begin_tz'
,
'>='
,
start2
.
isoformat
()])
fields
=
[
'name'
,
'week_number'
,
'registration_ids'
,
'standard_registration_ids'
,
'shift_template_id'
,
'shift_ticket_ids'
,
'date_begin_tz'
,
'date_end_tz'
,
'state'
]
services
=
api
.
search_read
(
'shift.shift'
,
cond
,
fields
,
order
=
"date_begin_tz ASC"
)
for
s
in
services
:
if
(
len
(
s
[
'registration_ids'
])
>
0
):
if
late_mode
is
True
:
s
[
'late'
]
=
(
now
.
replace
(
tzinfo
=
None
)
-
dateutil
.
parser
.
parse
(
s
[
'date_begin_tz'
])
.
replace
(
tzinfo
=
None
)
)
.
total_seconds
()
/
60
>
default_acceptable_minutes_after_shift_begins
if
with_members
is
True
:
cond
=
[[
'id'
,
'in'
,
s
[
'registration_ids'
]],
[
'state'
,
'not in'
,
[
'cancel'
,
'waiting'
,
'draft'
]]]
fields
=
[
'partner_id'
,
'shift_type'
,
'state'
,
'is_late'
,
'associate_registered'
]
members
=
api
.
search_read
(
'shift.registration'
,
cond
,
fields
)
s
[
'members'
]
=
sorted
(
members
,
key
=
lambda
x
:
x
[
'partner_id'
][
0
])
if
len
(
s
[
'members'
])
>
0
:
# search for associated people linked to these members
mids
=
[]
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
)
if
len
(
associated
)
>
0
:
for
m
in
s
[
'members'
]:
for
a
in
associated
:
if
int
(
a
[
'parent_id'
][
0
])
==
int
(
m
[
'partner_id'
][
0
]):
m
[
'partner_name'
]
=
m
[
'partner_id'
][
1
]
m
[
'partner_id'
][
1
]
+=
' en binôme avec '
+
a
[
'name'
]
m
[
'associate_name'
]
=
str
(
a
[
'barcode_base'
])
+
' - '
+
a
[
'name'
]
return
services
@staticmethod
def
registration_done
(
registration_id
,
overrided_date
=
""
,
typeAction
=
""
):
"""Equivalent to click present in presence form."""
api
=
OdooAPI
()
f
=
{
'state'
:
'done'
}
if
(
typeAction
!=
"normal"
and
typeAction
!=
""
):
f
[
'associate_registered'
]
=
typeAction
if
typeAction
==
"both"
:
f
[
'should_increment_extra_shift_done'
]
=
True
else
:
f
[
'should_increment_extra_shift_done'
]
=
False
late_mode
=
getattr
(
settings
,
'ENTRANCE_WITH_LATE_MODE'
,
False
)
if
late_mode
is
True
:
# services = CagetteServices.get_services_at_time('14:28',0, with_members=False)
if
len
(
overrided_date
)
>
0
and
getattr
(
settings
,
'APP_ENV'
,
"prod"
)
!=
"prod"
:
now
=
overrided_date
else
:
local_tz
=
pytz
.
timezone
(
'Europe/Paris'
)
now
=
datetime
.
datetime
.
utcnow
()
.
replace
(
tzinfo
=
pytz
.
utc
)
.
astimezone
(
local_tz
)
.
strftime
(
"
%
H:
%
MZ"
)
# coop_logger.info("Maintenant = %s (overrided %s) %s", now, overrided_date)
services
=
CagetteServices
.
get_services_at_time
(
now
,
0
,
with_members
=
False
)
if
len
(
services
)
>
0
:
# Notice : Despite is_late is defined as boolean in Odoo, 0 or 1 is needed for api call
is_late
=
0
if
services
[
0
][
'late'
]
is
True
:
is_late
=
1
f
[
'is_late'
]
=
is_late
else
:
return
False
return
api
.
update
(
'shift.registration'
,
[
int
(
registration_id
)],
f
)
@staticmethod
def
reopen_registration
(
registration_id
,
overrided_date
=
""
):
api
=
OdooAPI
()
f
=
{
'state'
:
'open'
}
return
api
.
update
(
'shift.registration'
,
[
int
(
registration_id
)],
f
)
@staticmethod
def
record_rattrapage
(
mid
,
sid
,
stid
,
typeAction
):
"""Add a shift registration for member mid.
(shift sid, shift ticket stid)
Once created, shift presence is confirmed.
"""
api
=
OdooAPI
()
fields
=
{
"partner_id"
:
mid
,
"shift_id"
:
sid
,
"shift_ticket_id"
:
stid
,
"shift_type"
:
"standard"
,
# ou ftop -> voir condition
"related_shift_state"
:
'confirm'
,
"state"
:
'open'
}
reg_id
=
api
.
create
(
'shift.registration'
,
fields
)
f
=
{
'state'
:
'done'
}
if
(
typeAction
!=
"normal"
and
typeAction
!=
""
):
f
[
'associate_registered'
]
=
typeAction
if
typeAction
==
"both"
:
f
[
'should_increment_extra_shift_done'
]
=
True
else
:
f
[
'should_increment_extra_shift_done'
]
=
False
return
api
.
update
(
'shift.registration'
,
[
int
(
reg_id
)],
f
)
@staticmethod
def
record_absences
(
date
):
"""Called by cron script."""
import
dateutil.parser
if
len
(
date
)
>
0
:
now
=
dateutil
.
parser
.
parse
(
date
)
else
:
now
=
datetime
.
datetime
.
now
()
# now = dateutil.parser.parse('2020-09-15T15:00:00Z')
date_24h_before
=
now
-
datetime
.
timedelta
(
hours
=
24
)
# let authorized people time to set presence for those who came in late
end_date
=
now
-
datetime
.
timedelta
(
hours
=
2
)
api
=
OdooAPI
()
# Let's start by adding an extra shift to associated member who came together
cond
=
[[
'date_begin'
,
'>='
,
date_24h_before
.
isoformat
()],
[
'date_begin'
,
'<='
,
end_date
.
isoformat
()],
[
'state'
,
'='
,
'done'
],
[
'associate_registered'
,
'='
,
'both'
],
[
'should_increment_extra_shift_done'
,
'='
,
True
]]
fields
=
[
'id'
,
'state'
,
'partner_id'
,
'date_begin'
]
res
=
api
.
search_read
(
'shift.registration'
,
cond
,
fields
)
extra_shift_done_incremented_srids
=
[]
# shift registration ids
for
r
in
res
:
cond
=
[[
'id'
,
'='
,
r
[
'partner_id'
][
0
]]]
fields
=
[
'id'
,
'extra_shift_done'
]
res_partner
=
api
.
search_read
(
'res.partner'
,
cond
,
fields
)
f
=
{
'extra_shift_done'
:
res_partner
[
0
][
'extra_shift_done'
]
+
1
}
api
.
update
(
'res.partner'
,
[
r
[
'partner_id'
][
0
]],
f
)
extra_shift_done_incremented_srids
.
append
(
int
(
r
[
'id'
]))
# Make sure the counter isn't incremented twice
f
=
{
'should_increment_extra_shift_done'
:
False
}
api
.
update
(
'shift.registration'
,
extra_shift_done_incremented_srids
,
f
)
absence_status
=
'excused'
res_c
=
api
.
search_read
(
'ir.config_parameter'
,
[[
'key'
,
'='
,
'lacagette_membership.absence_status'
]],
[
'value'
])
if
len
(
res_c
)
==
1
:
absence_status
=
res_c
[
0
][
'value'
]
cond
=
[[
'date_begin'
,
'>='
,
date_24h_before
.
isoformat
()],
[
'date_begin'
,
'<='
,
end_date
.
isoformat
()],
[
'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)
f
=
{
'state'
:
absence_status
,
'date_closed'
:
now
.
isoformat
()}
update_shift_reg_result
=
{
'update'
:
api
.
update
(
'shift.registration'
,
ids
,
f
),
'reg_shift'
:
res
,
'errors'
:
[]}
if
update_shift_reg_result
[
'update'
]
is
True
:
update_shift_reg_result
[
'process_status_res'
]
=
api
.
execute
(
'res.partner'
,
'run_process_target_status'
,
[])
# change shift state by triggering button_done method for all related shifts
if
len
(
canceled_reg_ids
)
>
0
:
f
=
{
'state'
:
'cancel'
,
'date_closed'
:
now
.
isoformat
()}
api
.
update
(
'shift.registration'
,
canceled_reg_ids
,
f
)
for
sid
in
shift_ids
:
try
:
api
.
execute
(
'shift.shift'
,
'button_done'
,
sid
)
except
Exception
as
e
:
marshal_none_error
=
'cannot marshal None unless allow_none is enabled'
if
not
(
marshal_none_error
in
str
(
e
)):
update_shift_reg_result
[
'errors'
]
.
append
({
'shift_id'
:
sid
,
'msg'
:
str
(
e
)})
return
update_shift_reg_result
@staticmethod
def
close_ftop_service
():
"""Called by cron script"""
# Retrieve the latest past FTOP service
import
dateutil.parser
now
=
datetime
.
datetime
.
now
()
# now = dateutil.parser.parse('2019-10-20T00:00:00Z')
cond
=
[[
'shift_type_id'
,
'='
,
2
],[
'date_end'
,
'<='
,
now
.
isoformat
()],[
'state'
,
'='
,
'draft'
],
[
'active'
,
'='
,
True
]]
fields
=
[
'name'
]
api
=
OdooAPI
()
res
=
api
.
search_read
(
'shift.shift'
,
cond
,
fields
,
order
=
"date_end ASC"
,
limit
=
1
)
# return res[0]['id']
result
=
{}
if
res
and
len
(
res
)
>
0
:
result
[
'service_found'
]
=
True
# Exceptions are due to the fact API returns None whereas the action is really done !...
marshal_none_error
=
'cannot marshal None unless allow_none is enabled'
actual_errors
=
0
try
:
api
.
execute
(
'shift.shift'
,
'button_confirm'
,
[
res
[
0
][
'id'
]])
except
Exception
as
e
:
if
not
(
marshal_none_error
in
str
(
e
)):
result
[
'exeption_confirm'
]
=
str
(
e
)
actual_errors
+=
1
try
:
api
.
execute
(
'shift.shift'
,
'button_makeupok'
,
[
res
[
0
][
'id'
]])
except
Exception
as
e
:
if
not
(
marshal_none_error
in
str
(
e
)):
result
[
'exeption_makeupok'
]
=
str
(
e
)
actual_errors
+=
1
try
:
api
.
execute
(
'shift.shift'
,
'button_done'
,
[
res
[
0
][
'id'
]])
except
Exception
as
e
:
if
not
(
marshal_none_error
in
str
(
e
)):
result
[
'exeption_done'
]
=
str
(
e
)
actual_errors
+=
1
if
actual_errors
==
0
:
result
[
'done'
]
=
True
else
:
result
[
'done'
]
=
False
result
[
'actual_errors'
]
=
actual_errors
else
:
result
[
'service_found'
]
=
False
return
result
@staticmethod
def
get_committees_shift_id
():
shift_id
=
None
try
:
api
=
OdooAPI
()
res
=
api
.
search_read
(
'ir.config_parameter'
,
[[
'key'
,
'='
,
'lacagette_membership.committees_shift_id'
]],
[
'value'
])
if
len
(
res
)
>
0
:
try
:
shift_id
=
int
(
res
[
0
][
'value'
])
except
:
pass
except
:
pass
return
shift_id
@staticmethod
def
get_first_ftop_shift_id
():
shift_id
=
None
try
:
api
=
OdooAPI
()
res
=
api
.
search_read
(
'shift.template'
,
[[
'shift_type_id'
,
'='
,
2
]],
[
'id'
,
'registration_qty'
])
# Get the ftop shift template with the max registrations: most likely the one in use
ftop_shift
=
{
'id'
:
None
,
'registration_qty'
:
0
}
for
shift_reg
in
res
:
if
shift_reg
[
"registration_qty"
]
>
ftop_shift
[
"registration_qty"
]:
ftop_shift
=
shift_reg
try
:
shift_id
=
int
(
ftop_shift
[
'id'
])
except
:
pass
except
:
pass
return
shift_id
@staticmethod
def
easy_validate_shift_presence
(
coop_id
):
"""Add a presence point if the request is valid."""
res
=
{}
try
:
committees_shift_id
=
CagetteServices
.
get_committees_shift_id
()
api
=
OdooAPI
()
# let verify coop_id is corresponding to a ftop subscriber
cond
=
[[
'id'
,
'='
,
coop_id
]]
fields
=
[
'tmpl_reg_line_ids'
]
coop
=
api
.
search_read
(
'res.partner'
,
cond
,
fields
)
if
coop
:
if
len
(
coop
[
0
][
'tmpl_reg_line_ids'
])
>
0
:
cond
=
[[
'id'
,
'='
,
coop
[
0
][
'tmpl_reg_line_ids'
][
0
]]]
fields
=
[
'shift_template_id'
]
shift_templ_res
=
api
.
search_read
(
'shift.template.registration.line'
,
cond
,
fields
)
if
(
len
(
shift_templ_res
)
>
0
and
shift_templ_res
[
0
][
'shift_template_id'
][
0
]
==
committees_shift_id
):
evt_name
=
getattr
(
settings
,
'ENTRANCE_ADD_PT_EVENT_NAME'
,
'Validation service comité'
)
c
=
[[
'partner_id'
,
'='
,
coop_id
],
[
'name'
,
'='
,
evt_name
]]
f
=
[
'create_date'
]
last_point_mvts
=
api
.
search_read
(
'shift.counter.event'
,
c
,
f
,
order
=
"create_date DESC"
,
limit
=
1
)
ok_for_adding_pt
=
False
if
len
(
last_point_mvts
):
now
=
datetime
.
datetime
.
now
()
past
=
datetime
.
datetime
.
strptime
(
last_point_mvts
[
0
][
'create_date'
],
'
%
Y-
%
m-
%
d
%
H:
%
M:
%
S'
)
if
(
now
-
past
)
.
total_seconds
()
>=
3600
*
24
:
ok_for_adding_pt
=
True
else
:
ok_for_adding_pt
=
True
if
ok_for_adding_pt
is
True
:
res
[
'evt_id'
]
=
CagetteMember
(
coop_id
)
.
add_pts
(
'ftop'
,
1
,
evt_name
)
else
:
res
[
'error'
]
=
"One point has been added less then 24 hours ago"
else
:
res
[
'error'
]
=
"Unallowed coop"
else
:
res
[
'error'
]
=
"Unregistred coop"
else
:
res
[
'error'
]
=
"Invalid coop id"
except
Exception
as
e
:
coop_logger
.
error
(
"easy_validate_shift_presence :
%
s
%
s"
,
str
(
coop_id
),
str
(
e
))
return
res
class
CagetteService
(
models
.
Model
):
"""Class to handle cagette Odoo service."""
def
__init__
(
self
,
id
):
"""Init with odoo id."""
self
.
id
=
int
(
id
)
self
.
o_api
=
OdooAPI
()
def
_process_associated_people_extra_shift_done
(
self
):
cond
=
[[
'shift_id'
,
'='
,
self
.
id
],
[
'state'
,
'='
,
'done'
],
[
'associate_registered'
,
'='
,
'both'
],
[
'should_increment_extra_shift_done'
,
'='
,
True
]]
fields
=
[
'id'
,
'state'
,
'partner_id'
,
'date_begin'
]
res
=
self
.
o_api
.
search_read
(
'shift.registration'
,
cond
,
fields
)
extra_shift_done_incremented_srids
=
[]
# shift registration ids
for
r
in
res
:
cond
=
[[
'id'
,
'='
,
r
[
'partner_id'
][
0
]]]
fields
=
[
'id'
,
'extra_shift_done'
]
res_partner
=
self
.
o_api
.
search_read
(
'res.partner'
,
cond
,
fields
)
f
=
{
'extra_shift_done'
:
res_partner
[
0
][
'extra_shift_done'
]
+
1
}
self
.
o_api
.
update
(
'res.partner'
,
[
r
[
'partner_id'
][
0
]],
f
)
extra_shift_done_incremented_srids
.
append
(
int
(
r
[
'id'
]))
# Make sure the counter isn't incremented twice
f
=
{
'should_increment_extra_shift_done'
:
False
}
self
.
o_api
.
update
(
'shift.registration'
,
extra_shift_done_incremented_srids
,
f
)
def
_process_related_shift_registrations
(
self
):
now
=
datetime
.
datetime
.
now
()
absence_status
=
'excused'
res_c
=
self
.
o_api
.
search_read
(
'ir.config_parameter'
,
[[
'key'
,
'='
,
'lacagette_membership.absence_status'
]],
[
'value'
])
if
len
(
res_c
)
==
1
:
absence_status
=
res_c
[
0
][
'value'
]
cond
=
[[
'shift_id'
,
'='
,
self
.
id
],
[
'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)
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
:
update_shift_reg_result
[
'process_status_res'
]
=
self
.
o_api
.
execute
(
'res.partner'
,
'run_process_target_status'
,
[])
# change shift state by triggering button_done method for all related shifts
if
len
(
canceled_reg_ids
)
>
0
:
f
=
{
'state'
:
'cancel'
,
'date_closed'
:
now
.
isoformat
()}
self
.
o_api
.
update
(
'shift.registration'
,
canceled_reg_ids
,
f
)
try
:
self
.
o_api
.
execute
(
'shift.shift'
,
'button_done'
,
self
.
id
)
except
Exception
as
e
:
marshal_none_error
=
'cannot marshal None unless allow_none is enabled'
if
not
(
marshal_none_error
in
str
(
e
)):
update_shift_reg_result
[
'errors'
]
.
append
({
'shift_id'
:
self
.
id
,
'msg'
:
str
(
e
)})
return
update_shift_reg_result
def
record_absences
(
self
,
request
):
"""Can only been executed if an Odoo user is beeing connected."""
res
=
{}
try
:
if
CagetteUser
.
are_credentials_ok
(
request
)
is
True
:
self
.
_process_associated_people_extra_shift_done
()
res
=
self
.
_process_related_shift_registrations
()
else
:
res
[
'error'
]
=
'Forbidden'
except
Exception
as
e
:
coop_logger
.
error
(
"CagetteService.record_absences :
%
s
%
s"
,
str
(
self
.
id
),
str
(
e
))
res
[
'error'
]
=
str
(
e
)
return
res
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