• Aucun résultat trouvé

Re2o et les cotisations

N/A
N/A
Protected

Academic year: 2022

Partager "Re2o et les cotisations"

Copied!
28
0
0

Texte intégral

(1)

Re2o et les cotisations

Rézo Rennes et Metz Fédérés

Klafyvel

10/07/2021

(2)

Sommaire

Les principales structures de données

La vue new_facture

Un exemple simple : FreePayment

Un exemple intéressant : ComnPay

Conclusion

(3)

Contrainte principale :

Ne pas faire de la merde avec les sous des

adhérents.

(4)

Les principales structures de données

(5)

L’objet Facture

• Représente une facture;

• Visible par les adhérents;

• Est censé être controlée par les trésoriers.

class Facture(BaseInvoice):

user = models.ForeignKey("users.User",...) paiement = models.ForeignKey("Paiement", ...) banque = models.ForeignKey("Banque", ...) cheque = models.CharField(...)

valid = models.BooleanField(...) control = models.BooleanField(...)

(6)

L’objet Facture

• Représente une facture;

• Visible par les adhérents;

• Est censé être controlée par les trésoriers.

class Facture(BaseInvoice):

user = models.ForeignKey("users.User",...) paiement = models.ForeignKey("Paiement", ...) banque = models.ForeignKey("Banque", ...) cheque = models.CharField(...)

valid = models.BooleanField(...) control = models.BooleanField(...)

(7)

L’objet Facture

• Représente une facture;

• Visible par les adhérents;

• Est censé être controlée par les trésoriers.

class Facture(BaseInvoice):

user = models.ForeignKey("users.User",...) paiement = models.ForeignKey("Paiement", ...) banque = models.ForeignKey("Banque", ...) cheque = models.CharField(...)

valid = models.BooleanField(...) control = models.BooleanField(...)

(8)

L’objet Vente

• Représente une vente de

number

articles(s) au prix unitaire

prix

;

• Stocke une information sur la durée d’adhésion / cotisation.

class Vente(RevMixin, AclMixin, models.Model):

facture = models.ForeignKey("BaseInvoice", ...) number = models.IntegerField(...)

name = models.CharField(...) prix = models.DecimalField(...)

duration_connection = models.PositiveIntegerField(...) duration_days_connection = models.PositiveIntegerField(...) duration_membership = models.PositiveIntegerField(...) duration_days_membership = models.PositiveIntegerField(...)

(9)

L’objet Article

• Une recette pour créer des

Vente

s;

• On ne lie pas directement les ventes aux articles, on peut supprimer les articles sans contrainte.

class Article(RevMixin, AclMixin, models.Model):

name = models.CharField(...) prix = models.DecimalField(...)

duration_membership = models.PositiveIntegerField(...) duration_days_membership = models.PositiveIntegerField(...) duration_connection = models.PositiveIntegerField(...) duration_days_connection = models.PositiveIntegerField(...) need_membership = models.BooleanField(...)

type_user = models.CharField(...)

available_for_everyone = models.BooleanField(...)

(10)

L’objet Cotisation

• Information sur les adhésions / cotisations des utilisateurs;

• C’est ce qui est utilisé par l’objet

User

pour savoir si un utilisateur est adhérent.

class Cotisation(RevMixin, AclMixin, models.Model):

vente = models.OneToOneField("Vente",...) date_start_con = models.DateTimeField(...) date_end_con = models.DateTimeField(...) date_start_memb = models.DateTimeField(...) date_end_memb = models.DateTimeField(...)

(11)

L’objet Paiement

• Enregistre un moyen de paiement;

• On peut y brancher des méthodes de paiement personnalisées.

class Paiement(RevMixin, AclMixin, models.Model):

moyen = models.CharField(...)

available_for_everyone = models.BooleanField(...) is_balance = models.BooleanField(...)

(12)

La vue new_facture

(13)

@login_required

@can_create(Facture)

@can_edit(User)

def new_facture(request, user, userid):

"""De la doc..."""

invoice = Facture(user=user)

article_list = Article.objects.filter(...) invoice_form = FactureForm(...)

article_formset = formset_factory(SelectArticleForm)(...) if invoice_form.is_valid() and article_formset.is_valid():

# On verra après

# Gestion du solde

p = Paiement.objects.filter(is_balance=True) if len(p) and p[0].can_use_payment(request.user):

balance = user.solde else:

balance = None

Vue assez classique de formulaire Django.

(14)

À l’intérieur de ce if

new_invoice_instance = invoice_form.save(commit=False) articles = article_formset

# Check if at least one article has been selected if any(art.cleaned_data for art inarticles):

# Encore un peu de patience, slide suivante else :

messages.error(request, _("You need to choose at least one article."))

(15)

Roulement de tambours...

(16)

# Building a purchase for each article sold purchases = []

total_price = 0

for art_item in articles:

if art_item.cleaned_data:

article = art_item.cleaned_data["article"]

quantity = art_item.cleaned_data["quantity"]

total_price += article.prix * quantity new_purchase = Vente(...)

purchases.append(new_purchase)

p = find_payment_method(new_invoice_instance.paiement) ifhasattr(p, "check_price"):

price_ok, msg = p.check_price(total_price, user) invoice_form.add_error(None, msg)

else:

price_ok = True

if price_ok:

new_invoice_instance.save()

# Saving purchases so the invoice can find them. Invoice

# will modify them after being validated to put the right dates.

for p in purchases:

p.facture = new_invoice_instance p.save()

return new_invoice_instance.paiement.end_payment(

new_invoice_instance, request )

(17)

Le retour du modèle Paiement

Pour finir un paiement,

• Si une méthode de paiement personnalisée existe et que la transisition n’est pas explicitement interdite, on branche;

• Sinon on valide la facture, on affiche un message et on redirige.

def end_payment(self, invoice, request, use_payment_method=True):

payment_method = find_payment_method(self) if payment_method is not None \

and use_payment_method:

return payment_method.end_payment(invoice, request)

# So make this invoice valid, trigger send mail invoice.valid = True

invoice.save(request=request)

(18)

Un exemple simple : FreePayment

(19)

class FreePayment(PaymentMethodMixin, models.Model):

"""..."""

class Meta:

verbose_name = _("Free payment") payment = models.OneToOneField(

Paiement,

on_delete=models.CASCADE,

related_name="payment_method_free", editable=False,

)

def end_payment(self, invoice, request):

"""Ends the payment normally.

"""

return invoice.paiement.end_payment(invoice, request,

use_payment_method=False )

def check_price(self, price, user, *args, **kwargs):

"""Checks that the price meets the requirement to be paid with user balance.

"""

return ( price == 0,

_("You can't pay this invoice for free.") )

(20)

Un exemple intéressant : ComnPay

(21)

Déroulé

• Le end_payment construit une requête spéciale pour que l’utilisateur l’envoie vers comnpay. La facture est invalide;

• L’utilisateur fait son affaire avec ComnPay;

• ComnPay notifie re2o que le paiement a été effectué. La facture est validée;

• L’utilisateur est redirigé vers re2o.

(22)

Déroulé

• Le end_payment construit une requête spéciale pour que l’utilisateur l’envoie vers comnpay. La facture est invalide;

• L’utilisateur fait son affaire avec ComnPay;

• ComnPay notifie re2o que le paiement a été effectué. La facture est validée;

• L’utilisateur est redirigé vers re2o.

(23)

Déroulé

• Le end_payment construit une requête spéciale pour que l’utilisateur l’envoie vers comnpay. La facture est invalide;

• L’utilisateur fait son affaire avec ComnPay;

• ComnPay notifie re2o que le paiement a été effectué. La facture est validée;

• L’utilisateur est redirigé vers re2o.

(24)

Déroulé

• Le end_payment construit une requête spéciale pour que l’utilisateur l’envoie vers comnpay. La facture est invalide;

• L’utilisateur fait son affaire avec ComnPay;

• ComnPay notifie re2o que le paiement a été effectué. La facture est validée;

• L’utilisateur est redirigé vers re2o.

(25)

Déroulé

• Le end_payment construit une requête spéciale pour que l’utilisateur l’envoie vers comnpay. La facture est invalide;

• L’utilisateur fait son affaire avec ComnPay;

• ComnPay notifie re2o que le paiement a été effectué. La facture est validée;

• L’utilisateur est redirigé vers re2o.

(26)

Un petit tour dans le code.

(27)

Conclusion

(28)

Conclusion

• Le système de paiement est modulable;

• Mais du coup il est complexe;

• Pour intégrer HelloAsso il faudrait s’inspirer du système ComnPay.

Références

Documents relatifs

De plus, s’il est possible de modéliser une antenne comme la ZL Spé- ciale en se contentant de défi nir correctement les amplitudes et déphasages des courants qui

note_ue1 : ce champ est de type Réel qui affiche un numérique avec 2 chiffres après la virgule, la valeur la plus grande est 99,99.. note_ue2 : ce champ est de type Réel

En tant que Act Tank international, Turritopsis, l’Institut Stratégique de Développent Durable (ISDD) fait partie des acteurs ayant un rôle important dans la promotion

Calculer l'escompte prévu pour les clients professionnels et présenter l'écriture comptable qu'il génère (facture avoir n° AV 74K8). Vous en recevrez confirmation

nécessaire afin de sélectionner les données qui correspondent aux attentes de l’utilisateur Bien que OFBiz dispose d’un outil qui permet de filtrer les données provenant

Ce n’est que bien plus tard dans les années 1940 que ce terme prend avec Pontrjagin son sens algébrique en théorie des groupes puis (dans les années 1960) que George Birkhoff

[r]

Ainsi, Anna découvre que plus elle est libre, plus elle devient créative, mieux elle vit sa formidable sensibilité et plus elle est heureuse, dans un cercle vertueux qui se met