diff options
| -rw-r--r-- | archaeological_files/forms.py | 26 | ||||
| -rw-r--r-- | archaeological_files/ishtar_menu.py | 6 | ||||
| -rw-r--r-- | archaeological_files/models.py | 14 | ||||
| -rw-r--r-- | archaeological_files/templates/ishtar/administrativeact_document.html | 23 | ||||
| -rw-r--r-- | archaeological_files/urls.py | 7 | ||||
| -rw-r--r-- | archaeological_files/views.py | 28 | ||||
| -rw-r--r-- | archaeological_operations/models.py | 5 | ||||
| -rw-r--r-- | ishtar_common/admin.py | 2 | ||||
| -rw-r--r-- | ishtar_common/migrations/0005_auto__add_documenttemplate.py | 209 | ||||
| -rw-r--r-- | ishtar_common/models.py | 57 | ||||
| -rw-r--r-- | ishtar_common/ooo_replace.py | 102 | ||||
| -rw-r--r-- | ishtar_common/templates/ishtar/wizard/wizard_list_search_result.html | 2 | ||||
| -rw-r--r-- | ishtar_common/views.py | 3 | 
13 files changed, 467 insertions, 17 deletions
| diff --git a/archaeological_files/forms.py b/archaeological_files/forms.py index 2adc58ba1..9affc0901 100644 --- a/archaeological_files/forms.py +++ b/archaeological_files/forms.py @@ -33,7 +33,7 @@ from django.utils.translation import ugettext_lazy as _  from django.utils.safestring import mark_safe  from ishtar_common.models import Person, PersonType, Town, Organization, \ -                                 OrganizationType, valid_id, is_unique +                         OrganizationType, valid_id, is_unique, DocumentTemplate  from archaeological_operations.models import ActType, AdministrativeAct  import models  from ishtar_common.forms import FinalForm, FormSet, ClosingDateFormSelection, \ @@ -185,16 +185,36 @@ class FileFormPreventive(forms.Form):          self.fields['permit_type'].choices = models.PermitType.get_types()          self.fields['permit_type'].help_text = models.PermitType.get_help() -  class FinalFileClosingForm(FinalForm):      confirm_msg = " "      confirm_end_msg = _(u"Would you like to close this archaeological file?") -  class FinalFileDeleteForm(FinalForm):      confirm_msg = " "      confirm_end_msg = _(u"Would you like to delete this archaelogical file ?") +class DocumentGenerationAdminActForm(forms.Form): +    _associated_model = AdministrativeAct +    document_template = forms.ChoiceField(label=_("Template"), choices=[]) + +    def __init__(self, *args, **kwargs): +        super(DocumentGenerationAdminActForm, self).__init__(*args, **kwargs) +        self.fields['document_template'].choices = DocumentTemplate.get_tuples( +                    dct={'associated_object_name': +                         'archaeological_operations.models.AdministrativeAct'}) + +    def save(self, object_pk): +        try: +            c_object = self._associated_model.objects.get(pk=object_pk) +        except self._associated_model.DoesNotExist: +            return +        try: +            template = DocumentTemplate.objects.get( +                            pk=self.cleaned_data.get('document_template')) +        except DocumentTemplate.DoesNotExist: +            return +        return template.publish(c_object) +  class AdministrativeActFileSelect(TableSelect):      associated_file__towns = get_town_field()      act_type = forms.ChoiceField(label=_("Act type"), choices=[]) diff --git a/archaeological_files/ishtar_menu.py b/archaeological_files/ishtar_menu.py index 6655a381c..87958848a 100644 --- a/archaeological_files/ishtar_menu.py +++ b/archaeological_files/ishtar_menu.py @@ -1,6 +1,6 @@  #!/usr/bin/env python  # -*- coding: utf-8 -*- -# Copyright (C) 2010-2012 Étienne Loks  <etienne.loks_AT_peacefrogsDOTnet> +# Copyright (C) 2010-2013 É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 @@ -60,6 +60,10 @@ MENU_SECTIONS = [                           _(u"Deletion"),                    model=AdministrativeAct,                    access_controls=['delete_file', 'delete_own_file']), +                MenuItem('file_administrativeact_document', +                         _(u"Documents"), +                  model=AdministrativeAct, +                  access_controls=['change_file', 'change_own_file']),                  ],),          ]),      ), diff --git a/archaeological_files/models.py b/archaeological_files/models.py index 0095dd13b..2b739fb1c 100644 --- a/archaeological_files/models.py +++ b/archaeological_files/models.py @@ -29,7 +29,7 @@ from ishtar_common.utils import cached_label_changed  from ishtar_common.models import GeneralType, BaseHistorizedItem, \      HistoricalRecords, OwnPerms, Person, Organization, Department, Town, \ -    Dashboard, IshtarUser +    Dashboard, IshtarUser, ValueGetter  class FileType(GeneralType):      class Meta: @@ -53,14 +53,14 @@ class PermitType(GeneralType):          ordering = ('label',)  if settings.COUNTRY == 'fr': -    class SaisineType(GeneralType): +    class SaisineType(GeneralType, ValueGetter):          delay = models.IntegerField(_(u"Delay (in days)"))          class Meta:              verbose_name = u"Type Saisine"              verbose_name_plural = u"Types Saisine"              ordering = ('label',) -class File(BaseHistorizedItem, OwnPerms): +class File(BaseHistorizedItem, OwnPerms, ValueGetter):      TABLE_COLS = ['numeric_reference', 'year', 'internal_reference',                    'file_type', 'saisine_type', 'towns', ]      year = models.IntegerField(_(u"Year"), @@ -139,6 +139,14 @@ class File(BaseHistorizedItem, OwnPerms):      def get_total_number(cls):          return cls.objects.count() +    def get_values(self, prefix=''): +        values = super(File, self).get_values(prefix=prefix) +        values['adminact_associated_file_towns_count'] = unicode( +                                                            self.towns.count()) +        values['adminact_associated_file_towns'] = u", ".join( +                                   [unicode(town)for town in self.towns.all()]) +        return values +      def __unicode__(self):          if self.cached_label:              return self.cached_label diff --git a/archaeological_files/templates/ishtar/administrativeact_document.html b/archaeological_files/templates/ishtar/administrativeact_document.html new file mode 100644 index 000000000..cdb2b45be --- /dev/null +++ b/archaeological_files/templates/ishtar/administrativeact_document.html @@ -0,0 +1,23 @@ +{% extends "base.html" %}Q +{% load i18n %} +{% block extra_head %} +{{search_form.media}} +{{ template_form.media }} +{% endblock %} + +{% block content %} +<h2>{% trans "Document generation" %}</h2> +<form action="." method="post">{% csrf_token %} +<div class='form'> +<table> +{{ search_form.as_table }} +</table> +<h4>{% trans "Choose the type of document" %}</h4> +<table> +{{ template_form }} +</table> +<input type="submit" id="submit_form" name='validate' value="{% trans "Generate" %}"/> +</div> +</form> +{% endblock %} + diff --git a/archaeological_files/urls.py b/archaeological_files/urls.py index 72a6e2df7..9d1f4f56f 100644 --- a/archaeological_files/urls.py +++ b/archaeological_files/urls.py @@ -1,6 +1,6 @@  #!/usr/bin/env python  # -*- coding: utf-8 -*- -# Copyright (C) 2010-2012 Étienne Loks  <etienne.loks_AT_peacefrogsDOTnet> +# Copyright (C) 2010-2013 É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 @@ -59,5 +59,8 @@ urlpatterns += patterns('archaeological_files.views',             'show_file', name='show-historized-file'),       url(r'revert-file/(?P<pk>.+)/(?P<date>.+)$',             'revert_file', name='revert-file'), -     url(r'dashboard_file/$', 'dashboard_file', name='dashboard-file') +     url(r'dashboard_file/$', 'dashboard_file', name='dashboard-file'), +     url(r'file_administrativeact_document/$', +           'file_administrativeactfile_document', +           name='administrativeact_document'),  ) diff --git a/archaeological_files/views.py b/archaeological_files/views.py index 407bbe821..e55368e62 100644 --- a/archaeological_files/views.py +++ b/archaeological_files/views.py @@ -18,10 +18,12 @@  # See the file COPYING for details.  import json +import os  from django.db.models import Q  from django.http import HttpResponse  from django.shortcuts import render_to_response +from django.template.defaultfilters import slugify  from django.utils.translation import ugettext_lazy as _  from ishtar_common.views import get_item, show_item, revert_item @@ -156,3 +158,29 @@ file_administrativeactfile_deletion_wizard = \                        label=_(u"File: administrative act deletion"),                        url_name='file_administrativeactfile_deletion',) +def file_administrativeactfile_document(request): +    dct = {} +    if request.POST: +        dct['search_form'] = AdministrativeActFileFormSelection(request.POST) +        dct['template_form'] = DocumentGenerationAdminActForm(request.POST) +        if dct['search_form'].is_valid() and dct['template_form'].is_valid(): +            doc = dct['template_form'].save( +                                dct['search_form'].cleaned_data.get('pk')) +            if doc: +                MIMES = {'odt':'application/vnd.oasis.opendocument.text', +                         'ods':'application/vnd.oasis.opendocument.spreadsheet'} +                ext = doc.split('.')[-1] +                doc_name = slugify(doc.split(os.path.sep)[-1][:-len(ext)])+ "."\ +                                                                          + ext +                mimetype = 'text/csv' +                if ext in MIMES: +                    mimetype = MIMES[ext] +                response = HttpResponse(open(doc), mimetype=mimetype) +                response['Content-Disposition'] = 'attachment; filename=%s' % \ +                                                                        doc_name +                return response +    else: +        dct['search_form'] = AdministrativeActFileFormSelection() +        dct['template_form'] = DocumentGenerationAdminActForm() +    return render_to_response('ishtar/administrativeact_document.html', dct, +                              context_instance=RequestContext(request)) diff --git a/archaeological_operations/models.py b/archaeological_operations/models.py index 3d6eaa15a..e846f15f8 100644 --- a/archaeological_operations/models.py +++ b/archaeological_operations/models.py @@ -31,7 +31,7 @@ from ishtar_common.utils import cached_label_changed  from ishtar_common.models import GeneralType, BaseHistorizedItem, \       HistoricalRecords, LightHistorizedItem, OwnPerms, Department, Source,\ -     Person, Organization, Town, Dashboard, IshtarUser +     Person, Organization, Town, Dashboard, IshtarUser, ValueGetter  FILES_AVAILABLE = 'archaeological_files' in settings.INSTALLED_APPS  if FILES_AVAILABLE:      from archaeological_files.models import File @@ -347,7 +347,7 @@ class ActType(GeneralType):          verbose_name_plural = _(u"Act types")          ordering = ('label',) -class AdministrativeAct(BaseHistorizedItem, OwnPerms): +class AdministrativeAct(BaseHistorizedItem, OwnPerms, ValueGetter):      TABLE_COLS = ['act_type', 'associated_file', 'operation',                    'associated_file.towns', 'operation.towns']      TABLE_COLS_FILE = ['act_type', 'associated_file', 'associated_file.towns',] @@ -375,6 +375,7 @@ class AdministrativeAct(BaseHistorizedItem, OwnPerms):          ref_sra = models.CharField(u"Référence SRA", max_length=15, blank=True,                                        null=True)      history = HistoricalRecords() +    _prefix = 'adminact_'      class Meta:          verbose_name = _(u"Administrative act") diff --git a/ishtar_common/admin.py b/ishtar_common/admin.py index 093d137ae..320136aec 100644 --- a/ishtar_common/admin.py +++ b/ishtar_common/admin.py @@ -88,7 +88,7 @@ general_models = [models.OrganizationType, models.SourceType, models.AuthorType]  for model in general_models:      admin.site.register(model, GeneralTypeAdmin) -basic_models = [models.IshtarUser] +basic_models = [models.IshtarUser, models.DocumentTemplate]  if settings.COUNTRY == 'fr':      basic_models += [models.Arrondissement, models.Canton] diff --git a/ishtar_common/migrations/0005_auto__add_documenttemplate.py b/ishtar_common/migrations/0005_auto__add_documenttemplate.py new file mode 100644 index 000000000..383ee5a32 --- /dev/null +++ b/ishtar_common/migrations/0005_auto__add_documenttemplate.py @@ -0,0 +1,209 @@ +# -*- coding: utf-8 -*- +import datetime +from south.db import db +from south.v2 import SchemaMigration +from django.db import models + + +class Migration(SchemaMigration): + +    def forwards(self, orm): +        # Adding model 'DocumentTemplate' +        db.create_table('ishtar_common_documenttemplate', ( +            ('id', self.gf('django.db.models.fields.AutoField')(primary_key=True)), +            ('name', self.gf('django.db.models.fields.CharField')(max_length=100)), +            ('template', self.gf('django.db.models.fields.files.FileField')(max_length=100)), +            ('associated_object_name', self.gf('django.db.models.fields.CharField')(max_length=100)), +            ('available', self.gf('django.db.models.fields.BooleanField')(default=True)), +        )) +        db.send_create_signal('ishtar_common', ['DocumentTemplate']) + + +    def backwards(self, orm): +        # Deleting model 'DocumentTemplate' +        db.delete_table('ishtar_common_documenttemplate') + + +    models = { +        'auth.group': { +            'Meta': {'object_name': 'Group'}, +            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), +            'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '80'}), +            'permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'}) +        }, +        'auth.permission': { +            'Meta': {'ordering': "('content_type__app_label', 'content_type__model', 'codename')", 'unique_together': "(('content_type', 'codename'),)", 'object_name': 'Permission'}, +            'codename': ('django.db.models.fields.CharField', [], {'max_length': '100'}), +            'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['contenttypes.ContentType']"}), +            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), +            'name': ('django.db.models.fields.CharField', [], {'max_length': '50'}) +        }, +        'auth.user': { +            'Meta': {'object_name': 'User'}, +            'date_joined': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}), +            'email': ('django.db.models.fields.EmailField', [], {'max_length': '75', 'blank': 'True'}), +            'first_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}), +            'groups': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Group']", 'symmetrical': 'False', 'blank': 'True'}), +            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), +            'is_active': ('django.db.models.fields.BooleanField', [], {'default': 'True'}), +            'is_staff': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), +            'is_superuser': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), +            'last_login': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}), +            'last_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}), +            'password': ('django.db.models.fields.CharField', [], {'max_length': '128'}), +            'user_permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'}), +            'username': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '30'}) +        }, +        'contenttypes.contenttype': { +            'Meta': {'ordering': "('name',)", 'unique_together': "(('app_label', 'model'),)", 'object_name': 'ContentType', 'db_table': "'django_content_type'"}, +            'app_label': ('django.db.models.fields.CharField', [], {'max_length': '100'}), +            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), +            'model': ('django.db.models.fields.CharField', [], {'max_length': '100'}), +            'name': ('django.db.models.fields.CharField', [], {'max_length': '100'}) +        }, +        'ishtar_common.arrondissement': { +            'Meta': {'object_name': 'Arrondissement'}, +            'department': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['ishtar_common.Department']"}), +            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), +            'name': ('django.db.models.fields.CharField', [], {'max_length': '30'}) +        }, +        'ishtar_common.author': { +            'Meta': {'object_name': 'Author'}, +            'author_type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['ishtar_common.AuthorType']"}), +            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), +            'person': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'author'", 'to': "orm['ishtar_common.Person']"}) +        }, +        'ishtar_common.authortype': { +            'Meta': {'object_name': 'AuthorType'}, +            'available': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), +            'comment': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}), +            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), +            'label': ('django.db.models.fields.CharField', [], {'max_length': '100'}), +            'txt_idx': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '30'}) +        }, +        'ishtar_common.canton': { +            'Meta': {'object_name': 'Canton'}, +            'arrondissement': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['ishtar_common.Arrondissement']"}), +            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), +            'name': ('django.db.models.fields.CharField', [], {'max_length': '30'}) +        }, +        'ishtar_common.department': { +            'Meta': {'ordering': "['number']", 'object_name': 'Department'}, +            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), +            'label': ('django.db.models.fields.CharField', [], {'max_length': '30'}), +            'number': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '3'}) +        }, +        'ishtar_common.documenttemplate': { +            'Meta': {'ordering': "['associated_object_name']", 'object_name': 'DocumentTemplate'}, +            'associated_object_name': ('django.db.models.fields.CharField', [], {'max_length': '100'}), +            'available': ('django.db.models.fields.BooleanField', [], {'default': 'True'}), +            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), +            'name': ('django.db.models.fields.CharField', [], {'max_length': '100'}), +            'template': ('django.db.models.fields.files.FileField', [], {'max_length': '100'}) +        }, +        'ishtar_common.historicalorganization': { +            'Meta': {'ordering': "('-history_date', '-history_id')", 'object_name': 'HistoricalOrganization'}, +            'address': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}), +            'address_complement': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}), +            'country': ('django.db.models.fields.CharField', [], {'max_length': '30', 'null': 'True', 'blank': 'True'}), +            'history_date': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}), +            'history_id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), +            'history_modifier_id': ('django.db.models.fields.IntegerField', [], {'db_index': 'True', 'null': 'True', 'blank': 'True'}), +            'history_type': ('django.db.models.fields.CharField', [], {'max_length': '1'}), +            'history_user': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.User']", 'null': 'True'}), +            'id': ('django.db.models.fields.IntegerField', [], {'db_index': 'True', 'blank': 'True'}), +            'mobile_phone': ('django.db.models.fields.CharField', [], {'max_length': '18', 'null': 'True', 'blank': 'True'}), +            'name': ('django.db.models.fields.CharField', [], {'max_length': '100'}), +            'organization_type_id': ('django.db.models.fields.IntegerField', [], {'db_index': 'True', 'null': 'True', 'blank': 'True'}), +            'phone': ('django.db.models.fields.CharField', [], {'max_length': '18', 'null': 'True', 'blank': 'True'}), +            'postal_code': ('django.db.models.fields.CharField', [], {'max_length': '10', 'null': 'True', 'blank': 'True'}), +            'town': ('django.db.models.fields.CharField', [], {'max_length': '30', 'null': 'True', 'blank': 'True'}) +        }, +        'ishtar_common.ishtaruser': { +            'Meta': {'object_name': 'IshtarUser', '_ormbases': ['auth.User']}, +            'person': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'ishtaruser'", 'unique': 'True', 'to': "orm['ishtar_common.Person']"}), +            'user_ptr': ('django.db.models.fields.related.OneToOneField', [], {'to': "orm['auth.User']", 'unique': 'True', 'primary_key': 'True'}) +        }, +        'ishtar_common.organization': { +            'Meta': {'object_name': 'Organization'}, +            'address': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}), +            'address_complement': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}), +            'country': ('django.db.models.fields.CharField', [], {'max_length': '30', 'null': 'True', 'blank': 'True'}), +            'history_modifier': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'+'", 'to': "orm['auth.User']"}), +            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), +            'mobile_phone': ('django.db.models.fields.CharField', [], {'max_length': '18', 'null': 'True', 'blank': 'True'}), +            'name': ('django.db.models.fields.CharField', [], {'max_length': '100'}), +            'organization_type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['ishtar_common.OrganizationType']"}), +            'phone': ('django.db.models.fields.CharField', [], {'max_length': '18', 'null': 'True', 'blank': 'True'}), +            'postal_code': ('django.db.models.fields.CharField', [], {'max_length': '10', 'null': 'True', 'blank': 'True'}), +            'town': ('django.db.models.fields.CharField', [], {'max_length': '30', 'null': 'True', 'blank': 'True'}) +        }, +        'ishtar_common.organizationtype': { +            'Meta': {'ordering': "('label',)", 'object_name': 'OrganizationType'}, +            'available': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), +            'comment': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}), +            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), +            'label': ('django.db.models.fields.CharField', [], {'max_length': '100'}), +            'txt_idx': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '30'}) +        }, +        'ishtar_common.person': { +            'Meta': {'object_name': 'Person'}, +            'address': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}), +            'address_complement': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}), +            'attached_to': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['ishtar_common.Organization']", 'null': 'True', 'blank': 'True'}), +            'country': ('django.db.models.fields.CharField', [], {'max_length': '30', 'null': 'True', 'blank': 'True'}), +            'email': ('django.db.models.fields.CharField', [], {'max_length': '40', 'null': 'True', 'blank': 'True'}), +            'history_modifier': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'+'", 'to': "orm['auth.User']"}), +            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), +            'mobile_phone': ('django.db.models.fields.CharField', [], {'max_length': '18', 'null': 'True', 'blank': 'True'}), +            'name': ('django.db.models.fields.CharField', [], {'max_length': '30'}), +            'person_types': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['ishtar_common.PersonType']", 'symmetrical': 'False'}), +            'phone': ('django.db.models.fields.CharField', [], {'max_length': '18', 'null': 'True', 'blank': 'True'}), +            'postal_code': ('django.db.models.fields.CharField', [], {'max_length': '10', 'null': 'True', 'blank': 'True'}), +            'surname': ('django.db.models.fields.CharField', [], {'max_length': '20', 'null': 'True', 'blank': 'True'}), +            'title': ('django.db.models.fields.CharField', [], {'max_length': '2'}), +            'town': ('django.db.models.fields.CharField', [], {'max_length': '30', 'null': 'True', 'blank': 'True'}) +        }, +        'ishtar_common.persontype': { +            'Meta': {'ordering': "('label',)", 'object_name': 'PersonType'}, +            'available': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), +            'comment': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}), +            'groups': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Group']", 'symmetrical': 'False'}), +            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), +            'label': ('django.db.models.fields.CharField', [], {'max_length': '100'}), +            'txt_idx': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '30'}) +        }, +        'ishtar_common.sourcetype': { +            'Meta': {'object_name': 'SourceType'}, +            'available': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), +            'comment': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}), +            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), +            'label': ('django.db.models.fields.CharField', [], {'max_length': '100'}), +            'txt_idx': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '30'}) +        }, +        'ishtar_common.town': { +            'Meta': {'ordering': "['numero_insee']", 'object_name': 'Town'}, +            'canton': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['ishtar_common.Canton']", 'null': 'True', 'blank': 'True'}), +            'center': ('django.contrib.gis.db.models.fields.PointField', [], {'srid': '27572', 'null': 'True', 'blank': 'True'}), +            'departement': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['ishtar_common.Department']", 'null': 'True', 'blank': 'True'}), +            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), +            'name': ('django.db.models.fields.CharField', [], {'max_length': '100'}), +            'numero_insee': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '6'}), +            'surface': ('django.db.models.fields.IntegerField', [], {'null': 'True', 'blank': 'True'}) +        }, +        'ishtar_common.wizard': { +            'Meta': {'ordering': "['url_name']", 'object_name': 'Wizard'}, +            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), +            'url_name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '128'}) +        }, +        'ishtar_common.wizardstep': { +            'Meta': {'ordering': "['wizard', 'order']", 'object_name': 'WizardStep'}, +            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), +            'name': ('django.db.models.fields.CharField', [], {'max_length': '128'}), +            'order': ('django.db.models.fields.IntegerField', [], {}), +            'url_name': ('django.db.models.fields.CharField', [], {'max_length': '128'}), +            'wizard': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['ishtar_common.Wizard']"}) +        } +    } + +    complete_apps = ['ishtar_common']
\ No newline at end of file diff --git a/ishtar_common/models.py b/ishtar_common/models.py index 89fbd1589..8d153f120 100644 --- a/ishtar_common/models.py +++ b/ishtar_common/models.py @@ -24,6 +24,7 @@ from cStringIO import StringIO  import datetime  from PIL import Image  import os +import tempfile  from django.conf import settings  from django.core.exceptions import ObjectDoesNotExist, ValidationError @@ -43,6 +44,8 @@ from django.contrib import admin  from simple_history.models import HistoricalRecords as BaseHistoricalRecords +from ooo_replace import ooo_replace +  def post_save_user(sender, **kwargs):      user = kwargs['instance']      ishtaruser = None @@ -57,6 +60,22 @@ def post_save_user(sender, **kwargs):                                                     txt_idx='administrator'))  post_save.connect(post_save_user, sender=User) +class ValueGetter(object): +    _prefix = "" +    def get_values(self, prefix=''): +        if not prefix: +            prefix = self._prefix +        values = {} +        for field_name in self._meta.get_all_field_names(): +            if not hasattr(self, field_name): +                continue +            value = getattr(self, field_name) +            if hasattr(value, 'get_values'): +                values.update(value.get_values(prefix + field_name + '_')) +            else: +                values[prefix + field_name] = value +        return values +  class HistoricalRecords(BaseHistoricalRecords):      def create_historical_record(self, instance, type):          history_modifier = getattr(instance, 'history_modifier', None) @@ -592,6 +611,41 @@ class Dashboard:              if vals[v] == mx:                  return v +class DocumentTemplate(models.Model): +    CLASSNAMES = (('archaeological_operations.models.AdministrativeAct', +                  _(u"Administrative Act")),) +    name = models.CharField(_(u"Name"), max_length=100) +    template = models.FileField(_(u"Template"), upload_to="upload/templates/") +    associated_object_name = models.CharField(_(u"Associated object"), +                                             max_length=100, choices=CLASSNAMES) +    available = models.BooleanField(_(u"Available"), default=True) + +    class Meta: +        verbose_name = _(u"Document template") +        verbose_name_plural = _(u"Document templates") +        ordering = ['associated_object_name'] + +    def __unicode__(self): +        return self.name + +    @classmethod +    def get_tuples(cls, dct={}, empty_first=True): +        dct['available'] = True +        if empty_first: +            yield ('', '--') +        items = cls.objects.filter(**dct) +        for item in items.order_by(*cls._meta.ordering).all(): +            yield (item.pk, _(unicode(item))) + +    def publish(self, c_object): +        tempdir = tempfile.mkdtemp("-ishtardocs") +        output_name = tempdir + os.path.sep + \ +            self.name.replace(' ', '_').lower() + u'-' +\ +            datetime.date.today().strftime('%Y-%m-%d') +\ +            u"." + self.template.name.split('.')[-1] +        missing = ooo_replace(self.template, output_name, c_object.get_values()) +        return output_name +  class Department(models.Model):      label = models.CharField(_(u"Label"), max_length=30)      number = models.CharField(_(u"Number"), unique=True, max_length=3) @@ -654,7 +708,8 @@ class PersonType(GeneralType):          verbose_name_plural = _(u"Person types")          ordering = ('label',) -class Person(Address, OwnPerms) : +class Person(Address, OwnPerms, ValueGetter) : +    _prefix = 'person_'      TYPE = (('Mr', _(u'Mr')),              ('Ms', _(u'Miss')),              ('Md', _(u'Mrs')), diff --git a/ishtar_common/ooo_replace.py b/ishtar_common/ooo_replace.py new file mode 100644 index 000000000..63b983b7b --- /dev/null +++ b/ishtar_common/ooo_replace.py @@ -0,0 +1,102 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- +# Copyright (C) 2013 É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 +# published by the Free Software Foundation, either version 3 of the +# License, or (at your option) any later version. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the +# GNU Affero General Public License for more details. + +# You should have received a copy of the GNU Affero General Public License +# along with this program.  If not, see <http://www.gnu.org/licenses/>. + +# See the file COPYING for details. + + +from zipfile import ZipFile, ZIP_DEFLATED +from cStringIO import StringIO +from xml.etree.cElementTree import ElementTree, fromstring + +OOO_NS = "{urn:oasis:names:tc:opendocument:xmlns:text:1.0}" + +def _set_value_from_formula(value, context): +    value = value.strip() +    if value.startswith("ooow:") and len(value) >= 5: +        value = value[5:] +    if value.startswith('"') and value.endswith('"') and len(value) > 1: +        value = value[1:-1] +    elif value in context: +        value = unicode(context[value]) +    else: +        value = None +    return value + +def _parse_condition(condition, context): +    # parse only == and != operator +    operator = "" +    if "!=" in condition: +        operator = "!=" +    elif "==" in condition: +        operator = "==" +    else: +        return +    var1, var2 = condition.split(operator) +    var1 = _set_value_from_formula(var1, context) +    var2 = _set_value_from_formula(var2, context) +    res = var1 == var2 +    if operator == '!=': +        res = not res +    return res + +def _format_value(value, default_value): +    value = unicode(value) if value else default_value +    #if hasattr(value, 'strftime'): +    #    value = value.strftime() +    return value + +def ooo_replace(infile, outfile, context, default_value=''): +    inzip = ZipFile(infile, 'r', ZIP_DEFLATED) +    outzip = ZipFile(outfile, 'w', ZIP_DEFLATED) +    content = ElementTree(fromstring(inzip.read('content.xml'))) +    missing_keys = set() +    for xp in ('variable-set', 'variable-get'): +        for p in content.findall(".//"+OOO_NS+xp): +            name = p.get(OOO_NS+"name") +            if name in context: +                value = context[name] +                p.text = _format_value(value, default_value) +            else: +                if default_value != None: +                    p.text = default_value +                missing_keys.add(name) +    for p in content.findall(".//"+OOO_NS+"conditional-text"): +        condition = p.get(OOO_NS+"condition") +        res = 'true' if _parse_condition(condition, context) else 'false' +        value = p.get(OOO_NS+'string-value-if-' + res) +        value = _format_value(value, default_value) +        if value.strip() in context: +            value = context[value.strip()] +        p.text = value +    for f in inzip.infolist(): +        if f.filename == 'content.xml': +            s = StringIO() +            content.write(s) +            outzip.writestr('content.xml', s.getvalue()) +        else: +            outzip.writestr(f, inzip.read(f.filename)) +    inzip.close() +    outzip.close() +    return missing_keys + +if __name__ == '__main__': +    infile = "../archaeological_files/tests/AR_dossier_DRAC_modele_ishtar_1-MOD.odt" +    outfile = "../archaeological_files/tests/AR_dossier_DRAC_modele_ishtar-test.odt" +    rep = {"file_incharge_surname":u"Yann", +           "file_incharge_name":u"Le Jeune", +           "fileact_ref":u"ref"} +    ooo_replace(infile, outfile, rep, default_value="") diff --git a/ishtar_common/templates/ishtar/wizard/wizard_list_search_result.html b/ishtar_common/templates/ishtar/wizard/wizard_list_search_result.html index c6be97b64..aca1798d9 100644 --- a/ishtar_common/templates/ishtar/wizard/wizard_list_search_result.html +++ b/ishtar_common/templates/ishtar/wizard/wizard_list_search_result.html @@ -3,7 +3,7 @@  {% block content %}  <div class='form'> -  <p>{% trans {%trans "PLease note that the file must be processed before :"%} %} {% calculated_deadline %}  </p> +  <p>{% trans {%trans "Please note that the file must be processed before :"%} %} {% calculated_deadline %}  </p>    <p>{% trans {%trans "Item successfully saved"%} %}</p>	    <p>{% trans "You have saved the following informations:" %}</p> diff --git a/ishtar_common/views.py b/ishtar_common/views.py index 46ea938de..31f5f688b 100644 --- a/ishtar_common/views.py +++ b/ishtar_common/views.py @@ -608,9 +608,6 @@ def action(request, action_slug, obj_id=None, *args, **kwargs):      globals_dct = globals()      if action_slug in globals_dct:          return globals_dct[action_slug](request, dct, obj_id, *args, **kwargs) -    elif hasattr(ishtar_forms, action_slug + "_wizard"): -        return getattr(ishtar_forms, action_slug+"_wizard")(request, *args, -                                                            **kwargs)      return render_to_response('index.html', dct,                                context_instance=RequestContext(request)) | 
