1 |
557bc2ea
|
Jérôme Schneider
|
# -*- coding: utf-8 -*-
|
2 |
5f372104
|
Jérôme Schneider
|
|
3 |
197e410c
|
Frédéric Péters
|
from datetime import datetime, time
|
4 |
|
|
from datetime import time as datetime_time
|
5 |
557bc2ea
|
Jérôme Schneider
|
|
6 |
197e410c
|
Frédéric Péters
|
from interval import Interval, IntervalSet
|
7 |
2ff5e689
|
Jérôme Schneider
|
|
8 |
2f8649fe
|
Mikaël Ates
|
from calebasse.actes.validation_states import VALIDATION_STATES
|
9 |
8c0910ce
|
Serghei MIHAI
|
from .models import EventWithAct
|
10 |
5f372104
|
Jérôme Schneider
|
|
11 |
|
|
class Appointment(object):
|
12 |
|
|
|
13 |
557bc2ea
|
Jérôme Schneider
|
def __init__(self, title=None, begin_time=None, type=None,
|
14 |
dd986559
|
Serghei MIHAI
|
length=None, description=None, ressource=None):
|
15 |
5f372104
|
Jérôme Schneider
|
self.title = title
|
16 |
|
|
self.type = type
|
17 |
|
|
self.length = length
|
18 |
|
|
self.description = description
|
19 |
dd986559
|
Serghei MIHAI
|
self.ressource = ressource
|
20 |
20cc4488
|
Jérôme Schneider
|
self.is_recurrent = False
|
21 |
17861d43
|
Jérôme Schneider
|
self.is_billed = False
|
22 |
5f372104
|
Jérôme Schneider
|
self.convocation_sent = None
|
23 |
1cff6363
|
Jérôme Schneider
|
self.other_services_names = []
|
24 |
4952abd0
|
Jérôme Schneider
|
self.patient = None
|
25 |
c1fa9f24
|
Jérôme Schneider
|
self.patient_record_id = None
|
26 |
ec83d7ba
|
Frédéric Péters
|
self.patient_record_paper_id = None
|
27 |
a87d6ad7
|
Jérôme Schneider
|
self.event_id = None
|
28 |
1cff6363
|
Jérôme Schneider
|
self.event_type = None
|
29 |
04c3096d
|
Frédéric Péters
|
self.workers = None
|
30 |
41dfa4b8
|
Jérôme Schneider
|
self.workers_initial = None
|
31 |
ec83d7ba
|
Frédéric Péters
|
self.workers_codes = None
|
32 |
72f229a9
|
Jérôme Schneider
|
self.act_id = None
|
33 |
ec83d7ba
|
Frédéric Péters
|
self.act_state = None
|
34 |
|
|
self.act_absence = None
|
35 |
e5d0f8c5
|
Jérôme Schneider
|
self.weight = 0
|
36 |
41dfa4b8
|
Jérôme Schneider
|
self.act_type = None
|
37 |
2f8649fe
|
Mikaël Ates
|
self.validation = None
|
38 |
db33aecd
|
Benjamin Dauvergne
|
self.holiday = False
|
39 |
49ef7554
|
Jérôme Schneider
|
self.services_names = []
|
40 |
8c0910ce
|
Serghei MIHAI
|
self.event = False
|
41 |
557bc2ea
|
Jérôme Schneider
|
self.__set_time(begin_time)
|
42 |
5f372104
|
Jérôme Schneider
|
|
43 |
557bc2ea
|
Jérôme Schneider
|
def __set_time(self, time):
|
44 |
|
|
self.begin_time = time
|
45 |
|
|
if time:
|
46 |
|
|
self.begin_hour = time.strftime("%H:%M")
|
47 |
|
|
else:
|
48 |
|
|
self.begin_hour = None
|
49 |
c1fa9f24
|
Jérôme Schneider
|
|
50 |
cdf3d9de
|
Mikaël Ates
|
def init_from_event(self, event, service, validation_states=None):
|
51 |
76974b6f
|
Benjamin Dauvergne
|
delta = event.end_datetime - event.start_datetime
|
52 |
17b459a8
|
Serghei MIHAI
|
self.event = not isinstance(event, EventWithAct)
|
53 |
76974b6f
|
Benjamin Dauvergne
|
self.event_id = event.id
|
54 |
557bc2ea
|
Jérôme Schneider
|
self.length = delta.seconds / 60
|
55 |
76974b6f
|
Benjamin Dauvergne
|
self.title = event.title
|
56 |
71647377
|
Jérôme Schneider
|
if (hasattr(event, 'parent') and event.parent.recurrence_periodicity) or \
|
57 |
|
|
event.exception_to:
|
58 |
20cc4488
|
Jérôme Schneider
|
self.is_recurrent = True
|
59 |
76974b6f
|
Benjamin Dauvergne
|
services = event.services.all()
|
60 |
|
|
self.date = event.start_datetime.date()
|
61 |
|
|
self.__set_time(time(event.start_datetime.hour, event.start_datetime.minute))
|
62 |
1cff6363
|
Jérôme Schneider
|
for e_service in services:
|
63 |
49ef7554
|
Jérôme Schneider
|
name = e_service.name.lower().replace(' ', '-')
|
64 |
1cff6363
|
Jérôme Schneider
|
if e_service != service:
|
65 |
|
|
self.other_services_names.append(name)
|
66 |
49ef7554
|
Jérôme Schneider
|
self.services_names.append(name)
|
67 |
1cff6363
|
Jérôme Schneider
|
if service in services:
|
68 |
5f372104
|
Jérôme Schneider
|
self.type = "busy-here"
|
69 |
|
|
else:
|
70 |
|
|
self.type = "busy-elsewhere"
|
71 |
76974b6f
|
Benjamin Dauvergne
|
self.event_id = event.id
|
72 |
dd986559
|
Serghei MIHAI
|
if event.ressource:
|
73 |
|
|
self.ressource = event.ressource.name
|
74 |
76974b6f
|
Benjamin Dauvergne
|
self.description = event.description
|
75 |
5f89e612
|
Jérôme Schneider
|
self.workers_initial = ""
|
76 |
|
|
self.workers_code = []
|
77 |
e6b125bd
|
Mikaël Ates
|
self.workers = event.participants.all()
|
78 |
|
|
self.len_workers = event.participants.count()
|
79 |
|
|
self.workers_absent = event.get_missing_participants()
|
80 |
76974b6f
|
Benjamin Dauvergne
|
if event.event_type.id == 1:
|
81 |
72f229a9
|
Jérôme Schneider
|
self.act_id = event.act.id
|
82 |
ddcbee95
|
Benjamin Dauvergne
|
self.convocation_sent = event.convocation_sent
|
83 |
098ed7bb
|
Benjamin Dauvergne
|
self.patient = event.patient
|
84 |
|
|
self.patient_record_id = event.patient.id
|
85 |
|
|
self.patient_record_paper_id = event.patient.paper_id
|
86 |
|
|
self.act_type = event.act_type.name
|
87 |
17861d43
|
Jérôme Schneider
|
self.is_billed = event.act.is_billed
|
88 |
af0ca53c
|
Mikaël Ates
|
self.already_billed = event.act.already_billed
|
89 |
433b67bb
|
Benjamin Dauvergne
|
state = event.get_state()
|
90 |
|
|
state_name = state.state_name if state else 'NON_VALIDE'
|
91 |
|
|
display_name = VALIDATION_STATES[state_name]
|
92 |
93f0b96d
|
Mikaël Ates
|
if event.is_absent():
|
93 |
4f798ffb
|
Mikaël Ates
|
self.act_absence = VALIDATION_STATES.get(state_name)
|
94 |
433b67bb
|
Benjamin Dauvergne
|
if state and not state.previous_state and state.state_name == 'NON_VALIDE':
|
95 |
2f8649fe
|
Mikaël Ates
|
state = None
|
96 |
cdf3d9de
|
Mikaël Ates
|
if not service in services:
|
97 |
|
|
validation_states = None
|
98 |
6b26af85
|
Mikaël Ates
|
self.validation = (event.act, state, display_name, validation_states)
|
99 |
e90f4c73
|
Jérôme Schneider
|
self.title = event.patient.display_name
|
100 |
1cff6363
|
Jérôme Schneider
|
else:
|
101 |
74231c6d
|
Mikaël Ates
|
if event.event_type.label == 'Autre' and event.title:
|
102 |
|
|
self.title = event.title
|
103 |
|
|
else:
|
104 |
|
|
self.title = '%s' % event.event_type.label
|
105 |
|
|
if event.title:
|
106 |
|
|
self.title += ' - %s' % event.title
|
107 |
76974b6f
|
Benjamin Dauvergne
|
self.event_type = event.event_type
|
108 |
1c8bec2a
|
Jérôme Schneider
|
for worker in self.workers:
|
109 |
|
|
self.workers_code.append("%s-%s" % (worker.id, worker.last_name.upper()))
|
110 |
88abfb2a
|
Jérôme Schneider
|
if not self.description:
|
111 |
|
|
self.description = ''
|
112 |
5f372104
|
Jérôme Schneider
|
|
113 |
557bc2ea
|
Jérôme Schneider
|
def init_free_time(self, length, begin_time):
|
114 |
edae34d7
|
Jérôme Schneider
|
self.type = "free"
|
115 |
|
|
self.length = length
|
116 |
557bc2ea
|
Jérôme Schneider
|
self.__set_time(begin_time)
|
117 |
c1fa9f24
|
Jérôme Schneider
|
|
118 |
344fbdb6
|
Mikaël Ates
|
def init_busy_time(self, title, length, begin_time, description=None):
|
119 |
1eab6c73
|
Frédéric Péters
|
self.title = title
|
120 |
|
|
self.length = length
|
121 |
|
|
self.__set_time(begin_time)
|
122 |
344fbdb6
|
Mikaël Ates
|
self.description = description
|
123 |
edae34d7
|
Jérôme Schneider
|
|
124 |
db33aecd
|
Benjamin Dauvergne
|
def init_holiday_time(self, title, length, begin_time, description=None):
|
125 |
|
|
self.init_busy_time(title, length, begin_time, description)
|
126 |
|
|
self.holiday = True
|
127 |
|
|
|
128 |
63076556
|
Serghei MIHAI
|
def init_start_stop(self, title, time, type):
|
129 |
edae34d7
|
Jérôme Schneider
|
"""
|
130 |
|
|
title: Arrivee ou Depart
|
131 |
|
|
"""
|
132 |
63076556
|
Serghei MIHAI
|
self.type = type
|
133 |
edae34d7
|
Jérôme Schneider
|
self.title = title
|
134 |
557bc2ea
|
Jérôme Schneider
|
self.__set_time(time)
|
135 |
|
|
|
136 |
76974b6f
|
Benjamin Dauvergne
|
def get_daily_appointments(date, worker, service, time_tables, events, holidays):
|
137 |
5f372104
|
Jérôme Schneider
|
"""
|
138 |
|
|
"""
|
139 |
edae34d7
|
Jérôme Schneider
|
appointments = []
|
140 |
dce0454a
|
Serghei MIHAI
|
activity = {'absences': []}
|
141 |
edae34d7
|
Jérôme Schneider
|
|
142 |
2ff5e689
|
Jérôme Schneider
|
timetables_set = IntervalSet((t.to_interval(date) for t in time_tables))
|
143 |
1eab6c73
|
Frédéric Péters
|
holidays_set = IntervalSet((h.to_interval(date) for h in holidays))
|
144 |
e9ed4bdf
|
Benjamin Dauvergne
|
busy_occurrences_set = IntervalSet((o.to_interval() for o in events if not o.is_event_absence()))
|
145 |
5f4c5dd2
|
Frédéric Péters
|
for free_time in timetables_set - (busy_occurrences_set+holidays_set):
|
146 |
2ff5e689
|
Jérôme Schneider
|
if free_time:
|
147 |
|
|
delta = free_time.upper_bound - free_time.lower_bound
|
148 |
|
|
delta_minutes = delta.seconds / 60
|
149 |
|
|
appointment = Appointment()
|
150 |
|
|
appointment.init_free_time(delta_minutes,
|
151 |
e5d0f8c5
|
Jérôme Schneider
|
time(free_time.lower_bound.hour, free_time.lower_bound.minute))
|
152 |
2ff5e689
|
Jérôme Schneider
|
appointments.append(appointment)
|
153 |
cdf3d9de
|
Mikaël Ates
|
validation_states = dict(VALIDATION_STATES)
|
154 |
|
|
if service.name != 'CMPP' and \
|
155 |
|
|
'ACT_DOUBLE' in validation_states:
|
156 |
|
|
validation_states.pop('ACT_DOUBLE')
|
157 |
|
|
vs = [('VALIDE', 'Présent')]
|
158 |
|
|
validation_states.pop('VALIDE')
|
159 |
a50df9c4
|
Mikaël Ates
|
validation_states.pop('ACT_LOST')
|
160 |
cdf3d9de
|
Mikaël Ates
|
validation_states = vs + sorted(validation_states.items(), key=lambda tup: tup[0])
|
161 |
dce0454a
|
Serghei MIHAI
|
|
162 |
|
|
events.sort(key=lambda event: event.start_datetime)
|
163 |
|
|
|
164 |
|
|
# get first and last events start times
|
165 |
|
|
if events:
|
166 |
|
|
activity['first_appointment'], activity['last_appointment'] = (e.start_datetime.time() for e in (events[0], events[-1]))
|
167 |
|
|
|
168 |
76974b6f
|
Benjamin Dauvergne
|
for event in events:
|
169 |
557bc2ea
|
Jérôme Schneider
|
appointment = Appointment()
|
170 |
cdf3d9de
|
Mikaël Ates
|
appointment.init_from_event(event, service, validation_states)
|
171 |
557bc2ea
|
Jérôme Schneider
|
appointments.append(appointment)
|
172 |
1eab6c73
|
Frédéric Péters
|
for holiday in holidays:
|
173 |
|
|
interval = holiday.to_interval(date)
|
174 |
|
|
delta = interval.upper_bound - interval.lower_bound
|
175 |
|
|
delta_minutes = delta.seconds / 60
|
176 |
|
|
appointment = Appointment()
|
177 |
5c9550bf
|
Serghei MIHAI
|
appointment.type = 'busy-here'
|
178 |
e969d52a
|
Serghei MIHAI
|
label = None
|
179 |
|
|
if not holiday.worker:
|
180 |
|
|
label = u"Absence de groupe : %s" % holiday.holiday_type.name
|
181 |
|
|
else:
|
182 |
|
|
label = u"Absence indiv. : %s" % holiday.holiday_type.name
|
183 |
dce0454a
|
Serghei MIHAI
|
|
184 |
db33aecd
|
Benjamin Dauvergne
|
appointment.init_holiday_time(label,
|
185 |
1eab6c73
|
Frédéric Péters
|
delta_minutes,
|
186 |
344fbdb6
|
Mikaël Ates
|
time(interval.lower_bound.hour, interval.lower_bound.minute),
|
187 |
|
|
description=holiday.comment)
|
188 |
dce0454a
|
Serghei MIHAI
|
activity['absences'].append(label)
|
189 |
54e6ef3d
|
Serghei MIHAI
|
services = holiday.services.all()
|
190 |
|
|
if service not in services:
|
191 |
|
|
appointment.type = 'busy-elsewhere'
|
192 |
488c701f
|
Serghei MIHAI
|
appointment.other_services_names = [s.slug for s in services if s != service]
|
193 |
1eab6c73
|
Frédéric Péters
|
appointments.append(appointment)
|
194 |
01b95bad
|
Serghei MIHAI
|
print "time tables: %s" % time_tables
|
195 |
557bc2ea
|
Jérôme Schneider
|
for time_table in time_tables:
|
196 |
1eab6c73
|
Frédéric Péters
|
interval_set = IntervalSet.between(time_table.to_interval(date).lower_bound.time(),
|
197 |
|
|
time_table.to_interval(date).upper_bound.time())
|
198 |
|
|
for holiday in holidays:
|
199 |
|
|
holiday_interval_set = IntervalSet.between(holiday.to_interval(date).lower_bound.time(),
|
200 |
|
|
holiday.to_interval(date).upper_bound.time())
|
201 |
|
|
interval_set = interval_set - holiday_interval_set
|
202 |
|
|
if not interval_set:
|
203 |
|
|
continue
|
204 |
|
|
start_time = interval_set.lower_bound()
|
205 |
|
|
end_time = interval_set.upper_bound()
|
206 |
63076556
|
Serghei MIHAI
|
|
207 |
e3482db9
|
Serghei MIHAI
|
services = time_table.services.all()
|
208 |
|
|
common_service = service in services
|
209 |
|
|
services = [s.slug for s in services if s != service]
|
210 |
|
|
if common_service:
|
211 |
63076556
|
Serghei MIHAI
|
appointment_type = 'info'
|
212 |
e3482db9
|
Serghei MIHAI
|
else:
|
213 |
|
|
appointment_type = 'busy-elsewhere'
|
214 |
557bc2ea
|
Jérôme Schneider
|
appointment = Appointment()
|
215 |
784abc51
|
Serghei MIHAI
|
appointment.other_services_names = services
|
216 |
63076556
|
Serghei MIHAI
|
appointment.init_start_stop(u"Arrivée", start_time, appointment_type)
|
217 |
dce0454a
|
Serghei MIHAI
|
activity['arrival'] = start_time
|
218 |
01b95bad
|
Serghei MIHAI
|
appointment.weight = 1
|
219 |
557bc2ea
|
Jérôme Schneider
|
appointments.append(appointment)
|
220 |
|
|
appointment = Appointment()
|
221 |
63076556
|
Serghei MIHAI
|
appointment.init_start_stop(u"Départ", end_time, appointment_type)
|
222 |
784abc51
|
Serghei MIHAI
|
appointment.other_services_names = services
|
223 |
dce0454a
|
Serghei MIHAI
|
activity['departure'] = end_time
|
224 |
01b95bad
|
Serghei MIHAI
|
appointment.weight = -1
|
225 |
557bc2ea
|
Jérôme Schneider
|
appointments.append(appointment)
|
226 |
5f372104
|
Jérôme Schneider
|
|
227 |
dce0454a
|
Serghei MIHAI
|
return activity, sorted(appointments, key=lambda app: (app.begin_time, app.weight, app.event_id))
|
228 |
197e410c
|
Frédéric Péters
|
|
229 |
|
|
def get_daily_usage(date, ressource, service, occurrences):
|
230 |
|
|
"""
|
231 |
|
|
"""
|
232 |
|
|
appointments = []
|
233 |
|
|
|
234 |
|
|
start_time = datetime_time(8, 0)
|
235 |
|
|
end_time = datetime_time(20, 0)
|
236 |
|
|
all_day = Interval(datetime.combine(date, start_time), datetime.combine(date, end_time))
|
237 |
|
|
timetables_set = IntervalSet([all_day])
|
238 |
|
|
occurrences_set = IntervalSet((o.to_interval() for o in occurrences))
|
239 |
|
|
for free_time in timetables_set - occurrences_set:
|
240 |
|
|
if free_time:
|
241 |
|
|
delta = free_time.upper_bound - free_time.lower_bound
|
242 |
|
|
delta_minutes = delta.seconds / 60
|
243 |
|
|
appointment = Appointment()
|
244 |
|
|
appointment.init_free_time(delta_minutes,
|
245 |
|
|
time(free_time.lower_bound.hour, free_time.lower_bound.minute))
|
246 |
|
|
appointments.append(appointment)
|
247 |
|
|
for occurrence in occurrences:
|
248 |
|
|
appointment = Appointment()
|
249 |
7a742662
|
Jérôme Schneider
|
appointment.init_from_event(occurrence, service)
|
250 |
197e410c
|
Frédéric Péters
|
appointments.append(appointment)
|
251 |
|
|
|
252 |
|
|
return sorted(appointments, key=lambda app: (app.begin_time, app.weight))
|