parent
8bba8247a4
commit
2f0793769e
|
@ -2,7 +2,9 @@ import csv
|
|||
import math
|
||||
import datetime
|
||||
from django import forms
|
||||
from datetime import date
|
||||
from .models import Client, Contract, Prestation
|
||||
from django_select2.forms import Select2MultipleWidget, ModelSelect2Widget
|
||||
|
||||
|
||||
class ClientForm(forms.ModelForm):
|
||||
|
@ -49,7 +51,11 @@ class ContractForm(forms.ModelForm):
|
|||
"name": forms.TextInput(
|
||||
attrs={"class": "form-control", "placeholder": "Nom du contract"}
|
||||
),
|
||||
"client": forms.HiddenInput(),
|
||||
"client": ModelSelect2Widget(
|
||||
search_fields=["client__name__icontains", "client__contact__icontains", "client__city__icontains"],
|
||||
max_results=10,
|
||||
attrs={"data-minimum-input-length": 0, "class": "form-control"},
|
||||
),
|
||||
"advance": forms.TextInput(
|
||||
attrs={"class": "form-control", }
|
||||
),
|
||||
|
@ -67,26 +73,18 @@ class ContractForm(forms.ModelForm):
|
|||
)
|
||||
}
|
||||
|
||||
client_related = forms.CharField(
|
||||
widget=forms.TextInput(
|
||||
attrs={
|
||||
"class": "form-control",
|
||||
"placeholder": "Recherche client…",
|
||||
"data-ref": "#id_client",
|
||||
}
|
||||
)
|
||||
)
|
||||
|
||||
class PrestationForm(forms.ModelForm):
|
||||
class Meta:
|
||||
model = Prestation
|
||||
fields = ("contract", "date", "label", "unit", "unit_price", "total_amount")
|
||||
fields = ("contract", "date", "label", "unit", "unit_price")
|
||||
widgets = {
|
||||
"contract": forms.TextInput(
|
||||
attrs={"class": "form-control", "placeholder": "Nom du contract"}
|
||||
),
|
||||
"date": forms.TextInput(
|
||||
attrs={"class": "form-control", }
|
||||
"contract": forms.HiddenInput(),
|
||||
"date": forms.DateInput(
|
||||
attrs={
|
||||
"class": "form-control datepicker",
|
||||
"value": date.today().strftime("%Y-%m-%d"),
|
||||
}
|
||||
),
|
||||
"label": forms.TextInput(
|
||||
attrs={"class": "form-control", }
|
||||
|
@ -94,10 +92,17 @@ class PrestationForm(forms.ModelForm):
|
|||
"unit": forms.TextInput(
|
||||
attrs={"class": "form-control", }
|
||||
),
|
||||
"unit_price": forms.CheckboxInput(
|
||||
attrs={"class": "form-control", }
|
||||
),
|
||||
"total_amount": forms.CheckboxInput(
|
||||
"unit_price": forms.TextInput(
|
||||
attrs={"class": "form-control", }
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
contract_related = forms.CharField(
|
||||
widget=forms.TextInput(
|
||||
attrs={
|
||||
"class": "form-control",
|
||||
"placeholder": "Recherche contract",
|
||||
"data-ref": "#id_client",
|
||||
}
|
||||
)
|
||||
)
|
|
@ -5,11 +5,13 @@ from .views import (
|
|||
client_listing,
|
||||
client_details,
|
||||
client_create_or_update,
|
||||
contract_lookup,
|
||||
contract_listing,
|
||||
contract_detail,
|
||||
contract_create_or_update,
|
||||
contract_export,
|
||||
prestation_listing,
|
||||
prestation_create_or_update,
|
||||
)
|
||||
|
||||
app_name = "billing"
|
||||
|
@ -21,6 +23,7 @@ urlpatterns = [
|
|||
url(r"^client/create/$", client_create_or_update, name="client_create"),
|
||||
url(r"^client/update/(?P<client_id>[0-9]+)/$", client_create_or_update, name="client_update"),
|
||||
|
||||
url(r"^contract/lookup/$", contract_lookup, name="contract_lookup"),
|
||||
url(r"^contract/$", contract_listing, name="contract_listing"),
|
||||
url(
|
||||
r"^contract/(?P<contract_id>[0-9]+)/$", contract_detail, name="contract_detail"
|
||||
|
@ -34,4 +37,6 @@ urlpatterns = [
|
|||
),
|
||||
|
||||
url(r"^prestation/$", prestation_listing, name="prestation_listing"),
|
||||
url(r"^prestation/create/$", prestation_create_or_update, name="prestation_create"),
|
||||
url(r"^prestation/update/(?P<prestation_id>[0-9]+)/$", prestation_create_or_update, name="prestation_update"),
|
||||
]
|
||||
|
|
|
@ -20,7 +20,7 @@ from .models import (
|
|||
from .forms import (
|
||||
ClientForm,
|
||||
ContractForm,
|
||||
# PrestationForm,
|
||||
PrestationForm,
|
||||
)
|
||||
|
||||
from tools.pdf_generator import BillPaper
|
||||
|
@ -34,7 +34,7 @@ def client_lookup(request):
|
|||
|
||||
if pattern is not None and len(pattern) >= 3:
|
||||
results = Client.objects.filter(
|
||||
Q(name__icontains=pattern) | Q(city__icontains=pattern)
|
||||
Q(name__icontains=pattern) | Q(contact__icontains=pattern) | Q(city__icontains=pattern)
|
||||
)
|
||||
client_list = [{"ID": x.id, "name": str(x)} for x in results]
|
||||
|
||||
|
@ -138,7 +138,7 @@ def contract_create_or_update(request, contract_id=None):
|
|||
|
||||
if form.is_valid():
|
||||
contract = form.save()
|
||||
return HttpResponseRedirect(reverse("contract_details", args=(contract.pk, )))
|
||||
return HttpResponseRedirect(reverse("billing:contract_details", args=(contract.pk, )))
|
||||
|
||||
else:
|
||||
form = ContractForm(instance=contract)
|
||||
|
@ -173,3 +173,44 @@ def prestation_listing(request):
|
|||
prestation_list = Prestation.objects.all()
|
||||
context = {"prestation_list": prestation_list}
|
||||
return render(request, "prestation_listing.html", context)
|
||||
|
||||
|
||||
@require_http_methods(["GET", "POST"])
|
||||
def prestation_create_or_update(request, prestation_id=None):
|
||||
""" Création d'un contract.
|
||||
|
||||
Args:
|
||||
prestation_id (int): identifiant d'un prestation.
|
||||
"""
|
||||
|
||||
if prestation_id:
|
||||
prestation = get_object_or_404(Prestation, pk=prestation_id)
|
||||
else:
|
||||
prestation = None
|
||||
|
||||
if request.method == "POST":
|
||||
form = PrestationForm(request.POST, instance=prestation)
|
||||
|
||||
if form.is_valid():
|
||||
prestation = form.save()
|
||||
return HttpResponseRedirect(reverse("prestation_details", args=(prestation.pk, )))
|
||||
|
||||
else:
|
||||
form = PrestationForm(instance=prestation)
|
||||
|
||||
context = {"form": form, "prestation_id": prestation_id}
|
||||
return render(request, "prestation_create_or_update.html", context)
|
||||
|
||||
|
||||
@require_http_methods(["GET"])
|
||||
def contract_lookup(request):
|
||||
""" Récupère la liste des clients à la volée suivant des caractères de recherches entrés.
|
||||
"""
|
||||
pattern = request.GET.get("pattern", 0)
|
||||
|
||||
if pattern is not None and len(pattern) >= 3:
|
||||
results = Contract.objects.filter(Q(name__icontains=pattern))
|
||||
contract_list = [{"ID": x.id, "name": str(x)} for x in results]
|
||||
|
||||
json = simplejson.dumps(contract_list)
|
||||
return HttpResponse(json, content_type="application/json")
|
||||
|
|
|
@ -29,6 +29,7 @@ INSTALLED_APPS = [
|
|||
"eventCompta.apps.ManagementConfig",
|
||||
"billing.apps.BillingConfig",
|
||||
"django.contrib.humanize",
|
||||
"django_select2",
|
||||
]
|
||||
|
||||
MIDDLEWARE = [
|
||||
|
|
|
@ -19,6 +19,7 @@ from django.contrib import admin
|
|||
from comptabilite.views import year_listing
|
||||
|
||||
urlpatterns = [
|
||||
url(r'^select2/', include('django_select2.urls')),
|
||||
url(r"^$", year_listing),
|
||||
url(r"^admin/", admin.site.urls),
|
||||
url(
|
||||
|
|
|
@ -12,7 +12,7 @@
|
|||
</div>
|
||||
<div class="row">
|
||||
<div class="col-md-6 col-lg-6 col-xl-6 col-md-offset-3 col-lg-offset-3 col-xl-offset-3">
|
||||
<form action="{% url 'billing:client_create' %}" method="post" class="form-horizontal" id="formulaire" name="formulaire">
|
||||
<form action="{% if client_id %}{% url 'billing:client_update' client_id %}{% else %}{% url 'billing:client_create' %}{% endif %}" method="post" class="form-horizontal" id="formulaire" name="formulaire">
|
||||
{% csrf_token %}
|
||||
<div class="form-group row ">
|
||||
<label for="id_date" class="col-4 col-sm-2 col-md-2 col-lg-2 col-xl-2 col-form-label">Nom</label>
|
||||
|
|
|
@ -8,17 +8,15 @@
|
|||
<div id="content">
|
||||
<div class="row">
|
||||
<div class="col-xs-12 col-sm-12 col-md-12 col-lg-12">
|
||||
<h1>Détails client</h1>
|
||||
<h1>Détails {{ client.name }}</h1>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col-xs-12 col-sm-12 col-md-12 col-lg-12">
|
||||
{{ client.name }}
|
||||
{{ client.company_number }}
|
||||
{{ client.contact }}
|
||||
{{ client.address }}
|
||||
{{ client.postal_code }}
|
||||
{{ client.city }}
|
||||
<p><b>Nom Client : </b>{{ client.name }}</p>
|
||||
<p><b>N° BCE : </b>{{ client.company_number }}</p>
|
||||
<p><b>Nom de contact : </b>{{ client.contact }}</p>
|
||||
<p><b>Adresse : </b>{{ client.address }} - {{ client.postal_code }} {{ client.city }}</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
@ -25,7 +25,7 @@
|
|||
{% for client in client_list %}
|
||||
<tr>
|
||||
<td><a href="{% url 'billing:client_details' client.id %}">{{ client.name }}</a></td>
|
||||
<td>{{ client.company_number }}</td>
|
||||
<td>{% if client.company_number %}{{ client.company_number }}{% endif %}</td>
|
||||
<td>{{ client.contact }}</td>
|
||||
<td>{{ client.address }}</td>
|
||||
<td>{{ client.postal_code }}</td>
|
||||
|
|
|
@ -7,57 +7,22 @@
|
|||
<div id="content">
|
||||
<div class="row">
|
||||
<div class="col-md-12 col-lg-12">
|
||||
<h1>{% if client_id %}Modification{% else %}Nouveau{% endif %} Contrat</h1>
|
||||
<h1>{% if contract_id %}Modification{% else %}Nouveau{% endif %} Contrat</h1>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col-md-6 col-l-6 col-xl-6 col-md-offset-3 col-l-offset-3 col-xl-offset-3">
|
||||
<form action="{% url 'billing:client_create' %}" method="post" class="form-horizontal" id="formulaire" name="formulaire">
|
||||
<form action="{% if contract_id %}{% url 'billing:contract_update' contract_id %}{% else %}{% url 'billing:contract_create' %}{% endif %}" method="post" class="form" id="formulaire" name="formulaire">
|
||||
{% csrf_token %}
|
||||
|
||||
<div class="form-group row ">
|
||||
<label for="id_name" class="col-4 col-sm-2 col-md-2 col-lg-2 col-xl-2 col-form-label">{{ form.name.label }}</label>
|
||||
<div class="col-8 col-sm-6 col-md-4 col-lg-4 col-xl-4 {% if form.date.errors %}has-danger{% endif %}">
|
||||
{{ form.name }}
|
||||
{% if form.name.errors %}<span class="btn btn-sm btn-danger-outline">{% for error in form.name.errors %}{{error}}{% endfor %}</span>{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group row ">
|
||||
<label for="id_client" class="col-4 col-sm-2 col-md-2 col-lg-2 col-xl-2 col-form-label">{{ form.client.label }}</label>
|
||||
<div class="col-sm-3 col-md-3 col-lg-3 col-xl-3 {% if form.gymnast.errors %}has-danger{% endif %}">
|
||||
{{ form.client }}
|
||||
{{ form.client_related }}
|
||||
{% if form.client.errors %} <span class="btn btn-sm btn-danger-outline">{% for error in form.client.errors %}{{error}}{% endfor %}</span>{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group row ">
|
||||
<label for="id_advance" class="col-4 col-sm-2 col-md-2 col-lg-2 col-xl-2 col-form-label">{{ form.advance.label }}</label>
|
||||
<div class="col-sm-3 col-md-3 col-lg-3 col-xl-3 {% if form.educative.errors %}has-danger{% endif %}">
|
||||
{{ form.advance }}
|
||||
{% if form.advance.errors %} <span class="btn btn-sm btn-danger-outline">{% for error in form.advance.errors %}{{error}}{% endfor %}</span>{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group row ">
|
||||
<label for="id_is_finished" class="col-4 col-sm-2 col-md-2 col-lg-2 col-xl-2 col-form-label">{{ form.is_finished.label }} ?</label>
|
||||
<div class="col-8 col-sm-8 col-md-6 col-lg-6 col-xl-6 {% if form.educative.errors %}has-danger{% endif %}">
|
||||
{{ form.is_finished }}
|
||||
{% if form.is_finished.errors %} <span class="btn btn-sm btn-danger-outline">{% for error in form.is_finished.errors %}{{error}}{% endfor %}</span>{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group row ">
|
||||
<label for="id_is_finished" class="col-4 col-sm-2 col-md-2 col-lg-2 col-xl-2 col-form-label">{{ form.is_paid.label }} ?</label>
|
||||
<div class="col-8 col-sm-8 col-md-6 col-lg-6 col-xl-6 {% if form.educative.errors %}has-danger{% endif %}">
|
||||
{{ form.is_paid }}
|
||||
{% if form.is_paid.errors %} <span class="btn btn-sm btn-danger-outline">{% for error in form.is_paid.errors %}{{error}}{% endfor %}</span>{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group row ">
|
||||
<label for="id_reference" class="col-4 col-sm-2 col-md-2 col-lg-2 col-xl-2 col-form-label">{{ form.reference.label }}</label>
|
||||
<div class="col-sm-3 col-md-3 col-lg-3 col-xl-3 {% if form.reference.errors %}has-danger{% endif %}">
|
||||
{{ form.reference }}
|
||||
{% if form.reference.errors %} <span class="btn btn-sm btn-danger-outline">{% for error in form.reference.errors %}{{error}}{% endfor %}</span>{% endif %}
|
||||
</div>
|
||||
{% for field in form %}
|
||||
<div class="form-group">
|
||||
<label for="">{{ field.label_tag }}</label>
|
||||
{{ field }}
|
||||
{% if field.errors %}<span class="btn btn-sm btn-danger-outline">{% for error in field.errors %}{{error}}{% endfor %}</span>{% endif %}
|
||||
</div>
|
||||
{% endfor %}
|
||||
|
||||
<div class="form-group text-center">
|
||||
<input type="submit" value="{% if client_id %}Sauvegarder{% else %}Ajouter{% endif %}" class="btn btn-warning" />
|
||||
</div>
|
||||
|
@ -69,37 +34,4 @@
|
|||
</div>
|
||||
</div>
|
||||
|
||||
<script type="text/javascript" >
|
||||
$(function(){
|
||||
$('#id_client_related').autocomplete({
|
||||
source: function(request, response){
|
||||
$.ajax({
|
||||
url: '/billing/client/lookup/?pattern=' + $('#id_client_related').val(),
|
||||
dataType: "json",
|
||||
success: function(data){
|
||||
if(data.length != 0){
|
||||
response($.map(data, function(item){
|
||||
return {
|
||||
label: item.Name,
|
||||
value: item.Name,
|
||||
clientid: item.ID
|
||||
}
|
||||
}))
|
||||
} else {
|
||||
response([{ label: 'No result found.', value: '' }]);
|
||||
};
|
||||
},
|
||||
|
||||
error: function(exception){
|
||||
console.log(exception);
|
||||
}
|
||||
});
|
||||
},
|
||||
minLength: 3,
|
||||
select: function(event, ui){
|
||||
$($(this).data('ref')).val(ui.item.clientid);
|
||||
}
|
||||
});
|
||||
});
|
||||
</script>
|
||||
{% endblock %}
|
|
@ -13,7 +13,7 @@
|
|||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col-xs-12 col-sm-12 col-md-10 col-lg-8 col-md-offset-1 col-lg-offset-2">
|
||||
<div class="col-xs-12 col-sm-12 col-md-12 col-lg-12">
|
||||
<table class="table table-striped table-bordered table-condensed">
|
||||
<thead>
|
||||
<th>Date</th>
|
||||
|
@ -36,8 +36,17 @@
|
|||
<td class="push-right"><b>{{ total|floatformat:2|intdot }}</b></td>
|
||||
</tr>
|
||||
</table>
|
||||
<p class="right"><a href="/billing/contract/pdf/{{ contract.id }}" class="btn btn-default btn-primary" role="button">Facture PDF</a></p>
|
||||
</div>
|
||||
|
||||
<div class="col-xs-6 col-sm-6 col-md-6 col-lg-6">
|
||||
<a href="/billing/contract/pdf/{{ contract.id }}" class="btn btn-default btn-success" role="button">Facture PDF</a>
|
||||
</div>
|
||||
<div class="col-xs-6 col-sm-6 col-md-6 col-lg-6">
|
||||
<p class="text-right">
|
||||
<a href="{% url 'billing:prestation_create' %}" class="btn btn-default btn-primary" role="button">Ajouter prestation</a>
|
||||
</p>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
@ -33,7 +33,9 @@
|
|||
</tr>
|
||||
{% endfor %}
|
||||
</table>
|
||||
<a href="{% url 'billing:contract_create' %}">Nouveau contrat</a>
|
||||
<p class="text-right">
|
||||
<a class="btn btn-primary" href="{% url 'billing:contract_create' %}">Nouveau contrat</a>
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
@ -0,0 +1,98 @@
|
|||
{% extends "base.html" %}
|
||||
|
||||
{% block content %}
|
||||
<div id="page" class=" sidebar_right">
|
||||
<div class="container">
|
||||
<div id="frame2">
|
||||
<div id="content">
|
||||
<div class="row">
|
||||
<div class="col-md-12 col-lg-12">
|
||||
<h1>{% if prestation_id %}Modification{% else %}Nouvelle{% endif %} Prestation</h1>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col-md-6 col-l-6 col-xl-6 col-md-offset-3 col-l-offset-3 col-xl-offset-3">
|
||||
<form action="{% if prestation_id %}{% url 'billing:prestation_update' prestation_id %}{% else %}{% url 'billing:prestation_create' %}{% endif %}" method="post" class="form-horizontal" id="formulaire" name="formulaire">
|
||||
{% csrf_token %}
|
||||
|
||||
<div class="form-group row ">
|
||||
<label for="id_contract" class="col-sm-4 col-md-4 col-lg-3 col-xl-2 col-form-label">{{ form.contract.label }}</label>
|
||||
<div class="col-sm-6 col-md-6 col-lg-6 col-xl-6 {% if form.gymnast.errors %}has-danger{% endif %}">
|
||||
{{ form.contract }}
|
||||
{{ form.contract_related }}
|
||||
{% if form.contract.errors %} <span class="btn btn-sm btn-danger-outline">{% for error in form.contract.errors %}{{error}}{% endfor %}</span>{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group row ">
|
||||
<label for="id_date" class="col-sm-4 col-md-4 col-lg-3 col-xl-2 col-form-label">{{ form.date.label }}</label>
|
||||
<div class="col-sm-3 col-md-3 col-lg-3 col-xl-3 {% if form.date.errors %}has-danger{% endif %}">
|
||||
{{ form.date }}
|
||||
{% if form.date.errors %} <span class="btn btn-sm btn-danger-outline">{% for error in form.date.errors %}{{error}}{% endfor %}</span>{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group row ">
|
||||
<label for="id_label" class="col-sm-4 col-md-4 col-lg-3 col-xl-2 col-form-label">{{ form.label.label }}</label>
|
||||
<div class="col-sm-6 col-md-6 col-lg-6 col-xl-6 {% if form.label.errors %}has-danger{% endif %}">
|
||||
{{ form.label }}
|
||||
{% if form.label.errors %} <span class="btn btn-sm btn-danger-outline">{% for error in form.label.errors %}{{error}}{% endfor %}</span>{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group row ">
|
||||
<label for="id_unit" class="col-sm-4 col-md-4 col-lg-3 col-xl-2 col-form-label">{{ form.unit.label }}</label>
|
||||
<div class="col-sm-3 col-md-3 col-lg-3 col-xl-3 {% if form.unit.errors %}has-danger{% endif %}">
|
||||
{{ form.unit }}
|
||||
{% if form.unit.errors %} <span class="btn btn-sm btn-danger-outline">{% for error in form.unit.errors %}{{error}}{% endfor %}</span>{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group row ">
|
||||
<label for="id_unit_price" class="col-sm-4 col-md-4 col-lg-3 col-xl-2 col-form-label">{{ form.unit_price.label }}</label>
|
||||
<div class="col-sm-3 col-md-3 col-lg-3 col-xl-3 {% if form.unit_price.errors %}has-danger{% endif %}">
|
||||
{{ form.unit_price }}
|
||||
{% if form.unit_price.errors %} <span class="btn btn-sm btn-danger-outline">{% for error in form.unit_price.errors %}{{error}}{% endfor %}</span>{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group text-center">
|
||||
<input type="submit" value="{% if client_id %}Sauvegarder{% else %}Ajouter{% endif %}" class="btn btn-primary" />
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script type="text/javascript" >
|
||||
$(function(){
|
||||
$('#id_contract_related').autocomplete({
|
||||
source: function(request, response){
|
||||
$.ajax({
|
||||
url: '/billing/contract/lookup/?pattern=' + $('#id_contract_related').val(),
|
||||
dataType: "json",
|
||||
success: function(data){
|
||||
if(data.length != 0){
|
||||
response($.map(data, function(item){
|
||||
return {
|
||||
label: item.Name,
|
||||
value: item.Name,
|
||||
contractid: item.ID
|
||||
}
|
||||
}))
|
||||
} else {
|
||||
response([{ label: 'No result found.', value: '' }]);
|
||||
};
|
||||
},
|
||||
|
||||
error: function(exception){
|
||||
console.log(exception);
|
||||
}
|
||||
});
|
||||
},
|
||||
minLength: 3,
|
||||
select: function(event, ui){
|
||||
$($(this).data('ref')).val(ui.item.contractid);
|
||||
}
|
||||
});
|
||||
});
|
||||
</script>
|
||||
{% endblock %}
|
Loading…
Reference in New Issue