Project

General

Profile

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

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

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.models import PhoneNumberField, ZipCodeField
14
from calebasse.personnes.models import People
15
from calebasse.ressources.models import (ServiceLinkedAbstractModel,
16
    NamedAbstractModel, Service)
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"Statut d'un état"
122
        verbose_name_plural = u"Statuts d'un état"
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
class PatientAddress(models.Model):
162

    
163
    # Address
164
    address = models.CharField(max_length=120,
165
            verbose_name=u"Addresse")
166
    address_complement = models.CharField(max_length=120,
167
            blank=True,
168
            null=True,
169
            default=None,
170
            verbose_name=u"Complément d'addresse")
171
    zip_code = ZipCodeField(verbose_name=u"Code postal")
172
    city = models.CharField(max_length=80,
173
            verbose_name=u"Ville")
174

    
175
class PatientContact(People):
176
    class Meta:
177
        verbose_name = u'Contact patient'
178
        verbose_name_plural = u'Contacts patient'
179

    
180
    phone = PhoneNumberField(verbose_name=u"Téléphone", blank=True, null=True)
181
    fax = PhoneNumberField(verbose_name=u"Fax", blank=True, null=True)
182
    email = models.EmailField(blank=True, null=True)
183
    social_security_id = models.CharField(max_length=13)
184
    addresses = models.ManyToManyField('PatientAddress')
185

    
186

    
187
class PatientRecord(ServiceLinkedAbstractModel, PatientContact):
188
    class Meta:
189
        verbose_name = u'Dossier'
190
        verbose_name_plural = u'Dossiers'
191

    
192
    created = models.DateTimeField(u'création', auto_now_add=True)
193
    creator = \
194
        models.ForeignKey(User,
195
        verbose_name=u'Créateur dossier patient',
196
        editable=True)
197
    contacts = models.ManyToManyField('personnes.People',
198
            related_name='contact_of')
199
    birthdate = models.DateField(null=True, blank=True)
200
    nationality = models.CharField(max_length=70, null=True, blank=True)
201
    paper_id = models.CharField(max_length=12,
202
            null=True, blank=True)
203
    last_state = models.ForeignKey(FileState, related_name='+',
204
            null=True)
205

    
206
    def __init__(self, *args, **kwargs):
207
        super(PatientRecord, self).__init__(*args, **kwargs)
208
        if not hasattr(self, 'service'):
209
            raise Exception('The field service is mandatory.')
210

    
211
    def get_state(self):
212
        return self.last_state
213

    
214
    def get_state_at_day(self, date):
215
        state = self.get_state()
216
        while(state):
217
            if datetime(state.date_selected.year,
218
                    state.date_selected.month, state.date_selected.day) <= \
219
                    datetime(date.year, date.month, date.day):
220
                return state
221
            state = state.previous_state
222
        return None
223

    
224
    def was_in_state_at_day(self, date, state_name):
225
        state_at_day = self.get_state_at_day(date)
226
        if state_at_day and state_at_day.state_name == state_name:
227
            return True
228
        return False
229

    
230
    def get_states_history(self):
231
        return self.filestate_set.order_by('date_selected')
232

    
233
    def set_state(self, status, author, date_selected=None, comment=None):
234
        if not author:
235
            raise Exception('Missing author to set state')
236
        if not date_selected:
237
            date_selected = datetime.now()
238
        current_state = self.get_state()
239
        if not current_state:
240
            raise Exception('Invalid patient record. '
241
                'Missing current state.')
242
        if date_selected < current_state.date_selected:
243
            raise Exception('You cannot set a state starting the %s that '
244
                'is before the previous state starting at day %s.' % \
245
                (str(date_selected), str(current_state.date_selected)))
246
        filestate = FileState.objects.create(patient=self, status=status,
247
            date_selected=date_selected, author=author, comment=comment,
248
            previous_state=current_state)
249
        self.last_state = filestate
250
        self.save()
251

    
252
    def change_day_selected_of_state(self, state, new_date):
253
        if state.previous_state:
254
            if new_date < state.previous_state.date_selected:
255
                raise Exception('You cannot set a state starting the %s '
256
                    'before the previous state starting at day %s.' % \
257
                    (str(new_date), str(state.previous_state.date_selected)))
258
        next_state = state.get_next_state()
259
        if next_state:
260
            if new_date > next_state.date_selected:
261
                raise Exception('You cannot set a state starting the %s '
262
                    'after the following state starting at day %s.' % \
263
                    (str(new_date), str(next_state.date_selected)))
264
        state.date_selected = new_date
265
        state.save()
266

    
267
    def remove_state(self, state):
268
        if state.patient.id != self.id:
269
            raise Exception('The state given is not about this patient '
270
                'record but about %s' % state.patient)
271
        next_state = state.get_next_state()
272
        if not next_state:
273
            self.remove_last_state()
274
        else:
275
            next_state.previous_state = state.previous_state
276
            next_state.save()
277
            state.delete()
278

    
279
    def remove_last_state(self):
280
        try:
281
            self.get_state().delete()
282
        except:
283
            pass
284

    
285
    # START Specific to sessad healthcare
286
    def get_last_notification(self):
287
        return SessadHealthCareNotification.objects.filter(patient=self, ).\
288
            latest('end_date')
289

    
290
    def days_before_notification_expiration(self):
291
        today = datetime.today()
292
        notification = self.get_last_notification(self)
293
        if not notification:
294
            return 0
295
        if notification.end_date < today:
296
            return 0
297
        else:
298
            return notification.end_date - today
299
    # END Specific to sessad healthcare
300

    
301
    # START Specific to cmpp healthcare
302
    def create_diag_healthcare(self, modifier):
303
        """
304
            Gestion de l'inscription automatique.
305

    
306
            Si un premier acte est validé alors une prise en charge
307
            diagnostique est ajoutée. Cela fera basculer le dossier dans l'état
308
            en diagnostic.
309

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

    
316
        """
317
        acts = self.act_set.order_by('date')
318
        hcs = self.healthcare_set.order_by('-start_date')
319
        if not hcs:
320
            # Pas de prise en charge, on recherche l'acte facturable le plus
321
            # ancien, on crée une pc diag à la même date.
322
            for act in acts:
323
                if are_all_acts_of_the_day_locked(act.date) and \
324
                        act.is_state('VALIDE') and act.is_billable():
325
                    CmppHealthCareDiagnostic(patient=self, author=modifier,
326
                        start_date=act.date).save()
327
                    break
328
        else:
329
            # On recherche l'acte facturable non facturé le plus ancien et
330
            # l'on regarde s'il a plus d'un an
331
            try:
332
                last_billed_act = self.act_set.filter(is_billed=True).\
333
                    latest('date')
334
                if last_billed_act:
335
                    for act in acts:
336
                        if are_all_acts_of_the_day_locked(act.date) and \
337
                                act.is_state('VALIDE') and \
338
                                act.is_billable() and \
339
                                (act.date - last_billed_act.date).days >= 365:
340
                            CmppHealthCareDiagnostic(patient=self,
341
                                author=modifier, start_date=act.date).save()
342
                            break
343
            except:
344
                pass
345

    
346
    def automated_switch_state(self, modifier):
347
        # Quel est le dernier acte facturable.
348
        acts = self.act_set.order_by('-date')
349
        # Si cet acte peut-être pris en charge en diagnostic c'est un acte de
350
        # diagnostic, sinon c'est un acte de traitement.
351
        last_state_services = self.last_state.status.\
352
                services.values_list('name', flat=True)
353
        cmpp = Service.objects.get(name='CMPP')
354
        for act in acts:
355
            if are_all_acts_of_the_day_locked(act.date) and \
356
                    act.is_state('VALIDE') and act.is_billable():
357
                cared, hc = act.is_act_covered_by_diagnostic_healthcare()
358
                if hc:
359
                    if (self.last_state.status.type == "ACCEUIL" \
360
                            or self.last_state.status.type == "TRAITEMENT") \
361
                            and "CMPP" in last_state_services:
362
                        status = Status.objects.filter(type="DIAGNOSTIC").\
363
                                filter(services__name='CMPP')[0]
364
                        self.set_state(status, modifier,
365
                            date_selected=act.date)
366
                # Sinon, si le dossier est en diag, s'il ne peut être couvert
367
                # en diag, il est en traitement.
368
                elif self.last_state.status.type == "DIAGNOSTIC" and \
369
                        "CMPP" in last_state_services:
370
                    status = Status.objects.filter(type="TRAITEMENT").\
371
                            filter(services__name='CMPP')[0]
372
                    self.set_state(status, modifier,
373
                            date_selected=act.date)
374
                break
375
    # END Specific to cmpp healthcare
376

    
377
reversion.register(PatientRecord, follow=['people_ptr'])
378

    
379

    
380
def create_patient(first_name, last_name, service, creator,
381
        date_selected=None):
382
    logger.debug('create_patient: creation for patient %s %s in service %s '
383
        'by %s' % (first_name, last_name, service, creator))
384
    if not (first_name and last_name and service and creator):
385
        raise Exception('Missing parameter to create a patient record.')
386
    status = Status.objects.filter(type="ACCUEIL").filter(services=service)
387
    if not status:
388
        raise Exception('%s has no ACCEUIL status' % service.name)
389
    patient = PatientRecord(first_name=first_name,
390
            last_name=last_name, service=service,
391
            creator=creator)
392
    fs = FileState(status=status[0], author=creator, previous_state=None)
393
    patient.last_state = fs
394
    patient.save()
395
    if not date_selected:
396
        date_selected = patient.created
397
    fs.patient = patient
398
    fs.date_selected = date_selected
399
    fs.save()
400
    return patient
401

    
(4-4/8)