diff --git a/eo_gestion/eo_facture/admin.py b/eo_gestion/eo_facture/admin.py
index b24b50c..2e8a1d1 100644
--- a/eo_gestion/eo_facture/admin.py
+++ b/eo_gestion/eo_facture/admin.py
@@ -152,8 +152,11 @@ class ClientAdmin(admin.ModelAdmin):
def show_client(obj):
- url = reverse('admin:eo_facture_client_change', args=[obj.client.id])
- return format_html('{1}', url, obj.client)
+ if obj.client:
+ url = reverse('admin:eo_facture_client_change', args=[obj.client.id])
+ return format_html('{1}', url, obj.client)
+ else:
+ return ""
show_client.short_description = 'Client'
diff --git a/eo_gestion/eo_facture/forms.py b/eo_gestion/eo_facture/forms.py
index 16b52ba..5227b78 100644
--- a/eo_gestion/eo_facture/forms.py
+++ b/eo_gestion/eo_facture/forms.py
@@ -21,6 +21,7 @@ from decimal import Decimal
from django import forms
from django.contrib.admin import widgets
from django.core.exceptions import ValidationError
+from django.db.models import Q
from django.db.transaction import atomic
from . import models
@@ -149,7 +150,11 @@ class FactureForm(forms.ModelForm):
pass # invalid input from client; ignore and fallback to empty Contrat queryset
if client_id:
- self.fields['contrat'].queryset = models.Contrat.objects.filter(client_id=client_id)
+ self.fields['contrat'].queryset = models.Contrat.objects.filter(
+ Q(client_id=client_id) | Q(client__isnull=True)
+ )
+ else:
+ self.fields['contrat'].queryset = models.Contrat.objects.filter(client__isnull=True)
def clean_proforma(self):
if not self.instance.proforma and 'proforma' in self.changed_data:
@@ -205,6 +210,7 @@ class ContratForm(forms.ModelForm):
self.fields['periodicite_debut'].widget.attrs['data-depends-on'] = 'periodicite'
if 'periodicite_fin' in self.fields:
self.fields['periodicite_fin'].widget.attrs['data-depends-on'] = 'periodicite'
+ self.fields['client'].required = False
class Meta:
fields = '__all__'
diff --git a/eo_gestion/eo_facture/migrations/0019_alter_contrat_client.py b/eo_gestion/eo_facture/migrations/0019_alter_contrat_client.py
new file mode 100644
index 0000000..796a159
--- /dev/null
+++ b/eo_gestion/eo_facture/migrations/0019_alter_contrat_client.py
@@ -0,0 +1,24 @@
+# Generated by Django 3.2.17 on 2023-02-16 15:46
+
+import django.db.models.deletion
+from django.db import migrations, models
+
+
+class Migration(migrations.Migration):
+
+ dependencies = [
+ ('eo_facture', '0018_client_notes_privees'),
+ ]
+
+ operations = [
+ migrations.AlterField(
+ model_name='contrat',
+ name='client',
+ field=models.ForeignKey(
+ null=True,
+ on_delete=django.db.models.deletion.CASCADE,
+ related_name='contrats',
+ to='eo_facture.client',
+ ),
+ ),
+ ]
diff --git a/eo_gestion/eo_facture/models.py b/eo_gestion/eo_facture/models.py
index 46e2fde..9eb8f34 100644
--- a/eo_gestion/eo_facture/models.py
+++ b/eo_gestion/eo_facture/models.py
@@ -126,7 +126,7 @@ def one_hundred_percent_this_year():
class Contrat(models.Model):
- client = models.ForeignKey(Client, related_name="contrats", on_delete=models.CASCADE)
+ client = models.ForeignKey(Client, related_name="contrats", on_delete=models.CASCADE, null=True)
intitule = models.CharField(max_length=150)
description = models.TextField(blank=True)
public_description = models.TextField(
@@ -230,12 +230,6 @@ class Contrat(models.Model):
montant_par_annee[today_year] += adjust
return montant_par_annee
- def nom_client(self):
- """
- Le nom du client qui a signé ce contrat avec EO.
- """
- return self.client.nom
-
def clean(self):
self.numero_marche = self.numero_marche.strip()
@@ -489,7 +483,7 @@ class Facture(models.Model):
if not self.intitule:
self.intitule = self.contrat.intitule
if self.client:
- if self.client != self.contrat.client:
+ if self.client != self.contrat.client and self.contrat.client is not None:
raise ValidationError("Le client de la facture et du contrat doivent être identiques.")
else:
self.client = self.contrat.client
@@ -737,11 +731,14 @@ class Ligne(models.Model):
ordering = ("order",)
def __str__(self):
- return "%s pour %s %s" % (
- self.intitule,
- self.montant,
- self.facture.client.monnaie,
- )
+ if self.facture.client:
+ return "%s pour %s %s" % (
+ self.intitule,
+ self.montant,
+ self.facture.client.monnaie,
+ )
+ else:
+ return "%s pour %s €" % (self.intitule, self.montant)
def encaissements_avec_solde_non_affecte():
diff --git a/eo_gestion/eo_facture/templates/admin/eo_facture/facture/change_form.html b/eo_gestion/eo_facture/templates/admin/eo_facture/facture/change_form.html
index ed013c7..dd83c63 100644
--- a/eo_gestion/eo_facture/templates/admin/eo_facture/facture/change_form.html
+++ b/eo_gestion/eo_facture/templates/admin/eo_facture/facture/change_form.html
@@ -3,6 +3,7 @@
{% block extrahead %}{{ block.super }}
{% if add and not original.client %}
+{% if not original.contrat or original.contrat.client %}
{% endif %}
+{% endif %}
{% endblock %}
{% block object-tools %}
diff --git a/eo_gestion/eo_facture/templatetags/eo_facture.py b/eo_gestion/eo_facture/templatetags/eo_facture.py
index 4454e8d..773c267 100644
--- a/eo_gestion/eo_facture/templatetags/eo_facture.py
+++ b/eo_gestion/eo_facture/templatetags/eo_facture.py
@@ -154,9 +154,12 @@ class StringWithHref(str):
def client_and_link(c):
- s = str(c)
- url = reverse("admin:eo_facture_client_change", args=(c.id,))
- return StringWithHref(s, url)
+ if c is not None:
+ s = str(c)
+ url = reverse("admin:eo_facture_client_change", args=(c.id,))
+ return StringWithHref(s, url)
+ else:
+ return ""
def dict_of_list():