Project

General

Profile

Download (14.8 KB) Statistics
| Branch: | Tag: | Revision:
1097fd0a Benjamin Dauvergne
# -*- coding: utf-8 -*-
50e85412 Benjamin Dauvergne
from datetime import date, time
76974b6f Benjamin Dauvergne
1097fd0a Benjamin Dauvergne
from django.db import models
d602f09e Mikaël Ates
from django.contrib.auth.models import User
1097fd0a Benjamin Dauvergne
366eb65a Benjamin Dauvergne
import reversion

e39efb4a Jérôme Schneider
from calebasse.agenda.models import Event, EventType
from calebasse.agenda.managers import EventManager
0d46dc26 Mikaël Ates
from calebasse.ressources.models import ServiceLinkedAbstractModel
5c2d0ea2 Benjamin Dauvergne
from ..middleware.request import get_request
1097fd0a Benjamin Dauvergne
d2fa070d Benjamin Dauvergne
from validation_states import VALIDATION_STATES, NON_VALIDE
a2addd88 Mikaël Ates
d602f09e Mikaël Ates
class ActValidationState(models.Model):

class Meta:
app_label = 'actes'
8bf43f56 Benjamin Dauvergne
ordering = ('-created',)
d602f09e Mikaël Ates
act = models.ForeignKey('actes.Act',
verbose_name=u'Acte', editable=False)
state_name = models.CharField(max_length=150)
created = models.DateTimeField(u'Création', auto_now_add=True)
author = \
models.ForeignKey(User,
18686159 Benjamin Dauvergne
verbose_name=u'Auteur', editable=False, blank=True, null=True)
d602f09e Mikaël Ates
previous_state = models.ForeignKey('ActValidationState',
verbose_name=u'Etat précédent',
editable=False, blank=True, null=True)
# To record if the validation has be done by the automated validation
a0440975 Mikaël Ates
auto = models.BooleanField(default=False,
70268033 Mikaël Ates
verbose_name=u'Validaté automatiquement')
d602f09e Mikaël Ates
a4233531 Benjamin Dauvergne
def __repr__(self):
ef86b6e5 Mikaël Ates
return self.state_name + ' ' + str(self.created)

a4233531 Benjamin Dauvergne
def __unicode__(self):
return VALIDATION_STATES[self.state_name]

4704ebbc Mikaël Ates
76974b6f Benjamin Dauvergne
class ActManager(models.Manager):
50e85412 Benjamin Dauvergne
def for_today(self, today=None):
today = today or date.today()
return self.filter(date=today)

76974b6f Benjamin Dauvergne
def create_act(self, author=None, **kwargs):
act = self.create(**kwargs)
ActValidationState.objects.create(act=act,state_name='NON_VALIDE',
author=author, previous_state=None)
return act

def next_acts(self, patient_record, today=None):
today = today or date.today()
return self.filter(date__gte=today) \
.filter(patient=patient_record) \
.order_by('date')

def last_acts(self, patient_record, today=None):
today = today or date.today()
return self.filter(date__lte=today) \
.filter(patient=patient_record) \
.order_by('-date')


96f613c6 Benjamin Dauvergne
class Act(models.Model):
76974b6f Benjamin Dauvergne
objects = ActManager()

a0440975 Mikaël Ates
patient = models.ForeignKey('dossiers.PatientRecord')
e9fb7b88 Benjamin Dauvergne
date = models.DateField(u'Date', db_index=True)
time = models.TimeField(u'Heure', blank=True, null=True, default=time(), db_index=True)
13f3e0a7 Benjamin Dauvergne
_duration = models.IntegerField(u'Durée en minutes', blank=True, null=True, default=0)
96f613c6 Benjamin Dauvergne
act_type = models.ForeignKey('ressources.ActType',
verbose_name=u'Type d\'acte')
a0440975 Mikaël Ates
validation_locked = models.BooleanField(default=False,
e9fb7b88 Benjamin Dauvergne
verbose_name=u'Vérouillage', db_index=True)
33375338 Mikaël Ates
is_billed = models.BooleanField(default=False,
e9fb7b88 Benjamin Dauvergne
verbose_name=u'Facturé', db_index=True)
ece5949c Mikaël Ates
is_lost = models.BooleanField(default=False,
verbose_name=u'Acte perdu', db_index=True)
33375338 Mikaël Ates
switch_billable = models.BooleanField(default=False,
verbose_name=u'Inverser type facturable')
c0014064 Mikaël Ates
healthcare = models.ForeignKey('dossiers.HealthCare',
blank=True,
null=True,
ea2e8d11 Mikaël Ates
verbose_name=u'Prise en charge utilisée pour facturer (CMPP)')
96f613c6 Benjamin Dauvergne
transport_company = models.ForeignKey('ressources.TransportCompany',
blank=True,
null=True,
verbose_name=u'Compagnie de transport')
transport_type = models.ForeignKey('ressources.TransportType',
blank=True,
null=True,
verbose_name=u'Type de transport')
3c279673 Benjamin Dauvergne
doctors = models.ManyToManyField('personnes.Worker',
d602f09e Mikaël Ates
limit_choices_to={'type__intervene': True},
9291e362 Mikaël Ates
verbose_name=u'Intervenants')
bc7e290e Mikaël Ates
pause = models.BooleanField(default=False,
e9fb7b88 Benjamin Dauvergne
verbose_name=u'Pause facturation', db_index=True)
0906807f Mikaël Ates
parent_event = models.ForeignKey('agenda.Event',
76974b6f Benjamin Dauvergne
verbose_name=u'Rendez-vous lié',
39019102 Benjamin Dauvergne
blank=True, null=True,
on_delete=models.SET_NULL)
76974b6f Benjamin Dauvergne
VALIDATION_CODE_CHOICES = (
('absent', u'Absent'),
('present', u'Présent'),
)
attendance = models.CharField(max_length=16,
choices=VALIDATION_CODE_CHOICES,
default='absent',
verbose_name=u'Présence')
99777656 Benjamin Dauvergne
comment = models.TextField(u'Commentaire')
old_id = models.CharField(max_length=256,
verbose_name=u'Ancien ID', blank=True, null=True)
76974b6f Benjamin Dauvergne
@property
def event(self):
if self.parent_event:
5c2d0ea2 Benjamin Dauvergne
return self.parent_event.today_occurrence(self.date)
76974b6f Benjamin Dauvergne
return None

@property
a1759d39 Benjamin Dauvergne
def start_datetime(self):
76974b6f Benjamin Dauvergne
event = self.event
if event:
a1759d39 Benjamin Dauvergne
return event.start_datetime
return self.date
55a8e535 Benjamin Dauvergne
19b3ab02 Mikaël Ates
def get_hc_tag(self):
if self.healthcare:
try:
self.healthcare.cmpphealthcaretreatment
return 'T'
except:
pass
try:
self.healthcare.cmpphealthcarediagnostic
acts = self.healthcare.act_set.order_by('date')
fb12233b Mikaël Ates
i = 1
19b3ab02 Mikaël Ates
for act in acts:
if act.id == self.id:
return 'D' + str(i)
i = i + 1
except:
pass
return None

b5877252 Benjamin Dauvergne
def is_new(self):
states = self.actvalidationstate_set.all()
states_len = len(states)
return states_len == 0 or \
(states_len == 1 and states[0].state_name == 'NON_VALIDE')

a0440975 Mikaël Ates
def is_absent(self):
5f4c5dd2 Frédéric Péters
state = self.get_state()
08bf3477 Mikaël Ates
if state and state.state_name in ('ABS_NON_EXC', 'ABS_EXC', 'ABS_INTER', 'ANNUL_NOUS',
6c9a3a0d Mikaël Ates
'ANNUL_FAMILLE', 'REPORTE', 'ABS_ESS_PPS', 'ENF_HOSP'):
a0440975 Mikaël Ates
return True
5f4c5dd2 Frédéric Péters
return False
a0440975 Mikaël Ates
def get_state(self):
bcb3b530 Benjamin Dauvergne
states = sorted(self.actvalidationstate_set.all(),
key=lambda avs: avs.created, reverse=True)
if states:
return states[0]
return None
a0440975 Mikaël Ates
def is_state(self, state_name):
state = self.get_state()
if state and state.state_name == state_name:
return True
return False

def set_state(self, state_name, author, auto=False,
change_state_check=True):
d6400658 Benjamin Dauvergne
if not self.id:
self.save()
a0440975 Mikaël Ates
if not author:
raise Exception('Missing author to set state')
4704ebbc Mikaël Ates
if not state_name in VALIDATION_STATES.keys():
a0440975 Mikaël Ates
raise Exception("Etat d'acte non existant %s")
current_state = self.get_state()
ActValidationState(act=self, state_name=state_name,
author=author, previous_state=current_state).save()

33375338 Mikaël Ates
def is_billable(self):
if (self.act_type.billable and not self.switch_billable) or \
(not self.act_type.billable and self.switch_billable):
return True

ef86b6e5 Mikaël Ates
# START Specific to sessad healthcare
def was_covered_by_notification(self):
0906807f Mikaël Ates
from calebasse.dossiers.models import SessadHealthCareNotification
ef86b6e5 Mikaël Ates
notifications = \
SessadHealthCareNotification.objects.filter(patient=self.patient,
start_date__lte=self.date, end_date__gte=self.date)
if notifications:
return True
# END Specific to sessad healthcare

c0014064 Mikaël Ates
# START Specific to cmpp healthcare
def is_act_covered_by_diagnostic_healthcare(self):
0906807f Mikaël Ates
from calebasse.dossiers.models import CmppHealthCareDiagnostic
from validation import are_all_acts_of_the_day_locked
c0014064 Mikaël Ates
# L'acte est déja pointé par une prise en charge
if self.is_billed:
# Sinon ce peut une refacturation, donc ne pas tenir compte qu'il
# y est une healthcare non vide
if self.healthcare and isinstance(self.healthcare,
CmppHealthCareDiagnostic):
return (False, self.healthcare)
elif self.healthcare:
return (False, None)
# L'acte doit être facturable
if not (are_all_acts_of_the_day_locked(self.date) and \
4704ebbc Mikaël Ates
self.is_state('VALIDE') and self.is_billable()):
c0014064 Mikaël Ates
return (False, None)
# On prend la dernière prise en charge diagnostic, l'acte ne sera pas
# pris en charge sur une prise en charge précédente
# Il peut arriver que l'on ait ajouté une prise en charge de
# traitement alors que tous les actes pour le diag ne sont pas encore facturés
try:
hc = CmppHealthCareDiagnostic.objects.\
filter(patient=self.patient).latest('start_date')
except:
return (False, None)
if not hc:
# On pourrait ici créer une prise en charge de diagnostic
return (False, None)
76974b6f Benjamin Dauvergne
if self.date < hc.start_date:
c0014064 Mikaël Ates
return (False, None)
# Les acts facturés déja couvert par la prise en charge sont pointés
# dans hc.act_set.all()
nb_acts_billed = len(hc.act_set.all())
if nb_acts_billed >= hc.get_act_number():
return (False, None)
# Il faut ajouter les actes facturables non encore facturés qui précède cet
# acte
acts_billable = [a for a in self.patient.act_set.\
filter(is_billed=False).order_by('date') \
if are_all_acts_of_the_day_locked(a.date) and \
4704ebbc Mikaël Ates
a.is_state('VALIDE') and a.is_billable()]
c0014064 Mikaël Ates
count = 0
for a in acts_billable:
if nb_acts_billed + count >= hc.get_act_number():
return (False, None)
76974b6f Benjamin Dauvergne
if a.date >= hc.start_date:
c0014064 Mikaël Ates
if a.id == self.id:
return (True, hc)
count = count + 1
return (False, None)

5d71419d Mikaël Ates
# def is_act_covered_by_treatment_healthcare(self):
# # L'acte est déja pointé par une prise en charge
# if self.is_billed:
# # Sinon ce peut une refacturation, donc ne pas tenir compte qu'il
# # y est une healthcare non vide
# if self.healthcare and isinstance(self.healthcare,
# CmppHealthCareTreatment):
# return (False, self.healthcare)
# elif self.healthcare:
# return (False, None)
# # L'acte doit être facturable
# if not (are_all_acts_of_the_day_locked(self.date) and \
# self.is_state('VALIDE') and self.is_billable()):
# return (False, None)
# # On prend la dernière prise en charge diagnostic, l'acte ne sera pas
# # pris en charge sur une prise en charge précédente
# # Il peut arriver que l'on ait ajouté une prise en charge de
# # traitement alors que tous les actes pour le diag ne sont pas encore facturés
# try:
# hc = CmppHealthCareTreatment.objects.\
# filter(patient=self.patient).latest('start_date')
# except:
# return (False, None)
# if not hc:
# return (False, None)
# if self.date < hc.start_date or self.date > hc.end_date:
# return (False, None)
# # Les acts facturés déja couvert par la prise en charge sont pointés
# # dans hc.act_set.all()
# nb_acts_billed = len(hc.act_set.all())
# if nb_acts_billed >= hc.get_act_number():
# return (False, None)
# # Il faut ajouter les actes facturables non encore facturés qui précède cet
# # acte
# acts_billable = [a for a in self.patient.act_set.\
# filter(is_billed=False).order_by('date') \
# if are_all_acts_of_the_day_locked(a.date) and \
# a.is_state('VALIDE') and a.is_billable()]
# count = 0
# for a in acts_billable:
# if nb_acts_billed + count >= hc.get_act_number():
# return (False, None)
# if a.date >= hc.start_date and a.date <= hc.end_date:
# if a.id == self.id:
# return (True, hc)
# count = count + 1
# return (False, None)
76974b6f Benjamin Dauvergne
# END Specific to cmpp healthcare

433b67bb Benjamin Dauvergne
def save(self, *args, **kwargs):
super(Act, self).save(*args, **kwargs)

76974b6f Benjamin Dauvergne
def duration(self):
'''Return a displayable duration for this field.'''
hours, remainder = divmod(self._duration, 60)
return '%02d:%02d' % (hours, remainder)
c0014064 Mikaël Ates
55a8e535 Benjamin Dauvergne
def __unicode__(self):
317c2f75 Benjamin Dauvergne
return u'{0} le {1} pour {2} avec {3}'.format(
55a8e535 Benjamin Dauvergne
self.act_type, self.date, self.patient,
', '.join(map(unicode, self.doctors.all())))

def __repr__(self):
return '<%s %r %r>' % (self.__class__.__name__, unicode(self), self.id)

5c2d0ea2 Benjamin Dauvergne
def cancel(self):
'''Parent event is canceled completely, or partially, act upon it.
'''
new_act = self.actvalidationstate_set.count() > 1
if self.date <= date.today():
if new_act:
self.set_state('ANNUL_NOUS', get_request().user)
self.parent_event = None
self.save()
else:
self.delete()

55a8e535 Benjamin Dauvergne
class Meta:
verbose_name = u"Acte"
verbose_name_plural = u"Actes"
ordering = ['-date', 'patient']

96f613c6 Benjamin Dauvergne
e39efb4a Jérôme Schneider
class EventActManager(EventManager):

a2addd88 Mikaël Ates
def create_patient_appointment(self, creator, title, patient, participants,
d602f09e Mikaël Ates
act_type, service, start_datetime, end_datetime, description='',
room=None, note=None, **rrule_params):
e39efb4a Jérôme Schneider
"""
This method allow you to create a new patient appointment quickly

Args:
title: patient appointment title (str)
patient: Patient object
participants: List of CalebasseUser (therapists)
act_type: ActType object
service: Service object. Use session service by defaut
start_datetime: datetime with the start date and time
end_datetime: datetime with the end date and time
freq, count, until, byweekday, rrule_params:
follow the ``dateutils`` API (see http://labix.org/python-dateutil)

Example:
d602f09e Mikaël Ates
Look at calebasse.agenda.tests.EventTest (test_create_appointments
method)
e39efb4a Jérôme Schneider
"""

event_type, created = EventType.objects.get_or_create(
fb9d7270 Jérôme Schneider
label=u"Rendez-vous patient"
e39efb4a Jérôme Schneider
)

act_event = EventAct.objects.create(
title=title,
event_type=event_type,
patient=patient,
act_type=act_type,
a2addd88 Mikaël Ates
date=start_datetime,
e39efb4a Jérôme Schneider
)
74ba9776 Benjamin Dauvergne
act_event.doctors = participants
4704ebbc Mikaël Ates
ActValidationState(act=act_event, state_name='NON_VALIDE',
a2addd88 Mikaël Ates
author=creator, previous_state=None).save()

e39efb4a Jérôme Schneider
return self._set_event(act_event, participants, description,
d602f09e Mikaël Ates
services=[service], start_datetime=start_datetime,
end_datetime=end_datetime,
room=room, note=note, **rrule_params)
e39efb4a Jérôme Schneider
0d46dc26 Mikaël Ates
class ValidationMessage(ServiceLinkedAbstractModel):
validation_date = models.DateTimeField()
what = models.CharField(max_length=256)
who = models.ForeignKey(User)
when = models.DateTimeField(auto_now_add=True)