facturation: gestion des bordereaux de remise de règlements (#88698) #177

Merged
lguerin merged 11 commits from wip/88698-invoicing-docket into main 2024-04-08 09:57:36 +02:00
Owner
No description provided.
lguerin added 11 commits 2024-03-29 16:29:12 +01:00
lguerin changed title from WIP: facturation: gestion des bordereaux de remise de règlements (#88698) to facturation: gestion des bordereaux de remise de règlements (#88698) 2024-03-29 16:33:37 +01:00
lguerin force-pushed wip/88698-invoicing-docket from 471e9bed2e to 5ab3d65d2c 2024-04-02 09:10:16 +02:00 Compare
lguerin force-pushed wip/88698-invoicing-docket from 5ab3d65d2c to a51e00205c 2024-04-02 09:17:27 +02:00 Compare
pmarillonnet requested review from pmarillonnet 2024-04-02 09:48:26 +02:00
Owner

(Je commence à relire.)

(Je commence à relire.)
lguerin force-pushed wip/88698-invoicing-docket from a51e00205c to 0deb65dba2 2024-04-02 10:39:54 +02:00 Compare
pmarillonnet reviewed 2024-04-03 17:04:00 +02:00
pmarillonnet left a comment
Owner

(Je fais assez moyennement confiance à gitea pour conserver mon brouillon de relecture — qui m’a pris plusieurs heures à constituer — d’ici demain. Par peur de perdre le travail en cours je pose ici ce début de relecture, qui concerne une première relecture des six premiers commits sur les onze proposés ici. J’essaie de boucler la relecture des cinq restants demain matin.)

———

Dans 0002, un + Counter.get_count(regie=regie, name='bar', kind='bucket') où je crois tu voulais dire kind='docket' :)
(Ce n’est pas visible dans le diff global.)

———

Agréable surprise de relecteur en voyant quel le gros du diff de la PR est en fait 0004 qui sépare les tests dans des fichiers différents. Par acquis de conscience, et parce que c’est le gros du diff de la PR, j’ai vérifié de part et d’autre (avant et après split) que ça correspondait. C’est ok pour moi. Ça me fait d’ailleurs me remémorer que j’ai encore du travail en cours côté authentic de ce point de vue là :)

———

0005, comme indiqué dans le commentaire inline gitea, je ne comprends pas trop la réalité fonctionnelle, et quel est le besoin qui motive d’afficher ces paiements effectués hors-bordereaux en particulier.

Edit : ah ok, je comprends à la lecture des commits suivants, on expose ces paiements sans bordereaux justement pour offrir la possibilité de les rattacher à un bordereau, ok.

———

J’étais pas super calé sur l’usage des FilterSet, ça m’a permis un petit rattrapage, merci :)

(Je fais assez moyennement confiance à gitea pour conserver mon brouillon de relecture — qui m’a pris plusieurs heures à constituer — d’ici demain. Par peur de perdre le travail en cours je pose ici ce début de relecture, qui concerne une première relecture des six premiers commits sur les onze proposés ici. J’essaie de boucler la relecture des cinq restants demain matin.) ——— Dans 0002, un `+ Counter.get_count(regie=regie, name='bar', kind='bucket')` où je crois tu voulais dire `kind='docket'` :) (Ce n’est pas visible dans le diff global.) ——— Agréable surprise de relecteur en voyant quel le gros du diff de la PR est en fait 0004 qui sépare les tests dans des fichiers différents. Par acquis de conscience, et parce que c’est le gros du diff de la PR, j’ai vérifié de part et d’autre (avant et après split) que ça correspondait. C’est ok pour moi. Ça me fait d’ailleurs me remémorer que j’ai encore du travail en cours côté authentic de ce point de vue là :) ——— 0005, comme indiqué dans le commentaire inline gitea, je ne comprends pas trop la réalité fonctionnelle, et quel est le besoin qui motive d’afficher ces paiements effectués hors-bordereaux en particulier. Edit : ah ok, je comprends à la lecture des commits suivants, on expose ces paiements sans bordereaux justement pour offrir la possibilité de les rattacher à un bordereau, ok. ——— J’étais pas super calé sur l’usage des FilterSet, ça m’a permis un petit rattrapage, merci :)
@ -848,0 +867,4 @@
def __init__(self, *args, **kwargs):
self.regie = kwargs.pop('regie')
if kwargs.get('data') is None:
# set initial through data, so form is valid on page load
Owner

Je ne connaissais pas l’astuce, ok :)

Je ne connaissais pas l’astuce, ok :)
Author
Owner

Oui, je ne suis pas super fière de moi, c'est un peu moche; mais en faisant avec initial ça ne valide pas le formulaire et donc pas de résultat du filtrage.
L'idée étant d'arriver sur la page avec déjà tous les paiements non remis listés

Oui, je ne suis pas super fière de moi, c'est un peu moche; mais en faisant avec initial ça ne valide pas le formulaire et donc pas de résultat du filtrage. L'idée étant d'arriver sur la page avec déjà tous les paiements non remis listés
Owner

Oui je vois, rien à redire et de toute façon je n’ai pas mieux à proposer, ok pour moi. Je marque comme résolue cette conversation.

Oui je vois, rien à redire et de toute façon je n’ai pas mieux à proposer, ok pour moi. Je marque comme résolue cette conversation.
pmarillonnet marked this conversation as resolved
@ -0,0 +15,4 @@
name='docket_number_format',
field=models.CharField(
default='B{regie_id:02d}-{yy}-{mm}-{number:07d}',
max_length=100,
Owner

Pas compris l’intérêt de limiter autant ce format sur le modèle de régie, lequel est a priori instancié en un nombre d’objets très limité. N’est-ce pas uniquement la longueur de l’identifiant généré à partir de ce format qu’il convient de contrôler ?

Pas compris l’intérêt de limiter autant ce format sur le modèle de régie, lequel est a priori instancié en un nombre d’objets très limité. N’est-ce pas uniquement la longueur de l’identifiant généré à partir de ce format qu’il convient de contrôler ?
Author
Owner

pas réfléchi plus que ça, les autres compteurs aussi ont un max_length à 100, et les formatted_number ont un max_length à 200, ce qui devrait suffire

pas réfléchi plus que ça, les autres compteurs aussi ont un max_length à 100, et les formatted_number ont un max_length à 200, ce qui devrait suffire
Owner

Ok.

Ok.
pmarillonnet marked this conversation as resolved
@ -0,0 +44,4 @@
('number', models.PositiveIntegerField(default=0)),
('formatted_number', models.CharField(max_length=200)),
('date_end', models.DateField(verbose_name='End date')),
('draft', models.BooleanField()),
Owner

Peut-être is_draft (pour ne pas croire à tort que ce champ est un accesseur vers les brouillons antérieurs du bordereau) ?

Peut-être `is_draft` (pour ne pas croire à tort que ce champ est un accesseur vers les brouillons antérieurs du bordereau) ?
Author
Owner

on a draft aussi sur les campagnes, et tu ne l'as pas relevé :)
je peux changer ici si tu insistes

on a draft aussi sur les campagnes, et tu ne l'as pas relevé :) je peux changer ici si tu insistes
Owner

Non, je n’ai pas vu que c’était ainsi par ailleurs, et je relève mais n’insiste pas :)
Laissons ainsi.

Non, je n’ai pas vu que c’était ainsi par ailleurs, et je relève mais n’insiste pas :) Laissons ainsi.
pmarillonnet marked this conversation as resolved
@ -0,0 +56,4 @@
],
),
migrations.AddField(
model_name='payment',
Owner

Je vais voir si je capte mieux dans la suite de la relecture, mais je ne comprends pas le choix de la FK dans ce sens et pas l’inverse. L’intuition me dit que c’est le paiement l’objet principal, vers lequel le bordereau, en tant qu’objet secondaire, pointe.

Edit: Ok, je comprends mieux à la lecture de la suite de la PR.

Je vais voir si je capte mieux dans la suite de la relecture, mais je ne comprends pas le choix de la FK dans ce sens et pas l’inverse. L’intuition me dit que c’est le paiement l’objet principal, vers lequel le bordereau, en tant qu’objet secondaire, pointe. Edit: Ok, je comprends mieux à la lecture de la suite de la PR.
Author
Owner

un payment ne peut être inclus que dans un seul bordereau :)

un payment ne peut être inclus que dans un seul bordereau :)
Owner

Oui j’ai capté ça en cours de route, c’est bon pour moi.

Oui j’ai capté ça en cours de route, c’est bon pour moi.
pmarillonnet marked this conversation as resolved
@ -401,4 +413,1 @@
data['cashier_role'] = Group.objects.get(name=role_name)
except Group.DoesNotExists:
raise RegieImportError('Missing role: %s' % role_name)
except Group.MultipleObjectsReturned:
Owner

Ok, je ne savais pas que la définition du Group de django.contrib.auth impose l’unicité sur le nom, top.

Ok, je ne savais pas que la définition du `Group` de `django.contrib.auth` impose l’unicité sur le nom, top.
pmarillonnet marked this conversation as resolved
@ -1338,0 +1355,4 @@
date_end = models.DateField(_('End date'))
draft = models.BooleanField()
payment_types = models.ManyToManyField(PaymentType)
payment_types_info = models.JSONField(blank=True, default=dict)
Owner

Note pour moi-même, aller voir à quoi ça correspond dans le code ajouté par les commits successifs.

Note pour moi-même, aller voir à quoi ça correspond dans le code ajouté par les commits successifs.
Owner

Ok, davantage capté, à la lecture des commits successifs, à quoi sert ce JSONField.

Ok, davantage capté, à la lecture des commits successifs, à quoi sert ce JSONField.
pmarillonnet marked this conversation as resolved
@ -0,0 +44,4 @@
{% block sidebar %}
<aside id="sidebar">
{% if not has_draft %}
Owner

Peut-être ici un {% else %} avec un message indiquant que l’action de création d’un nouveau bordereau n’est pas disponible car il y a déjà des bordereaux à l’état de brouillons ? (Je vois déjà arriver les tickets clients “L’action « Nouveau bordereau » a disparu”).

Peut-être ici un {% else %} avec un message indiquant que l’action de création d’un nouveau bordereau n’est pas disponible car il y a déjà des bordereaux à l’état de brouillons ? (Je vois déjà arriver les tickets clients “L’action « Nouveau bordereau » a disparu”).
Author
Owner

je fais ça dans un fixup (avec une copie d'écran attaché à la PR)

je fais ça dans un fixup (avec une copie d'écran attaché à la PR)
Owner

Top, je te remercie.

Top, je te remercie.
pmarillonnet marked this conversation as resolved
@ -736,0 +762,4 @@
def get_queryset(self):
self.filterset = RegieDocketPaymentFilterSet(
data=self.request.GET or None,
queryset=Payment.objects.filter(regie=self.regie, docket__isnull=True, cancelled_at__isnull=True)
Owner

J’ai du mal à comprendre le besoin fonctionnel d’exposer une liste des “paiements hors bordereaux” (“payments outside dockets”). Ça correspond à quoi en réalité ?

Edit: ok, pigé dans la suite de la relecture des commits successifs de cette PR.

J’ai du mal à comprendre le besoin fonctionnel d’exposer une liste des “paiements hors bordereaux” (“payments outside dockets”). Ça correspond à quoi en réalité ? Edit: ok, pigé dans la suite de la relecture des commits successifs de cette PR.
pmarillonnet marked this conversation as resolved
@ -736,0 +854,4 @@
'payment_types': request.GET.getlist('payment_type'),
'date_end': request.GET.get('date_end'),
}
if request.GET
Owner

Ça correspond à quelle disjonction, ce test request.GET évalué à vrai ou non, sans chercher davantage à creuser ce que ce dictionnaire contiendrait ? Ça correspond à quels cas ?
À vue de nez on dirait qu’on cherche à faire dans def get(…): ce qu’une CreateView opérerait normalement dans def post(…):.

Ça correspond à quelle disjonction, ce test `request.GET` évalué à vrai ou non, sans chercher davantage à creuser ce que ce dictionnaire contiendrait ? Ça correspond à quels cas ? À vue de nez on dirait qu’on cherche à faire dans `def get(…):` ce qu’une CreateView opérerait normalement dans `def post(…):`.
Author
Owner

effectivement, je voulais qu'au click sur le bouton "créer", s'il y a des trucs dans request.GET, qui viennent du listing des paiements non remis et du filtrage qui a été fait, et qu'il n'y a pas d'erreur, faire ce qui est fait normalement en POST. En gros, zapper la page de présentation du formulaire qu'on doit submit, pour éviter de remontrer à l'usager un formulaire qu'il a déjà renseigné sur la page de listing

effectivement, je voulais qu'au click sur le bouton "créer", s'il y a des trucs dans request.GET, qui viennent du listing des paiements non remis et du filtrage qui a été fait, et qu'il n'y a pas d'erreur, faire ce qui est fait normalement en POST. En gros, zapper la page de présentation du formulaire qu'on doit submit, pour éviter de remontrer à l'usager un formulaire qu'il a déjà renseigné sur la page de listing
Owner

Ah oui ok, je comprends mieux, merci.

Ah oui ok, je comprends mieux, merci.
pmarillonnet marked this conversation as resolved
pmarillonnet reviewed 2024-04-04 10:42:14 +02:00
pmarillonnet left a comment
Owner

(La second partie de cette première relecture)

(La second partie de cette première relecture)
@ -1338,0 +1362,4 @@
def __str__(self):
if self.draft:
return '%s-%s' % (_('TEMPORARY'), self.pk)
Owner

Est-ce qu’on a pas intérêt à gérer (dans un autre ticket) aussi un format de brouillon paramétrable ? Est-ce qu’on est certain que le format fixé à 'TEMPORARY-' va convenir à coup sûr ?

Est-ce qu’on a pas intérêt à gérer (dans un autre ticket) aussi un format de brouillon paramétrable ? Est-ce qu’on est certain que le format fixé à 'TEMPORARY-<pk>' va convenir à coup sûr ?
Author
Owner

on numérote les factures temporaires aussi comme ça, et on ne veut pas consommer un compteur pour un draft

on numérote les factures temporaires aussi comme ça, et on ne veut pas consommer un compteur pour un draft
Owner

Ah oui il y a la gestion des compteurs aussi, c’est vrai. Ok.

Ah oui il y a la gestion des compteurs aussi, c’est vrai. Ok.
pmarillonnet marked this conversation as resolved
@ -0,0 +32,4 @@
{% for payment_type in docket.payment_types.all %}{{ payment_type }}{% if not forloop.last %}, {% endif %}{% endfor %}
</td>
<td>
{% if docket.active_count %}<span class="meta meta-success">{{ docket.active_count }} ({% blocktrans with amount=docket.active_amount|floatformat:"2" %}{{ amount }}€{% endblocktrans %})</span>{% endif %}
Owner

Ici juste ça va afficher un chiffre suivi d’un montant en euros entre parenthèses. Niveau UI c’est les classes meta-success et meta-warning qui permettent de distinguer si on parle de paiements actifs ou de paiements annulés ?
Est-ce qu’on aurait pas intérêt à préciser à chaque fois, en toutes lettres, dans lequel des deux cas on se situe, genre 2 actifs (34.34 €) ou 7 annulés (187.87 €) ?

Ici juste ça va afficher un chiffre suivi d’un montant en euros entre parenthèses. Niveau UI c’est les classes `meta-success` et `meta-warning` qui permettent de distinguer si on parle de paiements actifs ou de paiements annulés ? Est-ce qu’on aurait pas intérêt à préciser à chaque fois, en toutes lettres, dans lequel des deux cas on se situe, genre `2 actifs (34.34 €)` ou `7 annulés (187.87 €)` ?
Author
Owner

ça a été vu avec stef, il a validé en l'état; sur les campagnes aussi on a juste des nombres et une différence de couleur
on pourra toujours revenir dessus plus tard si besoin :)

ça a été vu avec stef, il a validé en l'état; sur les campagnes aussi on a juste des nombres et une différence de couleur on pourra toujours revenir dessus plus tard si besoin :)
Owner

Ok, très bien alors, laissons comme ça.

Ok, très bien alors, laissons comme ça.
pmarillonnet marked this conversation as resolved
@ -211,0 +218,4 @@
regie_views.regie_docket_list,
name='lingo-manager-invoicing-regie-docket-list',
),
path(
Owner

Je loupe peut-être un truc mais j’ai l’impression qu’il manquerait une vue pour éditer un bordereau existant (je vois bien des vues du genre DocketAdd, DocketDelete, DocketList et DocketDetails pas mais de vue DocketEdit). C’est volontaire genre c’est un objet qu’on n’est pas censé éditer directement ainsi (seulement le type de paiement via RegieDocketPaymentTypeEditView), ou bien c’est un oubli ?

Je loupe peut-être un truc mais j’ai l’impression qu’il manquerait une vue pour éditer un bordereau existant (je vois bien des vues du genre DocketAdd, DocketDelete, DocketList et DocketDetails pas mais de vue DocketEdit). C’est volontaire genre c’est un objet qu’on n’est pas censé éditer directement ainsi (seulement le type de paiement via `RegieDocketPaymentTypeEditView`), ou bien c’est un oubli ?
Owner

Ah, c’est la PR suivante, #88699, top.

Ah, c’est la PR suivante, #88699, top.
pmarillonnet marked this conversation as resolved
@ -736,0 +810,4 @@
.annotate(
active_count=Coalesce(Subquery(active_count, output_field=IntegerField()), Value(0)),
cancelled_count=Coalesce(Subquery(cancelled_count, output_field=IntegerField()), Value(0)),
active_amount=Coalesce(Subquery(active_amount, output_field=IntegerField()), Value(0)),
Owner

On écrase les centimes ici en envoyant ça dans un IntegerField au lieu d’un flottant, non ? (pareil pour la ligne du dessous)

On écrase les centimes ici en envoyant ça dans un `IntegerField` au lieu d’un flottant, non ? (pareil pour la ligne du dessous)
Author
Owner

bien vu, merci

bien vu, merci
Author
Owner

fixup

fixup
pmarillonnet marked this conversation as resolved
lguerin added 2 commits 2024-04-04 14:57:25 +02:00
Author
Owner
lguerin added 1 commit 2024-04-04 15:07:43 +02:00
gitea/lingo/pipeline/head This commit looks good Details
db1df8067c
fixup! invoicing: list dockets (#88698)
Owner

Top, merci.

> Top, merci.
Owner

Je vais refaire un tour un peu plus macro pour voir si j’aurais loupé un truc à la première relecture, mais a priori j’ai plus grand chose à redire (et le ack va s’ensuivre).

Je vais refaire un tour un peu plus macro pour voir si j’aurais loupé un truc à la première relecture, mais a priori j’ai plus grand chose à redire (et le ack va s’ensuivre).
pmarillonnet approved these changes 2024-04-04 15:52:27 +02:00
pmarillonnet left a comment
Owner

J’ai refait un tour un peu plus en diagonale, rien à redire. Merci pour tes réponses détaillées à mes interrogations et incompréhensions initiales. Ack.

J’ai refait un tour un peu plus en diagonale, rien à redire. Merci pour tes réponses détaillées à mes interrogations et incompréhensions initiales. Ack.
lguerin force-pushed wip/88698-invoicing-docket from db1df8067c to 71d6242cb3 2024-04-04 15:54:09 +02:00 Compare
lguerin force-pushed wip/88698-invoicing-docket from 71d6242cb3 to 9602043df4 2024-04-08 08:58:24 +02:00 Compare
lguerin merged commit 9602043df4 into main 2024-04-08 09:57:36 +02:00
lguerin deleted branch wip/88698-invoicing-docket 2024-04-08 09:57:36 +02:00
Sign in to join this conversation.
No reviewers
No Label
No Milestone
No Assignees
2 Participants
Notifications
Due Date
The due date is invalid or out of range. Please use the format 'yyyy-mm-dd'.

No due date set.

Dependencies

No dependencies set.

Reference: entrouvert/lingo#177
No description provided.