Project

General

Profile

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

calebasse / calebasse / dossiers / models.py @ 0259c7ef

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

    
3
import logging
4

    
5
from datetime import datetime
6
from datetime import timedelta
7

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

    
12
import reversion
13

    
14
from calebasse.models import PhoneNumberField, ZipCodeField
15
from calebasse.personnes.models import People
16
from calebasse.ressources.models import (ServiceLinkedAbstractModel,
17
    NamedAbstractModel, Service)
18
from calebasse.actes.validation import are_all_acts_of_the_day_locked
19

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

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

    
27

    
28
class HealthCare(models.Model):
29

    
30
    class Meta:
31
        app_label = 'dossiers'
32

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

    
42

    
43
class CmppHealthCareDiagnostic(HealthCare):
44

    
45
    class Meta:
46
        app_label = 'dossiers'
47

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

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

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

    
59

    
60
class CmppHealthCareTreatment(HealthCare):
61

    
62
    class Meta:
63
        app_label = 'dossiers'
64

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

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

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

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

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

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

    
97

    
98
class SessadHealthCareNotification(HealthCare):
99

    
100
    class Meta:
101
        app_label = 'dossiers'
102

    
103
    end_date = models.DateTimeField()
104

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

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

    
118
class Status(NamedAbstractModel):
119

    
120
    class Meta:
121
        app_label = 'dossiers'
122
        verbose_name = u"Statut d'un état"
123
        verbose_name_plural = u"Statuts d'un état"
124

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

    
128
class AnalyseMotive(NamedAbstractModel):
129
    class Meta:
130
        verbose_name = u"Motif analysé"
131
        verbose_name_plural = u"Motifs analysés"
132

    
133
class FamillyMotive(NamedAbstractModel):
134
    class Meta:
135
        verbose_name = u"Motif familiale"
136
        verbose_name_plural = u"Motifs familiaux"
137

    
138
class AdviceGiver(NamedAbstractModel):
139
    class Meta:
140
        verbose_name = u"Conseilleur"
141
        verbose_name_plural = u"Conseilleurs"
142

    
143
class ParentalAuthority(NamedAbstractModel):
144
    class Meta:
145
        verbose_name = u"Autorité parentale"
146
        verbose_name_plural = u"Autorités parentales"
147

    
148
class FamillySituation(NamedAbstractModel):
149
    class Meta:
150
        verbose_name = u"Situation familiale"
151
        verbose_name_plural = u"Situations familiales"
152

    
153
class ChildCustody(NamedAbstractModel):
154
    class Meta:
155
        verbose_name = u"Garde parentale"
156
        verbose_name_plural = u"Gardes parentales"
157

    
158
class FileState(models.Model):
159

    
160
    class Meta:
161
        app_label = 'dossiers'
162
        verbose_name = u'Etat du dossier patient'
163
        verbose_name_plural = u'Etats du dossier patient'
164

    
165
    patient = models.ForeignKey('dossiers.PatientRecord',
166
        verbose_name=u'Dossier patient')
167
    status = models.ForeignKey('dossiers.Status')
168
    created = models.DateTimeField(u'Création', auto_now_add=True)
169
    date_selected = models.DateTimeField()
170
    author = \
171
        models.ForeignKey(User,
172
        verbose_name=u'Auteur')
173
    comment = models.TextField(max_length=3000, blank=True, null=True)
174
    previous_state = models.ForeignKey('FileState',
175
        verbose_name=u'Etat précédent', blank=True, null=True)
176

    
177
    def get_next_state(self):
178
        try:
179
            return FileState.objects.get(previous_state=self)
180
        except:
181
            return None
182

    
183
    def save(self, **kwargs):
184
        self.date_selected = \
185
                datetime(self.date_selected.year,
186
                        self.date_selected.month, self.date_selected.day)
187
        super(FileState, self).save(**kwargs)
188

    
189
    def __unicode__(self):
190
        return self.status.name + ' ' + str(self.date_selected)
191

    
192
class PatientAddress(models.Model):
193

    
194
    def __unicode__(self):
195
        return self.address + ', ' + self.city
196

    
197
    phone = PhoneNumberField(verbose_name=u"Téléphone", blank=True, null=True)
198
    fax = PhoneNumberField(verbose_name=u"Fax", blank=True, null=True)
199
    address = models.CharField(max_length=120,
200
            verbose_name=u"Adresse")
201
    address_complement = models.CharField(max_length=120,
202
            blank=True,
203
            null=True,
204
            default=None,
205
            verbose_name=u"Complément d'addresse")
206
    zip_code = ZipCodeField(verbose_name=u"Code postal")
207
    city = models.CharField(max_length=80,
208
            verbose_name=u"Ville")
209

    
210
class PatientContact(People):
211
    class Meta:
212
        verbose_name = u'Contact patient'
213
        verbose_name_plural = u'Contacts patient'
214

    
215
    mobile = PhoneNumberField(verbose_name=u"Téléphone mobile", blank=True, null=True)
216
    email = models.EmailField(blank=True, null=True)
217
    social_security_id = models.CharField(max_length=13, verbose_name=u"Numéro de sécurité sociale")
218
    addresses = models.ManyToManyField('PatientAddress', verbose_name=u"Adresses",
219
            blank=True, null=True)
220

    
221

    
222
class PatientRecord(ServiceLinkedAbstractModel, PatientContact):
223
    class Meta:
224
        verbose_name = u'Dossier'
225
        verbose_name_plural = u'Dossiers'
226

    
227
    created = models.DateTimeField(u'création', auto_now_add=True)
228
    creator = \
229
        models.ForeignKey(User,
230
        verbose_name=u'Créateur dossier patient',
231
        editable=True)
232
    contacts = models.ManyToManyField('personnes.People',
233
            related_name='contact_of')
234
    birthdate = models.DateField(verbose_name=u"Date de naissance",
235
            null=True, blank=True)
236
    nationality = models.CharField(verbose_name=u"Nationalité",
237
            max_length=70, null=True, blank=True)
238
    paper_id = models.CharField(max_length=12,
239
            null=True, blank=True)
240
    last_state = models.ForeignKey(FileState, related_name='+',
241
            null=True)
242
    school = models.ForeignKey('ressources.School',
243
            null=True, blank=True, default=None)
244
    comment = models.TextField(verbose_name=u"Commentaire",
245
            null=True, blank=True, default=None)
246
    pause = models.BooleanField(verbose_name=u"Pause facturation",
247
            default=False)
248

    
249
    # Physiology
250
    size = models.IntegerField(verbose_name=u"Taille (cm)",
251
            null=True, blank=True, default=None)
252
    weight = models.IntegerField(verbose_name=u"Poids (kg)",
253
            null=True, blank=True, default=None)
254
    pregnancy_term = models.IntegerField(verbose_name=u"Terme en semaines",
255
            null=True, blank=True, default=None)
256

    
257
    # Inscription motive
258
    analyse_motive = models.ForeignKey('AnalyseMotive',
259
            verbose_name=u"Motif (analysé)",
260
            null=True, blank=True, default=None)
261
    familly_motive = models.ForeignKey('FamillyMotive',
262
            verbose_name=u"Motif (famille)",
263
            null=True, blank=True, default=None)
264
    advice_giver = models.ForeignKey('AdviceGiver',
265
            verbose_name=u"Conseilleur",
266
            null=True, blank=True, default=None)
267

    
268
    # Familly
269
    sibship_place = models.IntegerField(verbose_name=u"Place dans la fratrie",
270
            null=True, blank=True, default=None)
271
    nb_children_family = models.IntegerField(verbose_name=u"Nombre d'enfants dans la fratrie",
272
            null=True, blank=True, default=None)
273
    twinning_rank = models.IntegerField(verbose_name=u"Rang (gémellité)",
274
            null=True, blank=True, default=None)
275
    parental_authority = models.ForeignKey('ParentalAuthority',
276
            verbose_name=u"Autorité parentale",
277
            null=True, blank=True, default=None)
278
    familly_situation = models.ForeignKey('FamillySituation',
279
            verbose_name=u"Situation familiale",
280
            null=True, blank=True, default=None)
281
    child_custody = models.ForeignKey('ChildCustody',
282
            verbose_name=u"Garde parentale",
283
            null=True, blank=True, default=None)
284

    
285
    def __init__(self, *args, **kwargs):
286
        super(PatientRecord, self).__init__(*args, **kwargs)
287
        if not hasattr(self, 'service'):
288
            raise Exception('The field service is mandatory.')
289

    
290
    def get_state(self):
291
        return self.last_state
292

    
293
    def get_state_at_day(self, date):
294
        state = self.get_state()
295
        while(state):
296
            if datetime(state.date_selected.year,
297
                    state.date_selected.month, state.date_selected.day) <= \
298
                    datetime(date.year, date.month, date.day):
299
                return state
300
            state = state.previous_state
301
        return None
302

    
303
    def was_in_state_at_day(self, date, status_type):
304
        state_at_day = self.get_state_at_day(date)
305
        if state_at_day and state_at_day.status.type == status_type:
306
            return True
307
        return False
308

    
309
    def get_states_history(self):
310
        return self.filestate_set.order_by('date_selected')
311

    
312
    def set_state(self, status, author, date_selected=None, comment=None):
313
        if not author:
314
            raise Exception('Missing author to set state')
315
        if not date_selected:
316
            date_selected = datetime.now()
317
        current_state = self.get_state()
318
        if not current_state:
319
            raise Exception('Invalid patient record. '
320
                'Missing current state.')
321
        if date_selected < current_state.date_selected:
322
            raise Exception('You cannot set a state starting the %s that '
323
                'is before the previous state starting at day %s.' % \
324
                (str(date_selected), str(current_state.date_selected)))
325
        filestate = FileState.objects.create(patient=self, status=status,
326
            date_selected=date_selected, author=author, comment=comment,
327
            previous_state=current_state)
328
        self.last_state = filestate
329
        self.save()
330

    
331
    def change_day_selected_of_state(self, state, new_date):
332
        if state.previous_state:
333
            if new_date < state.previous_state.date_selected:
334
                raise Exception('You cannot set a state starting the %s '
335
                    'before the previous state starting at day %s.' % \
336
                    (str(new_date), str(state.previous_state.date_selected)))
337
        next_state = state.get_next_state()
338
        if next_state:
339
            if new_date > next_state.date_selected:
340
                raise Exception('You cannot set a state starting the %s '
341
                    'after the following state starting at day %s.' % \
342
                    (str(new_date), str(next_state.date_selected)))
343
        state.date_selected = new_date
344
        state.save()
345

    
346
    def remove_state(self, state):
347
        if state.patient.id != self.id:
348
            raise Exception('The state given is not about this patient '
349
                'record but about %s' % state.patient)
350
        next_state = state.get_next_state()
351
        if not next_state:
352
            self.remove_last_state()
353
        else:
354
            next_state.previous_state = state.previous_state
355
            next_state.save()
356
            state.delete()
357

    
358
    def remove_last_state(self):
359
        try:
360
            self.get_state().delete()
361
        except:
362
            pass
363

    
364
    # START Specific to sessad healthcare
365
    def get_last_notification(self):
366
        return SessadHealthCareNotification.objects.filter(patient=self, ).\
367
            latest('end_date')
368

    
369
    def days_before_notification_expiration(self):
370
        today = datetime.today()
371
        notification = self.get_last_notification(self)
372
        if not notification:
373
            return 0
374
        if notification.end_date < today:
375
            return 0
376
        else:
377
            return notification.end_date - today
378
    # END Specific to sessad healthcare
379

    
380
    # START Specific to cmpp healthcare
381
    def create_diag_healthcare(self, modifier):
382
        """
383
            Gestion de l'inscription automatique.
384

    
385
            Si un premier acte est validé alors une prise en charge
386
            diagnostique est ajoutée. Cela fera basculer le dossier dans l'état
387
            en diagnostic.
388

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

    
395
        """
396
        acts = self.act_set.order_by('date')
397
        hcs = self.healthcare_set.order_by('-start_date')
398
        if not hcs:
399
            # Pas de prise en charge, on recherche l'acte facturable le plus
400
            # ancien, on crée une pc diag à la même date.
401
            for act in acts:
402
                if are_all_acts_of_the_day_locked(act.date) and \
403
                        act.is_state('VALIDE') and act.is_billable():
404
                    CmppHealthCareDiagnostic(patient=self, author=modifier,
405
                        start_date=act.date).save()
406
                    break
407
        else:
408
            # On recherche l'acte facturable non facturé le plus ancien et
409
            # l'on regarde s'il a plus d'un an
410
            try:
411
                last_billed_act = self.act_set.filter(is_billed=True).\
412
                    latest('date')
413
                if last_billed_act:
414
                    for act in acts:
415
                        if are_all_acts_of_the_day_locked(act.date) and \
416
                                act.is_state('VALIDE') and \
417
                                act.is_billable() and \
418
                                (act.date - last_billed_act.date).days >= 365:
419
                            CmppHealthCareDiagnostic(patient=self,
420
                                author=modifier, start_date=act.date).save()
421
                            break
422
            except:
423
                pass
424

    
425
    def automated_switch_state(self, modifier):
426
        # Quel est le dernier acte facturable.
427
        acts = self.act_set.order_by('-date')
428
        # Si cet acte peut-être pris en charge en diagnostic c'est un acte de
429
        # diagnostic, sinon c'est un acte de traitement.
430
        last_state_services = self.last_state.status.\
431
                services.values_list('name', flat=True)
432
        cmpp = Service.objects.get(name='CMPP')
433
        for act in acts:
434
            if are_all_acts_of_the_day_locked(act.date) and \
435
                    act.is_state('VALIDE') and act.is_billable():
436
                cared, hc = act.is_act_covered_by_diagnostic_healthcare()
437
                if hc:
438
                    if (self.last_state.status.type == "ACCUEIL" \
439
                            or self.last_state.status.type == "TRAITEMENT") \
440
                            and "CMPP" in last_state_services:
441
                        status = Status.objects.filter(type="DIAGNOSTIC").\
442
                                filter(services__name='CMPP')[0]
443
                        self.set_state(status, modifier,
444
                            date_selected=act.date)
445
                # Sinon, si le dossier est en diag, s'il ne peut être couvert
446
                # en diag, il est en traitement.
447
                elif self.last_state.status.type == "DIAGNOSTIC" and \
448
                        "CMPP" in last_state_services:
449
                    status = Status.objects.filter(type="TRAITEMENT").\
450
                            filter(services__name='CMPP')[0]
451
                    self.set_state(status, modifier,
452
                            date_selected=act.date)
453
                break
454
    # END Specific to cmpp healthcare
455

    
456
reversion.register(PatientRecord, follow=['people_ptr'])
457

    
458

    
459
def create_patient(first_name, last_name, service, creator,
460
        date_selected=None):
461
    logger.debug('create_patient: creation for patient %s %s in service %s '
462
        'by %s' % (first_name, last_name, service, creator))
463
    if not (first_name and last_name and service and creator):
464
        raise Exception('Missing parameter to create a patient record.')
465
    status = Status.objects.filter(type="ACCUEIL").filter(services=service)
466
    if not status:
467
        raise Exception('%s has no ACCEUIL status' % service.name)
468
    patient = PatientRecord.objects.create(first_name=first_name,
469
            last_name=last_name, service=service,
470
            creator=creator)
471
    fs = FileState(status=status[0], author=creator, previous_state=None)
472
    if not date_selected:
473
        date_selected = patient.created
474
    fs.patient = patient
475
    fs.date_selected = date_selected
476
    fs.save()
477
    patient.last_state = fs
478
    patient.save()
479
    return patient
480

    
(4-4/8)