First commit

This commit is contained in:
Hugo Levy-Falk 2021-07-10 21:42:45 +02:00
commit f3df8d70e1
5 changed files with 666 additions and 0 deletions

302
.gitignore vendored Normal file
View file

@ -0,0 +1,302 @@
# Created by https://www.toptal.com/developers/gitignore/api/latex
# Edit at https://www.toptal.com/developers/gitignore?templates=latex
### LaTeX ###
## Core latex/pdflatex auxiliary files:
*.aux
*.lof
*.log
*.lot
*.fls
*.out
*.toc
*.fmt
*.fot
*.cb
*.cb2
.*.lb
## Intermediate documents:
*.dvi
*.xdv
*-converted-to.*
# these rules might exclude image files for figures etc.
# *.ps
# *.eps
# *.pdf
## Generated if empty string is given at "Please type another file name for output:"
.pdf
## Bibliography auxiliary files (bibtex/biblatex/biber):
*.bbl
*.bcf
*.blg
*-blx.aux
*-blx.bib
*.run.xml
## Build tool auxiliary files:
*.fdb_latexmk
*.synctex
*.synctex(busy)
*.synctex.gz
*.synctex.gz(busy)
*.pdfsync
## Build tool directories for auxiliary files
# latexrun
latex.out/
## Auxiliary and intermediate files from other packages:
# algorithms
*.alg
*.loa
# achemso
acs-*.bib
# amsthm
*.thm
# beamer
*.nav
*.pre
*.snm
*.vrb
# changes
*.soc
# comment
*.cut
# cprotect
*.cpt
# elsarticle (documentclass of Elsevier journals)
*.spl
# endnotes
*.ent
# fixme
*.lox
# feynmf/feynmp
*.mf
*.mp
*.t[1-9]
*.t[1-9][0-9]
*.tfm
#(r)(e)ledmac/(r)(e)ledpar
*.end
*.?end
*.[1-9]
*.[1-9][0-9]
*.[1-9][0-9][0-9]
*.[1-9]R
*.[1-9][0-9]R
*.[1-9][0-9][0-9]R
*.eledsec[1-9]
*.eledsec[1-9]R
*.eledsec[1-9][0-9]
*.eledsec[1-9][0-9]R
*.eledsec[1-9][0-9][0-9]
*.eledsec[1-9][0-9][0-9]R
# glossaries
*.acn
*.acr
*.glg
*.glo
*.gls
*.glsdefs
*.lzo
*.lzs
# uncomment this for glossaries-extra (will ignore makeindex's style files!)
# *.ist
# gnuplottex
*-gnuplottex-*
# gregoriotex
*.gaux
*.glog
*.gtex
# htlatex
*.4ct
*.4tc
*.idv
*.lg
*.trc
*.xref
# hyperref
*.brf
# knitr
*-concordance.tex
# TODO Uncomment the next line if you use knitr and want to ignore its generated tikz files
# *.tikz
*-tikzDictionary
# listings
*.lol
# luatexja-ruby
*.ltjruby
# makeidx
*.idx
*.ilg
*.ind
# minitoc
*.maf
*.mlf
*.mlt
*.mtc[0-9]*
*.slf[0-9]*
*.slt[0-9]*
*.stc[0-9]*
# minted
_minted*
*.pyg
# morewrites
*.mw
# newpax
*.newpax
# nomencl
*.nlg
*.nlo
*.nls
# pax
*.pax
# pdfpcnotes
*.pdfpc
# sagetex
*.sagetex.sage
*.sagetex.py
*.sagetex.scmd
# scrwfile
*.wrt
# sympy
*.sout
*.sympy
sympy-plots-for-*.tex/
# pdfcomment
*.upa
*.upb
# pythontex
*.pytxcode
pythontex-files-*/
# tcolorbox
*.listing
# thmtools
*.loe
# TikZ & PGF
*.dpth
*.md5
*.auxlock
# todonotes
*.tdo
# vhistory
*.hst
*.ver
# easy-todo
*.lod
# xcolor
*.xcp
# xmpincl
*.xmpi
# xindy
*.xdy
# xypic precompiled matrices and outlines
*.xyc
*.xyd
# endfloat
*.ttt
*.fff
# Latexian
TSWLatexianTemp*
## Editors:
# WinEdt
*.bak
*.sav
# Texpad
.texpadtmp
# LyX
*.lyx~
# Kile
*.backup
# gummi
.*.swp
# KBibTeX
*~[0-9]*
# TeXnicCenter
*.tps
# auto folder when using emacs and auctex
./auto/*
*.el
# expex forward references with \gathertags
*-tags.tex
# standalone packages
*.sta
# Makeindex log files
*.lpz
# xwatermark package
*.xwm
# REVTeX puts footnotes in the bibliography by default, unless the nofootinbib
# option is specified. Footnotes are the stored in a file with suffix Notes.bib.
# Uncomment the next line to have this generated file ignored.
#*Notes.bib
### LaTeX Patch ###
# LIPIcs / OASIcs
*.vtc
# glossaries
*.glstex
# End of https://www.toptal.com/developers/gitignore/api/latex

24
.latexmkrc Normal file
View file

@ -0,0 +1,24 @@
# LaTeXmk configuration file
# Usage example
# latexmk file.tex
# Main command line options
# -pdf : generate pdf using pdflatex
# -pv : run file previewer
# -pvc : run file previewer and continually recompile on change
# -C : clean up by removing all regeneratable files
# Generate pdf using pdflatex (-pdf)
$pdf_mode = 1;
# Define command to compile with pdfsync support and nonstopmode
$pdflatex = 'lualatex -shell-escape';
# Use default pdf viewer (Skim)
$pdf_previewer = 'evince';
# Also remove pdfsync files on clean
$clean_ext = 'pdfsync synctex.gz';
$ENV{'TEXINPUTS'}='/home/klafyvel/Documents/asso/rezo/formations/SystèmePaiementRe2o/rmrf-latex:' . $ENV{'TEXINPUTS'};

14
Makefile Normal file
View file

@ -0,0 +1,14 @@
# Makefile for presentation
.PHONY: presentation.pdf all clean
all: presentation.pdf
presentation.pdf: presentation.tex
latexmk -use-make $<
cleanall:
latexmk -C
clean:
latexmk -c

BIN
presentation.pdf Normal file

Binary file not shown.

326
presentation.tex Normal file
View file

@ -0,0 +1,326 @@
\documentclass[10pt,xcolor={table,dvipsnames},t, aspectratio=169]{beamer}
\usepackage{minted}
\usetheme{rmrf}
\title{Re2o et les cotisations}
\subtitle{Rézo Rennes et Metz Fédérés}
\author{Klafyvel}
\date{10/07/2021}
\begin{document}
\begin{frame}
\titlepage
\end{frame}
\begin{frame}{Sommaire}
\tableofcontents
\end{frame}
\begin{frame}
\vspace{2cm}
\centering{\Huge\textbf{Contrainte principale :}\\Ne pas faire de la merde avec les sous des adhérents.}
\end{frame}
\section{Les principales structures de données}
\begin{frame}[fragile]{L'objet Facture}
\begin{columns}
\begin{column}{0.5\textwidth}
\begin{itemize}
\item<1-> Représente une facture;
\item<2-> Visible par les adhérents;
\item<3-> Est censé être controlée par les trésoriers.
\end{itemize}
\end{column}
\begin{column}{0.5\textwidth}
\begin{minted}[fontsize=\footnotesize,]{python}
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(...)
\end{minted}
\end{column}
\end{columns}
\end{frame}
\begin{frame}[fragile]{L'objet Vente}
\begin{columns}
\begin{column}{0.5\textwidth}
\begin{itemize}
\item Représente une vente de \verb|number| articles(s) au prix unitaire \verb|prix|;
\item Stocke une information sur la durée d'adhésion / cotisation.
\end{itemize}
\end{column}
\begin{column}{0.5\textwidth}
\begin{minted}[fontsize=\footnotesize,]{python}
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(...)
\end{minted}
\end{column}
\end{columns}
\end{frame}
\begin{frame}[fragile]{L'objet Article}
\begin{columns}
\begin{column}{0.5\textwidth}
\begin{itemize}
\item Une recette pour créer des \verb|Vente|s;
\item On ne lie pas directement les ventes aux articles, on peut supprimer les articles sans contrainte.
\end{itemize}
\end{column}
\begin{column}{0.5\textwidth}
\begin{minted}[fontsize=\footnotesize,]{python}
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(...)
\end{minted}
\end{column}
\end{columns}
\end{frame}
\begin{frame}[fragile]{L'objet Cotisation}
\begin{columns}
\begin{column}{0.5\textwidth}
\begin{itemize}
\item Information sur les adhésions / cotisations des utilisateurs;
\item Cest ce qui est utilisé par lobjet \verb|User| pour savoir si un utilisateur est adhérent.
\end{itemize}
\end{column}
\begin{column}{0.5\textwidth}
\begin{minted}[fontsize=\footnotesize,]{python}
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(...)
\end{minted}
\end{column}
\end{columns}
\end{frame}
\begin{frame}[fragile]{L'objet Paiement}
\begin{columns}
\begin{column}{0.5\textwidth}
\begin{itemize}
\item Enregistre un moyen de paiement;
\item On peut y brancher des méthodes de paiement personnalisées.
\end{itemize}
\end{column}
\begin{column}{0.5\textwidth}
\begin{minted}[fontsize=\footnotesize,]{python}
class Paiement(RevMixin, AclMixin, models.Model):
moyen = models.CharField(...)
available_for_everyone = models.BooleanField(...)
is_balance = models.BooleanField(...)
\end{minted}
\end{column}
\end{columns}
\end{frame}
\section{La vue new\_facture}
\begin{frame}[fragile]
\begin{columns}
\begin{column}{0.5\textwidth}
\begin{minted}[fontsize=\footnotesize,]{python}
@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
return form(...)
\end{minted}
\end{column}
\begin{column}{0.5\textwidth}
Vue assez classique de formulaire Django.
\end{column}
\end{columns}
\end{frame}
\begin{frame}[fragile]{À l'intérieur de ce if}
\begin{minted}[fontsize=\footnotesize,]{python}
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 in articles):
# Encore un peu de patience, slide suivante
else :
messages.error(request, _("You need to choose at least one article."))
\end{minted}
\end{frame}
\begin{frame}
\vspace{2cm}
\centering{\Huge\textbf{Roulement de tambours...}}
\end{frame}
\begin{frame}[fragile]
\begin{columns}
\begin{column}{0.5\textwidth}
\begin{minted}[fontsize=\footnotesize,]{python}
# 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)
if hasattr(p, "check_price"):
price_ok, msg = p.check_price(total_price, user)
invoice_form.add_error(None, msg)
else:
price_ok = True
\end{minted}
\end{column}
\begin{column}{0.5\textwidth}
\begin{minted}[fontsize=\footnotesize,]{python}
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
)
\end{minted}
\end{column}
\end{columns}
\end{frame}
\begin{frame}[fragile]{Le retour du modèle Paiement}
\begin{columns}
\begin{column}{0.5\textwidth}
Pour finir un paiement,
\begin{itemize}
\item Si une méthode de paiement personnalisée existe et que la transisition n'est pas explicitement interdite, on branche;
\item Sinon on valide la facture, on affiche un message et on redirige.
\end{itemize}
\end{column}
\begin{column}{0.5\textwidth}
\begin{minted}[fontsize=\footnotesize,]{python}
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)
# Du code pas intéressant
return redirect(...)
\end{minted}
\end{column}
\end{columns}
\end{frame}
\section{Un exemple simple : FreePayment}
\begin{frame}[fragile]
\begin{columns}
\begin{column}{0.5\textwidth}
\begin{minted}[fontsize=\footnotesize,]{python}
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,
)
\end{minted}
\end{column}
\begin{column}{0.5\textwidth}
\begin{minted}[fontsize=\footnotesize,]{python}
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.")
)
\end{minted}
\end{column}
\end{columns}
\end{frame}
\section{Un exemple intéressant : ComnPay}
\begin{frame}{Déroulé}
\begin{itemize}
\item<2-> Le end\_payment construit une requête spéciale pour que l'utilisateur l'envoie vers comnpay. La facture est invalide;
\item<3-> L'utilisateur fait son affaire avec ComnPay;
\item<4-> ComnPay notifie re2o que le paiement a été effectué. La facture est validée;
\item<5-> L'utilisateur est redirigé vers re2o.
\end{itemize}
\end{frame}
\begin{frame}
\vspace{2cm}
\centering{\Huge\textbf{Un petit tour dans le code.}}
\end{frame}
\section{Conclusion}
\begin{frame}{Conclusion}
\begin{itemize}
\item Le système de paiement est modulable;
\item Mais du coup il est complexe;
\item Pour intégrer HelloAsso il faudrait s'inspirer du système ComnPay.
\end{itemize}
\end{frame}
\end{document}