Project

General

Profile

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

calebasse / calebasse / dossiers / models.py @ 7948e4a4

1
# -*- coding: utf-8 -*-
2

    
3
import logging
4

    
5
from datetime import datetime
6
from datetime import timedelta
7

    
8
from django.db import models
9
from django.contrib.auth.models import User
10

    
11
import reversion
12

    
13
from calebasse.personnes.models import People
14
from calebasse.ressources.models import (ServiceLinkedAbstractModel,
15
    NamedAbstractModel, Service)
16
#from calebasse.dossiers.states import STATES, STATE_ACCUEIL
17
from calebasse.actes.validation import are_all_acts_of_the_day_locked
18

    
19
DEFAULT_ACT_NUMBER_DIAGNOSTIC = 6
20
DEFAULT_ACT_NUMBER_TREATMENT = 30
21
DEFAULT_ACT_NUMBER_PROLONGATION = 10
22
VALIDITY_PERIOD_TREATMENT_HEALTHCARE = 365
23

    
24
logger = logging.getLogger('calebasse.dossiers')
25

    
26

    
27
class HealthCare(models.Model):
28

    
29
    class Meta:
30
        app_label = 'dossiers'
31

    
32
    patient = models.ForeignKey('dossiers.PatientRecord',
33
        verbose_name=u'Dossier patient', editable=False)
34
    created = models.DateTimeField(u'Création', auto_now_add=True)
35
    author = \
36
        models.ForeignKey(User,
37
        verbose_name=u'Auteur', editable=False)
38
    comment = models.TextField(max_length=3000, blank=True, null=True)
39
    start_date = models.DateTimeField()
40

    
41

    
42
class CmppHealthCareDiagnostic(HealthCare):
43

    
44
    class Meta:
45
        app_label = 'dossiers'
46

    
47
    _act_number = models.IntegerField(default=DEFAULT_ACT_NUMBER_DIAGNOSTIC)
48

    
49
    def get_act_number(self):
50
        return self._act_number
51

    
52
    def save(self, **kwargs):
53
        self.start_date = \
54
            datetime(self.start_date.year, self.start_date.month,
55
                self.start_date.day)
56
        super(CmppHealthCareDiagnostic, self).save(**kwargs)
57

    
58

    
59
class CmppHealthCareTreatment(HealthCare):
60

    
61
    class Meta:
62
        app_label = 'dossiers'
63

    
64
    _act_number = models.IntegerField(default=DEFAULT_ACT_NUMBER_TREATMENT)
65
    end_date = models.DateTimeField()
66
    prolongation = models.IntegerField(default=0,
67
            verbose_name=u'Prolongation')
68

    
69
    def get_act_number(self):
70
        if self.is_extended():
71
            return self._act_number + self.prolongation
72
        return self._act_number
73

    
74
    def is_extended(self):
75
        if self.prolongation > 0:
76
            return True
77
        return False
78

    
79
    def add_prolongation(self, value=None):
80
        if not value:
81
            value = DEFAULT_ACT_NUMBER_PROLONGATION
82
        if self.is_extended():
83
            raise Exception(u'Prise en charge déja prolongée')
84
        self.prolongation = value
85
        self.save()
86

    
87
    def save(self, **kwargs):
88
        self.start_date = \
89
            datetime(self.start_date.year, self.start_date.month,
90
                self.start_date.day)
91
        self.end_date = self.start_date + \
92
            timedelta(days=VALIDITY_PERIOD_TREATMENT_HEALTHCARE)
93

    
94
        super(CmppHealthCareTreatment, self).save(**kwargs)
95

    
96

    
97
class SessadHealthCareNotification(HealthCare):
98

    
99
    class Meta:
100
        app_label = 'dossiers'
101

    
102
    end_date = models.DateTimeField()
103

    
104
    def save(self, **kwargs):
105
        self.start_date = \
106
            datetime(self.start_date.year, self.start_date.month,
107
                self.start_date.day)
108
        self.end_date = \
109
            datetime(self.end_date.year, self.end_date.month,
110
                self.end_date.day)
111
        super(SessadHealthCareNotification, self).save(**kwargs)
112

    
113
reversion.register(CmppHealthCareDiagnostic, follow=['healthcare_ptr'])
114
reversion.register(CmppHealthCareTreatment, follow=['healthcare_ptr'])
115
reversion.register(SessadHealthCareNotification, follow=['healthcare_ptr'])
116

    
117
class Status(NamedAbstractModel):
118

    
119
    class Meta:
120
        app_label = 'dossiers'
121
        verbose_name = u'Etat'
122
        verbose_name_plural = u'Etats'
123

    
124
    type = models.CharField(max_length=80)
125
    services = models.ManyToManyField('ressources.Service')
126

    
127
class FileState(models.Model):
128

    
129
    class Meta:
130
        app_label = 'dossiers'
131
        verbose_name = u'Etat du dossier patient'
132
        verbose_name_plural = u'Etats du dossier patient'
133

    
134
    patient = models.ForeignKey('dossiers.PatientRecord',
135
        verbose_name=u'Dossier patient')
136
    status = models.ForeignKey('dossiers.Status')
137
    created = models.DateTimeField(u'Création', auto_now_add=True)
138
    date_selected = models.DateTimeField()
139
    author = \
140
        models.ForeignKey(User,
141
        verbose_name=u'Auteur')
142
    comment = models.TextField(max_length=3000, blank=True, null=True)
143
    previous_state = models.ForeignKey('FileState',
144
        verbose_name=u'Etat précédent', blank=True, null=True)
145

    
146
    def get_next_state(self):
147
        try:
148
            return FileState.objects.get(previous_state=self)
149
        except:
150
            return None
151

    
152
    def save(self, **kwargs):
153
        self.date_selected = \
154
            datetime(self.date_selected.year,
155
                self.date_selected.month, self.date_selected.day)
156
        super(FileState, self).save(**kwargs)
157

    
158
    def __unicode__(self):
159
        return self.state_name + ' ' + str(self.date_selected)
160

    
161

    
162
class PatientRecord(ServiceLinkedAbstractModel, People):
163
    class Meta:
164
        verbose_name = u'Dossier'
165
        verbose_name_plural = u'Dossiers'
166

    
167
    created = models.DateTimeField(u'création', auto_now_add=True)
168
    creator = \
169
        models.ForeignKey(User,
170
        verbose_name=u'Créateur dossier patient',
171
        editable=True)
172
    contacts = models.ManyToManyField('personnes.People',
173
            related_name='contact_of')
174
    birthdate = models.DateField(null=True, blank=True)
175
    paper_id = models.CharField(max_length=12,
176
            null=True, blank=True)
177
    social_security_id = models.CharField(max_length=13)
178
    last_state = models.ForeignKey(FileState, related_name='+')
179

    
180
    def __init__(self, *args, **kwargs):
181
        super(PatientRecord, self).__init__(*args, **kwargs)
182
        if not hasattr(self, 'service'):
183
            raise Exception('The field service is mandatory.')
184

    
185
    def get_state(self):
186
        return self.last_state
187

    
188
    def get_state_at_day(self, date):
189
        state = self.get_state()
190
        while(state):
191
            if datetime(state.date_selected.year,
192
                    state.date_selected.month, state.date_selected.day) <= \
193
                    datetime(date.year, date.month, date.day):
194
                return state
195
            state = state.previous_state
196
        return None
197

    
198
    def was_in_state_at_day(self, date, state_name):
199
        state_at_day = self.get_state_at_day(date)
200
        if state_at_day and state_at_day.state_name == state_name:
201
            return True
202
        return False
203

    
204
    def get_states_history(self):
205
        return self.filestate_set.order_by('date_selected')
206

    
207
    def set_state(self, status, author, date_selected=None, comment=None):
208
        if not author:
209
            raise Exception('Missing author to set state')
210
        if not date_selected:
211
            date_selected = datetime.now()
212
        current_state = self.get_state()
213
        if not current_state:
214
            raise Exception('Invalid patient record. '
215
                'Missing current state.')
216
        if date_selected < current_state.date_selected:
217
            raise Exception('You cannot set a state starting the %s that '
218
                'is before the previous state starting at day %s.' % \
219
                (str(date_selected), str(current_state.date_selected)))
220
        filestate = FileState.objects.create(patient=self, status=status,
221
            date_selected=date_selected, author=author, comment=comment,
222
            previous_state=current_state)
223
        self.last_state = filestate
224
        self.save()
225

    
226
    def change_day_selected_of_state(self, state, new_date):
227
        if state.previous_state:
228
            if new_date < state.previous_state.date_selected:
229
                raise Exception('You cannot set a state starting the %s '
230
                    'before the previous state starting at day %s.' % \
231
                    (str(new_date), str(state.previous_state.date_selected)))
232
        next_state = state.get_next_state()
233
        if next_state:
234
            if new_date > next_state.date_selected:
235
                raise Exception('You cannot set a state starting the %s '
236
                    'after the following state starting at day %s.' % \
237
                    (str(new_date), str(next_state.date_selected)))
238
        state.date_selected = new_date
239
        state.save()
240

    
241
    def remove_state(self, state):
242
        if state.patient.id != self.id:
243
            raise Exception('The state given is not about this patient '
244
                'record but about %s' % state.patient)
245
        next_state = state.get_next_state()
246
        if not next_state:
247
            self.remove_last_state()
248
        else:
249
            next_state.previous_state = state.previous_state
250
            next_state.save()
251
            state.delete()
252

    
253
    def remove_last_state(self):
254
        try:
255
            self.get_state().delete()
256
        except:
257
            pass
258

    
259
    # START Specific to sessad healthcare
260
    def get_last_notification(self):
261
        return SessadHealthCareNotification.objects.filter(patient=self, ).\
262
            latest('end_date')
263

    
264
    def days_before_notification_expiration(self):
265
        today = datetime.today()
266
        notification = self.get_last_notification(self)
267
        if not notification:
268
            return 0
269
        if notification.end_date < today:
270
            return 0
271
        else:
272
            return notification.end_date - today
273
    # END Specific to sessad healthcare
274

    
275
    # START Specific to cmpp healthcare
276
    def create_diag_healthcare(self, modifier):
277
        """
278
            Gestion de l'inscription automatique.
279

    
280
            Si un premier acte est validé alors une prise en charge
281
            diagnostique est ajoutée. Cela fera basculer le dossier dans l'état
282
            en diagnostic.
283

    
284
            A voir si auto ou manuel :
285
            Si ce n'est pas le premier acte validé mais que l'acte précédement
286
            facturé a plus d'un an, on peut créer une prise en charge
287
            diagnostique. Même s'il y a une prise en charge de traitement
288
            expirée depuis moins d'un an donc renouvelable.
289

    
290
        """
291
        acts = self.act_set.order_by('date')
292
        hcs = self.healthcare_set.order_by('-start_date')
293
        if not hcs:
294
            # Pas de prise en charge, on recherche l'acte facturable le plus
295
            # ancien, on crée une pc diag à la même date.
296
            for act in acts:
297
                if are_all_acts_of_the_day_locked(act.date) and \
298
                        act.is_state('VALIDE') and act.is_billable():
299
                    CmppHealthCareDiagnostic(patient=self, author=modifier,
300
                        start_date=act.date).save()
301
                    break
302
        else:
303
            # On recherche l'acte facturable non facturé le plus ancien et
304
            # l'on regarde s'il a plus d'un an
305
            try:
306
                last_billed_act = self.act_set.filter(is_billed=True).\
307
                    latest('date')
308
                if last_billed_act:
309
                    for act in acts:
310
                        if are_all_acts_of_the_day_locked(act.date) and \
311
                                act.is_state('VALIDE') and \
312
                                act.is_billable() and \
313
                                (act.date - last_billed_act.date).days >= 365:
314
                            CmppHealthCareDiagnostic(patient=self,
315
                                author=modifier, start_date=act.date).save()
316
                            break
317
            except:
318
                pass
319

    
320
    def automated_switch_state(self, modifier):
321
        # Quel est le dernier acte facturable.
322
        acts = self.act_set.order_by('-date')
323
        # Si cet acte peut-être pris en charge en diagnostic c'est un acte de
324
        # diagnostic, sinon c'est un acte de traitement.
325
        last_state_services = self.last_state.status.\
326
                services.values_list('name', flat=True)
327
        cmpp = Service.objects.get(name='CMPP')
328
        for act in acts:
329
            if are_all_acts_of_the_day_locked(act.date) and \
330
                    act.is_state('VALIDE') and act.is_billable():
331
                cared, hc = act.is_act_covered_by_diagnostic_healthcare()
332
                if hc:
333
                    if (self.last_state.status.type == "ACCEUIL" \
334
                            or self.last_state.status.type == "TRAITMENT") \
335
                            and "CMPP" in last_state_services:
336
                        status = Status.objects.filter(type="DIAGNOSTIC").\
337
                                filter(services__name='CMPP')[0]
338
                        self.set_state(status, modifier,
339
                            date_selected=act.date)
340
                # Sinon, si le dossier est en diag, s'il ne peut être couvert
341
                # en diag, il est en traitement.
342
                elif self.last_state.status.type == "DIAGNOSTIC" and \
343
                        "CMPP" in last_state_services:
344
                    status = Status.objects.filter(type="TRAITMENT").\
345
                            filter(services__name='CMPP')[0]
346
                    self.set_state(status, modifier,
347
                            date_selected=act.date)
348
                break
349
    # END Specific to cmpp healthcare
350

    
351
reversion.register(PatientRecord, follow=['people_ptr'])
352

    
353

    
354
def create_patient(first_name, last_name, service, creator,
355
        date_selected=None):
356
    logger.debug('create_patient: creation for patient %s %s in service %s '
357
        'by %s' % (first_name, last_name, service, creator))
358
    if not (first_name and last_name and service and creator):
359
        raise Exception('Missing parameter to create a patient record.')
360
    patient = PatientRecord(first_name=first_name, last_name=last_name,
361
        service=service, creator=creator)
362
    patient.save()
363
    if not date_selected:
364
        date_selected = patient.created
365
    status = Status.object.filter(type="ACCUEIL").filter(services__name=service)
366
    if not status:
367
        raise Exception('%s has no ACCEUIL status' % service.name)
368
    FileState(patient=patient, status=status[0],
369
        date_selected=date_selected, author=creator,
370
        previous_state=None).save()
371
    return patient
(4-4/8)