diff --git a/README.md b/README.md index 735c9083..0f873031 100644 --- a/README.md +++ b/README.md @@ -15,6 +15,8 @@ Dépendances : * django-bootstrap3 (pip install) * python3-django-macaddress (stretch) * python3-dateutil (jessie-backports) + * texlive-latex-base + * texlive-fonts-recommended Moteur de db conseillé (mysql), postgresql fonctionne également. Pour mysql, il faut installer : diff --git a/cotisations/forms.py b/cotisations/forms.py index 86cc95d5..bf323602 100644 --- a/cotisations/forms.py +++ b/cotisations/forms.py @@ -1,13 +1,13 @@ from django import forms from django.forms import ModelForm, Form -from .models import Article, Paiement, Facture, Banque +from django import forms +from .models import Article, Paiement, Facture, Banque, Vente class NewFactureForm(ModelForm): - article = forms.ModelMultipleChoiceField(queryset=Article.objects.all(), label="Article") + article = forms.ModelMultipleChoiceField(queryset=Article.objects.all(), label="Article", widget=forms.CheckboxSelectMultiple()) def __init__(self, *args, **kwargs): super(NewFactureForm, self).__init__(*args, **kwargs) - self.fields['number'].label = 'Quantité' self.fields['cheque'].required = False self.fields['banque'].required = False self.fields['cheque'].label = 'Numero de chèque' @@ -16,7 +16,7 @@ class NewFactureForm(ModelForm): class Meta: model = Facture - fields = ['paiement','banque','cheque','number'] + fields = ['paiement','banque','cheque'] def clean(self): cleaned_data=super(NewFactureForm, self).clean() @@ -27,13 +27,17 @@ class NewFactureForm(ModelForm): raise forms.ValidationError("Le numero de chèque et la banque sont obligatoires") return cleaned_data +class SelectArticleForm(Form): + article = forms.ModelChoiceField(queryset=Article.objects.all(), label="Article") + quantity = forms.IntegerField(label="Quantité") + class NewFactureFormPdf(Form): article = forms.ModelMultipleChoiceField(queryset=Article.objects.all(), label="Article") number = forms.IntegerField(label="Quantité") paid = forms.BooleanField(label="Payé", required=False) dest = forms.CharField(required=True, max_length=255, label="Destinataire") - obj = forms.CharField(required=False, label="Objet") - detail = forms.CharField(required=False, max_length=255, label="Détails") + chambre = forms.CharField(required=False, max_length=10, label="Adresse") + fid = forms.CharField(required=True, max_length=10, label="Numéro de la facture") class EditFactureForm(NewFactureForm): class Meta(NewFactureForm.Meta): diff --git a/cotisations/templates/cotisations/aff_cotisations.html b/cotisations/templates/cotisations/aff_cotisations.html index 54080588..5638c6ab 100644 --- a/cotisations/templates/cotisations/aff_cotisations.html +++ b/cotisations/templates/cotisations/aff_cotisations.html @@ -3,8 +3,7 @@ Utilisateur Designation - Nombre - Prix unitaire + Prix total Moyen de paiement Date @@ -15,8 +14,7 @@ {{ facture.user }} {{ facture.name }} - {{ facture.number }} - {{ facture.prix }} + {{ facture.prix_total }} {{ facture.paiement }} {{ facture.date }} {% if is_cableur %} Editer{% endif %} diff --git a/cotisations/templates/cotisations/facture.html b/cotisations/templates/cotisations/facture.html index 48147b96..50721ef7 100644 --- a/cotisations/templates/cotisations/facture.html +++ b/cotisations/templates/cotisations/facture.html @@ -9,6 +9,10 @@
{% csrf_token %} {% bootstrap_form factureform %} + {% for vente in venteform %} + {% bootstrap_form vente %} + {% endfor %} + {{ venteform.management_form }} {% bootstrap_button "Créer ou modifier" button_type="submit" icon="star" %}
{% endblock %} diff --git a/cotisations/templates/cotisations/factures.tex b/cotisations/templates/cotisations/factures.tex index acead159..d2d68e6a 100644 --- a/cotisations/templates/cotisations/factures.tex +++ b/cotisations/templates/cotisations/factures.tex @@ -34,6 +34,7 @@ \usepackage{graphicx} \usepackage{calc} \usepackage{tabularx} +\usepackage{eurosym} \pagestyle{empty} % No page numbers \linespread{1.5} % Line spacing @@ -52,12 +53,8 @@ %---------------------------------------------------------------------------------------- % HEADING SECTION %---------------------------------------------------------------------------------------- -\begin{titlepage} -%\begin{textblock}{4cm}(20mm,5mm) -%\includegraphics[scale=0.3]{/static_files/rezo-logo.png} -%\end{textblock} -\end{titlepage} -\hfil{\Huge\bf {{asso_name}} }\hfil % Company providing the invoice +\includegraphics[width=3.5cm]{% templatetag openbrace %}{{ tpl_path }}} +\tab \tab \tab \tab \tab {\Huge\bf {{asso_name}} }\hfil % Company providing the invoice \bigskip\break % Whitespace \hrule % Horizontal line \\ \vspace{0.5cm} @@ -66,7 +63,7 @@ Siret : {{siret}} \\ \\ {\bf À :} \tab {{dest.name}} {{dest.surname}} \\ % Invoice recipient -{\bf Chambre :} \tab {% if dest.room = None %} Aucune chambre {% else %}{{dest.room}}{% endif %} \\ +{\bf Adresse :} \tab {% if dest.room = None %} Aucune adresse renseignée {% else %}{{dest.room}}{% endif %} \\ {\bf Date:} \tab {{DATE}} \\ % Invoice date @@ -77,29 +74,27 @@ Siret : {{siret}} \begin{tabularx}{\textwidth}{|X|r|r|r|} \hline - \textbf{Désignation} & \textbf{Prix Unit.} & \textbf{Quantité} & \textbf{Prix total} \\ + \textbf{Désignation} & \textbf{Prix Unit.} \euro & \textbf{Quantité} & \textbf{Prix total} \euro\\ \hline {% for a in article %} \hline - {{a.0.name}} & {{a.0.prix}} & {{a.1}} & {{a.2}}\\ + {{a.0.name}} & {{a.0.prix}} \euro & {{a.1}} & {{a.2}} \euro\\ \hline {% endfor %} \hline \end{tabularx} -%\setcounter{paid}{0} -%\setcounter{topay}{\real{\value{total}}-\value{paid}} \vspace{1cm} \hfill \begin{tabular}{|l|r|} \hline -\textbf{Total} & {{total|floatformat:2}} \\ -\textbf{Votre règlement} & {% if paid %}{{total|floatformat:2}}{% else %} 00,00 {% endif %} \\ +\textbf{Total} & {{total|floatformat:2}} \euro \\ +\textbf{Votre règlement} & {% if paid %}{{total|floatformat:2}}{% else %} 00,00 {% endif %} \euro \\ \hline -\textbf{À PAYER} & {% if not paid %}{{total|floatformat:2}}{% else %} 00,00 {% endif %}\\ +\textbf{À PAYER} & {% if not paid %}{{total|floatformat:2}}{% else %} 00,00 {% endif %} \euro\\ \hline \hline diff --git a/cotisations/templates/cotisations/sidebar.html b/cotisations/templates/cotisations/sidebar.html index e34d045b..42a627ec 100644 --- a/cotisations/templates/cotisations/sidebar.html +++ b/cotisations/templates/cotisations/sidebar.html @@ -5,4 +5,5 @@

Liste des articles en vente

Liste des banques

Liste des moyens de paiement

+ {% if is_trez %}

Créer une nouvelle facture

{% endif %} {% endblock %} diff --git a/cotisations/views.py b/cotisations/views.py index 772319aa..19d9dca0 100644 --- a/cotisations/views.py +++ b/cotisations/views.py @@ -8,12 +8,15 @@ from django.template import Context, RequestContext, loader from django.contrib.auth.decorators import login_required, permission_required from django.contrib import messages from django.db.models import Max, ProtectedError +from django.forms import modelformset_factory, formset_factory +import os from .models import Facture, Article, Vente, Cotisation, Paiement, Banque from .forms import NewFactureForm, EditFactureForm, ArticleForm, DelArticleForm, PaiementForm, DelPaiementForm, BanqueForm, DelBanqueForm, NewFactureFormPdf from users.models import User from .tex import render_tex from re2o.settings_local import ASSO_NAME, ASSO_ADDRESS_LINE1, ASSO_ADDRESS_LINE2, ASSO_SIRET, ASSO_EMAIL, ASSO_PHONE, LOGO_PATH +from re2o import settings from dateutil.relativedelta import relativedelta from django.utils import timezone @@ -44,15 +47,16 @@ def new_facture(request, userid): return redirect("/cotisations/") facture = Facture(user=user) facture_form = NewFactureForm(request.POST or None, instance=facture) + ArticleFormSet = formset_factory(ArticleForm) if facture_form.is_valid(): new_facture = facture_form.save(commit=False) article = facture_form.cleaned_data['article'] new_facture.save() for art in article: - new_vente = Vente.objects.create(facture=new_facture, name=art.name, prix=art.prix, cotisation=art.cotisation, duration=art.duration) + new_vente = Vente.objects.create(facture=new_facture, name=art.name, prix=art.prix, cotisation=art.cotisation, duration=art.duration, number=1) new_vente.save() if any(art.cotisation for art in article): - duration = sum(art.duration*facture.number for art in article if art.cotisation) + duration = sum(art.duration for art in article if art.cotisation) create_cotis(new_facture, user, duration) messages.success(request, "La cotisation a été prolongée pour l'adhérent %s " % user.name ) else: @@ -61,7 +65,7 @@ def new_facture(request, userid): return form({'factureform': facture_form}, 'cotisations/facture.html', request) @login_required -@permission_required('cableur') +@permission_required('trésorier') def new_facture_pdf(request): facture_form = NewFactureFormPdf(request.POST or None) if facture_form.is_valid(): @@ -70,12 +74,13 @@ def new_facture_pdf(request): quantite = facture_form.cleaned_data['number'] paid = facture_form.cleaned_data['paid'] destinataire = facture_form.cleaned_data['dest'] - objet = facture_form.cleaned_data['obj'] - detail = facture_form.cleaned_data['detail'] + chambre = facture_form.cleaned_data['chambre'] + fid = facture_form.cleaned_data['fid'] for a in article: tbl.append([a, quantite, a.prix * quantite]) prix_total = sum(a[2] for a in tbl) - return render_tex(request, 'cotisations/factures.tex', {'DATE' : timezone.now(),'dest':destinataire, 'obj':objet, 'detail':detail, 'article':tbl, 'total':prix_total, 'paid':paid, 'asso_name':ASSO_NAME, 'line1':ASSO_ADDRESS_LINE1, 'line2':ASSO_ADDRESS_LINE2, 'siret':ASSO_SIRET, 'email':ASSO_EMAIL, 'phone':ASSO_PHONE}) + user = {'name':destinataire, 'room':chambre} + return render_tex(request, 'cotisations/factures.tex', {'DATE' : timezone.now(),'dest':user,'fid':fid, 'article':tbl, 'total':prix_total, 'paid':paid, 'asso_name':ASSO_NAME, 'line1':ASSO_ADDRESS_LINE1, 'line2':ASSO_ADDRESS_LINE2, 'siret':ASSO_SIRET, 'email':ASSO_EMAIL, 'phone':ASSO_PHONE, 'tpl_path': os.path.join(settings.BASE_DIR, LOGO_PATH)}) return form({'factureform': facture_form}, 'cotisations/facture.html', request) @login_required @@ -91,9 +96,10 @@ def facture_pdf(request, factureid): vente = Vente.objects.all().filter(facture=facture) ventes = [] for v in vente: - ventes.append([v, facture.number, v.prix * facture.number]) - return render_tex(request, 'cotisations/factures.tex', {'paid':True, 'fid':facture.id, 'DATE':facture.date,'dest':facture.user, 'article':ventes, 'total': facture.prix_total(), 'asso_name':ASSO_NAME, 'line1': ASSO_ADDRESS_LINE1, 'line2':ASSO_ADDRESS_LINE2, 'siret':ASSO_SIRET, 'email':ASSO_EMAIL, 'phone':ASSO_PHONE, 'tpl_path':LOGO_PATH}) + ventes.append([v, v.number, v.prix_total]) + return render_tex(request, 'cotisations/factures.tex', {'paid':True, 'fid':facture.id, 'DATE':facture.date,'dest':facture.user, 'article':ventes, 'total': facture.prix_total(), 'asso_name':ASSO_NAME, 'line1': ASSO_ADDRESS_LINE1, 'line2':ASSO_ADDRESS_LINE2, 'siret':ASSO_SIRET, 'email':ASSO_EMAIL, 'phone':ASSO_PHONE, 'tpl_path':os.path.join(settings.BASE_DIR, LOGO_PATH)}) +@login_required @permission_required('cableur') def edit_facture(request, factureid): try: @@ -102,11 +108,15 @@ def edit_facture(request, factureid): messages.error(request, u"Facture inexistante" ) return redirect("/cotisations/") facture_form = EditFactureForm(request.POST or None, instance=facture) - if facture_form.is_valid(): + ventes_objects = Vente.objects.filter(facture=facture) + vente_form_set = modelformset_factory(Vente, fields=('name','prix','number'), can_delete=True) + vente_form = vente_form_set(request.POST or None, queryset=ventes_objects) + if facture_form.is_valid() and vente_form.is_valid(): facture_form.save() + vente_form.save() messages.success(request, "La facture a bien été modifiée") return redirect("/cotisations/") - return form({'factureform': facture_form}, 'cotisations/facture.html', request) + return form({'factureform': facture_form, 'venteform': vente_form}, 'cotisations/facture.html', request) @login_required @permission_required('trésorier') diff --git a/re2o/settings.py b/re2o/settings.py index e110269d..5cb9903a 100644 --- a/re2o/settings.py +++ b/re2o/settings.py @@ -12,7 +12,7 @@ https://docs.djangoproject.com/en/1.8/ref/settings/ # Build paths inside the project like this: os.path.join(BASE_DIR, ...) import os -from .settings_local import SECRET_KEY, DATABASES, DEBUG, ALLOWED_HOSTS, ASSO_NAME, ASSO_ADDRESS_LINE1, ASSO_ADDRESS_LINE2, ASSO_SIRET, ASSO_EMAIL, ASSO_PHONE +from .settings_local import SECRET_KEY, DATABASES, DEBUG, ALLOWED_HOSTS, ASSO_NAME, ASSO_ADDRESS_LINE1, ASSO_ADDRESS_LINE2, ASSO_SIRET, ASSO_EMAIL, ASSO_PHONE, LOGO_PATH BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))