Skip to content
GitLab
Projects
Groups
Snippets
Help
Loading...
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
R
re2o
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Service Desk
Milestones
Merge Requests
1
Merge Requests
1
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Operations
Operations
Incidents
Environments
Analytics
Analytics
CI / CD
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
Nounous
re2o
Commits
f7657a22
Commit
f7657a22
authored
Jan 12, 2018
by
Hugo LEVY-FALK
Committed by
root
Jan 28, 2018
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Rechargement via comnpay du solde.
parent
d9ebb266
Changes
15
Hide whitespace changes
Inline
Side-by-side
Showing
15 changed files
with
343 additions
and
6 deletions
+343
-6
cotisations/forms.py
cotisations/forms.py
+8
-0
cotisations/models.py
cotisations/models.py
+1
-1
cotisations/payment.py
cotisations/payment.py
+101
-0
cotisations/payment_utils/__init__.py
cotisations/payment_utils/__init__.py
+0
-0
cotisations/payment_utils/comnpay.py
cotisations/payment_utils/comnpay.py
+68
-0
cotisations/templates/cotisations/payment.html
cotisations/templates/cotisations/payment.html
+37
-0
cotisations/templates/cotisations/recharge.html
cotisations/templates/cotisations/recharge.html
+39
-0
cotisations/urls.py
cotisations/urls.py
+16
-0
cotisations/views.py
cotisations/views.py
+23
-0
machines/models.py
machines/models.py
+1
-0
preferences/forms.py
preferences/forms.py
+1
-1
preferences/migrations/0029_auto_20180111_1134.py
preferences/migrations/0029_auto_20180111_1134.py
+20
-0
preferences/migrations/0030_auto_20180111_2346.py
preferences/migrations/0030_auto_20180111_2346.py
+24
-0
preferences/models.py
preferences/models.py
+2
-2
preferences/templates/preferences/display_preferences.html
preferences/templates/preferences/display_preferences.html
+2
-2
No files found.
cotisations/forms.py
View file @
f7657a22
...
...
@@ -279,3 +279,11 @@ class NewFactureSoldeForm(NewFactureForm):
raise
forms
.
ValidationError
(
"Le numéro de chèque et
\
la banque sont obligatoires."
)
return
cleaned_data
class
RechargeForm
(
Form
):
value
=
forms
.
FloatField
(
label
=
'Valeur'
,
min_value
=
0.01
,
validators
=
[]
)
cotisations/models.py
View file @
f7657a22
...
...
@@ -289,7 +289,7 @@ class Vente(models.Model):
if
not
user_request
.
has_perm
(
'cotisations.change_vente'
):
return
False
,
u
"Vous n'avez pas le droit d'éditer les ventes"
elif
not
user_request
.
has_perm
(
'cotisations.change_all_facture'
)
and
not
self
.
facture
.
user
.
can_edit
(
user_request
,
*
args
,
**
kwargs
)[
0
]:
return
False
,
u
"Vous ne pouvez pas éditer les factures de cet user protégé"
return
False
,
u
"Vous ne pouvez pas éditer les factures de cet user protégé"
elif
not
user_request
.
has_perm
(
'cotisations.change_all_vente'
)
and
\
(
self
.
facture
.
control
or
not
self
.
facture
.
valid
):
return
False
,
u
"Vous n'avez pas le droit d'éditer une vente
\
...
...
cotisations/payment.py
0 → 100644
View file @
f7657a22
"""Payment
Here are defined some views dedicated to online payement.
"""
from
django.urls
import
reverse
from
django.shortcuts
import
redirect
,
get_object_or_404
from
django.contrib.auth.decorators
import
login_required
from
django.contrib
import
messages
from
django.views.decorators.csrf
import
csrf_exempt
from
django.utils.datastructures
import
MultiValueDictKeyError
from
django.http
import
HttpResponse
,
HttpResponseBadRequest
from
collections
import
OrderedDict
from
.models
import
Facture
from
.payment_utils.comnpay
import
Payment
as
ComnpayPayment
@
csrf_exempt
@
login_required
def
accept_payment
(
request
,
factureid
):
facture
=
get_object_or_404
(
Facture
,
id
=
factureid
)
messages
.
success
(
request
,
"Le paiement de {} € a été accepté."
.
format
(
facture
.
prix
())
)
return
redirect
(
reverse
(
'users:profil'
,
kwargs
=
{
'userid'
:
request
.
user
.
id
}))
@
csrf_exempt
@
login_required
def
refuse_payment
(
request
):
messages
.
error
(
request
,
"Le paiement a été refusé."
)
return
redirect
(
reverse
(
'users:profil'
,
kwargs
=
{
'userid'
:
request
.
user
.
id
}))
@
csrf_exempt
def
ipn
(
request
):
p
=
ComnpayPayment
()
order
=
(
'idTpe'
,
'idTransaction'
,
'montant'
,
'result'
,
'sec'
,
)
try
:
data
=
OrderedDict
([(
f
,
request
.
POST
[
f
])
for
f
in
order
])
except
MultiValueDictKeyError
:
return
HttpResponseBadRequest
(
"HTTP/1.1 400 Bad Request"
)
if
not
p
.
validSec
(
data
,
"DEMO"
):
return
HttpResponseBadRequest
(
"HTTP/1.1 400 Bad Request"
)
result
=
True
if
(
request
.
POST
[
'result'
]
==
'OK'
)
else
False
idTpe
=
request
.
POST
[
'idTpe'
]
idTransaction
=
request
.
POST
[
'idTransaction'
]
# On vérifie que le paiement nous est destiné
if
not
idTpe
==
"DEMO"
:
return
HttpResponseBadRequest
(
"HTTP/1.1 400 Bad Request"
)
try
:
factureid
=
int
(
idTransaction
)
except
ValueError
:
return
HttpResponseBadRequest
(
"HTTP/1.1 400 Bad Request"
)
facture
=
get_object_or_404
(
Facture
,
id
=
factureid
)
# On vérifie que le paiement est valide
if
not
result
:
# Le paiement a échoué : on effectue les actions nécessaires (On indique qu'elle a échoué)
facture
.
delete
()
# On notifie au serveur ComNPay qu'on a reçu les données pour traitement
return
HttpResponse
(
"HTTP/1.1 200 OK"
)
facture
.
valid
=
True
facture
.
save
()
# A nouveau, on notifie au serveur qu'on a bien traité les données
return
HttpResponse
(
"HTTP/1.0 200 OK"
)
def
comnpay
(
facture
,
host
):
p
=
ComnpayPayment
(
"DEMO"
,
"DEMO"
,
'https://'
+
host
+
reverse
(
'cotisations:accept_payment'
,
kwargs
=
{
'factureid'
:
facture
.
id
}),
'https://'
+
host
+
reverse
(
'cotisations:refuse_payment'
),
'https://'
+
host
+
reverse
(
'cotisations:ipn'
),
""
,
"D"
)
r
=
{
'action'
:
'https://secure.homologation.comnpay.com'
,
'method'
:
'POST'
,
'content'
:
p
.
buildSecretHTML
(
"Rechargement du solde"
,
facture
.
prix
(),
idTransaction
=
str
(
facture
.
id
)),
'amount'
:
facture
.
prix
,
}
return
r
PAYMENT_SYSTEM
=
{
'COMNPAY'
:
comnpay
,
'NONE'
:
None
}
cotisations/payment_utils/__init__.py
0 → 100644
View file @
f7657a22
cotisations/payment_utils/comnpay.py
0 → 100644
View file @
f7657a22
import
time
from
random
import
randrange
import
base64
import
hashlib
from
collections
import
OrderedDict
from
itertools
import
chain
class
Payment
():
vad_number
=
""
secret_key
=
""
urlRetourOK
=
""
urlRetourNOK
=
""
urlIPN
=
""
source
=
""
typeTr
=
"D"
def
__init__
(
self
,
vad_number
=
""
,
secret_key
=
""
,
urlRetourOK
=
""
,
urlRetourNOK
=
""
,
urlIPN
=
""
,
source
=
""
,
typeTr
=
"D"
):
self
.
vad_number
=
vad_number
self
.
secret_key
=
secret_key
self
.
urlRetourOK
=
urlRetourOK
self
.
urlRetourNOK
=
urlRetourNOK
self
.
urlIPN
=
urlIPN
self
.
source
=
source
self
.
typeTr
=
typeTr
def
buildSecretHTML
(
self
,
produit
=
"Produit"
,
montant
=
"0.00"
,
idTransaction
=
""
):
if
idTransaction
==
""
:
self
.
idTransaction
=
str
(
time
.
time
())
+
self
.
vad_number
+
str
(
randrange
(
999
))
else
:
self
.
idTransaction
=
idTransaction
array_tpe
=
OrderedDict
(
montant
=
str
(
montant
),
idTPE
=
self
.
vad_number
,
idTransaction
=
self
.
idTransaction
,
devise
=
"EUR"
,
lang
=
'fr'
,
nom_produit
=
produit
,
source
=
self
.
source
,
urlRetourOK
=
self
.
urlRetourOK
,
urlRetourNOK
=
self
.
urlRetourNOK
,
typeTr
=
str
(
self
.
typeTr
)
)
if
self
.
urlIPN
!=
""
:
array_tpe
[
'urlIPN'
]
=
self
.
urlIPN
array_tpe
[
'key'
]
=
self
.
secret_key
;
strWithKey
=
base64
.
b64encode
(
bytes
(
'|'
.
join
(
array_tpe
.
values
()),
'utf-8'
))
del
array_tpe
[
"key"
]
array_tpe
[
'sec'
]
=
hashlib
.
sha512
(
strWithKey
).
hexdigest
()
ret
=
""
for
key
in
array_tpe
:
ret
+=
'<input type="hidden" name="'
+
key
+
'" value="'
+
array_tpe
[
key
]
+
'"/>'
return
ret
def
validSec
(
self
,
values
,
secret_key
):
if
"sec"
in
values
:
sec
=
values
[
'sec'
]
del
values
[
"sec"
]
strWithKey
=
hashlib
.
sha512
(
base64
.
b64encode
(
bytes
(
'|'
.
join
(
values
.
values
())
+
"|"
+
secret_key
,
'utf-8'
))).
hexdigest
()
return
strWithKey
.
upper
()
==
sec
.
upper
()
else
:
return
False
cotisations/templates/cotisations/payment.html
0 → 100644
View file @
f7657a22
{% extends "cotisations/sidebar.html" %}
{% comment %}
Re2o est un logiciel d'administration développé initiallement au rezometz. Il
se veut agnostique au réseau considéré, de manière à être installable en
quelques clics.
Copyright © 2017 Gabriel Détraz
Copyright © 2017 Goulven Kermarec
Copyright © 2017 Augustin Lemesle
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License along
with this program; if not, write to the Free Software Foundation, Inc.,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
{% endcomment %}
{% load bootstrap3 %}
{% load staticfiles%}
{% block title %}Rechargement du solde{% endblock %}
{% block content %}
<h3>
Recharger de {{ amount }} €
</h3>
<form
class=
"form"
method=
"{{ method }}"
action=
"{{action}}"
>
{{ content | safe }}
{% bootstrap_button "Payer" button_type="submit" icon="piggy-bank" %}
</form>
{% endblock %}
cotisations/templates/cotisations/recharge.html
0 → 100644
View file @
f7657a22
{% extends "cotisations/sidebar.html" %}
{% comment %}
Re2o est un logiciel d'administration développé initiallement au rezometz. Il
se veut agnostique au réseau considéré, de manière à être installable en
quelques clics.
Copyright © 2017 Gabriel Détraz
Copyright © 2017 Goulven Kermarec
Copyright © 2017 Augustin Lemesle
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License along
with this program; if not, write to the Free Software Foundation, Inc.,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
{% endcomment %}
{% load bootstrap3 %}
{% load staticfiles%}
{% block title %}Rechargement du solde{% endblock %}
{% block content %}
<h3>
Rechargement du solde
</h3>
<p>
Solde de l'utilisateur : {{ request.user.solde }} €
</p>
<form
class=
"form"
method=
"post"
>
{% csrf_token %}
{% bootstrap_form rechargeform %}
{% bootstrap_button "Valider" button_type="submit" icon="piggy-bank" %}
</form>
{% endblock %}
cotisations/urls.py
View file @
f7657a22
...
...
@@ -115,5 +115,21 @@ urlpatterns = [
views
.
new_facture_solde
,
name
=
'new_facture_solde'
),
url
(
r
'^recharge/$'
,
views
.
recharge
,
name
=
'recharge'
),
url
(
r
'^payment/accept/(?P<factureid>[0-9]+)$'
,
payment
.
accept_payment
,
name
=
'accept_payment'
),
url
(
r
'^payment/refuse/$'
,
payment
.
refuse_payment
,
name
=
'refuse_payment'
),
url
(
r
'^payment/ipn/$'
,
payment
.
ipn
,
name
=
'ipn'
),
url
(
r
'^$'
,
views
.
index
,
name
=
'index'
),
]
cotisations/views.py
View file @
f7657a22
...
...
@@ -37,6 +37,8 @@ from django.db import transaction
from
django.db.models
import
Q
from
django.forms
import
modelformset_factory
,
formset_factory
from
django.utils
import
timezone
from
django.views.decorators.csrf
import
csrf_exempt
from
django.views.decorators.debug
import
sensitive_variables
from
reversion
import
revisions
as
reversion
from
reversion.models
import
Version
# Import des models, forms et fonctions re2o
...
...
@@ -72,6 +74,7 @@ from .forms import (
NewFactureSoldeForm
,
RechargeForm
)
from
.
import
payment
from
.tex
import
render_invoice
...
...
@@ -682,3 +685,23 @@ def new_facture_solde(request, userid):
},
'cotisations/new_facture_solde.html'
,
request
)
@
login_required
def
recharge
(
request
):
f
=
RechargeForm
(
request
.
POST
or
None
)
if
f
.
is_valid
():
facture
=
Facture
(
user
=
request
.
user
)
paiement
,
_created
=
Paiement
.
objects
.
get_or_create
(
moyen
=
'Rechargement en ligne'
)
facture
.
paiement
=
paiement
facture
.
valid
=
False
facture
.
save
()
v
=
Vente
.
objects
.
create
(
facture
=
facture
,
name
=
'solde'
,
prix
=
f
.
cleaned_data
[
'value'
],
number
=
1
,
)
v
.
save
()
options
,
_created
=
AssoOption
.
objects
.
get_or_create
()
content
=
payment
.
PAYMENT_SYSTEM
[
options
.
payment
](
facture
,
request
.
get_host
())
return
render
(
request
,
'cotisations/payment.html'
,
content
)
return
form
({
'rechargeform'
:
f
},
'cotisations/recharge.html'
,
request
)
machines/models.py
View file @
f7657a22
...
...
@@ -2153,3 +2153,4 @@ def srv_post_save(sender, **kwargs):
def
text_post_delete
(
sender
,
**
kwargs
):
"""Regeneration dns après modification d'un SRV"""
regen
(
'dns'
)
preferences/forms.py
View file @
f7657a22
...
...
@@ -48,7 +48,7 @@ class EditOptionalUserForm(ModelForm):
téléphone'
self
.
fields
[
'user_solde'
].
label
=
'Activation du solde pour
\
les utilisateurs'
self
.
fields
[
'max_
recharge'
].
label
=
'Rechargement max
'
self
.
fields
[
'max_
solde'
].
label
=
'Solde maximum
'
class
EditOptionalMachineForm
(
ModelForm
):
...
...
preferences/migrations/0029_auto_20180111_1134.py
0 → 100644
View file @
f7657a22
# -*- coding: utf-8 -*-
# Generated by Django 1.10.7 on 2018-01-11 10:34
from
__future__
import
unicode_literals
from
django.db
import
migrations
,
models
class
Migration
(
migrations
.
Migration
):
dependencies
=
[
(
'preferences'
,
'0028_auto_20180111_1129'
),
]
operations
=
[
migrations
.
AddField
(
model_name
=
'assooption'
,
name
=
'payment'
,
field
=
models
.
CharField
(
choices
=
[(
'NONE'
,
'NONE'
),
(
'COMNPAY'
,
'COMNPAY'
)],
default
=
'NONE'
,
max_length
=
255
),
),
]
preferences/migrations/0030_auto_20180111_2346.py
0 → 100644
View file @
f7657a22
# -*- coding: utf-8 -*-
# Generated by Django 1.10.7 on 2018-01-11 22:46
from
__future__
import
unicode_literals
from
django.db
import
migrations
,
models
class
Migration
(
migrations
.
Migration
):
dependencies
=
[
(
'preferences'
,
'0029_auto_20180111_1134'
),
]
operations
=
[
migrations
.
RemoveField
(
model_name
=
'optionaluser'
,
name
=
'max_recharge'
,
),
migrations
.
AddField
(
model_name
=
'optionaluser'
,
name
=
'max_solde'
,
field
=
models
.
DecimalField
(
decimal_places
=
2
,
default
=
50
,
max_digits
=
5
),
),
]
preferences/models.py
View file @
f7657a22
...
...
@@ -41,10 +41,10 @@ class OptionalUser(models.Model):
decimal_places
=
2
,
default
=
0
)
max_
recharg
e
=
models
.
DecimalField
(
max_
sold
e
=
models
.
DecimalField
(
max_digits
=
5
,
decimal_places
=
2
,
default
=
10
0
default
=
5
0
)
gpg_fingerprint
=
models
.
BooleanField
(
default
=
True
)
all_can_create
=
models
.
BooleanField
(
...
...
preferences/templates/preferences/display_preferences.html
View file @
f7657a22
...
...
@@ -55,8 +55,8 @@ with this program; if not, write to the Free Software Foundation, Inc.,
<th>
Creations d'users par tous
</th>
<td>
{{ useroptions.all_can_create }}
</td>
{% if useroptions.user_solde %}
<th>
Rechargement max
</th>
<td>
{{ useroptions.max_
recharg
e }}
</td>
<th>
Solde maximum
</th>
<td>
{{ useroptions.max_
sold
e }}
</td>
{% endif %}
</tr>
</table>
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
.
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment