summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorÉtienne Loks <etienne.loks@proxience.com>2014-12-30 16:59:44 +0100
committerÉtienne Loks <etienne.loks@proxience.com>2015-05-06 15:38:32 +0200
commit25ec2a9794786ac83fa8ce743078305682d8298d (patch)
tree52e8f0c1333377628b60f0feefad64861980519f
parent155b3890c7938e98f6c1596551260a92041bea68 (diff)
downloadIshtar-25ec2a9794786ac83fa8ce743078305682d8298d.tar.bz2
Ishtar-25ec2a9794786ac83fa8ce743078305682d8298d.zip
Work on new town field (with state and department) - work on new UI for files
-rw-r--r--archaeological_files_pdl/forms.py56
-rw-r--r--archaeological_files_pdl/templates/ishtar/wizard/wizard_instruction.html100
-rw-r--r--archaeological_files_pdl/templates/ishtar/wizard/wizard_preventiveplanning.html77
-rw-r--r--archaeological_files_pdl/views.py2
-rw-r--r--archaeological_files_pdl/wizards.py17
-rw-r--r--ishtar_common/forms_common.py8
-rw-r--r--ishtar_common/static/media/style.css4
-rw-r--r--ishtar_common/tasks.py35
-rw-r--r--ishtar_common/templates/blocks/JQueryAdvancedTown.html99
-rw-r--r--ishtar_common/templates/blocks/JQueryAdvancedTown.js1
-rw-r--r--ishtar_common/urls.py4
-rw-r--r--ishtar_common/views.py39
-rw-r--r--ishtar_common/widgets.py101
-rw-r--r--ishtar_common/wizards.py7
14 files changed, 537 insertions, 13 deletions
diff --git a/archaeological_files_pdl/forms.py b/archaeological_files_pdl/forms.py
index 2703e52fd..295edcd36 100644
--- a/archaeological_files_pdl/forms.py
+++ b/archaeological_files_pdl/forms.py
@@ -21,13 +21,14 @@ import datetime
from django import forms
from django.core import validators
+from django.utils.safestring import mark_safe
from django.utils.translation import ugettext_lazy as _
-from ishtar_common.models import Person, valid_id
+from ishtar_common.models import Person, PersonType, valid_id
from archaeological_files import models
from ishtar_common.forms import get_now, reverse_lazy
-from ishtar_common.forms_common import get_town_field
+from ishtar_common.forms_common import get_advanced_town_field
from archaeological_files.forms import GENERAL_CONTRACTOR, \
RESPONSIBLE_PLANNING_SERVICE
@@ -72,11 +73,14 @@ class FileFormPlanning(forms.Form):
associated_models = {'town':models.Town}
name = forms.CharField(label=_(u"Planning name"), required=False,
max_length=100)
- main_town = get_town_field(required=False)
+ main_town = get_advanced_town_field(required=True)
locality = forms.CharField(label=_(u"Locality"), max_length=100,
required=False)
address = forms.CharField(label=_(u"Address (number/street)"),
- widget=forms.Textarea, required=False)
+ widget=forms.Textarea(
+ attrs={"placeholder":_(u"Number/street")}),
+ required=False,
+ )
postal_code = forms.CharField(label=_(u"Postal code"), max_length=10,
required=False)
total_surface = forms.IntegerField(required=False,
@@ -156,6 +160,8 @@ class FileFormGeneralContractor(forms.Form):
class FileFormPlanningService(forms.Form):
form_label = _(u"Town planning service")
associated_models = {'responsible_planning_service':models.Person}
+ reference_number = forms.IntegerField(label=_(u"File reference"),
+ required=False)
def __init__(self, *args, **kwargs):
super(FileFormPlanningService, self).__init__(*args, **kwargs)
@@ -170,4 +176,46 @@ class FileFormPlanningService(forms.Form):
js_template='ishtar/blocks/JQueryCorporationPerson.js',
new=True),
validators=[valid_id(Person)])
+ self.fields.keyOrder = ['responsible_planning_service',
+ 'reference_number']
+
+class FileFormInstruction(forms.Form):
+ form_label = u"Instruction SRA"
+ in_charge = forms.IntegerField(label=_("Person in charge"),
+ widget=widgets.JQueryAutoComplete(reverse_lazy('autocomplete-person',
+ args=[PersonType.objects.get(txt_idx='sra_agent').pk]),
+ limit={'person_types':[PersonType.objects.get(txt_idx='sra_agent').pk]},
+ associated_model=Person, new=True),
+ validators=[valid_id(Person)])
+ related_file = forms.IntegerField(label=_("Related file"), required=False,
+ widget=widgets.JQueryAutoComplete(reverse_lazy('autocomplete-file'),
+ associated_model=models.File),
+ validators=[valid_id(models.File)])
+ comment = forms.CharField(label=_(u"Comment"), widget=forms.Textarea,
+ required=False)
+ year = forms.IntegerField(label=_("Year"),
+ validators=[validators.MinValueValidator(1900),
+ validators.MaxValueValidator(2100)])
+ numeric_reference = forms.IntegerField(label=_("Numeric reference"),
+ required=False)
+ end_date = forms.DateField(initial=get_now, widget=widgets.JQueryDate,
+ required=False)
+ def __init__(self, *args, **kwargs):
+ c_year = datetime.date.today().year
+ if 'year' in kwargs:
+ c_year = kwargs.pop('year')
+ super(FileFormInstruction, self).__init__(*args, **kwargs)
+ self.fields['year'].initial = c_year
+ self.fields['year'].widget.attrs.update({'readonly':'readonly'})
+ c_num, lasts = 0, ""
+ q = models.File.objects.filter(numeric_reference__isnull=False,
+ year=c_year).order_by('-numeric_reference')
+ if q.count():
+ num = q.all()[0].numeric_reference
+ lasts = u"SRA %s-%d" % (unicode(c_year), num)
+ lbl = self.fields['numeric_reference'].label
+ if lasts:
+ lbl += u"<br/>(dernière entrée : %s)" % lasts
+ self.fields['numeric_reference'].label = mark_safe(lbl)
+ self.fields['numeric_reference'].initial = c_num + 1
diff --git a/archaeological_files_pdl/templates/ishtar/wizard/wizard_instruction.html b/archaeological_files_pdl/templates/ishtar/wizard/wizard_instruction.html
new file mode 100644
index 000000000..b47de2cce
--- /dev/null
+++ b/archaeological_files_pdl/templates/ishtar/wizard/wizard_instruction.html
@@ -0,0 +1,100 @@
+{% extends "ishtar/wizard/default_wizard.html" %}
+{% load i18n range table_form %}
+{% block wizard_form %}
+<form action="." method="post" name='wizard'{% if wizard.form.file_upload %} enctype="multipart/form-data"{% endif %}>{% csrf_token %}
+<div class='form'>
+{{ wizard.form.media }}
+{{ wizard.management_form }}
+
+<table>
+
+<tr class='required'>
+ <th><label for="id_instruction-{{CURRENT_ACTION}}-in_charge">Dossier suivi par</label></th>
+</tr>
+<tr class='required'>
+ <td>{{wizard.form.in_charge|safe}}</td>
+</tr>
+
+<tr>
+ <th><label for="id_instruction-{{CURRENT_ACTION}}-related_file">Dossier lié à</label></th>
+</tr>
+<tr>
+ <td>{{wizard.form.related_file|safe}}</td>
+</tr>
+
+<tr>
+ <th><label for="id_instruction-{{CURRENT_ACTION}}-comment">Commentaire</label></th>
+</tr>
+<tr>
+ <td>{{wizard.form.comment|safe}}</td>
+</tr>
+
+<tr class='required'>
+ <th><label>État du dossier</label></th>
+</tr>
+<tr>
+ <td><input type='radio' name='state' value='open' id='state-open'/> <label for='state-open'>Dossier actif</label></td>
+</tr>
+<tr>
+ <td><input type='radio' name='state' value='closed' id='state-closed'/> <label for='state-closed'>Dossier clos / date de clôture</label> : {{wizard.form.end_date|safe}}</td>
+</tr>
+
+<tr class='required'>
+ <th><label for="id_instruction-{{CURRENT_ACTION}}-year">{{wizard.form.numeric_reference.label}}</label></th>
+</tr>
+<tr>
+ <td>SRA <span class='small'>{{wizard.form.year|safe}}</span> - <span class='small'>{{wizard.form.numeric_reference|safe}}</span></td>
+</tr>
+</table>
+
+<input type="hidden" name="{{ step_field }}" value="{{ step0 }}" />
+{{ previous_fields|safe }}
+<div id='validation-bar'>
+ <input type="submit" id="submit_form" name='validate' value="{% trans "Validate" %}"/>
+ {% if next_steps %}<input type="submit" id="submit_end_form" name='validate_and_end' value="{% trans "Validate and end" %}"/>{% endif %}
+</div>
+</div>
+</form>
+<script type='text/javascript'>
+$(function(){
+
+ if ($('#id_instruction-{{CURRENT_ACTION}}-end_date').val()){
+ $("#state-closed").prop('checked', true);
+ } else {
+ $("#state-open").prop('checked', true);
+ }
+
+ check_state = function(){
+ var state = $("input[name=state]:checked").val();
+ if (state == 'closed'){
+ $('#id_instruction-{{CURRENT_ACTION}}-end_date').focus();
+ $('#id_instruction-{{CURRENT_ACTION}}-end_date').prop('disabled', false);
+ } else if (state == 'open'){
+ $('#id_instruction-{{CURRENT_ACTION}}-end_date').val('');
+ $('#id_instruction-{{CURRENT_ACTION}}-end_date').prop('disabled', true);
+ }
+ };
+
+ $('input[name=state]').click(check_state);
+
+ check_state();
+
+ $('#submit_form').click(function(){
+ var state = $("input[name=state]:checked").val();
+ if (state == 'closed'){
+ if (!$('#id_instruction-{{CURRENT_ACTION}}-end_date').val()){
+ alert("Vous devez sélectionner une date de clôture.")
+ return false;
+ }
+ return true;
+ } else if (state == 'open'){
+ return true;
+ } else {
+ alert("Vous devez choisir un état pour ce dossier.")
+ return false;
+ }
+ return true;
+ });
+});
+</script>
+{% endblock %}
diff --git a/archaeological_files_pdl/templates/ishtar/wizard/wizard_preventiveplanning.html b/archaeological_files_pdl/templates/ishtar/wizard/wizard_preventiveplanning.html
new file mode 100644
index 000000000..41527629d
--- /dev/null
+++ b/archaeological_files_pdl/templates/ishtar/wizard/wizard_preventiveplanning.html
@@ -0,0 +1,77 @@
+{% extends "ishtar/wizard/default_wizard.html" %}
+{% load i18n range table_form %}
+{% block wizard_form %}
+<form action="." method="post" name='wizard'{% if wizard.form.file_upload %} enctype="multipart/form-data"{% endif %}>{% csrf_token %}
+<div class='form'>
+{{ wizard.form.media }}
+{{ wizard.management_form }}
+
+<table>
+
+<tr class='required'>
+ <th><label for="id_preventiveplanning-{{CURRENT_ACTION}}-name">Nom de l'aménagement</label></th>
+</tr>
+<tr class='required'>
+ <td>{{wizard.form.name|safe}}</td>
+</tr>
+
+</table>
+
+<h4>Localisation</h4>
+<table>
+
+<tr>
+ <td>{{wizard.form.main_town|safe}}</td>
+</tr>
+
+<tr>
+ <th colspan='2'><label for="id_preventiveplanning-{{CURRENT_ACTION}}-locality">Lieu-dit</label></th>
+</tr>
+<tr>
+ <td colspan='2'>{{wizard.form.locality|safe}}</td>
+</tr>
+
+<tr>
+ <th colspan='2'><label for="id_preventiveplanning-{{CURRENT_ACTION}}-address">Adresse</label></th>
+</tr>
+<tr>
+ <td colspan='2'>{{wizard.form.address|safe}}</td>
+</tr>
+
+<tr>
+ <th colspan='2'><label for="id_preventiveplanning-{{CURRENT_ACTION}}-postal_code">Code postal</label></th>
+</tr>
+<tr>
+ <td colspan='2'>{{wizard.form.postal_code|safe}}</td>
+</tr>
+
+</table>
+
+<h4>Surfaces</h4>
+<table>
+
+<tr>
+ <th><label for="id_preventiveplanning-{{CURRENT_ACTION}}-total_surface">Surface totale des terrains</label></th>
+</tr>
+<tr>
+ <td>{{wizard.form.total_surface|safe}}</td>
+</tr>
+
+<tr>
+ <th><label for="id_preventiveplanning-{{CURRENT_ACTION}}-total_developed_surface">Surface totale aménagée</label></th>
+</tr>
+<tr>
+ <td>{{wizard.form.total_developed_surface|safe}}</td>
+</tr>
+
+</table>
+
+<input type="hidden" name="{{ step_field }}" value="{{ step0 }}" />
+{{ previous_fields|safe }}
+<div id='validation-bar'>
+ <input type="submit" id="submit_form" name='validate' value="{% trans "Validate" %}"/>
+ {% if next_steps %}<input type="submit" id="submit_end_form" name='validate_and_end' value="{% trans "Validate and end" %}"/>{% endif %}
+</div>
+</div>
+</form>
+{% endblock %}
diff --git a/archaeological_files_pdl/views.py b/archaeological_files_pdl/views.py
index 712990234..c8e1d1498 100644
--- a/archaeological_files_pdl/views.py
+++ b/archaeological_files_pdl/views.py
@@ -39,6 +39,8 @@ file_creation_wizard = FileWizard.as_view([
forms.FileFormGeneralContractor),
('planningservice-file_creation',
forms.FileFormPlanningService),
+ ('instruction-file_creation',
+ forms.FileFormInstruction),
('research-file_creation', ref_forms.FileFormResearch),
('final-file_creation', ref_forms.FinalForm)],
label=_(u"New file"),
diff --git a/archaeological_files_pdl/wizards.py b/archaeological_files_pdl/wizards.py
index 4abe5f0d5..6f688d7ca 100644
--- a/archaeological_files_pdl/wizards.py
+++ b/archaeological_files_pdl/wizards.py
@@ -25,12 +25,23 @@ class FileWizard(BaseFileWizard):
town_input_id = 'main_town'
multi_towns = False
wizard_templates = {
- 'generalcontractor-file_creation':\
- 'ishtar/wizard/wizard_generalcontractor.html',}
+ 'generalcontractor-%(url_name)s':\
+ 'ishtar/wizard/wizard_generalcontractor.html',
+ 'instruction-%(url_name)s':\
+ 'ishtar/wizard/wizard_instruction.html',
+ 'preventiveplanning-%(url_name)s':\
+ 'ishtar/wizard/wizard_preventiveplanning.html',
+ }
+
+ def get_current_year(self):
+ general_form_key = 'general-' + self.url_name
+ return self.session_get_value(general_form_key, 'year')
def get_form_kwargs(self, *args, **kwargs):
returned = super(FileWizard, self).get_form_kwargs(*args, **kwargs)
- if args and args[0].startswith('generalcontractor-file_creation'):
+ if args and args[0].startswith('generalcontractor-'):
if 'status' in self.request.GET:
returned['status'] = self.request.GET['status']
+ if args and args[0].startswith('instruction-'):
+ returned['year'] = self.get_current_year()
return returned
diff --git a/ishtar_common/forms_common.py b/ishtar_common/forms_common.py
index e1a0e9063..23d7126c9 100644
--- a/ishtar_common/forms_common.py
+++ b/ishtar_common/forms_common.py
@@ -54,6 +54,14 @@ def get_town_field(label=_(u"Town"), required=True):
validators=[models.valid_id(models.Town)], label=label,
help_text=mark_safe(help_text), required=required)
+def get_advanced_town_field(label=_(u"Town"), required=True):
+ # !FIXME hard_link, reverse_lazy doen't seem to work with formsets
+ return forms.IntegerField(
+ widget=widgets.JQueryTown("/" + settings.URL_PATH + \
+ 'autocomplete-advanced-town'),
+ validators=[models.valid_id(models.Town)], label=label,
+ required=required)
+
def get_person_field(label=_(u"Person"), required=True, person_types=[]):
# !FIXME hard_link, reverse_lazy doen't seem to work with formsets
widget = None
diff --git a/ishtar_common/static/media/style.css b/ishtar_common/static/media/style.css
index 55bb95e30..a1b084002 100644
--- a/ishtar_common/static/media/style.css
+++ b/ishtar_common/static/media/style.css
@@ -906,6 +906,10 @@ a.remove{
width:60px;
}
+.small, .small input{
+ width:60px;
+}
+
#progress{
display:none;
position:fixed;
diff --git a/ishtar_common/tasks.py b/ishtar_common/tasks.py
index a9db26087..a8db97bb1 100644
--- a/ishtar_common/tasks.py
+++ b/ishtar_common/tasks.py
@@ -1,6 +1,6 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*-
-# Copyright (C) 2013 Étienne Loks <etienne.loks_AT_peacefrogsDOTnet>
+# Copyright (C) 2013-2014 Étienne Loks <etienne.loks_AT_peacefrogsDOTnet>
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License as
@@ -17,13 +17,15 @@
# See the file COPYING for details.
+import sys
+
from django.conf import settings
from django.db.models import Q
-from geodjangofla.models import Commune
-from ishtar_common.models import Town
+from ishtar_common.models import Town, Department
def load_towns():
+ from geodjangofla.models import Commune
q = None
for dpt_number in settings.ISHTAR_DPTS:
query = Q(insee_com__istartswith=dpt_number)
@@ -51,3 +53,30 @@ def load_towns():
setattr(town, k, defaults[k])
town.save()
return nb, updated
+
+def update_towns():
+ nb, updated = 0, 0
+ dpts = dict([(dpt.number, dpt) for dpt in Department.objects.all()])
+ q = Town.objects.filter(numero_insee__isnull=False)
+ total = q.count()
+ for idx, town in enumerate(q.all()):
+ sys.stdout.write('\rProcessing... %s/%d' % (
+ str(idx+1).zfill(len(str(total))), total))
+ if len(town.numero_insee) < 2:
+ continue
+ dpt_code = town.numero_insee[:2]
+ if dpt_code.startswith('9') and int(dpt_code) > 95:
+ dpt_code = town.numero_insee[:3]
+ if dpt_code not in dpts:
+ sys.stdout.write('Missing department with INSEE code: %s' % dpt_code)
+ continue
+ if town.departement == dpts[dpt_code]:
+ continue
+ if town.departement:
+ updated += 1
+ else:
+ nb += 1
+ town.departement = dpts[dpt_code]
+ town.save()
+ sys.stdout.write('\n')
+ return nb, updated
diff --git a/ishtar_common/templates/blocks/JQueryAdvancedTown.html b/ishtar_common/templates/blocks/JQueryAdvancedTown.html
new file mode 100644
index 000000000..78d2d7831
--- /dev/null
+++ b/ishtar_common/templates/blocks/JQueryAdvancedTown.html
@@ -0,0 +1,99 @@
+{% load i18n %}{% load url from future %}</td></tr>
+<tr>
+ <td>{% trans "State" context "Région" %}</td>
+ <td>
+ <select id='current-state'>
+ <option value=''>--------</option>{% for state in states %}
+ <option value='{{state.number}}'{% if state.number == selected_state %}selected='selected'{% endif %}>{{state}}</option>
+ {% endfor %}</select>
+ </td>
+</tr>
+<tr>
+ <td>{% trans "Department" %}</td>
+ <td>
+ <select id='current-department'>
+ </select>
+ </td>
+</tr>
+<tr class='required'>
+ <th><label>{% trans "Town" %}</label></th>
+ <td><input{{attrs_select}}/>
+<input type="hidden"{{attrs_hidden}}/>
+<script type="text/javascript"><!--//
+ selected_department = "{{selected_department}}";
+ var empty_select = "<option value=''>--------</option>";
+
+ function update_department_field(){
+ var selected_state = $("#current-state").val();
+ if (!selected_state){
+ $("#current-department").html("<option value=''>"+"{% trans 'Choose a state first' %}"+"</option>");
+ $("#current-department").prop('disabled', true);
+ $('#id_select_{{field_id}}').prop('disabled', true);
+ return;
+ }
+ $.ajax({
+ url: "{% url 'department-by-state' %}" + selected_state,
+ type: 'get',
+ dataType: 'json',
+ success: function(data) {
+ var html = "";
+ for (idx in data){
+ dpt = data[idx];
+ html += "<option value='" + dpt.number + "'";
+ if (String(dpt.number) == String(selected_department)){
+ html += " selected='selected'";
+ }
+ html += ">" + dpt.value + "</option>";
+ }
+ $("#current-department").html(html);
+ $("#current-department").prop('disabled', false);
+ update_search_town();
+ }
+ });
+ }
+
+ function update_search_town(){
+ selected_department = $("#current-department").val();
+ if (selected_department){
+ $("#id_select_{{field_id}}").autocomplete( "option", "source", {{source}}+selected_department);
+ $('#id_select_{{field_id}}').prop('disabled', false);
+ } else {
+ $('#id_select_{{field_id}}').prop('disabled', true);
+ }
+ }
+
+ function empty_town(){
+ $('#id_{{field_id}}').val(null);
+ $('#id_select_{{field_id}}').val(null);
+ }
+
+ $(function() {
+ update_department_field();
+
+ $("#current-state").change(function(){
+ empty_town();
+ update_department_field();
+ });
+
+ $("#current-department").change(function(){
+ empty_town();
+ update_search_town();
+ });
+
+ $("#id_select_{{field_id}}").autocomplete({
+ source: {{source}},
+ select: function( event, ui ) {
+ if(ui.item){
+ $('#id_{{field_id}}').val(ui.item.id);
+ } else {
+ $('#id_{{field_id}}').val(null);
+ }
+ },
+ minLength: 2{% if options %},
+ {{options}}
+ {% endif %}
+ });
+
+ $('#id_select_{{field_id}}').live('click', empty_town);
+
+});//--></script>
diff --git a/ishtar_common/templates/blocks/JQueryAdvancedTown.js b/ishtar_common/templates/blocks/JQueryAdvancedTown.js
new file mode 100644
index 000000000..8b1378917
--- /dev/null
+++ b/ishtar_common/templates/blocks/JQueryAdvancedTown.js
@@ -0,0 +1 @@
+
diff --git a/ishtar_common/urls.py b/ishtar_common/urls.py
index d31d0d359..0c4059eeb 100644
--- a/ishtar_common/urls.py
+++ b/ishtar_common/urls.py
@@ -98,8 +98,12 @@ urlpatterns += patterns('ishtar_common.views',
name='get-person'),
url(r'show-person(?:/(?P<pk>.+))?/(?P<type>.+)?$',
'show_person', name='show-person'),
+ url(r'department-by-state/(?P<state_id>.+)?$', 'department_by_state',
+ name='department-by-state'),
url(r'autocomplete-town/?$', 'autocomplete_town',
name='autocomplete-town'),
+ url(r'autocomplete-advanced-town/(?P<department_id>[0-9]+[ABab]?)?$',
+ 'autocomplete_advanced_town', name='autocomplete-advanced-town'),
url(r'autocomplete-department/?$', 'autocomplete_department',
name='autocomplete-department'),
url(r'new-author/(?:(?P<parent_name>[^/]+)/)?(?:(?P<limits>[^/]+)/)?$',
diff --git a/ishtar_common/views.py b/ishtar_common/views.py
index a8ab91fb9..66b488254 100644
--- a/ishtar_common/views.py
+++ b/ishtar_common/views.py
@@ -202,6 +202,45 @@ def autocomplete_town(request):
for town in towns])
return HttpResponse(data, mimetype='text/plain')
+def autocomplete_advanced_town(request, department_id=None, state_id=None):
+ if not request.GET.get('term'):
+ return HttpResponse(mimetype='text/plain')
+ q = request.GET.get('term')
+ q = unicodedata.normalize("NFKD", q).encode('ascii','ignore')
+ query = Q()
+ for q in q.split(' '):
+ extra = Q(name__icontains=q)
+ if settings.COUNTRY == 'fr':
+ extra = extra | Q(numero_insee__istartswith=q)
+ if not department_id:
+ extra = extra | Q(departement__label__istartswith=q)
+ query = query & extra
+ if department_id:
+ query = query & Q(departement__number__iexact=department_id)
+ if state_id:
+ query = query & Q(departement__state__number__iexact=state_id)
+ limit = 20
+ towns = models.Town.objects.filter(query)[:limit]
+ result = []
+ for town in towns:
+ val = town.name
+ if hasattr(town, 'numero_insee'):
+ val += " (%s)" % town.numero_insee
+ result.append({'id':town.pk, 'value':val})
+ data = json.dumps(result)
+ return HttpResponse(data, mimetype='text/plain')
+
+def department_by_state(request, state_id=''):
+ if not state_id:
+ data = []
+ else:
+ departments = models.Department.objects.filter(state__number=state_id)
+ data = json.dumps([{'id':department.pk, 'number':department.number,
+ 'value':unicode(department)}
+ for department in departments])
+ return HttpResponse(data, mimetype='text/plain')
+
+
from types import NoneType
def format_val(val):
diff --git a/ishtar_common/widgets.py b/ishtar_common/widgets.py
index 91594edbd..ba7e61e46 100644
--- a/ishtar_common/widgets.py
+++ b/ishtar_common/widgets.py
@@ -34,7 +34,7 @@ from django.utils.safestring import mark_safe
from django.utils.simplejson import JSONEncoder
from django.utils.translation import ugettext_lazy as _
-import models
+from ishtar_common import models
reverse_lazy = lazy(reverse, unicode)
@@ -283,6 +283,105 @@ class JQueryAutoComplete(forms.TextInput):
}
return html
+class JQueryTown(forms.TextInput):
+ """
+ Town fields whith state and department pre-selections
+ """
+
+ def __init__(self, source, options={},
+ attrs={}, new=False, limit={}):
+ self.options = None
+ self.attrs = {}
+ self.source = source
+ if len(options) > 0:
+ self.options = JSONEncoder().encode(options)
+ self.attrs.update(attrs)
+ self.new = new
+ self.limit = limit
+
+ @classmethod
+ def encode_source(cls, source):
+ encoded_src = ''
+ if isinstance(source, list):
+ encoded_src = JSONEncoder().encode(source)
+ elif isinstance(source, str) \
+ or isinstance(source, unicode):
+ src = escape(source)
+ if not src.endswith('/'):
+ src += "/"
+ encoded_src = "'%s'" % src
+ else:
+ try:
+ src = unicode(source)
+ if not src.endswith('/'):
+ src += "/"
+ encoded_src = "'%s'" % src
+ except:
+ raise ValueError('source type is not valid')
+ return encoded_src
+
+ def render(self, name, value=None, attrs=None):
+ attrs_hidden = self.build_attrs(attrs, name=name)
+ attrs_select = self.build_attrs(attrs)
+ attrs_select['placeholder'] = _(u"Search...")
+ selected = ''
+ selected_state = ''
+ selected_department = ''
+ if value:
+ hiddens = []
+ selects = []
+ if type(value) not in (list, tuple):
+ values = unicode(escape(smart_unicode(value)))
+ values = values.replace('[', '').replace(']', '')
+ values = values.split(',')
+ else:
+ values = []
+ for v in value:
+ values += v.split(',')
+ for v in values:
+ if not v:
+ continue
+ hiddens.append(v)
+ selects.append(v)
+ try:
+ item = models.Town.objects.get(pk=v)
+ selects[-1] = unicode(item)
+ if item.departement:
+ selected_department = item.departement.number
+ if item.departement.state:
+ selected_state = item.departement.state.number
+ selected = item.pk
+ except (models.Town.DoesNotExist, ValueError):
+ selects.pop()
+ hiddens.pop()
+ if hiddens and selects:
+ attrs_hidden['value'] = hiddens[0]
+ attrs_select['value'] = selects[0]
+ if not self.attrs.has_key('id'):
+ attrs_hidden['id'] = 'id_%s' % name
+ attrs_select['id'] = 'id_select_%s' % name
+ if 'class' not in attrs_select:
+ attrs_select['class'] = 'autocomplete'
+
+ source = self.encode_source(self.source)
+ dct = {'source':mark_safe(source),
+ 'selected':selected,
+ 'safe_field_id':slugify(name).replace('-', '_'),
+ 'field_id':name}
+ if self.options:
+ dct['options'] = mark_safe('%s' % self.options)
+
+ dct.update({'attrs_select':mark_safe(flatatt(attrs_select)),
+ 'attrs_hidden':mark_safe(flatatt(attrs_hidden)),
+ 'name':name,
+ 'states':models.State.objects.all().order_by('label'),
+ 'selected_department':selected_department,
+ 'selected_state':selected_state
+ })
+ html = loader.get_template('blocks/JQueryAdvancedTown.html').render(
+ Context(dct))
+ return html
+
class JQueryPersonOrganization(forms.TextInput):
"""
Complex widget which manage:
diff --git a/ishtar_common/wizards.py b/ishtar_common/wizards.py
index 190a7fc86..2ad3635d7 100644
--- a/ishtar_common/wizards.py
+++ b/ishtar_common/wizards.py
@@ -95,8 +95,11 @@ class Wizard(NamedUrlWizardView):
def get_template_names(self):
templates = ['ishtar/wizard/default_wizard.html']
current_step = self.steps.current
- if current_step in self.wizard_templates:
- templates = [self.wizard_templates[current_step]] + templates
+ wizard_templates = dict([
+ (key % {'url_name':self.url_name}, self.wizard_templates[key])
+ for key in self.wizard_templates])
+ if current_step in wizard_templates:
+ templates = [wizard_templates[current_step]] + templates
elif current_step == self.steps.last:
templates = ['ishtar/wizard/confirm_wizard.html'] + templates
return templates