Project

General

Profile

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

calebasse / calebasse / dossiers / models.py @ f3407c83

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.actes.validation import are_all_acts_of_the_day_locked
17

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

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

    
25

    
26
class HealthCare(models.Model):
27

    
28
    class Meta:
29
        app_label = 'dossiers'
30

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

    
40

    
41
class CmppHealthCareDiagnostic(HealthCare):
42

    
43
    class Meta:
44
        app_label = 'dossiers'
45

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

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

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

    
57

    
58
class CmppHealthCareTreatment(HealthCare):
59

    
60
    class Meta:
61
        app_label = 'dossiers'
62

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

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

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

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

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

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

    
95

    
96
class SessadHealthCareNotification(HealthCare):
97

    
98
    class Meta:
99
        app_label = 'dossiers'
100

    
101
    end_date = models.DateTimeField()
102

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

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

    
116
class Status(NamedAbstractModel):
117

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

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

    
126
class FileState(models.Model):
127

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

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

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

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

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

    
160

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

    
166
    created = models.DateTimeField(u'création', auto_now_add=True)
167
    creator = \
168
        models.ForeignKey(User,
169
        verbose_name=u'Créateur dossier patient',
170
        editable=True)
171
    contacts = models.ManyToManyField('personnes.People',
172
            related_name='contact_of')
173
    birthdate = models.DateField(null=True, blank=True)
174
    nationality = models.CharField(max_length=70, 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
            null=True)
180

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
354

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

    
(4-4/8)