eo_facture: autoriser les contrats sans clients (#74608)
gitea/barbacompta/pipeline/head This commit looks good Details

This commit is contained in:
Pierre Ducroquet 2023-02-16 16:04:44 +01:00
parent c235781e7c
commit d2b03f4a1b
6 changed files with 54 additions and 19 deletions

View File

@ -152,8 +152,11 @@ class ClientAdmin(admin.ModelAdmin):
def show_client(obj): def show_client(obj):
url = reverse('admin:eo_facture_client_change', args=[obj.client.id]) if obj.client:
return format_html('<a href="{0}">{1}</a>', url, obj.client) url = reverse('admin:eo_facture_client_change', args=[obj.client.id])
return format_html('<a href="{0}">{1}</a>', url, obj.client)
else:
return ""
show_client.short_description = 'Client' show_client.short_description = 'Client'

View File

@ -21,6 +21,7 @@ from decimal import Decimal
from django import forms from django import forms
from django.contrib.admin import widgets from django.contrib.admin import widgets
from django.core.exceptions import ValidationError from django.core.exceptions import ValidationError
from django.db.models import Q
from django.db.transaction import atomic from django.db.transaction import atomic
from . import models from . import models
@ -149,7 +150,11 @@ class FactureForm(forms.ModelForm):
pass # invalid input from client; ignore and fallback to empty Contrat queryset pass # invalid input from client; ignore and fallback to empty Contrat queryset
if client_id: 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): def clean_proforma(self):
if not self.instance.proforma and 'proforma' in self.changed_data: 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' self.fields['periodicite_debut'].widget.attrs['data-depends-on'] = 'periodicite'
if 'periodicite_fin' in self.fields: if 'periodicite_fin' in self.fields:
self.fields['periodicite_fin'].widget.attrs['data-depends-on'] = 'periodicite' self.fields['periodicite_fin'].widget.attrs['data-depends-on'] = 'periodicite'
self.fields['client'].required = False
class Meta: class Meta:
fields = '__all__' fields = '__all__'

View File

@ -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',
),
),
]

View File

@ -126,7 +126,7 @@ def one_hundred_percent_this_year():
class Contrat(models.Model): 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) intitule = models.CharField(max_length=150)
description = models.TextField(blank=True) description = models.TextField(blank=True)
public_description = models.TextField( public_description = models.TextField(
@ -230,12 +230,6 @@ class Contrat(models.Model):
montant_par_annee[today_year] += adjust montant_par_annee[today_year] += adjust
return montant_par_annee 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): def clean(self):
self.numero_marche = self.numero_marche.strip() self.numero_marche = self.numero_marche.strip()
@ -489,7 +483,7 @@ class Facture(models.Model):
if not self.intitule: if not self.intitule:
self.intitule = self.contrat.intitule self.intitule = self.contrat.intitule
if self.client: 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.") raise ValidationError("Le client de la facture et du contrat doivent être identiques.")
else: else:
self.client = self.contrat.client self.client = self.contrat.client
@ -737,11 +731,14 @@ class Ligne(models.Model):
ordering = ("order",) ordering = ("order",)
def __str__(self): def __str__(self):
return "%s pour %s %s" % ( if self.facture.client:
self.intitule, return "%s pour %s %s" % (
self.montant, self.intitule,
self.facture.client.monnaie, self.montant,
) self.facture.client.monnaie,
)
else:
return "%s pour %s" % (self.intitule, self.montant)
def encaissements_avec_solde_non_affecte(): def encaissements_avec_solde_non_affecte():

View File

@ -3,6 +3,7 @@
{% block extrahead %}{{ block.super }} {% block extrahead %}{{ block.super }}
{% if add and not original.client %} {% if add and not original.client %}
{% if not original.contrat or original.contrat.client %}
<script type="text/javascript"> <script type="text/javascript">
window.addEventListener("load", function(){ window.addEventListener("load", function(){
let client_selector = document.getElementById("id_client"); let client_selector = document.getElementById("id_client");
@ -18,6 +19,7 @@ window.addEventListener("load", function(){
}); });
</script> </script>
{% endif %} {% endif %}
{% endif %}
{% endblock %} {% endblock %}
{% block object-tools %} {% block object-tools %}

View File

@ -154,9 +154,12 @@ class StringWithHref(str):
def client_and_link(c): def client_and_link(c):
s = str(c) if c is not None:
url = reverse("admin:eo_facture_client_change", args=(c.id,)) s = str(c)
return StringWithHref(s, url) url = reverse("admin:eo_facture_client_change", args=(c.id,))
return StringWithHref(s, url)
else:
return ""
def dict_of_list(): def dict_of_list():