8
0
Fork 0
mirror of https://gitlab2.federez.net/re2o/re2o synced 2025-02-18 21:47:55 +00:00

Add discount for custom invoices.

This commit is contained in:
Hugo LEVY-FALK 2018-12-29 14:01:22 +01:00 committed by chirac
parent 81b7a7c4af
commit e7a7e81a2c
4 changed files with 172 additions and 98 deletions

View file

@ -46,7 +46,7 @@ from django.shortcuts import get_object_or_404
from re2o.field_permissions import FieldPermissionFormMixin from re2o.field_permissions import FieldPermissionFormMixin
from re2o.mixins import FormRevMixin from re2o.mixins import FormRevMixin
from .models import Article, Paiement, Facture, Banque, CustomInvoice from .models import Article, Paiement, Facture, Banque, CustomInvoice, Vente
from .payment_methods import balance from .payment_methods import balance
@ -104,7 +104,44 @@ class SelectArticleForm(FormRevMixin, Form):
user = kwargs.pop('user') user = kwargs.pop('user')
target_user = kwargs.pop('target_user', None) target_user = kwargs.pop('target_user', None)
super(SelectArticleForm, self).__init__(*args, **kwargs) super(SelectArticleForm, self).__init__(*args, **kwargs)
self.fields['article'].queryset = Article.find_allowed_articles(user, target_user) self.fields['article'].queryset = Article.find_allowed_articles(
user, target_user)
class DiscountForm(Form):
"""
Form used in oder to create a discount on an invoice.
"""
is_relative = forms.BooleanField(
label=_("Discount is on percentage"),
required=False,
)
discount = forms.DecimalField(
label=_("Discount"),
max_value=100,
min_value=0,
max_digits=5,
decimal_places=2,
required=False,
)
def apply_to_invoice(self, invoice):
invoice_price = invoice.prix_total()
discount = self.cleaned_data['discount']
is_relative = self.cleaned_data['is_relative']
if is_relative:
amount = discount/100 * invoice_price
else:
amount = discount
if amount > 0:
name = _("{}% discount") if is_relative else _("{}€ discount")
name = name.format(discount)
Vente.objects.create(
facture=invoice,
name=name,
prix=-amount,
number=1
)
class CustomInvoiceForm(FormRevMixin, ModelForm): class CustomInvoiceForm(FormRevMixin, ModelForm):
@ -248,7 +285,8 @@ class RechargeForm(FormRevMixin, Form):
super(RechargeForm, self).__init__(*args, **kwargs) super(RechargeForm, self).__init__(*args, **kwargs)
self.fields['payment'].empty_label = \ self.fields['payment'].empty_label = \
_("Select a payment method") _("Select a payment method")
self.fields['payment'].queryset = Paiement.find_allowed_payments(user_source).exclude(is_balance=True) self.fields['payment'].queryset = Paiement.find_allowed_payments(
user_source).exclude(is_balance=True)
def clean(self): def clean(self):
""" """
@ -266,4 +304,3 @@ class RechargeForm(FormRevMixin, Form):
} }
) )
return self.cleaned_data return self.cleaned_data

View file

@ -44,6 +44,8 @@ with this program; if not, write to the Free Software Foundation, Inc.,
{% blocktrans %}Current balance: {{ balance }} €{% endblocktrans %} {% blocktrans %}Current balance: {{ balance }} €{% endblocktrans %}
</p> </p>
{% endif %} {% endif %}
{% bootstrap_form_errors factureform %}
{% bootstrap_form_errors discount_form %}
<form class="form" method="post"> <form class="form" method="post">
{% csrf_token %} {% csrf_token %}
@ -68,6 +70,10 @@ with this program; if not, write to the Free Software Foundation, Inc.,
{% endfor %} {% endfor %}
</div> </div>
<input class="btn btn-primary btn-block" role="button" value="{% trans "Add an extra article"%}" id="add_one"> <input class="btn btn-primary btn-block" role="button" value="{% trans "Add an extra article"%}" id="add_one">
<h3>{% trans "Discount" %}</h3>
{% if discount_form %}
{% bootstrap_form discount_form %}
{% endif %}
<p> <p>
{% blocktrans %}Total price: <span id="total_price">0,00</span> €{% endblocktrans %} {% blocktrans %}Total price: <span id="total_price">0,00</span> €{% endblocktrans %}
</p> </p>
@ -119,6 +125,14 @@ with this program; if not, write to the Free Software Foundation, Inc.,
'id_form-' + i.toString() + '-quantity').value; 'id_form-' + i.toString() + '-quantity').value;
price += article_price * quantity; price += article_price * quantity;
} }
{% if discount_form %}
var relative_discount = document.getElementById('id_is_relative').checked;
var discount = document.getElementById('id_discount').value;
if(relative_discount) {
discount = discount/100 * price;
}
price -= discount;
{% endif %}
document.getElementById('total_price').innerHTML = document.getElementById('total_price').innerHTML =
price.toFixed(2).toString().replace('.', ','); price.toFixed(2).toString().replace('.', ',');
} }
@ -148,6 +162,10 @@ with this program; if not, write to the Free Software Foundation, Inc.,
for (i = 0; i < product_count; ++i){ for (i = 0; i < product_count; ++i){
add_listenner_for_id(i); add_listenner_for_id(i);
} }
document.getElementById('id_discount')
.addEventListener('change', update_price, true);
document.getElementById('id_is_relative')
.addEventListener('click', update_price, true);
update_price(); update_price();
}); });
{% endif %} {% endif %}

View file

@ -36,6 +36,7 @@ from django.template import Context
from django.http import HttpResponse from django.http import HttpResponse
from django.conf import settings from django.conf import settings
from django.utils.text import slugify from django.utils.text import slugify
import logging
TEMP_PREFIX = getattr(settings, 'TEX_TEMP_PREFIX', 'render_tex-') TEMP_PREFIX = getattr(settings, 'TEX_TEMP_PREFIX', 'render_tex-')
@ -93,6 +94,20 @@ def create_pdf(template, ctx={}):
return pdf return pdf
def escape_chars(string):
"""Escape the '%' and the '' signs to avoid messing with LaTeX"""
if not isinstance(string, str):
return string
mapping = (
('', r'\euro'),
('%', r'\%'),
)
r = str(string)
for k, v in mapping:
r = r.replace(k, v)
return r
def render_tex(_request, template, ctx={}): def render_tex(_request, template, ctx={}):
"""Creates a PDF from a LaTex templates using pdflatex. """Creates a PDF from a LaTex templates using pdflatex.

View file

@ -80,9 +80,10 @@ from .forms import (
DelBanqueForm, DelBanqueForm,
SelectArticleForm, SelectArticleForm,
RechargeForm, RechargeForm,
CustomInvoiceForm CustomInvoiceForm,
DiscountForm
) )
from .tex import render_invoice from .tex import render_invoice, escape_chars
from .payment_methods.forms import payment_method_factory from .payment_methods.forms import payment_method_factory
from .utils import find_payment_method from .utils import find_payment_method
@ -198,8 +199,9 @@ def new_custom_invoice(request):
request.POST or None, request.POST or None,
form_kwargs={'user': request.user} form_kwargs={'user': request.user}
) )
discount_form = DiscountForm(request.POST or None)
if invoice_form.is_valid() and articles_formset.is_valid(): if invoice_form.is_valid() and articles_formset.is_valid() and discount_form.is_valid():
new_invoice_instance = invoice_form.save() new_invoice_instance = invoice_form.save()
for art_item in articles_formset: for art_item in articles_formset:
if art_item.cleaned_data: if art_item.cleaned_data:
@ -213,6 +215,7 @@ def new_custom_invoice(request):
duration=article.duration, duration=article.duration,
number=quantity number=quantity
) )
discount_form.apply_to_invoice(new_invoice_instance)
messages.success( messages.success(
request, request,
_("The custom invoice was created.") _("The custom invoice was created.")
@ -223,7 +226,8 @@ def new_custom_invoice(request):
'factureform': invoice_form, 'factureform': invoice_form,
'action_name': _("Confirm"), 'action_name': _("Confirm"),
'articlesformset': articles_formset, 'articlesformset': articles_formset,
'articlelist': articles 'articlelist': articles,
'discount_form': discount_form
}, 'cotisations/facture.html', request) }, 'cotisations/facture.html', request)
@ -382,7 +386,7 @@ def custom_invoice_pdf(request, invoice, **_kwargs):
purchases_info = [] purchases_info = []
for purchase in purchases_objects: for purchase in purchases_objects:
purchases_info.append({ purchases_info.append({
'name': purchase.name, 'name': escape_chars(purchase.name),
'price': purchase.prix, 'price': purchase.prix,
'quantity': purchase.number, 'quantity': purchase.number,
'total_price': purchase.prix_total 'total_price': purchase.prix_total