This repository has been archived on 2023-02-21. You can view files and clone it, but cannot push or open issues or pull requests.
polynum/polynum/request/views.py

793 lines
34 KiB
Python

# -*- coding: utf-8 -*-
import datetime
import os.path
import json
import csv
from django.core.urlresolvers import reverse
from django.conf import settings
from django.shortcuts import redirect, get_object_or_404, render
from django.contrib.formtools.wizard.views import NamedUrlSessionWizardView
from django.core.files.storage import FileSystemStorage
from django.contrib.auth.decorators import login_required
from django.views.decorators.csrf import csrf_exempt
from django.views.generic.detail import SingleObjectMixin, DetailView
from django.views.generic.list import ListView
from django.db import transaction
from django.db.models import Q
from django.contrib.formtools.wizard.storage.session import SessionStorage
from django.utils.translation import ugettext_lazy as _
from django.http import Http404, HttpResponse, HttpResponseRedirect, HttpResponseBadRequest
from django.utils.http import urlencode, urlquote
from django.utils.timezone import now
from django.contrib import messages
from django.utils.safestring import mark_safe
from django.utils.datastructures import SortedDict
from django.contrib.formtools.wizard.forms import ManagementForm
from django.contrib.auth.models import User
from ..base.models import (Request, Transition, Entity, Status,
DocumentLicence)
from ..base.models.request import get_default_status
from ..base.rbac import get_workable_requests, get_workflows, get_entity_filter
from ..utils import sort_by_frequency
from forms import DocumentUploadForm, DocumentDetailsForm, ReproDetailsForm, \
DeliveryForm, CopyrigtsForm, ValidationForm, ReproOriginForm, \
FinancialForm, CostForm
import app_settings
from utils import field_completion
import models
import utils
named_new_request_forms = (
('document_upload', DocumentUploadForm),
('document_details', DocumentDetailsForm),
('repro_origin', ReproOriginForm),
('reprography', ReproDetailsForm),
('delivery', DeliveryForm),
('document_copyrights', CopyrigtsForm),
('financial_information', FinancialForm),
('real_cost', CostForm),
('validation', ValidationForm),
)
class DummyStorage(SessionStorage):
def set_step_files(self, step, files):
super(DummyStorage, self).set_step_files(step, {})
def get_step_files(self, step):
return None
class RequestWizardView(NamedUrlSessionWizardView, SingleObjectMixin):
model = Request
template_name = 'new_request.html'
file_storage = FileSystemStorage(location = os.path.join(settings.MEDIA_ROOT, 'temporary-uploads'))
storage_name = 'polynum.request.views.DummyStorage'
def dispatch(self, request, *args, **kwargs):
self.kwargs = kwargs
self.object = self.get_object() # cache the current object
return super(RequestWizardView, self).dispatch(request, *args, **kwargs)
def get_template_names(self):
return ['%s.%s' % (self.steps.current, self.template_name), self.template_name]
def done(self, form_list, **kwargs):
ctx = self.get_context_data(form_list[0], **kwargs)
if ctx.get('validated'):
instance = self.object
instance.status = get_default_status()
instance.save()
return redirect('list_request')
for step, form, missings in ctx['all_forms']:
if missings:
return redirect(self.get_step_url(step=step))
raise NotImplemented
def get_frequent_financial_codes(self, user):
frequent_codes = list(Request.objects.filter(
Q(user=user)|Q(history__user=user)) \
.order_by('-creation_date') \
.distinct()[:15] \
.values_list('financial_code', flat=True))
instance = self.object
codes = instance.entity.accounting_codes().values_list('code', flat=True)
frequent_codes.extend(codes)
return map(lambda x: (x,x), sort_by_frequency(filter(None, frequent_codes)))
def get_frequent_entities(self, user):
return sort_by_frequency(filter(lambda x: x[1] is not None, list(Request.objects.filter(
Q(user=user)|Q(history__user=user))
.order_by('-creation_date')
.distinct()[:15]
.select_related('entity')
.values_list('entity__name', 'entity__id'))
+ list(Entity.objects.filter(
code__in=user.get_preferred_entities())
.values_list('name', 'id'))))
def get_form_kwargs(self, step):
kwargs = super(RequestWizardView, self).get_form_kwargs(self)
if step == 'financial_information':
kwargs['frequent_financial_codes'] = self.get_frequent_financial_codes(
self.request.user)
if step == 'repro_origin':
kwargs['frequent_entities'] = self.get_frequent_entities(
self.request.user)
return kwargs
def get_context_data(self, form, **kwargs):
'''
Add all_forms = list of (step, form, pprint_data), where pprint_data is
a list of (name, value) created by each form, representing a "nice"
view of the stored datas
'''
context = super(RequestWizardView, self).get_context_data(form=form, **kwargs)
# cleaned_data = self.get_all_cleaned_data() or {}
all_forms = []
validated = True
for step, form in self.get_form_list().items():
form_instance = self.get_form(step=step)
pprint_data = form_instance.pprint_data({})
if pprint_data:
missings = [ l[0] for l in pprint_data if len(l) > 2 and l[2]]
else:
missings = []
validated = validated and not bool(missings)
all_forms += [ (step, form, pprint_data, missings) ]
context['all_forms'] = all_forms
context['validated'] = validated
context['object'] = self.object
context['workflows'] = get_workflows(self.request.user, context['object']) \
.exclude(action__special_type='edit').filter(action__validate_request__lte=validated).order_by('-warn', 'default')
context['roots'] = [(e.pk, e.get_description().strip(), e.code) for e in
Entity.objects.filter(depth=app_settings.ENTITY_ROOTS_DEPTH,
is_active=True)]
return context
def get_prefix(self, *args, **kwargs):
prefix = super(RequestWizardView, self).get_prefix(*args, **kwargs)
prefix += '_%s' % kwargs.get('pk', '')
return prefix
def get_form_instance(self, step):
return self.object
def get_step_url(self, step):
return reverse(self.url_name, kwargs={self.pk_url_kwarg: self.object.pk, 'step': step})
def render_next_step(self, form, **kwargs):
if hasattr(form, 'cleaned_data') and hasattr(form, 'save') and form.is_valid():
form.save()
if hasattr(form, 'save_m2m'):
form.save_m2m()
# special case when coming from the validation page
if 'correction' in self.request.GET:
return redirect(self.get_step_url('validation'))
pprint_data = form.pprint_data({})
# do not apply when going to the validation page, that's useless
if any([x[2] for x in pprint_data]) and self.steps.next != 'validation':
field_names = [x[0] for x in pprint_data if x[2]]
messages.warning(self.request,
_(u"Vous n'avez pas remplis les champs obligatoires suivants: "
u"%s. Vous pouvez tout de même continuer à remplir votre demande, "
u"et aussi la sauver comme brouillon. Mais vous ne pourrez pas "
u"la soumettre tant que ces champs ne seront pas remplis")
% ', '.join(map(unicode, field_names)))
return super(RequestWizardView, self).render_next_step(form, **kwargs)
def get_form_list(self):
transitions = get_workflows(self.request.user, self.object) \
.select_related().filter(action__special_type='edit')
pages = reduce(set.__or__, [set(transition.action.edit_pages()) for transition in transitions], set())
return SortedDict([
(key,value) for key, value in super(RequestWizardView, self).get_form_list().iteritems()
if key in pages or key == 'validation'])
@transaction.commit_on_success
def post(self, *args, **kwargs):
"""
Surcharge de NamedUrlSessionWizardView.post pour enregistrer le
"""
wizard_goto_step = self.request.POST.get('wizard_goto_step', None)
delete = 'delete-uploadfile' in self.request.POST
if delete or (wizard_goto_step and wizard_goto_step in self.get_form_list()):
# Check if form was refreshed
management_form = ManagementForm(self.request.POST, prefix=self.prefix)
if not management_form.is_valid():
messages.error(self.request, _(u'Une erreur a eu lieu, veuillez réessayer.'))
return redirect(self.get_step_url(self.steps.current))
form_current_step = management_form.cleaned_data['current_step']
if (form_current_step != self.steps.current and
self.storage.current_step is not None):
# form refreshed, change current step
self.storage.current_step = form_current_step
if delete:
request = self.object
if not request.is_paper():
request.uploadfile.delete()
request.uploadfile = None
request.save()
return redirect(self.get_step_url(form_current_step))
# get the form for the current step
form = self.get_form(data=self.request.POST, files=self.request.FILES)
# and try to validate
if form.is_valid():
# if the form is valid, store the cleaned data and files.
self.storage.set_step_data(self.steps.current, self.process_step(form))
self.storage.set_step_files(self.steps.current, self.process_step_files(form))
if hasattr(form, 'save'):
form.save()
if hasattr(form, 'save_m2m'):
form.save_m2m()
self.storage.current_step = wizard_goto_step
return redirect(self.get_step_url(wizard_goto_step))
return super(RequestWizardView, self).post(*args, **kwargs)
def render(self, form=None, **kwargs):
from django.forms.models import model_to_dict
if self.steps.current == 'document_copyrights' and self.object:
message = None
if self.object.usage and self.object.usage.no_diffusion:
message = _(u"L'usage « {0} » n'autorisant pas la diffusion, "
u"l'étape « Options de diffusion » a donc été automatiquement sautée.").format(self.object.usage)
if self.object.is_from_remote_request:
message = _(u"La requête venant d'une plate-forme distante, "
u"l'étape « Options de diffusion » a donc été automatiquement sautée.").format(self.object.usage)
if self.object.is_paper():
message = _(u"La requête ne comportant pas de fichier, "
u"l'étape « Options de diffusion » a donc été automatiquement sautée.").format(self.object.usage)
if message:
messages.info(self.request, message)
return self.render_next_step(form, **kwargs)
if hasattr(form, 'instance') and form.instance and not form.is_bound and kwargs.get('step') != 'document_copyrights':
data = dict(((form.prefix+'-'+k,v) for k,v in model_to_dict(form.instance).iteritems()))
for choice in form.instance.choices.all().select_related():
data[form.add_prefix('profile_option_%s' % choice.option.id)] =\
unicode(choice.id)
form = self.get_form(data=data)
form.full_clean()
return super(RequestWizardView, self).render(form=form, **kwargs)
class RequestDetails(DetailView):
model = Request
template_name = 'request_detail.html'
context_object_name = 'poly_request'
queryset = Request.objects.select_related().prefetch_related('choices', 'base_profile__choices')
def get_context_data(self, **kwargs):
ctx = super(RequestDetails, self).get_context_data(**kwargs)
request = self.get_object()
ctx['docname'] = request.name
if not request.is_paper():
ctx['filename'] = os.path.basename(request.uploadfile.name)
if not ctx['docname']:
ctx['docname'] = ctx['filename']
ctx['creation'] = request.history_set.start()
ctx['end'] = request.history_set.end()
# Let only one edit transition be displayed
transitions = []
already_one_edit_transition = False
t1 = get_workflows(self.request.user, request) \
.filter(action__validate_request__lte=request.validate(),
show_on_detail=True).order_by('action__id')
# FIXME in Django 1.6
if t1:
t1 = t1.distinct('action', 'destination')
t2 = Transition.objects.filter(id__in=t1) \
.order_by('-warn', 'default')
for transition in t2:
if transition.action.special_type == 'edit':
if already_one_edit_transition:
continue
already_one_edit_transition = True
transitions.append(transition)
ctx['workflows'] = transitions
ctx['use_pdf_viewer'] = app_settings.USE_PDF_VIEWER
ctx['entities'] = []
if request.entity is not None:
def entity_parent(x, kind):
return getattr(x.entity.parent_of_type(kind), 'description', None)
for caption, ref in app_settings.ENTITY_TYPE_TO_SHOW:
what = entity_parent(request, ref)
if what is None or what == request.entity:
continue
ctx['entities'].append((caption, what))
return ctx
class RequestHistory(DetailView):
model = Request
template_name = 'request_history.html'
context_object_name = 'poly_request'
@login_required
@transaction.commit_on_success
def new_request(request):
try:
default_licence = DocumentLicence.objects.get(default=True)
except (DocumentLicence.DoesNotExist, DocumentLicence.MultipleObjectsReturned):
default_licence = None
request = Request.objects.create(
user=request.user,
status=get_default_status(),
contact_email=getattr(request.user, 'email', ''),
contact_telephone1=getattr(request.user, 'telephoneNumber', ''),
contact_telephone2=getattr(request.user, 'supannAutreTelephone', ''),
contact_bureau=getattr(request.user, 'roomNumber', ''),
sponsor=u'%(first_name)s %(last_name)s (%(username)s)' % request.user._wrapped.__dict__,
licence=default_licence,
)
return redirect('request_wizard', pk=request.pk)
@transaction.commit_on_success
def request_delete(request, pk):
instance = get_object_or_404(Request, pk=pk)
instance.delete()
return redirect('list_request')
request_wizard_step = login_required(RequestWizardView.as_view(named_new_request_forms,
done_step_name='finished', url_name='request_wizard_step'))
def upload(request, attached_file):
response = HttpResponse(attached_file.chunks(), mimetype='application/octet-stream')
filename = urlquote(
os.path.basename(attached_file.name).encode('utf-8'))
response['Content-disposition'] = "attachment; filename*=UTF-8''%s" % filename
return response
def request_download(request, pk):
instance = get_object_or_404(Request, pk=pk)
if not instance.uploadfile.name:
raise Http404
return upload(request, instance.uploadfile)
@transaction.commit_on_success
def request_action(request, pk, workflow_pk):
poly_request = get_object_or_404(Request, pk=pk)
try:
workflow = get_workflows(request.user, poly_request).get(pk=workflow_pk)
except Transition.DoesNotExist:
transition = get_object_or_404(Transition, pk=workflow_pk)
message = _(u"L'action « {0} » n'est pas autorisée sur la demande {1}.") \
.format(transition.action.name,
poly_request.request_number())
messages.error(request, message)
if get_workable_requests(request.user).filter(pk=pk).exists():
return redirect('request_detail', pk=pk)
else:
return redirect('list_request')
if workflow.comment and not request.POST.get('comment'):
return render(request, 'request_action.html', locals())
poly_request.act(request.user, workflow, description=request.POST.get('comment'))
if workflow.action.ui_message:
messages.info(request, mark_safe(workflow.action.ui_message))
if workflow.is_edit:
return redirect('request_wizard', pk=pk)
elif workflow.is_delete:
return redirect('request_delete', pk=pk)
elif workflow.is_duplicate:
return redirect('request_duplicate', pk=pk)
return redirect('request_detail', pk=pk)
@transaction.commit_on_success
def request_duplicate(request, pk):
from django.core.files.base import ContentFile
poly_request = get_object_or_404(Request, pk=pk)
new_poly_request = get_object_or_404(Request, pk=pk)
new_poly_request.pk = None
new_poly_request.creation_date = now()
new_poly_request.month_order = -1
new_poly_request.status = get_default_status()
if poly_request.uploadfile:
content = ContentFile(poly_request.uploadfile.read())
filename = os.path.split(poly_request.uploadfile.name)[-1]
new_poly_request.uploadfile.save(filename, content)
poly_request.uploadfile.close()
new_poly_request.save()
new_poly_request.choices = poly_request.choices.all()
return redirect('request_wizard', pk=new_poly_request.pk)
class ListRequest(ListView):
template_name = 'list_request.html'
model = Request
paginate_by = app_settings.PAGINATE_BY
context_object_name = 'requests'
def dispatch(self, request, *args, **kwargs):
self.request = request
self.filters = []
self.filter_choices = []
self.sort = request.GET.get('sort')
self.handle_filter_status()
self.handle_search_filter()
self.handle_entity_filter()
self.handle_date_filter()
self.handle_licence_filter()
self.handle_free_text_filter()
return super(ListRequest, self).dispatch(request, *args, **kwargs)
def post(self, request, *args, **kwargs):
params = {}
if 'from_date' in request.POST:
params['from_date'] = request.POST['from_date']
if 'to_date' in request.POST:
params['to_date'] = request.POST['to_date']
return HttpResponseRedirect(self.qs(**params))
def get_queryset(self, without_filter=()):
qs = super(ListRequest, self).get_queryset()
qs = get_workable_requests(self.request.user)
# apply filters
qs = qs.filter(status__visible=True)
for filter_name, value, display_list in self.filters:
if filter_name in without_filter:
continue
apply_filter = 'apply_filter_%s' % filter_name
if hasattr(self, apply_filter):
qs = getattr(self, apply_filter)(qs, value)
else:
qs = qs.filter(**{filter_name: value})
# apply ordering
if self.sort:
qs = qs.order_by(self.sort)
qs = qs.prefetch_related('choices').select_related('base_profile', 'user', 'entity', 'status')
return qs
def handle_filter_status(self):
current = self.request.GET.get('filter_status')
choices = []
if current:
display = Status.objects.get(id=current).name
self.filters.append(('status', current, [(display, self.qs(**{'status': None}))]))
choices = Status.objects \
.filter(request__in=self.get_queryset(without_filter=('status',))) \
.distinct().values_list('id', 'name')
choices = [
(self.qs(**{'status': status}), display)
for status, display in choices
]
if choices:
self.filter_choices.append({
'caption': _(u'Sur le statut'),
'choices': choices })
def handle_search_filter(self):
current = self.request.GET.get('filter_search')
if current:
self.filters.append(('search', current, [_(u'Contient le texte %s') % current,
self.qs(**{'search': None})]))
def apply_filter_search(sefl, qs, value):
q = Q(uploadfile__contains=value) | Q(name__contains=value) \
| Q(user__username__contains=value)
return qs.filter(q)
def handle_entity_filter(self,
min_depth=app_settings.MIN_ENTITY_FILTER_DEPTH,
max_depth=app_settings.MAX_ENTITY_FILTER_DEPTH):
value = self.request.GET.get('filter_entity')
qs = Entity.objects \
.filter(depth__lte=max_depth, depth__gte=min_depth) \
.filter(get_entity_filter(self.request.user))
if False:
request_table = qs.query.join((None, Request._meta.db_table, None, None),
promote=True, always_create=True)
entity_table2 = qs.query.join((request_table, Entity._meta.db_table,
"entity_id", "id"))
qs = qs.extra(where=[
'{0}.left_bound <= {1}.left_bound'.format(
Entity._meta.db_table, entity_table2),
'{0}.right_bound >= {1}.right_bound'.format(
Entity._meta.db_table, entity_table2)])
qs = qs.order_by('name')
by_code = dict([(entity.pk, entity) for entity in qs])
current = None
path = []
if value:
path = value.split(',')
path_entities = []
for entity_code in path:
try:
entity_code = int(entity_code)
except ValueError:
return
entity = by_code.get(entity_code)
if not entity:
return
path_entities.append(entity)
current = path_entities[-1]
display_list = [ (_(u'Composante %s') % path_entities[0].name,
self.qs(**{'entity': None}))]
delete_value = path[0]
for entity in path_entities[1:]:
display_list.append((entity.get_name(),
self.qs(**{'entity': delete_value})))
delete_value = '%s,%s' % (delete_value, entity.pk)
self.filters.append(('entity', current, display_list))
parent = None
if len(path) > 1:
parent = by_code.get(path[-2])
if current:
if current.depth == max_depth or not current.children().exists():
depth = current.depth
path = path[:-1]
else:
depth = current.depth+1
else:
depth = min_depth
path = []
# filter on depth
choices = [entity for entity in by_code.itervalues() if entity.depth==depth]
# filter on parenting
if parent:
choices = [entity for entity in choices if
entity.left_bound>=parent.left_bound and
entity.right_bound<=parent.right_bound]
# create filter choices
choices = sorted(choices, key=lambda entity: entity.get_description().title())
choices = [(self.qs(**{'entity': ','.join(path+[str(entity.pk)])}),
entity.get_description().title()) for entity in choices if entity != current]
if choices:
self.filter_choices.append({
'caption': _('Sur le service ou la composante'),
'choices': choices,
})
def apply_filter_entity(self, qs, value):
return qs.filter(entity__left_bound__gte=value.left_bound,
entity__right_bound__lte=value.right_bound)
def get_filters_field(self, field, caption):
result = {}
result['caption'] = caption
current = self.filters.get(field)
values = self.get_queryset().values_list(field, flat=True).distinct()
if current:
choices = [({field: None}, _('< Tous')), (None, values[0])]
else:
if not values:
return []
choices = [({field: a}, a) for a in values]
choices = [ (self.qs(**a) if a else a, b) for a, b in choices ]
result['choices'] = choices
return [result]
def qs(self, **kwargs):
params = dict()
for k in self.request.GET:
params[k] = self.request.GET[k]
for k,v in kwargs.iteritems():
k = 'filter_%s' % k
if v is None:
params.pop(k, None)
else:
params[k] = v
return '?%s' % urlencode(params)
def handle_date_filter(self):
from_date = self.request.GET.get('filter_from_date')
to_date = self.request.GET.get('filter_to_date')
if from_date:
try:
from_date = datetime.datetime.strptime(from_date, '%Y-%m-%d').date()
except ValueError:
from_date = None
if to_date:
try:
to_date = datetime.datetime.strptime(to_date, '%Y-%m-%d').date()
except ValueError:
to_date = None
display_list = []
if from_date:
display_list.append(
(_(u'À livrer après le %s') % from_date, self.qs(**{'from_date': None})))
if to_date:
display_list.append(
(_(u'À livrer avant le %s') % to_date, self.qs(**{'to_date': None})))
if display_list:
self.filters.append(('date', (from_date, to_date), display_list))
def apply_filter_date(self, qs, value):
from_date, to_date = value
if from_date:
qs = qs.filter(delivery_date__gte=from_date)
if to_date:
qs = qs.filter(delivery_date__lte=to_date)
return qs
def handle_licence_filter(self):
licences = DocumentLicence.objects.all()
choices = [(self.qs(**{'licence': licence.id}), licence.name) for licence in licences]
self.filter_choices.append({
'caption': _('Autorisation de diffusion'),
'choices': choices})
licence = self.request.GET.get('filter_licence')
try:
licence = DocumentLicence.objects.get(id=int(licence))
except (TypeError, ValueError, DocumentLicence.DoesNotExist):
pass
else:
self.filters.append(('licence',
licence, ((_(u'Diffusion: %s') % licence.name,
self.qs(**{'licence': None})),)))
def handle_free_text_filter(self):
text = self.request.GET.get('filter_free_text')
if text:
self.filters.append(('free_text', text,
((_(u'Contenant: %s') % text,
self.qs(**{'free_text': None})),)))
def apply_filter_free_text(self, qs, value):
for elt in value.split():
m = Request.NUMBER_RE.match(elt)
if m:
year, month, month_order = m.groups()
qs = qs.filter(creation_date__year=int(year),
creation_date__month=int(month),
month_order=int(month_order))
continue
m = Request.FINANCIAL_CODE_RE.match(elt)
if m:
financial_code = m.group()
qs = qs.filter(financial_code=financial_code)
continue
qs = qs.filter(Q(entity__description__icontains=elt)
|Q(entity__description_override__icontains=elt)
|Q(entity__code__icontains=elt)
|Q(user__username__icontains=elt)
|Q(user__first_name__icontains=elt)
|Q(user__last_name__icontains=elt)
|Q(user__email__icontains=elt)
|Q(sponsor__icontains=elt)
|Q(name__icontains=elt)
|Q(contact_email__icontains=elt))
return qs
def get_context_data(self, **kwargs):
ctx = super(ListRequest, self).get_context_data(**kwargs)
ctx['sort'] = self.sort
ctx['filters'] = self.filters
ctx['filter_choices'] = self.filter_choices
ctx['total_cost'] = self.get_queryset().total_cost()
ctx['qs'] = self.qs()
ctx['now'] = now().strftime('%Y-%m-%d')
ctx['csv_qs'] = self.qs(**{'csv': 1})
return ctx
class CSVListRequest(ListRequest):
def get(self, request, *args, **kwargs):
response = HttpResponse(content_type="text/csv")
response['Content-disposition'] = 'attachment; filename=listing.csv'
writer = csv.writer(response, delimiter=';')
response.write(u''.encode('utf_8_sig'))
fields = [('Numéro de demande', 'request_number_csv'),
('Commanditaire', 'sponsor_display'),
'name',
'uploadfile',
'nb_pages',
'usage__name',
'licence__name',
'copyright',
'comments',
'sponsor',
('Entité', 'entity__description')]
def loader(kind):
def entity_parent(x):
return getattr(x.entity.parent_of_type(kind), 'description', None)
return entity_parent
for caption, ref in app_settings.ENTITY_TYPE_TO_SHOW:
fields.append((caption.encode('utf-8'), loader(ref)))
fields += [
'copies',
'status__name',
'base_profile__name',
'details',
'delivery_date',
'delivery_place__name',
'comments',
'creation_date',
'modification_date',
'contact_email',
'contact_telephone1',
'contact_telephone2',
'contact_bureau',
'financial_code',
'financial_comment',
'estimated_cost',
'cost' ]
normalized_fields = []
for field in fields:
if isinstance(field, tuple):
caption, ref = field
else:
caption, ref = field, field
if callable(ref):
pass
elif callable(getattr(Request, ref, None)):
ref = getattr(Request, ref)
normalized_fields.append((caption, ref))
# Write headers
writer.writerow([field[0] for field in normalized_fields])
qs = self.get_queryset()
value_fields = [field[1] for field in normalized_fields if not callable(field[1])]
for instance, values in zip(qs, qs.values(*value_fields)):
row = []
for caption, ref in normalized_fields:
if callable(ref):
cell = ref(instance)
else:
cell = values[ref]
if cell is None:
cell = _(u'Aucun(e)')
try:
cell = float(cell)
cell = unicode(cell)
cell = cell.replace('.',',')
except:
pass
# try to fix newlines for excel
cell.replace('\r\n', '\n')
cell.replace('\r', '')
row.append(unicode(cell).encode('utf-8'))
writer.writerow(row)
return response
def autocomplete(request, field_names=('name',)):
completion_data = field_completion(request.user, field_names, without_scores='without_scores' in request.GET)
response = HttpResponse(json.dumps(completion_data), mimetype='application/javascript')
return response
@csrf_exempt
def remote_request(request):
contents = []
entity = None
if 'uploadfile' not in request.FILES:
return HttpResponseBadRequest(u'paramètres invalides', content_type='text/plain')
if 'username' in request.POST and \
not User.objects.filter(username=request.POST['username']).exists():
contents.append(u"l'utilisateur « %s » n'est pas enregistré dans polynum" % request.POST['username'])
if 'entity_hint' in request.POST:
entities = Entity.objects.filter(code=request.POST['entity_hint'].lower())
if entities:
entity = entities[0]
else:
contents.append(u'entité « %s » inconnue' % request.POST['entity_hint'])
else:
entity = None
try:
utils.check_pdf(request.FILES['uploadfile'])
except ValueError, e:
return HttpResponseBadRequest(e.args[0], content_type='text/plain')
request.FILES['uploadfile'].seek(0)
temp_remote_request = models.RemoteRequest.objects.create(
uploadfile=request.FILES['uploadfile'], entity=entity)
response = redirect('finish_remote_request', pk=temp_remote_request.pk)
response['Content-Type'] = 'text/plain'
response.content = u''.join(contents)
return response
@transaction.commit_on_success
def finish_remote_request(request, pk):
temp_remote_request = get_object_or_404(models.RemoteRequest, pk=pk)
document = Request.objects.create(user=request.user,
status=get_default_status(),
entity=temp_remote_request.entity,
is_from_remote_request=True)
document.uploadfile.save(os.path.basename(temp_remote_request.uploadfile.name),
temp_remote_request.uploadfile, save=False)
utils.fill_document_attributes_from_pdf_file(document, document.uploadfile)
document.clean()
document.save()
temp_remote_request.delete()
return redirect('request_wizard', pk=document.pk)