Project

General

Profile

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

calebasse / calebasse / dossiers / models.py @ bb269b6a

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

    
3
import logging
4
import os
5

    
6
from datetime import datetime, date
7
from dateutil.relativedelta import relativedelta
8

    
9
from django import forms
10
from django.conf import settings
11
from django.db import models
12
from django.contrib.auth.models import User
13

    
14
import reversion
15

    
16
from calebasse.choices import LARGE_REGIME_CHOICES
17
from calebasse.models import PhoneNumberField, ZipCodeField
18
from calebasse.personnes.models import People
19
from calebasse.ressources.models import (ServiceLinkedAbstractModel,
20
        NamedAbstractModel, Service)
21
from calebasse.actes.validation import are_all_acts_of_the_day_locked
22

    
23
DEFAULT_ACT_NUMBER_DIAGNOSTIC = 6
24
DEFAULT_ACT_NUMBER_TREATMENT = 30
25
DEFAULT_ACT_NUMBER_PROLONGATION = 10
26
VALIDITY_PERIOD_TREATMENT_HEALTHCARE_DAYS = 0
27
VALIDITY_PERIOD_TREATMENT_HEALTHCARE_MONTHS = 0
28
VALIDITY_PERIOD_TREATMENT_HEALTHCARE_YEARS = 1
29

    
30
logger = logging.getLogger('calebasse.dossiers')
31

    
32

    
33
class HealthCare(models.Model):
34

    
35
    class Meta:
36
        app_label = 'dossiers'
37

    
38
    start_date = models.DateField(verbose_name=u"Date de début")
39
    patient = models.ForeignKey('dossiers.PatientRecord',
40
        verbose_name=u'Dossier patient')
41
    created = models.DateTimeField(u'Création', auto_now_add=True)
42
    author = \
43
        models.ForeignKey(User,
44
        verbose_name=u'Auteur')
45
    comment = models.TextField(max_length=3000, blank=True, null=True, verbose_name=u"Commentaire")
46

    
47
    def get_nb_acts_cared(self):
48
        return len(self.act_set.all())
49

    
50

    
51
class CmppHealthCareDiagnostic(HealthCare):
52

    
53
    class Meta:
54
        app_label = 'dossiers'
55

    
56
    act_number = models.IntegerField(default=DEFAULT_ACT_NUMBER_DIAGNOSTIC, verbose_name=u"Nombre d'actes couverts")
57

    
58
    def get_act_number(self):
59
        return self.act_number
60

    
61
    def set_act_number(self, value):
62
        if value < self.get_nb_acts_cared():
63
            raise Exception("La valeur doit être supérieur au "
64
                "nombre d'actes déjà pris en charge")
65
        self.act_number = value
66
        self.save()
67

    
68
    def save(self, **kwargs):
69
        self.start_date = \
70
            datetime(self.start_date.year, self.start_date.month,
71
                self.start_date.day)
72
        super(CmppHealthCareDiagnostic, self).save(**kwargs)
73

    
74

    
75
class CmppHealthCareTreatment(HealthCare):
76

    
77
    class Meta:
78
        app_label = 'dossiers'
79

    
80
    act_number = models.IntegerField(default=DEFAULT_ACT_NUMBER_TREATMENT,
81
            verbose_name=u"Nombre d'actes couverts")
82
    end_date = models.DateField(verbose_name=u"Date de fin")
83
    prolongation = models.IntegerField(default=0,
84
            verbose_name=u'Prolongation')
85

    
86
    def get_act_number(self):
87
        if self.is_extended():
88
            return self.act_number + self.prolongation
89
        return self.act_number
90

    
91
    def set_act_number(self, value):
92
        if value < self.get_nb_acts_cared():
93
            raise Exception("La valeur doit être supérieur au "
94
                "nombre d'actes déjà pris en charge")
95
        self.act_number = value
96
        self.save()
97

    
98
    def is_extended(self):
99
        if self.prolongation > 0:
100
            return True
101
        return False
102

    
103
    def add_prolongation(self, value=None):
104
        if not value:
105
            value = DEFAULT_ACT_NUMBER_PROLONGATION
106
        if self.is_extended():
107
            raise Exception(u'Prise en charge déja prolongée')
108
        self.prolongation = value
109
        self.save()
110

    
111
    def save(self, **kwargs):
112
        self.start_date = \
113
            datetime(self.start_date.year, self.start_date.month,
114
                self.start_date.day)
115
        self.end_date = self.start_date + \
116
            relativedelta(years=VALIDITY_PERIOD_TREATMENT_HEALTHCARE_YEARS) + \
117
            relativedelta(months=VALIDITY_PERIOD_TREATMENT_HEALTHCARE_MONTHS) + \
118
            relativedelta(days=VALIDITY_PERIOD_TREATMENT_HEALTHCARE_DAYS)
119
        super(CmppHealthCareTreatment, self).save(**kwargs)
120

    
121

    
122
class SessadHealthCareNotification(HealthCare):
123

    
124
    class Meta:
125
        app_label = 'dossiers'
126

    
127
    end_date = models.DateField()
128

    
129
    def save(self, **kwargs):
130
        self.start_date = \
131
            datetime(self.start_date.year, self.start_date.month,
132
                self.start_date.day)
133
        self.end_date = \
134
            datetime(self.end_date.year, self.end_date.month,
135
                self.end_date.day)
136
        super(SessadHealthCareNotification, self).save(**kwargs)
137

    
138
reversion.register(CmppHealthCareDiagnostic, follow=['healthcare_ptr'])
139
reversion.register(CmppHealthCareTreatment, follow=['healthcare_ptr'])
140
reversion.register(SessadHealthCareNotification, follow=['healthcare_ptr'])
141

    
142
class Status(NamedAbstractModel):
143

    
144
    class Meta:
145
        app_label = 'dossiers'
146
        verbose_name = u"Statut d'un état"
147
        verbose_name_plural = u"Statuts d'un état"
148

    
149
    type = models.CharField(max_length=80)
150
    services = models.ManyToManyField('ressources.Service')
151

    
152

    
153
class FileState(models.Model):
154

    
155
    class Meta:
156
        app_label = 'dossiers'
157
        verbose_name = u'Etat du dossier patient'
158
        verbose_name_plural = u'Etats du dossier patient'
159

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

    
172
    def get_next_state(self):
173
        try:
174
            return FileState.objects.get(previous_state=self)
175
        except:
176
            return None
177

    
178
    def save(self, **kwargs):
179
        self.date_selected = \
180
                datetime(self.date_selected.year,
181
                        self.date_selected.month, self.date_selected.day)
182
        super(FileState, self).save(**kwargs)
183

    
184
    def __unicode__(self):
185
        return self.status.name + ' ' + str(self.date_selected)
186

    
187
    def delete(self, *args, **kwargs):
188
        next_state = self.get_next_state()
189
        if next_state and self.previous_state:
190
            next_state.previous_state = self.previous_state
191
            next_state.save()
192
        if self.patient.last_state == self:
193
            self.patient.last_state = self.previous_state
194
            self.patient.save()
195
        super(FileState, self).delete(*args, **kwargs)
196

    
197
class PatientAddress(models.Model):
198

    
199
    display_name = models.CharField(max_length=276,
200
            verbose_name=u'Adresse complète', editable=False)
201
    phone = PhoneNumberField(verbose_name=u"Téléphone", blank=True, null=True)
202
    fax = PhoneNumberField(verbose_name=u"Fax", blank=True, null=True)
203
    place_of_life = models.BooleanField(verbose_name=u"Lieu de vie")
204
    number = models.CharField(max_length=12,
205
            verbose_name=u"Numéro", blank=True, null=True)
206
    street = models.CharField(max_length=100,
207
            verbose_name=u"Rue", blank=True, null=True)
208
    address_complement = models.CharField(max_length=100,
209
            blank=True, null=True,
210
            verbose_name=u"Complément d'adresse")
211
    zip_code = ZipCodeField(verbose_name=u"Code postal", blank=True, null=True)
212
    city = models.CharField(max_length=60,
213
            verbose_name=u"Ville", blank=True, null=True)
214
    comment = models.TextField(verbose_name=u"Commentaire",
215
            null=True, blank=True)
216

    
217
    def __unicode__(self):
218
        return self.display_name
219

    
220
    def save(self, **kwargs):
221
        self.display_name = ''
222
        if self.number:
223
            self.display_name += self.number + ' '
224
        if self.street:
225
            self.display_name += self.street + ' '
226
        if self.address_complement:
227
            self.display_name += self.address_complement + ' '
228
        if self.zip_code:
229
            self.display_name += self.zip_code + ' '
230
        if self.city:
231
            self.display_name += self.city + ' '
232
        super(PatientAddress, self).save(**kwargs)
233

    
234

    
235
class PatientContact(People):
236
    class Meta:
237
        verbose_name = u'Contact patient'
238
        verbose_name_plural = u'Contacts patient'
239

    
240
    mobile = PhoneNumberField(verbose_name=u"Téléphone mobile", blank=True, null=True)
241
    # carte vitale
242
    social_security_id = models.CharField(max_length=13, verbose_name=u"NIR",
243
            null=True, blank=True)
244
    birthdate = models.DateField(verbose_name=u"Date de naissance",
245
            null=True, blank=True)
246
    birthplace = models.CharField(max_length=100, verbose_name=u"Lieu de naissance",
247
            null=True, blank=True)
248
    twinning_rank = models.IntegerField(verbose_name=u"Rang (gémellité)",
249
            null=True, blank=True)
250
    thirdparty_payer = models.BooleanField(verbose_name=u'Tiers-payant',
251
            default=False)
252
    begin_rights = models.DateField(verbose_name=u"Début de droits",
253
            null=True, blank=True)
254
    end_rights = models.DateField(verbose_name=u"Fin de droits",
255
            null=True, blank=True)
256
    health_center = models.ForeignKey('ressources.HealthCenter',
257
            verbose_name=u"Centre d'assurance maladie",
258
            null=True, blank=True)
259
    other_health_center = models.CharField(verbose_name=u"Centre spécifique",
260
            max_length=4,
261
            null=True, blank=True)
262
    job = models.ForeignKey('ressources.Job',
263
            related_name="job",
264
            verbose_name=u"Profession",
265
            null=True, blank=True, default=None)
266
    parente = models.ForeignKey('ressources.PatientRelatedLink',
267
            verbose_name=u"Lien avec le patient (Parenté)",
268
            null=True, blank=True, default=None)
269

    
270
    addresses = models.ManyToManyField('PatientAddress', verbose_name=u"Adresses")
271
    contact_comment = models.TextField(verbose_name=u"Commentaire",
272
            null=True, blank=True)
273

    
274
    old_contact_id = models.CharField(max_length=256,
275
            verbose_name=u'Ancien ID du contact', blank=True, null=True)
276

    
277
    def get_control_key(self):
278
        if self.social_security_id:
279
            nir = self.social_security_id
280
            try:
281
                # Corse dpt 2A et 2B
282
                minus = 0
283
                if nir[6] in ('A', 'a'):
284
                    nir = [c for c in nir]
285
                    nir[6] = '0'
286
                    nir = ''.join(nir)
287
                    minus = 1000000
288
                elif nir[6] in ('B', 'b'):
289
                    nir = [c for c in nir]
290
                    nir[6] = '0'
291
                    nir = ''.join(nir)
292
                    minus = 2000000
293
                nir = int(nir) - minus
294
                return (97 - (nir % 97))
295
            except Exception, e:
296
                print str(e)
297
                return None
298
        return None
299

    
300

    
301
class PatientRecordManager(models.Manager):
302
    def for_service(self, service):
303
        return self.filter(service=service)
304

    
305
class PatientRecord(ServiceLinkedAbstractModel, PatientContact):
306
    objects = PatientRecordManager()
307

    
308
    class Meta:
309
        verbose_name = u'Dossier'
310
        verbose_name_plural = u'Dossiers'
311

    
312
    created = models.DateTimeField(u'création', auto_now_add=True)
313
    creator = \
314
        models.ForeignKey(User,
315
        verbose_name=u'Créateur dossier patient',
316
        editable=True)
317
    policyholder = models.ForeignKey('PatientContact',
318
            null=True, blank=True,
319
            verbose_name="Assuré", related_name="+",
320
            on_delete=models.SET_NULL)
321
    contacts = models.ManyToManyField('PatientContact',
322
            related_name='contact_of')
323
    nationality = models.CharField(verbose_name=u"Nationalité",
324
            max_length=70, null=True, blank=True)
325
    paper_id = models.CharField(max_length=6,
326
            verbose_name=u"N° dossier papier",
327
            null=True, blank=True)
328
    last_state = models.ForeignKey(FileState, related_name='+',
329
            null=True, on_delete=models.SET_NULL)
330
    comment = models.TextField(verbose_name=u"Commentaire",
331
            null=True, blank=True, default=None)
332
    pause = models.BooleanField(verbose_name=u"Pause facturation",
333
            default=False)
334
    confidential = models.BooleanField(verbose_name=u"Confidentiel",
335
            default=False)
336
    socialisation_durations = models.ManyToManyField('ressources.SocialisationDuration',
337
            related_name='socialisation_duration_of')
338
    mdph_requests = models.ManyToManyField('ressources.MDPHRequest',
339
            related_name='mdph_requests_of')
340
    mdph_responses = models.ManyToManyField('ressources.MDPHResponse',
341
            related_name='mdph_responses_of')
342

    
343
    # Physiology and health data
344
    size = models.IntegerField(verbose_name=u"Taille (cm)",
345
            null=True, blank=True, default=None)
346
    weight = models.IntegerField(verbose_name=u"Poids (g)",
347
            null=True, blank=True, default=None)
348
    pregnancy_term = models.IntegerField(verbose_name=u"Terme en semaines",
349
            null=True, blank=True, default=None)
350
    cranium_perimeter = models.DecimalField(verbose_name=u"Périmètre cranien", max_digits=5, decimal_places=2,
351
            null=True, blank=True, default=None)
352
    chest_perimeter = models.DecimalField(verbose_name=u"Périmètre thoracique", max_digits=5, decimal_places=2,
353
            null=True, blank=True, default=None)
354
    apgar_score_one = models.IntegerField(verbose_name=u"Test d'Apgar (1)",
355
            null=True, blank=True, default=None)
356
    apgar_score_two = models.IntegerField(verbose_name=u"Test d'Apgar (5)",
357
            null=True, blank=True, default=None)
358
    mises_1 = models.ManyToManyField('ressources.CodeCFTMEA', related_name="mises1",
359
            verbose_name=u"Axe I : catégories cliniques",
360
            null=True, blank=True, default=None)
361
    mises_2 = models.ManyToManyField('ressources.CodeCFTMEA', related_name="mises2",
362
            verbose_name=u"Axe II : facteurs organiques",
363
            null=True, blank=True, default=None)
364
    mises_3 = models.ManyToManyField('ressources.CodeCFTMEA', related_name="mises3",
365
            verbose_name=u"Axe II : facteurs environnementaux",
366
            null=True, blank=True, default=None)
367

    
368
    # Inscription motive
369
    analysemotive = models.ForeignKey('ressources.AnalyseMotive',
370
            verbose_name=u"Motif (analysé)",
371
            null=True, blank=True, default=None)
372
    familymotive = models.ForeignKey('ressources.FamilyMotive',
373
            verbose_name=u"Motif (famille)",
374
            null=True, blank=True, default=None)
375
    provenance = models.ForeignKey('ressources.Provenance',
376
            verbose_name=u"Provenance",
377
            null=True, blank=True, default=None)
378
    advicegiver = models.ForeignKey('ressources.AdviceGiver',
379
            verbose_name=u"Conseilleur",
380
            null=True, blank=True, default=None)
381

    
382
    # Out motive
383
    outmotive = models.ForeignKey('ressources.OutMotive',
384
            verbose_name=u"Motif de sortie",
385
            null=True, blank=True, default=None)
386
    outto = models.ForeignKey('ressources.OutTo',
387
            verbose_name=u"Orientation",
388
            null=True, blank=True, default=None)
389

    
390
    # Family
391
    sibship_place = models.IntegerField(verbose_name=u"Place dans la fratrie",
392
            null=True, blank=True, default=None)
393
    nb_children_family = models.IntegerField(verbose_name=u"Nombre d'enfants dans la fratrie",
394
            null=True, blank=True, default=None)
395
    parental_authority = models.ForeignKey('ressources.ParentalAuthorityType',
396
            verbose_name=u"Autorité parentale",
397
            null=True, blank=True, default=None)
398
    family_situation = models.ForeignKey('ressources.FamilySituationType',
399
            verbose_name=u"Situation familiale",
400
            null=True, blank=True, default=None)
401
    child_custody = models.ForeignKey('ressources.ParentalCustodyType',
402
            verbose_name=u"Garde parentale",
403
            null=True, blank=True, default=None)
404
    job_mother = models.ForeignKey('ressources.Job',
405
            related_name="job_mother",
406
            verbose_name=u"Profession de la mère",
407
            null=True, blank=True, default=None)
408
    job_father = models.ForeignKey('ressources.Job',
409
            related_name="job_father",
410
            verbose_name=u"Profession du père",
411
            null=True, blank=True, default=None)
412
    rm_mother = models.ForeignKey('ressources.MaritalStatusType',
413
            related_name="rm_mother",
414
            verbose_name=u"Régime matrimonial de la mère",
415
            null=True, blank=True, default=None)
416
    rm_father = models.ForeignKey('ressources.MaritalStatusType',
417
            related_name="rm_father",
418
            verbose_name=u"Régime matrimonial du père",
419
            null=True, blank=True, default=None)
420
    family_comment = models.TextField(verbose_name=u"Commentaire",
421
            null=True, blank=True, default=None)
422

    
423
    # Transport
424
    transporttype = models.ForeignKey('ressources.TransportType',
425
            verbose_name=u"Type de transport",
426
            null=True, blank=True, default=None)
427
    transportcompany = models.ForeignKey('ressources.TransportCompany',
428
            verbose_name=u"Compagnie de transport",
429
            null=True, blank=True, default=None)
430

    
431
    # FollowUp
432
    coordinators = models.ManyToManyField('personnes.Worker',
433
            verbose_name=u"Coordinateurs",
434
            null=True, blank=True, default=None)
435
    externaldoctor = models.ForeignKey('personnes.ExternalTherapist',
436
            verbose_name=u"Médecin extérieur",
437
            null=True, blank=True, default=None)
438
    externalintervener = models.ForeignKey('personnes.ExternalWorker',
439
            verbose_name=u"Intervenant extérieur",
440
            null=True, blank=True, default=None)
441

    
442
    old_id = models.CharField(max_length=256,
443
            verbose_name=u'Ancien ID', blank=True, null=True)
444
    old_old_id = models.CharField(max_length=256,
445
            verbose_name=u'Ancien ancien ID', blank=True, null=True)
446

    
447
    def save(self, *args, **kwargs):
448
        if not getattr(self, 'service', None):
449
            raise Exception('The field service is mandatory.')
450
        super(PatientRecord, self).save(*args, **kwargs)
451

    
452
    def get_state(self):
453
        return self.last_state
454

    
455
    def get_initial_state(self):
456
        return self.filestate_set.order_by('date_selected')[0]
457

    
458
    def get_current_state(self):
459
        today = date.today()
460
        return self.get_state_at_day(today)
461

    
462
    def get_state_at_day(self, date):
463
        state = self.get_state()
464
        while(state):
465
            if datetime(state.date_selected.year,
466
                    state.date_selected.month, state.date_selected.day) <= \
467
                    datetime(date.year, date.month, date.day):
468
                return state
469
            state = state.previous_state
470
        return self.get_state()
471

    
472
    def was_in_state_at_day(self, date, status_type):
473
        state_at_day = self.get_state_at_day(date)
474
        if state_at_day and state_at_day.status.type == status_type:
475
            return True
476
        return False
477

    
478
    def get_states_history(self):
479
        return self.filestate_set.order_by('date_selected')
480

    
481
    def can_be_deleted(self):
482
        for act in self.act_set.all():
483
            if act.is_state('VALIDE'):
484
                return False
485
        return True
486

    
487
    def delete(self, *args, **kwargs):
488
        if self.can_be_deleted():
489
            super(PatientRecord, self).delete(*args, **kwargs)
490

    
491
    def get_ondisk_directory(self, service):
492
        if not settings.PATIENT_FILES_BASE_DIRECTORY:
493
            return None
494

    
495
        dirnames = []
496
        dirname = self.last_name.upper()
497
        dirnames.append(dirname)
498
        if self.first_name:
499
            dirname = '%s %s' % (dirname, self.first_name)
500
            dirnames.append(dirname)
501
        if self.paper_id:
502
            dirname = '%s %s' % (dirname, self.paper_id)
503
            dirnames.append(dirname)
504

    
505
        for i, dirname in enumerate(dirnames):
506
            fullpath = os.path.join(settings.PATIENT_FILES_BASE_DIRECTORY, service, dirname)
507
            try:
508
                next_fullpath = os.path.join(settings.PATIENT_FILES_BASE_DIRECTORY, service, dirnames[i+1])
509
            except IndexError:
510
                pass
511
            else:
512
                 if os.path.exists(fullpath) and not os.path.exists(next_fullpath):
513
                     os.rename(fullpath, next_fullpath)
514
                 continue
515
            if not os.path.exists(fullpath):
516
                os.makedirs(fullpath)
517
            for subdir in settings.PATIENT_SUBDIRECTORIES:
518
                subdir_fullpath = os.path.join(fullpath, subdir)
519
                if not os.path.exists(subdir_fullpath):
520
                    os.makedirs(subdir_fullpath)
521
        return fullpath
522

    
523
    def get_client_side_directory(self, service):
524
        directory = self.get_ondisk_directory(service)
525
        if not directory:
526
            return None
527
        if not settings.CLIENT_SIDE_PATIENT_FILES_BASE_DIRECTORY:
528
            return None
529
        return os.path.join(settings.CLIENT_SIDE_PATIENT_FILES_BASE_DIRECTORY,
530
                            directory[len(settings.PATIENT_FILES_BASE_DIRECTORY)+1:])
531

    
532
    def set_state(self, status, author, date_selected=None, comment=None):
533
        if not author:
534
            raise Exception('Missing author to set state')
535
        if not date_selected:
536
            date_selected = datetime.now()
537
        current_state = self.get_state()
538
        if not current_state:
539
            raise Exception('Invalid patient record. '
540
                'Missing current state.')
541
        if date_selected < current_state.date_selected:
542
            raise Exception('You cannot set a state starting the %s that '
543
                'is before the previous state starting at day %s.' % \
544
                (str(date_selected), str(current_state.date_selected)))
545
        filestate = FileState.objects.create(patient=self, status=status,
546
            date_selected=date_selected, author=author, comment=comment,
547
            previous_state=current_state)
548
        self.last_state = filestate
549
        self.save()
550

    
551
    def change_day_selected_of_state(self, state, new_date):
552
        if state.previous_state:
553
            if new_date < state.previous_state.date_selected:
554
                raise Exception('You cannot set a state starting the %s '
555
                    'before the previous state starting at day %s.' % \
556
                    (str(new_date), str(state.previous_state.date_selected)))
557
        next_state = state.get_next_state()
558
        if next_state:
559
            if new_date > next_state.date_selected:
560
                raise Exception('You cannot set a state starting the %s '
561
                    'after the following state starting at day %s.' % \
562
                    (str(new_date), str(next_state.date_selected)))
563
        state.date_selected = new_date
564
        state.save()
565

    
566
    def remove_state(self, state):
567
        if state.patient.id != self.id:
568
            raise Exception('The state given is not about this patient '
569
                'record but about %s' % state.patient)
570
        next_state = state.get_next_state()
571
        if not next_state:
572
            self.remove_last_state()
573
        else:
574
            next_state.previous_state = state.previous_state
575
            next_state.save()
576
            state.delete()
577

    
578
    def remove_last_state(self):
579
        try:
580
            self.get_state().delete()
581
        except:
582
            pass
583

    
584
    # START Specific to sessad healthcare
585
    def get_last_notification(self):
586
        return SessadHealthCareNotification.objects.filter(patient=self, ).\
587
            latest('end_date')
588

    
589
    def days_before_notification_expiration(self):
590
        today = datetime.today()
591
        notification = self.get_last_notification(self)
592
        if not notification:
593
            return 0
594
        if notification.end_date < today:
595
            return 0
596
        else:
597
            return notification.end_date - today
598
    # END Specific to sessad healthcare
599

    
600
    # START Specific to cmpp healthcare
601
    def create_diag_healthcare(self, modifier):
602
        """
603
            Gestion de l'inscription automatique.
604

    
605
            Si un premier acte est validé alors une prise en charge
606
            diagnostique est ajoutée. Cela fera basculer le dossier dans l'état
607
            en diagnostic.
608

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

    
615
        """
616
        acts = self.act_set.order_by('date')
617
        hcds = CmppHealthCareDiagnostic.objects.filter(patient=self).order_by('-start_date')
618
        if not hcds:
619
            # Pas de prise en charge, on recherche l'acte facturable le plus
620
            # ancien, on crée une pc diag à la même date.
621
            for act in acts:
622
                if act.is_state('VALIDE') and act.is_billable():
623
                    CmppHealthCareDiagnostic(patient=self, author=modifier,
624
                        start_date=act.date).save()
625
                    break
626
        else:
627
            # On recherche l'acte facturable non facturé le plus ancien et
628
            # l'on regarde s'il a plus d'un an
629
            try:
630
                last_billed_act = self.act_set.filter(is_billed=True).\
631
                    latest('date')
632
                if last_billed_act:
633
                    for act in acts:
634
                        if act.is_state('VALIDE') and \
635
                                act.is_billable() and \
636
                                (act.date - last_billed_act.date).days >= 365:
637
                            return True
638
            except:
639
                pass
640
        return False
641

    
642
    def automated_switch_state(self, modifier):
643
        # Quel est le dernier acte facturable.
644
        acts = self.act_set.order_by('-date')
645
        # Si cet acte peut-être pris en charge en diagnostic c'est un acte de
646
        # diagnostic, sinon c'est un acte de traitement.
647
        last_state_services = self.last_state.status.\
648
                services.values_list('name', flat=True)
649
        cmpp = Service.objects.get(name='CMPP')
650
        for act in acts:
651
            if act.is_state('VALIDE') and act.is_billable() and \
652
                    act.date >= self.get_state().date_selected.date() and \
653
                    are_all_acts_of_the_day_locked(act.date):
654
                cared, hc = act.is_act_covered_by_diagnostic_healthcare()
655
                if hc:
656
                    if (self.last_state.status.type == "ACCUEIL" \
657
                            or self.last_state.status.type == "TRAITEMENT") \
658
                            and "CMPP" in last_state_services:
659
                        status = Status.objects.filter(type="DIAGNOSTIC").\
660
                                filter(services__name='CMPP')[0]
661
                        try:
662
                            self.set_state(status, modifier,
663
                                date_selected=act.date)
664
                        except:
665
                            pass
666
                # Sinon, si le dossier est en diag, s'il ne peut être couvert
667
                # en diag, il est en traitement.
668
                elif self.last_state.status.type == "DIAGNOSTIC" and \
669
                        "CMPP" in last_state_services:
670
                    status = Status.objects.filter(type="TRAITEMENT").\
671
                            filter(services__name='CMPP')[0]
672
                    try:
673
                        self.set_state(status, modifier,
674
                                date_selected=act.date)
675
                    except:
676
                        pass
677
                break
678
    # END Specific to cmpp healthcare
679

    
680
reversion.register(PatientRecord, follow=['people_ptr'])
681

    
682

    
683
def create_patient(first_name, last_name, service, creator,
684
        date_selected=None):
685
    logger.debug('create_patient: creation for patient %s %s in service %s '
686
        'by %s' % (first_name, last_name, service, creator))
687
    if not (first_name and last_name and service and creator):
688
        raise Exception('Missing parameter to create a patient record.')
689
    status = Status.objects.filter(type="ACCUEIL").filter(services=service)
690
    if not status:
691
        raise Exception('%s has no ACCEUIL status' % service.name)
692
    patient = PatientRecord.objects.create(first_name=first_name,
693
            last_name=last_name, service=service,
694
            creator=creator)
695
    fs = FileState(status=status[0], author=creator, previous_state=None)
696
    if not date_selected:
697
        date_selected = patient.created
698
    fs.patient = patient
699
    fs.date_selected = date_selected
700
    fs.save()
701
    patient.last_state = fs
702
    patient.save()
703
    return patient
(5-5/9)