Commit 411467a5 authored by chirac's avatar chirac

Merge branch 'feature_document_templates' into 'dev'

Feature document templates

See merge request federez/re2o!391
parents 1cc5d7bb 31ba9a27
Pipeline #945 failed with stage
......@@ -164,3 +164,17 @@ Collec new statics
```bash
python3 manage.py collectstatic
```
## MR 391: Document templates and subscription vouchers
Re2o can now use templates for generated invoices. To load default templates run
```bash
./install update
```
Be carefull, you need the proper rights to edit a DocumentTemplate.
Re2o now sends subscription voucher when an invoice is controlled. It uses one
of the templates. You also need to set the name of the president of your association
to be set in your settings.
......@@ -611,9 +611,11 @@ class HostMacIpView(generics.ListAPIView):
"""Exposes the associations between hostname, mac address and IPv4 in
order to build the DHCP lease files.
"""
queryset = all_active_interfaces()
serializer_class = serializers.HostMacIpSerializer
def get_queryset(self):
return all_active_interfaces()
# Firewall
......@@ -646,7 +648,7 @@ class DNSZonesView(generics.ListAPIView):
class DNSReverseZonesView(generics.ListAPIView):
"""Exposes the detailed information about each extension (hostnames,
"""Exposes the detailed information about each extension (hostnames,
IPs, DNS records, etc.) in order to build the DNS zone files.
"""
queryset = (machines.IpType.objects.all())
......
......@@ -48,7 +48,7 @@ from re2o.field_permissions import FieldPermissionFormMixin
from re2o.mixins import FormRevMixin
from .models import (
Article, Paiement, Facture, Banque,
CustomInvoice, Vente, CostEstimate
CustomInvoice, Vente, CostEstimate,
)
from .payment_methods import balance
......
......@@ -46,11 +46,14 @@ from django.urls import reverse
from django.shortcuts import redirect
from django.contrib import messages
from preferences.models import CotisationsOption
from machines.models import regen
from re2o.field_permissions import FieldPermissionModelMixin
from re2o.mixins import AclMixin, RevMixin
from cotisations.utils import find_payment_method, send_mail_invoice
from cotisations.utils import (
find_payment_method, send_mail_invoice, send_mail_voucher
)
from cotisations.validators import check_no_balance
......@@ -236,15 +239,35 @@ class Facture(BaseInvoice):
'control': self.can_change_control,
}
self.__original_valid = self.valid
self.__original_control = self.control
def get_subscription(self):
"""Returns every subscription associated with this invoice."""
return Cotisation.objects.filter(
vente__in=self.vente_set.filter(
Q(type_cotisation='All') |
Q(type_cotisation='Adhesion')
)
)
def is_subscription(self):
"""Returns True if this invoice contains at least one subscribtion."""
return bool(self.get_subscription())
def save(self, *args, **kwargs):
super(Facture, self).save(*args, **kwargs)
if not self.__original_valid and self.valid:
send_mail_invoice(self)
if self.is_subscription() \
and not self.__original_control \
and self.control \
and CotisationsOption.get_cached_value('send_voucher_mail'):
send_mail_voucher(self)
def __str__(self):
return str(self.user) + ' ' + str(self.date)
@receiver(post_save, sender=Facture)
def facture_post_save(**kwargs):
"""
......@@ -775,7 +798,7 @@ class Paiement(RevMixin, AclMixin, models.Model):
if payment_method is not None and use_payment_method:
return payment_method.end_payment(invoice, request)
## So make this invoice valid, trigger send mail
# So make this invoice valid, trigger send mail
invoice.valid = True
invoice.save()
......
......@@ -75,7 +75,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
{% if estimate.final_invoice %}
<a href="{% url 'cotisations:edit-custom-invoice' estimate.final_invoice.pk %}"><i style="color: #1ECA18;" class="fa fa-check"></i></a>
{% else %}
<i style="color: #D10115;" class="fa fa-times"></i>'
<i style="color: #D10115;" class="fa fa-times"></i>
{% endif %}
</td>
<td>
......
......@@ -48,7 +48,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
{% trans "Date" as tr_date %}
{% include 'buttons/sort.html' with prefix='cotis' col='date' text=tr_date %}
</th>
<th>
<th>
{% trans "Invoice ID" as tr_invoice_id %}
{% include 'buttons/sort.html' with prefix='cotis' col='id' text=tr_invoice_id %}
</th>
......@@ -63,17 +63,17 @@ with this program; if not, write to the Free Software Foundation, Inc.,
<td>{{ facture.prix_total }}</td>
<td>{{ facture.paiement }}</td>
<td>{{ facture.date }}</td>
<td>{{ facture.id }}</td>
<td>{{ facture.id }}</td>
<td>
{% can_edit facture %}
{% include 'buttons/edit.html' with href='cotisations:edit-facture' id=facture.id %}
{% include 'buttons/edit.html' with href='cotisations:edit-facture' id=facture.id %}
{% acl_else %}
{% trans "Controlled invoice" %}
{% acl_end %}
{% can_delete facture %}
{% include 'buttons/suppr.html' with href='cotisations:del-facture' id=facture.id %}
{% include 'buttons/suppr.html' with href='cotisations:del-facture' id=facture.id %}
{% acl_end %}
{% history_button facture %}
{% history_button facture %}
</td>
<td>
{% if facture.valid %}
......@@ -83,13 +83,18 @@ with this program; if not, write to the Free Software Foundation, Inc.,
{% else %}
<i class="text-danger">{% trans "Invalidated invoice" %}</i>
{% endif %}
{% if facture.control and facture.is_subscription %}
<a class="btn btn-primary btn-sm" role="button" href="{% url 'cotisations:voucher-pdf' facture.id %}">
<i class="fa fa-file-pdf-o"></i> {% trans "Voucher" %}
</a>
{% endif %}
</td>
</tr>
{% endfor %}
</table>
{% if facture_list.paginator %}
{% if facture_list.paginator %}
{% include 'pagination.html' with list=facture_list %}
{% endif %}
{% endif %}
</div>
Bonjour {{name}} !
Nous vous informons que votre cotisation auprès de {{asso_name}} a été acceptée. Vous voilà donc membre de l'association.
Vous trouverez en pièce jointe un reçu.
Pour nous faire part de toute remarque, suggestion ou problème vous pouvez nous envoyer un mail à {{asso_email}}.
À bientôt,
L'équipe de {{asso_name}}.
---
Your subscription to {{asso_name}} has just been accepted. You are now a full member of {{asso_name}}.
You will find with this email a subscription voucher.
For any information, suggestion or problem, you can contact us via email at
{{asso_email}}.
Regards,
The {{asso_name}} team.
{% load i18n %}
{% language 'fr' %}
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% Invoice Template
% LaTeX Template
% Version 1.0 (3/11/12)
%% This template has been downloaded from:
% http://www.LaTeXTemplates.com
%
% Original author:
% Trey Hunner (http://www.treyhunner.com/)
%
% License:
% CC BY-NC-SA 3.0 (http://creativecommons.org/licenses/by-nc-sa/3.0/)
%
% Important note:
% This template requires the invoice.cls file to be in the same directory as
% the .tex file. The invoice.cls file provides the style used for structuring the
% document.
%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%----------------------------------------------------------------------------------------
% DOCUMENT CONFIGURATION
%----------------------------------------------------------------------------------------
\documentclass[12pt]{article} % Use the custom invoice class (invoice.cls)
\usepackage[utf8]{inputenc}
\usepackage[letterpaper,hmargin=0.79in,vmargin=0.79in]{geometry}
\usepackage{longtable}
\usepackage{graphicx}
\usepackage{tabularx}
\usepackage{eurosym}
\usepackage{multicol}
\pagestyle{empty} % No page numbers
\linespread{1.5}
\newcommand{\doublehline}{\noalign{\hrule height 1pt}}
\setlength{\parindent}{0cm}
\begin{document}
%----------------------------------------------------------------------------------------
% HEADING SECTION
%----------------------------------------------------------------------------------------
\begin{center}
{\Huge\bf Reçu d'adhésion \\ {{asso_name|safe}} } % Company providing the invoice
\end{center}
\bigskip
\hrule
\bigskip
\vfill
Je sousigné, {{pres_name|safe}}, déclare par la présente avoir reçu le bulletin d'adhésion de:
\begin{center}
\setlength{\tabcolsep}{10pt} % Make table columns tighter, usefull for postionning
\begin{tabular}{r l r l}
{\bf Prénom :}~ & {{firstname|safe}} & {% if phone %}{\bf Téléphone :}~ & {{phone}}{% else %} & {% endif %} \\
{\bf Nom :}~ & {{lastname|safe}} & {\bf Mail :}~ & {{email|safe}} \\
\end{tabular}
\end{center}
\bigskip
ainsi que sa cotisation.
Le postulant, déclare reconnaître l'objet de l'association, et en a accepté les statuts ainsi que le règlement intérieur qui sont mis à sa disposition dans les locaux de l'association. L'adhésion du membre sus-nommé est ainsi validée. Ce reçu confirme la qualité de membre du postulant, et ouvre droit à la participation à l'assemblée générale de l'association jusqu'au {{date_end|date:"d F Y"}}.
\bigskip
Validé électroniquement par {{pres_name|safe}}, le {{date_begin|date:"d/m/Y"}}.
\vfill
\hrule
\smallskip
\footnotesize
Les informations recueillies sont nécessaires pour votre adhésion. Conformément à la loi "Informatique et Libertés" du 6 janvier 1978, vous disposez d'un droit d'accès et de rectification aux données personnelles vous concernant. Pour l'exercer, adressez-vous au secrétariat de l'association.
\end{document}
{% endlanguage %}
......@@ -31,12 +31,16 @@ from subprocess import Popen, PIPE
import os
from datetime import datetime
from django.db import models
from django.template.loader import get_template
from django.template import Context
from django.http import HttpResponse
from django.conf import settings
from django.utils.text import slugify
import logging
from django.utils.translation import ugettext_lazy as _
from re2o.mixins import AclMixin, RevMixin
from preferences.models import CotisationsOption
TEMP_PREFIX = getattr(settings, 'TEX_TEMP_PREFIX', 'render_tex-')
......@@ -49,6 +53,7 @@ def render_invoice(_request, ctx={}):
Render an invoice using some available information such as the current
date, the user, the articles, the prices, ...
"""
options, _ = CotisationsOption.objects.get_or_create()
is_estimate = ctx.get('is_estimate', False)
filename = '_'.join([
'cost_estimate' if is_estimate else 'invoice',
......@@ -58,7 +63,30 @@ def render_invoice(_request, ctx={}):
str(ctx.get('DATE', datetime.now()).month),
str(ctx.get('DATE', datetime.now()).day),
])
r = render_tex(_request, 'cotisations/factures.tex', ctx)
templatename = options.invoice_template.template.name.split('/')[-1]
r = render_tex(_request, templatename, ctx)
r['Content-Disposition'] = 'attachment; filename="{name}.pdf"'.format(
name=filename
)
return r
def render_voucher(_request, ctx={}):
"""
Render a subscribtion voucher.
"""
options, _ = CotisationsOption.objects.get_or_create()
filename = '_'.join([
'voucher',
slugify(ctx.get('asso_name', "")),
slugify(ctx.get('firstname', "")),
slugify(ctx.get('lastname', "")),
str(ctx.get('date_begin', datetime.now()).year),
str(ctx.get('date_begin', datetime.now()).month),
str(ctx.get('date_begin', datetime.now()).day),
])
templatename = options.voucher_template.template.name.split('/')[-1]
r = render_tex(_request, templatename, ctx)
r['Content-Disposition'] = 'attachment; filename="{name}.pdf"'.format(
name=filename
)
......@@ -83,12 +111,13 @@ def create_pdf(template, ctx={}):
with tempfile.TemporaryDirectory() as tempdir:
for _ in range(2):
process = Popen(
['pdflatex', '-output-directory', tempdir],
stdin=PIPE,
stdout=PIPE,
)
process.communicate(rendered_tpl)
with open("/var/www/re2o/out.log", "w") as f:
process = Popen(
['pdflatex', '-output-directory', tempdir],
stdin=PIPE,
stdout=f,#PIPE,
)
process.communicate(rendered_tpl)
with open(os.path.join(tempdir, 'texput.pdf'), 'rb') as f:
pdf = f.read()
......
......@@ -51,6 +51,11 @@ urlpatterns = [
views.facture_pdf,
name='facture-pdf'
),
url(
r'^voucher_pdf/(?P<factureid>[0-9]+)$',
views.voucher_pdf,
name='voucher-pdf'
),
url(
r'^new_cost_estimate/$',
views.new_cost_estimate,
......@@ -176,5 +181,5 @@ urlpatterns = [
views.control,
name='control'
),
url(r'^$', views.index, name='index'),
url(r'^$', views.index, name='index'),
] + payment_methods.urls.urlpatterns
......@@ -25,7 +25,7 @@ from django.template.loader import get_template
from django.core.mail import EmailMessage
from .tex import create_pdf
from preferences.models import AssoOption, GeneralOption
from preferences.models import AssoOption, GeneralOption, CotisationsOption
from re2o.settings import LOGO_PATH
from re2o import settings
......@@ -93,3 +93,38 @@ def send_mail_invoice(invoice):
attachments=[('invoice.pdf', pdf, 'application/pdf')]
)
mail.send()
def send_mail_voucher(invoice):
"""Creates a voucher from an invoice and sends it by email to the client"""
ctx = {
'asso_name': AssoOption.get_cached_value('name'),
'pres_name': AssoOption.get_cached_value('pres_name'),
'firstname': invoice.user.name,
'lastname': invoice.user.surname,
'email': invoice.user.email,
'phone': invoice.user.telephone,
'date_end': invoice.get_subscription().latest('date_end').date_end,
'date_begin': invoice.get_subscription().earliest('date_start').date_start
}
templatename = CotisationsOption.get_cached_value('voucher_template').template.name.split('/')[-1]
pdf = create_pdf(templatename, ctx)
template = get_template('cotisations/email_subscription_accepted')
ctx = {
'name': "{} {}".format(
invoice.user.name,
invoice.user.surname
),
'asso_email': AssoOption.get_cached_value('contact'),
'asso_name': AssoOption.get_cached_value('name')
}
mail = EmailMessage(
'Votre reçu / Your voucher',
template.render(ctx),
GeneralOption.get_cached_value('email_from'),
[invoice.user.get_mail],
attachments=[('voucher.pdf', pdf, 'application/pdf')]
)
mail.send()
......@@ -69,7 +69,7 @@ from .models import (
Banque,
CustomInvoice,
BaseInvoice,
CostEstimate
CostEstimate,
)
from .forms import (
FactureForm,
......@@ -85,7 +85,7 @@ from .forms import (
DiscountForm,
CostEstimateForm,
)
from .tex import render_invoice, escape_chars
from .tex import render_invoice, render_voucher, escape_chars
from .payment_methods.forms import payment_method_factory
from .utils import find_payment_method
......@@ -217,6 +217,7 @@ def new_cost_estimate(request):
number=quantity
)
discount_form.apply_to_invoice(cost_estimate_instance)
messages.success(
request,
_("The cost estimate was created.")
......@@ -482,7 +483,6 @@ def cost_estimate_pdf(request, invoice, **_kwargs):
invoice with the total price, the payment method, the address and the
legal information for the user.
"""
# TODO : change vente to purchase
purchases_objects = Vente.objects.all().filter(facture=invoice)
# Get the article list and build an list out of it
# contiaining (article_name, article_price, quantity, total_price)
......@@ -720,7 +720,7 @@ def edit_paiement(request, paiement_instance, **_kwargs):
if payment_method is not None:
payment_method.save()
messages.success(
request,_("The payment method was edited.")
request, _("The payment method was edited.")
)
return redirect(reverse('cotisations:index-paiement'))
return form({
......@@ -954,7 +954,8 @@ def index_custom_invoice(request):
"""View used to display every custom invoice."""
pagination_number = GeneralOption.get_cached_value('pagination_number')
cost_estimate_ids = [i for i, in CostEstimate.objects.values_list('id')]
custom_invoice_list = CustomInvoice.objects.prefetch_related('vente_set').exclude(id__in=cost_estimate_ids)
custom_invoice_list = CustomInvoice.objects.prefetch_related(
'vente_set').exclude(id__in=cost_estimate_ids)
custom_invoice_list = SortTable.sort(
custom_invoice_list,
request.GET.get('col'),
......@@ -1020,7 +1021,8 @@ def credit_solde(request, user, **_kwargs):
kwargs={'userid': user.id}
))
refill_form = RechargeForm(request.POST or None, user=user, user_source=request.user)
refill_form = RechargeForm(
request.POST or None, user=user, user_source=request.user)
if refill_form.is_valid():
price = refill_form.cleaned_data['value']
invoice = Facture(user=user)
......@@ -1050,3 +1052,29 @@ def credit_solde(request, user, **_kwargs):
'max_balance': find_payment_method(p).maximum_balance,
}, 'cotisations/facture.html', request)
@login_required
@can_view(Facture)
def voucher_pdf(request, invoice, **_kwargs):
"""
View used to generate a PDF file from a controlled invoice
Creates a line for each Purchase (thus article sold) and generate the
invoice with the total price, the payment method, the address and the
legal information for the user.
"""
if not invoice.control:
messages.error(
request,
_("Could not find a voucher for that invoice.")
)
return redirect(reverse('cotisations:index'))
return render_voucher(request, {
'asso_name': AssoOption.get_cached_value('name'),
'pres_name': AssoOption.get_cached_value('pres_name'),
'firstname': invoice.user.name,
'lastname': invoice.user.surname,
'email': invoice.user.email,
'phone': invoice.user.telephone,
'date_end': invoice.get_subscription().latest('date_end').date_end,
'date_begin': invoice.date
})
......@@ -59,7 +59,7 @@ _ask_value() {
install_requirements() {
### Usage: install_requirements
### Usage: install_requirements
#
# This function will install the required packages from APT repository
# and Pypi repository. Those packages are all required for Re2o to work
......@@ -273,7 +273,7 @@ write_settings_file() {
django_secret_key="$(python -c "import random; print(''.join([random.SystemRandom().choice('abcdefghijklmnopqrstuvwxyz0123456789%=+') for i in range(50)]))")"
aes_key="$(python -c "import random; print(''.join([random.SystemRandom().choice('abcdefghijklmnopqrstuvwxyz0123456789%=+') for i in range(32)]))")"
if [ "$db_engine_type" == 1 ]; then
sed -i 's/db_engine/django.db.backends.mysql/g' "$SETTINGS_LOCAL_FILE"
else
......@@ -324,6 +324,21 @@ update_django() {
copy_templates_files() {
### Usage: copy_templates_files
#
# This will copy LaTeX templates in the media root.
echo "Copying LaTeX templates ..."
mkdir -p media/templates/
cp cotisations/templates/cotisations/factures.tex media/templates/default_invoice.tex
cp cotisations/templates/cotisations/voucher.tex media/templates/default_voucher.tex
chown -R www-data:www-data media/templates/
echo "Copying LaTeX templates: Done"
}
create_superuser() {
### Usage: create_superuser
#
......@@ -476,7 +491,7 @@ interactive_guide() {
sql_host="$(dialog --clear --backtitle "$BACKTITLE" \
--title "$TITLE" --inputbox "$INPUTBOX" \
$HEIGHT $WIDTH 2>&1 >/dev/tty)"
# Prompt to enter the remote database name
TITLE="SQL database name"
INPUTBOX="The name of the remote SQL database"
......@@ -523,14 +538,14 @@ interactive_guide() {
ldap_is_local="$(dialog --clear --backtitle "$BACKTITLE" \
--title "$TITLE" --menu "$MENU" \
$HEIGHT $WIDTH $CHOICE_HEIGHT "${OPTIONS[@]}" 2>&1 >/dev/tty)"
# Prompt to enter the LDAP domain extension
TITLE="Domain extension"
INPUTBOX="The local domain extension to use (e.g. 'example.net'). This is used in the LDAP configuration."
extension_locale="$(dialog --clear --backtitle "$BACKTITLE" \
--title "$TITLE" --inputbox "$INPUTBOX" \
$HEIGHT $WIDTH 2>&1 >/dev/tty)"
# Building the DN of the LDAP from the extension
IFS='.' read -a extension_locale_array <<< $extension_locale
for i in "${extension_locale_array[@]}"
......@@ -546,7 +561,7 @@ interactive_guide() {
ldap_host="$(dialog --clear --backtitle "$BACKTITLE" \
--title "$TITLE" --inputbox "$INPUTBOX" \
$HEIGHT $WIDTH 2>&1 >/dev/tty)"
# Prompt to choose if TLS should be activated or not for the LDAP
TITLE="TLS on LDAP"
MENU="Would you like to activate TLS for communicating with the remote LDAP ?"
......@@ -583,7 +598,7 @@ interactive_guide() {
#########################
BACKTITLE="Re2o setup - configuration of the mail server"
# Prompt to enter the hostname of the mail server
TITLE="Mail server hostname"
INPUTBOX="The hostname of the mail server to use"
......@@ -591,7 +606,7 @@ interactive_guide() {
--title "$TITLE" --inputbox "$TITLE" \
$HEIGHT $WIDTH 2>&1 >/dev/tty)"
# Prompt to choose the port of the mail server
# Prompt to choose the port of the mail server
TITLE="Mail server port"
MENU="Which port (thus which protocol) to use to contact the mail server"
OPTIONS=(25 "SMTP"
......@@ -608,7 +623,7 @@ interactive_guide() {
########################
BACKTITLE="Re2o setup - configuration of the web server"
# Prompt to choose the web server
TITLE="Web server to use"
MENU="Which web server to install for accessing Re2o web frontend (automatic setup of nginx is not supported) ?"
......@@ -617,14 +632,14 @@ interactive_guide() {
web_serveur="$(dialog --clear --backtitle "$BACKTITLE" \
--title "$TITLE" --menu "$MENU" \
$HEIGHT $WIDTH $CHOICE_HEIGHT "${OPTIONS[@]}" 2>&1 >/dev/tty)"
# Prompt to enter the requested URL for the web frontend
TITLE="Web URL"
INPUTBOX="URL for accessing the web server (e.g. re2o.example.net). Be sure that this URL is accessible and correspond to a DNS entry (if applicable)."
url_server="$(dialog --clear --backtitle "$BACKTITLE" \
--title "$TITLE" --inputbox "$INPUTBOX" \
$HEIGHT $WIDTH 2>&1 >/dev/tty)"
# Prompt to choose if the TLS should be setup or not for the web server
TITLE="TLS on web server"
MENU="Would you like to activate the TLS (with Let'Encrypt) on the web server ?"
......@@ -679,7 +694,7 @@ interactive_guide() {
update_django
create_superuser
install_webserver "$web_serveur" "$is_tls" "$url_server"
......@@ -748,9 +763,10 @@ main_function() {
echo " * {help} ---------- Display this quick usage documentation"
echo " * {setup} --------- Launch the full interactive guide to setup entirely"
echo " re2o from scratch"
echo " * {update} -------- Collect frontend statics, install the missing APT"
echo " * {update} -------- Collect frontend statics, install the missing APT and copy LaTeX templates files"
echo " and pip packages and apply the migrations to the DB"
echo " * {update-django} - Apply Django migration and collect frontend statics"
echo " * {copy-template-files} - Copy LaTeX templates files to media/templates"
echo " * {update-packages} Install the missing APT and pip packages"
echo " * {update-settings} Interactively rewrite the settings file"
echo " * {reset-db} ------ Erase the previous local database, setup a new empty"
......@@ -782,9 +798,14 @@ main_function() {
update )
install_requirements
copy_templates_files
update_django
;;
copy-templates-files )
copy_templates_files
;;
update-django )
update_django
;;
......@@ -800,7 +821,7 @@ main_function() {
reset-db )
if [ ! -z "$2" ]; then
db_password="$2"
case "$3" in
case "$3" in
mysql )
db_engine_type=1;;
postresql )
......
......@@ -40,7 +40,8 @@ from .models import (
HomeOption,
RadiusKey,
SwitchManagementCred,
Reminder
Reminder,
DocumentTemplate
)
......@@ -101,6 +102,12 @@ class ReminderAdmin(VersionAdmin):
"""Class reminder for switch"""
pass
class DocumentTemplateAdmin(VersionAdmin):
"""Admin class for DocumentTemplate"""
pass
admin.site.register(OptionalUser, OptionalUserAdmin)
admin.site.register(OptionalMachine, OptionalMachineAdmin)
admin.site.register(OptionalTopologie, OptionalTopologieAdmin)
......@@ -113,3 +120,4 @@ admin.site.register(RadiusKey, RadiusKeyAdmin)
admin.site.register(SwitchManagementCred, SwitchManagementCredAdmin)
admin.site.register(AssoOption, AssoOptionAdmin)
admin.site.register(MailMessageOption, MailMessageOptionAdmin)
admin.site.register(DocumentTemplate, DocumentTemplateAdmin)
......@@ -43,9 +43,12 @@ from .models import (
RadiusKey,
SwitchManagementCred,
RadiusOption,
CotisationsOption,
DocumentTemplate
)
from topologie.models import Switch
class EditOptionalUserForm(ModelForm):
"""Formulaire d'édition des options de l'user. (solde, telephone..)"""
class Meta:
......@@ -182,9 +185,6 @@ class EditAssoOptionForm(ModelForm):
self.fields['pseudo'].label = _("Usual name")
self.fields['utilisateur_asso'].label = _("Account used for editing"
" from /admin")
self.fields['payment'].label = _("Payment")
self.fields['payment_id'].label = _("Payment ID")
self.fields['payment_pass'].label = _("Payment password")
self.fields['description'].label = _("Description")
......@@ -253,6 +253,13 @@ class EditRadiusOptionForm(ModelForm):
return cleaned_data
class EditCotisationsOptionForm(ModelForm):
"""Edition forms for Cotisations options"""
class Meta:
model = CotisationsOption
fields = '__all__'
class ServiceForm(ModelForm):
"""Edition, ajout de services sur la page d'accueil"""
class Meta:
......@@ -371,3 +378,36 @@ class DelMailContactForm(Form):
else:
self.fields['mailcontacts'].queryset = MailContact.objects.all()
class DocumentTemplateForm(FormRevMixin, ModelForm):
"""
Form used to create a document template.