Commit 932f6470 authored by root's avatar root

Merge branch 'master' into ouverture_des_ports

parents b84f654f 54cb9f46
...@@ -4,3 +4,4 @@ settings_local.py ...@@ -4,3 +4,4 @@ settings_local.py
re2o.png re2o.png
__pycache__/* __pycache__/*
static_files/* static_files/*
static/logo/*
...@@ -28,23 +28,37 @@ from reversion.admin import VersionAdmin ...@@ -28,23 +28,37 @@ from reversion.admin import VersionAdmin
from .models import Facture, Article, Banque, Paiement, Cotisation, Vente from .models import Facture, Article, Banque, Paiement, Cotisation, Vente
class FactureAdmin(VersionAdmin): class FactureAdmin(VersionAdmin):
list_display = ('user','paiement','date','valid','control') """Class admin d'une facture, tous les champs"""
pass
class VenteAdmin(VersionAdmin): class VenteAdmin(VersionAdmin):
list_display = ('facture','name','prix','number','iscotisation','duration') """Class admin d'une vente, tous les champs (facture related)"""
pass
class ArticleAdmin(VersionAdmin): class ArticleAdmin(VersionAdmin):
list_display = ('name','prix','iscotisation','duration') """Class admin d'un article en vente"""
pass
class BanqueAdmin(VersionAdmin): class BanqueAdmin(VersionAdmin):
list_display = ('name',) """Class admin de la liste des banques (facture related)"""
pass
class PaiementAdmin(VersionAdmin): class PaiementAdmin(VersionAdmin):
list_display = ('moyen','type_paiement') """Class admin d'un moyen de paiement (facture related"""
pass
class CotisationAdmin(VersionAdmin): class CotisationAdmin(VersionAdmin):
list_display = ('vente','date_start','date_end') """Class admin d'une cotisation (date de debut et de fin),
Vente related"""
pass
admin.site.register(Facture, FactureAdmin) admin.site.register(Facture, FactureAdmin)
admin.site.register(Article, ArticleAdmin) admin.site.register(Article, ArticleAdmin)
......
...@@ -19,74 +19,125 @@ ...@@ -19,74 +19,125 @@
# You should have received a copy of the GNU General Public License along # You should have received a copy of the GNU General Public License along
# with this program; if not, write to the Free Software Foundation, Inc., # with this program; if not, write to the Free Software Foundation, Inc.,
# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
"""
Forms de l'application cotisation de re2o. Dépendance avec les models,
importé par les views.
Permet de créer une nouvelle facture pour un user (NewFactureForm),
et de l'editer (soit l'user avec EditFactureForm,
soit le trésorier avec TrezEdit qui a plus de possibilités que self
notamment sur le controle trésorier)
SelectArticleForm est utilisée lors de la creation d'une facture en
parrallèle de NewFacture pour le choix des articles désirés.
(la vue correspondante est unique)
ArticleForm, BanqueForm, PaiementForm permettent aux admin d'ajouter,
éditer ou supprimer une banque/moyen de paiement ou un article
"""
from __future__ import unicode_literals from __future__ import unicode_literals
from django import forms from django import forms
from django.forms import ModelForm, Form from django.forms import ModelForm, Form
from django import forms
from django.core.validators import MinValueValidator from django.core.validators import MinValueValidator
from .models import Article, Paiement, Facture, Banque, Vente from .models import Article, Paiement, Facture, Banque
class NewFactureForm(ModelForm): class NewFactureForm(ModelForm):
"""Creation d'une facture, moyen de paiement, banque et numero
de cheque"""
def __init__(self, *args, **kwargs): def __init__(self, *args, **kwargs):
super(NewFactureForm, self).__init__(*args, **kwargs) prefix = kwargs.pop('prefix', self.Meta.model.__name__)
super(NewFactureForm, self).__init__(*args, prefix=prefix, **kwargs)
self.fields['cheque'].required = False self.fields['cheque'].required = False
self.fields['banque'].required = False self.fields['banque'].required = False
self.fields['cheque'].label = 'Numero de chèque' self.fields['cheque'].label = 'Numero de chèque'
self.fields['banque'].empty_label = "Non renseigné" self.fields['banque'].empty_label = "Non renseigné"
self.fields['paiement'].empty_label = "Séléctionner un moyen de paiement" self.fields['paiement'].empty_label = "Séléctionner\
self.fields['paiement'].widget.attrs['data-cheque'] = Paiement.objects.filter(type_paiement=1).first().id un moyen de paiement"
self.fields['paiement'].widget.attrs['data-cheque'] = Paiement.objects\
.filter(type_paiement=1).first().id
class Meta: class Meta:
model = Facture model = Facture
fields = ['paiement','banque','cheque'] fields = ['paiement', 'banque', 'cheque']
def clean(self): def clean(self):
cleaned_data=super(NewFactureForm, self).clean() cleaned_data = super(NewFactureForm, self).clean()
paiement = cleaned_data.get("paiement") paiement = cleaned_data.get("paiement")
cheque = cleaned_data.get("cheque") cheque = cleaned_data.get("cheque")
banque = cleaned_data.get("banque") banque = cleaned_data.get("banque")
if not paiement: if not paiement:
raise forms.ValidationError("Le moyen de paiement est obligatoire.") raise forms.ValidationError("Le moyen de paiement est obligatoire")
elif paiement.type_paiement == "check" and not (cheque and banque): elif paiement.type_paiement == "check" and not (cheque and banque):
raise forms.ValidationError("Le numéro de chèque et la banque sont obligatoires.") raise forms.ValidationError("Le numéro de chèque et\
la banque sont obligatoires.")
return cleaned_data return cleaned_data
class CreditSoldeForm(NewFactureForm): class CreditSoldeForm(NewFactureForm):
"""Permet de faire des opérations sur le solde si il est activé"""
class Meta(NewFactureForm.Meta): class Meta(NewFactureForm.Meta):
model = Facture model = Facture
fields = ['paiement','banque','cheque'] fields = ['paiement', 'banque', 'cheque']
def __init__(self, *args, **kwargs): def __init__(self, *args, **kwargs):
super(CreditSoldeForm, self).__init__(*args, **kwargs) super(CreditSoldeForm, self).__init__(*args, **kwargs)
self.fields['paiement'].queryset = Paiement.objects.exclude(moyen='solde').exclude(moyen="Solde") self.fields['paiement'].queryset = Paiement.objects.exclude(
moyen='solde'
).exclude(moyen="Solde")
montant = forms.DecimalField(max_digits=5, decimal_places=2, required=True) montant = forms.DecimalField(max_digits=5, decimal_places=2, required=True)
class SelectArticleForm(Form): class SelectArticleForm(Form):
article = forms.ModelChoiceField(queryset=Article.objects.all(), label="Article", required=True) """Selection d'un article lors de la creation d'une facture"""
quantity = forms.IntegerField(label="Quantité", validators=[MinValueValidator(1)], required=True) article = forms.ModelChoiceField(
queryset=Article.objects.all(),
label="Article",
required=True
)
quantity = forms.IntegerField(
label="Quantité",
validators=[MinValueValidator(1)],
required=True
)
class NewFactureFormPdf(Form): class NewFactureFormPdf(Form):
article = forms.ModelMultipleChoiceField(queryset=Article.objects.all(), label="Article") """Creation d'un pdf facture par le trésorier"""
number = forms.IntegerField(label="Quantité", validators=[MinValueValidator(1)]) article = forms.ModelMultipleChoiceField(
queryset=Article.objects.all(),
label="Article"
)
number = forms.IntegerField(
label="Quantité",
validators=[MinValueValidator(1)]
)
paid = forms.BooleanField(label="Payé", required=False) paid = forms.BooleanField(label="Payé", required=False)
dest = forms.CharField(required=True, max_length=255, label="Destinataire") dest = forms.CharField(required=True, max_length=255, label="Destinataire")
chambre = forms.CharField(required=False, max_length=10, label="Adresse") chambre = forms.CharField(required=False, max_length=10, label="Adresse")
fid = forms.CharField(required=True, max_length=10, label="Numéro de la facture") fid = forms.CharField(
required=True,
max_length=10,
label="Numéro de la facture"
)
class EditFactureForm(NewFactureForm): class EditFactureForm(NewFactureForm):
"""Edition d'une facture : moyen de paiement, banque, user parent"""
class Meta(NewFactureForm.Meta): class Meta(NewFactureForm.Meta):
fields = ['paiement','banque','cheque','user'] fields = ['paiement', 'banque', 'cheque', 'user']
def __init__(self, *args, **kwargs): def __init__(self, *args, **kwargs):
super(EditFactureForm, self).__init__(*args, **kwargs) super(EditFactureForm, self).__init__(*args, **kwargs)
self.fields['user'].label = 'Adherent' self.fields['user'].label = 'Adherent'
self.fields['user'].empty_label = "Séléctionner l'adhérent propriétaire" self.fields['user'].empty_label = "Séléctionner\
l'adhérent propriétaire"
class TrezEditFactureForm(EditFactureForm): class TrezEditFactureForm(EditFactureForm):
"""Vue pour édition controle trésorier"""
class Meta(EditFactureForm.Meta): class Meta(EditFactureForm.Meta):
fields = '__all__' fields = '__all__'
...@@ -97,38 +148,67 @@ class TrezEditFactureForm(EditFactureForm): ...@@ -97,38 +148,67 @@ class TrezEditFactureForm(EditFactureForm):
class ArticleForm(ModelForm): class ArticleForm(ModelForm):
"""Creation d'un article. Champs : nom, cotisation, durée"""
class Meta: class Meta:
model = Article model = Article
fields = '__all__' fields = '__all__'
def __init__(self, *args, **kwargs): def __init__(self, *args, **kwargs):
super(ArticleForm, self).__init__(*args, **kwargs) prefix = kwargs.pop('prefix', self.Meta.model.__name__)
super(ArticleForm, self).__init__(*args, prefix=prefix, **kwargs)
self.fields['name'].label = "Désignation de l'article" self.fields['name'].label = "Désignation de l'article"
class DelArticleForm(Form): class DelArticleForm(Form):
articles = forms.ModelMultipleChoiceField(queryset=Article.objects.all(), label="Articles actuels", widget=forms.CheckboxSelectMultiple) """Suppression d'un ou plusieurs articles en vente. Choix
parmis les modèles"""
articles = forms.ModelMultipleChoiceField(
queryset=Article.objects.all(),
label="Articles actuels",
widget=forms.CheckboxSelectMultiple
)
class PaiementForm(ModelForm): class PaiementForm(ModelForm):
"""Creation d'un moyen de paiement, champ text moyen et type
permettant d'indiquer si il s'agit d'un chèque ou non pour le form"""
class Meta: class Meta:
model = Paiement model = Paiement
fields = ['moyen', 'type_paiement'] fields = ['moyen', 'type_paiement']
def __init__(self, *args, **kwargs): def __init__(self, *args, **kwargs):
super(PaiementForm, self).__init__(*args, **kwargs) prefix = kwargs.pop('prefix', self.Meta.model.__name__)
super(PaiementForm, self).__init__(*args, prefix=prefix, **kwargs)
self.fields['moyen'].label = 'Moyen de paiement à ajouter' self.fields['moyen'].label = 'Moyen de paiement à ajouter'
self.fields['type_paiement'].label = 'Type de paiement à ajouter' self.fields['type_paiement'].label = 'Type de paiement à ajouter'
class DelPaiementForm(Form): class DelPaiementForm(Form):
paiements = forms.ModelMultipleChoiceField(queryset=Paiement.objects.all(), label="Moyens de paiement actuels", widget=forms.CheckboxSelectMultiple) """Suppression d'un ou plusieurs moyens de paiements, selection
parmis les models"""
paiements = forms.ModelMultipleChoiceField(
queryset=Paiement.objects.all(),
label="Moyens de paiement actuels",
widget=forms.CheckboxSelectMultiple
)
class BanqueForm(ModelForm): class BanqueForm(ModelForm):
"""Creation d'une banque, field name"""
class Meta: class Meta:
model = Banque model = Banque
fields = ['name'] fields = ['name']
def __init__(self, *args, **kwargs): def __init__(self, *args, **kwargs):
super(BanqueForm, self).__init__(*args, **kwargs) prefix = kwargs.pop('prefix', self.Meta.model.__name__)
super(BanqueForm, self).__init__(*args, prefix=prefix, **kwargs)
self.fields['name'].label = 'Banque à ajouter' self.fields['name'].label = 'Banque à ajouter'
class DelBanqueForm(Form): class DelBanqueForm(Form):
banques = forms.ModelMultipleChoiceField(queryset=Banque.objects.all(), label="Banques actuelles", widget=forms.CheckboxSelectMultiple) """Selection d'une ou plusieurs banques, pour suppression"""
banques = forms.ModelMultipleChoiceField(
queryset=Banque.objects.all(),
label="Banques actuelles",
widget=forms.CheckboxSelectMultiple
)
This diff is collapsed.
...@@ -25,6 +25,7 @@ with this program; if not, write to the Free Software Foundation, Inc., ...@@ -25,6 +25,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
{% load bootstrap3 %} {% load bootstrap3 %}
{% load staticfiles%} {% load staticfiles%}
{% load massive_bootstrap_form %}
{% block title %}Création et modification de factures{% endblock %} {% block title %}Création et modification de factures{% endblock %}
...@@ -34,7 +35,7 @@ with this program; if not, write to the Free Software Foundation, Inc., ...@@ -34,7 +35,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
<form class="form" method="post"> <form class="form" method="post">
{% csrf_token %} {% csrf_token %}
<h3>Editer la facture</h3> <h3>Editer la facture</h3>
{% bootstrap_form factureform %} {% massive_bootstrap_form factureform 'user' %}
{{ venteform.management_form }} {{ venteform.management_form }}
<h3>Articles de la facture</h3> <h3>Articles de la facture</h3>
<table class="table table-striped"> <table class="table table-striped">
......
...@@ -38,18 +38,20 @@ with this program; if not, write to the Free Software Foundation, Inc., ...@@ -38,18 +38,20 @@ with this program; if not, write to the Free Software Foundation, Inc.,
{{ venteform.management_form }} {{ venteform.management_form }}
<!-- TODO: FIXME to include data-type="check" for right option in id_cheque select --> <!-- TODO: FIXME to include data-type="check" for right option in id_cheque select -->
<h3>Articles de la facture</h3> <h3>Articles de la facture</h3>
<div id="form_set"> <div id="form_set" class="form-group">
{% for form in venteform.forms %} {% for form in venteform.forms %}
<div class='product_to_sell'> <div class='product_to_sell form-inline'>
<p> Article : &nbsp;
{{ form.as_table }} {% bootstrap_form form label_class='sr-only' %}
</p> &nbsp;
<button class="btn btn-danger btn-sm"
id="id_form-0-article-remove" type="button">
<span class="glyphicon glyphicon-remove"></span>
</button>
</div> </div>
{% endfor %} {% endfor %}
</div> </div>
<p>
<input class="btn btn-primary btn-sm" role="button" value="Ajouter un article" id="add_one"> <input class="btn btn-primary btn-sm" role="button" value="Ajouter un article" id="add_one">
</p>
<p> <p>
Prix total : <span id="total_price">0,00</span> Prix total : <span id="total_price">0,00</span>
</p> </p>
...@@ -63,19 +65,23 @@ with this program; if not, write to the Free Software Foundation, Inc., ...@@ -63,19 +65,23 @@ with this program; if not, write to the Free Software Foundation, Inc.,
prices[{{ article.id|escapejs }}] = {{ article.prix }}; prices[{{ article.id|escapejs }}] = {{ article.prix }};
{% endfor %} {% endfor %}
var template = `<p>{{ venteform.empty_form.as_table }}</p>`; var template = `Article : &nbsp;
{% bootstrap_form venteform.empty_form label_class='sr-only' %}
&nbsp;
<button class="btn btn-danger btn-sm"
id="id_form-__prefix__-article-remove" type="button">
<span class="glyphicon glyphicon-remove"></span>
</button>`
function add_article(){ function add_article(){
// Index start at 0 => new_index = number of items // Index start at 0 => new_index = number of items
var new_index = var new_index =
document.getElementsByClassName('product_to_sell').length; document.getElementsByClassName('product_to_sell').length;
document.getElementById('id_form-TOTAL_FORMS').value = document.getElementById('id_form-TOTAL_FORMS').value ++;
parseInt(document.getElementById('id_form-TOTAL_FORMS').value) + 1;
var new_article = document.createElement('div'); var new_article = document.createElement('div');
new_article.className = 'product_to_sell'; new_article.className = 'product_to_sell form-inline';
new_article.innerHTML = template.replace(/__prefix__/g, new_index); new_article.innerHTML = template.replace(/__prefix__/g, new_index);
document.getElementById('form_set') document.getElementById('form_set').appendChild(new_article);
.appendChild(new_article);
add_listenner_for_id(new_index); add_listenner_for_id(new_index);
} }
...@@ -106,18 +112,28 @@ with this program; if not, write to the Free Software Foundation, Inc., ...@@ -106,18 +112,28 @@ with this program; if not, write to the Free Software Foundation, Inc.,
.addEventListener("onkeypress", update_price, true); .addEventListener("onkeypress", update_price, true);
document.getElementById('id_form-' + i.toString() + '-quantity') document.getElementById('id_form-' + i.toString() + '-quantity')
.addEventListener("change", update_price, true); .addEventListener("change", update_price, true);
document.getElementById('id_form-' + i.toString() + '-article-remove')
.addEventListener("click", function(event) {
var article = event.target.parentNode;
article.parentNode.removeChild(article);
document.getElementById('id_form-TOTAL_FORMS').value --;
update_price();
}
)
} }
function set_cheque_info_visibility(){ function set_cheque_info_visibility() {
var visible = document.getElementById("id_paiement").value == document.getElementById("id_paiement").getAttribute('data-cheque'); var paiement = document.getElementById("id_Facture-paiement");
p = document.getElementById("id_paiement") var visible = paiement.value == paiement.getAttribute('data-cheque');
console.log(p); p = document.getElementById("id_Facture-paiement");
var display = 'none'; var display = 'none';
if (visible) { if (visible) {
display = 'block'; display = 'block';
} }
document.getElementById("id_cheque").parentNode.style.display = display; document.getElementById("id_Facture-cheque")
document.getElementById("id_banque").parentNode.style.display = display; .parentNode.style.display = display;
document.getElementById("id_Facture-banque")
.parentNode.style.display = display;
} }
// Add events manager when DOM is fully loaded // Add events manager when DOM is fully loaded
...@@ -129,7 +145,7 @@ with this program; if not, write to the Free Software Foundation, Inc., ...@@ -129,7 +145,7 @@ 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_paiement") document.getElementById("id_Facture-paiement")
.addEventListener("change", set_cheque_info_visibility, true); .addEventListener("change", set_cheque_info_visibility, true);
set_cheque_info_visibility(); set_cheque_info_visibility();
update_price(); update_price();
......
...@@ -27,30 +27,96 @@ from django.conf.urls import url ...@@ -27,30 +27,96 @@ from django.conf.urls import url
from . import views from . import views
urlpatterns = [ urlpatterns = [
url(r'^new_facture/(?P<userid>[0-9]+)$', views.new_facture, name='new-facture'), url(r'^new_facture/(?P<userid>[0-9]+)$',
url(r'^edit_facture/(?P<factureid>[0-9]+)$', views.edit_facture, name='edit-facture'), views.new_facture,
url(r'^del_facture/(?P<factureid>[0-9]+)$', views.del_facture, name='del-facture'), name='new-facture'
url(r'^facture_pdf/(?P<factureid>[0-9]+)$', views.facture_pdf, name='facture-pdf'), ),
url(r'^new_facture_pdf/$', views.new_facture_pdf, name='new-facture-pdf'), url(r'^edit_facture/(?P<factureid>[0-9]+)$',
url(r'^credit_solde/(?P<userid>[0-9]+)$', views.credit_solde, name='credit-solde'), views.edit_facture,
url(r'^add_article/$', views.add_article, name='add-article'), name='edit-facture'
url(r'^edit_article/(?P<articleid>[0-9]+)$', views.edit_article, name='edit-article'), ),
url(r'^del_article/$', views.del_article, name='del-article'), url(r'^del_facture/(?P<factureid>[0-9]+)$',
url(r'^add_paiement/$', views.add_paiement, name='add-paiement'), views.del_facture,
url(r'^edit_paiement/(?P<paiementid>[0-9]+)$', views.edit_paiement, name='edit-paiement'), name='del-facture'
url(r'^del_paiement/$', views.del_paiement, name='del-paiement'), ),
url(r'^add_banque/$', views.add_banque, name='add-banque'), url(r'^facture_pdf/(?P<factureid>[0-9]+)$',
url(r'^edit_banque/(?P<banqueid>[0-9]+)$', views.edit_banque, name='edit-banque'), views.facture_pdf,
url(r'^del_banque/$', views.del_banque, name='del-banque'), name='facture-pdf'
url(r'^index_article/$', views.index_article, name='index-article'), ),
url(r'^index_banque/$', views.index_banque, name='index-banque'), url(r'^new_facture_pdf/$',
url(r'^index_paiement/$', views.index_paiement, name='index-paiement'), views.new_facture_pdf,
url(r'^history/(?P<object>facture)/(?P<id>[0-9]+)$', views.history, name='history'), name='new-facture-pdf'
url(r'^history/(?P<object>article)/(?P<id>[0-9]+)$', views.history, name='history'), ),
url(r'^history/(?P<object>paiement)/(?P<id>[0-9]+)$', views.history, name='history'), url(r'^credit_solde/(?P<userid>[0-9]+)$',
url(r'^history/(?P<object>banque)/(?P<id>[0-9]+)$', views.history, name='history'), views.credit_solde,
url(r'^control/$', views.control, name='control'), name='credit-solde'
),
url(r'^add_article/$',
views.add_article,
name='add-article'
),
url(r'^edit_article/(?P<articleid>[0-9]+)$',
views.edit_article,
name='edit-article'
),
url(r'^del_article/$',
views.del_article,
name='del-article'
),
url(r'^add_paiement/$',
views.add_paiement,
name='add-paiement'
),
url(r'^edit_paiement/(?P<paiementid>[0-9]+)$',
views.edit_paiement,
name='edit-paiement'
),
url(r'^del_paiement/$',
views.del_paiement,
name='del-paiement'
),
url(r'^add_banque/$',
views.add_banque,
name='add-banque'
),
url(r'^edit_banque/(?P<banqueid>[0-9]+)$',
views.edit_banque,
name='edit-banque'
),
url(r'^del_banque/$',
views.del_banque,
name='del-banque'
),
url(r'^index_article/$',
views.index_article,
name='index-article'
),
url(r'^index_banque/$',
views.index_banque,
name='index-banque'
),
url(r'^index_paiement/$',
views.index_paiement,
name='index-paiement'
),
url(r'^history/(?P<object>facture)/(?P<id>[0-9]+)$',
views.history,