diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml
new file mode 100644
index 0000000..ce247d6
--- /dev/null
+++ b/.pre-commit-config.yaml
@@ -0,0 +1,18 @@
+# See https://pre-commit.com for more information
+# See https://pre-commit.com/hooks.html for more hooks
+repos:
+- repo: https://github.com/psf/black
+ rev: 20.8b1
+ hooks:
+ - id: black
+ args: ['--target-version', 'py37', '--skip-string-normalization', '--line-length', '110']
+- repo: https://github.com/PyCQA/isort
+ rev: 5.7.0
+ hooks:
+ - id: isort
+ args: ['--profile', 'black', '--line-length', '110']
+- repo: https://github.com/asottile/pyupgrade
+ rev: v2.20.0
+ hooks:
+ - id: pyupgrade
+ args: ['--keep-percent-format', '--py37-plus']
diff --git a/eo_gestion/actions.py b/eo_gestion/actions.py
index 9621567..29b1dfb 100644
--- a/eo_gestion/actions.py
+++ b/eo_gestion/actions.py
@@ -15,9 +15,9 @@
# along with this program. If not, see .
import csv
-from io import BytesIO
import os
import zipfile
+from io import BytesIO
from django.core.exceptions import PermissionDenied
from django.http import HttpResponse
@@ -65,7 +65,7 @@ def export_references_as_fodt(modeladmin, request, queryset):
output_filename = 'references.fodt'
mimetype = 'application/vnd.oasis.opendocument.text'
- t = Template(open(template, 'r').read())
+ t = Template(open(template).read())
export = t.render(Context(context)).encode('utf-8')
response = HttpResponse(content=export, content_type=mimetype)
diff --git a/eo_gestion/admin.py b/eo_gestion/admin.py
index f3149c0..3ff9f41 100644
--- a/eo_gestion/admin.py
+++ b/eo_gestion/admin.py
@@ -14,17 +14,16 @@
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see .
+import taggit.admin
from django.conf import settings
from django.contrib import admin
from django.contrib.auth import REDIRECT_FIELD_NAME
-from django.contrib.auth.models import User, Group
-from django.contrib.auth.admin import UserAdmin, GroupAdmin
+from django.contrib.auth.admin import GroupAdmin, UserAdmin
+from django.contrib.auth.models import Group, User
from django.http import HttpResponseRedirect
from django.utils.http import urlencode
from django.views.decorators.cache import never_cache
-import taggit.admin
-
class EOGestionAdminSite(admin.AdminSite):
@never_cache
@@ -32,18 +31,18 @@ class EOGestionAdminSite(admin.AdminSite):
if "mellon" in settings.INSTALLED_APPS:
next_url = request.GET.get(REDIRECT_FIELD_NAME, settings.LOGIN_REDIRECT_URL or "/")
query = urlencode({REDIRECT_FIELD_NAME: next_url})
- url = "/accounts/mellon/login/?{0}".format(query)
+ url = f"/accounts/mellon/login/?{query}"
return HttpResponseRedirect(url)
- return super(EOGestionAdminSite, self).login(request, extra_context=extra_context)
+ return super().login(request, extra_context=extra_context)
@never_cache
def logout(self, request, extra_context=None):
if "mellon" in settings.INSTALLED_APPS:
next_url = request.GET.get(REDIRECT_FIELD_NAME, settings.LOGIN_REDIRECT_URL or "/")
query = urlencode({REDIRECT_FIELD_NAME: next_url})
- url = "/accounts/mellon/logout/?{0}".format(query)
+ url = f"/accounts/mellon/logout/?{query}"
return HttpResponseRedirect(url)
- return super(EOGestionAdminSite, self).logout(request, extra_context=extra_context)
+ return super().logout(request, extra_context=extra_context)
site = EOGestionAdminSite()
diff --git a/eo_gestion/chorus/admin.py b/eo_gestion/chorus/admin.py
index 6002a1e..7c66bfc 100644
--- a/eo_gestion/chorus/admin.py
+++ b/eo_gestion/chorus/admin.py
@@ -15,6 +15,7 @@
# along with this program. If not, see .
from django.contrib import admin
+
import eo_gestion.admin
from . import models
diff --git a/eo_gestion/chorus/annuaire.py b/eo_gestion/chorus/annuaire.py
index 2e6e38a..5a3eee7 100644
--- a/eo_gestion/chorus/annuaire.py
+++ b/eo_gestion/chorus/annuaire.py
@@ -15,14 +15,12 @@
# along with this program. If not, see .
import itertools
-import zipfile
-
-from xml.dom import pulldom
import xml.etree.ElementTree as ET
-
-from django.core.files.storage import default_storage
+import zipfile
+from xml.dom import pulldom
import requests
+from django.core.files.storage import default_storage
from . import chorus
@@ -34,7 +32,7 @@ def grouper(iterable, n, fillvalue=None):
return itertools.zip_longest(*args, fillvalue=fillvalue)
-class AnnuaireManager(object):
+class AnnuaireManager:
STRUCTURE_UNITAIRE_TAG_NAME = 'CPPStructurePartenaireUnitaire'
def _update_annuaire(self):
@@ -48,7 +46,7 @@ class AnnuaireManager(object):
structures = [struct for struct in structures if struct] # ignore None
inserts = []
updates = []
- identifiers = set(structure.full_identifier for structure in structures)
+ identifiers = {structure.full_identifier for structure in structures}
known.update(identifiers)
known_structures = {
struct.full_identifier: struct
diff --git a/eo_gestion/chorus/chorus.py b/eo_gestion/chorus/chorus.py
index 087d44a..8170765 100644
--- a/eo_gestion/chorus/chorus.py
+++ b/eo_gestion/chorus/chorus.py
@@ -17,11 +17,10 @@
import base64
import logging
+import requests
from django.conf import settings
from django.utils.encoding import force_text
-import requests
-
from eo_gestion.decorators import cache
logger = logging.getLogger(__name__)
diff --git a/eo_gestion/chorus/migrations/0001_initial.py b/eo_gestion/chorus/migrations/0001_initial.py
index 81326c9..a6faac2 100644
--- a/eo_gestion/chorus/migrations/0001_initial.py
+++ b/eo_gestion/chorus/migrations/0001_initial.py
@@ -1,6 +1,7 @@
# Generated by Django 2.2.9 on 2020-02-04 09:08
from django.db import migrations, models
+
import eo_gestion.chorus.validators
@@ -31,7 +32,9 @@ class Migration(migrations.Migration):
('email', models.EmailField(max_length=254, null=True)),
('engagement_obligatoire', models.BooleanField()),
],
- options={'ordering': ('name', 'service_name'),},
+ options={
+ 'ordering': ('name', 'service_name'),
+ },
),
migrations.CreateModel(
name='Update',
@@ -46,6 +49,7 @@ class Migration(migrations.Migration):
],
),
migrations.AddIndex(
- model_name='structure', index=models.Index(fields=['name', 'service_name'], name='name_idx'),
+ model_name='structure',
+ index=models.Index(fields=['name', 'service_name'], name='name_idx'),
),
]
diff --git a/eo_gestion/chorus/models.py b/eo_gestion/chorus/models.py
index 8fbafcb..f96e9d9 100644
--- a/eo_gestion/chorus/models.py
+++ b/eo_gestion/chorus/models.py
@@ -20,22 +20,30 @@ from .validators import validate_siret
class Update(models.Model):
- timestamp = models.DateTimeField(auto_now_add=True,)
- success = models.BooleanField(default=False,)
+ timestamp = models.DateTimeField(
+ auto_now_add=True,
+ )
+ success = models.BooleanField(
+ default=False,
+ )
message = models.TextField()
class Structure(models.Model):
name = models.CharField(max_length=80)
full_identifier = models.CharField(max_length=len('29202001300010') + 64, unique=True)
- siret = models.CharField(max_length=len('29202001300010'), validators=[validate_siret], db_index=True,)
+ siret = models.CharField(
+ max_length=len('29202001300010'),
+ validators=[validate_siret],
+ db_index=True,
+ )
service_code = models.CharField(max_length=64, default='', blank=True)
service_name = models.CharField(max_length=80, default='', blank=True)
email = models.EmailField(null=True)
engagement_obligatoire = models.BooleanField()
def __init__(self, *args, **kwargs):
- super(Structure, self).__init__(*args, **kwargs)
+ super().__init__(*args, **kwargs)
if not self.full_identifier:
self.full_identifier = (self.siret + self.service_code)[: len('29202001300010') + 64]
diff --git a/eo_gestion/eo_banque/admin.py b/eo_gestion/eo_banque/admin.py
index 3dfbdd5..c26f585 100644
--- a/eo_gestion/eo_banque/admin.py
+++ b/eo_gestion/eo_banque/admin.py
@@ -17,11 +17,12 @@
from django.contrib import admin
from django.contrib.contenttypes.admin import GenericStackedInline
-from django.db.models import Sum, F, Q
+from django.db.models import F, Q, Sum
+from .. import actions
+from .. import admin as eo_gestion_admin
from ..eo_facture.admin import PaymentInline
from ..eo_facture.templatetags.eo_facture import amountformat
-from .. import actions, admin as eo_gestion_admin
from . import models
@@ -83,7 +84,7 @@ class LigneBanquePopAdmin(admin.ModelAdmin):
return True
def get_queryset(self, request):
- qs = super(LigneBanquePopAdmin, self).get_queryset(request)
+ qs = super().get_queryset(request)
qs = qs.prefetch_related("payments")
return qs
diff --git a/eo_gestion/eo_banque/management/commands/load-csv-banquepop.py b/eo_gestion/eo_banque/management/commands/load-csv-banquepop.py
index 468eef7..a7efabd 100644
--- a/eo_gestion/eo_banque/management/commands/load-csv-banquepop.py
+++ b/eo_gestion/eo_banque/management/commands/load-csv-banquepop.py
@@ -8,10 +8,10 @@ from eo_gestion.eo_banque.models import LigneBanquePop
class Command(BaseCommand):
- '''
- Charge un fichier CSV exporté depuis notre banque en ligne Banque
- Populaire
- '''
+ """
+ Charge un fichier CSV exporté depuis notre banque en ligne Banque
+ Populaire
+ """
can_import_django_settings = True
output_transaction = True
@@ -39,7 +39,7 @@ class Command(BaseCommand):
def load_one_file(self, csv_file_path):
for delimiter in [";", "\t"]:
- csv_file = open(csv_file_path, 'r', encoding='latin1')
+ csv_file = open(csv_file_path, encoding='latin1')
csv_lines = csv.reader(csv_file, delimiter=delimiter)
first_line = next(csv_lines)
if first_line == self.HEADER:
diff --git a/eo_gestion/eo_banque/management/commands/nouveau-solde.py b/eo_gestion/eo_banque/management/commands/nouveau-solde.py
index 438d7f6..9f21b82 100644
--- a/eo_gestion/eo_banque/management/commands/nouveau-solde.py
+++ b/eo_gestion/eo_banque/management/commands/nouveau-solde.py
@@ -7,9 +7,9 @@ from eo_gestion.eo_banque.models import SoldeBanquePop
class Command(BaseCommand):
- '''
- Charge un fichier CSV exporté depuis notre banque en ligne Baneque Populaire
- '''
+ """
+ Charge un fichier CSV exporté depuis notre banque en ligne Baneque Populaire
+ """
can_import_django_settings = True
output_transaction = True
diff --git a/eo_gestion/eo_banque/management/commands/solde.py b/eo_gestion/eo_banque/management/commands/solde.py
index 16902db..7c159b5 100644
--- a/eo_gestion/eo_banque/management/commands/solde.py
+++ b/eo_gestion/eo_banque/management/commands/solde.py
@@ -1,4 +1,4 @@
-from datetime import timedelta, date, datetime
+from datetime import date, datetime, timedelta
from django.core.management.base import BaseCommand
from django.db import transaction
@@ -7,9 +7,9 @@ from eo_gestion.eo_banque.models import solde
class Command(BaseCommand):
- '''
- Charge un fichier CSV exporté depuis notre banque en ligne Banque Populaire
- '''
+ """
+ Charge un fichier CSV exporté depuis notre banque en ligne Banque Populaire
+ """
can_import_django_settings = True
output_transaction = True
diff --git a/eo_gestion/eo_banque/migrations/0001_initial.py b/eo_gestion/eo_banque/migrations/0001_initial.py
index 819d2ba..bf72023 100644
--- a/eo_gestion/eo_banque/migrations/0001_initial.py
+++ b/eo_gestion/eo_banque/migrations/0001_initial.py
@@ -1,4 +1,4 @@
-from django.db import models, migrations
+from django.db import migrations, models
class Migration(migrations.Migration):
@@ -57,8 +57,8 @@ class Migration(migrations.Migration):
),
migrations.AlterUniqueTogether(
name='lignebanquepop',
- unique_together=set(
- [('compte', 'date_comptabilisation', 'date_operation', 'libelle', 'reference', 'montant')]
- ),
+ unique_together={
+ ('compte', 'date_comptabilisation', 'date_operation', 'libelle', 'reference', 'montant')
+ },
),
]
diff --git a/eo_gestion/eo_banque/models.py b/eo_gestion/eo_banque/models.py
index 6c7ade8..972f03c 100644
--- a/eo_gestion/eo_banque/models.py
+++ b/eo_gestion/eo_banque/models.py
@@ -16,9 +16,9 @@
from datetime import date
-from django.db import models
from django.contrib.contenttypes.fields import GenericForeignKey
from django.contrib.contenttypes.models import ContentType
+from django.db import models
from django.utils import six
@@ -44,7 +44,6 @@ def solde(t=None):
return m
-@six.python_2_unicode_compatible
class Commentaire(models.Model):
contenu = models.TextField()
content_type = models.ForeignKey(ContentType, on_delete=models.CASCADE)
@@ -56,11 +55,10 @@ class Commentaire(models.Model):
return "Commentaire créé le %s" % self.creation
-@six.python_2_unicode_compatible
class LigneBanquePop(models.Model):
- '''
- Une ligne de notre relevé de compte Banque Populaire
- '''
+ """
+ Une ligne de notre relevé de compte Banque Populaire
+ """
compte = models.CharField(max_length=20)
date_comptabilisation = models.DateField()
@@ -79,13 +77,13 @@ class LigneBanquePop(models.Model):
return "%(date_valeur)s %(libelle)s %(montant)s" % self.__dict__
def montant_non_affecte(self):
- return self.montant - sum([x.montant_affecte for x in self.payments.all()])
+ return self.montant - sum(x.montant_affecte for x in self.payments.all())
class SoldeBanquePop(models.Model):
- '''
- Le solde à un temps T, permet de calculer notre solde à toute date
- '''
+ """
+ Le solde à un temps T, permet de calculer notre solde à toute date
+ """
compte = models.CharField(max_length=20)
date = models.DateField(auto_now_add=True)
diff --git a/eo_gestion/eo_banque/templatetags/eo_banque.py b/eo_gestion/eo_banque/templatetags/eo_banque.py
index aff824e..08c866d 100644
--- a/eo_gestion/eo_banque/templatetags/eo_banque.py
+++ b/eo_gestion/eo_banque/templatetags/eo_banque.py
@@ -21,8 +21,8 @@ from django import template
from django.db.models import Sum
from django.urls import reverse
-from ..models import LigneBanquePop, solde
from ...decorators import cache
+from ..models import LigneBanquePop, solde
register = template.Library()
@@ -84,8 +84,8 @@ def finances(month=3):
def total(context):
qs = context["cl"].get_queryset(context["request"])
ls = [ligne[0] for ligne in qs.values_list("montant")]
- credit = sum([montant for montant in ls if montant > 0])
- debit = sum([montant for montant in ls if montant < 0])
+ credit = sum(montant for montant in ls if montant > 0)
+ debit = sum(montant for montant in ls if montant < 0)
total = sum(ls)
return {'credit': credit, 'debit': debit, 'total': total}
diff --git a/eo_gestion/eo_facture/admin.py b/eo_gestion/eo_facture/admin.py
index f82ae2a..abfe49d 100644
--- a/eo_gestion/eo_facture/admin.py
+++ b/eo_gestion/eo_facture/admin.py
@@ -17,35 +17,35 @@
import datetime as dt
-from django.contrib import admin
+import django.http as http
+from adminsortable2.admin import SortableInlineAdminMixin
from django.conf.urls import url
+from django.contrib import admin
+from django.contrib.admin.options import BaseModelAdmin
+from django.contrib.humanize.templatetags.humanize import ordinal
+from django.db.models import TextField
+from django.forms import Textarea
+from django.forms.models import BaseInlineFormSet
from django.shortcuts import render
from django.urls import reverse
-from django.contrib.admin.options import BaseModelAdmin
-from django.db.models import TextField
-import django.http as http
-from django.contrib.humanize.templatetags.humanize import ordinal
-from django.forms.models import BaseInlineFormSet
-from django.forms import Textarea
from django.utils.html import format_html
from django.utils.six import BytesIO
-from adminsortable2.admin import SortableInlineAdminMixin
-
-from .. import ods, actions
-from . import forms, models, views
-from .templatetags.eo_facture import amountformat
import eo_gestion.admin
+from .. import actions, ods
+from . import forms, models, views
+from .templatetags.eo_facture import amountformat
-class LookupAllowed(object):
+
+class LookupAllowed:
def lookup_allowed(self, *args, **kwargs):
return True
-class SelectRelatedMixin(object):
+class SelectRelatedMixin:
def get_queryset(self, request):
- qs = super(SelectRelatedMixin, self).get_queryset(request)
+ qs = super().get_queryset(request)
return qs.select_related()
@@ -55,7 +55,7 @@ class CommonPaymentInline(BaseModelAdmin):
kwargs['queryset'] = models.Facture.objects.avec_solde()
if db_field.name == 'ligne_banque_pop' and request.path.endswith('/add/'):
kwargs['queryset'] = models.encaissements_avec_solde_non_affecte()
- return super(CommonPaymentInline, self).formfield_for_foreignkey(db_field, request, **kwargs)
+ return super().formfield_for_foreignkey(db_field, request, **kwargs)
class PrestationInline(SelectRelatedMixin, admin.TabularInline):
@@ -70,7 +70,7 @@ class FactureInline(SelectRelatedMixin, admin.TabularInline):
class PaymentInlineFormset(BaseInlineFormSet):
def __init__(self, *args, **kwargs):
- super(PaymentInlineFormset, self).__init__(*args, **kwargs)
+ super().__init__(*args, **kwargs)
for form in self.forms:
if form.instance.id is None:
field = form.fields["ligne_banque_pop"]
@@ -135,7 +135,7 @@ class ClientAdmin(admin.ModelAdmin):
raw_id_fields = ['chorus_structure']
def get_readonly_fields(self, request, obj=None):
- readonly_fields = super(ClientAdmin, self).get_readonly_fields(request, obj=obj)
+ readonly_fields = super().get_readonly_fields(request, obj=obj)
if obj and obj.chorus_structure:
readonly_fields += ('siret', 'service_code')
return readonly_fields
@@ -186,7 +186,7 @@ class ContratAdmin(LookupAllowed, admin.ModelAdmin):
column_montant.short_description = 'Montant'
def get_queryset(self, request):
- qs = super(ContratAdmin, self).get_queryset(request)
+ qs = super().get_queryset(request)
return qs.prefetch_related('prestations', 'factures__lignes', 'tags')
def tag_list(self, obj):
@@ -223,7 +223,7 @@ class ContratAdmin(LookupAllowed, admin.ModelAdmin):
return render(request, "admin/eo_facture/contrat/duplicate.html", context=context)
def get_urls(self):
- urls = super(ContratAdmin, self).get_urls()
+ urls = super().get_urls()
duplicate_view = self.admin_site.admin_view(self.duplicate)
my_urls = [url(r'^(.+)/duplicate/$', duplicate_view, name='eo_facture_contrat_duplicate')]
return my_urls + urls
@@ -295,7 +295,7 @@ class FactureAdmin(LookupAllowed, admin.ModelAdmin):
def get_queryset(self, request):
from django.db import connection
- qs = super(FactureAdmin, self).get_queryset(request)
+ qs = super().get_queryset(request)
qs = qs.prefetch_related("lignes__facture__client")
qs = qs.prefetch_related("payments__ligne_banque_pop")
qs = qs.prefetch_related("contrat__factures")
@@ -359,7 +359,7 @@ class FactureAdmin(LookupAllowed, admin.ModelAdmin):
return response
def get_urls(self):
- urls = super(FactureAdmin, self).get_urls()
+ urls = super().get_urls()
my_urls = [
url(r'^view/([^/]*)', views.facture),
url(
@@ -378,7 +378,11 @@ class FactureAdmin(LookupAllowed, admin.ModelAdmin):
self.admin_site.admin_view(views.send_to_chorus),
name='eo_facture_facture_send_to_chorus',
),
- url(r"^sheet/$", self.admin_site.admin_view(self.sheet), name="eo_facture_facture_sheet",),
+ url(
+ r"^sheet/$",
+ self.admin_site.admin_view(self.sheet),
+ name="eo_facture_facture_sheet",
+ ),
]
return my_urls + urls
diff --git a/eo_gestion/eo_facture/facturx.py b/eo_gestion/eo_facture/facturx.py
index 7865617..34da9c7 100644
--- a/eo_gestion/eo_facture/facturx.py
+++ b/eo_gestion/eo_facture/facturx.py
@@ -19,9 +19,8 @@ import os
import subprocess
import tempfile
-from django.template.loader import render_to_string
-
import facturx
+from django.template.loader import render_to_string
logger = logging.getLogger(__name__)
@@ -50,9 +49,7 @@ def to_pdfa(pdf_bytes: bytes, icc_profile: str = DEFAULT_ICC_PROFILE):
input_fd.name,
]
logger.debug('converting to PDF/A, calling %s', args)
- completed = subprocess.run(
- args, stdout=subprocess.PIPE, stderr=subprocess.PIPE, universal_newlines=True, check=False
- )
+ completed = subprocess.run(args, capture_output=True, text=True, check=False)
logger.debug('ghostscript result %s', completed)
if completed.returncode != 0:
logger.error('ghostcript call failed %s', completed)
diff --git a/eo_gestion/eo_facture/fields.py b/eo_gestion/eo_facture/fields.py
index 70df4c7..4bd78ae 100644
--- a/eo_gestion/eo_facture/fields.py
+++ b/eo_gestion/eo_facture/fields.py
@@ -17,17 +17,17 @@
from decimal import Decimal, InvalidOperation
-from django.core.exceptions import ValidationError
-from django.core import validators
-from django.db import models
from django import forms
-from django.utils.translation import ugettext_lazy as _
+from django.core import validators
+from django.core.exceptions import ValidationError
+from django.db import models
from django.utils.six import text_type
+from django.utils.translation import ugettext_lazy as _
class PercentagePerYear(list):
def __init__(self, sequence):
- super(PercentagePerYear, self).__init__(sequence)
+ super().__init__(sequence)
def __str__(self):
return ','.join(map(lambda p: ':'.join(map(str, [p[0], int(100 * p[1])])), self))
@@ -37,7 +37,7 @@ class EuroField(models.DecimalField):
def __init__(self, *args, **kwargs):
kwargs["max_digits"] = 8
kwargs["decimal_places"] = 2
- super(EuroField, self).__init__(*args, **kwargs)
+ super().__init__(*args, **kwargs)
def assertion_error_to_validation_error(fun):
@@ -105,7 +105,7 @@ class PercentagePerYearField(models.Field):
def __init__(self, *args, **kwargs):
kwargs["max_length"] = 64
- super(PercentagePerYearField, self).__init__(*args, **kwargs)
+ super().__init__(*args, **kwargs)
def from_db_value(self, value, expression, connection, context):
return self.to_python(value)
@@ -143,4 +143,4 @@ class PercentagePerYearField(models.Field):
def formfield(self, **kwargs):
defaults = {"form_class": PercentagePerYearFormField}
defaults.update(kwargs)
- return super(PercentagePerYearField, self).formfield(**kwargs)
+ return super().formfield(**kwargs)
diff --git a/eo_gestion/eo_facture/forms.py b/eo_gestion/eo_facture/forms.py
index 7da5253..f1527a2 100644
--- a/eo_gestion/eo_facture/forms.py
+++ b/eo_gestion/eo_facture/forms.py
@@ -19,9 +19,9 @@ import datetime
from decimal import Decimal
from django import forms
-from django.db.transaction import atomic
-from django.core.exceptions import ValidationError
from django.contrib.admin import widgets
+from django.core.exceptions import ValidationError
+from django.db.transaction import atomic
from . import models
@@ -37,7 +37,7 @@ class RapidFactureForm(forms.Form):
def __init__(self, request=None, *args, **kwargs):
self.request = request
- super(RapidFactureForm, self).__init__(*args, **kwargs)
+ super().__init__(*args, **kwargs)
@atomic
def clean(self):
@@ -89,7 +89,7 @@ class DuplicateContractForm(forms.Form):
def __init__(self, request=None, *args, **kwargs):
self.request = request
- super(DuplicateContractForm, self).__init__(*args, **kwargs)
+ super().__init__(*args, **kwargs)
@atomic
def clean(self):
diff --git a/eo_gestion/eo_facture/migrations/0001_initial.py b/eo_gestion/eo_facture/migrations/0001_initial.py
index e517c34..93993fd 100644
--- a/eo_gestion/eo_facture/migrations/0001_initial.py
+++ b/eo_gestion/eo_facture/migrations/0001_initial.py
@@ -1,10 +1,12 @@
-from django.db import models, migrations
import datetime
-import eo_gestion.eo_facture.models
-import eo_gestion.eo_facture.fields
from decimal import Decimal
-from django.conf import settings
+
import django.core.validators
+from django.conf import settings
+from django.db import migrations, models
+
+import eo_gestion.eo_facture.fields
+import eo_gestion.eo_facture.models
class Migration(migrations.Migration):
@@ -46,11 +48,16 @@ class Migration(migrations.Migration):
(
'tva',
models.DecimalField(
- default=Decimal('20'), verbose_name='TVA par défaut', max_digits=8, decimal_places=2,
+ default=Decimal('20'),
+ verbose_name='TVA par défaut',
+ max_digits=8,
+ decimal_places=2,
),
),
],
- options={'ordering': ('nom',),},
+ options={
+ 'ordering': ('nom',),
+ },
bases=(models.Model,),
),
migrations.CreateModel(
@@ -87,7 +94,9 @@ class Migration(migrations.Migration):
),
),
],
- options={'ordering': ('-id',),},
+ options={
+ 'ordering': ('-id',),
+ },
bases=(models.Model,),
),
migrations.CreateModel(
@@ -168,7 +177,9 @@ class Migration(migrations.Migration):
),
),
],
- options={'ordering': ('-id',),},
+ options={
+ 'ordering': ('-id',),
+ },
bases=(models.Model,),
),
migrations.CreateModel(
@@ -193,7 +204,9 @@ class Migration(migrations.Migration):
),
),
],
- options={'ordering': ('order',),},
+ options={
+ 'ordering': ('order',),
+ },
bases=(models.Model,),
),
migrations.CreateModel(
@@ -230,7 +243,10 @@ class Migration(migrations.Migration):
),
),
],
- options={'ordering': ('-ligne_banque_pop__date_valeur',), 'verbose_name': 'Paiement',},
+ options={
+ 'ordering': ('-ligne_banque_pop__date_valeur',),
+ 'verbose_name': 'Paiement',
+ },
bases=(models.Model,),
),
migrations.CreateModel(
@@ -251,7 +267,9 @@ class Migration(migrations.Migration):
),
),
],
- options={'ordering': ('contrat', 'id'),},
+ options={
+ 'ordering': ('contrat', 'id'),
+ },
bases=(models.Model,),
),
]
diff --git a/eo_gestion/eo_facture/migrations/0002_facture_account_on_previous_period.py b/eo_gestion/eo_facture/migrations/0002_facture_account_on_previous_period.py
index 1314b3a..de8a8b8 100644
--- a/eo_gestion/eo_facture/migrations/0002_facture_account_on_previous_period.py
+++ b/eo_gestion/eo_facture/migrations/0002_facture_account_on_previous_period.py
@@ -1,4 +1,4 @@
-from django.db import models, migrations
+from django.db import migrations, models
class Migration(migrations.Migration):
diff --git a/eo_gestion/eo_facture/migrations/0006_client_contacts.py b/eo_gestion/eo_facture/migrations/0006_client_contacts.py
index 3e97487..97514af 100644
--- a/eo_gestion/eo_facture/migrations/0006_client_contacts.py
+++ b/eo_gestion/eo_facture/migrations/0006_client_contacts.py
@@ -11,6 +11,8 @@ class Migration(migrations.Migration):
operations = [
migrations.AddField(
- model_name='client', name='contacts', field=models.TextField(blank=True, verbose_name='Contacts'),
+ model_name='client',
+ name='contacts',
+ field=models.TextField(blank=True, verbose_name='Contacts'),
),
]
diff --git a/eo_gestion/eo_facture/migrations/0007_auto_20191009_1335.py b/eo_gestion/eo_facture/migrations/0007_auto_20191009_1335.py
index b622bdc..9cc7aaa 100644
--- a/eo_gestion/eo_facture/migrations/0007_auto_20191009_1335.py
+++ b/eo_gestion/eo_facture/migrations/0007_auto_20191009_1335.py
@@ -16,6 +16,7 @@
from decimal import Decimal
+
from django.db import migrations, models
diff --git a/eo_gestion/eo_facture/migrations/0008_auto_20200201_1559.py b/eo_gestion/eo_facture/migrations/0008_auto_20200201_1559.py
index 8e124a5..df93bab 100644
--- a/eo_gestion/eo_facture/migrations/0008_auto_20200201_1559.py
+++ b/eo_gestion/eo_facture/migrations/0008_auto_20200201_1559.py
@@ -1,6 +1,7 @@
# Generated by Django 2.2.9 on 2020-02-01 14:59
from django.db import migrations, models
+
import eo_gestion.eo_facture.validators
diff --git a/eo_gestion/eo_facture/migrations/0009_client_chorus_structure.py b/eo_gestion/eo_facture/migrations/0009_client_chorus_structure.py
index 2619459..8165c72 100644
--- a/eo_gestion/eo_facture/migrations/0009_client_chorus_structure.py
+++ b/eo_gestion/eo_facture/migrations/0009_client_chorus_structure.py
@@ -1,7 +1,7 @@
# Generated by Django 2.2.9 on 2020-02-01 15:00
-from django.db import migrations, models
import django.db.models.deletion
+from django.db import migrations, models
class Migration(migrations.Migration):
diff --git a/eo_gestion/eo_facture/migrations/0011_contrat_url.py b/eo_gestion/eo_facture/migrations/0011_contrat_url.py
index 2ad6523..9271f55 100644
--- a/eo_gestion/eo_facture/migrations/0011_contrat_url.py
+++ b/eo_gestion/eo_facture/migrations/0011_contrat_url.py
@@ -11,6 +11,8 @@ class Migration(migrations.Migration):
operations = [
migrations.AddField(
- model_name='contrat', name='url', field=models.URLField(blank=True, verbose_name='URL'),
+ model_name='contrat',
+ name='url',
+ field=models.URLField(blank=True, verbose_name='URL'),
),
]
diff --git a/eo_gestion/eo_facture/migrations/0012_client_active.py b/eo_gestion/eo_facture/migrations/0012_client_active.py
index 30100b6..d096662 100644
--- a/eo_gestion/eo_facture/migrations/0012_client_active.py
+++ b/eo_gestion/eo_facture/migrations/0012_client_active.py
@@ -11,6 +11,8 @@ class Migration(migrations.Migration):
operations = [
migrations.AddField(
- model_name='client', name='active', field=models.BooleanField(default=True, verbose_name='Actif'),
+ model_name='client',
+ name='active',
+ field=models.BooleanField(default=True, verbose_name='Actif'),
),
]
diff --git a/eo_gestion/eo_facture/migrations/0013_contrat_tags.py b/eo_gestion/eo_facture/migrations/0013_contrat_tags.py
index 78526c7..969d4af 100644
--- a/eo_gestion/eo_facture/migrations/0013_contrat_tags.py
+++ b/eo_gestion/eo_facture/migrations/0013_contrat_tags.py
@@ -1,6 +1,7 @@
# Generated by Django 2.2.9 on 2020-07-04 14:55
from django.db import migrations
+
import eo_gestion.eo_facture.taggit
diff --git a/eo_gestion/eo_facture/models.py b/eo_gestion/eo_facture/models.py
index d5d5288..2f75f51 100644
--- a/eo_gestion/eo_facture/models.py
+++ b/eo_gestion/eo_facture/models.py
@@ -15,29 +15,28 @@
# along with this program. If not, see .
-from decimal import Decimal, ROUND_HALF_UP
import datetime
from collections import defaultdict
+from decimal import ROUND_HALF_UP, Decimal
+from django.conf import settings
from django.contrib.auth.models import User
from django.core.exceptions import ValidationError
+from django.core.validators import RegexValidator, validate_email
from django.db import models
-from django.db.models import Sum, Q, F
-from django.core.validators import validate_email, RegexValidator
-from django.conf import settings
-from django.db.models.signals import post_save, post_delete
+from django.db.models import F, Q, Sum
from django.db.models.query import QuerySet
+from django.db.models.signals import post_delete, post_save
from django.template.loader import get_template
-from django.utils.translation import ugettext_lazy as _
from django.utils import six
from django.utils.timezone import now
-
+from django.utils.translation import ugettext_lazy as _
from weasyprint import HTML
+from eo_gestion.utils import percentage_str
from ..eo_banque import models as banque_models
-from . import fields, validators, facturx, taggit
-from eo_gestion.utils import percentage_str
+from . import facturx, fields, taggit, validators
validate_telephone = RegexValidator(r"[. 0-9]*")
@@ -52,7 +51,6 @@ def today():
return now().date()
-@six.python_2_unicode_compatible
class Client(models.Model):
nom = models.CharField(max_length=255, unique=True)
adresse = models.TextField()
@@ -73,7 +71,12 @@ class Client(models.Model):
blank=True,
default='',
)
- service_code = models.CharField(max_length=128, db_index=True, blank=True, default='',)
+ service_code = models.CharField(
+ max_length=128,
+ db_index=True,
+ blank=True,
+ default='',
+ )
active = models.BooleanField(verbose_name='Actif', default=True)
chorus_structure = models.ForeignKey(
@@ -101,7 +104,6 @@ def one_hundred_percent_this_year():
return "%s:100" % now().date().year
-@six.python_2_unicode_compatible
class Contrat(models.Model):
client = models.ForeignKey(Client, related_name="contrats", on_delete=models.CASCADE)
intitule = models.CharField(max_length=150)
@@ -123,7 +125,7 @@ class Contrat(models.Model):
tags = taggit.TaggableManager(blank=True)
def montant_facture(self):
- return sum([facture.montant for facture in self.factures.non_proforma()])
+ return sum(facture.montant for facture in self.factures.non_proforma())
def pourcentage_facture(self):
return percentage_str(self.montant_facture(), self.montant())
@@ -132,11 +134,11 @@ class Contrat(models.Model):
def montant(self):
"""
- Montant total d'un contrat, y compris les prestations
- optionnelles. Si pas de prestation définie, montant des factures émises.
+ Montant total d'un contrat, y compris les prestations
+ optionnelles. Si pas de prestation définie, montant des factures émises.
"""
if self.prestations.exists():
- return Decimal(sum([p.montant() for p in self.prestations.all()]))
+ return Decimal(sum(p.montant() for p in self.prestations.all()))
else:
return self.montant_facture()
@@ -145,7 +147,7 @@ class Contrat(models.Model):
def nom_client(self):
"""
- Le nom du client qui a signé ce contrat avec EO.
+ Le nom du client qui a signé ce contrat avec EO.
"""
return self.client.nom
@@ -159,7 +161,6 @@ class Contrat(models.Model):
ordering = ('-id',)
-@six.python_2_unicode_compatible
class Prestation(models.Model):
contrat = models.ForeignKey(Contrat, related_name='prestations', on_delete=models.CASCADE)
intitule = models.CharField(max_length=255, verbose_name='Intitulé')
@@ -213,7 +214,6 @@ class FactureQuerySet(QuerySet):
)
-@six.python_2_unicode_compatible
class Facture(models.Model):
proforma = models.BooleanField(default=True, verbose_name='Facture proforma', db_index=True)
ordre = models.IntegerField(
@@ -274,7 +274,7 @@ class Facture(models.Model):
def save(self):
if self.ordre is None and not self.proforma:
self.ordre = self.last_ordre_plus_one()
- super(Facture, self).save()
+ super().save()
def clean(self):
if not (self.contrat or self.client):
@@ -333,7 +333,7 @@ class Facture(models.Model):
@property
def montant(self):
- return sum([ligne.montant for ligne in self.lignes.all()])
+ return sum(ligne.montant for ligne in self.lignes.all())
def solde(self):
payments = self.payments.all()
@@ -395,7 +395,6 @@ class Facture(models.Model):
ordering = ("-id",)
-@six.python_2_unicode_compatible
class Ligne(models.Model):
facture = models.ForeignKey(Facture, related_name="lignes", on_delete=models.CASCADE)
intitule = models.TextField(blank=True)
@@ -428,8 +427,8 @@ class Ligne(models.Model):
if self.facture.contrat and not self.facture.proforma:
facture = self.facture
contrat = facture.contrat
- deja_facture = sum([f.montant for f in contrat.factures.exclude(id=facture.id)])
- deja_facture += sum([l.montant for l in facture.lignes.all() if l != self])
+ deja_facture = sum(f.montant for f in contrat.factures.exclude(id=facture.id))
+ deja_facture += sum(l.montant for l in facture.lignes.all() if l != self)
if deja_facture + self.montant > contrat.montant():
errors.append(
'Cette ligne fait dépasser le montant initial du contrat de %.2f %s'
@@ -442,7 +441,11 @@ class Ligne(models.Model):
ordering = ("order",)
def __str__(self):
- return "%s pour %s %s" % (self.intitule, self.montant, self.facture.client.monnaie,)
+ return "%s pour %s %s" % (
+ self.intitule,
+ self.montant,
+ self.facture.client.monnaie,
+ )
def encaissements_avec_solde_non_affecte():
@@ -455,7 +458,6 @@ def encaissements_avec_solde_non_affecte():
)
-@six.python_2_unicode_compatible
class Payment(models.Model):
facture = models.ForeignKey(Facture, related_name='payments', on_delete=models.CASCADE)
ligne_banque_pop = models.ForeignKey(
@@ -502,7 +504,10 @@ class Payment(models.Model):
pass
else:
deja_affecte = other_payments.aggregate(aggregate).get("montant_affecte") or 0
- if self.montant_affecte is not None and deja_affecte + self.montant_affecte > self.facture.montant_ttc:
+ if (
+ self.montant_affecte is not None
+ and deja_affecte + self.montant_affecte > self.facture.montant_ttc
+ ):
raise ValidationError(
'Le montant affecté aux différentes factures '
'est supérieur au montant de l\'encaissement.'
diff --git a/eo_gestion/eo_facture/taggit.py b/eo_gestion/eo_facture/taggit.py
index d5cf128..f04fffb 100644
--- a/eo_gestion/eo_facture/taggit.py
+++ b/eo_gestion/eo_facture/taggit.py
@@ -15,7 +15,6 @@
# along with this program. If not, see .
from django.forms import ModelMultipleChoiceField, SelectMultiple
-
from taggit.managers import TaggableManager
from taggit.models import Tag
@@ -25,6 +24,7 @@ class TagWidget(SelectMultiple):
class Media:
'''Enable use of Select2 in template'''
+
js = [
'xstatic/jquery.js',
'xstatic/jquery-ui.js',
@@ -42,9 +42,7 @@ class TagField(ModelMultipleChoiceField):
if value is None:
return value
# TagManager returns Trough model and not the target model, we must adapt
- if (hasattr(value, '__iter__')
- and not isinstance(value, str)
- and not hasattr(value, '_meta')):
+ if hasattr(value, '__iter__') and not isinstance(value, str) and not hasattr(value, '_meta'):
if value and hasattr(value[0], '_meta'):
value = list(value.select_related('tag').values_list('tag__name', flat=True))
return value
diff --git a/eo_gestion/eo_facture/templatetags/eo_facture.py b/eo_gestion/eo_facture/templatetags/eo_facture.py
index d9f76e0..5a5367d 100644
--- a/eo_gestion/eo_facture/templatetags/eo_facture.py
+++ b/eo_gestion/eo_facture/templatetags/eo_facture.py
@@ -15,21 +15,21 @@
# along with this program. If not, see .
-from datetime import date, timedelta, datetime
-from decimal import Decimal, InvalidOperation
from collections import defaultdict
+from datetime import date, datetime, timedelta
+from decimal import Decimal, InvalidOperation
from django import template
-from django.dispatch import receiver
from django.db import transaction
-from django.db.models.signals import post_save, post_delete
-from django.utils.formats import number_format
-from django.utils.timesince import timesince
-from django.utils.six import text_type
+from django.db.models.signals import post_delete, post_save
+from django.dispatch import receiver
from django.urls import reverse
+from django.utils.formats import number_format
+from django.utils.six import text_type
+from django.utils.timesince import timesince
-from eo_gestion.eo_facture.models import Contrat, Facture, DELAI_PAIEMENT, Payment
from eo_gestion.eo_banque.models import LigneBanquePop
+from eo_gestion.eo_facture.models import DELAI_PAIEMENT, Contrat, Facture, Payment
from eo_gestion.utils import percentage
from ...decorators import cache
@@ -107,7 +107,8 @@ def income():
invoiced_clients_by_year = {}
for year in invoiced_by_year_and_client:
clients = sorted(
- invoiced_by_year_and_client[year].keys(), key=lambda x: -invoiced_by_year_and_client[year][x],
+ invoiced_by_year_and_client[year].keys(),
+ key=lambda x: -invoiced_by_year_and_client[year][x],
)
invoiced_clients_by_year[year] = clients
contracted_by_year = defaultdict(lambda: Decimal(0))
@@ -153,7 +154,7 @@ class StringWithHref(text_type):
return text_type.__new__(cls, v)
def __init__(self, v, href=None):
- super(StringWithHref, self).__init__()
+ super().__init__()
self.href = href
@@ -213,7 +214,7 @@ def income_by_clients(year=None):
total = sum(total_by_clients.values())
total_invoiced = sum(invoiced_by_clients.values())
total_contracted = sum(contracted_by_clients.values())
- percent_by_clients = dict([(i, Decimal(100) * v / total) for i, v in total_by_clients.items()])
+ percent_by_clients = {i: Decimal(100) * v / total for i, v in total_by_clients.items()}
clients = sorted(total_by_clients.keys(), key=lambda x: -total_by_clients[x])
running_total = Decimal(0)
# compute pareto index
@@ -290,7 +291,7 @@ def a_facturer():
}
)
contrats_a_facturer.sort(key=lambda x: -x['depuis'])
- montant = sum([x['montant'] for x in contrats_a_facturer])
+ montant = sum(x['montant'] for x in contrats_a_facturer)
return {'a_facturer': contrats_a_facturer, 'montant': montant}
diff --git a/eo_gestion/eo_facture/views.py b/eo_gestion/eo_facture/views.py
index d8f56bb..d877433 100644
--- a/eo_gestion/eo_facture/views.py
+++ b/eo_gestion/eo_facture/views.py
@@ -20,13 +20,14 @@ import logging
import os.path
from django import http
-from django.shortcuts import get_object_or_404, redirect
from django.conf import settings
from django.contrib import messages
from django.contrib.admin.models import LogEntry
from django.contrib.contenttypes.models import ContentType
+from django.shortcuts import get_object_or_404, redirect
from eo_gestion.chorus.chorus import push_to_chorus
+
from .models import Contrat, Facture
logger = logging.getLogger(__name__)
@@ -46,7 +47,8 @@ def facture_pdf(request, facture_id):
pdf = facture.pdf(base_uri=request.build_absolute_uri('/'))
if hasattr(settings, 'FACTURE_DIR'):
filename = os.path.join(
- settings.FACTURE_DIR, '%s-%s.pdf' % (facture.code(), facture.contrat.client.nom.encode('utf8')),
+ settings.FACTURE_DIR,
+ '%s-%s.pdf' % (facture.code(), facture.contrat.client.nom.encode('utf8')),
)
with open(filename, 'wb') as fd:
fd.write(pdf)
@@ -90,11 +92,11 @@ def send_to_chorus(request, facture_id):
description = ''
if 'numeroFluxDepot' in response:
- msg = 'Facture {facture} envoyée à ChorusPro'.format(facture=facture.code())
+ msg = f'Facture {facture.code()} envoyée à ChorusPro'
for key, value in response.items():
- description += ' | {key} - {value}'.format(key=key, value=value)
+ description += f' | {key} - {value}'
else:
- msg = 'Échec d\'envoi de la facture {facture} à ChorusPro'.format(facture=facture.code())
+ msg = f'Échec d\'envoi de la facture {facture.code()} à ChorusPro'
msg += description
LogEntry.objects.create(
diff --git a/eo_gestion/mule.py b/eo_gestion/mule.py
index 8a0f16b..82f8aee 100644
--- a/eo_gestion/mule.py
+++ b/eo_gestion/mule.py
@@ -18,10 +18,8 @@
import logging
import django
-
from uwsgidecorators import timer
-
django.setup()
logger = logging.getLogger('django.server')
diff --git a/eo_gestion/ods.py b/eo_gestion/ods.py
index 77e70f8..ac7cb76 100644
--- a/eo_gestion/ods.py
+++ b/eo_gestion/ods.py
@@ -14,14 +14,13 @@
# You should have received a copy of the GNU General Public License
# along with this program; if not, see .
-from datetime import date, datetime
import re
import xml.etree.ElementTree as ET
import zipfile
+from datetime import date, datetime
from django.utils.encoding import force_text
-
NS = {
"fo": "urn:oasis:names:tc:opendocument:xmlns:xsl-fo-compatible:1.0",
"office": "urn:oasis:names:tc:opendocument:xmlns:office:1.0",
@@ -46,7 +45,7 @@ def is_number(value):
return True
-class Workbook(object):
+class Workbook:
def __init__(self):
self.sheets = []
@@ -158,7 +157,7 @@ class Workbook(object):
z.close()
-class WorkSheet(object):
+class WorkSheet:
def __init__(self, workbook, name):
self.cells = {}
self.name = name
@@ -184,7 +183,7 @@ class WorkSheet(object):
return root
-class WorkCell(object):
+class WorkCell:
def __init__(self, worksheet, value):
if value is None:
value = ""
diff --git a/eo_gestion/settings.py b/eo_gestion/settings.py
index d4104c5..0777b6a 100644
--- a/eo_gestion/settings.py
+++ b/eo_gestion/settings.py
@@ -16,9 +16,8 @@
import os.path
-from django.conf import global_settings
-
import facturx
+from django.conf import global_settings
# Django settings for facturation project.
@@ -40,7 +39,12 @@ DATABASES = {
}
}
-CACHES = {'default': {'BACKEND': 'django.core.cache.backends.db.DatabaseCache', 'LOCATION': 'cache',}}
+CACHES = {
+ 'default': {
+ 'BACKEND': 'django.core.cache.backends.db.DatabaseCache',
+ 'LOCATION': 'cache',
+ }
+}
LOGGING = {
'version': 1,
@@ -51,10 +55,23 @@ LOGGING = {
'datefmt': '%Y-%m-%d %a %H:%M:%S',
},
},
- 'handlers': {'console': {'level': 'DEBUG', 'class': 'logging.StreamHandler', 'formatter': 'verbose',}},
+ 'handlers': {
+ 'console': {
+ 'level': 'DEBUG',
+ 'class': 'logging.StreamHandler',
+ 'formatter': 'verbose',
+ }
+ },
'loggers': {
- '': {'handlers': ['console'], 'level': 'INFO',},
- 'factur-x': {'level': 'WARNING', 'handlers': [], 'propagate': False,},
+ '': {
+ 'handlers': ['console'],
+ 'level': 'INFO',
+ },
+ 'factur-x': {
+ 'level': 'WARNING',
+ 'handlers': [],
+ 'propagate': False,
+ },
},
}
@@ -116,7 +133,9 @@ ROOT_URLCONF = "eo_gestion.urls"
TEMPLATES = [
{
'BACKEND': 'django.template.backends.django.DjangoTemplates',
- 'DIRS': [os.path.join(os.path.dirname(__file__), 'templates'),],
+ 'DIRS': [
+ os.path.join(os.path.dirname(__file__), 'templates'),
+ ],
'APP_DIRS': True,
'OPTIONS': {
'context_processors': [
diff --git a/eo_gestion/urls.py b/eo_gestion/urls.py
index e1df7c5..ca746be 100644
--- a/eo_gestion/urls.py
+++ b/eo_gestion/urls.py
@@ -15,14 +15,12 @@
# along with this program. If not, see .
-from django.conf.urls import include, url
-
-from django.conf import settings
import django.contrib.admin
+from django.conf import settings
+from django.conf.urls import include, url
from django.views.generic.base import RedirectView
from . import admin
-
from .eo_facture.views import api_references
django.contrib.admin.autodiscover()
diff --git a/eo_gestion/vendor/adminsortable2/admin.py b/eo_gestion/vendor/adminsortable2/admin.py
index bb4afa2..4d17d63 100644
--- a/eo_gestion/vendor/adminsortable2/admin.py
+++ b/eo_gestion/vendor/adminsortable2/admin.py
@@ -1,5 +1,5 @@
-import os
import json
+import os
from itertools import chain
from types import MethodType
@@ -19,13 +19,10 @@ from django.db.models.functions import Coalesce
from django.db.models.signals import post_save, pre_save
from django.forms import widgets
from django.forms.models import BaseInlineFormSet
-from django.http import (
- HttpResponse, HttpResponseBadRequest,
- HttpResponseNotAllowed, HttpResponseForbidden
-)
+from django.http import HttpResponse, HttpResponseBadRequest, HttpResponseForbidden, HttpResponseNotAllowed
+from django.urls import path, reverse
from django.utils.safestring import mark_safe
from django.utils.translation import gettext_lazy as _
-from django.urls import path, reverse
__all__ = ['SortableAdminMixin', 'SortableInlineAdminMixin']
@@ -55,12 +52,10 @@ class MovePageActionForm(admin.helpers.ActionForm):
required=False,
initial=1,
widget=widgets.NumberInput(attrs={'id': 'changelist-form-step'}),
- label=False
+ label=False,
)
page = forms.IntegerField(
- required=False,
- widget=widgets.NumberInput(attrs={'id': 'changelist-form-page'}),
- label=False
+ required=False, widget=widgets.NumberInput(attrs={'id': 'changelist-form-page'}), label=False
)
@@ -91,7 +86,7 @@ class SortableAdminMixin(SortableAdminBase):
return [
os.path.join('adminsortable2', app_label, opts.model_name, 'change_list.html'),
os.path.join('adminsortable2', app_label, 'change_list.html'),
- 'adminsortable2/change_list.html'
+ 'adminsortable2/change_list.html',
]
def __init__(self, model, admin_site):
@@ -111,31 +106,22 @@ class SortableAdminMixin(SortableAdminBase):
# Insert the magic field into the same position as the first occurrence
# of the default_order_field, or, if not present, at the start
try:
- self.default_order_field_index = self.list_display.index(
- self.default_order_field
- )
+ self.default_order_field_index = self.list_display.index(self.default_order_field)
except ValueError:
self.default_order_field_index = 0
self.list_display.insert(self.default_order_field_index, '_reorder')
# Remove *all* occurrences of the field from `list_display`
if self.list_display and self.default_order_field in self.list_display:
- self.list_display = [
- f for f in self.list_display if f != self.default_order_field
- ]
+ self.list_display = [f for f in self.list_display if f != self.default_order_field]
# Remove *all* occurrences of the field from `list_display_links`
if self.list_display_links and self.default_order_field in self.list_display_links:
- self.list_display_links = [
- f for f in self.list_display_links if
- f != self.default_order_field
- ]
+ self.list_display_links = [f for f in self.list_display_links if f != self.default_order_field]
# Remove *all* occurrences of the field from `ordering`
if self.ordering and self.default_order_field in self.ordering:
- self.ordering = [
- f for f in self.ordering if f != self.default_order_field
- ]
+ self.ordering = [f for f in self.ordering if f != self.default_order_field]
rev_field = '-' + self.default_order_field
if self.ordering and rev_field in self.ordering:
self.ordering = [f for f in self.ordering if f != rev_field]
@@ -148,7 +134,7 @@ class SortableAdminMixin(SortableAdminBase):
path(
'adminsortable2_update/',
self.admin_site.admin_view(self.update_order),
- name=self._get_update_url_name()
+ name=self._get_update_url_name(),
),
]
return my_urls + super().get_urls()
@@ -209,10 +195,12 @@ class SortableAdminMixin(SortableAdminBase):
def media(self):
m = super().media
if self.enable_sorting:
- m = m + widgets.Media(js=[
- 'adminsortable2/js/libs/jquery.ui.sortable-1.11.4.js',
- 'adminsortable2/js/list-sortable.js',
- ])
+ m = m + widgets.Media(
+ js=[
+ 'adminsortable2/js/libs/jquery.ui.sortable-1.11.4.js',
+ 'adminsortable2/js/list-sortable.js',
+ ]
+ )
return m
def _add_reorder_method(self):
@@ -223,11 +211,13 @@ class SortableAdminMixin(SortableAdminBase):
This can only be done using a function, since it is not possible
to add dynamic attributes to bound methods.
"""
+
def func(this, item):
html = ''
if this.enable_sorting:
- html = '
' \
- '
'.format(getattr(item, this.default_order_field), item.pk)
+ html = '' '
'.format(
+ getattr(item, this.default_order_field), item.pk
+ )
return mark_safe(html)
setattr(func, 'allow_tags', True)
@@ -255,36 +245,37 @@ class SortableAdminMixin(SortableAdminBase):
endorder = int(request.POST.get('endorder', 0))
moved_items = list(self._move_item(request, startorder, endorder))
return HttpResponse(
- json.dumps(moved_items, cls=DjangoJSONEncoder),
- content_type='application/json;charset=UTF-8'
+ json.dumps(moved_items, cls=DjangoJSONEncoder), content_type='application/json;charset=UTF-8'
)
def save_model(self, request, obj, form, change):
if not change:
- setattr(
- obj, self.default_order_field,
- self.get_max_order(request, obj) + 1
- )
+ setattr(obj, self.default_order_field, self.get_max_order(request, obj) + 1)
super().save_model(request, obj, form, change)
def move_to_exact_page(self, request, queryset):
self._bulk_move(request, queryset, self.EXACT)
+
move_to_exact_page.short_description = _('Move selected to specific page')
def move_to_back_page(self, request, queryset):
self._bulk_move(request, queryset, self.BACK)
+
move_to_back_page.short_description = _('Move selected ... pages back')
def move_to_forward_page(self, request, queryset):
self._bulk_move(request, queryset, self.FORWARD)
+
move_to_forward_page.short_description = _('Move selected ... pages forward')
def move_to_first_page(self, request, queryset):
self._bulk_move(request, queryset, self.FIRST)
+
move_to_first_page.short_description = _('Move selected to first page')
def move_to_last_page(self, request, queryset):
self._bulk_move(request, queryset, self.LAST)
+
move_to_last_page.short_description = _('Move selected to last page')
def _move_item(self, request, startorder, endorder):
@@ -332,10 +323,7 @@ class SortableAdminMixin(SortableAdminBase):
move_qs = model.objects.filter(**move_filter).order_by(order_by)
move_objs = list(move_qs)
for instance in move_objs:
- setattr(
- instance, rank_field,
- getattr(instance, rank_field) + move_delta
- )
+ setattr(instance, rank_field, getattr(instance, rank_field) + move_delta)
# Do not run `instance.save()`, because it will be updated
# later in bulk by `move_qs.update`.
pre_save.send(
@@ -359,10 +347,10 @@ class SortableAdminMixin(SortableAdminBase):
setattr(obj, rank_field, endorder)
obj.save(update_fields=[rank_field])
- return [{
- 'pk': instance.pk,
- 'order': getattr(instance, rank_field)
- } for instance in chain(move_objs, [obj])]
+ return [
+ {'pk': instance.pk, 'order': getattr(instance, rank_field)}
+ for instance in chain(move_objs, [obj])
+ ]
@staticmethod
def get_extra_model_filters(request):
@@ -372,9 +360,7 @@ class SortableAdminMixin(SortableAdminBase):
return {}
def get_max_order(self, request, obj=None):
- return self.model.objects.aggregate(
- max_order=Coalesce(Max(self.default_order_field), 0)
- )['max_order']
+ return self.model.objects.aggregate(max_order=Coalesce(Max(self.default_order_field), 0))['max_order']
def _bulk_move(self, request, queryset, method):
if not self.enable_sorting:
@@ -416,15 +402,9 @@ class SortableAdminMixin(SortableAdminBase):
self.message_user(request, msg, level=messages.ERROR)
return
- endorders_start = getattr(
- objects[page.start_index() - 1], self.default_order_field
- )
+ endorders_start = getattr(objects[page.start_index() - 1], self.default_order_field)
endorders_step = -1 if self.order_by.startswith('-') else 1
- endorders = range(
- endorders_start,
- endorders_start + endorders_step * queryset_size,
- endorders_step
- )
+ endorders = range(endorders_start, endorders_start + endorders_step * queryset_size, endorders_step)
if page.number > current_page_number: # Move forward (like drag down)
queryset = queryset.reverse()
@@ -455,10 +435,11 @@ class PolymorphicSortableAdminMixin(SortableAdminMixin):
rather than ``admin.ModelAdmin``, then additionally inherit from ``PolymorphicSortableAdminMixin``
rather than ``SortableAdminMixin``.
"""
+
def get_max_order(self, request, obj=None):
- return self.base_model.objects.aggregate(
- max_order=Coalesce(Max(self.default_order_field), 0)
- )['max_order']
+ return self.base_model.objects.aggregate(max_order=Coalesce(Max(self.default_order_field), 0))[
+ 'max_order'
+ ]
class CustomInlineFormSetMixin:
@@ -466,8 +447,9 @@ class CustomInlineFormSetMixin:
self.default_order_direction, self.default_order_field = _get_default_ordering(self.model, self)
if self.default_order_field not in self.form.base_fields:
- self.form.base_fields[self.default_order_field] = \
- self.model._meta.get_field(self.default_order_field).formfield()
+ self.form.base_fields[self.default_order_field] = self.model._meta.get_field(
+ self.default_order_field
+ ).formfield()
self.form.base_fields[self.default_order_field].is_hidden = True
self.form.base_fields[self.default_order_field].required = False
@@ -476,12 +458,8 @@ class CustomInlineFormSetMixin:
super().__init__(*args, **kwargs)
def get_max_order(self):
- query_set = self.model.objects.filter(
- **{self.fk.get_attname(): self.instance.pk}
- )
- return query_set.aggregate(
- max_order=Coalesce(Max(self.default_order_field), 0)
- )['max_order']
+ query_set = self.model.objects.filter(**{self.fk.get_attname(): self.instance.pk})
+ return query_set.aggregate(max_order=Coalesce(Max(self.default_order_field), 0))['max_order']
def save_new(self, form, commit=True):
"""
@@ -548,19 +526,18 @@ class SortableInlineAdminMixin(SortableAdminBase):
@property
def media(self):
- shared = (
- super().media + widgets.Media(
- js=('adminsortable2/js/libs/jquery.ui.sortable-1.11.4.js',
- 'adminsortable2/js/inline-sortable.js')))
+ shared = super().media + widgets.Media(
+ js=('adminsortable2/js/libs/jquery.ui.sortable-1.11.4.js', 'adminsortable2/js/inline-sortable.js')
+ )
if isinstance(self, admin.StackedInline):
return shared + widgets.Media(
- js=('adminsortable2/js/inline-sortable.js',
- 'adminsortable2/js/inline-stacked.js'))
+ js=('adminsortable2/js/inline-sortable.js', 'adminsortable2/js/inline-stacked.js')
+ )
else:
# assume TabularInline (don't return None in any case)
return shared + widgets.Media(
- js=('adminsortable2/js/inline-sortable.js',
- 'adminsortable2/js/inline-tabular.js'))
+ js=('adminsortable2/js/inline-sortable.js', 'adminsortable2/js/inline-tabular.js')
+ )
@property
def template(self):
@@ -580,14 +557,11 @@ class CustomGenericInlineFormSet(CustomInlineFormSetMixin, BaseGenericInlineForm
**{
self.ct_fk_field.name: self.instance.pk,
self.ct_field.name: ContentType.objects.get_for_model(
- self.instance,
- for_concrete_model=self.for_concrete_model
- )
+ self.instance, for_concrete_model=self.for_concrete_model
+ ),
}
)
- return query_set.aggregate(
- max_order=Coalesce(Max(self.default_order_field), 0)
- )['max_order']
+ return query_set.aggregate(max_order=Coalesce(Max(self.default_order_field), 0))['max_order']
class SortableGenericInlineAdminMixin(SortableInlineAdminMixin):
diff --git a/gestion.wsgi b/gestion.wsgi
index 96e9b75..5be6b5b 100644
--- a/gestion.wsgi
+++ b/gestion.wsgi
@@ -4,4 +4,5 @@ import sys
sys.path.append(os.path.dirname(__file__))
os.environ['DJANGO_SETTINGS_MODULE'] = 'eo_gestion.settings'
import django.core.handlers.wsgi
+
application = django.core.handlers.wsgi.WSGIHandler()
diff --git a/setup.py b/setup.py
index 38d2574..2e883f8 100644
--- a/setup.py
+++ b/setup.py
@@ -3,11 +3,11 @@
import os
import subprocess
-
from distutils.cmd import Command
from distutils.command.build import build as _build
from distutils.command.sdist import sdist
-from setuptools import setup, find_packages
+
+from setuptools import find_packages, setup
from setuptools.command.install_lib import install_lib as _install_lib
install_requires = [
@@ -23,11 +23,11 @@ install_requires = [
def get_version():
- '''Use the VERSION, if absent generates a version with git describe, if not
- tag exists, take 0.0- and add the length of the commit log.
- '''
+ """Use the VERSION, if absent generates a version with git describe, if not
+ tag exists, take 0.0- and add the length of the commit log.
+ """
if os.path.exists('VERSION'):
- with open('VERSION', 'r') as v:
+ with open('VERSION') as v:
return v.read()
if os.path.exists('.git'):
p = subprocess.Popen(
diff --git a/tests/base/conftest.py b/tests/base/conftest.py
index cf68317..3b5d0ee 100644
--- a/tests/base/conftest.py
+++ b/tests/base/conftest.py
@@ -15,11 +15,8 @@
# along with this program. If not, see .
import pytest
-
-from django.core.management import call_command
-
from django.contrib.auth.models import User
-
+from django.core.management import call_command
DATA = ["tests/fixture.json"]
diff --git a/tests/base/test_api.py b/tests/base/test_api.py
index 34d9cd8..4f2d57c 100644
--- a/tests/base/test_api.py
+++ b/tests/base/test_api.py
@@ -14,9 +14,10 @@
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see .
-from eo_gestion.eo_facture.models import Contrat
from taggit.models import Tag
+from eo_gestion.eo_facture.models import Contrat
+
def test_references(app):
gru = Tag.objects.create(name='GRU')
diff --git a/tests/conftest.py b/tests/conftest.py
index 17f4bea..942c417 100644
--- a/tests/conftest.py
+++ b/tests/conftest.py
@@ -14,9 +14,8 @@
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see .
-import pytest
-
import django_webtest
+import pytest
@pytest.fixture
diff --git a/tests/settings.py b/tests/settings.py
index e169ac8..6bb635b 100644
--- a/tests/settings.py
+++ b/tests/settings.py
@@ -16,7 +16,6 @@
import os
-
ALLOWED_HOSTS = ["localhost"]
DATABASES = {
diff --git a/tests/test_chorus.py b/tests/test_chorus.py
index 1ec0323..75e060b 100644
--- a/tests/test_chorus.py
+++ b/tests/test_chorus.py
@@ -14,9 +14,8 @@
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see .
-import pytest
import httmock
-
+import pytest
import requests
from eo_gestion.chorus import chorus
@@ -47,7 +46,12 @@ def chorus_connection_error(url, request):
@httmock.urlmatch()
def chorus_error_500(url, request):
return httmock.response(
- 500, b'Pas content \xe9', headers={'Header Pourri': 'Héhé'.encode('latin1'), 'Header-Ok': 'ok',}
+ 500,
+ b'Pas content \xe9',
+ headers={
+ 'Header Pourri': 'Héhé'.encode('latin1'),
+ 'Header-Ok': 'ok',
+ },
)
@@ -69,5 +73,8 @@ def test_push_to_chorus_error_500():
assert result == {
'http.response.status-code': 500,
'http.response.body': "b'Pas content \\xe9'",
- 'http.response.headers': {'Header Pourri': 'H�h�', 'Header-Ok': 'ok',},
+ 'http.response.headers': {
+ 'Header Pourri': 'H�h�',
+ 'Header-Ok': 'ok',
+ },
}
diff --git a/tests/test_facturx.py b/tests/test_facturx.py
index 8ec5227..d3e0c29 100644
--- a/tests/test_facturx.py
+++ b/tests/test_facturx.py
@@ -16,12 +16,12 @@
import datetime
import io
-import pytest
import xml.etree.ElementTree as ET
import facturx
+import pytest
-from eo_gestion.eo_facture.facturx import to_pdfa, add_facturx_from_bytes
+from eo_gestion.eo_facture.facturx import add_facturx_from_bytes, to_pdfa
@pytest.fixture
@@ -88,7 +88,14 @@ def test_add_facturx_from_bytes(fake_invoice_bytes):
['PostalTradeAddress', ['CountryID', 'FR']],
['SpecifiedTaxRegistration', ['ID', 'FR09491081899']],
],
- ['BuyerTradeParty', ['Name', 'RGFIPD'], ['SpecifiedLegalOrganization', ['ID', '1234'],],],
+ [
+ 'BuyerTradeParty',
+ ['Name', 'RGFIPD'],
+ [
+ 'SpecifiedLegalOrganization',
+ ['ID', '1234'],
+ ],
+ ],
['BuyerOrderReferencedDocument', ['IssuerAssignedID', '5678']],
['ContractReferencedDocument', ['IssuerAssignedID', 'ABCD']],
],
diff --git a/tests/test_forms.py b/tests/test_forms.py
index fad5221..eef0ca7 100644
--- a/tests/test_forms.py
+++ b/tests/test_forms.py
@@ -17,6 +17,7 @@
from datetime import date, timedelta
from django.contrib.auth.models import User
+
from eo_gestion.eo_facture.forms import FactureForm
from eo_gestion.eo_facture.models import Client, Contrat
@@ -86,4 +87,4 @@ def test_facture_form(db, freezer):
data['initial-emission'] = '2019-01-03'
form = FactureForm(data=dict(data, proforma='true', emission='2019-01-01'), instance=facture)
assert not form.is_valid(), form.errors
- assert set(form.errors) == set(['proforma', 'emission'])
+ assert set(form.errors) == {'proforma', 'emission'}
diff --git a/tox.ini b/tox.ini
index efd2db5..c35de06 100644
--- a/tox.ini
+++ b/tox.ini
@@ -1,6 +1,6 @@
[tox]
toxworkdir = {env:TMPDIR:/tmp}/tox-{env:USER}/barbacompta/{env:BRANCH_NAME:}
-envlist = py3-pylint
+envlist = py3-pylint,code-style
[testenv]
setenv =
@@ -29,6 +29,13 @@ setenv =
commands =
./manage.py {posargs:--help}
+[testenv:code-style]
+skip_install = true
+deps =
+ pre-commit
+commands =
+ pre-commit run --all-files --show-diff-on-failure
+
[pytest]
filterwarnings=
ignore:Using or importing the ABCs from