Project

General

Profile

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

calebasse / calebasse / dossiers / models.py @ 3e915eb3

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 PatientRecordManager(models.Manager):
223
    def for_service(self, service):
224
        return self.filter(service=service)
225

    
226
class PatientRecord(ServiceLinkedAbstractModel, PatientContact):
227
    objects = PatientRecordManager()
228

    
229
    class Meta:
230
        verbose_name = u'Dossier'
231
        verbose_name_plural = u'Dossiers'
232

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

    
255
    # Physiology
256
    size = models.IntegerField(verbose_name=u"Taille (cm)",
257
            null=True, blank=True, default=None)
258
    weight = models.IntegerField(verbose_name=u"Poids (kg)",
259
            null=True, blank=True, default=None)
260
    pregnancy_term = models.IntegerField(verbose_name=u"Terme en semaines",
261
            null=True, blank=True, default=None)
262

    
263
    # Inscription motive
264
    analyse_motive = models.ForeignKey('AnalyseMotive',
265
            verbose_name=u"Motif (analysé)",
266
            null=True, blank=True, default=None)
267
    familly_motive = models.ForeignKey('FamillyMotive',
268
            verbose_name=u"Motif (famille)",
269
            null=True, blank=True, default=None)
270
    advice_giver = models.ForeignKey('AdviceGiver',
271
            verbose_name=u"Conseilleur",
272
            null=True, blank=True, default=None)
273

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

    
291
    def __init__(self, *args, **kwargs):
292
        super(PatientRecord, self).__init__(*args, **kwargs)
293
        if not hasattr(self, 'service'):
294
            raise Exception('The field service is mandatory.')
295

    
296
    def get_state(self):
297
        return self.last_state
298

    
299
    def get_state_at_day(self, date):
300
        state = self.get_state()
301
        while(state):
302
            if datetime(state.date_selected.year,
303
                    state.date_selected.month, state.date_selected.day) <= \
304
                    datetime(date.year, date.month, date.day):
305
                return state
306
            state = state.previous_state
307
        return None
308

    
309
    def was_in_state_at_day(self, date, status_type):
310
        state_at_day = self.get_state_at_day(date)
311
        if state_at_day and state_at_day.status.type == status_type:
312
            return True
313
        return False
314

    
315
    def get_states_history(self):
316
        return self.filestate_set.order_by('date_selected')
317

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

    
337
    def change_day_selected_of_state(self, state, new_date):
338
        if state.previous_state:
339
            if new_date < state.previous_state.date_selected:
340
                raise Exception('You cannot set a state starting the %s '
341
                    'before the previous state starting at day %s.' % \
342
                    (str(new_date), str(state.previous_state.date_selected)))
343
        next_state = state.get_next_state()
344
        if next_state:
345
            if new_date > next_state.date_selected:
346
                raise Exception('You cannot set a state starting the %s '
347
                    'after the following state starting at day %s.' % \
348
                    (str(new_date), str(next_state.date_selected)))
349
        state.date_selected = new_date
350
        state.save()
351

    
352
    def remove_state(self, state):
353
        if state.patient.id != self.id:
354
            raise Exception('The state given is not about this patient '
355
                'record but about %s' % state.patient)
356
        next_state = state.get_next_state()
357
        if not next_state:
358
            self.remove_last_state()
359
        else:
360
            next_state.previous_state = state.previous_state
361
            next_state.save()
362
            state.delete()
363

    
364
    def remove_last_state(self):
365
        try:
366
            self.get_state().delete()
367
        except:
368
            pass
369

    
370
    # START Specific to sessad healthcare
371
    def get_last_notification(self):
372
        return SessadHealthCareNotification.objects.filter(patient=self, ).\
373
            latest('end_date')
374

    
375
    def days_before_notification_expiration(self):
376
        today = datetime.today()
377
        notification = self.get_last_notification(self)
378
        if not notification:
379
            return 0
380
        if notification.end_date < today:
381
            return 0
382
        else:
383
            return notification.end_date - today
384
    # END Specific to sessad healthcare
385

    
386
    # START Specific to cmpp healthcare
387
    def create_diag_healthcare(self, modifier):
388
        """
389
            Gestion de l'inscription automatique.
390

    
391
            Si un premier acte est validé alors une prise en charge
392
            diagnostique est ajoutée. Cela fera basculer le dossier dans l'état
393
            en diagnostic.
394

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

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

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

    
462
reversion.register(PatientRecord, follow=['people_ptr'])
463

    
464

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

    
(4-4/8)