First commit
This commit is contained in:
commit
f3df8d70e1
5 changed files with 666 additions and 0 deletions
302
.gitignore
vendored
Normal file
302
.gitignore
vendored
Normal 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
24
.latexmkrc
Normal 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
14
Makefile
Normal 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
BIN
presentation.pdf
Normal file
Binary file not shown.
326
presentation.tex
Normal file
326
presentation.tex
Normal 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 C’est ce qui est utilisé par l’objet \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}
|
Loading…
Reference in a new issue