Merge branch 'master' into demo

This commit is contained in:
Jérôme Schneider 2014-07-07 19:19:56 +02:00
commit 04e3ad2193
52 changed files with 1050 additions and 468 deletions

View File

@ -6,4 +6,4 @@ Installation with virtualenv on Debian
. ./venv/bin/activate
pip install -U setuptools
pip install -U pip
pip install -r requirements
pip install -r requirements.txt

View File

@ -18,6 +18,7 @@ class ActSearchForm(forms.Form):
('lost', u'Perdus'),
('pause-invoicing', u'En pause facturation'),
('invoiced', u'Facturés'),
('group', u'De groupe'),
# ('current-invoicing', u'Facturation en cours')
)

View File

@ -221,7 +221,8 @@ class Act(models.Model):
# END Specific to sessad healthcare
def save(self, *args, **kwargs):
super(Act, self).save(*args, **kwargs)
if self.parent_event and not self.parent_event.canceled:
super(Act, self).save(*args, **kwargs)
def duration(self):
'''Return a displayable duration for this field.'''

View File

@ -8,6 +8,8 @@ from django.shortcuts import redirect
from calebasse.cbv import ListView, UpdateView, DeleteView
from calebasse.agenda.views import NewAppointmentView
from calebasse.agenda.models import EventWithAct
from calebasse.agenda.forms import UpdateAppointmentForm, NewAppointmentForm
import copy
import models
@ -28,6 +30,7 @@ class ActListingView(ListView):
qs = qs.filter(date=self.date)
self.search_form = forms.ActSearchForm(data=self.request.GET or None)
last_name = self.request.GET.get('last_name')
group = self.request.GET.get('group')
patient_record_id = self.request.GET.get('patient_record_id')
social_security_number = self.request.GET.get('social_security_number')
doctor_name = self.request.GET.get('doctor_name')
@ -40,6 +43,8 @@ class ActListingView(ListView):
qs = qs.filter(doctors__last_name__icontains=doctor_name)
if 'valide' in filters:
qs = qs.exclude(last_validation_state__state_name__exact='VALIDE')
if 'group' in filters:
qs = qs.filter(act_type__group=True)
if 'pointe' in filters:
qs = qs.filter(last_validation_state__isnull=False). \
exclude(last_validation_state__state_name__exact='NON_VALIDE')
@ -74,6 +79,8 @@ class ActListingView(ListView):
class NewAct(NewAppointmentView):
success_url = '.'
success_msg = u'Acte enregistré avec succès.'
model = EventWithAct
form_class = UpdateAppointmentForm
def form_valid(self, form):
result = super(NewAct, self).form_valid(form)

View File

@ -10,7 +10,7 @@ from ..ressources.models import ActType
from ..middleware.request import get_request
from ajax_select import make_ajax_field
from ajax_select.fields import AutoCompleteSelectField
from ajax_select.fields import AutoCompleteSelectField, AutoCompleteSelectMultipleField
from models import Event, EventWithAct, EventType
class BaseForm(forms.ModelForm):
@ -22,7 +22,7 @@ class BaseForm(forms.ModelForm):
class NewAppointmentForm(BaseForm):
patient = make_ajax_field(EventWithAct, 'patient', 'patientrecord', False)
patient = AutoCompleteSelectMultipleField('patientrecord')
class Meta:
model = EventWithAct
@ -65,7 +65,12 @@ class NewAppointmentForm(BaseForm):
try:
return int(duration)
except ValueError:
return 0
raise forms.ValidationError('Veuillez saisir un entier')
def clean_patient(self):
patients = self.cleaned_data['patient']
if patients:
return [patient for patient in PatientRecord.objects.filter(pk__in=patients)]
def clean(self):
cleaned_data = super(NewAppointmentForm, self).clean()
@ -74,8 +79,37 @@ class NewAppointmentForm(BaseForm):
if cleaned_data.has_key('date') and cleaned_data.has_key('time'):
cleaned_data['start_datetime'] = datetime.combine(cleaned_data['date'],
cleaned_data['time'])
if 'patient' in cleaned_data and isinstance(cleaned_data['patient'], list):
# nasty trick to store the list of patients and pass the form
# validation
cleaned_data['patients'] = cleaned_data['patient']
cleaned_data['patient'] = cleaned_data['patient'][0]
return cleaned_data
def save(self, commit=True):
patients = self.cleaned_data.pop('patients')
for patient in patients:
appointment = forms.save_instance(self, self._meta.model(), commit=False)
appointment.start_datetime = datetime.combine(self.cleaned_data['date'],
self.cleaned_data['time'])
appointment.end_datetime = appointment.start_datetime + timedelta(
minutes=self.cleaned_data['duration'])
appointment.creator = get_request().user
appointment.clean()
if commit:
appointment.patient = patient
appointment.save()
self.save_m2m()
appointment.services = [self.service]
class UpdateAppointmentForm(NewAppointmentForm):
patient = make_ajax_field(EventWithAct, 'patient', 'patientrecord', False)
def clean_patient(self):
return self.cleaned_data['patient']
def save(self, commit=True):
appointment = super(NewAppointmentForm, self).save(commit=False)
appointment.start_datetime = datetime.combine(self.cleaned_data['date'],
@ -86,25 +120,13 @@ class NewAppointmentForm(BaseForm):
appointment.clean()
if commit:
appointment.save()
self.save_m2m()
appointment.services = [self.service]
return appointment
class UpdateAppointmentForm(NewAppointmentForm):
class Meta(NewAppointmentForm.Meta):
fields = (
'start_datetime',
'date',
'time',
'duration',
'patient',
'participants',
'ressource',
'act_type',
)
class UpdatePeriodicAppointmentForm(NewAppointmentForm):
class UpdatePeriodicAppointmentForm(UpdateAppointmentForm):
patient = make_ajax_field(EventWithAct, 'patient', 'patientrecord', False)
recurrence_periodicity = forms.ChoiceField(label=u"Périodicité",
choices=Event.PERIODICITIES, required=True)
@ -152,7 +174,7 @@ class NewEventForm(BaseForm):
'services',
'description',
'recurrence_periodicity',
'recurrence_end_date'
'recurrence_end_date',
)
widgets = {
'start_datetime': forms.HiddenInput,

View File

@ -49,7 +49,7 @@ class EventQuerySet(InheritanceQuerySet):
occurences = ( e.today_occurrence(today) for e in self )
return sorted(occurences, key=lambda e: e.start_datetime)
def daily_disponibilities(self, date, events, participants, time_tables,
def daily_disponibilities(self, date, events, participant, time_tables,
holidays):
'''Slice the day into quarters between 8:00 and 19:00, and returns the
list of particpants with their status amon free, busy and away for each
@ -63,35 +63,64 @@ class EventQuerySet(InheritanceQuerySet):
'''
result = dict()
quarter = 0
events_set = {}
timetables_set = {}
holidays_set = {}
for participant in participants:
events_set[participant.id] = IntervalSet((o.to_interval() for o in events[participant.id] if not o.is_event_absence()))
timetables_set[participant.id] = IntervalSet((t.to_interval(date) for t in time_tables[participant.id]))
holidays_set[participant.id] = IntervalSet((h.to_interval(date) for h in holidays[participant.id]))
events_intervals = IntervalSet((o.to_interval() for o in events if not o.is_event_absence()))
timetables_intervals = IntervalSet((t.to_interval(date) for t in time_tables))
holidays_intervals = IntervalSet((h.to_interval(date) for h in holidays))
start_datetime = datetime(date.year, date.month, date.day, 8, 0)
end_datetime = datetime(date.year, date.month, date.day, 8, 15)
while (start_datetime.hour <= 19):
for participant in participants:
if not result.has_key(start_datetime.hour):
result[start_datetime.hour] = [[], [], [], []]
quarter = 0
interval = IntervalSet.between(start_datetime, end_datetime, False)
mins = quarter * 15
if interval.intersection(events_set[participant.id]):
result[start_datetime.hour][quarter].append((mins, {'id': participant.id, 'dispo': 'busy'}))
elif interval.intersection(holidays_set[participant.id]):
result[start_datetime.hour][quarter].append((mins, {'id': participant.id, 'dispo': 'busy'}))
elif not interval.intersection(timetables_set[participant.id]):
result[start_datetime.hour][quarter].append((mins, {'id': participant.id, 'dispo': 'away'}))
else:
result[start_datetime.hour][quarter].append((mins, {'id': participant.id, 'dispo': 'free'}))
if not result.has_key(start_datetime.hour):
result[start_datetime.hour] = [[], [], [], []]
quarter = 0
interval = IntervalSet.between(start_datetime, end_datetime, False)
mins = quarter * 15
crossed_events = self.overlap_occurences(start_datetime, events)
if len(crossed_events) > 1:
result[start_datetime.hour][quarter].append((mins, {'id': participant.id, 'dispo': 'overlap'}))
elif interval.intersection(events_intervals):
result[start_datetime.hour][quarter].append((mins, {'id': participant.id, 'dispo': 'busy'}))
elif interval.intersection(holidays_intervals):
result[start_datetime.hour][quarter].append((mins, {'id': participant.id, 'dispo': 'busy'}))
elif not interval.intersection(timetables_intervals):
result[start_datetime.hour][quarter].append((mins, {'id': participant.id, 'dispo': 'away'}))
else:
result[start_datetime.hour][quarter].append((mins, {'id': participant.id, 'dispo': 'free'}))
quarter += 1
start_datetime += timedelta(minutes=15)
end_datetime += timedelta(minutes=15)
return result
def overlap_occurences(self, date_time=None, events=None):
"""
returns the list of overlapping event occurences which do not begin and end
at the same time and have the same act type
"""
date_time = date_time or datetime.now()
if events is None:
events = self.today_occurrences(date_time.date())
overlap = filter(lambda e: e.start_datetime <= date_time and e.end_datetime > date_time \
and not e.is_absent(), events)
same_type_events = []
different_overlap = []
for event in overlap:
if different_overlap:
for e in different_overlap:
try:
if event.start_datetime == e.start_datetime and \
event.end_datetime == e.end_datetime and \
event.act_type == e.act_type:
continue
different_overlap.append(event)
except AttributeError:
continue
else:
different_overlap.append(event)
return different_overlap
class EventManager(PassThroughManager.for_queryset_class(EventQuerySet),
InheritanceManager):

View File

@ -393,6 +393,9 @@ class Event(models.Model):
def is_event_absence(self):
return False
def get_inactive_participants(self):
return self.participants.filter(worker__enabled=False)
def get_missing_participants(self):
missing_participants = []
for participant in self.participants.all():
@ -446,6 +449,12 @@ class Event(models.Model):
parts.append(self.recurrence_end_date.strftime('%d/%m/%Y'))
return u' '.join(parts)
def is_absent(self):
try:
return self.eventwithact.is_absent()
except self.DoesNotExist:
return False
def __unicode__(self):
return self.title
@ -512,7 +521,7 @@ class EventWithAct(Event):
act.save = old_save
old_save(*args, **kwargs)
act.comment = self.description
act.doctors = self.participants.select_subclasses()
act.doctors = (participant.worker for participant in self.participants.all())
last_validation_state = ActValidationState.objects.create(
act=act, state_name='NON_VALIDE',
author=self.creator, previous_state=None)

View File

@ -18,7 +18,7 @@
<div class="worker-agenda">
<h2>
<strong>{{ service_name }}</strong> - Planning de {{ worker_agenda.worker.first_name }} <span class="lastname">{{ worker_agenda.worker.last_name }}</span>
<input type="checkbox" class="printable" checked>
<input type="checkbox" class="printable" {% if worker_agenda.has_events %}checked{% endif %}>
</h2>
<h3>{{ date|date:"DATE_FORMAT"|title }}</h3>

View File

@ -4,30 +4,43 @@
<div>
{% for appointment in ressource_agenda.appointments %}
<h3 class="{{ appointment.type }} {% if appointment.act_absence %}act-absence{% endif %} appointment"
{% if appointment.act_absence %}title="{{appointment.act_absence}}"{% endif %}>
{% if appointment.act_absence %}title="{{appointment.act_absence}}"{% endif %} id="{{ appointment.event_id }}">
<span class="hour">{{ appointment.begin_hour }}</span>
{% if appointment.event_type %} — {{ appointment.event_type }} {% endif %}
{% if appointment.title %} — {{ appointment.title }} {% endif %}
{% if appointment.length %} — {{ appointment.length }}m {% endif %}
{% if appointment.ressources_initial %} —{{ appointment.ressources_initial }} {% endif %}
{% if appointment.act_type %} — {{ appointment.act_type }} {% endif %}
{% if appointment.ressource %} — {{ appointment.ressource }} {% endif %}
{% if appointment.title %}<span class="title">{{ appointment.title }}</span>{% endif %}
{% if appointment.length %}<span class="length">{{ appointment.length }} min</span> {% endif %}
{% if appointment.act_type %}<span class="act_type">{{ appointment.act_type }}</span>{% endif %}
<span class="participants">
{% if appointment.len_workers > 4 %}
{% if appointment.workers_absent %}<span class="absent" title="Au moins un intervenant est absent">{% endif %}
{{ appointment.len_workers }} inter.
{% if appointment.workers_absent %}</span>{% endif %}
{% else %}
{% if appointment.workers %}
{% for worker in appointment.workers %}
{% if worker in appointment.workers_absent %}<span class="absent" title="Absent">{% endif %}
{{ worker.worker.initials }}{% if not forloop.last %} {% endif %}
{% if worker in appointment.workers_absent %}</span>{% endif %}
{% endfor %}
{% endif %}
{% endif %}
</span>
<span class="right">
{% for service_name in appointment.other_services_names %}
<span class="box {{ service_name }}" title="{{ service_name }}"></span>
{% endfor %}
{% if appointment.description %}
<span title="Un commentaire existe" class="icon-comment"></span>
{% endif %}
<span title="Un commentaire existe" class="icon-comment" {% if appointment.description %}style='display: inline'{% endif %}></span>
{% if appointment.event_id %}
{% if appointment.is_recurrent %} R {% endif %}
{% if appointment.patient_record_id %}
<button title="Éditer un rendez-vous" class="edit-appointment icon-edit" data-event-id="{{ appointment.event_id }}"></button>
{% else %}
<button title="Éditer un événement" class="edit-event icon-edit" data-event-id="{{ appointment.event_id }}">
{% if service in appointment.services_names %}
{% if appointment.patient_record_id %}
<button title="Éditer un rendez-vous" class="edit-appointment icon-edit" data-event-id="{{ appointment.event_id }}"></button>
{% else %}
<button title="Éditer un événement" class="edit-event icon-edit" data-event-id="{{ appointment.event_id }}">
{% endif %}
<button class="remove-appointment icon-remove-sign" title="Supprimer un rendez-vous" data-url="{% url 'delete-occurrence' date=date service=service pk=appointment.event_id %}" data-rdv="{{ appointment.title }}"></button>
<button class="remove-appointment icon-remove-sign" title="Supprimer un rendez-vous" data-url="{% url 'delete-occurrence' date=date service=service pk=appointment.event_id %}" data-rdv="{{ appointment.title }}"></button>
{% endif %}
{% endif %}
</span>
</h3>
@ -45,11 +58,15 @@
{% endfor %}
</p>
{% endif %}
<div class="tabs-ressource-{{ ressource_agenda.ressource.id }} textedit">
<span></span>
<textarea>{{ appointment.description }}</textarea>
<button disabled="disabled" data-event-id="{{ appointment.event_id }}"></button>
</div>
{% if service in appointment.services_names %}
<div class="tabs-ressource-{{ ressource_agenda.ressource.id }} textedit">
<span></span>
<textarea>{{ appointment.description }}</textarea>
<button disabled="disabled" data-event-id="{{ appointment.event_id }}" data-date="{{ date|date:"Y-m-d" }}"></button>
</div>
{% else %}
<p>{{ appointment.description }}</p>
{% endif %}
{% endif %}
{% if appointment.patient_record_id %}
<p class="phones">
@ -57,7 +74,9 @@
{% if address.place_of_life and address.phone %}
<span title="{{ address.number }} {{ address.street }} {{ address.zip_code }} {{ address.city }}" class="icon-home-space">{{ address.phone }}</span>
{% for contact in address.patientcontact_set.all %}
<span title="{{ contact.first_name }} {{ contact.last_name|upper }}" class="icon-user-space">{{ contact.mobile }}</span>
{% if contact.mobile %}
<span title="{{ contact.first_name }} {{ contact.last_name|upper }}" class="icon-user-space">{{ contact.mobile }}</span>
{% endif %}
{% endfor %}
{% endif %}
{% endfor %}

View File

@ -3,10 +3,10 @@
<p><a href="{% url 'periodic-events-for-worker' service=service date=date worker_id=worker_agenda.worker.id %}">Rendez-vous périodiques</a></p>
<div {% if appointment.event_id %}data-event-id="{{ appointment.event_id }}"{% endif %}>
{% for appointment in worker_agenda.appointments %}
<h3 class="{{ appointment.type }} {% if appointment.act_absence %}act-absence{% endif %} appointment"
<h3 id="{{ appointment.event_id }}" class="{{ appointment.type }} {% if appointment.act_absence %}act-absence{% endif %} appointment"
{% if appointment.act_absence %}title="{{appointment.act_absence}}"{% endif %}>
<span class="hour">{{ appointment.begin_hour }}</span>
<span class="length">{% if appointment.length %}{% if appointment.length|str_length_lt:3 %}&nbsp;{% endif %}{{ appointment.length }} mn{% endif %}</span>
<span class="length">{% if appointment.length %}{% if appointment.length|str_length_lt:3 %}&nbsp;{% endif %}{{ appointment.length }} min{% endif %}</span>
<span class="title">{% if appointment.title %}{{ appointment.title }}{% endif %}
{% if appointment.patient.paper_id %} {{ appointment.patient.paper_id }} {% endif %}</span>
<span class="participants">
@ -33,9 +33,7 @@
{% for service_name in appointment.other_services_names %}
<span class="box {{ service_name }}" title="{{ service_name }}"></span>
{% endfor %}
{% if appointment.description %}
<span title="Un commentaire existe" class="icon-comment"></span>
{% endif %}
<span title="Un commentaire existe" class="icon-comment" {% if appointment.description %}style='display: inline'{% endif %}></span>
{% if appointment.event_id %}
{% if appointment.is_recurrent %} R {% endif %}
{% if appointment.patient.confidential %}

View File

@ -49,12 +49,14 @@
</td>
<td {% if form.patient.field.required %}class="required"{% endif %}>
<h4>{{ form.patient.label_tag }}</h4>
<div id="patient">
{% if object.exception_to and not object.exception_to.canceled %}
{{ object.patient }}
{% else %}
{{ form.patient }}
{{ form.patient.errors }}
{% endif %}
</div>
</td>
<td {% if form.act_type.field.required %}class="required"{% endif %}>
<h4>{{ form.act_type.label_tag }}</h4>
@ -76,12 +78,12 @@
{% if object.exception_to %}
<hr/>
{% if object.id != object.exception_to.id %}
<p><em>Attention: cette objet est une exception à un rendez-vous périodique; si
<p><em>Attention: cet objet est une exception à un rendez-vous périodique; si
vous modifiez ou supprimiez ce rendez-vous périodique, l'exception n'en serait pas
affecté.</em></p>
affectée.</em></p>
{% endif %}
<div>Occurence du {{object.exception_date}} d'un rendez-vous périodique
{% if object.exception_to.canceled %}<em>supprimé</em> et initialement prévu{% endif %}
{% if object.exception_to.canceled %}<em>supprimée</em> et initialement prévue{% endif %}
{{ object.exception_to.recurrence_description|lower }}</div>
{% if not object.exception_to.canceled %}
<button type="button" data-delete-url="{% url 'delete-event' service=service date=date pk=object.exception_to.pk %}" data-id="{{ object.exception_to.id }}" class="update-periodic-rdv">Éditer le rendez-vous périodique</button>

View File

@ -2,6 +2,7 @@
{% load url from future %}
{% block extrascripts %}
{{ block.super }}
<script src="{{ STATIC_URL }}js/json2.js"></script>
<script src="{{ STATIC_URL }}js/calebasse.agenda.js"></script>
<script src="{{ STATIC_URL }}js/calebasse.datesel.js"></script>

View File

@ -84,12 +84,12 @@
{% if object.exception_to %}
<hr/>
{% if object.id != object.exception_to.id %}
<p><em>Attention: cette objet est une exception à un évènement périodique; si
<p><em>Attention: cet objet est une exception à un évènement périodique; si
vous modifiez ou supprimiez cet évènement périodique, l'exception n'en serait pas
affecté.</em></p>
affectée.</em></p>
{% endif %}
<div>Occurence du {{object.exception_date}} d'un évènement périodique
{% if object.exception_to.canceled %}<em>supprimé</em> et initialement prévu{% endif %}
{% if object.exception_to.canceled %}<em>supprimée</em> et initialement prévue{% endif %}
{{ object.exception_to.recurrence_description|lower }}</div>
{% if not object.exception_to.canceled %}
<button type="button" data-delete-url="{% url 'delete-event' service=service date=date pk=object.exception_to.pk %}" data-id="{{ object.exception_to.id }}" class="update-periodic-event">Éditer l'évènement périodique</button>

View File

@ -88,7 +88,7 @@
<span class="hour">{{ event.start_datetime.time }}</span>
{% if event.title %} — {{ event.title }} {% endif %}
{% if event.patient.paper_id %} — {{ event.patient.paper_id }} {% endif %}
{% if event.length %} — {{ event.length }} mn {% endif %}
{% if event.length %} — {{ event.length }} min {% endif %}
{% if event.workers_initial %} — {{ event.workers_initial }} {% endif %}
{% if event.ressource %} — {{ event.ressource }} {% endif %}
<span class="right">

View File

@ -1,168 +0,0 @@
{% extends "agenda/base.html" %}
{% load url from future %}
{% load apptags %}
{% block appbar %}
<h2>Agenda</h2>
<a href="../">Retourner à l'agenda</a>
<button class="newevent" data-hour="" data-url="{% url 'new-event' service=service date=date %}">Nouvel événement</button>
<button class="newrdv" data-hour="" data-url="{% url 'nouveau-rdv' service=service date=date %}">Nouveau rendez-vous patient</button>
{% endblock %}
{% block beforecontent %}
<div id="users">
<div id="filtre">
<input type="text"/>
</div>
<dl>
{% for ressources_type in ressources_types %}
<dt>{{ ressources_type.type }}</dt>
<dd><ul>
{% for ressource in ressources_type.ressources %}
<li id="selector-ressource-{{ressource.id}}" class="ressource-item" data-ressource-id="{{ressource.id}}" data-target=".ressource-{{ressource.id}}.agenda">{{ ressource.name }} <span class="toggle" title="cliquer pour déselectionner">(-)</span></li>
{% endfor %}
</ul></dd>
{% endfor %}
</dl>
</div>
{% endblock %}
{% block agenda-content %}
<table>
<tbody>
<tr>
<td id="dispos">
<button id="close-all-ressource-agendas" style="display: none">Fermer tous les agendas</button>
Disponibilités
<table>
<tr class="initials"><td></td></tr>
{% for start_time in disponibility_start_times %}
<tr class="hour-mark">
<td rowspan="4">{{ start_time }}:00</td>
</tr>
<tr></tr>
<tr></tr>
<tr></tr>
{% endfor %}
</table>
</td>
<td id="agendas">
<div id="tabs">
<ul>
{% for ressource_agenda in ressources_agenda %}
<li style="display: none" class="ressource-{{ ressource_agenda.ressource.id }} agenda">
<a id="link-tab-ressource-{{ ressource_agenda.ressource.id }}" href="#tabs-ressource-{{ ressource_agenda.ressource.id }}" class="tab" data-id="{{ ressource_agenda.ressource.id }}">{{ ressource_agenda.ressource.name }}</a>
<a href="#" style="padding: 3px;cursor: auto;" class="close-tab" data-target="selector-ressource-{{ ressource_agenda.ressource.id }}"><span class="ui-icon ui-icon-circle-close"></span></a>
</li>
{% endfor %}
</ul>
{% for ressource_agenda in ressources_agenda %}
<div id="tabs-ressource-{{ ressource_agenda.ressource.id }}" class="tabs agenda ressource-{{ ressource_agenda.ressource.id }}" style="display: none;">
<a class="print" href="#">Imprimer</a>
<div>
{% for appointment in ressource_agenda.appointments %}
<h3 class="{{ appointment.type }} {% if appointment.act_absence %}act-absence{% endif %} appointment"
{% if appointment.act_absence %}title="{{appointment.act_absence}}"{% endif %}>
<span class="hour">{{ appointment.begin_hour }}</span>
{% if appointment.event_type %} — {{ appointment.event_type }} {% endif %}
{% if appointment.title %} — {{ appointment.title }} {% endif %}
{% if appointment.length %} — {{ appointment.length }}m {% endif %}
{% if appointment.ressources_initial %} —{{ appointment.ressources_initial }} {% endif %}
{% if appointment.act_type %} — {{ appointment.act_type }} {% endif %}
{% if appointment.ressource %} — {{ appointment.ressource }} {% endif %}
<span class="right">
{% for service_name in appointment.other_services_names %}
<span class="box {{ service_name }}" title="{{ service_name }}"></span>
{% endfor %}
{% if appointment.description %}
<span title="Un commentaire existe" class="icon-comment"></span>
{% endif %}
{% if appointment.event_id %}
{% if appointment.is_recurrent %} R {% endif %}
{% if appointment.patient_record_id %}
<button title="Éditer un rendez-vous" class="edit-appointment icon-edit" data-event-id="{{ appointment.event_id }}"></button>
{% else %}
<button title="Éditer un événement" class="edit-event icon-edit" data-event-id="{{ appointment.event_id }}">
{% endif %}
<button class="remove-appointment icon-remove-sign" title="Supprimer un rendez-vous" data-url="{% url 'delete-occurrence' date=date service=service pk=appointment.event_id %}" data-rdv="{{ appointment.title }}"></button>
{% endif %}
</span>
</h3>
<div>
{% if appointment.type == 'free' %}
<button class='newrdv' data-url="{% url 'nouveau-rdv' service=service date=date %}" data-hour="{{ appointment.begin_hour }}">Nouveau rendez-vous patient</button>
<button class='newevent' data-url="{% url 'new-event' service=service date=date %}" data-hour="{{ appointment.begin_hour }}">Nouvel événement</button>
{% endif %}
{% if appointment.event_id %}
{% if appointment.workers %}
<p class="workers">
Intervenants :
{% for worker in appointment.workers %}
{{ worker.first_name }} <span class="lastname">{{ worker.last_name }}</span>{% if forloop.last %}.{% else %}, {% endif %}
{% endfor %}
</p>
{% endif %}
<div class="tabs-ressource-{{ ressource_agenda.ressource.id }} textedit">
<span></span>
<textarea>{{ appointment.description }}</textarea>
<button disabled="disabled" data-event-id="{{ appointment.event_id }}"></button>
</div>
{% endif %}
{% if appointment.patient_record_id %}
<p class="phones">
{% for address in appointment.patient.addresses.all %}
{% if address.place_of_life and address.phone %}
<span title="{{ address.number }} {{ address.street }} {{ address.zip_code }} {{ address.city }}" class="icon-home-space">{{ address.phone }}</span>
{% for contact in address.patientcontact_set.all %}
<span title="{{ contact.first_name }} {{ contact.last_name|upper }}" class="icon-user-space">{{ contact.mobile }}</span>
{% endfor %}
{% endif %}
{% endfor %}
</p>
<a href="/{{ service }}/dossiers/{{ appointment.patient_record_id }}/view" target="_blank">Dossier patient</a> -
<a href="/{{ service }}/dossiers/{{ appointment.patient_record_id }}/view#tab=5" target="_blank">Prochains rendez-vous</a> -
<a href="#" class="generate-mail-btn" data-dossier-id="{{ appointment.patient_record_id }}" data-date="{{date|date:"Y-m-d"}}" data-event-id="{{ appointment.event_id }}" data-next-url="{{ request.get_full_path }}">Courrier</a>
{% endif %}
{% if appointment.validation %}
<div><span>{% if appointment.validation.1 %}<strong>{{ appointment.validation.2 }}</strong>, le {{ appointment.validation.1.created }} par {{ appointment.validation.1.author }}
{% if appointment.validation.1.auto %}(par validation automatique){% endif %}. {% if appointment.validation.0.is_billed %}<strong>Acte facturé</strong>{% endif %}
{% else %}
Non pointé.
{% endif %}
</span>
{% if not appointment.validation.0.validation_locked and appointment.validation.3 %}
<form method="post" class="inline-form">
{% csrf_token %}
<input type="hidden" value="{{appointment.validation.0.id}}" name="acte-id">
<select data-previous="{{ last_status.state_name }}" name="act_state">
{% for state_name, display_state_name in appointment.validation.3.items %}
<option value="{{ state_name }}" {% if state_name == appointment.validation.1.state_name %}selected{% endif %}>{{ display_state_name }}</option>
{% endfor %}
</select>
<button>Modifier</button>
</form>
{% endif %}
</div>
{% endif %}
</div>
{% endfor %}
</div>
</div>
{% endfor %}
</div>
</div>
</td>
</tr>
</tbody>
</table>
{% endblock %}
{% block dialogs %}
<div id="rdv" style="display: none;"></div>
<div id="ajax-dlg" style="display: none;"></div>
{% endblock %}

View File

@ -10,6 +10,8 @@
{% block agenda-content %}
<div class="print-only page-header">{{ date|date:"DATE_FORMAT"|lower }}</div>
<h2 class="print-only">Activité du {{ service_name }} - {{ date|date:"DATE_FORMAT"|title }}</h2>
<table class="main" id="activity">

View File

@ -7,7 +7,7 @@ from itertools import chain
from django.contrib import messages
from django.db.models import Q
from django.shortcuts import redirect, get_object_or_404
from django.http import HttpResponseRedirect, HttpResponse
from django.http import HttpResponseRedirect, HttpResponse, Http404
from django.conf import settings
from calebasse.cbv import TemplateView, CreateView, UpdateView
@ -24,7 +24,7 @@ from calebasse.actes.validation import (automated_validation, unlock_all_acts_of
from calebasse import cbv
from calebasse.agenda.forms import (NewAppointmentForm, NewEventForm, UpdatePeriodicAppointmentForm,
DisablePatientAppointmentForm, UpdateAppointmentForm, UpdatePeriodicEventForm,
DisablePatientAppointmentForm, UpdateAppointmentForm, UpdatePeriodicEventForm,
UpdateEventForm, PeriodicEventsSearchForm)
logger = logging.getLogger(__name__)
@ -133,7 +133,7 @@ class AgendaServiceActivityView(TemplateView, cbv.ServiceViewMixin):
return context
class NewAppointmentView(cbv.ReturnToObjectMixin, cbv.ServiceFormMixin, CreateView):
class NewAppointmentView(cbv.ServiceFormMixin, CreateView):
model = EventWithAct
form_class = NewAppointmentForm
template_name = 'agenda/new-appointment.html'
@ -150,23 +150,22 @@ class NewAppointmentView(cbv.ReturnToObjectMixin, cbv.ServiceFormMixin, CreateVi
initial['duration'] = self.request.GET.get('duration')
return initial
def get_form_kwargs(self):
kwargs = super(NewAppointmentView, self).get_form_kwargs()
kwargs['service'] = self.service
return kwargs
def get_success_url(self):
return self.request.META.get('HTTP_REFERER', '..')
def form_valid(self, form):
obj = super(NewAppointmentView, self).form_valid(form)
messages.add_message(self.request, messages.INFO, self.success_msg)
return super(NewAppointmentView, self).form_valid(form)
return obj
class TodayOccurrenceMixin(object):
def get_object(self, queryset=None):
o = super(TodayOccurrenceMixin, self).get_object(queryset)
return o.today_occurrence(self.date)
obj = o.today_occurrence(self.date)
if obj:
return obj
raise Http404
class BaseAppointmentView(UpdateView):
@ -204,7 +203,6 @@ class UpdateAppointmentView(TodayOccurrenceMixin, BaseAppointmentView):
else:
return self.form_class
class UpdatePeriodicAppointmentView(BaseAppointmentView):
form_class = UpdatePeriodicAppointmentForm
template_name = 'agenda/new-appointment.html'
@ -278,12 +276,19 @@ class UpdatePeriodicEventView(BaseEventView):
template_name = 'agenda/new-event.html'
def delete_eventwithact(event):
assert event.event_type == 1
if event.act.id \
and not event.act.is_billed:
event.act.delete()
if not event.act.id or \
not event.act.is_billed:
assert event.event_type_id == 1
# in case of "event" is an instance of "Event" model and not "EventWithAct"
# and so doesn't have 'act' attribute
try:
if event.act.id \
and not event.act.is_billed:
event.act.delete()
if not event.act.id or \
not event.act.is_billed:
event.delete()
except AttributeError:
event.delete()
class DeleteOccurrenceView(TodayOccurrenceMixin, cbv.DeleteView):
@ -293,7 +298,7 @@ class DeleteOccurrenceView(TodayOccurrenceMixin, cbv.DeleteView):
def delete(self, request, *args, **kwargs):
self.object = self.get_object()
if self.object.event_type == 1:
if self.object.event_type_id == 1:
delete_eventwithact(self.object)
else:
self.object.delete()
@ -312,12 +317,12 @@ class DeleteEventView(cbv.DeleteView):
exception.recurrence_periodicity = None
exception.exception_to = None
exception.save()
if exception.event_type == 1:
if exception.event_type_id == 1:
delete_eventwithact(exception)
else:
exception.delete()
if self.object.event_type == 1:
if self.object.event_type_id == 1:
delete_eventwithact(self.object)
else:
self.object.delete()
@ -507,7 +512,8 @@ class AgendasTherapeutesView(AgendaHomepageView):
if all(map(lambda x: x.holiday, daily_appointments)):
continue
context['workers_agenda'].append({'worker': worker,
'appointments': daily_appointments})
'appointments': daily_appointments,
'has_events': True if events_worker else False})
for worker_agenda in context.get('workers_agenda', []):
patient_appointments = [x for x in worker_agenda['appointments'] if x.patient_record_id]
@ -627,14 +633,17 @@ class AjaxDisponibilityColumnView(TemplateView):
mins = quarter * 15
if events:
event = events[0]
if event.start_datetime <= start_datetime and event.end_datetime >= end_datetime:
dispo = 'busy'
for event in events:
overlap_events = Event.objects.overlap_occurences(start_datetime, events)
if len(overlap_events) > 1:
dispo = 'overlap'
elif event.start_datetime <= start_datetime and event.end_datetime >= end_datetime:
dispo = 'busy'
disponibility[start_datetime.hour][quarter].append((mins, {'id': ressource_id, 'dispo': dispo}))
quarter += 1
start_datetime += datetime.timedelta(minutes=15)
end_datetime += datetime.timedelta(minutes=15)
context['disponibility'] = disponibility
return context
@ -642,11 +651,11 @@ class AjaxDisponibilityColumnView(TemplateView):
def get_worker_context_data(self, worker_id, context):
worker = Worker.objects.get(pk=worker_id)
time_tables_worker = TimeTable.objects.select_related('worker'). \
time_tables = TimeTable.objects.select_related('worker'). \
filter(services=self.service, worker=worker). \
for_today(self.date). \
order_by('start_date')
holidays_worker = Holiday.objects.for_worker(worker). \
holidays = Holiday.objects.for_worker(worker). \
for_period(self.date, self.date). \
order_by('start_date')
events = Event.objects.for_today(self.date) \
@ -664,13 +673,13 @@ class AjaxDisponibilityColumnView(TemplateView):
events = list(events) + list(eventswithact)
events = [ e.today_occurrence(self.date) for e in events ]
time_tables_workers = {worker.id: time_tables_worker}
time_tables_workers = {worker.id: time_tables}
events_workers = {worker.id: events}
holidays_workers = {worker.id: holidays_worker}
holidays_workers = {worker.id: holidays}
context['initials'] = worker.initials
context['disponibility'] = Event.objects.daily_disponibilities(self.date,
events_workers, [worker], time_tables_workers, holidays_workers)
events, worker, time_tables, holidays)
return context
def get_context_data(self, ressource_type, ressource_id, **kwargs):

View File

@ -18,6 +18,7 @@ from calebasse.ressources.models import (HealthCenter, LargeRegime,
CodeCFTMEA, SocialisationDuration, MDPHRequest, MDPHResponse)
from ajax_select import make_ajax_field
from django_select2.widgets import Select2MultipleWidget
logger = logging.getLogger(__name__)
@ -111,10 +112,6 @@ class CivilStatusForm(ModelForm):
fields = ('first_name', 'last_name', 'birthdate', 'birthplace', 'gender', 'nationality')
class FilteredSelectMultipleMise(django.contrib.admin.widgets.FilteredSelectMultiple):
def __init__(self, **kwargs):
super(FilteredSelectMultipleMise, self).__init__(u'Catégorie', False)
class PhysiologyForm(ModelForm):
cranium_perimeter = forms.DecimalField(label=u"Périmètre cranien",
max_digits=5, decimal_places=2, localize=True,
@ -135,10 +132,11 @@ class PhysiologyForm(ModelForm):
'deficiency_polyhandicap', 'deficiency_behavioral_disorder',
'deficiency_in_diagnostic', 'deficiency_other_disorder')
widgets = {
'mises_1': FilteredSelectMultipleMise,
'mises_2': FilteredSelectMultipleMise,
'mises_3': FilteredSelectMultipleMise,
}
'mises_1': Select2MultipleWidget(attrs={'style': 'width: 32em'}),
'mises_2': Select2MultipleWidget(attrs={'style': 'width: 32em'}),
'mises_3': Select2MultipleWidget(attrs={'style': 'width: 32em'}),
}
def __init__(self, instance, **kwargs):
super(PhysiologyForm, self).__init__(instance=instance, **kwargs)

View File

@ -34,9 +34,6 @@ class PatientRecordLookup(CalebasseLookup):
return chain(qs, closed)
def format_match(self,obj):
return self.format_item_display(texte)
def get_result(self, obj):
return self.format_item_display(obj)

View File

@ -479,7 +479,7 @@ class PatientRecord(ServiceLinkedAbstractModel, PatientContact):
deficiency_polyhandicap = models.BooleanField(verbose_name=u'Polyhandicap',
default=False)
deficiency_behavioral_disorder = models.IntegerField(max_length=1,
verbose_name=u"Troubles du comportement et de la communication",
verbose_name=u"Troubles de la conduite et du comportement",
choices=DEFICIENCY_CHOICES,
default=0)
deficiency_in_diagnostic = models.BooleanField(verbose_name=u'En diagnostic',

View File

@ -7,6 +7,7 @@
{% block extrascripts %}
{{ block.super }}
<script src="{{ STATIC_URL }}js/jquery.parse-url.js"></script>
<script src="{{ STATIC_URL }}js/calebasse.dossiers.js"></script>
{% endblock %}

View File

@ -110,7 +110,7 @@
{% endif %}
<form method="post" action="tab1" id="create-directory-form" action="create-directory">{% csrf_token %}
<form method="post" action="{% url "create_directory" service object.id %}" id="create-directory-form">{% csrf_token %}
<button>Créer répertoire patient</button>
</form>
</div>

View File

@ -1,7 +1,7 @@
<div id="tabs-5">
{% for state, last_rdvs in history %}
<div class="frame">
<h3>{{ state.status.name }} depuis le {{ state.date_selected|date:"SHORT_DATE_FORMAT" }}</h3>
<h3>{% if state %}{{ state.status.name }} depuis le {{ state.date_selected|date:"SHORT_DATE_FORMAT" }}{% else %}Indéfini{% endif %}</h3>
{% if last_rdvs %}
<table class="basic">
<thead>

View File

@ -4,15 +4,23 @@
<tr> <th>Date</th> <th>Pointage</th> <th>Type d'acte</th> <th>Intervenants</th> <th>Commentaire</th> </tr>
</thead>
<tbody>
{% for event, state, missing_participants in next_rdvs %}
{% for event, state, missing_participants, inactive_participants in next_rdvs %}
<tr>
<td>{% firstof event.start_datetime|date:"l d/m/y H:i"|title %}{% if missing_participants %} <span title="Au moins un intervenant est absent" class="icon-warning-sign absent"></span>{% endif %}</td>
<td>{% firstof event.start_datetime|date:"l d/m/y H:i"|title %}{% if missing_participants or inactive_participants %} <span title="Au moins un intervenant est absent ou ne fait plus partie du service" class="icon-warning-sign absent"></span>{% endif %}</td>
<td>{% if state %}{% if state.state_name != 'VALIDE' %}<strong>{% endif %}{{ state }}{% if state.state_name != 'VALIDE' %}</strong>{% endif %}{% else %}Non pointé.{% endif %}</td>
<td>{{ event.act_type }}</td>
<td class="width-limited">{% for participant in event.participants.all %}
{% if participant in missing_participants %}<span class="absent" title="Absent">{% endif %}
{% if participant in missing_participants %}
<span class="absent" title="Absent">
{{ participant.first_name }} <span class="lastname">{{ participant.last_name }}</span>
{% if participant in missing_participants %}</span>{% endif %}
</span>
{% elif participant in inactive_participants %}
<span class="inactive" title="Ne fait plus parti du service">
{{ participant.first_name }} <span class="lastname">{{ participant.last_name }}</span>
</span>
{% else %}
{{ participant.first_name }} <span class="lastname">{{ participant.last_name }}</span>
{% endif %}
{% endfor %}</td>
{% if event.act.id %}
<td class="width-limited">{{ event.act.comment }}</td>

View File

@ -5,6 +5,14 @@
{% for duration in object.socialisation_durations.all %}
<div class="subframe">
Arrivée le <strong>{{ duration.start_date }}</strong> dans {% if duration.school %}l'établissement <strong>{{ duration.school }}</strong>{% else %}un établissement non renseigné{% endif %}{% if duration.level %} (en {{ duration.level }}){% endif %}
<ul>
{% if duration.school.address %}
<li><label>Adresse établissement : </label>{{ duration.school.address }}, {{ duration.school.zip_code }} {{ duration.school.city }}</span></li>
{% endif %}
{% if duration.school.phone %}
<li><span class="icon-phone">{{ duration.school.phone }}</span></li>
{% endif %}
</ul>
<div class="buttons">
<button type="button" data-id="{{ duration.id }}" class="del-duration icon-minus" title="Supprimer"></button>
<button type="button" data-id="{{ duration.id }}" class="update-duration-btn icon-edit" title="Modifier"></button>

View File

@ -1,15 +1,15 @@
{% extends "dossiers/base.html" %}
{% load url from future %}
{% load dossiers %}
{% block extrastyles %}
{{ block.super }}
<link rel="stylesheet" type="text/css" media="all" href="{{ STATIC_URL }}filter-widget/css/filter-widget.css"/>
{% endblock %}
{% block extrascripts %}
<link rel="stylesheet" type="text/css" media="all" href="{{ STATIC_URL }}filter-widget/css/filter-widget.css"/>
{{ block.super }}
<script src="{{ STATIC_URL }}js/jquery.parse-url.js"></script>
<script src="{{ STATIC_URL }}js/calebasse.dossiers.js"></script>
<script src="{{ STATIC_URL }}filter-widget/js/i18n.js"></script>
<script src="{{ STATIC_URL }}filter-widget/js/core.js"></script>
<script src="{{ STATIC_URL }}filter-widget/js/SelectBox.js"></script>
<script src="{{ STATIC_URL }}filter-widget/js/SelectFilter2.js"></script>
{% endblock %}
{% block title %}{{ object.last_name }} {{ object.first_name }}{% if object.paper_id %} - Dossier {{ object.paper_id}}{% endif %}{% endblock %}

View File

@ -49,7 +49,7 @@ urlpatterns = patterns('calebasse.dossiers.views',
url(r'^(?P<patientrecord_id>\d+)/mdph_response/(?P<pk>\d+)/update$', 'update_mdph_response'),
url(r'^(?P<patientrecord_id>\d+)/mdph_response/(?P<pk>\d+)/del$', 'delete_mdph_response'),
url(r'^(?P<patientrecord_id>\d+)/generate$', 'generate_rtf_form'),
url(r'^(?P<patientrecord_id>\d+)/create-directory$', 'create_directory'),
url(r'^(?P<patientrecord_id>\d+)/create-directory$', 'create_directory', name="create_directory"),
url(r'^(?P<patientrecord_id>\d+)/prescription-transport$', 'prescription_transport'),
url(r'^(?P<patientrecord_id>\d+)/protection/new$', 'new_protection'),
url(r'^(?P<patientrecord_id>\d+)/protection/(?P<pk>\d+)/update$', 'update_protection'),

View File

@ -270,10 +270,12 @@ class PatientRecordGeneralView(cbv.UpdateView):
ctx['last_rdv'] = get_last_rdv(ctx['object'])
ctx['next_rdv'] = get_next_rdv(ctx['object'])
current_state = ctx['object'].get_current_state()
if STATES_MAPPING.has_key(current_state.status.type):
if current_state.status and STATES_MAPPING.has_key(current_state.status.type):
state = STATES_MAPPING[current_state.status.type]
else:
elif current_state.status:
state = current_state.status.name
else:
state = "Aucun"
ctx['current_state'] = current_state
ctx['status'], ctx['hc_status'] = get_status(ctx, self.request.user)
ctx['missing_policy'] = False
@ -433,7 +435,7 @@ class PatientRecordNextAppointmentsView(cbv.DetailView):
state = event.act.get_state()
if state and not state.previous_state and state.state_name == 'NON_VALIDE':
state = None
ctx['next_rdvs'].append((event, state, event.get_missing_participants()))
ctx['next_rdvs'].append((event, state, event.get_missing_participants(), event.get_inactive_participants()))
return ctx
tab6_next_rdv = PatientRecordNextAppointmentsView.as_view()

View File

@ -14,7 +14,7 @@ def get_status(ctx, user):
"""
status = []
close_btn = STATES_BTN_MAPPER['CLOS']
if 'next_rdv' in ctx:
if ctx.get('next_rdv'):
close_btn = STATES_BTN_MAPPER['CLOS_RDV']
if ctx['object'].service.slug == "cmpp":
ctx['can_rediag'] = ctx['object'].create_diag_healthcare(user)

View File

@ -1,5 +1,7 @@
{% extends "facturation/base.html" %}
{% load url from future %}
{% block extrascripts %}
{% endblock %}
{% block appbar %}
<h2>{% if service_name == "CMPP" %}Facturation{% else %}Décompte{% endif %}</h2>

View File

@ -3,13 +3,15 @@
{% block title %}{{ block.super }} - Gestion des personnes {% endblock %}
{% block extrascripts %}
{{ block.super }}
<script src="{{ STATIC_URL }}js/calebasse.absences.js"></script>
{% endblock %}
{% block extrastyles %}
{{ block.super }}
<link rel="stylesheet" type="text/css" href="{{ STATIC_URL }}css/personnes.css" />
{% endblock %}
{{ block.super }}
<script src="{{ STATIC_URL }}js/calebasse.absences.js"></script>
{% endblock %}
{% block header %}
{{ block.super }}

View File

@ -1,6 +1,7 @@
{% extends "personnes/base.html" %}
{% block extrascripts %}
{{ block.super }}
<script>
$(function() {
$('#new-membre').click(function() {

View File

@ -168,8 +168,7 @@ class WorkerUpdateView(cbv.ServiceViewMixin, cbv.MultiUpdateView):
ctx['timetables'] = timetable
ctx['holidays'] = models.Holiday.objects \
.for_worker(self.object) \
.future() \
.order_by('start_date')
.order_by('-start_date')
try:
holiday = models.Holiday.objects \
.for_worker(self.object) \

View File

@ -1,8 +1,9 @@
# -*- coding: utf-8 -*-
import itertools
from calebasse.lookups import CalebasseLookup
from calebasse.personnes.models import Worker
from calebasse.ressources.models import Service
from calebasse.ressources.models import Service, School
class FakeGroup:
pk = None
@ -56,3 +57,28 @@ class WorkerOrGroupLookup(CalebasseLookup):
class AllWorkerOrGroupLookup(WorkerOrGroupLookup):
enabled = False
class SchoolLookup(CalebasseLookup):
model = School
search_field = 'name'
def get_result(self, obj):
return self.format_item_display(obj)
def format_match(self, obj):
return self.format_item_display(obj)
def format_item_display(self, obj):
text = ''
if obj.school_type.name != 'Inconnu':
text = unicode(obj.school_type) + ' ' + obj.name
else:
text = obj.name
if obj.address:
text += " - " + obj.address
if obj.private:
text += " (Privé)"
else:
text += " (Public)"
return text

View File

@ -0,0 +1,320 @@
# -*- coding: utf-8 -*-
from south.utils import datetime_utils as datetime
from south.db import db
from south.v2 import SchemaMigration
from django.db import models
class Migration(SchemaMigration):
def forwards(self, orm):
# Adding field 'ActType.group'
db.add_column(u'ressources_acttype', 'group',
self.gf('django.db.models.fields.BooleanField')(default=False),
keep_default=False)
def backwards(self, orm):
# Deleting field 'ActType.group'
db.delete_column(u'ressources_acttype', 'group')
models = {
u'ressources.acttype': {
'Meta': {'ordering': "('-display_first', 'name')", 'object_name': 'ActType'},
'billable': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
'display_first': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
'group': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'name': ('django.db.models.fields.CharField', [], {'max_length': '150'}),
'old_id': ('django.db.models.fields.CharField', [], {'max_length': '256', 'null': 'True', 'blank': 'True'}),
'service': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['ressources.Service']", 'null': 'True', 'blank': 'True'})
},
u'ressources.advicegiver': {
'Meta': {'object_name': 'AdviceGiver'},
u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'name': ('django.db.models.fields.CharField', [], {'max_length': '150'})
},
u'ressources.analysemotive': {
'Meta': {'object_name': 'AnalyseMotive'},
u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'name': ('django.db.models.fields.CharField', [], {'max_length': '150'})
},
u'ressources.codecftmea': {
'Meta': {'ordering': "['ordering_code']", 'object_name': 'CodeCFTMEA'},
'axe': ('django.db.models.fields.IntegerField', [], {'max_length': '1'}),
'code': ('django.db.models.fields.IntegerField', [], {}),
u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'name': ('django.db.models.fields.CharField', [], {'max_length': '150'}),
'ordering_code': ('django.db.models.fields.CharField', [], {'max_length': '20', 'null': 'True', 'blank': 'True'})
},
u'ressources.familymotive': {
'Meta': {'object_name': 'FamilyMotive'},
u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'name': ('django.db.models.fields.CharField', [], {'max_length': '150'})
},
u'ressources.familysituationtype': {
'Meta': {'object_name': 'FamilySituationType'},
u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'name': ('django.db.models.fields.CharField', [], {'max_length': '150'})
},
u'ressources.healthcenter': {
'Meta': {'object_name': 'HealthCenter'},
'abbreviation': ('django.db.models.fields.CharField', [], {'default': 'True', 'max_length': '8', 'null': 'True'}),
'accounting_number': ('django.db.models.fields.CharField', [], {'max_length': '30', 'null': 'True', 'blank': 'True'}),
'active': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
'address': ('django.db.models.fields.CharField', [], {'max_length': '120'}),
'address_complement': ('django.db.models.fields.CharField', [], {'default': 'None', 'max_length': '120', 'null': 'True', 'blank': 'True'}),
'city': ('django.db.models.fields.CharField', [], {'max_length': '80'}),
'code': ('django.db.models.fields.CharField', [], {'max_length': '4', 'null': 'True', 'blank': 'True'}),
'computer_center_code': ('django.db.models.fields.CharField', [], {'default': 'True', 'max_length': '8', 'null': 'True'}),
'correspondant': ('django.db.models.fields.CharField', [], {'max_length': '80'}),
'dest_organism': ('django.db.models.fields.CharField', [], {'max_length': '8'}),
'email': ('django.db.models.fields.EmailField', [], {'max_length': '75', 'null': 'True', 'blank': 'True'}),
'fax': ('django.db.models.fields.CharField', [], {'max_length': '30', 'null': 'True', 'blank': 'True'}),
'hc_invoice': ('django.db.models.fields.related.ForeignKey', [], {'default': 'None', 'to': u"orm['ressources.HealthCenter']", 'null': 'True', 'blank': 'True'}),
'health_fund': ('django.db.models.fields.CharField', [], {'max_length': '3'}),
u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'large_regime': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['ressources.LargeRegime']"}),
'name': ('django.db.models.fields.CharField', [], {'max_length': '150'}),
'phone': ('django.db.models.fields.CharField', [], {'max_length': '30'}),
'zip_code': ('django.db.models.fields.CharField', [], {'max_length': '8'})
},
u'ressources.holidaytype': {
'Meta': {'object_name': 'HolidayType'},
'for_group': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'name': ('django.db.models.fields.CharField', [], {'max_length': '150'})
},
u'ressources.inscriptionmotive': {
'Meta': {'object_name': 'InscriptionMotive'},
u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'name': ('django.db.models.fields.CharField', [], {'max_length': '150'})
},
u'ressources.job': {
'Meta': {'object_name': 'Job'},
u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'name': ('django.db.models.fields.CharField', [], {'max_length': '150'})
},
u'ressources.largeregime': {
'Meta': {'object_name': 'LargeRegime'},
'code': ('django.db.models.fields.CharField', [], {'max_length': '2'}),
u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'name': ('django.db.models.fields.CharField', [], {'max_length': '150'})
},
u'ressources.managementcode': {
'Meta': {'object_name': 'ManagementCode'},
'code': ('django.db.models.fields.CharField', [], {'max_length': '10'}),
u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'name': ('django.db.models.fields.CharField', [], {'max_length': '150'}),
'old_id': ('django.db.models.fields.CharField', [], {'max_length': '256', 'null': 'True', 'blank': 'True'})
},
u'ressources.maritalstatustype': {
'Meta': {'object_name': 'MaritalStatusType'},
u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'name': ('django.db.models.fields.CharField', [], {'max_length': '150'})
},
u'ressources.mdph': {
'Meta': {'object_name': 'MDPH'},
'address': ('django.db.models.fields.CharField', [], {'max_length': '120', 'null': 'True', 'blank': 'True'}),
'address_complement': ('django.db.models.fields.CharField', [], {'default': 'None', 'max_length': '120', 'null': 'True', 'blank': 'True'}),
'city': ('django.db.models.fields.CharField', [], {'max_length': '80', 'null': 'True', 'blank': 'True'}),
'department': ('django.db.models.fields.CharField', [], {'max_length': '200'}),
'description': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}),
'email': ('django.db.models.fields.EmailField', [], {'max_length': '75', 'null': 'True', 'blank': 'True'}),
'fax': ('calebasse.models.PhoneNumberField', [], {'max_length': '20', 'null': 'True', 'blank': 'True'}),
u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'phone': ('calebasse.models.PhoneNumberField', [], {'max_length': '20', 'null': 'True', 'blank': 'True'}),
'website': ('django.db.models.fields.CharField', [], {'max_length': '200', 'null': 'True', 'blank': 'True'}),
'zip_code': ('calebasse.models.ZipCodeField', [], {'max_length': '5', 'null': 'True', 'blank': 'True'})
},
u'ressources.mdphrequest': {
'Meta': {'object_name': 'MDPHRequest'},
'comment': ('django.db.models.fields.TextField', [], {'max_length': '3000', 'null': 'True', 'blank': 'True'}),
'created': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}),
u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'mdph': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['ressources.MDPH']"}),
'start_date': ('django.db.models.fields.DateField', [], {})
},
u'ressources.mdphresponse': {
'Meta': {'object_name': 'MDPHResponse'},
'comment': ('django.db.models.fields.TextField', [], {'max_length': '3000', 'null': 'True', 'blank': 'True'}),
'created': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}),
'end_date': ('django.db.models.fields.DateField', [], {}),
u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'mdph': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['ressources.MDPH']"}),
'name': ('django.db.models.fields.CharField', [], {'max_length': '200', 'null': 'True', 'blank': 'True'}),
'rate': ('django.db.models.fields.CharField', [], {'max_length': '10', 'null': 'True', 'blank': 'True'}),
'start_date': ('django.db.models.fields.DateField', [], {}),
'type_aide': ('django.db.models.fields.IntegerField', [], {'default': '0', 'max_length': '1'})
},
u'ressources.nationality': {
'Meta': {'object_name': 'Nationality'},
u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'name': ('django.db.models.fields.CharField', [], {'max_length': '150'})
},
u'ressources.office': {
'Meta': {'object_name': 'Office'},
'address': ('django.db.models.fields.CharField', [], {'default': 'None', 'max_length': '120', 'null': 'True', 'blank': 'True'}),
'address_complement': ('django.db.models.fields.CharField', [], {'default': 'None', 'max_length': '120', 'null': 'True', 'blank': 'True'}),
'city': ('django.db.models.fields.CharField', [], {'default': 'None', 'max_length': '80', 'null': 'True', 'blank': 'True'}),
'description': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}),
'email': ('django.db.models.fields.EmailField', [], {'max_length': '75', 'null': 'True', 'blank': 'True'}),
'fax': ('calebasse.models.PhoneNumberField', [], {'max_length': '20', 'null': 'True', 'blank': 'True'}),
u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'name': ('django.db.models.fields.CharField', [], {'max_length': '150'}),
'phone': ('calebasse.models.PhoneNumberField', [], {'max_length': '20', 'null': 'True', 'blank': 'True'}),
'zip_code': ('calebasse.models.ZipCodeField', [], {'default': 'None', 'max_length': '5', 'null': 'True', 'blank': 'True'})
},
u'ressources.outmotive': {
'Meta': {'object_name': 'OutMotive'},
u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'name': ('django.db.models.fields.CharField', [], {'max_length': '150'})
},
u'ressources.outto': {
'Meta': {'object_name': 'OutTo'},
u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'name': ('django.db.models.fields.CharField', [], {'max_length': '150'})
},
u'ressources.parentalauthoritytype': {
'Meta': {'object_name': 'ParentalAuthorityType'},
u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'name': ('django.db.models.fields.CharField', [], {'max_length': '150'})
},
u'ressources.parentalcustodytype': {
'Meta': {'object_name': 'ParentalCustodyType'},
u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'name': ('django.db.models.fields.CharField', [], {'max_length': '150'})
},
u'ressources.patientrelatedlink': {
'Meta': {'object_name': 'PatientRelatedLink'},
u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'name': ('django.db.models.fields.CharField', [], {'max_length': '150'}),
'old_camsp_id': ('django.db.models.fields.CharField', [], {'max_length': '256', 'null': 'True', 'blank': 'True'}),
'old_cmpp_id': ('django.db.models.fields.CharField', [], {'max_length': '256', 'null': 'True', 'blank': 'True'}),
'old_sessad_dys_id': ('django.db.models.fields.CharField', [], {'max_length': '256', 'null': 'True', 'blank': 'True'}),
'old_sessad_ted_id': ('django.db.models.fields.CharField', [], {'max_length': '256', 'null': 'True', 'blank': 'True'})
},
u'ressources.priceperact': {
'Meta': {'object_name': 'PricePerAct'},
u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'price': ('django.db.models.fields.DecimalField', [], {'max_digits': '5', 'decimal_places': '2'}),
'start_date': ('django.db.models.fields.DateField', [], {})
},
u'ressources.provenance': {
'Meta': {'object_name': 'Provenance'},
u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'name': ('django.db.models.fields.CharField', [], {'max_length': '150'}),
'old_id': ('django.db.models.fields.CharField', [], {'max_length': '256', 'null': 'True', 'blank': 'True'}),
'old_service': ('django.db.models.fields.CharField', [], {'max_length': '256', 'null': 'True', 'blank': 'True'})
},
u'ressources.provenanceplace': {
'Meta': {'object_name': 'ProvenancePlace'},
u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'name': ('django.db.models.fields.CharField', [], {'max_length': '150'})
},
u'ressources.ressource': {
'Meta': {'object_name': 'Ressource'},
'etablissement': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['ressources.Office']"}),
u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'name': ('django.db.models.fields.CharField', [], {'max_length': '150'})
},
u'ressources.school': {
'Meta': {'object_name': 'School'},
'address': ('django.db.models.fields.CharField', [], {'default': 'None', 'max_length': '120', 'null': 'True', 'blank': 'True'}),
'address_complement': ('django.db.models.fields.CharField', [], {'default': 'None', 'max_length': '120', 'null': 'True', 'blank': 'True'}),
'city': ('django.db.models.fields.CharField', [], {'default': 'None', 'max_length': '80', 'null': 'True', 'blank': 'True'}),
'description': ('django.db.models.fields.TextField', [], {'default': 'None', 'null': 'True', 'blank': 'True'}),
'director_name': ('django.db.models.fields.CharField', [], {'default': 'None', 'max_length': '70', 'null': 'True', 'blank': 'True'}),
'email': ('django.db.models.fields.EmailField', [], {'default': 'None', 'max_length': '75', 'null': 'True', 'blank': 'True'}),
'fax': ('django.db.models.fields.CharField', [], {'default': 'None', 'max_length': '30', 'null': 'True', 'blank': 'True'}),
u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'name': ('django.db.models.fields.CharField', [], {'max_length': '150'}),
'old_id': ('django.db.models.fields.CharField', [], {'max_length': '256', 'null': 'True', 'blank': 'True'}),
'old_service': ('django.db.models.fields.CharField', [], {'max_length': '256', 'null': 'True', 'blank': 'True'}),
'phone': ('calebasse.models.PhoneNumberField', [], {'default': 'None', 'max_length': '20', 'null': 'True', 'blank': 'True'}),
'private': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
'school_type': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['ressources.SchoolType']"}),
'zip_code': ('calebasse.models.ZipCodeField', [], {'default': 'None', 'max_length': '5', 'null': 'True', 'blank': 'True'})
},
u'ressources.schoollevel': {
'Meta': {'object_name': 'SchoolLevel'},
u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'name': ('django.db.models.fields.CharField', [], {'max_length': '150'}),
'old_id': ('django.db.models.fields.CharField', [], {'max_length': '256', 'null': 'True', 'blank': 'True'}),
'old_service': ('django.db.models.fields.CharField', [], {'max_length': '256', 'null': 'True', 'blank': 'True'})
},
u'ressources.schoolteacherrole': {
'Meta': {'object_name': 'SchoolTeacherRole'},
u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'name': ('django.db.models.fields.CharField', [], {'max_length': '150'})
},
u'ressources.schooltype': {
'Meta': {'object_name': 'SchoolType'},
u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'name': ('django.db.models.fields.CharField', [], {'max_length': '150'}),
'services': ('django.db.models.fields.related.ManyToManyField', [], {'to': u"orm['ressources.Service']", 'symmetrical': 'False'})
},
u'ressources.service': {
'Meta': {'object_name': 'Service'},
'description': ('django.db.models.fields.TextField', [], {}),
'email': ('django.db.models.fields.EmailField', [], {'max_length': '75'}),
'fax': ('calebasse.models.PhoneNumberField', [], {'max_length': '20'}),
u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'name': ('django.db.models.fields.CharField', [], {'max_length': '150'}),
'phone': ('calebasse.models.PhoneNumberField', [], {'max_length': '20'}),
'slug': ('django.db.models.fields.SlugField', [], {'max_length': '50'})
},
u'ressources.sessiontype': {
'Meta': {'object_name': 'SessionType'},
u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'name': ('django.db.models.fields.CharField', [], {'max_length': '150'})
},
u'ressources.socialisationduration': {
'Meta': {'object_name': 'SocialisationDuration'},
'comment': ('django.db.models.fields.TextField', [], {'max_length': '3000', 'null': 'True', 'blank': 'True'}),
'contact': ('django.db.models.fields.CharField', [], {'default': 'None', 'max_length': '200', 'null': 'True', 'blank': 'True'}),
'created': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}),
'end_date': ('django.db.models.fields.DateField', [], {'null': 'True', 'blank': 'True'}),
u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'level': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['ressources.SchoolLevel']", 'null': 'True', 'blank': 'True'}),
'redoublement': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
'school': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['ressources.School']", 'null': 'True', 'blank': 'True'}),
'start_date': ('django.db.models.fields.DateField', [], {})
},
u'ressources.transportcompany': {
'Meta': {'object_name': 'TransportCompany'},
'address': ('django.db.models.fields.CharField', [], {'default': 'None', 'max_length': '120', 'null': 'True', 'blank': 'True'}),
'address_complement': ('django.db.models.fields.CharField', [], {'default': 'None', 'max_length': '120', 'null': 'True', 'blank': 'True'}),
'city': ('django.db.models.fields.CharField', [], {'default': 'None', 'max_length': '80', 'null': 'True', 'blank': 'True'}),
'correspondant': ('django.db.models.fields.CharField', [], {'max_length': '80', 'null': 'True', 'blank': 'True'}),
'description': ('django.db.models.fields.TextField', [], {'default': 'None', 'null': 'True', 'blank': 'True'}),
'email': ('django.db.models.fields.EmailField', [], {'max_length': '75', 'null': 'True', 'blank': 'True'}),
'fax': ('django.db.models.fields.CharField', [], {'default': 'None', 'max_length': '30', 'null': 'True', 'blank': 'True'}),
u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'name': ('django.db.models.fields.CharField', [], {'max_length': '150'}),
'old_camsp_id': ('django.db.models.fields.CharField', [], {'max_length': '256', 'null': 'True', 'blank': 'True'}),
'old_cmpp_id': ('django.db.models.fields.CharField', [], {'max_length': '256', 'null': 'True', 'blank': 'True'}),
'old_sessad_dys_id': ('django.db.models.fields.CharField', [], {'max_length': '256', 'null': 'True', 'blank': 'True'}),
'old_sessad_ted_id': ('django.db.models.fields.CharField', [], {'max_length': '256', 'null': 'True', 'blank': 'True'}),
'phone': ('calebasse.models.PhoneNumberField', [], {'default': 'None', 'max_length': '20', 'null': 'True', 'blank': 'True'}),
'zip_code': ('calebasse.models.ZipCodeField', [], {'default': 'None', 'max_length': '5', 'null': 'True', 'blank': 'True'})
},
u'ressources.transporttype': {
'Meta': {'object_name': 'TransportType'},
u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'name': ('django.db.models.fields.CharField', [], {'max_length': '150'})
},
u'ressources.uninvoicablecode': {
'Meta': {'object_name': 'UninvoicableCode'},
u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'})
},
u'ressources.workertype': {
'Meta': {'object_name': 'WorkerType'},
u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'intervene': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
'name': ('django.db.models.fields.CharField', [], {'max_length': '150'})
}
}
complete_apps = ['ressources']

View File

@ -401,6 +401,7 @@ class ActType(NamedAbstractModel, ServiceLinkedAbstractModel):
old_id = models.CharField(max_length=256,
verbose_name=u'Ancien ID', blank=True, null=True)
display_first = models.BooleanField(default=False, verbose_name=u"Acte principalement utilisé")
group = models.BooleanField(default=False, verbose_name=u'De groupe')
class Meta(NamedAbstractModel.Meta):
verbose_name = u'Type d\'actes'

View File

@ -0,0 +1,33 @@
{% extends "ressources/list.html" %}
{% block content %}
{% if object_list %}
<table id="ressource-list" class="main">
<thead>
<th class="col-id">Identifiant</th>
<th class="col-label">Libellé</th>
<th class="col-service">Service</th>
<th class="col-action"></th>
</thead>
<tbody>
{% for object in object_list %}
<tr id="ressource-{{ object.pk }}" {% if new_id == object.pk %}class="new-object"{% endif %}>
<td class="col-id">{{object.pk}}</td>
<td class="col-label"><a href="{{ object.pk }}">{{object}}</a></td>
<td class="col-service"><span class="box {{object.service.slug}}" title="{{object.service.name}}"></span></td>
<td class="col-action"><button class="dialog-button delete-object-button"
data-url="{{ object.pk }}/delete/ #form-content">Supprimer</button></td>
</tr>
{% endfor %}
</tbody>
</table>
<script type="text/javascript">$('.new-object').effect('highlight', {}, 3000);</script>
{% else %}
<div class="big-msg-info">
<p>
Cliquez sur le bouton « Ajouter » en haut à droite pour ajouter un
élément.
</p>
</div>
{% endif %}
{% endblock %}

View File

@ -39,11 +39,15 @@ def homepage(request, service):
def list_view(request, service, model_name):
model = get_ressource_model(model_name)
if model_name == 'acttype':
template = 'ressources/acttype_list.html'
else:
template = 'ressources/list.html'
if model is None:
raise Http404
view = ListView.as_view(model=model,
queryset=model.objects.select_related(),
template_name='ressources/list.html')
template_name=template)
return view(request, service=service)
class RessourceCreateView(CreateView):

View File

@ -151,6 +151,7 @@ INSTALLED_APPS = (
'south',
'django.contrib.admin',
'ajax_select',
'django_select2',
#'debug_toolbar',
'widget_tweaks',
# Uncomment the next line to enable admin documentation:
@ -235,7 +236,8 @@ AJAX_LOOKUP_CHANNELS = {
#'patientrecord' : {'model':'dossiers.PatientRecord', 'search_field':'display_name'}
#'coordinators' : {'model':'dossiers.PatientRecord', 'search_field':'display_name'}
'patientrecord' : ('calebasse.dossiers.lookups', 'PatientRecordLookup'),
'school' : {'model':'ressources.School', 'search_field':'name'},
#'school' : {'model':'ressources.School', 'search_field':'name'},
'school' : ('calebasse.ressources.lookups', 'SchoolLookup'),
'addresses' : ('calebasse.dossiers.lookups', 'PatientAddressLookup'),
'worker-or-group' : ('calebasse.ressources.lookups', 'WorkerOrGroupLookup'),
'all-worker-or-group' : ('calebasse.ressources.lookups', 'AllWorkerOrGroupLookup'),

View File

@ -178,6 +178,10 @@ li.away {
background: #ccc;
}
li.overlap {
background: #640018;
}
li#time {
margin-top: -0.15em;
}
@ -219,4 +223,12 @@ ul.addresses {
button.screen-only {
margin: 1em 0;
float: right;
}
h3 .icon-comment {
display: none;
}
.worker-agenda {
margin-top: 2em;
}

View File

@ -112,3 +112,14 @@ div#tabs-4 div div.buttons {
margin-top: .4em;
}
.select2-choices {
font-size: 11pt;
}
#id_school_text {
min-width: 600px;
}
#ajax-dlg input, ul.ui-autocomplete, .results_on_deck {
font-size: 90%;
}

View File

@ -33,7 +33,6 @@ div#content div.worker-agenda h2 {
margin-bottom: 1ex;
color: black;
background: none;
font-size: 1.4em;
}
.worker-agenda+.worker-agenda {
@ -41,11 +40,11 @@ div#content div.worker-agenda h2 {
}
div.worker-agenda table{
font-size: 1.25em;
font-size: 70%;
}
table#activity{
font-size: 95%;
font-size: 80%;
}
div.worker-agenda h3 {
@ -78,3 +77,8 @@ div.summary {
div#sidebar {
display: none;
}
div.page-header {
position: fixed;
top: 0;
}

View File

@ -124,7 +124,7 @@ div#wrap-large {
padding-top: 5px;
}
#agendas span.box {
#agendas span.box, #ressource-list span.box {
display: inline-block;
height: 20px;
width: 20px;
@ -472,6 +472,11 @@ span.absent{
font-style: italic;
}
span.inactive {
color: #8B008B;
font-style: italic;
}
td#agendas {
vertical-align: top;
width: 100%;
@ -1187,12 +1192,11 @@ a [class^="icon-"], a [class*=" icon-"] {
right: 10px;
}
#id_participants_on_deck {
#id_participants_on_deck, #id_patient_on_deck {
max-height: 7em;
overflow-y: scroll;
}
ul.messages, ul.ajax_messages {
position: absolute;
width: 30em;

View File

@ -44,14 +44,14 @@ function get_initial_fields(button, base) {
function enable_new_appointment(base) {
var base = base || 'body';
$(base).find('.newrdv').click(function() {
event_dialog($(this).data('url') + "?" + get_initial_fields(this, base), 'Nouveau rendez-vous', '850px', 'Ajouter');
add_dialog('#ajax-dlg', $(this).data('url') + "?" + get_initial_fields(this, base), 'Nouveau rendez-vous', '880px', 'Ajouter');
});
}
function enable_new_event(base) {
var base = base || 'body';
$(base).find('.newevent').click(function() {
event_dialog($(this).data('url') + "?" + get_initial_fields(this, base), 'Nouvel événement', '850px', 'Ajouter');
add_dialog('#ajax-dlg', $(this).data('url') + "?" + get_initial_fields(this, base), 'Nouvel événement', '850px', 'Ajouter');
});
}
@ -61,12 +61,13 @@ function enable_events(base) {
});
$(base).find('.textedit button').on('click', function() {
var textarea = $(this).prev();
var span = textarea.prev()
var btn = $(this)
var span = textarea.prev();
var btn = $(this);
var comment = {description: textarea.val()};
var data = JSON.stringify(comment);
if ($(this).data('act-id'))
{
var data = {comment: textarea.val() };
var data = JSON.stringify(data);
$.ajax({
url: '/api/v1/act/' + $(this).data("act-id") + '/?format=json&date=' + $(this).data('date'),
type: 'PATCH',
@ -74,21 +75,29 @@ function enable_events(base) {
data: data,
success: function(data) {
btn.attr('disabled', 'disabled');
if (comment['description']) {
$('h3#' + btn.data("event-id") + ' span.icon-comment').fadeIn();
}
else {
$('h3#' + btn.data("event-id") + ' span.icon-comment').fadeOut();
}
span.html('Commentaire modifié avec succès');
}
});
}
else
{
var data = {description: textarea.val() };
var data = JSON.stringify(data);
$.ajax({
url: '/api/v1/event/' + $(this).data("event-id") + '/?format=json&date=' + $(this).data('date'),
type: 'PATCH',
contentType: 'application/json',
data: data,
success: function(data) {
success: function(response) {
btn.attr('disabled', 'disabled');
if (comment['description'])
$('h3#' + btn.data("event-id") + ' span.icon-comment').fadeIn();
else
$('h3#' + btn.data("event-id") + ' span.icon-comment').fadeOut();
span.html('Commentaire modifié avec succès');
}
});
@ -264,9 +273,14 @@ function toggle_ressource(ressource) {
return $(ressource_target).find('a.tab');
}
function init_datepickers(dialog) {
$('.datepicker-date', dialog).datepicker({dateFormat: 'd/m/yy', showOn: 'button'});
$('.datepicker input', dialog).datepicker({dateFormat: 'd/m/yy', showOn: 'button'});
}
function event_dialog(url, title, width, btn_text) {
function add_periodic_events(base) {
init_datepickers(base);
$(base).on('click', '.update-periodic-event', function () {
$('.ui-icon-closethick').click();
// remove the form from previous hidden layer in order to prevent two
@ -294,11 +308,7 @@ function event_dialog(url, title, width, btn_text) {
}
};
generic_ajaxform_dialog('/' + service + '/' + app_name + '/' + current_date + '/update-periodic-event/' + id,
'Modifier un évènement périodique', '#ajax-dlg', '900px', 'Modifier', null,
function (dialog) {
$('#ajax-dlg .datepicker-date').datepicker({dateFormat: 'd/m/yy', showOn: 'button'});
}, null, delete_button
);
'Modifier un évènement périodique', '#ajax-dlg', '900px', 'Modifier', null, init_datepickers, null, delete_button);
});
$(base).on('click', '.update-periodic-rdv', function () {
$('.ui-icon-closethick').click();
@ -323,11 +333,7 @@ function event_dialog(url, title, width, btn_text) {
}
};
generic_ajaxform_dialog('/' + service + '/' + app_name + '/' + current_date + '/update-periodic-rdv/' + id,
'Modifier un rendez-vous périodique', '#ajax-dlg', '900px', 'Modifier', null,
function (dialog) {
$('#ajax-dlg .datepicker-date').datepicker({dateFormat: 'd/m/yy', showOn: 'button'});
}, null, delete_button
);
'Modifier un rendez-vous périodique', '#ajax-dlg', '900px', 'Modifier', null, init_datepickers, null, delete_button);
});
}

View File

@ -22,6 +22,8 @@ function generic_ajaxform_dialog(url, title, id, width, btn_submit_name, redirec
height = 'auto';
$(id).load(url,
function () {
$('.datepicker-date').datepicker({dateFormat: 'd/m/yy', showOn: 'button'});
$('.datepicker input').datepicker({dateFormat: 'd/m/yy', showOn: 'button'});
function onsuccess(response, status, xhr, form) {
enable_button($('#submit-btn'));
var parse = $(response);
@ -76,11 +78,33 @@ function generic_ajaxform_dialog(url, title, id, width, btn_submit_name, redirec
});
}
/**
* Transform form(s) to ajax forms
* id: jQuery id where you want to replace form by ajaxForm
*/
function calebasse_ajax_form(id) {
function onsuccess(response, status, xhr, form) {
if ($('.errorlist', response).length != 0) {
$(id).html(response);
$('form').ajaxForm({
success: onsuccess,
});
}
else {
window.location.reload(true);
}
}
$('form').ajaxForm({
success: onsuccess,
});
}
function add_dialog(on, url, title, width, btn_text) {
// function used to add patient schedules, events and acts
function init_dialog() {
$('#rdv .datepicker-date').datepicker({dateFormat: 'd/m/yy', showOn: 'button'});
$('.datepicker-date').datepicker({dateFormat: 'd/m/yy', showOn: 'button'});
$('.datepicker input').datepicker({dateFormat: 'd/m/yy', showOn: 'button'});
$('#id_description').attr('rows', '3');
$('#id_description').attr('cols', '30');
var deck = $('#id_participants_on_deck');

View File

@ -131,6 +131,7 @@ function load_tab2_adm() {
'#ajax-dlg', '500px', 'Supprimer');
});
$('input#id_id-birthdate').datepicker({dateFormat: 'd/m/yy', showOn: 'button' });
calebasse_ajax_form('#tabs-2');
}
function load_tab3_addresses() {
@ -323,6 +324,7 @@ function load_tab7_socialisation() {
}
function load_tab8_medical() {
calebasse_ajax_form('#tabs-8');
SelectFilter.init("id_mises_1", "Catégorie", 0, "/static/admin/");
SelectFilter.init("id_mises_2", "Catégorie", 0, "/static/admin/");
SelectFilter.init("id_mises_3", "Catégorie", 0, "/static/admin/");

View File

@ -1,16 +1,28 @@
/*!
* jQuery Form Plugin
* version: 3.18 (28-SEP-2012)
* @requires jQuery v1.5 or later
*
* version: 3.50.0-2014.02.05
* Requires jQuery v1.5 or later
* Copyright (c) 2013 M. Alsup
* Examples and documentation at: http://malsup.com/jquery/form/
* Project repository: https://github.com/malsup/form
* Dual licensed under the MIT and GPL licenses:
* http://malsup.github.com/mit-license.txt
* http://malsup.github.com/gpl-license-v2.txt
* Dual licensed under the MIT and GPL licenses.
* https://github.com/malsup/form#copyright-and-license
*/
/*global ActiveXObject alert */
;(function($) {
/*global ActiveXObject */
// AMD support
(function (factory) {
"use strict";
if (typeof define === 'function' && define.amd) {
// using AMD; register as anon module
define(['jquery'], factory);
} else {
// no AMD; invoke directly
factory( (typeof(jQuery) != 'undefined') ? jQuery : window.Zepto );
}
}
(function($) {
"use strict";
/*
@ -37,7 +49,7 @@
target: '#output'
});
});
You can also use ajaxForm with delegation (requires jQuery v1.7+), so the
form does not have to exist when you invoke ajaxForm:
@ -45,7 +57,7 @@
delegation: true,
target: '#output'
});
When using ajaxForm, the ajaxSubmit function will be invoked for you
at the appropriate time.
*/
@ -57,6 +69,23 @@ var feature = {};
feature.fileapi = $("<input type='file'/>").get(0).files !== undefined;
feature.formdata = window.FormData !== undefined;
var hasProp = !!$.fn.prop;
// attr2 uses prop when it can but checks the return type for
// an expected string. this accounts for the case where a form
// contains inputs with names like "action" or "method"; in those
// cases "prop" returns the element
$.fn.attr2 = function() {
if ( ! hasProp ) {
return this.attr.apply(this, arguments);
}
var val = this.prop.apply(this, arguments);
if ( ( val && val.jquery ) || typeof val === 'string' ) {
return val;
}
return this.attr.apply(this, arguments);
};
/**
* ajaxSubmit() provides a mechanism for immediately submitting
* an HTML form using AJAX.
@ -69,15 +98,19 @@ $.fn.ajaxSubmit = function(options) {
log('ajaxSubmit: skipping submit process - no element selected');
return this;
}
var method, action, url, $form = this;
if (typeof options == 'function') {
options = { success: options };
}
else if ( options === undefined ) {
options = {};
}
method = options.type || this.attr2('method');
action = options.url || this.attr2('action');
method = this.attr('method');
action = this.attr('action');
url = (typeof action === 'string') ? $.trim(action) : '';
url = url || window.location.href || '';
if (url) {
@ -88,7 +121,7 @@ $.fn.ajaxSubmit = function(options) {
options = $.extend(true, {
url: url,
success: $.ajaxSettings.success,
type: method || 'GET',
type: method || $.ajaxSettings.type,
iframeSrc: /^https/i.test(window.location.href || '') ? 'javascript:false' : 'about:blank'
}, options);
@ -111,7 +144,7 @@ $.fn.ajaxSubmit = function(options) {
if ( traditional === undefined ) {
traditional = $.ajaxSettings.traditional;
}
var elements = [];
var qx, a = this.formToArray(options.semantic, elements);
if (options.data) {
@ -135,7 +168,7 @@ $.fn.ajaxSubmit = function(options) {
var q = $.param(a, traditional);
if (qx) {
q = ( q ? (q + '&' + qx) : qx );
}
}
if (options.type.toUpperCase() == 'GET') {
options.url += (options.url.indexOf('?') >= 0 ? '&' : '?') + q;
options.data = null; // data is null for 'get'
@ -165,14 +198,34 @@ $.fn.ajaxSubmit = function(options) {
}
options.success = function(data, status, xhr) { // jQuery 1.4+ passes xhr as 3rd arg
var context = options.context || this ; // jQuery 1.4+ supports scope context
var context = options.context || this ; // jQuery 1.4+ supports scope context
for (var i=0, max=callbacks.length; i < max; i++) {
callbacks[i].apply(context, [data, status, xhr || $form, $form]);
}
};
if (options.error) {
var oldError = options.error;
options.error = function(xhr, status, error) {
var context = options.context || this;
oldError.apply(context, [xhr, status, error, $form]);
};
}
if (options.complete) {
var oldComplete = options.complete;
options.complete = function(xhr, status) {
var context = options.context || this;
oldComplete.apply(context, [xhr, status, $form]);
};
}
// are there files to upload?
var fileInputs = $('input:file:enabled[value]', this); // [value] (issue #113)
// [value] (issue #113), also see comment:
// https://github.com/malsup/form/commit/588306aedba1de01388032d5f42a60159eea9228#commitcomment-2180219
var fileInputs = $('input[type=file]:enabled', this).filter(function() { return $(this).val() !== ''; });
var hasFileInputs = fileInputs.length > 0;
var mp = 'multipart/form-data';
var multipart = ($form.attr('enctype') == mp || $form.attr('encoding') == mp);
@ -207,8 +260,9 @@ $.fn.ajaxSubmit = function(options) {
$form.removeData('jqxhr').data('jqxhr', jqxhr);
// clear element array
for (var k=0; k < elements.length; k++)
for (var k=0; k < elements.length; k++) {
elements[k] = null;
}
// fire 'notify' event
this.trigger('form-submit-notify', [this, options]);
@ -216,13 +270,16 @@ $.fn.ajaxSubmit = function(options) {
// utility fn for deep serialization
function deepSerialize(extraData){
var serialized = $.param(extraData).split('&');
var serialized = $.param(extraData, options.traditional).split('&');
var len = serialized.length;
var result = {};
var result = [];
var i, part;
for (i=0; i < len; i++) {
// #252; undo param space replacement
serialized[i] = serialized[i].replace(/\+/g,' ');
part = serialized[i].split('=');
result[decodeURIComponent(part[0])] = decodeURIComponent(part[1]);
// #278; use array instead of object storage, favoring array serializations
result.push([decodeURIComponent(part[0]), decodeURIComponent(part[1])]);
}
return result;
}
@ -237,9 +294,11 @@ $.fn.ajaxSubmit = function(options) {
if (options.extraData) {
var serializedData = deepSerialize(options.extraData);
for (var p in serializedData)
if (serializedData.hasOwnProperty(p))
formdata.append(p, serializedData[p]);
for (i=0; i < serializedData.length; i++) {
if (serializedData[i]) {
formdata.append(serializedData[i][0], serializedData[i][1]);
}
}
}
options.data = null;
@ -250,13 +309,13 @@ $.fn.ajaxSubmit = function(options) {
cache: false,
type: method || 'POST'
});
if (options.uploadProgress) {
// workaround because jqXHR does not expose upload property
s.xhr = function() {
var xhr = jQuery.ajaxSettings.xhr();
var xhr = $.ajaxSettings.xhr();
if (xhr.upload) {
xhr.upload.onprogress = function(event) {
xhr.upload.addEventListener('progress', function(event) {
var percent = 0;
var position = event.loaded || event.position; /*event.position is deprecated*/
var total = event.total;
@ -264,18 +323,25 @@ $.fn.ajaxSubmit = function(options) {
percent = Math.ceil(position / total * 100);
}
options.uploadProgress(event, position, total, percent);
};
}, false);
}
return xhr;
};
}
s.data = null;
var beforeSend = s.beforeSend;
s.beforeSend = function(xhr, o) {
var beforeSend = s.beforeSend;
s.beforeSend = function(xhr, o) {
//Send FormData() provided by user
if (options.formData) {
o.data = options.formData;
}
else {
o.data = formdata;
if(beforeSend)
beforeSend.call(this, xhr, o);
}
if(beforeSend) {
beforeSend.call(this, xhr, o);
}
};
return $.ajax(s);
}
@ -283,25 +349,23 @@ $.fn.ajaxSubmit = function(options) {
// private function for handling file uploads (hat tip to YAHOO!)
function fileUploadIframe(a) {
var form = $form[0], el, i, s, g, id, $io, io, xhr, sub, n, timedOut, timeoutHandle;
var useProp = !!$.fn.prop;
var deferred = $.Deferred();
if ($(':input[name=submit],:input[id=submit]', form).length) {
// if there is an input with a name or id of 'submit' then we won't be
// able to invoke the submit fn on the form (at least not x-browser)
alert('Error: Form elements must not have name or id of "submit".');
deferred.reject();
return deferred;
}
// #341
deferred.abort = function(status) {
xhr.abort(status);
};
if (a) {
// ensure that every serialized input is still enabled
for (i=0; i < elements.length; i++) {
el = $(elements[i]);
if ( useProp )
if ( hasProp ) {
el.prop('disabled', false);
else
}
else {
el.removeAttr('disabled');
}
}
}
@ -310,11 +374,13 @@ $.fn.ajaxSubmit = function(options) {
id = 'jqFormIO' + (new Date().getTime());
if (s.iframeTarget) {
$io = $(s.iframeTarget);
n = $io.attr('name');
if (!n)
$io.attr('name', id);
else
n = $io.attr2('name');
if (!n) {
$io.attr2('name', id);
}
else {
id = n;
}
}
else {
$io = $('<iframe name="' + id + '" src="'+ s.iframeSrc +'" />');
@ -336,20 +402,25 @@ $.fn.ajaxSubmit = function(options) {
var e = (status === 'timeout' ? 'timeout' : 'aborted');
log('aborting upload... ' + e);
this.aborted = 1;
// #214
if (io.contentWindow.document.execCommand) {
try { // #214
try { // #214, #257
if (io.contentWindow.document.execCommand) {
io.contentWindow.document.execCommand('Stop');
} catch(ignore) {}
}
}
catch(ignore) {}
$io.attr('src', s.iframeSrc); // abort op in progress
xhr.error = e;
if (s.error)
if (s.error) {
s.error.call(s.context, xhr, e, status);
if (g)
}
if (g) {
$.event.trigger("ajaxError", [xhr, s, e]);
if (s.complete)
}
if (s.complete) {
s.complete.call(s.context, xhr, e);
}
}
};
@ -387,15 +458,44 @@ $.fn.ajaxSubmit = function(options) {
}
}
}
var CLIENT_TIMEOUT_ABORT = 1;
var SERVER_ABORT = 2;
function getDoc(frame) {
var doc = frame.contentWindow ? frame.contentWindow.document : frame.contentDocument ? frame.contentDocument : frame.document;
/* it looks like contentWindow or contentDocument do not
* carry the protocol property in ie8, when running under ssl
* frame.document is the only valid response document, since
* the protocol is know but not on the other two objects. strange?
* "Same origin policy" http://en.wikipedia.org/wiki/Same_origin_policy
*/
var doc = null;
// IE8 cascading access check
try {
if (frame.contentWindow) {
doc = frame.contentWindow.document;
}
} catch(err) {
// IE8 access denied under ssl & missing protocol
log('cannot get iframe.contentWindow document: ' + err);
}
if (doc) { // successful getting content
return doc;
}
try { // simply checking may throw in ie8 under ssl or mismatched protocol
doc = frame.contentDocument ? frame.contentDocument : frame.document;
} catch(err) {
// last attempt
log('cannot get iframe.contentDocument: ' + err);
doc = frame.document;
}
return doc;
}
// Rails CSRF hack (thanks to Yvan Barthelemy)
var csrf_token = $('meta[name=csrf-token]').attr('content');
var csrf_param = $('meta[name=csrf-param]').attr('content');
@ -407,11 +507,14 @@ $.fn.ajaxSubmit = function(options) {
// take a breath so that pending repaints get some cpu time before the upload starts
function doSubmit() {
// make sure form attrs are set
var t = $form.attr('target'), a = $form.attr('action');
var t = $form.attr2('target'),
a = $form.attr2('action'),
mp = 'multipart/form-data',
et = $form.attr('enctype') || $form.attr('encoding') || mp;
// update form attrs in IE friendly way
form.setAttribute('target',id);
if (!method) {
if (!method || /post/i.test(method) ) {
form.setAttribute('method', 'POST');
}
if (a != s.url) {
@ -430,20 +533,22 @@ $.fn.ajaxSubmit = function(options) {
if (s.timeout) {
timeoutHandle = setTimeout(function() { timedOut = true; cb(CLIENT_TIMEOUT_ABORT); }, s.timeout);
}
// look for server aborts
function checkState() {
try {
var state = getDoc(io).readyState;
log('state = ' + state);
if (state && state.toLowerCase() == 'uninitialized')
if (state && state.toLowerCase() == 'uninitialized') {
setTimeout(checkState,50);
}
}
catch(e) {
log('Server abort: ' , e, ' (', e.name, ')');
cb(SERVER_ABORT);
if (timeoutHandle)
if (timeoutHandle) {
clearTimeout(timeoutHandle);
}
timeoutHandle = undefined;
}
}
@ -457,11 +562,11 @@ $.fn.ajaxSubmit = function(options) {
// if using the $.param format that allows for multiple values with the same name
if($.isPlainObject(s.extraData[n]) && s.extraData[n].hasOwnProperty('name') && s.extraData[n].hasOwnProperty('value')) {
extraInputs.push(
$('<input type="hidden" name="'+s.extraData[n].name+'">').attr('value',s.extraData[n].value)
$('<input type="hidden" name="'+s.extraData[n].name+'">').val(s.extraData[n].value)
.appendTo(form)[0]);
} else {
extraInputs.push(
$('<input type="hidden" name="'+n+'">').attr('value',s.extraData[n])
$('<input type="hidden" name="'+n+'">').val(s.extraData[n])
.appendTo(form)[0]);
}
}
@ -471,17 +576,27 @@ $.fn.ajaxSubmit = function(options) {
if (!s.iframeTarget) {
// add iframe to doc and submit the form
$io.appendTo('body');
if (io.attachEvent)
io.attachEvent('onload', cb);
else
io.addEventListener('load', cb, false);
}
if (io.attachEvent) {
io.attachEvent('onload', cb);
}
else {
io.addEventListener('load', cb, false);
}
setTimeout(checkState,15);
form.submit();
try {
form.submit();
} catch(err) {
// just in case form has element with name/id of 'submit'
var submitFn = document.createElement('form').submit;
submitFn.apply(form);
}
}
finally {
// reset attrs and remove "extra" input elements
form.setAttribute('action',a);
form.setAttribute('enctype', et); // #380
if(t) {
form.setAttribute('target', t);
} else {
@ -504,11 +619,10 @@ $.fn.ajaxSubmit = function(options) {
if (xhr.aborted || callbackProcessed) {
return;
}
try {
doc = getDoc(io);
}
catch(ex) {
log('cannot access response document: ', ex);
doc = getDoc(io);
if(!doc) {
log('cannot access response document');
e = SERVER_ABORT;
}
if (e === CLIENT_TIMEOUT_ABORT && xhr) {
@ -524,13 +638,16 @@ $.fn.ajaxSubmit = function(options) {
if (!doc || doc.location.href == s.iframeSrc) {
// response not received yet
if (!timedOut)
if (!timedOut) {
return;
}
}
if (io.detachEvent)
if (io.detachEvent) {
io.detachEvent('onload', cb);
else
}
else {
io.removeEventListener('load', cb, false);
}
var status = 'success', errMsg;
try {
@ -557,11 +674,12 @@ $.fn.ajaxSubmit = function(options) {
var docRoot = doc.body ? doc.body : doc.documentElement;
xhr.responseText = docRoot ? docRoot.innerHTML : null;
xhr.responseXML = doc.XMLDocument ? doc.XMLDocument : doc;
if (isXml)
if (isXml) {
s.dataType = 'xml';
}
xhr.getResponseHeader = function(header){
var headers = {'content-type': s.dataType};
return headers[header];
return headers[header.toLowerCase()];
};
// support for XHR 'status' & 'statusText' emulation :
if (docRoot) {
@ -599,15 +717,15 @@ $.fn.ajaxSubmit = function(options) {
try {
data = httpData(xhr, dt, s);
}
catch (e) {
catch (err) {
status = 'parsererror';
xhr.error = errMsg = (e || status);
xhr.error = errMsg = (err || status);
}
}
catch (e) {
log('error caught: ',e);
catch (err) {
log('error caught: ',err);
status = 'error';
xhr.error = errMsg = (e || status);
xhr.error = errMsg = (err || status);
}
if (xhr.aborted) {
@ -621,40 +739,52 @@ $.fn.ajaxSubmit = function(options) {
// ordering of these callbacks/triggers is odd, but that's how $.ajax does it
if (status === 'success') {
if (s.success)
if (s.success) {
s.success.call(s.context, data, 'success', xhr);
}
deferred.resolve(xhr.responseText, 'success', xhr);
if (g)
if (g) {
$.event.trigger("ajaxSuccess", [xhr, s]);
}
}
else if (status) {
if (errMsg === undefined)
if (errMsg === undefined) {
errMsg = xhr.statusText;
if (s.error)
}
if (s.error) {
s.error.call(s.context, xhr, status, errMsg);
}
deferred.reject(xhr, 'error', errMsg);
if (g)
if (g) {
$.event.trigger("ajaxError", [xhr, s, errMsg]);
}
}
if (g)
if (g) {
$.event.trigger("ajaxComplete", [xhr, s]);
}
if (g && ! --$.active) {
$.event.trigger("ajaxStop");
}
if (s.complete)
if (s.complete) {
s.complete.call(s.context, xhr, status);
}
callbackProcessed = true;
if (s.timeout)
if (s.timeout) {
clearTimeout(timeoutHandle);
}
// clean up
setTimeout(function() {
if (!s.iframeTarget)
if (!s.iframeTarget) {
$io.remove();
}
else { //adding else to clean up existing iframe response.
$io.attr('src', s.iframeSrc);
}
xhr.responseXML = null;
}, 100);
}
@ -682,8 +812,9 @@ $.fn.ajaxSubmit = function(options) {
data = xml ? xhr.responseXML : xhr.responseText;
if (xml && data.documentElement.nodeName === 'parsererror') {
if ($.error)
if ($.error) {
$.error('parsererror');
}
}
if (s && s.dataFilter) {
data = s.dataFilter(data, type);
@ -720,7 +851,7 @@ $.fn.ajaxSubmit = function(options) {
$.fn.ajaxForm = function(options) {
options = options || {};
options.delegation = options.delegation && $.isFunction($.fn.on);
// in jQuery 1.3+ we can fix mistakes with the ready state
if (!options.delegation && this.length === 0) {
var o = { s: this.selector, c: this.context };
@ -750,23 +881,23 @@ $.fn.ajaxForm = function(options) {
.bind('click.form-plugin', options, captureSubmittingElement);
};
// private event handlers
// private event handlers
function doAjaxSubmit(e) {
/*jshint validthis:true */
var options = e.data;
if (!e.isDefaultPrevented()) { // if event has been canceled, don't proceed
e.preventDefault();
$(this).ajaxSubmit(options);
$(e.target).ajaxSubmit(options); // #365
}
}
function captureSubmittingElement(e) {
/*jshint validthis:true */
var target = e.target;
var $el = $(target);
if (!($el.is(":submit,input:image"))) {
if (!($el.is("[type=submit],[type=image]"))) {
// is this a child element of the submit el? (ex: a span within a button)
var t = $el.closest(':submit');
var t = $el.closest('[type=submit]');
if (t.length === 0) {
return;
}
@ -815,8 +946,23 @@ $.fn.formToArray = function(semantic, elements) {
}
var form = this[0];
var formId = this.attr('id');
var els = semantic ? form.getElementsByTagName('*') : form.elements;
if (!els) {
var els2;
if (els && !/MSIE [678]/.test(navigator.userAgent)) { // #390
els = $(els).get(); // convert to standard array
}
// #386; account for inputs outside the form which use the 'form' attribute
if ( formId ) {
els2 = $(':input[form=' + formId + ']').get();
if ( els2.length ) {
els = (els || []).concat(els2);
}
}
if (!els || !els.length) {
return a;
}
@ -824,13 +970,13 @@ $.fn.formToArray = function(semantic, elements) {
for(i=0, max=els.length; i < max; i++) {
el = els[i];
n = el.name;
if (!n) {
if (!n || el.disabled) {
continue;
}
if (semantic && form.clk && el.type == "image") {
// handle image inputs on the fly when semantic == true
if(!el.disabled && form.clk == el) {
if(form.clk == el) {
a.push({name: n, value: $(el).val(), type: el.type });
a.push({name: n+'.x', value: form.clk_x}, {name: n+'.y', value: form.clk_y});
}
@ -839,15 +985,17 @@ $.fn.formToArray = function(semantic, elements) {
v = $.fieldValue(el, true);
if (v && v.constructor == Array) {
if (elements)
if (elements) {
elements.push(el);
}
for(j=0, jmax=v.length; j < jmax; j++) {
a.push({name: n, value: v[j]});
}
}
else if (feature.fileapi && el.type == 'file' && !el.disabled) {
if (elements)
else if (feature.fileapi && el.type == 'file') {
if (elements) {
elements.push(el);
}
var files = el.files;
if (files.length) {
for (j=0; j < files.length; j++) {
@ -860,8 +1008,9 @@ $.fn.formToArray = function(semantic, elements) {
}
}
else if (v !== null && typeof v != 'undefined') {
if (elements)
if (elements) {
elements.push(el);
}
a.push({name: n, value: v, type: el.type, required: el.required});
}
}
@ -924,19 +1073,19 @@ $.fn.fieldSerialize = function(successful) {
* <input name="C" type="radio" value="C2" />
* </fieldset></form>
*
* var v = $(':text').fieldValue();
* var v = $('input[type=text]').fieldValue();
* // if no values are entered into the text inputs
* v == ['','']
* // if values entered into the text inputs are 'foo' and 'bar'
* v == ['foo','bar']
*
* var v = $(':checkbox').fieldValue();
* var v = $('input[type=checkbox]').fieldValue();
* // if neither checkbox is checked
* v === undefined
* // if both checkboxes are checked
* v == ['B1', 'B2']
*
* var v = $(':radio').fieldValue();
* var v = $('input[type=radio]').fieldValue();
* // if neither radio is checked
* v === undefined
* // if first radio is checked
@ -957,10 +1106,12 @@ $.fn.fieldValue = function(successful) {
if (v === null || typeof v == 'undefined' || (v.constructor == Array && !v.length)) {
continue;
}
if (v.constructor == Array)
if (v.constructor == Array) {
$.merge(val, v);
else
}
else {
val.push(v);
}
}
return val;
};
@ -994,7 +1145,7 @@ $.fieldValue = function(el, successful) {
if (op.selected) {
var v = op.value;
if (!v) { // extra pain for IE...
v = (op.attributes && op.attributes['value'] && !(op.attributes['value'].specified)) ? op.text : op.value;
v = (op.attributes && op.attributes.value && !(op.attributes.value.specified)) ? op.text : op.value;
}
if (one) {
return v;
@ -1037,14 +1188,22 @@ $.fn.clearFields = $.fn.clearInputs = function(includeHidden) {
else if (tag == 'select') {
this.selectedIndex = -1;
}
else if (t == "file") {
if (/MSIE/.test(navigator.userAgent)) {
$(this).replaceWith($(this).clone(true));
} else {
$(this).val('');
}
}
else if (includeHidden) {
// includeHidden can be the value true, or it can be a selector string
// indicating a special test; for example:
// $('#myForm').clearForm('.special:hidden')
// the above would clean hidden inputs that have the class of 'special'
if ( (includeHidden === true && /hidden/.test(t)) ||
(typeof includeHidden == 'string' && $(this).is(includeHidden)) )
(typeof includeHidden == 'string' && $(this).is(includeHidden)) ) {
this.value = '';
}
}
});
};
@ -1103,8 +1262,9 @@ $.fn.ajaxSubmit.debug = false;
// helper fn for console logging
function log() {
if (!$.fn.ajaxSubmit.debug)
if (!$.fn.ajaxSubmit.debug) {
return;
}
var msg = '[jquery.form] ' + Array.prototype.join.call(arguments,'');
if (window.console && window.console.log) {
window.console.log(msg);
@ -1114,4 +1274,5 @@ function log() {
}
}
})(jQuery);
}));

View File

@ -1213,7 +1213,7 @@ def patients_synthesis(statistic):
nb_patients, acts.count())])
data_tables.append(data)
data = []
data.append(['Féminin', 'Masculin'])
data.append(['Filles', 'Garçons'])
data.append([(patients.filter(gender='2').count(),
patients.filter(gender='1').count())])
data_tables.append(data)
@ -1342,16 +1342,17 @@ def patients_synthesis(statistic):
data = []
data.append(["Code ANAP", "Tranche d'âge (au %s)" \
% formats.date_format(statistic.in_end_date, "SHORT_DATE_FORMAT"),
"Nombre de dossiers", "%"])
"Nombre de dossiers", "%", "Filles", "%", "Garçons", "%"])
values = []
for i in range(len(lower_bounds)):
lower_bound = lower_bounds[i]
if i == len(lower_bounds) - 1:
values.append([anap_code, "De %d ans et plus" % lower_bound, 0, None])
values.append([anap_code, "De %d ans et plus" % lower_bound, 0, 0, 0, 0, 0, 0])
else:
values.append([anap_code, "De %d à %d ans" % (lower_bound, lower_bounds[i + 1] - 1), 0, None])
values.append([anap_code, "De %d à %d ans" % (lower_bound, lower_bounds[i + 1] - 1), 0, 0, 0, 0, 0, 0])
anap_code += 1
unknown = 0
patients_sorted = {}
unknowns = [0, 0]
for patient in patients:
try:
age = statistic.in_end_date.date() - patient.birthdate
@ -1361,12 +1362,29 @@ def patients_synthesis(statistic):
i += 1
if i == len(lower_bounds) - 1:
break
values[i][2] += 1
patients_sorted.setdefault(i, [0, 0])
if patient.gender == 1:
patients_sorted[i][0] += 1
else:
patients_sorted[i][1] += 1
except:
unknown += 1
for value in values:
value[3] = "%.2f" % (value[2] / float(len(patients)) * 100)
values.append(['', "Non renseignée", unknown, "%.2f" % (unknown / float(len(patients)) * 100)])
if patient.gender == 1:
unknowns[0] += 1
else:
unknowns[1] += 1
for k, v in patients_sorted.items():
values[k][2] = v[0] + v[1]
values[k][3] = "%.2f" % (values[k][2] / float(len(patients)) * 100)
values[k][4] = v[1]
values[k][5] = "%.2f" % (v[1] / float(values[k][2]) * 100)
values[k][6] = v[0]
values[k][7] = "%.2f" % (v[0] / float(values[k][2]) * 100)
l_ukn = unknowns[0] + unknowns[1]
if l_ukn:
values.append(['', "Non renseigné", l_ukn, "%.2f" % (l_ukn / float(len(patients)) * 100),
unknowns[1], "%.2f" % (unknowns[1] / float(l_ukn) * 100),
unknowns[0], "%.2f" % (unknowns[0] / float(l_ukn) * 100)])
data.append(values)
data_tables.append(data)

View File

@ -22,12 +22,12 @@
<script src="{{ STATIC_URL }}js/ajax_select.js"></script>
<script src="{{ STATIC_URL }}js/jquery.mousewheel.js"></script>
<script src="{{ STATIC_URL }}js/calebasse.mousewheel.js"></script>
<script src="{{ STATIC_URL }}js/calebasse.dialog.js"></script>
<script src="{{ STATIC_URL }}js/calebasse.tables.js"></script>
<script src="{{ STATIC_URL }}js/calebasse.text_input_wrapper.js"></script>
<script src="{{ STATIC_URL }}/js/calebasse.checkboxwidget.js"></script>
<script src="{{ STATIC_URL }}/js/calebasse.divmenu.js"></script>
{% block extrascripts %}
<script src="{{ STATIC_URL }}js/calebasse.dialog.js"></script>
{% endblock %}
{% block extrastyles %}
{% endblock %}

View File

@ -27,6 +27,7 @@ service_patterns = patterns('',
url(r'^personnes/', include('calebasse.personnes.urls')),
url(r'^ressources/', include('calebasse.ressources.urls')),
url(r'^statistics/', include('calebasse.statistics.urls')),
url(r'^select2/', include('django_select2.urls')),
)
urlpatterns = patterns('',

View File

@ -1,5 +1,6 @@
--allow-external pyPdf
--allow-unverified pyPdf
pyPdf
Django >= 1.4, < 1.6
south > 0.7
django-reversion == 1.6.6
@ -17,4 +18,5 @@ django-localflavor
raven >= 3.5.2, < 3.6
M2Crypto
--allow-external pycairo
django_select2 < 4.3
#PyGTK doesn't work with pip

View File

@ -50,6 +50,7 @@ setup(name='calebasse',
'django-ajax-selects < 1.3.0',
'django-widget-tweaks < 1.2.0',
'django-tastypie == 0.9.14',
'django-select2 < 4.3',
'interval == 1.0.0',
'python-entrouvert >= 1.3'
'django-localflavor',