Project

General

Profile

Download (13.6 KB) Statistics
| Branch: | Tag: | Revision:

calebasse / calebasse / actes / models.py @ a4233531

1
# -*- coding: utf-8 -*-
2
from django.db import models
3
from django.contrib.auth.models import User
4

    
5
import reversion
6

    
7
from calebasse.agenda.models import Event, EventType
8
from calebasse.agenda.managers import EventManager
9
from calebasse.dossiers.models import SessadHealthCareNotification, \
10
    CmppHealthCareDiagnostic, CmppHealthCareTreatment
11
from calebasse.actes.validation import are_all_acts_of_the_day_locked
12

    
13
from validation_states import VALIDATION_STATES, NON_VALIDE
14

    
15

    
16
class ActValidationState(models.Model):
17

    
18
    class Meta:
19
        app_label = 'actes'
20

    
21
    act = models.ForeignKey('actes.Act',
22
        verbose_name=u'Acte', editable=False)
23
    state_name = models.CharField(max_length=150)
24
    created = models.DateTimeField(u'Création', auto_now_add=True)
25
    author = \
26
        models.ForeignKey(User,
27
        verbose_name=u'Auteur', editable=False)
28
    previous_state = models.ForeignKey('ActValidationState',
29
        verbose_name=u'Etat précédent',
30
        editable=False, blank=True, null=True)
31
    # To record if the validation has be done by the automated validation
32
    auto = models.BooleanField(default=False,
33
            verbose_name=u'Vérouillage')
34

    
35
    def __repr__(self):
36
        return self.state_name + ' ' + str(self.created)
37

    
38
    def __unicode__(self):
39
        return VALIDATION_STATES[self.state_name]
40

    
41

    
42
class Act(models.Model):
43
    patient = models.ForeignKey('dossiers.PatientRecord')
44
    date = models.DateTimeField()
45
    act_type = models.ForeignKey('ressources.ActType',
46
            verbose_name=u'Type d\'acte')
47
    validation_locked = models.BooleanField(default=False,
48
            verbose_name=u'Vérouillage')
49
    is_billed = models.BooleanField(default=False,
50
            verbose_name=u'Facturé')
51
    switch_billable = models.BooleanField(default=False,
52
            verbose_name=u'Inverser type facturable')
53
    healthcare = models.ForeignKey('dossiers.HealthCare',
54
            blank=True,
55
            null=True,
56
            verbose_name=u'Prise en charge utilisée pour facturée (CMPP)')
57
    transport_company = models.ForeignKey('ressources.TransportCompany',
58
            blank=True,
59
            null=True,
60
            verbose_name=u'Compagnie de transport')
61
    transport_type = models.ForeignKey('ressources.TransportType',
62
            blank=True,
63
            null=True,
64
            verbose_name=u'Type de transport')
65
    doctors = models.ManyToManyField('personnes.Worker',
66
            limit_choices_to={'type__intervene': True},
67
            verbose_name=u'Thérapeutes')
68

    
69
    def is_absent(self):
70
        if self.get_state() in ('ABS_NON_EXC', 'ABS_EXC', 'ANNUL_NOUS',
71
                'ANNUL_FAMILLE', 'ABS_ESS_PPS', 'ENF_HOSP'):
72
            return True
73

    
74
    def get_state(self):
75
        return self.actvalidationstate_set.latest('created')
76

    
77
    def is_state(self, state_name):
78
        state = self.get_state()
79
        if state and state.state_name == state_name:
80
            return True
81
        return False
82

    
83
    def set_state(self, state_name, author, auto=False,
84
            change_state_check=True):
85
        if not author:
86
            raise Exception('Missing author to set state')
87
        if not state_name in VALIDATION_STATES.keys():
88
            raise Exception("Etat d'acte non existant %s")
89
        current_state = self.get_state()
90
        ActValidationState(act=self, state_name=state_name,
91
            author=author, previous_state=current_state).save()
92

    
93
    def is_billable(self):
94
        if (self.act_type.billable and not self.switch_billable) or \
95
                (not self.act_type.billable and self.switch_billable):
96
            return True
97

    
98
    # START Specific to sessad healthcare
99
    def was_covered_by_notification(self):
100
        notifications = \
101
            SessadHealthCareNotification.objects.filter(patient=self.patient,
102
            start_date__lte=self.date, end_date__gte=self.date)
103
        if notifications:
104
            return True
105
    # END Specific to sessad healthcare
106

    
107
    # START Specific to cmpp healthcare
108
    def is_act_covered_by_diagnostic_healthcare(self):
109
        # L'acte est déja pointé par une prise en charge
110
        if self.is_billed:
111
            # Sinon ce peut une refacturation, donc ne pas tenir compte qu'il
112
            # y est une healthcare non vide
113
            if self.healthcare and isinstance(self.healthcare,
114
                    CmppHealthCareDiagnostic):
115
                return (False, self.healthcare)
116
            elif self.healthcare:
117
                return (False, None)
118
        # L'acte doit être facturable
119
        if not (are_all_acts_of_the_day_locked(self.date) and \
120
                self.is_state('VALIDE') and self.is_billable()):
121
            return (False, None)
122
        # On prend la dernière prise en charge diagnostic, l'acte ne sera pas
123
        # pris en charge sur une prise en charge précédente
124
        # Il peut arriver que l'on ait ajouté une prise en charge de
125
        # traitement alors que tous les actes pour le diag ne sont pas encore facturés
126
        try:
127
            hc = CmppHealthCareDiagnostic.objects.\
128
                filter(patient=self.patient).latest('start_date')
129
        except:
130
            return (False, None)
131
        if not hc:
132
            # On pourrait ici créer une prise en charge de diagnostic
133
            return (False, None)
134
        if self.date < hc.start_date:
135
            return (False, None)
136
        # Les acts facturés déja couvert par la prise en charge sont pointés
137
        # dans hc.act_set.all()
138
        nb_acts_billed = len(hc.act_set.all())
139
        if nb_acts_billed >= hc.get_act_number():
140
            return (False, None)
141
        # Il faut ajouter les actes facturables non encore facturés qui précède cet
142
        # acte
143
        acts_billable = [a for a in self.patient.act_set.\
144
            filter(is_billed=False).order_by('date') \
145
            if are_all_acts_of_the_day_locked(a.date) and \
146
            a.is_state('VALIDE') and a.is_billable()]
147
        count = 0
148
        for a in acts_billable:
149
            if nb_acts_billed + count >= hc.get_act_number():
150
                return (False, None)
151
            if a.date >= hc.start_date:
152
                if a.id == self.id:
153
                    return (True, hc)
154
                count = count + 1
155
        return (False, None)
156

    
157
    def is_act_covered_by_treatment_healthcare(self):
158
        # L'acte est déja pointé par une prise en charge
159
        if self.is_billed:
160
            # Sinon ce peut une refacturation, donc ne pas tenir compte qu'il
161
            # y est une healthcare non vide
162
            if self.healthcare and isinstance(self.healthcare,
163
                    CmppHealthCareTreatment):
164
                return (False, self.healthcare)
165
            elif self.healthcare:
166
                return (False, None)
167
        # L'acte doit être facturable
168
        if not (are_all_acts_of_the_day_locked(self.date) and \
169
                self.is_state('VALIDE') and self.is_billable()):
170
            return (False, None)
171
        # On prend la dernière prise en charge diagnostic, l'acte ne sera pas
172
        # pris en charge sur une prise en charge précédente
173
        # Il peut arriver que l'on ait ajouté une prise en charge de
174
        # traitement alors que tous les actes pour le diag ne sont pas encore facturés
175
        try:
176
            hc = CmppHealthCareTreatment.objects.\
177
                filter(patient=self.patient).latest('start_date')
178
        except:
179
            return (False, None)
180
        if not hc:
181
            return (False, None)
182
        if self.date < hc.start_date or self.date > hc.end_date:
183
            return (False, None)
184
        # Les acts facturés déja couvert par la prise en charge sont pointés
185
        # dans hc.act_set.all()
186
        nb_acts_billed = len(hc.act_set.all())
187
        if nb_acts_billed >= hc.get_act_number():
188
            return (False, None)
189
        # Il faut ajouter les actes facturables non encore facturés qui précède cet
190
        # acte
191
        acts_billable = [a for a in self.patient.act_set.\
192
            filter(is_billed=False).order_by('date') \
193
            if are_all_acts_of_the_day_locked(a.date) and \
194
            a.is_state('VALIDE') and a.is_billable()]
195
        count = 0
196
        for a in acts_billable:
197
            if nb_acts_billed + count >= hc.get_act_number():
198
                return (False, None)
199
            if a.date >= hc.start_date and a.date <= hc.end_date:
200
                if a.id == self.id:
201
                    return (True, hc)
202
                count = count + 1
203
        return (False, None)
204
    # END Specific to cmpp healthcare
205

    
206
    def __unicode__(self):
207
        return '{0} le {1} pour {2} avec {3}'.format(
208
                self.act_type, self.date, self.patient,
209
                ', '.join(map(unicode, self.doctors.all())))
210

    
211
    def __repr__(self):
212
        return '<%s %r %r>' % (self.__class__.__name__, unicode(self), self.id)
213

    
214
    class Meta:
215
        verbose_name = u"Acte"
216
        verbose_name_plural = u"Actes"
217
        ordering = ['-date', 'patient']
218

    
219

    
220
class EventActManager(EventManager):
221

    
222
    def create_patient_appointment(self, creator, title, patient, participants,
223
            act_type, service, start_datetime, end_datetime, description='',
224
            room=None, note=None, **rrule_params):
225
        """
226
        This method allow you to create a new patient appointment quickly
227

    
228
        Args:
229
            title: patient appointment title (str)
230
            patient: Patient object
231
            participants: List of CalebasseUser (therapists)
232
            act_type: ActType object
233
            service: Service object. Use session service by defaut
234
            start_datetime: datetime with the start date and time
235
            end_datetime: datetime with the end date and time
236
            freq, count, until, byweekday, rrule_params:
237
            follow the ``dateutils`` API (see http://labix.org/python-dateutil)
238

    
239
        Example:
240
            Look at calebasse.agenda.tests.EventTest (test_create_appointments
241
            method)
242
        """
243

    
244
        event_type, created = EventType.objects.get_or_create(
245
                label=u"Rendez-vous patient"
246
                )
247

    
248
        act_event = EventAct.objects.create(
249
                title=title,
250
                event_type=event_type,
251
                patient=patient,
252
                act_type=act_type,
253
                date=start_datetime,
254
                )
255
        act_event.doctors = participants
256
        ActValidationState(act=act_event, state_name='NON_VALIDE',
257
            author=creator, previous_state=None).save()
258

    
259
        return self._set_event(act_event, participants, description,
260
                services=[service], start_datetime=start_datetime,
261
                end_datetime=end_datetime,
262
                room=room, note=note, **rrule_params)
263

    
264
    def modify_patient_appointment(self, creator, title, patient, participants,
265
            act_type, service, start_datetime, end_datetime, description='',
266
            room=None, note=None, **rrule_params):
267
        """
268
        This method allow you to create a new patient appointment quickly
269

    
270
        Args:
271
            creator: author of the modification
272
            title: patient appointment title (str)
273
            patient: Patient object
274
            participants: List of CalebasseUser (therapists)
275
            act_type: ActType object
276
            service: Service object. Use session service by defaut
277
            start_datetime: datetime with the start date and time
278
            end_datetime: datetime with the end date and time
279
            description: description of the event
280
            room: room where the event will take place
281
            freq, count, until, byweekday, rrule_params:
282
            follow the ``dateutils`` API (see http://labix.org/python-dateutil)
283

    
284
        Example:
285
            Look at calebasse.agenda.tests.EventTest (test_create_appointments
286
            method)
287
        """
288

    
289
        event_type, created = EventType.objects.get_or_create(
290
                label=u"Rendez-vous patient"
291
                )
292

    
293
        act_event = EventAct.objects.create(
294
                title=title,
295
                event_type=event_type,
296
                patient=patient,
297
                act_type=act_type,
298
                date=start_datetime,
299
                )
300
        act_event.doctors = participants
301
        ActValidationState(act=act_event, state_name=NON_VALIDE,
302
            author=creator, previous_state=None).save()
303

    
304
        return self._set_event(act_event, participants, description,
305
                services=[service], start_datetime=start_datetime,
306
                end_datetime=end_datetime,
307
                room=room, note=note, **rrule_params)
308

    
309
class EventAct(Act, Event):
310
    objects = EventActManager()
311

    
312
    VALIDATION_CODE_CHOICES = (
313
            ('absent', u'Absent'),
314
            ('present', u'Présent'),
315
            )
316
    attendance = models.CharField(max_length=16,
317
            choices=VALIDATION_CODE_CHOICES,
318
            default='absent',
319
            verbose_name=u'Présence')
320
    convocation_sent = models.BooleanField(blank=True,
321
            verbose_name=u'Convoqué')
322

    
323
    def __unicode__(self):
324
        return 'Rdv le {0} de {1} avec {2} pour {3}'.format(
325
                self.occurrence_set.all()[0].start_time, self.patient,
326
                ', '.join(map(unicode, self.participants.all())),
327
                self.act_type)
328

    
329
    def __repr__(self):
330
        return '<%s %r %r>' % (self.__class__.__name__, unicode(self),
331
            self.id)
332

    
333
    def start_time(self):
334
        return self.occurrence_set.all()[0].start_time
335

    
336
    def duration(self):
337
        o = self.occurrence_set.all()[0]
338
        td = o.end_time - o.start_time
339
        hours, remainder = divmod(td.seconds, 3600)
340
        minutes, remainder = divmod(remainder, 60)
341
        return '%02d:%02d' % (hours, minutes)
342

    
343
    class Meta:
344
        verbose_name = 'Rendez-vous patient'
345
        verbose_name_plural = 'Rendez-vous patient'
346
        ordering = ['-date', 'patient']
347

    
348
reversion.register(EventAct, follow=['act_ptr', 'event_ptr'])
(4-4/9)