mirror of
https://gitlab2.federez.net/re2o/re2o
synced 2024-11-25 22:22:26 +00:00
Release : 2.8
This commit is contained in:
commit
56fdfca1aa
759 changed files with 27074 additions and 16710 deletions
25
CHANGELOG.md
25
CHANGELOG.md
|
@ -178,3 +178,28 @@ Be carefull, you need the proper rights to edit a DocumentTemplate.
|
|||
Re2o now sends subscription voucher when an invoice is controlled. It uses one
|
||||
of the templates. You also need to set the name of the president of your association
|
||||
to be set in your settings.
|
||||
|
||||
## MR 427: Tickets
|
||||
Manually edit `settings_local.py` to provide the new `OPTIONNAL_APPS` lists:
|
||||
```python
|
||||
OPTIONNAL_APPS_RE2O = ('tickets',)
|
||||
OPTIONNAL_APPS = OPTIONNAL_APPS_RE2O + (...,...,)
|
||||
```
|
||||
|
||||
Don't forget to run migrations afterwards.
|
||||
|
||||
## MR 433 : upgrade django-ldapdb to 1.3.0
|
||||
|
||||
Uninstall the existing django-ldapdb installation
|
||||
|
||||
pip3 uninstall django-ldapdb
|
||||
|
||||
Install debian(buster) supported version
|
||||
|
||||
apt install python3-django-ldapdb
|
||||
|
||||
If you use MySQL, please run
|
||||
|
||||
```
|
||||
SET GLOBAL SQL_MODE=ANSI_QUOTES;
|
||||
```
|
||||
|
|
18
api/acl.py
18
api/acl.py
|
@ -40,14 +40,14 @@ def _create_api_permission():
|
|||
"""
|
||||
api_content_type, created = ContentType.objects.get_or_create(
|
||||
app_label=settings.API_CONTENT_TYPE_APP_LABEL,
|
||||
model=settings.API_CONTENT_TYPE_MODEL
|
||||
model=settings.API_CONTENT_TYPE_MODEL,
|
||||
)
|
||||
if created:
|
||||
api_content_type.save()
|
||||
api_permission, created = Permission.objects.get_or_create(
|
||||
name=settings.API_PERMISSION_NAME,
|
||||
content_type=api_content_type,
|
||||
codename=settings.API_PERMISSION_CODENAME
|
||||
codename=settings.API_PERMISSION_CODENAME,
|
||||
)
|
||||
if created:
|
||||
api_permission.save()
|
||||
|
@ -67,9 +67,13 @@ def can_view(user):
|
|||
viewing is granted and msg is a message (can be None).
|
||||
"""
|
||||
kwargs = {
|
||||
'app_label': settings.API_CONTENT_TYPE_APP_LABEL,
|
||||
'codename': settings.API_PERMISSION_CODENAME
|
||||
"app_label": settings.API_CONTENT_TYPE_APP_LABEL,
|
||||
"codename": settings.API_PERMISSION_CODENAME,
|
||||
}
|
||||
can = user.has_perm('%(app_label)s.%(codename)s' % kwargs)
|
||||
return can, None if can else _("You don't have the right to see this"
|
||||
" application.")
|
||||
permission = "%(app_label)s.%(codename)s" % kwargs
|
||||
can = user.has_perm(permission)
|
||||
return (
|
||||
can,
|
||||
None if can else _("You don't have the right to view this application."),
|
||||
(permission,),
|
||||
)
|
||||
|
|
|
@ -41,9 +41,7 @@ class ExpiringTokenAuthentication(TokenAuthentication):
|
|||
user, token = base.authenticate_credentials(key)
|
||||
|
||||
# Check that the genration time of the token is not too old
|
||||
token_duration = datetime.timedelta(
|
||||
seconds=settings.API_TOKEN_DURATION
|
||||
)
|
||||
token_duration = datetime.timedelta(seconds=settings.API_TOKEN_DURATION)
|
||||
utc_now = datetime.datetime.now(datetime.timezone.utc)
|
||||
if token.created < utc_now - token_duration:
|
||||
raise exceptions.AuthenticationFailed(_("The token has expired."))
|
||||
|
|
|
@ -21,7 +21,7 @@ msgid ""
|
|||
msgstr ""
|
||||
"Project-Id-Version: 2.5\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2019-01-08 23:06+0100\n"
|
||||
"POT-Creation-Date: 2019-11-19 23:43+0100\n"
|
||||
"PO-Revision-Date: 2019-01-07 01:37+0100\n"
|
||||
"Last-Translator: Laouen Fernet <laouen.fernet@supelec.fr>\n"
|
||||
"Language-Team: \n"
|
||||
|
@ -31,10 +31,10 @@ msgstr ""
|
|||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"Plural-Forms: nplurals=2; plural=(n > 1);\n"
|
||||
|
||||
#: acl.py:74
|
||||
msgid "You don't have the right to see this application."
|
||||
#: api/acl.py:77
|
||||
msgid "You don't have the right to view this application."
|
||||
msgstr "Vous n'avez pas le droit de voir cette application."
|
||||
|
||||
#: authentication.py:49
|
||||
#: api/authentication.py:47
|
||||
msgid "The token has expired."
|
||||
msgstr "Le jeton a expiré."
|
||||
|
|
|
@ -38,8 +38,9 @@ class PageSizedPagination(pagination.PageNumberPagination):
|
|||
max_page_size: The maximum number of results a page can output no
|
||||
matter what is requested.
|
||||
"""
|
||||
page_size_query_param = 'page_size'
|
||||
all_pages_strings = ('all',)
|
||||
|
||||
page_size_query_param = "page_size"
|
||||
all_pages_strings = ("all",)
|
||||
max_page_size = 10000
|
||||
|
||||
def get_page_size(self, request):
|
||||
|
|
|
@ -55,17 +55,21 @@ def _get_param_in_view(view, param_name):
|
|||
AssertionError: None of the getter function or the attribute are
|
||||
defined in the view.
|
||||
"""
|
||||
assert hasattr(view, 'get_' + param_name) \
|
||||
or getattr(view, param_name, None) is not None, (
|
||||
'cannot apply {} on a view that does not set '
|
||||
'`.{}` or have a `.get_{}()` method.'
|
||||
).format(self.__class__.__name__, param_name, param_name)
|
||||
assert (
|
||||
hasattr(view, "get_" + param_name)
|
||||
or getattr(view, param_name, None) is not None
|
||||
), (
|
||||
"cannot apply {} on a view that does not set "
|
||||
"`.{}` or have a `.get_{}()` method."
|
||||
).format(
|
||||
self.__class__.__name__, param_name, param_name
|
||||
)
|
||||
|
||||
if hasattr(view, 'get_' + param_name):
|
||||
param = getattr(view, 'get_' + param_name)()
|
||||
assert param is not None, (
|
||||
'{}.get_{}() returned None'
|
||||
).format(view.__class__.__name__, param_name)
|
||||
if hasattr(view, "get_" + param_name):
|
||||
param = getattr(view, "get_" + param_name)()
|
||||
assert param is not None, ("{}.get_{}() returned None").format(
|
||||
view.__class__.__name__, param_name
|
||||
)
|
||||
return param
|
||||
return getattr(view, param_name)
|
||||
|
||||
|
@ -97,7 +101,7 @@ class ACLPermission(permissions.BasePermission):
|
|||
rest_framework.exception.MethodNotAllowed: The requested method
|
||||
is not allowed for this view.
|
||||
"""
|
||||
perms_map = _get_param_in_view(view, 'perms_map')
|
||||
perms_map = _get_param_in_view(view, "perms_map")
|
||||
|
||||
if method not in perms_map:
|
||||
raise exceptions.MethodNotAllowed(method)
|
||||
|
@ -123,7 +127,7 @@ class ACLPermission(permissions.BasePermission):
|
|||
"""
|
||||
# Workaround to ensure ACLPermissions are not applied
|
||||
# to the root view when using DefaultRouter.
|
||||
if getattr(view, '_ignore_model_permissions', False):
|
||||
if getattr(view, "_ignore_model_permissions", False):
|
||||
return True
|
||||
|
||||
if not request.user or not request.user.is_authenticated:
|
||||
|
@ -148,22 +152,22 @@ class AutodetectACLPermission(permissions.BasePermission):
|
|||
"""
|
||||
|
||||
perms_map = {
|
||||
'GET': [can_see_api, lambda model: model.can_view_all],
|
||||
'OPTIONS': [can_see_api, lambda model: model.can_view_all],
|
||||
'HEAD': [can_see_api, lambda model: model.can_view_all],
|
||||
'POST': [can_see_api, lambda model: model.can_create],
|
||||
'PUT': [], # No restrictions, apply to objects
|
||||
'PATCH': [], # No restrictions, apply to objects
|
||||
'DELETE': [], # No restrictions, apply to objects
|
||||
"GET": [can_see_api, lambda model: model.can_view_all],
|
||||
"OPTIONS": [can_see_api, lambda model: model.can_view_all],
|
||||
"HEAD": [can_see_api, lambda model: model.can_view_all],
|
||||
"POST": [can_see_api, lambda model: model.can_create],
|
||||
"PUT": [], # No restrictions, apply to objects
|
||||
"PATCH": [], # No restrictions, apply to objects
|
||||
"DELETE": [], # No restrictions, apply to objects
|
||||
}
|
||||
perms_obj_map = {
|
||||
'GET': [can_see_api, lambda obj: obj.can_view],
|
||||
'OPTIONS': [can_see_api, lambda obj: obj.can_view],
|
||||
'HEAD': [can_see_api, lambda obj: obj.can_view],
|
||||
'POST': [], # No restrictions, apply to models
|
||||
'PUT': [can_see_api, lambda obj: obj.can_edit],
|
||||
'PATCH': [can_see_api, lambda obj: obj.can_edit],
|
||||
'DELETE': [can_see_api, lambda obj: obj.can_delete],
|
||||
"GET": [can_see_api, lambda obj: obj.can_view],
|
||||
"OPTIONS": [can_see_api, lambda obj: obj.can_view],
|
||||
"HEAD": [can_see_api, lambda obj: obj.can_view],
|
||||
"POST": [], # No restrictions, apply to models
|
||||
"PUT": [can_see_api, lambda obj: obj.can_edit],
|
||||
"PATCH": [can_see_api, lambda obj: obj.can_edit],
|
||||
"DELETE": [can_see_api, lambda obj: obj.can_delete],
|
||||
}
|
||||
|
||||
def get_required_permissions(self, method, model):
|
||||
|
@ -210,7 +214,7 @@ class AutodetectACLPermission(permissions.BasePermission):
|
|||
|
||||
@staticmethod
|
||||
def _queryset(view):
|
||||
return _get_param_in_view(view, 'queryset')
|
||||
return _get_param_in_view(view, "queryset")
|
||||
|
||||
def has_permission(self, request, view):
|
||||
"""Check that the user has the model-based permissions to perform
|
||||
|
@ -232,7 +236,7 @@ class AutodetectACLPermission(permissions.BasePermission):
|
|||
"""
|
||||
# Workaround to ensure ACLPermissions are not applied
|
||||
# to the root view when using DefaultRouter.
|
||||
if getattr(view, '_ignore_model_permissions', False):
|
||||
if getattr(view, "_ignore_model_permissions", False):
|
||||
return True
|
||||
|
||||
if not request.user or not request.user.is_authenticated:
|
||||
|
@ -274,7 +278,7 @@ class AutodetectACLPermission(permissions.BasePermission):
|
|||
# to make another lookup.
|
||||
raise Http404
|
||||
|
||||
read_perms = self.get_required_object_permissions('GET', obj)
|
||||
read_perms = self.get_required_object_permissions("GET", obj)
|
||||
if not read_perms(request.user)[0]:
|
||||
raise Http404
|
||||
|
||||
|
|
|
@ -74,9 +74,9 @@ class AllViewsRouter(DefaultRouter):
|
|||
Returns:
|
||||
The name to use for this route.
|
||||
"""
|
||||
return pattern.split('/')[-1]
|
||||
return pattern.split("/")[-1]
|
||||
|
||||
def get_api_root_view(self, schema_urls=None):
|
||||
def get_api_root_view(self, schema_urls=None, api_urls=None):
|
||||
"""Create a class-based view to use as the API root.
|
||||
|
||||
Highly inspired by the base class. See details on the implementation
|
||||
|
@ -102,12 +102,10 @@ class AllViewsRouter(DefaultRouter):
|
|||
if schema_urls and self.schema_title:
|
||||
view_renderers += list(self.schema_renderers)
|
||||
schema_generator = SchemaGenerator(
|
||||
title=self.schema_title,
|
||||
patterns=schema_urls
|
||||
title=self.schema_title, patterns=schema_urls
|
||||
)
|
||||
schema_media_types = [
|
||||
renderer.media_type
|
||||
for renderer in self.schema_renderers
|
||||
renderer.media_type for renderer in self.schema_renderers
|
||||
]
|
||||
|
||||
class APIRoot(views.APIView):
|
||||
|
@ -128,14 +126,14 @@ class AllViewsRouter(DefaultRouter):
|
|||
namespace = request.resolver_match.namespace
|
||||
for key, url_name in api_root_dict.items():
|
||||
if namespace:
|
||||
url_name = namespace + ':' + url_name
|
||||
url_name = namespace + ":" + url_name
|
||||
try:
|
||||
ret[key] = reverse(
|
||||
url_name,
|
||||
args=args,
|
||||
kwargs=kwargs,
|
||||
request=request,
|
||||
format=kwargs.get('format', None)
|
||||
format=kwargs.get("format", None),
|
||||
)
|
||||
except NoReverseMatch:
|
||||
# Don't bail out if eg. no list routes exist, only detail routes.
|
||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -24,28 +24,24 @@
|
|||
|
||||
# RestFramework config for API
|
||||
REST_FRAMEWORK = {
|
||||
'URL_FIELD_NAME': 'api_url',
|
||||
'DEFAULT_AUTHENTICATION_CLASSES': (
|
||||
'api.authentication.ExpiringTokenAuthentication',
|
||||
'rest_framework.authentication.SessionAuthentication',
|
||||
"URL_FIELD_NAME": "api_url",
|
||||
"DEFAULT_AUTHENTICATION_CLASSES": (
|
||||
"api.authentication.ExpiringTokenAuthentication",
|
||||
"rest_framework.authentication.SessionAuthentication",
|
||||
),
|
||||
'DEFAULT_PERMISSION_CLASSES': (
|
||||
'api.permissions.AutodetectACLPermission',
|
||||
),
|
||||
'DEFAULT_PAGINATION_CLASS': 'api.pagination.PageSizedPagination',
|
||||
'PAGE_SIZE': 100
|
||||
"DEFAULT_PERMISSION_CLASSES": ("api.permissions.AutodetectACLPermission",),
|
||||
"DEFAULT_PAGINATION_CLASS": "api.pagination.PageSizedPagination",
|
||||
"PAGE_SIZE": 100,
|
||||
}
|
||||
|
||||
# API permission settings
|
||||
API_CONTENT_TYPE_APP_LABEL = 'api'
|
||||
API_CONTENT_TYPE_MODEL = 'api'
|
||||
API_PERMISSION_NAME = 'Can use the API'
|
||||
API_PERMISSION_CODENAME = 'use_api'
|
||||
API_CONTENT_TYPE_APP_LABEL = "api"
|
||||
API_CONTENT_TYPE_MODEL = "api"
|
||||
API_PERMISSION_NAME = "Can use the API"
|
||||
API_PERMISSION_CODENAME = "use_api"
|
||||
|
||||
# Activate token authentication
|
||||
API_APPS = (
|
||||
'rest_framework.authtoken',
|
||||
)
|
||||
API_APPS = ("rest_framework.authtoken",)
|
||||
|
||||
# The expiration time for an authentication token
|
||||
API_TOKEN_DURATION = 86400 # 24 hours
|
||||
|
|
523
api/tests.py
523
api/tests.py
|
@ -50,171 +50,170 @@ class APIEndpointsTestCase(APITestCase):
|
|||
superuser: A superuser (with all permissions) used for the tests and
|
||||
initialized at the beggining of this test case.
|
||||
"""
|
||||
no_auth_endpoints = [
|
||||
'/api/'
|
||||
]
|
||||
|
||||
no_auth_endpoints = ["/api/"]
|
||||
auth_no_perm_endpoints = []
|
||||
auth_perm_endpoints = [
|
||||
'/api/cotisations/article/',
|
||||
'/api/cotisations/article/1/',
|
||||
'/api/cotisations/banque/',
|
||||
'/api/cotisations/banque/1/',
|
||||
'/api/cotisations/cotisation/',
|
||||
'/api/cotisations/cotisation/1/',
|
||||
'/api/cotisations/facture/',
|
||||
'/api/cotisations/facture/1/',
|
||||
'/api/cotisations/paiement/',
|
||||
'/api/cotisations/paiement/1/',
|
||||
'/api/cotisations/vente/',
|
||||
'/api/cotisations/vente/1/',
|
||||
'/api/machines/domain/',
|
||||
'/api/machines/domain/1/',
|
||||
'/api/machines/extension/',
|
||||
'/api/machines/extension/1/',
|
||||
'/api/machines/interface/',
|
||||
'/api/machines/interface/1/',
|
||||
'/api/machines/iplist/',
|
||||
'/api/machines/iplist/1/',
|
||||
'/api/machines/iptype/',
|
||||
'/api/machines/iptype/1/',
|
||||
'/api/machines/ipv6list/',
|
||||
'/api/machines/ipv6list/1/',
|
||||
'/api/machines/machine/',
|
||||
'/api/machines/machine/1/',
|
||||
'/api/machines/machinetype/',
|
||||
'/api/machines/machinetype/1/',
|
||||
'/api/machines/mx/',
|
||||
'/api/machines/mx/1/',
|
||||
'/api/machines/nas/',
|
||||
'/api/machines/nas/1/',
|
||||
'/api/machines/ns/',
|
||||
'/api/machines/ns/1/',
|
||||
'/api/machines/ouvertureportlist/',
|
||||
'/api/machines/ouvertureportlist/1/',
|
||||
'/api/machines/ouvertureport/',
|
||||
'/api/machines/ouvertureport/1/',
|
||||
'/api/machines/servicelink/',
|
||||
'/api/machines/servicelink/1/',
|
||||
'/api/machines/service/',
|
||||
'/api/machines/service/1/',
|
||||
'/api/machines/soa/',
|
||||
'/api/machines/soa/1/',
|
||||
'/api/machines/srv/',
|
||||
'/api/machines/srv/1/',
|
||||
'/api/machines/txt/',
|
||||
'/api/machines/txt/1/',
|
||||
'/api/machines/vlan/',
|
||||
'/api/machines/vlan/1/',
|
||||
'/api/preferences/optionaluser/',
|
||||
'/api/preferences/optionalmachine/',
|
||||
'/api/preferences/optionaltopologie/',
|
||||
'/api/preferences/generaloption/',
|
||||
'/api/preferences/service/',
|
||||
'/api/preferences/service/1/',
|
||||
'/api/preferences/assooption/',
|
||||
'/api/preferences/homeoption/',
|
||||
'/api/preferences/mailmessageoption/',
|
||||
'/api/topologie/acesspoint/',
|
||||
"/api/cotisations/article/",
|
||||
"/api/cotisations/article/1/",
|
||||
"/api/cotisations/banque/",
|
||||
"/api/cotisations/banque/1/",
|
||||
"/api/cotisations/cotisation/",
|
||||
"/api/cotisations/cotisation/1/",
|
||||
"/api/cotisations/facture/",
|
||||
"/api/cotisations/facture/1/",
|
||||
"/api/cotisations/paiement/",
|
||||
"/api/cotisations/paiement/1/",
|
||||
"/api/cotisations/vente/",
|
||||
"/api/cotisations/vente/1/",
|
||||
"/api/machines/domain/",
|
||||
"/api/machines/domain/1/",
|
||||
"/api/machines/extension/",
|
||||
"/api/machines/extension/1/",
|
||||
"/api/machines/interface/",
|
||||
"/api/machines/interface/1/",
|
||||
"/api/machines/iplist/",
|
||||
"/api/machines/iplist/1/",
|
||||
"/api/machines/iptype/",
|
||||
"/api/machines/iptype/1/",
|
||||
"/api/machines/ipv6list/",
|
||||
"/api/machines/ipv6list/1/",
|
||||
"/api/machines/machine/",
|
||||
"/api/machines/machine/1/",
|
||||
"/api/machines/machinetype/",
|
||||
"/api/machines/machinetype/1/",
|
||||
"/api/machines/mx/",
|
||||
"/api/machines/mx/1/",
|
||||
"/api/machines/nas/",
|
||||
"/api/machines/nas/1/",
|
||||
"/api/machines/ns/",
|
||||
"/api/machines/ns/1/",
|
||||
"/api/machines/ouvertureportlist/",
|
||||
"/api/machines/ouvertureportlist/1/",
|
||||
"/api/machines/ouvertureport/",
|
||||
"/api/machines/ouvertureport/1/",
|
||||
"/api/machines/servicelink/",
|
||||
"/api/machines/servicelink/1/",
|
||||
"/api/machines/service/",
|
||||
"/api/machines/service/1/",
|
||||
"/api/machines/soa/",
|
||||
"/api/machines/soa/1/",
|
||||
"/api/machines/srv/",
|
||||
"/api/machines/srv/1/",
|
||||
"/api/machines/txt/",
|
||||
"/api/machines/txt/1/",
|
||||
"/api/machines/vlan/",
|
||||
"/api/machines/vlan/1/",
|
||||
"/api/preferences/optionaluser/",
|
||||
"/api/preferences/optionalmachine/",
|
||||
"/api/preferences/optionaltopologie/",
|
||||
"/api/preferences/generaloption/",
|
||||
"/api/preferences/service/",
|
||||
"/api/preferences/service/1/",
|
||||
"/api/preferences/assooption/",
|
||||
"/api/preferences/homeoption/",
|
||||
"/api/preferences/mailmessageoption/",
|
||||
"/api/topologie/acesspoint/",
|
||||
# 2nd machine to be create (machines_machine_1, topologie_accesspoint_1)
|
||||
'/api/topologie/acesspoint/2/',
|
||||
'/api/topologie/building/',
|
||||
'/api/topologie/building/1/',
|
||||
'/api/topologie/constructorswitch/',
|
||||
'/api/topologie/constructorswitch/1/',
|
||||
'/api/topologie/modelswitch/',
|
||||
'/api/topologie/modelswitch/1/',
|
||||
'/api/topologie/room/',
|
||||
'/api/topologie/room/1/',
|
||||
'/api/topologie/server/',
|
||||
"/api/topologie/acesspoint/2/",
|
||||
"/api/topologie/building/",
|
||||
"/api/topologie/building/1/",
|
||||
"/api/topologie/constructorswitch/",
|
||||
"/api/topologie/constructorswitch/1/",
|
||||
"/api/topologie/modelswitch/",
|
||||
"/api/topologie/modelswitch/1/",
|
||||
"/api/topologie/room/",
|
||||
"/api/topologie/room/1/",
|
||||
"/api/topologie/server/",
|
||||
# 3rd machine to be create (machines_machine_1, topologie_accesspoint_1,
|
||||
# topologie_server_1)
|
||||
'/api/topologie/server/3/',
|
||||
'/api/topologie/stack/',
|
||||
'/api/topologie/stack/1/',
|
||||
'/api/topologie/switch/',
|
||||
"/api/topologie/server/3/",
|
||||
"/api/topologie/stack/",
|
||||
"/api/topologie/stack/1/",
|
||||
"/api/topologie/switch/",
|
||||
# 4th machine to be create (machines_machine_1, topologie_accesspoint_1,
|
||||
# topologie_server_1, topologie_switch_1)
|
||||
'/api/topologie/switch/4/',
|
||||
'/api/topologie/switchbay/',
|
||||
'/api/topologie/switchbay/1/',
|
||||
'/api/topologie/switchport/',
|
||||
'/api/topologie/switchport/1/',
|
||||
'/api/topologie/switchport/2/',
|
||||
'/api/topologie/switchport/3/',
|
||||
'/api/users/adherent/',
|
||||
"/api/topologie/switch/4/",
|
||||
"/api/topologie/switchbay/",
|
||||
"/api/topologie/switchbay/1/",
|
||||
"/api/topologie/switchport/",
|
||||
"/api/topologie/switchport/1/",
|
||||
"/api/topologie/switchport/2/",
|
||||
"/api/topologie/switchport/3/",
|
||||
"/api/users/adherent/",
|
||||
# 3rd user to be create (stduser, superuser, users_adherent_1)
|
||||
'/api/users/adherent/3/',
|
||||
'/api/users/ban/',
|
||||
'/api/users/ban/1/',
|
||||
'/api/users/club/',
|
||||
"/api/users/adherent/3/",
|
||||
"/api/users/ban/",
|
||||
"/api/users/ban/1/",
|
||||
"/api/users/club/",
|
||||
# 4th user to be create (stduser, superuser, users_adherent_1,
|
||||
# users_club_1)
|
||||
'/api/users/club/4/',
|
||||
'/api/users/listright/',
|
||||
"/api/users/club/4/",
|
||||
"/api/users/listright/",
|
||||
# TODO: Merge !145
|
||||
# '/api/users/listright/1/',
|
||||
'/api/users/school/',
|
||||
'/api/users/school/1/',
|
||||
'/api/users/serviceuser/',
|
||||
'/api/users/serviceuser/1/',
|
||||
'/api/users/shell/',
|
||||
'/api/users/shell/1/',
|
||||
'/api/users/user/',
|
||||
'/api/users/user/1/',
|
||||
'/api/users/whitelist/',
|
||||
'/api/users/whitelist/1/',
|
||||
'/api/dns/zones/',
|
||||
'/api/dhcp/hostmacip/',
|
||||
'/api/mailing/standard',
|
||||
'/api/mailing/club',
|
||||
'/api/services/regen/',
|
||||
"/api/users/school/",
|
||||
"/api/users/school/1/",
|
||||
"/api/users/serviceuser/",
|
||||
"/api/users/serviceuser/1/",
|
||||
"/api/users/shell/",
|
||||
"/api/users/shell/1/",
|
||||
"/api/users/user/",
|
||||
"/api/users/user/1/",
|
||||
"/api/users/whitelist/",
|
||||
"/api/users/whitelist/1/",
|
||||
"/api/dns/zones/",
|
||||
"/api/dhcp/hostmacip/",
|
||||
"/api/mailing/standard",
|
||||
"/api/mailing/club",
|
||||
"/api/services/regen/",
|
||||
]
|
||||
not_found_endpoints = [
|
||||
'/api/cotisations/article/4242/',
|
||||
'/api/cotisations/banque/4242/',
|
||||
'/api/cotisations/cotisation/4242/',
|
||||
'/api/cotisations/facture/4242/',
|
||||
'/api/cotisations/paiement/4242/',
|
||||
'/api/cotisations/vente/4242/',
|
||||
'/api/machines/domain/4242/',
|
||||
'/api/machines/extension/4242/',
|
||||
'/api/machines/interface/4242/',
|
||||
'/api/machines/iplist/4242/',
|
||||
'/api/machines/iptype/4242/',
|
||||
'/api/machines/ipv6list/4242/',
|
||||
'/api/machines/machine/4242/',
|
||||
'/api/machines/machinetype/4242/',
|
||||
'/api/machines/mx/4242/',
|
||||
'/api/machines/nas/4242/',
|
||||
'/api/machines/ns/4242/',
|
||||
'/api/machines/ouvertureportlist/4242/',
|
||||
'/api/machines/ouvertureport/4242/',
|
||||
'/api/machines/servicelink/4242/',
|
||||
'/api/machines/service/4242/',
|
||||
'/api/machines/soa/4242/',
|
||||
'/api/machines/srv/4242/',
|
||||
'/api/machines/txt/4242/',
|
||||
'/api/machines/vlan/4242/',
|
||||
'/api/preferences/service/4242/',
|
||||
'/api/topologie/acesspoint/4242/',
|
||||
'/api/topologie/building/4242/',
|
||||
'/api/topologie/constructorswitch/4242/',
|
||||
'/api/topologie/modelswitch/4242/',
|
||||
'/api/topologie/room/4242/',
|
||||
'/api/topologie/server/4242/',
|
||||
'/api/topologie/stack/4242/',
|
||||
'/api/topologie/switch/4242/',
|
||||
'/api/topologie/switchbay/4242/',
|
||||
'/api/topologie/switchport/4242/',
|
||||
'/api/users/adherent/4242/',
|
||||
'/api/users/ban/4242/',
|
||||
'/api/users/club/4242/',
|
||||
'/api/users/listright/4242/',
|
||||
'/api/users/school/4242/',
|
||||
'/api/users/serviceuser/4242/',
|
||||
'/api/users/shell/4242/',
|
||||
'/api/users/user/4242/',
|
||||
'/api/users/whitelist/4242/',
|
||||
"/api/cotisations/article/4242/",
|
||||
"/api/cotisations/banque/4242/",
|
||||
"/api/cotisations/cotisation/4242/",
|
||||
"/api/cotisations/facture/4242/",
|
||||
"/api/cotisations/paiement/4242/",
|
||||
"/api/cotisations/vente/4242/",
|
||||
"/api/machines/domain/4242/",
|
||||
"/api/machines/extension/4242/",
|
||||
"/api/machines/interface/4242/",
|
||||
"/api/machines/iplist/4242/",
|
||||
"/api/machines/iptype/4242/",
|
||||
"/api/machines/ipv6list/4242/",
|
||||
"/api/machines/machine/4242/",
|
||||
"/api/machines/machinetype/4242/",
|
||||
"/api/machines/mx/4242/",
|
||||
"/api/machines/nas/4242/",
|
||||
"/api/machines/ns/4242/",
|
||||
"/api/machines/ouvertureportlist/4242/",
|
||||
"/api/machines/ouvertureport/4242/",
|
||||
"/api/machines/servicelink/4242/",
|
||||
"/api/machines/service/4242/",
|
||||
"/api/machines/soa/4242/",
|
||||
"/api/machines/srv/4242/",
|
||||
"/api/machines/txt/4242/",
|
||||
"/api/machines/vlan/4242/",
|
||||
"/api/preferences/service/4242/",
|
||||
"/api/topologie/acesspoint/4242/",
|
||||
"/api/topologie/building/4242/",
|
||||
"/api/topologie/constructorswitch/4242/",
|
||||
"/api/topologie/modelswitch/4242/",
|
||||
"/api/topologie/room/4242/",
|
||||
"/api/topologie/server/4242/",
|
||||
"/api/topologie/stack/4242/",
|
||||
"/api/topologie/switch/4242/",
|
||||
"/api/topologie/switchbay/4242/",
|
||||
"/api/topologie/switchport/4242/",
|
||||
"/api/users/adherent/4242/",
|
||||
"/api/users/ban/4242/",
|
||||
"/api/users/club/4242/",
|
||||
"/api/users/listright/4242/",
|
||||
"/api/users/school/4242/",
|
||||
"/api/users/serviceuser/4242/",
|
||||
"/api/users/shell/4242/",
|
||||
"/api/users/user/4242/",
|
||||
"/api/users/whitelist/4242/",
|
||||
]
|
||||
|
||||
stduser = None
|
||||
|
@ -232,26 +231,18 @@ class APIEndpointsTestCase(APITestCase):
|
|||
|
||||
# A user with no rights
|
||||
cls.stduser = users.User.objects.create_user(
|
||||
"apistduser",
|
||||
"apistduser",
|
||||
"apistduser@example.net",
|
||||
"apistduser"
|
||||
"apistduser", "apistduser", "apistduser@example.net", "apistduser"
|
||||
)
|
||||
# A user with all the rights
|
||||
cls.superuser = users.User.objects.create_superuser(
|
||||
"apisuperuser",
|
||||
"apisuperuser",
|
||||
"apisuperuser@example.net",
|
||||
"apisuperuser"
|
||||
"apisuperuser", "apisuperuser", "apisuperuser@example.net", "apisuperuser"
|
||||
)
|
||||
|
||||
# Creates 1 instance for each object so the "details" endpoints
|
||||
# can be tested too. Objects need to be created in the right order.
|
||||
# Dependencies (relatedFields, ...) are highlighted by a comment at
|
||||
# the end of the concerned line (# Dep <model>).
|
||||
cls.users_school_1 = users.School.objects.create(
|
||||
name="users_school_1"
|
||||
)
|
||||
cls.users_school_1 = users.School.objects.create(name="users_school_1")
|
||||
cls.users_school_1.save()
|
||||
cls.users_listshell_1 = users.ListShell.objects.create(
|
||||
shell="users_listshell_1"
|
||||
|
@ -270,7 +261,7 @@ class APIEndpointsTestCase(APITestCase):
|
|||
registered=datetime.datetime.now(datetime.timezone.utc),
|
||||
telephone="0123456789",
|
||||
uid_number=21102,
|
||||
rezo_rez_uid=21102
|
||||
rezo_rez_uid=21102,
|
||||
)
|
||||
cls.users_user_1 = cls.users_adherent_1
|
||||
cls.cotisations_article_1 = cotisations.Article.objects.create(
|
||||
|
@ -278,14 +269,14 @@ class APIEndpointsTestCase(APITestCase):
|
|||
prix=10,
|
||||
duration=1,
|
||||
type_user=cotisations.Article.USER_TYPES[0][0],
|
||||
type_cotisation=cotisations.Article.COTISATION_TYPE[0][0]
|
||||
type_cotisation=cotisations.Article.COTISATION_TYPE[0][0],
|
||||
)
|
||||
cls.cotisations_banque_1 = cotisations.Banque.objects.create(
|
||||
name="cotisations_banque_1"
|
||||
)
|
||||
cls.cotisations_paiement_1 = cotisations.Paiement.objects.create(
|
||||
moyen="cotisations_paiement_1",
|
||||
type_paiement=cotisations.Paiement.PAYMENT_TYPES[0][0]
|
||||
type_paiement=cotisations.Paiement.PAYMENT_TYPES[0][0],
|
||||
)
|
||||
cls.cotisations_facture_1 = cotisations.Facture.objects.create(
|
||||
user=cls.users_user_1, # Dep users.User
|
||||
|
@ -294,7 +285,7 @@ class APIEndpointsTestCase(APITestCase):
|
|||
cheque="1234567890",
|
||||
date=datetime.datetime.now(datetime.timezone.utc),
|
||||
valid=True,
|
||||
control=False
|
||||
control=False,
|
||||
)
|
||||
cls.cotisations_vente_1 = cotisations.Vente.objects.create(
|
||||
facture=cls.cotisations_facture_1, # Dep cotisations.Facture
|
||||
|
@ -302,18 +293,18 @@ class APIEndpointsTestCase(APITestCase):
|
|||
name="cotisations_vente_1",
|
||||
prix=10,
|
||||
duration=1,
|
||||
type_cotisation=cotisations.Vente.COTISATION_TYPE[0][0]
|
||||
type_cotisation=cotisations.Vente.COTISATION_TYPE[0][0],
|
||||
)
|
||||
# A cotisation is automatically created by the Vente object and
|
||||
# trying to create another cotisation associated with this vente
|
||||
# will fail so we simply retrieve it so it can be used in the tests
|
||||
cls.cotisations_cotisation_1 = cotisations.Cotisation.objects.get(
|
||||
vente=cls.cotisations_vente_1, # Dep cotisations.Vente
|
||||
vente=cls.cotisations_vente_1 # Dep cotisations.Vente
|
||||
)
|
||||
cls.machines_machine_1 = machines.Machine.objects.create(
|
||||
user=cls.users_user_1, # Dep users.User
|
||||
name="machines_machine_1",
|
||||
active=True
|
||||
active=True,
|
||||
)
|
||||
cls.machines_ouvertureportlist_1 = machines.OuverturePortList.objects.create(
|
||||
name="machines_ouvertureportlist_1"
|
||||
|
@ -324,19 +315,17 @@ class APIEndpointsTestCase(APITestCase):
|
|||
refresh=86400,
|
||||
retry=7200,
|
||||
expire=3600000,
|
||||
ttl=172800
|
||||
ttl=172800,
|
||||
)
|
||||
cls.machines_extension_1 = machines.Extension.objects.create(
|
||||
name="machines_extension_1",
|
||||
need_infra=False,
|
||||
# Do not set origin because of circular dependency
|
||||
origin_v6="2001:db8:1234::",
|
||||
soa=cls.machines_soa_1 # Dep machines.SOA
|
||||
soa=cls.machines_soa_1, # Dep machines.SOA
|
||||
)
|
||||
cls.machines_vlan_1 = machines.Vlan.objects.create(
|
||||
vlan_id=0,
|
||||
name="machines_vlan_1",
|
||||
comment="machines Vlan 1"
|
||||
vlan_id=0, name="machines_vlan_1", comment="machines Vlan 1"
|
||||
)
|
||||
cls.machines_iptype_1 = machines.IpType.objects.create(
|
||||
type="machines_iptype_1",
|
||||
|
@ -346,13 +335,12 @@ class APIEndpointsTestCase(APITestCase):
|
|||
domaine_ip_stop="10.0.0.255",
|
||||
prefix_v6="2001:db8:1234::",
|
||||
vlan=cls.machines_vlan_1, # Dep machines.Vlan
|
||||
ouverture_ports=cls.machines_ouvertureportlist_1 # Dep machines.OuverturePortList
|
||||
ouverture_ports=cls.machines_ouvertureportlist_1, # Dep machines.OuverturePortList
|
||||
)
|
||||
# All IPs in the IpType range are autocreated so we can't create
|
||||
# new ones and thus we only retrieve it if needed in the tests
|
||||
cls.machines_iplist_1 = machines.IpList.objects.get(
|
||||
ipv4="10.0.0.1",
|
||||
ip_type=cls.machines_iptype_1, # Dep machines.IpType
|
||||
ipv4="10.0.0.1", ip_type=cls.machines_iptype_1 # Dep machines.IpType
|
||||
)
|
||||
cls.machines_machinetype_1 = machines.MachineType.objects.create(
|
||||
type="machines_machinetype_1",
|
||||
|
@ -375,16 +363,16 @@ class APIEndpointsTestCase(APITestCase):
|
|||
cls.machines_mx_1 = machines.Mx.objects.create(
|
||||
zone=cls.machines_extension_1, # Dep machines.Extension
|
||||
priority=10,
|
||||
name=cls.machines_domain_1 # Dep machines.Domain
|
||||
name=cls.machines_domain_1, # Dep machines.Domain
|
||||
)
|
||||
cls.machines_ns_1 = machines.Ns.objects.create(
|
||||
zone=cls.machines_extension_1, # Dep machines.Extension
|
||||
ns=cls.machines_domain_1 # Dep machines.Domain
|
||||
ns=cls.machines_domain_1, # Dep machines.Domain
|
||||
)
|
||||
cls.machines_txt_1 = machines.Txt.objects.create(
|
||||
zone=cls.machines_extension_1, # Dep machines.Extension
|
||||
field1="machines_txt_1",
|
||||
field2="machies Txt 1"
|
||||
field2="machies Txt 1",
|
||||
)
|
||||
cls.machines_srv_1 = machines.Srv.objects.create(
|
||||
service="machines_srv_1",
|
||||
|
@ -398,7 +386,7 @@ class APIEndpointsTestCase(APITestCase):
|
|||
cls.machines_ipv6list_1 = machines.Ipv6List.objects.create(
|
||||
ipv6="2001:db8:1234::",
|
||||
interface=cls.machines_interface_1, # Dep machines.Interface
|
||||
slaac_ip=False
|
||||
slaac_ip=False,
|
||||
)
|
||||
cls.machines_service_1 = machines.Service.objects.create(
|
||||
service_type="machines_service_1",
|
||||
|
@ -410,45 +398,45 @@ class APIEndpointsTestCase(APITestCase):
|
|||
service=cls.machines_service_1, # Dep machines.Service
|
||||
server=cls.machines_interface_1, # Dep machines.Interface
|
||||
last_regen=datetime.datetime.now(datetime.timezone.utc),
|
||||
asked_regen=False
|
||||
asked_regen=False,
|
||||
)
|
||||
cls.machines_ouvertureport_1 = machines.OuverturePort.objects.create(
|
||||
begin=1,
|
||||
end=2,
|
||||
port_list=cls.machines_ouvertureportlist_1, # Dep machines.OuverturePortList
|
||||
protocole=machines.OuverturePort.TCP,
|
||||
io=machines.OuverturePort.OUT
|
||||
io=machines.OuverturePort.OUT,
|
||||
)
|
||||
cls.machines_nas_1 = machines.Nas.objects.create(
|
||||
name="machines_nas_1",
|
||||
nas_type=cls.machines_machinetype_1, # Dep machines.MachineType
|
||||
machine_type=cls.machines_machinetype_1, # Dep machines.MachineType
|
||||
port_access_mode=machines.Nas.AUTH[0][0],
|
||||
autocapture_mac=False
|
||||
autocapture_mac=False,
|
||||
)
|
||||
cls.preferences_service_1 = preferences.Service.objects.create(
|
||||
name="preferences_service_1",
|
||||
url="https://example.net",
|
||||
description="preferences Service 1",
|
||||
image="/media/logo/none.png"
|
||||
image="/media/logo/none.png",
|
||||
)
|
||||
cls.topologie_stack_1 = topologie.Stack.objects.create(
|
||||
name="topologie_stack_1",
|
||||
stack_id="1",
|
||||
details="topologie Stack 1",
|
||||
member_id_min=1,
|
||||
member_id_max=10
|
||||
member_id_max=10,
|
||||
)
|
||||
cls.topologie_accespoint_1 = topologie.AccessPoint.objects.create(
|
||||
user=cls.users_user_1, # Dep users.User
|
||||
name="machines_machine_1",
|
||||
active=True,
|
||||
location="topologie AccessPoint 1"
|
||||
location="topologie AccessPoint 1",
|
||||
)
|
||||
cls.topologie_server_1 = topologie.Server.objects.create(
|
||||
user=cls.users_user_1, # Dep users.User
|
||||
name="machines_machine_1",
|
||||
active=True
|
||||
active=True,
|
||||
)
|
||||
cls.topologie_building_1 = topologie.Building.objects.create(
|
||||
name="topologie_building_1"
|
||||
|
@ -456,14 +444,14 @@ class APIEndpointsTestCase(APITestCase):
|
|||
cls.topologie_switchbay_1 = topologie.SwitchBay.objects.create(
|
||||
name="topologie_switchbay_1",
|
||||
building=cls.topologie_building_1, # Dep topologie.Building
|
||||
info="topologie SwitchBay 1"
|
||||
info="topologie SwitchBay 1",
|
||||
)
|
||||
cls.topologie_constructorswitch_1 = topologie.ConstructorSwitch.objects.create(
|
||||
name="topologie_constructorswitch_1"
|
||||
)
|
||||
cls.topologie_modelswitch_1 = topologie.ModelSwitch.objects.create(
|
||||
reference="topologie_modelswitch_1",
|
||||
constructor=cls.topologie_constructorswitch_1 # Dep topologie.ConstructorSwitch
|
||||
constructor=cls.topologie_constructorswitch_1, # Dep topologie.ConstructorSwitch
|
||||
)
|
||||
cls.topologie_switch_1 = topologie.Switch.objects.create(
|
||||
user=cls.users_user_1, # Dep users.User
|
||||
|
@ -473,11 +461,10 @@ class APIEndpointsTestCase(APITestCase):
|
|||
stack=cls.topologie_stack_1, # Dep topologie.Stack
|
||||
stack_member_id=1,
|
||||
model=cls.topologie_modelswitch_1, # Dep topologie.ModelSwitch
|
||||
switchbay=cls.topologie_switchbay_1 # Dep topologie.SwitchBay
|
||||
switchbay=cls.topologie_switchbay_1, # Dep topologie.SwitchBay
|
||||
)
|
||||
cls.topologie_room_1 = topologie.Room.objects.create(
|
||||
name="topologie_romm_1",
|
||||
details="topologie Room 1"
|
||||
name="topologie_romm_1", details="topologie Room 1"
|
||||
)
|
||||
cls.topologie_port_1 = topologie.Port.objects.create(
|
||||
switch=cls.topologie_switch_1, # Dep topologie.Switch
|
||||
|
@ -485,7 +472,7 @@ class APIEndpointsTestCase(APITestCase):
|
|||
room=cls.topologie_room_1, # Dep topologie.Room
|
||||
radius=topologie.Port.STATES[0][0],
|
||||
vlan_force=cls.machines_vlan_1, # Dep machines.Vlan
|
||||
details="topologie_switch_1"
|
||||
details="topologie_switch_1",
|
||||
)
|
||||
cls.topologie_port_2 = topologie.Port.objects.create(
|
||||
switch=cls.topologie_switch_1, # Dep topologie.Switch
|
||||
|
@ -493,7 +480,7 @@ class APIEndpointsTestCase(APITestCase):
|
|||
machine_interface=cls.machines_interface_1, # Dep machines.Interface
|
||||
radius=topologie.Port.STATES[0][0],
|
||||
vlan_force=cls.machines_vlan_1, # Dep machines.Vlan
|
||||
details="topologie_switch_1"
|
||||
details="topologie_switch_1",
|
||||
)
|
||||
cls.topologie_port_3 = topologie.Port.objects.create(
|
||||
switch=cls.topologie_switch_1, # Dep topologie.Switch
|
||||
|
@ -501,14 +488,15 @@ class APIEndpointsTestCase(APITestCase):
|
|||
room=cls.topologie_room_1, # Dep topologie.Room
|
||||
radius=topologie.Port.STATES[0][0],
|
||||
# Do not defines related because circular dependency # Dep machines.Vlan
|
||||
details="topologie_switch_1"
|
||||
details="topologie_switch_1",
|
||||
)
|
||||
cls.users_ban_1 = users.Ban.objects.create(
|
||||
user=cls.users_user_1, # Dep users.User
|
||||
raison="users Ban 1",
|
||||
date_start=datetime.datetime.now(datetime.timezone.utc),
|
||||
date_end=datetime.datetime.now(datetime.timezone.utc) + datetime.timedelta(days=1),
|
||||
state=users.Ban.STATES[0][0]
|
||||
date_end=datetime.datetime.now(datetime.timezone.utc)
|
||||
+ datetime.timedelta(days=1),
|
||||
state=users.Ban.STATES[0][0],
|
||||
)
|
||||
cls.users_club_1 = users.Club.objects.create(
|
||||
password="password",
|
||||
|
@ -524,7 +512,7 @@ class APIEndpointsTestCase(APITestCase):
|
|||
registered=datetime.datetime.now(datetime.timezone.utc),
|
||||
telephone="0123456789",
|
||||
uid_number=21103,
|
||||
rezo_rez_uid=21103
|
||||
rezo_rez_uid=21103,
|
||||
)
|
||||
# Need merge of MR145 to work
|
||||
# TODO: Merge !145
|
||||
|
@ -539,17 +527,17 @@ class APIEndpointsTestCase(APITestCase):
|
|||
last_login=datetime.datetime.now(datetime.timezone.utc),
|
||||
pseudo="usersserviceuser1",
|
||||
access_group=users.ServiceUser.ACCESS[0][0],
|
||||
comment="users ServiceUser 1"
|
||||
comment="users ServiceUser 1",
|
||||
)
|
||||
cls.users_whitelist_1 = users.Whitelist.objects.create(
|
||||
user=cls.users_user_1,
|
||||
raison="users Whitelist 1",
|
||||
date_start=datetime.datetime.now(datetime.timezone.utc),
|
||||
date_end=datetime.datetime.now(datetime.timezone.utc) + datetime.timedelta(days=1)
|
||||
date_end=datetime.datetime.now(datetime.timezone.utc)
|
||||
+ datetime.timedelta(days=1),
|
||||
)
|
||||
|
||||
def check_responses_code(self, urls, expected_code, formats=None,
|
||||
assert_more=None):
|
||||
def check_responses_code(self, urls, expected_code, formats=None, assert_more=None):
|
||||
"""Utility function to test if a list of urls answer an expected code.
|
||||
|
||||
Args:
|
||||
|
@ -665,17 +653,20 @@ class APIEndpointsTestCase(APITestCase):
|
|||
"""
|
||||
self.client.force_authenticate(user=self.superuser)
|
||||
|
||||
urls = self.no_auth_endpoints + self.auth_no_perm_endpoints + \
|
||||
self.auth_perm_endpoints
|
||||
urls = (
|
||||
self.no_auth_endpoints
|
||||
+ self.auth_no_perm_endpoints
|
||||
+ self.auth_perm_endpoints
|
||||
)
|
||||
|
||||
def assert_more(response, url, format):
|
||||
"""Assert the response is valid json when format is json"""
|
||||
if format is 'json':
|
||||
if format is "json":
|
||||
json.loads(response.content.decode())
|
||||
|
||||
self.check_responses_code(urls, codes.ok,
|
||||
formats=[None, 'json', 'api'],
|
||||
assert_more=assert_more)
|
||||
self.check_responses_code(
|
||||
urls, codes.ok, formats=[None, "json", "api"], assert_more=assert_more
|
||||
)
|
||||
|
||||
|
||||
class APIPaginationTestCase(APITestCase):
|
||||
|
@ -688,56 +679,56 @@ class APIPaginationTestCase(APITestCase):
|
|||
"""
|
||||
|
||||
endpoints = [
|
||||
'/api/cotisations/article/',
|
||||
'/api/cotisations/banque/',
|
||||
'/api/cotisations/cotisation/',
|
||||
'/api/cotisations/facture/',
|
||||
'/api/cotisations/paiement/',
|
||||
'/api/cotisations/vente/',
|
||||
'/api/machines/domain/',
|
||||
'/api/machines/extension/',
|
||||
'/api/machines/interface/',
|
||||
'/api/machines/iplist/',
|
||||
'/api/machines/iptype/',
|
||||
'/api/machines/ipv6list/',
|
||||
'/api/machines/machine/',
|
||||
'/api/machines/machinetype/',
|
||||
'/api/machines/mx/',
|
||||
'/api/machines/nas/',
|
||||
'/api/machines/ns/',
|
||||
'/api/machines/ouvertureportlist/',
|
||||
'/api/machines/ouvertureport/',
|
||||
'/api/machines/servicelink/',
|
||||
'/api/machines/service/',
|
||||
'/api/machines/soa/',
|
||||
'/api/machines/srv/',
|
||||
'/api/machines/txt/',
|
||||
'/api/machines/vlan/',
|
||||
'/api/preferences/service/',
|
||||
'/api/topologie/acesspoint/',
|
||||
'/api/topologie/building/',
|
||||
'/api/topologie/constructorswitch/',
|
||||
'/api/topologie/modelswitch/',
|
||||
'/api/topologie/room/',
|
||||
'/api/topologie/server/',
|
||||
'/api/topologie/stack/',
|
||||
'/api/topologie/switch/',
|
||||
'/api/topologie/switchbay/',
|
||||
'/api/topologie/switchport/',
|
||||
'/api/users/adherent/',
|
||||
'/api/users/ban/',
|
||||
'/api/users/club/',
|
||||
'/api/users/listright/',
|
||||
'/api/users/school/',
|
||||
'/api/users/serviceuser/',
|
||||
'/api/users/shell/',
|
||||
'/api/users/user/',
|
||||
'/api/users/whitelist/',
|
||||
'/api/dns/zones/',
|
||||
'/api/dhcp/hostmacip/',
|
||||
'/api/mailing/standard',
|
||||
'/api/mailing/club',
|
||||
'/api/services/regen/',
|
||||
"/api/cotisations/article/",
|
||||
"/api/cotisations/banque/",
|
||||
"/api/cotisations/cotisation/",
|
||||
"/api/cotisations/facture/",
|
||||
"/api/cotisations/paiement/",
|
||||
"/api/cotisations/vente/",
|
||||
"/api/machines/domain/",
|
||||
"/api/machines/extension/",
|
||||
"/api/machines/interface/",
|
||||
"/api/machines/iplist/",
|
||||
"/api/machines/iptype/",
|
||||
"/api/machines/ipv6list/",
|
||||
"/api/machines/machine/",
|
||||
"/api/machines/machinetype/",
|
||||
"/api/machines/mx/",
|
||||
"/api/machines/nas/",
|
||||
"/api/machines/ns/",
|
||||
"/api/machines/ouvertureportlist/",
|
||||
"/api/machines/ouvertureport/",
|
||||
"/api/machines/servicelink/",
|
||||
"/api/machines/service/",
|
||||
"/api/machines/soa/",
|
||||
"/api/machines/srv/",
|
||||
"/api/machines/txt/",
|
||||
"/api/machines/vlan/",
|
||||
"/api/preferences/service/",
|
||||
"/api/topologie/acesspoint/",
|
||||
"/api/topologie/building/",
|
||||
"/api/topologie/constructorswitch/",
|
||||
"/api/topologie/modelswitch/",
|
||||
"/api/topologie/room/",
|
||||
"/api/topologie/server/",
|
||||
"/api/topologie/stack/",
|
||||
"/api/topologie/switch/",
|
||||
"/api/topologie/switchbay/",
|
||||
"/api/topologie/switchport/",
|
||||
"/api/users/adherent/",
|
||||
"/api/users/ban/",
|
||||
"/api/users/club/",
|
||||
"/api/users/listright/",
|
||||
"/api/users/school/",
|
||||
"/api/users/serviceuser/",
|
||||
"/api/users/shell/",
|
||||
"/api/users/user/",
|
||||
"/api/users/whitelist/",
|
||||
"/api/dns/zones/",
|
||||
"/api/dhcp/hostmacip/",
|
||||
"/api/mailing/standard",
|
||||
"/api/mailing/club",
|
||||
"/api/services/regen/",
|
||||
]
|
||||
superuser = None
|
||||
|
||||
|
@ -752,7 +743,7 @@ class APIPaginationTestCase(APITestCase):
|
|||
"apisuperuser2",
|
||||
"apisuperuser2",
|
||||
"apisuperuser2@example.net",
|
||||
"apisuperuser2"
|
||||
"apisuperuser2",
|
||||
)
|
||||
|
||||
@classmethod
|
||||
|
@ -771,10 +762,10 @@ class APIPaginationTestCase(APITestCase):
|
|||
self.client.force_authenticate(self.superuser)
|
||||
for url in self.endpoints:
|
||||
with self.subTest(url=url):
|
||||
response = self.client.get(url, format='json')
|
||||
response = self.client.get(url, format="json")
|
||||
res_json = json.loads(response.content.decode())
|
||||
assert 'count' in res_json.keys()
|
||||
assert 'next' in res_json.keys()
|
||||
assert 'previous' in res_json.keys()
|
||||
assert 'results' in res_json.keys()
|
||||
assert not len('results') > 100
|
||||
assert "count" in res_json.keys()
|
||||
assert "next" in res_json.keys()
|
||||
assert "previous" in res_json.keys()
|
||||
assert "results" in res_json.keys()
|
||||
assert not len("results") > 100
|
||||
|
|
170
api/urls.py
170
api/urls.py
|
@ -34,95 +34,109 @@ from .routers import AllViewsRouter
|
|||
|
||||
router = AllViewsRouter()
|
||||
# COTISATIONS
|
||||
router.register_viewset(r'cotisations/facture', views.FactureViewSet)
|
||||
router.register_viewset(r'cotisations/vente', views.VenteViewSet)
|
||||
router.register_viewset(r'cotisations/article', views.ArticleViewSet)
|
||||
router.register_viewset(r'cotisations/banque', views.BanqueViewSet)
|
||||
router.register_viewset(r'cotisations/paiement', views.PaiementViewSet)
|
||||
router.register_viewset(r'cotisations/cotisation', views.CotisationViewSet)
|
||||
router.register_viewset(r"cotisations/facture", views.FactureViewSet)
|
||||
router.register_viewset(r"cotisations/vente", views.VenteViewSet)
|
||||
router.register_viewset(r"cotisations/article", views.ArticleViewSet)
|
||||
router.register_viewset(r"cotisations/banque", views.BanqueViewSet)
|
||||
router.register_viewset(r"cotisations/paiement", views.PaiementViewSet)
|
||||
router.register_viewset(r"cotisations/cotisation", views.CotisationViewSet)
|
||||
# MACHINES
|
||||
router.register_viewset(r'machines/machine', views.MachineViewSet)
|
||||
router.register_viewset(r'machines/machinetype', views.MachineTypeViewSet)
|
||||
router.register_viewset(r'machines/iptype', views.IpTypeViewSet)
|
||||
router.register_viewset(r'machines/vlan', views.VlanViewSet)
|
||||
router.register_viewset(r'machines/nas', views.NasViewSet)
|
||||
router.register_viewset(r'machines/soa', views.SOAViewSet)
|
||||
router.register_viewset(r'machines/extension', views.ExtensionViewSet)
|
||||
router.register_viewset(r'machines/mx', views.MxViewSet)
|
||||
router.register_viewset(r'machines/ns', views.NsViewSet)
|
||||
router.register_viewset(r'machines/txt', views.TxtViewSet)
|
||||
router.register_viewset(r'machines/dname', views.DNameViewSet)
|
||||
router.register_viewset(r'machines/srv', views.SrvViewSet)
|
||||
router.register_viewset(r'machines/sshfp', views.SshFpViewSet)
|
||||
router.register_viewset(r'machines/interface', views.InterfaceViewSet)
|
||||
router.register_viewset(r'machines/ipv6list', views.Ipv6ListViewSet)
|
||||
router.register_viewset(r'machines/domain', views.DomainViewSet)
|
||||
router.register_viewset(r'machines/iplist', views.IpListViewSet)
|
||||
router.register_viewset(r'machines/service', views.ServiceViewSet)
|
||||
router.register_viewset(r'machines/servicelink', views.ServiceLinkViewSet, base_name='servicelink')
|
||||
router.register_viewset(r'machines/ouvertureportlist', views.OuverturePortListViewSet)
|
||||
router.register_viewset(r'machines/ouvertureport', views.OuverturePortViewSet)
|
||||
router.register_viewset(r'machines/role', views.RoleViewSet)
|
||||
router.register_viewset(r"machines/machine", views.MachineViewSet)
|
||||
router.register_viewset(r"machines/machinetype", views.MachineTypeViewSet)
|
||||
router.register_viewset(r"machines/iptype", views.IpTypeViewSet)
|
||||
router.register_viewset(r"machines/vlan", views.VlanViewSet)
|
||||
router.register_viewset(r"machines/nas", views.NasViewSet)
|
||||
router.register_viewset(r"machines/soa", views.SOAViewSet)
|
||||
router.register_viewset(r"machines/extension", views.ExtensionViewSet)
|
||||
router.register_viewset(r"machines/mx", views.MxViewSet)
|
||||
router.register_viewset(r"machines/ns", views.NsViewSet)
|
||||
router.register_viewset(r"machines/txt", views.TxtViewSet)
|
||||
router.register_viewset(r"machines/dname", views.DNameViewSet)
|
||||
router.register_viewset(r"machines/srv", views.SrvViewSet)
|
||||
router.register_viewset(r"machines/sshfp", views.SshFpViewSet)
|
||||
router.register_viewset(r"machines/interface", views.InterfaceViewSet)
|
||||
router.register_viewset(r"machines/ipv6list", views.Ipv6ListViewSet)
|
||||
router.register_viewset(r"machines/domain", views.DomainViewSet)
|
||||
router.register_viewset(r"machines/iplist", views.IpListViewSet)
|
||||
router.register_viewset(r"machines/service", views.ServiceViewSet)
|
||||
router.register_viewset(
|
||||
r"machines/servicelink", views.ServiceLinkViewSet, base_name="servicelink"
|
||||
)
|
||||
router.register_viewset(r"machines/ouvertureportlist", views.OuverturePortListViewSet)
|
||||
router.register_viewset(r"machines/ouvertureport", views.OuverturePortViewSet)
|
||||
router.register_viewset(r"machines/role", views.RoleViewSet)
|
||||
# PREFERENCES
|
||||
router.register_view(r'preferences/optionaluser', views.OptionalUserView),
|
||||
router.register_view(r'preferences/optionalmachine', views.OptionalMachineView),
|
||||
router.register_view(r'preferences/optionaltopologie', views.OptionalTopologieView),
|
||||
router.register_view(r'preferences/radiusoption', views.RadiusOptionView),
|
||||
router.register_view(r'preferences/generaloption', views.GeneralOptionView),
|
||||
router.register_viewset(r'preferences/service', views.HomeServiceViewSet, base_name='homeservice'),
|
||||
router.register_view(r'preferences/assooption', views.AssoOptionView),
|
||||
router.register_view(r'preferences/homeoption', views.HomeOptionView),
|
||||
router.register_view(r'preferences/mailmessageoption', views.MailMessageOptionView),
|
||||
router.register_view(r"preferences/optionaluser", views.OptionalUserView),
|
||||
router.register_view(r"preferences/optionalmachine", views.OptionalMachineView),
|
||||
router.register_view(r"preferences/optionaltopologie", views.OptionalTopologieView),
|
||||
router.register_view(r"preferences/radiusoption", views.RadiusOptionView),
|
||||
router.register_view(r"preferences/generaloption", views.GeneralOptionView),
|
||||
router.register_viewset(
|
||||
r"preferences/service", views.HomeServiceViewSet, base_name="homeservice"
|
||||
),
|
||||
router.register_view(r"preferences/assooption", views.AssoOptionView),
|
||||
router.register_view(r"preferences/homeoption", views.HomeOptionView),
|
||||
router.register_view(r"preferences/mailmessageoption", views.MailMessageOptionView),
|
||||
# TOPOLOGIE
|
||||
router.register_viewset(r'topologie/stack', views.StackViewSet)
|
||||
router.register_viewset(r'topologie/acesspoint', views.AccessPointViewSet)
|
||||
router.register_viewset(r'topologie/switch', views.SwitchViewSet)
|
||||
router.register_viewset(r'topologie/server', views.ServerViewSet)
|
||||
router.register_viewset(r'topologie/modelswitch', views.ModelSwitchViewSet)
|
||||
router.register_viewset(r'topologie/constructorswitch', views.ConstructorSwitchViewSet)
|
||||
router.register_viewset(r'topologie/switchbay', views.SwitchBayViewSet)
|
||||
router.register_viewset(r'topologie/building', views.BuildingViewSet)
|
||||
router.register_viewset(r'topologie/switchport', views.SwitchPortViewSet, base_name='switchport')
|
||||
router.register_viewset(r'topologie/portprofile', views.PortProfileViewSet, base_name='portprofile')
|
||||
router.register_viewset(r'topologie/room', views.RoomViewSet)
|
||||
router.register(r'topologie/portprofile', views.PortProfileViewSet)
|
||||
router.register_viewset(r"topologie/stack", views.StackViewSet)
|
||||
router.register_viewset(r"topologie/acesspoint", views.AccessPointViewSet)
|
||||
router.register_viewset(r"topologie/switch", views.SwitchViewSet)
|
||||
router.register_viewset(r"topologie/server", views.ServerViewSet)
|
||||
router.register_viewset(r"topologie/modelswitch", views.ModelSwitchViewSet)
|
||||
router.register_viewset(r"topologie/constructorswitch", views.ConstructorSwitchViewSet)
|
||||
router.register_viewset(r"topologie/switchbay", views.SwitchBayViewSet)
|
||||
router.register_viewset(r"topologie/building", views.BuildingViewSet)
|
||||
router.register_viewset(
|
||||
r"topologie/switchport", views.SwitchPortViewSet, base_name="switchport"
|
||||
)
|
||||
router.register_viewset(
|
||||
r"topologie/portprofile", views.PortProfileViewSet, base_name="portprofile"
|
||||
)
|
||||
router.register_viewset(r"topologie/room", views.RoomViewSet)
|
||||
router.register(r"topologie/portprofile", views.PortProfileViewSet)
|
||||
# USERS
|
||||
router.register_viewset(r'users/user', views.UserViewSet, base_name='user')
|
||||
router.register_viewset(r'users/homecreation', views.HomeCreationViewSet, base_name='homecreation')
|
||||
router.register_viewset(r'users/normaluser', views.NormalUserViewSet, base_name='normaluser')
|
||||
router.register_viewset(r'users/criticaluser', views.CriticalUserViewSet, base_name='criticaluser')
|
||||
router.register_viewset(r'users/club', views.ClubViewSet)
|
||||
router.register_viewset(r'users/adherent', views.AdherentViewSet)
|
||||
router.register_viewset(r'users/serviceuser', views.ServiceUserViewSet)
|
||||
router.register_viewset(r'users/school', views.SchoolViewSet)
|
||||
router.register_viewset(r'users/listright', views.ListRightViewSet)
|
||||
router.register_viewset(r'users/shell', views.ShellViewSet, base_name='shell')
|
||||
router.register_viewset(r'users/ban', views.BanViewSet)
|
||||
router.register_viewset(r'users/whitelist', views.WhitelistViewSet)
|
||||
router.register_viewset(r'users/emailaddress', views.EMailAddressViewSet)
|
||||
router.register_viewset(r"users/user", views.UserViewSet, base_name="user")
|
||||
router.register_viewset(
|
||||
r"users/homecreation", views.HomeCreationViewSet, base_name="homecreation"
|
||||
)
|
||||
router.register_viewset(
|
||||
r"users/normaluser", views.NormalUserViewSet, base_name="normaluser"
|
||||
)
|
||||
router.register_viewset(
|
||||
r"users/criticaluser", views.CriticalUserViewSet, base_name="criticaluser"
|
||||
)
|
||||
router.register_viewset(r"users/club", views.ClubViewSet)
|
||||
router.register_viewset(r"users/adherent", views.AdherentViewSet)
|
||||
router.register_viewset(r"users/serviceuser", views.ServiceUserViewSet)
|
||||
router.register_viewset(r"users/school", views.SchoolViewSet)
|
||||
router.register_viewset(r"users/listright", views.ListRightViewSet)
|
||||
router.register_viewset(r"users/shell", views.ShellViewSet, base_name="shell")
|
||||
router.register_viewset(r"users/ban", views.BanViewSet)
|
||||
router.register_viewset(r"users/whitelist", views.WhitelistViewSet)
|
||||
router.register_viewset(r"users/emailaddress", views.EMailAddressViewSet)
|
||||
# SERVICE REGEN
|
||||
router.register_viewset(r'services/regen', views.ServiceRegenViewSet, base_name='serviceregen')
|
||||
router.register_viewset(
|
||||
r"services/regen", views.ServiceRegenViewSet, base_name="serviceregen"
|
||||
)
|
||||
# DHCP
|
||||
router.register_view(r'dhcp/hostmacip', views.HostMacIpView),
|
||||
router.register_view(r"dhcp/hostmacip", views.HostMacIpView),
|
||||
# LOCAL EMAILS
|
||||
router.register_view(r'localemail/users', views.LocalEmailUsersView),
|
||||
router.register_view(r"localemail/users", views.LocalEmailUsersView),
|
||||
# Firewall
|
||||
router.register_view(r'firewall/subnet-ports', views.SubnetPortsOpenView),
|
||||
router.register_view(r'firewall/interface-ports', views.InterfacePortsOpenView),
|
||||
router.register_view(r"firewall/subnet-ports", views.SubnetPortsOpenView),
|
||||
router.register_view(r"firewall/interface-ports", views.InterfacePortsOpenView),
|
||||
# Switches config
|
||||
router.register_view(r'switchs/ports-config', views.SwitchPortView),
|
||||
router.register_view(r'switchs/role', views.RoleView),
|
||||
router.register_view(r"switchs/ports-config", views.SwitchPortView),
|
||||
router.register_view(r"switchs/role", views.RoleView),
|
||||
# Reminder
|
||||
router.register_view(r'reminder/get-users', views.ReminderView),
|
||||
router.register_view(r"reminder/get-users", views.ReminderView),
|
||||
# DNS
|
||||
router.register_view(r'dns/zones', views.DNSZonesView),
|
||||
router.register_view(r'dns/reverse-zones', views.DNSReverseZonesView),
|
||||
router.register_view(r"dns/zones", views.DNSZonesView),
|
||||
router.register_view(r"dns/reverse-zones", views.DNSReverseZonesView),
|
||||
# MAILING
|
||||
router.register_view(r'mailing/standard', views.StandardMailingView),
|
||||
router.register_view(r'mailing/club', views.ClubMailingView),
|
||||
router.register_view(r"mailing/standard", views.StandardMailingView),
|
||||
router.register_view(r"mailing/club", views.ClubMailingView),
|
||||
# TOKEN AUTHENTICATION
|
||||
router.register_view(r'token-auth', views.ObtainExpiringAuthToken)
|
||||
router.register_view(r"token-auth", views.ObtainExpiringAuthToken)
|
||||
|
||||
urlpatterns = [
|
||||
url(r'^', include(router.urls)),
|
||||
]
|
||||
urlpatterns = [url(r"^", include(router.urls))]
|
||||
|
|
179
api/views.py
179
api/views.py
|
@ -52,12 +52,15 @@ from .permissions import ACLPermission
|
|||
class FactureViewSet(viewsets.ReadOnlyModelViewSet):
|
||||
"""Exposes list and details of `cotisations.models.Facture` objects.
|
||||
"""
|
||||
|
||||
queryset = cotisations.Facture.objects.all()
|
||||
serializer_class = serializers.FactureSerializer
|
||||
|
||||
|
||||
class FactureViewSet(viewsets.ReadOnlyModelViewSet):
|
||||
"""Exposes list and details of `cotisations.models.Facture` objects.
|
||||
"""
|
||||
|
||||
queryset = cotisations.BaseInvoice.objects.all()
|
||||
serializer_class = serializers.BaseInvoiceSerializer
|
||||
|
||||
|
@ -65,6 +68,7 @@ class FactureViewSet(viewsets.ReadOnlyModelViewSet):
|
|||
class VenteViewSet(viewsets.ReadOnlyModelViewSet):
|
||||
"""Exposes list and details of `cotisations.models.Vente` objects.
|
||||
"""
|
||||
|
||||
queryset = cotisations.Vente.objects.all()
|
||||
serializer_class = serializers.VenteSerializer
|
||||
|
||||
|
@ -72,6 +76,7 @@ class VenteViewSet(viewsets.ReadOnlyModelViewSet):
|
|||
class ArticleViewSet(viewsets.ReadOnlyModelViewSet):
|
||||
"""Exposes list and details of `cotisations.models.Article` objects.
|
||||
"""
|
||||
|
||||
queryset = cotisations.Article.objects.all()
|
||||
serializer_class = serializers.ArticleSerializer
|
||||
|
||||
|
@ -79,6 +84,7 @@ class ArticleViewSet(viewsets.ReadOnlyModelViewSet):
|
|||
class BanqueViewSet(viewsets.ReadOnlyModelViewSet):
|
||||
"""Exposes list and details of `cotisations.models.Banque` objects.
|
||||
"""
|
||||
|
||||
queryset = cotisations.Banque.objects.all()
|
||||
serializer_class = serializers.BanqueSerializer
|
||||
|
||||
|
@ -86,6 +92,7 @@ class BanqueViewSet(viewsets.ReadOnlyModelViewSet):
|
|||
class PaiementViewSet(viewsets.ReadOnlyModelViewSet):
|
||||
"""Exposes list and details of `cotisations.models.Paiement` objects.
|
||||
"""
|
||||
|
||||
queryset = cotisations.Paiement.objects.all()
|
||||
serializer_class = serializers.PaiementSerializer
|
||||
|
||||
|
@ -93,6 +100,7 @@ class PaiementViewSet(viewsets.ReadOnlyModelViewSet):
|
|||
class CotisationViewSet(viewsets.ReadOnlyModelViewSet):
|
||||
"""Exposes list and details of `cotisations.models.Cotisation` objects.
|
||||
"""
|
||||
|
||||
queryset = cotisations.Cotisation.objects.all()
|
||||
serializer_class = serializers.CotisationSerializer
|
||||
|
||||
|
@ -103,6 +111,7 @@ class CotisationViewSet(viewsets.ReadOnlyModelViewSet):
|
|||
class MachineViewSet(viewsets.ReadOnlyModelViewSet):
|
||||
"""Exposes list and details of `machines.models.Machine` objects.
|
||||
"""
|
||||
|
||||
queryset = machines.Machine.objects.all()
|
||||
serializer_class = serializers.MachineSerializer
|
||||
|
||||
|
@ -110,6 +119,7 @@ class MachineViewSet(viewsets.ReadOnlyModelViewSet):
|
|||
class MachineTypeViewSet(viewsets.ReadOnlyModelViewSet):
|
||||
"""Exposes list and details of `machines.models.MachineType` objects.
|
||||
"""
|
||||
|
||||
queryset = machines.MachineType.objects.all()
|
||||
serializer_class = serializers.MachineTypeSerializer
|
||||
|
||||
|
@ -117,6 +127,7 @@ class MachineTypeViewSet(viewsets.ReadOnlyModelViewSet):
|
|||
class IpTypeViewSet(viewsets.ReadOnlyModelViewSet):
|
||||
"""Exposes list and details of `machines.models.IpType` objects.
|
||||
"""
|
||||
|
||||
queryset = machines.IpType.objects.all()
|
||||
serializer_class = serializers.IpTypeSerializer
|
||||
|
||||
|
@ -124,6 +135,7 @@ class IpTypeViewSet(viewsets.ReadOnlyModelViewSet):
|
|||
class VlanViewSet(viewsets.ReadOnlyModelViewSet):
|
||||
"""Exposes list and details of `machines.models.Vlan` objects.
|
||||
"""
|
||||
|
||||
queryset = machines.Vlan.objects.all()
|
||||
serializer_class = serializers.VlanSerializer
|
||||
|
||||
|
@ -131,6 +143,7 @@ class VlanViewSet(viewsets.ReadOnlyModelViewSet):
|
|||
class NasViewSet(viewsets.ReadOnlyModelViewSet):
|
||||
"""Exposes list and details of `machines.models.Nas` objects.
|
||||
"""
|
||||
|
||||
queryset = machines.Nas.objects.all()
|
||||
serializer_class = serializers.NasSerializer
|
||||
|
||||
|
@ -138,6 +151,7 @@ class NasViewSet(viewsets.ReadOnlyModelViewSet):
|
|||
class SOAViewSet(viewsets.ReadOnlyModelViewSet):
|
||||
"""Exposes list and details of `machines.models.SOA` objects.
|
||||
"""
|
||||
|
||||
queryset = machines.SOA.objects.all()
|
||||
serializer_class = serializers.SOASerializer
|
||||
|
||||
|
@ -145,6 +159,7 @@ class SOAViewSet(viewsets.ReadOnlyModelViewSet):
|
|||
class ExtensionViewSet(viewsets.ReadOnlyModelViewSet):
|
||||
"""Exposes list and details of `machines.models.Extension` objects.
|
||||
"""
|
||||
|
||||
queryset = machines.Extension.objects.all()
|
||||
serializer_class = serializers.ExtensionSerializer
|
||||
|
||||
|
@ -152,6 +167,7 @@ class ExtensionViewSet(viewsets.ReadOnlyModelViewSet):
|
|||
class MxViewSet(viewsets.ReadOnlyModelViewSet):
|
||||
"""Exposes list and details of `machines.models.Mx` objects.
|
||||
"""
|
||||
|
||||
queryset = machines.Mx.objects.all()
|
||||
serializer_class = serializers.MxSerializer
|
||||
|
||||
|
@ -159,6 +175,7 @@ class MxViewSet(viewsets.ReadOnlyModelViewSet):
|
|||
class NsViewSet(viewsets.ReadOnlyModelViewSet):
|
||||
"""Exposes list and details of `machines.models.Ns` objects.
|
||||
"""
|
||||
|
||||
queryset = machines.Ns.objects.all()
|
||||
serializer_class = serializers.NsSerializer
|
||||
|
||||
|
@ -166,6 +183,7 @@ class NsViewSet(viewsets.ReadOnlyModelViewSet):
|
|||
class TxtViewSet(viewsets.ReadOnlyModelViewSet):
|
||||
"""Exposes list and details of `machines.models.Txt` objects.
|
||||
"""
|
||||
|
||||
queryset = machines.Txt.objects.all()
|
||||
serializer_class = serializers.TxtSerializer
|
||||
|
||||
|
@ -173,6 +191,7 @@ class TxtViewSet(viewsets.ReadOnlyModelViewSet):
|
|||
class DNameViewSet(viewsets.ReadOnlyModelViewSet):
|
||||
"""Exposes list and details of `machines.models.DName` objects.
|
||||
"""
|
||||
|
||||
queryset = machines.DName.objects.all()
|
||||
serializer_class = serializers.DNameSerializer
|
||||
|
||||
|
@ -180,6 +199,7 @@ class DNameViewSet(viewsets.ReadOnlyModelViewSet):
|
|||
class SrvViewSet(viewsets.ReadOnlyModelViewSet):
|
||||
"""Exposes list and details of `machines.models.Srv` objects.
|
||||
"""
|
||||
|
||||
queryset = machines.Srv.objects.all()
|
||||
serializer_class = serializers.SrvSerializer
|
||||
|
||||
|
@ -187,6 +207,7 @@ class SrvViewSet(viewsets.ReadOnlyModelViewSet):
|
|||
class SshFpViewSet(viewsets.ReadOnlyModelViewSet):
|
||||
"""Exposes list and details of `machines.models.SshFp` objects.
|
||||
"""
|
||||
|
||||
queryset = machines.SshFp.objects.all()
|
||||
serializer_class = serializers.SshFpSerializer
|
||||
|
||||
|
@ -194,6 +215,7 @@ class SshFpViewSet(viewsets.ReadOnlyModelViewSet):
|
|||
class InterfaceViewSet(viewsets.ReadOnlyModelViewSet):
|
||||
"""Exposes list and details of `machines.models.Interface` objects.
|
||||
"""
|
||||
|
||||
queryset = machines.Interface.objects.all()
|
||||
serializer_class = serializers.InterfaceSerializer
|
||||
|
||||
|
@ -201,6 +223,7 @@ class InterfaceViewSet(viewsets.ReadOnlyModelViewSet):
|
|||
class Ipv6ListViewSet(viewsets.ReadOnlyModelViewSet):
|
||||
"""Exposes list and details of `machines.models.Ipv6List` objects.
|
||||
"""
|
||||
|
||||
queryset = machines.Ipv6List.objects.all()
|
||||
serializer_class = serializers.Ipv6ListSerializer
|
||||
|
||||
|
@ -208,6 +231,7 @@ class Ipv6ListViewSet(viewsets.ReadOnlyModelViewSet):
|
|||
class DomainViewSet(viewsets.ReadOnlyModelViewSet):
|
||||
"""Exposes list and details of `machines.models.Domain` objects.
|
||||
"""
|
||||
|
||||
queryset = machines.Domain.objects.all()
|
||||
serializer_class = serializers.DomainSerializer
|
||||
|
||||
|
@ -215,6 +239,7 @@ class DomainViewSet(viewsets.ReadOnlyModelViewSet):
|
|||
class IpListViewSet(viewsets.ReadOnlyModelViewSet):
|
||||
"""Exposes list and details of `machines.models.IpList` objects.
|
||||
"""
|
||||
|
||||
queryset = machines.IpList.objects.all()
|
||||
serializer_class = serializers.IpListSerializer
|
||||
|
||||
|
@ -222,6 +247,7 @@ class IpListViewSet(viewsets.ReadOnlyModelViewSet):
|
|||
class ServiceViewSet(viewsets.ReadOnlyModelViewSet):
|
||||
"""Exposes list and details of `machines.models.Service` objects.
|
||||
"""
|
||||
|
||||
queryset = machines.Service.objects.all()
|
||||
serializer_class = serializers.ServiceSerializer
|
||||
|
||||
|
@ -229,6 +255,7 @@ class ServiceViewSet(viewsets.ReadOnlyModelViewSet):
|
|||
class ServiceLinkViewSet(viewsets.ReadOnlyModelViewSet):
|
||||
"""Exposes list and details of `machines.models.Service_link` objects.
|
||||
"""
|
||||
|
||||
queryset = machines.Service_link.objects.all()
|
||||
serializer_class = serializers.ServiceLinkSerializer
|
||||
|
||||
|
@ -237,6 +264,7 @@ class OuverturePortListViewSet(viewsets.ReadOnlyModelViewSet):
|
|||
"""Exposes list and details of `machines.models.OuverturePortList`
|
||||
objects.
|
||||
"""
|
||||
|
||||
queryset = machines.OuverturePortList.objects.all()
|
||||
serializer_class = serializers.OuverturePortListSerializer
|
||||
|
||||
|
@ -244,6 +272,7 @@ class OuverturePortListViewSet(viewsets.ReadOnlyModelViewSet):
|
|||
class OuverturePortViewSet(viewsets.ReadOnlyModelViewSet):
|
||||
"""Exposes list and details of `machines.models.OuverturePort` objects.
|
||||
"""
|
||||
|
||||
queryset = machines.OuverturePort.objects.all()
|
||||
serializer_class = serializers.OuverturePortSerializer
|
||||
|
||||
|
@ -251,6 +280,7 @@ class OuverturePortViewSet(viewsets.ReadOnlyModelViewSet):
|
|||
class RoleViewSet(viewsets.ReadOnlyModelViewSet):
|
||||
"""Exposes list and details of `machines.models.Machine` objects.
|
||||
"""
|
||||
|
||||
queryset = machines.Role.objects.all()
|
||||
serializer_class = serializers.RoleSerializer
|
||||
|
||||
|
@ -259,11 +289,13 @@ class RoleViewSet(viewsets.ReadOnlyModelViewSet):
|
|||
# Those views differ a bit because there is only one object
|
||||
# to display, so we don't bother with the listing part
|
||||
|
||||
|
||||
class OptionalUserView(generics.RetrieveAPIView):
|
||||
"""Exposes details of `preferences.models.` settings.
|
||||
"""
|
||||
|
||||
permission_classes = (ACLPermission,)
|
||||
perms_map = {'GET': [preferences.OptionalUser.can_view_all]}
|
||||
perms_map = {"GET": [preferences.OptionalUser.can_view_all]}
|
||||
serializer_class = serializers.OptionalUserSerializer
|
||||
|
||||
def get_object(self):
|
||||
|
@ -273,8 +305,9 @@ class OptionalUserView(generics.RetrieveAPIView):
|
|||
class OptionalMachineView(generics.RetrieveAPIView):
|
||||
"""Exposes details of `preferences.models.OptionalMachine` settings.
|
||||
"""
|
||||
|
||||
permission_classes = (ACLPermission,)
|
||||
perms_map = {'GET': [preferences.OptionalMachine.can_view_all]}
|
||||
perms_map = {"GET": [preferences.OptionalMachine.can_view_all]}
|
||||
serializer_class = serializers.OptionalMachineSerializer
|
||||
|
||||
def get_object(self):
|
||||
|
@ -284,8 +317,9 @@ class OptionalMachineView(generics.RetrieveAPIView):
|
|||
class OptionalTopologieView(generics.RetrieveAPIView):
|
||||
"""Exposes details of `preferences.models.OptionalTopologie` settings.
|
||||
"""
|
||||
|
||||
permission_classes = (ACLPermission,)
|
||||
perms_map = {'GET': [preferences.OptionalTopologie.can_view_all]}
|
||||
perms_map = {"GET": [preferences.OptionalTopologie.can_view_all]}
|
||||
serializer_class = serializers.OptionalTopologieSerializer
|
||||
|
||||
def get_object(self):
|
||||
|
@ -295,8 +329,9 @@ class OptionalTopologieView(generics.RetrieveAPIView):
|
|||
class RadiusOptionView(generics.RetrieveAPIView):
|
||||
"""Exposes details of `preferences.models.OptionalTopologie` settings.
|
||||
"""
|
||||
|
||||
permission_classes = (ACLPermission,)
|
||||
perms_map = {'GET': [preferences.RadiusOption.can_view_all]}
|
||||
perms_map = {"GET": [preferences.RadiusOption.can_view_all]}
|
||||
serializer_class = serializers.RadiusOptionSerializer
|
||||
|
||||
def get_object(self):
|
||||
|
@ -306,8 +341,9 @@ class RadiusOptionView(generics.RetrieveAPIView):
|
|||
class GeneralOptionView(generics.RetrieveAPIView):
|
||||
"""Exposes details of `preferences.models.GeneralOption` settings.
|
||||
"""
|
||||
|
||||
permission_classes = (ACLPermission,)
|
||||
perms_map = {'GET': [preferences.GeneralOption.can_view_all]}
|
||||
perms_map = {"GET": [preferences.GeneralOption.can_view_all]}
|
||||
serializer_class = serializers.GeneralOptionSerializer
|
||||
|
||||
def get_object(self):
|
||||
|
@ -317,6 +353,7 @@ class GeneralOptionView(generics.RetrieveAPIView):
|
|||
class HomeServiceViewSet(viewsets.ReadOnlyModelViewSet):
|
||||
"""Exposes list and details of `preferences.models.Service` objects.
|
||||
"""
|
||||
|
||||
queryset = preferences.Service.objects.all()
|
||||
serializer_class = serializers.HomeServiceSerializer
|
||||
|
||||
|
@ -324,8 +361,9 @@ class HomeServiceViewSet(viewsets.ReadOnlyModelViewSet):
|
|||
class AssoOptionView(generics.RetrieveAPIView):
|
||||
"""Exposes details of `preferences.models.AssoOption` settings.
|
||||
"""
|
||||
|
||||
permission_classes = (ACLPermission,)
|
||||
perms_map = {'GET': [preferences.AssoOption.can_view_all]}
|
||||
perms_map = {"GET": [preferences.AssoOption.can_view_all]}
|
||||
serializer_class = serializers.AssoOptionSerializer
|
||||
|
||||
def get_object(self):
|
||||
|
@ -335,8 +373,9 @@ class AssoOptionView(generics.RetrieveAPIView):
|
|||
class HomeOptionView(generics.RetrieveAPIView):
|
||||
"""Exposes details of `preferences.models.HomeOption` settings.
|
||||
"""
|
||||
|
||||
permission_classes = (ACLPermission,)
|
||||
perms_map = {'GET': [preferences.HomeOption.can_view_all]}
|
||||
perms_map = {"GET": [preferences.HomeOption.can_view_all]}
|
||||
serializer_class = serializers.HomeOptionSerializer
|
||||
|
||||
def get_object(self):
|
||||
|
@ -346,8 +385,9 @@ class HomeOptionView(generics.RetrieveAPIView):
|
|||
class MailMessageOptionView(generics.RetrieveAPIView):
|
||||
"""Exposes details of `preferences.models.MailMessageOption` settings.
|
||||
"""
|
||||
|
||||
permission_classes = (ACLPermission,)
|
||||
perms_map = {'GET': [preferences.MailMessageOption.can_view_all]}
|
||||
perms_map = {"GET": [preferences.MailMessageOption.can_view_all]}
|
||||
serializer_class = serializers.MailMessageOptionSerializer
|
||||
|
||||
def get_object(self):
|
||||
|
@ -360,6 +400,7 @@ class MailMessageOptionView(generics.RetrieveAPIView):
|
|||
class StackViewSet(viewsets.ReadOnlyModelViewSet):
|
||||
"""Exposes list and details of `topologie.models.Stack` objects.
|
||||
"""
|
||||
|
||||
queryset = topologie.Stack.objects.all()
|
||||
serializer_class = serializers.StackSerializer
|
||||
|
||||
|
@ -367,6 +408,7 @@ class StackViewSet(viewsets.ReadOnlyModelViewSet):
|
|||
class AccessPointViewSet(viewsets.ReadOnlyModelViewSet):
|
||||
"""Exposes list and details of `topologie.models.AccessPoint` objects.
|
||||
"""
|
||||
|
||||
queryset = topologie.AccessPoint.objects.all()
|
||||
serializer_class = serializers.AccessPointSerializer
|
||||
|
||||
|
@ -374,6 +416,7 @@ class AccessPointViewSet(viewsets.ReadOnlyModelViewSet):
|
|||
class SwitchViewSet(viewsets.ReadOnlyModelViewSet):
|
||||
"""Exposes list and details of `topologie.models.Switch` objects.
|
||||
"""
|
||||
|
||||
queryset = topologie.Switch.objects.all()
|
||||
serializer_class = serializers.SwitchSerializer
|
||||
|
||||
|
@ -381,6 +424,7 @@ class SwitchViewSet(viewsets.ReadOnlyModelViewSet):
|
|||
class ServerViewSet(viewsets.ReadOnlyModelViewSet):
|
||||
"""Exposes list and details of `topologie.models.Server` objects.
|
||||
"""
|
||||
|
||||
queryset = topologie.Server.objects.all()
|
||||
serializer_class = serializers.ServerSerializer
|
||||
|
||||
|
@ -388,6 +432,7 @@ class ServerViewSet(viewsets.ReadOnlyModelViewSet):
|
|||
class ModelSwitchViewSet(viewsets.ReadOnlyModelViewSet):
|
||||
"""Exposes list and details of `topologie.models.ModelSwitch` objects.
|
||||
"""
|
||||
|
||||
queryset = topologie.ModelSwitch.objects.all()
|
||||
serializer_class = serializers.ModelSwitchSerializer
|
||||
|
||||
|
@ -396,6 +441,7 @@ class ConstructorSwitchViewSet(viewsets.ReadOnlyModelViewSet):
|
|||
"""Exposes list and details of `topologie.models.ConstructorSwitch`
|
||||
objects.
|
||||
"""
|
||||
|
||||
queryset = topologie.ConstructorSwitch.objects.all()
|
||||
serializer_class = serializers.ConstructorSwitchSerializer
|
||||
|
||||
|
@ -403,6 +449,7 @@ class ConstructorSwitchViewSet(viewsets.ReadOnlyModelViewSet):
|
|||
class SwitchBayViewSet(viewsets.ReadOnlyModelViewSet):
|
||||
"""Exposes list and details of `topologie.models.SwitchBay` objects.
|
||||
"""
|
||||
|
||||
queryset = topologie.SwitchBay.objects.all()
|
||||
serializer_class = serializers.SwitchBaySerializer
|
||||
|
||||
|
@ -410,6 +457,7 @@ class SwitchBayViewSet(viewsets.ReadOnlyModelViewSet):
|
|||
class BuildingViewSet(viewsets.ReadOnlyModelViewSet):
|
||||
"""Exposes list and details of `topologie.models.Building` objects.
|
||||
"""
|
||||
|
||||
queryset = topologie.Building.objects.all()
|
||||
serializer_class = serializers.BuildingSerializer
|
||||
|
||||
|
@ -417,6 +465,7 @@ class BuildingViewSet(viewsets.ReadOnlyModelViewSet):
|
|||
class SwitchPortViewSet(viewsets.ReadOnlyModelViewSet):
|
||||
"""Exposes list and details of `topologie.models.Port` objects.
|
||||
"""
|
||||
|
||||
queryset = topologie.Port.objects.all()
|
||||
serializer_class = serializers.SwitchPortSerializer
|
||||
|
||||
|
@ -424,6 +473,7 @@ class SwitchPortViewSet(viewsets.ReadOnlyModelViewSet):
|
|||
class PortProfileViewSet(viewsets.ReadOnlyModelViewSet):
|
||||
"""Exposes list and details of `topologie.models.PortProfile` objects.
|
||||
"""
|
||||
|
||||
queryset = topologie.PortProfile.objects.all()
|
||||
serializer_class = serializers.PortProfileSerializer
|
||||
|
||||
|
@ -431,6 +481,7 @@ class PortProfileViewSet(viewsets.ReadOnlyModelViewSet):
|
|||
class RoomViewSet(viewsets.ReadOnlyModelViewSet):
|
||||
"""Exposes list and details of `topologie.models.Room` objects.
|
||||
"""
|
||||
|
||||
queryset = topologie.Room.objects.all()
|
||||
serializer_class = serializers.RoomSerializer
|
||||
|
||||
|
@ -438,6 +489,7 @@ class RoomViewSet(viewsets.ReadOnlyModelViewSet):
|
|||
class PortProfileViewSet(viewsets.ReadOnlyModelViewSet):
|
||||
"""Exposes list and details of `topologie.models.PortProfile` objects.
|
||||
"""
|
||||
|
||||
queryset = topologie.PortProfile.objects.all()
|
||||
serializer_class = serializers.PortProfileSerializer
|
||||
|
||||
|
@ -448,6 +500,7 @@ class PortProfileViewSet(viewsets.ReadOnlyModelViewSet):
|
|||
class UserViewSet(viewsets.ReadOnlyModelViewSet):
|
||||
"""Exposes list and details of `users.models.Users` objects.
|
||||
"""
|
||||
|
||||
queryset = users.User.objects.all()
|
||||
serializer_class = serializers.UserSerializer
|
||||
|
||||
|
@ -455,18 +508,25 @@ class UserViewSet(viewsets.ReadOnlyModelViewSet):
|
|||
class HomeCreationViewSet(viewsets.ReadOnlyModelViewSet):
|
||||
"""Exposes infos of `users.models.Users` objects to create homes.
|
||||
"""
|
||||
queryset = users.User.objects.exclude(Q(state=users.User.STATE_DISABLED) | Q(state=users.User.STATE_NOT_YET_ACTIVE))
|
||||
|
||||
queryset = users.User.objects.exclude(
|
||||
Q(state=users.User.STATE_DISABLED)
|
||||
| Q(state=users.User.STATE_NOT_YET_ACTIVE)
|
||||
| Q(state=users.User.STATE_FULL_ARCHIVE)
|
||||
)
|
||||
serializer_class = serializers.BasicUserSerializer
|
||||
|
||||
|
||||
class NormalUserViewSet(viewsets.ReadOnlyModelViewSet):
|
||||
"""Exposes infos of `users.models.Users`without specific rights objects."""
|
||||
|
||||
queryset = users.User.objects.exclude(groups__listright__critical=True).distinct()
|
||||
serializer_class = serializers.BasicUserSerializer
|
||||
|
||||
|
||||
class CriticalUserViewSet(viewsets.ReadOnlyModelViewSet):
|
||||
"""Exposes infos of `users.models.Users`without specific rights objects."""
|
||||
|
||||
queryset = users.User.objects.filter(groups__listright__critical=True).distinct()
|
||||
serializer_class = serializers.BasicUserSerializer
|
||||
|
||||
|
@ -474,6 +534,7 @@ class CriticalUserViewSet(viewsets.ReadOnlyModelViewSet):
|
|||
class ClubViewSet(viewsets.ReadOnlyModelViewSet):
|
||||
"""Exposes list and details of `users.models.Club` objects.
|
||||
"""
|
||||
|
||||
queryset = users.Club.objects.all()
|
||||
serializer_class = serializers.ClubSerializer
|
||||
|
||||
|
@ -481,6 +542,7 @@ class ClubViewSet(viewsets.ReadOnlyModelViewSet):
|
|||
class AdherentViewSet(viewsets.ReadOnlyModelViewSet):
|
||||
"""Exposes list and details of `users.models.Adherent` objects.
|
||||
"""
|
||||
|
||||
queryset = users.Adherent.objects.all()
|
||||
serializer_class = serializers.AdherentSerializer
|
||||
|
||||
|
@ -488,6 +550,7 @@ class AdherentViewSet(viewsets.ReadOnlyModelViewSet):
|
|||
class ServiceUserViewSet(viewsets.ReadOnlyModelViewSet):
|
||||
"""Exposes list and details of `users.models.ServiceUser` objects.
|
||||
"""
|
||||
|
||||
queryset = users.ServiceUser.objects.all()
|
||||
serializer_class = serializers.ServiceUserSerializer
|
||||
|
||||
|
@ -495,6 +558,7 @@ class ServiceUserViewSet(viewsets.ReadOnlyModelViewSet):
|
|||
class SchoolViewSet(viewsets.ReadOnlyModelViewSet):
|
||||
"""Exposes list and details of `users.models.School` objects.
|
||||
"""
|
||||
|
||||
queryset = users.School.objects.all()
|
||||
serializer_class = serializers.SchoolSerializer
|
||||
|
||||
|
@ -502,6 +566,7 @@ class SchoolViewSet(viewsets.ReadOnlyModelViewSet):
|
|||
class ListRightViewSet(viewsets.ReadOnlyModelViewSet):
|
||||
"""Exposes list and details of `users.models.ListRight` objects.
|
||||
"""
|
||||
|
||||
queryset = users.ListRight.objects.all()
|
||||
serializer_class = serializers.ListRightSerializer
|
||||
|
||||
|
@ -509,6 +574,7 @@ class ListRightViewSet(viewsets.ReadOnlyModelViewSet):
|
|||
class ShellViewSet(viewsets.ReadOnlyModelViewSet):
|
||||
"""Exposes list and details of `users.models.ListShell` objects.
|
||||
"""
|
||||
|
||||
queryset = users.ListShell.objects.all()
|
||||
serializer_class = serializers.ShellSerializer
|
||||
|
||||
|
@ -516,6 +582,7 @@ class ShellViewSet(viewsets.ReadOnlyModelViewSet):
|
|||
class BanViewSet(viewsets.ReadOnlyModelViewSet):
|
||||
"""Exposes list and details of `users.models.Ban` objects.
|
||||
"""
|
||||
|
||||
queryset = users.Ban.objects.all()
|
||||
serializer_class = serializers.BanSerializer
|
||||
|
||||
|
@ -523,6 +590,7 @@ class BanViewSet(viewsets.ReadOnlyModelViewSet):
|
|||
class WhitelistViewSet(viewsets.ReadOnlyModelViewSet):
|
||||
"""Exposes list and details of `users.models.Whitelist` objects.
|
||||
"""
|
||||
|
||||
queryset = users.Whitelist.objects.all()
|
||||
serializer_class = serializers.WhitelistSerializer
|
||||
|
||||
|
@ -530,14 +598,13 @@ class WhitelistViewSet(viewsets.ReadOnlyModelViewSet):
|
|||
class EMailAddressViewSet(viewsets.ReadOnlyModelViewSet):
|
||||
"""Exposes list and details of `users.models.EMailAddress` objects.
|
||||
"""
|
||||
|
||||
serializer_class = serializers.EMailAddressSerializer
|
||||
queryset = users.EMailAddress.objects.none()
|
||||
|
||||
def get_queryset(self):
|
||||
if preferences.OptionalUser.get_cached_value(
|
||||
'local_email_accounts_enabled'):
|
||||
return (users.EMailAddress.objects
|
||||
.filter(user__local_email_enabled=True))
|
||||
if preferences.OptionalUser.get_cached_value("local_email_accounts_enabled"):
|
||||
return users.EMailAddress.objects.filter(user__local_email_enabled=True)
|
||||
else:
|
||||
return users.EMailAddress.objects.none()
|
||||
|
||||
|
@ -548,34 +615,47 @@ class EMailAddressViewSet(viewsets.ReadOnlyModelViewSet):
|
|||
class ServiceRegenViewSet(viewsets.ModelViewSet):
|
||||
"""Exposes list and details of the services to regen
|
||||
"""
|
||||
|
||||
serializer_class = serializers.ServiceRegenSerializer
|
||||
|
||||
def get_queryset(self):
|
||||
queryset = machines.Service_link.objects.select_related(
|
||||
'server__domain'
|
||||
).select_related(
|
||||
'service'
|
||||
)
|
||||
if 'hostname' in self.request.GET:
|
||||
hostname = self.request.GET['hostname']
|
||||
"server__domain"
|
||||
).select_related("service")
|
||||
if "hostname" in self.request.GET:
|
||||
hostname = self.request.GET["hostname"]
|
||||
queryset = queryset.filter(server__domain__name__iexact=hostname)
|
||||
return queryset
|
||||
|
||||
|
||||
# Config des switches
|
||||
|
||||
|
||||
class SwitchPortView(generics.ListAPIView):
|
||||
"""Output each port of a switch, to be serialized with
|
||||
additionnal informations (profiles etc)
|
||||
"""
|
||||
queryset = topologie.Switch.objects.all().select_related("switchbay").select_related("model__constructor").prefetch_related("ports__custom_profile__vlan_tagged").prefetch_related("ports__custom_profile__vlan_untagged").prefetch_related("ports__machine_interface__domain__extension").prefetch_related("ports__room")
|
||||
|
||||
queryset = (
|
||||
topologie.Switch.objects.all()
|
||||
.select_related("switchbay")
|
||||
.select_related("model__constructor")
|
||||
.prefetch_related("ports__custom_profile__vlan_tagged")
|
||||
.prefetch_related("ports__custom_profile__vlan_untagged")
|
||||
.prefetch_related("ports__machine_interface__domain__extension")
|
||||
.prefetch_related("ports__room")
|
||||
)
|
||||
|
||||
serializer_class = serializers.SwitchPortSerializer
|
||||
|
||||
|
||||
# Rappel fin adhésion
|
||||
|
||||
|
||||
class ReminderView(generics.ListAPIView):
|
||||
"""Output for users to remind an end of their subscription.
|
||||
"""
|
||||
|
||||
queryset = preferences.Reminder.objects.all()
|
||||
serializer_class = serializers.ReminderSerializer
|
||||
|
||||
|
@ -583,7 +663,8 @@ class ReminderView(generics.ListAPIView):
|
|||
class RoleView(generics.ListAPIView):
|
||||
"""Output of roles for each server
|
||||
"""
|
||||
queryset = machines.Role.objects.all().prefetch_related('servers')
|
||||
|
||||
queryset = machines.Role.objects.all().prefetch_related("servers")
|
||||
serializer_class = serializers.RoleSerializer
|
||||
|
||||
|
||||
|
@ -593,13 +674,12 @@ class RoleView(generics.ListAPIView):
|
|||
class LocalEmailUsersView(generics.ListAPIView):
|
||||
"""Exposes all the aliases of the users that activated the internal address
|
||||
"""
|
||||
|
||||
serializer_class = serializers.LocalEmailUsersSerializer
|
||||
|
||||
def get_queryset(self):
|
||||
if preferences.OptionalUser.get_cached_value(
|
||||
'local_email_accounts_enabled'):
|
||||
return (users.User.objects
|
||||
.filter(local_email_enabled=True))
|
||||
if preferences.OptionalUser.get_cached_value("local_email_accounts_enabled"):
|
||||
return users.User.objects.filter(local_email_enabled=True)
|
||||
else:
|
||||
return users.User.objects.none()
|
||||
|
||||
|
@ -611,6 +691,7 @@ class HostMacIpView(generics.ListAPIView):
|
|||
"""Exposes the associations between hostname, mac address and IPv4 in
|
||||
order to build the DHCP lease files.
|
||||
"""
|
||||
|
||||
serializer_class = serializers.HostMacIpSerializer
|
||||
|
||||
def get_queryset(self):
|
||||
|
@ -619,6 +700,7 @@ class HostMacIpView(generics.ListAPIView):
|
|||
|
||||
# Firewall
|
||||
|
||||
|
||||
class SubnetPortsOpenView(generics.ListAPIView):
|
||||
queryset = machines.IpType.objects.all()
|
||||
serializer_class = serializers.SubnetPortsOpenSerializer
|
||||
|
@ -636,14 +718,19 @@ class DNSZonesView(generics.ListAPIView):
|
|||
"""Exposes the detailed information about each extension (hostnames,
|
||||
IPs, DNS records, etc.) in order to build the DNS zone files.
|
||||
"""
|
||||
queryset = (machines.Extension.objects
|
||||
.prefetch_related('soa')
|
||||
.prefetch_related('ns_set').prefetch_related('ns_set__ns')
|
||||
.prefetch_related('origin')
|
||||
.prefetch_related('mx_set').prefetch_related('mx_set__name')
|
||||
.prefetch_related('txt_set')
|
||||
.prefetch_related('srv_set').prefetch_related('srv_set__target')
|
||||
.all())
|
||||
|
||||
queryset = (
|
||||
machines.Extension.objects.prefetch_related("soa")
|
||||
.prefetch_related("ns_set")
|
||||
.prefetch_related("ns_set__ns")
|
||||
.prefetch_related("origin")
|
||||
.prefetch_related("mx_set")
|
||||
.prefetch_related("mx_set__name")
|
||||
.prefetch_related("txt_set")
|
||||
.prefetch_related("srv_set")
|
||||
.prefetch_related("srv_set__target")
|
||||
.all()
|
||||
)
|
||||
serializer_class = serializers.DNSZonesSerializer
|
||||
|
||||
|
||||
|
@ -651,7 +738,8 @@ class DNSReverseZonesView(generics.ListAPIView):
|
|||
"""Exposes the detailed information about each extension (hostnames,
|
||||
IPs, DNS records, etc.) in order to build the DNS zone files.
|
||||
"""
|
||||
queryset = (machines.IpType.objects.all())
|
||||
|
||||
queryset = machines.IpType.objects.all()
|
||||
serializer_class = serializers.DNSReverseZonesSerializer
|
||||
|
||||
|
||||
|
@ -662,13 +750,16 @@ class StandardMailingView(views.APIView):
|
|||
"""Exposes list and details of standard mailings (name and members) in
|
||||
order to building the corresponding mailing lists.
|
||||
"""
|
||||
|
||||
pagination_class = PageSizedPagination
|
||||
permission_classes = (ACLPermission,)
|
||||
perms_map = {'GET': [users.User.can_view_all]}
|
||||
perms_map = {"GET": [users.User.can_view_all]}
|
||||
|
||||
def get(self, request, format=None):
|
||||
adherents_data = serializers.MailingMemberSerializer(all_has_access(), many=True).data
|
||||
data = [{'name': 'adherents', 'members': adherents_data}]
|
||||
adherents_data = serializers.MailingMemberSerializer(
|
||||
all_has_access(), many=True
|
||||
).data
|
||||
data = [{"name": "adherents", "members": adherents_data}]
|
||||
paginator = self.pagination_class()
|
||||
paginator.paginate_queryset(data, request)
|
||||
return paginator.get_paginated_response(data)
|
||||
|
@ -678,6 +769,7 @@ class ClubMailingView(generics.ListAPIView):
|
|||
"""Exposes list and details of club mailings (name, members and admins) in
|
||||
order to build the corresponding mailing lists.
|
||||
"""
|
||||
|
||||
queryset = users.Club.objects.all()
|
||||
serializer_class = serializers.MailingSerializer
|
||||
|
||||
|
@ -696,12 +788,10 @@ class ObtainExpiringAuthToken(ObtainAuthToken):
|
|||
def post(self, request, *args, **kwargs):
|
||||
serializer = self.serializer_class(data=request.data)
|
||||
serializer.is_valid(raise_exception=True)
|
||||
user = serializer.validated_data['user']
|
||||
user = serializer.validated_data["user"]
|
||||
token, created = Token.objects.get_or_create(user=user)
|
||||
|
||||
token_duration = datetime.timedelta(
|
||||
seconds=settings.API_TOKEN_DURATION
|
||||
)
|
||||
token_duration = datetime.timedelta(seconds=settings.API_TOKEN_DURATION)
|
||||
utc_now = datetime.datetime.now(datetime.timezone.utc)
|
||||
if not created and token.created < utc_now - token_duration:
|
||||
token.delete()
|
||||
|
@ -709,7 +799,6 @@ class ObtainExpiringAuthToken(ObtainAuthToken):
|
|||
token.created = datetime.datetime.utcnow()
|
||||
token.save()
|
||||
|
||||
return Response({
|
||||
'token': token.key,
|
||||
'expiration': token.created + token_duration
|
||||
})
|
||||
return Response(
|
||||
{"token": token.key, "expiration": token.created + token_duration}
|
||||
)
|
||||
|
|
|
@ -5,6 +5,7 @@ texlive-fonts-recommended
|
|||
python3-djangorestframework
|
||||
python3-django-reversion
|
||||
python3-pip
|
||||
python3-pil
|
||||
libsasl2-dev libldap2-dev
|
||||
libssl-dev
|
||||
python3-crypto
|
||||
|
@ -18,3 +19,4 @@ fonts-font-awesome
|
|||
graphviz
|
||||
git
|
||||
gettext
|
||||
python3-django-ldapdb
|
||||
|
|
23
apt_requirements_radius.txt
Normal file
23
apt_requirements_radius.txt
Normal file
|
@ -0,0 +1,23 @@
|
|||
python-django
|
||||
python-dateutil
|
||||
texlive-latex-base
|
||||
texlive-fonts-recommended
|
||||
python-djangorestframework
|
||||
python-django-reversion
|
||||
python-pip
|
||||
libsasl2-dev libldap2-dev
|
||||
libssl-dev
|
||||
python-crypto
|
||||
python-git
|
||||
javascript-common
|
||||
libjs-jquery
|
||||
libjs-jquery-ui
|
||||
libjs-jquery-timepicker
|
||||
libjs-bootstrap
|
||||
fonts-font-awesome
|
||||
graphviz
|
||||
git
|
||||
gettext
|
||||
freeradius-common
|
||||
freeradius-python2
|
||||
python-mysqldb
|
|
@ -4,7 +4,7 @@
|
|||
# quelques clics.
|
||||
#
|
||||
# Copyright © 2017 Gabriel Détraz
|
||||
# Copyright © 2017 Goulven Kermarec
|
||||
# Copyright © 2017 Lara Kermarec
|
||||
# Copyright © 2017 Augustin Lemesle
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or modify
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
# quelques clics.
|
||||
#
|
||||
# Copyright © 2017 Gabriel Détraz
|
||||
# Copyright © 2017 Goulven Kermarec
|
||||
# Copyright © 2017 Lara Kermarec
|
||||
# Copyright © 2017 Augustin Lemesle
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or modify
|
||||
|
@ -38,9 +38,12 @@ def can_view(user):
|
|||
A couple (allowed, msg) where allowed is a boolean which is True if
|
||||
viewing is granted and msg is a message (can be None).
|
||||
"""
|
||||
can = user.has_module_perms('cotisations')
|
||||
can = user.has_module_perms("cotisations")
|
||||
if can:
|
||||
return can, None
|
||||
return can, None, ("cotisations",)
|
||||
else:
|
||||
return can, _("You don't have the right to view this application.")
|
||||
|
||||
return (
|
||||
can,
|
||||
_("You don't have the right to view this application."),
|
||||
("cotisations",),
|
||||
)
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
# quelques clics.
|
||||
#
|
||||
# Copyright © 2017 Gabriel Détraz
|
||||
# Copyright © 2017 Goulven Kermarec
|
||||
# Copyright © 2017 Lara Kermarec
|
||||
# Copyright © 2017 Augustin Lemesle
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or modify
|
||||
|
@ -35,42 +35,50 @@ from .models import CustomInvoice, CostEstimate
|
|||
|
||||
class FactureAdmin(VersionAdmin):
|
||||
"""Class admin d'une facture, tous les champs"""
|
||||
|
||||
pass
|
||||
|
||||
|
||||
class CostEstimateAdmin(VersionAdmin):
|
||||
"""Admin class for cost estimates."""
|
||||
|
||||
pass
|
||||
|
||||
|
||||
class CustomInvoiceAdmin(VersionAdmin):
|
||||
"""Admin class for custom invoices."""
|
||||
|
||||
pass
|
||||
|
||||
|
||||
class VenteAdmin(VersionAdmin):
|
||||
"""Class admin d'une vente, tous les champs (facture related)"""
|
||||
|
||||
pass
|
||||
|
||||
|
||||
class ArticleAdmin(VersionAdmin):
|
||||
"""Class admin d'un article en vente"""
|
||||
|
||||
pass
|
||||
|
||||
|
||||
class BanqueAdmin(VersionAdmin):
|
||||
"""Class admin de la liste des banques (facture related)"""
|
||||
|
||||
pass
|
||||
|
||||
|
||||
class PaiementAdmin(VersionAdmin):
|
||||
"""Class admin d'un moyen de paiement (facture related"""
|
||||
|
||||
pass
|
||||
|
||||
|
||||
class CotisationAdmin(VersionAdmin):
|
||||
"""Class admin d'une cotisation (date de debut et de fin),
|
||||
Vente related"""
|
||||
|
||||
pass
|
||||
|
||||
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
# quelques clics.
|
||||
#
|
||||
# Copyright © 2017 Gabriel Détraz
|
||||
# Copyright © 2017 Goulven Kermarec
|
||||
# Copyright © 2017 Lara Kermarec
|
||||
# Copyright © 2017 Augustin Lemesle
|
||||
# Copyright © 2018 Hugo Levy-Falk
|
||||
#
|
||||
|
@ -47,8 +47,13 @@ from django.shortcuts import get_object_or_404
|
|||
from re2o.field_permissions import FieldPermissionFormMixin
|
||||
from re2o.mixins import FormRevMixin
|
||||
from .models import (
|
||||
Article, Paiement, Facture, Banque,
|
||||
CustomInvoice, Vente, CostEstimate,
|
||||
Article,
|
||||
Paiement,
|
||||
Facture,
|
||||
Banque,
|
||||
CustomInvoice,
|
||||
Vente,
|
||||
CostEstimate,
|
||||
)
|
||||
from .payment_methods import balance
|
||||
|
||||
|
@ -59,31 +64,27 @@ class FactureForm(FieldPermissionFormMixin, FormRevMixin, ModelForm):
|
|||
"""
|
||||
|
||||
def __init__(self, *args, creation=False, **kwargs):
|
||||
user = kwargs['user']
|
||||
prefix = kwargs.pop('prefix', self.Meta.model.__name__)
|
||||
user = kwargs["user"]
|
||||
prefix = kwargs.pop("prefix", self.Meta.model.__name__)
|
||||
super(FactureForm, self).__init__(*args, prefix=prefix, **kwargs)
|
||||
self.fields['paiement'].empty_label = \
|
||||
_("Select a payment method")
|
||||
self.fields['paiement'].queryset = Paiement.find_allowed_payments(user)
|
||||
self.fields["paiement"].empty_label = _("Select a payment method")
|
||||
self.fields["paiement"].queryset = Paiement.find_allowed_payments(user)
|
||||
if not creation:
|
||||
self.fields['user'].label = _("Member")
|
||||
self.fields['user'].empty_label = \
|
||||
_("Select the proprietary member")
|
||||
self.fields['valid'].label = _("Validated invoice")
|
||||
self.fields["user"].label = _("Member")
|
||||
self.fields["user"].empty_label = _("Select the proprietary member")
|
||||
self.fields["valid"].label = _("Validated invoice")
|
||||
else:
|
||||
self.fields = {'paiement': self.fields['paiement']}
|
||||
self.fields = {"paiement": self.fields["paiement"]}
|
||||
|
||||
class Meta:
|
||||
model = Facture
|
||||
fields = '__all__'
|
||||
fields = "__all__"
|
||||
|
||||
def clean(self):
|
||||
cleaned_data = super(FactureForm, self).clean()
|
||||
paiement = cleaned_data.get('paiement')
|
||||
paiement = cleaned_data.get("paiement")
|
||||
if not paiement:
|
||||
raise forms.ValidationError(
|
||||
_("A payment method must be specified.")
|
||||
)
|
||||
raise forms.ValidationError(_("A payment method must be specified."))
|
||||
return cleaned_data
|
||||
|
||||
|
||||
|
@ -92,32 +93,30 @@ class SelectArticleForm(FormRevMixin, Form):
|
|||
Form used to select an article during the creation of an invoice for a
|
||||
member.
|
||||
"""
|
||||
|
||||
article = forms.ModelChoiceField(
|
||||
queryset=Article.objects.none(),
|
||||
label=_("Article"),
|
||||
required=True
|
||||
queryset=Article.objects.none(), label=_("Article"), required=True
|
||||
)
|
||||
quantity = forms.IntegerField(
|
||||
label=_("Quantity"),
|
||||
validators=[MinValueValidator(1)],
|
||||
required=True
|
||||
label=_("Quantity"), validators=[MinValueValidator(1)], required=True
|
||||
)
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
user = kwargs.pop('user')
|
||||
target_user = kwargs.pop('target_user', None)
|
||||
user = kwargs.pop("user")
|
||||
target_user = kwargs.pop("target_user", None)
|
||||
super(SelectArticleForm, self).__init__(*args, **kwargs)
|
||||
self.fields['article'].queryset = Article.find_allowed_articles(
|
||||
user, target_user)
|
||||
self.fields["article"].queryset = Article.find_allowed_articles(
|
||||
user, target_user
|
||||
)
|
||||
|
||||
|
||||
class DiscountForm(Form):
|
||||
"""
|
||||
Form used in oder to create a discount on an invoice.
|
||||
"""
|
||||
|
||||
is_relative = forms.BooleanField(
|
||||
label=_("Discount is on percentage."),
|
||||
required=False,
|
||||
label=_("Discount is in percentage."), required=False
|
||||
)
|
||||
discount = forms.DecimalField(
|
||||
label=_("Discount"),
|
||||
|
@ -130,53 +129,51 @@ class DiscountForm(Form):
|
|||
|
||||
def apply_to_invoice(self, invoice):
|
||||
invoice_price = invoice.prix_total()
|
||||
discount = self.cleaned_data['discount']
|
||||
is_relative = self.cleaned_data['is_relative']
|
||||
discount = self.cleaned_data["discount"]
|
||||
is_relative = self.cleaned_data["is_relative"]
|
||||
if is_relative:
|
||||
amount = discount/100 * invoice_price
|
||||
amount = discount / 100 * invoice_price
|
||||
else:
|
||||
amount = discount
|
||||
if amount:
|
||||
name = _("{}% discount") if is_relative else _("{}€ discount")
|
||||
name = _("{}% discount") if is_relative else _("{} € discount")
|
||||
name = name.format(discount)
|
||||
Vente.objects.create(
|
||||
facture=invoice,
|
||||
name=name,
|
||||
prix=-amount,
|
||||
number=1
|
||||
)
|
||||
Vente.objects.create(facture=invoice, name=name, prix=-amount, number=1)
|
||||
|
||||
|
||||
class CustomInvoiceForm(FormRevMixin, ModelForm):
|
||||
"""
|
||||
Form used to create a custom invoice.
|
||||
"""
|
||||
|
||||
class Meta:
|
||||
model = CustomInvoice
|
||||
fields = '__all__'
|
||||
fields = "__all__"
|
||||
|
||||
|
||||
class CostEstimateForm(FormRevMixin, ModelForm):
|
||||
"""
|
||||
Form used to create a cost estimate.
|
||||
"""
|
||||
|
||||
class Meta:
|
||||
model = CostEstimate
|
||||
exclude = ['paid', 'final_invoice']
|
||||
exclude = ["paid", "final_invoice"]
|
||||
|
||||
|
||||
class ArticleForm(FormRevMixin, ModelForm):
|
||||
"""
|
||||
Form used to create an article.
|
||||
"""
|
||||
|
||||
class Meta:
|
||||
model = Article
|
||||
fields = '__all__'
|
||||
fields = "__all__"
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
prefix = kwargs.pop('prefix', self.Meta.model.__name__)
|
||||
prefix = kwargs.pop("prefix", self.Meta.model.__name__)
|
||||
super(ArticleForm, self).__init__(*args, prefix=prefix, **kwargs)
|
||||
self.fields['name'].label = _("Article name")
|
||||
self.fields["name"].label = _("Article name")
|
||||
|
||||
|
||||
class DelArticleForm(FormRevMixin, Form):
|
||||
|
@ -184,19 +181,20 @@ class DelArticleForm(FormRevMixin, Form):
|
|||
Form used to delete one or more of the currently available articles.
|
||||
The user must choose the one to delete by checking the boxes.
|
||||
"""
|
||||
|
||||
articles = forms.ModelMultipleChoiceField(
|
||||
queryset=Article.objects.none(),
|
||||
label=_("Available articles"),
|
||||
widget=forms.CheckboxSelectMultiple
|
||||
label=_("Current articles"),
|
||||
widget=forms.CheckboxSelectMultiple,
|
||||
)
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
instances = kwargs.pop('instances', None)
|
||||
instances = kwargs.pop("instances", None)
|
||||
super(DelArticleForm, self).__init__(*args, **kwargs)
|
||||
if instances:
|
||||
self.fields['articles'].queryset = instances
|
||||
self.fields["articles"].queryset = instances
|
||||
else:
|
||||
self.fields['articles'].queryset = Article.objects.all()
|
||||
self.fields["articles"].queryset = Article.objects.all()
|
||||
|
||||
|
||||
# TODO : change Paiement to Payment
|
||||
|
@ -206,15 +204,16 @@ class PaiementForm(FormRevMixin, ModelForm):
|
|||
The 'cheque' type is used to associate a specific behaviour requiring
|
||||
a cheque number and a bank.
|
||||
"""
|
||||
|
||||
class Meta:
|
||||
model = Paiement
|
||||
# TODO : change moyen to method and type_paiement to payment_type
|
||||
fields = ['moyen', 'available_for_everyone']
|
||||
fields = ["moyen", "available_for_everyone"]
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
prefix = kwargs.pop('prefix', self.Meta.model.__name__)
|
||||
prefix = kwargs.pop("prefix", self.Meta.model.__name__)
|
||||
super(PaiementForm, self).__init__(*args, prefix=prefix, **kwargs)
|
||||
self.fields['moyen'].label = _("Payment method name")
|
||||
self.fields["moyen"].label = _("Payment method name")
|
||||
|
||||
|
||||
# TODO : change paiement to payment
|
||||
|
@ -223,20 +222,21 @@ class DelPaiementForm(FormRevMixin, Form):
|
|||
Form used to delete one or more payment methods.
|
||||
The user must choose the one to delete by checking the boxes.
|
||||
"""
|
||||
|
||||
# TODO : change paiement to payment
|
||||
paiements = forms.ModelMultipleChoiceField(
|
||||
queryset=Paiement.objects.none(),
|
||||
label=_("Available payment methods"),
|
||||
widget=forms.CheckboxSelectMultiple
|
||||
label=_("Current payment methods"),
|
||||
widget=forms.CheckboxSelectMultiple,
|
||||
)
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
instances = kwargs.pop('instances', None)
|
||||
instances = kwargs.pop("instances", None)
|
||||
super(DelPaiementForm, self).__init__(*args, **kwargs)
|
||||
if instances:
|
||||
self.fields['paiements'].queryset = instances
|
||||
self.fields["paiements"].queryset = instances
|
||||
else:
|
||||
self.fields['paiements'].queryset = Paiement.objects.all()
|
||||
self.fields["paiements"].queryset = Paiement.objects.all()
|
||||
|
||||
|
||||
# TODO : change banque to bank
|
||||
|
@ -244,15 +244,16 @@ class BanqueForm(FormRevMixin, ModelForm):
|
|||
"""
|
||||
Form used to create a bank.
|
||||
"""
|
||||
|
||||
class Meta:
|
||||
# TODO : change banque to bank
|
||||
model = Banque
|
||||
fields = ['name']
|
||||
fields = ["name"]
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
prefix = kwargs.pop('prefix', self.Meta.model.__name__)
|
||||
prefix = kwargs.pop("prefix", self.Meta.model.__name__)
|
||||
super(BanqueForm, self).__init__(*args, prefix=prefix, **kwargs)
|
||||
self.fields['name'].label = _("Bank name")
|
||||
self.fields["name"].label = _("Bank name")
|
||||
|
||||
|
||||
# TODO : change banque to bank
|
||||
|
@ -261,20 +262,21 @@ class DelBanqueForm(FormRevMixin, Form):
|
|||
Form used to delete one or more banks.
|
||||
The use must choose the one to delete by checking the boxes.
|
||||
"""
|
||||
|
||||
# TODO : change banque to bank
|
||||
banques = forms.ModelMultipleChoiceField(
|
||||
queryset=Banque.objects.none(),
|
||||
label=_("Available banks"),
|
||||
widget=forms.CheckboxSelectMultiple
|
||||
label=_("Current banks"),
|
||||
widget=forms.CheckboxSelectMultiple,
|
||||
)
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
instances = kwargs.pop('instances', None)
|
||||
instances = kwargs.pop("instances", None)
|
||||
super(DelBanqueForm, self).__init__(*args, **kwargs)
|
||||
if instances:
|
||||
self.fields['banques'].queryset = instances
|
||||
self.fields["banques"].queryset = instances
|
||||
else:
|
||||
self.fields['banques'].queryset = Banque.objects.all()
|
||||
self.fields["banques"].queryset = Banque.objects.all()
|
||||
|
||||
|
||||
# TODO : Better name and docstring
|
||||
|
@ -282,37 +284,36 @@ class RechargeForm(FormRevMixin, Form):
|
|||
"""
|
||||
Form used to refill a user's balance
|
||||
"""
|
||||
value = forms.DecimalField(
|
||||
label=_("Amount"),
|
||||
min_value=0.01,
|
||||
validators=[]
|
||||
)
|
||||
|
||||
value = forms.DecimalField(label=_("Amount"), decimal_places=2)
|
||||
payment = forms.ModelChoiceField(
|
||||
queryset=Paiement.objects.none(),
|
||||
label=_("Payment method")
|
||||
queryset=Paiement.objects.none(), label=_("Payment method")
|
||||
)
|
||||
|
||||
def __init__(self, *args, user=None, user_source=None, **kwargs):
|
||||
self.user = user
|
||||
super(RechargeForm, self).__init__(*args, **kwargs)
|
||||
self.fields['payment'].empty_label = \
|
||||
_("Select a payment method")
|
||||
self.fields['payment'].queryset = Paiement.find_allowed_payments(
|
||||
user_source).exclude(is_balance=True)
|
||||
self.fields["payment"].empty_label = _("Select a payment method")
|
||||
self.fields["payment"].queryset = Paiement.find_allowed_payments(
|
||||
user_source
|
||||
).exclude(is_balance=True)
|
||||
|
||||
def clean(self):
|
||||
"""
|
||||
Returns a cleaned value from the received form by validating
|
||||
the value is well inside the possible limits
|
||||
"""
|
||||
value = self.cleaned_data['value']
|
||||
value = self.cleaned_data["value"]
|
||||
balance_method = get_object_or_404(balance.PaymentMethod)
|
||||
if balance_method.maximum_balance is not None and \
|
||||
value + self.user.solde > balance_method.maximum_balance:
|
||||
if (
|
||||
balance_method.maximum_balance is not None
|
||||
and value + self.user.solde > balance_method.maximum_balance
|
||||
):
|
||||
raise forms.ValidationError(
|
||||
_("Requested amount is too high. Your balance can't exceed"
|
||||
" %(max_online_balance)s €.") % {
|
||||
'max_online_balance': balance_method.maximum_balance
|
||||
}
|
||||
_(
|
||||
"Requested amount is too high. Your balance can't exceed"
|
||||
" %(max_online_balance)s €."
|
||||
)
|
||||
% {"max_online_balance": balance_method.maximum_balance}
|
||||
)
|
||||
return self.cleaned_data
|
||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -3,7 +3,7 @@
|
|||
# quelques clics.
|
||||
#
|
||||
# Copyright © 2017 Gabriel Détraz
|
||||
# Copyright © 2017 Goulven Kermarec
|
||||
# Copyright © 2017 Lara Kermarec
|
||||
# Copyright © 2017 Augustin Lemesle
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or modify
|
||||
|
@ -29,54 +29,100 @@ import django.db.models.deletion
|
|||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('users', '0005_auto_20160702_0006'),
|
||||
]
|
||||
dependencies = [("users", "0005_auto_20160702_0006")]
|
||||
|
||||
operations = [
|
||||
migrations.CreateModel(
|
||||
name='Article',
|
||||
name="Article",
|
||||
fields=[
|
||||
('id', models.AutoField(verbose_name='ID', auto_created=True, primary_key=True, serialize=False)),
|
||||
('name', models.CharField(max_length=255)),
|
||||
('prix', models.DecimalField(decimal_places=2, max_digits=5)),
|
||||
(
|
||||
"id",
|
||||
models.AutoField(
|
||||
verbose_name="ID",
|
||||
auto_created=True,
|
||||
primary_key=True,
|
||||
serialize=False,
|
||||
),
|
||||
),
|
||||
("name", models.CharField(max_length=255)),
|
||||
("prix", models.DecimalField(decimal_places=2, max_digits=5)),
|
||||
],
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name='Banque',
|
||||
name="Banque",
|
||||
fields=[
|
||||
('id', models.AutoField(verbose_name='ID', auto_created=True, primary_key=True, serialize=False)),
|
||||
('name', models.CharField(max_length=255)),
|
||||
(
|
||||
"id",
|
||||
models.AutoField(
|
||||
verbose_name="ID",
|
||||
auto_created=True,
|
||||
primary_key=True,
|
||||
serialize=False,
|
||||
),
|
||||
),
|
||||
("name", models.CharField(max_length=255)),
|
||||
],
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name='Facture',
|
||||
name="Facture",
|
||||
fields=[
|
||||
('id', models.AutoField(verbose_name='ID', auto_created=True, primary_key=True, serialize=False)),
|
||||
('cheque', models.CharField(max_length=255)),
|
||||
('number', models.IntegerField()),
|
||||
('date', models.DateTimeField(auto_now_add=True)),
|
||||
('name', models.CharField(max_length=255)),
|
||||
('prix', models.DecimalField(decimal_places=2, max_digits=5)),
|
||||
('article', models.ForeignKey(to='cotisations.Article', on_delete=django.db.models.deletion.PROTECT)),
|
||||
('banque', models.ForeignKey(to='cotisations.Banque', on_delete=django.db.models.deletion.PROTECT)),
|
||||
(
|
||||
"id",
|
||||
models.AutoField(
|
||||
verbose_name="ID",
|
||||
auto_created=True,
|
||||
primary_key=True,
|
||||
serialize=False,
|
||||
),
|
||||
),
|
||||
("cheque", models.CharField(max_length=255)),
|
||||
("number", models.IntegerField()),
|
||||
("date", models.DateTimeField(auto_now_add=True)),
|
||||
("name", models.CharField(max_length=255)),
|
||||
("prix", models.DecimalField(decimal_places=2, max_digits=5)),
|
||||
(
|
||||
"article",
|
||||
models.ForeignKey(
|
||||
to="cotisations.Article",
|
||||
on_delete=django.db.models.deletion.PROTECT,
|
||||
),
|
||||
),
|
||||
(
|
||||
"banque",
|
||||
models.ForeignKey(
|
||||
to="cotisations.Banque",
|
||||
on_delete=django.db.models.deletion.PROTECT,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name='Paiement',
|
||||
name="Paiement",
|
||||
fields=[
|
||||
('id', models.AutoField(verbose_name='ID', auto_created=True, primary_key=True, serialize=False)),
|
||||
('moyen', models.CharField(max_length=255)),
|
||||
(
|
||||
"id",
|
||||
models.AutoField(
|
||||
verbose_name="ID",
|
||||
auto_created=True,
|
||||
primary_key=True,
|
||||
serialize=False,
|
||||
),
|
||||
),
|
||||
("moyen", models.CharField(max_length=255)),
|
||||
],
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='facture',
|
||||
name='paiement',
|
||||
field=models.ForeignKey(to='cotisations.Paiement', on_delete=django.db.models.deletion.PROTECT),
|
||||
model_name="facture",
|
||||
name="paiement",
|
||||
field=models.ForeignKey(
|
||||
to="cotisations.Paiement", on_delete=django.db.models.deletion.PROTECT
|
||||
),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='facture',
|
||||
name='user',
|
||||
field=models.ForeignKey(to='users.User', on_delete=django.db.models.deletion.PROTECT),
|
||||
model_name="facture",
|
||||
name="user",
|
||||
field=models.ForeignKey(
|
||||
to="users.User", on_delete=django.db.models.deletion.PROTECT
|
||||
),
|
||||
),
|
||||
]
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
# quelques clics.
|
||||
#
|
||||
# Copyright © 2017 Gabriel Détraz
|
||||
# Copyright © 2017 Goulven Kermarec
|
||||
# Copyright © 2017 Lara Kermarec
|
||||
# Copyright © 2017 Augustin Lemesle
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or modify
|
||||
|
@ -28,13 +28,6 @@ from django.db import migrations, models
|
|||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('cotisations', '0001_initial'),
|
||||
]
|
||||
dependencies = [("cotisations", "0001_initial")]
|
||||
|
||||
operations = [
|
||||
migrations.RemoveField(
|
||||
model_name='facture',
|
||||
name='article',
|
||||
),
|
||||
]
|
||||
operations = [migrations.RemoveField(model_name="facture", name="article")]
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
# quelques clics.
|
||||
#
|
||||
# Copyright © 2017 Gabriel Détraz
|
||||
# Copyright © 2017 Goulven Kermarec
|
||||
# Copyright © 2017 Lara Kermarec
|
||||
# Copyright © 2017 Augustin Lemesle
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or modify
|
||||
|
@ -29,14 +29,17 @@ import django.db.models.deletion
|
|||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('cotisations', '0002_remove_facture_article'),
|
||||
]
|
||||
dependencies = [("cotisations", "0002_remove_facture_article")]
|
||||
|
||||
operations = [
|
||||
migrations.AlterField(
|
||||
model_name='facture',
|
||||
name='banque',
|
||||
field=models.ForeignKey(blank=True, to='cotisations.Banque', on_delete=django.db.models.deletion.PROTECT, null=True),
|
||||
),
|
||||
model_name="facture",
|
||||
name="banque",
|
||||
field=models.ForeignKey(
|
||||
blank=True,
|
||||
to="cotisations.Banque",
|
||||
on_delete=django.db.models.deletion.PROTECT,
|
||||
null=True,
|
||||
),
|
||||
)
|
||||
]
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
# quelques clics.
|
||||
#
|
||||
# Copyright © 2017 Gabriel Détraz
|
||||
# Copyright © 2017 Goulven Kermarec
|
||||
# Copyright © 2017 Lara Kermarec
|
||||
# Copyright © 2017 Augustin Lemesle
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or modify
|
||||
|
@ -28,19 +28,17 @@ from django.db import migrations, models
|
|||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('cotisations', '0003_auto_20160702_1448'),
|
||||
]
|
||||
dependencies = [("cotisations", "0003_auto_20160702_1448")]
|
||||
|
||||
operations = [
|
||||
migrations.AlterField(
|
||||
model_name='facture',
|
||||
name='name',
|
||||
model_name="facture",
|
||||
name="name",
|
||||
field=models.CharField(null=True, max_length=255),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='facture',
|
||||
name='prix',
|
||||
model_name="facture",
|
||||
name="prix",
|
||||
field=models.DecimalField(max_digits=5, null=True, decimal_places=2),
|
||||
),
|
||||
]
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
# quelques clics.
|
||||
#
|
||||
# Copyright © 2017 Gabriel Détraz
|
||||
# Copyright © 2017 Goulven Kermarec
|
||||
# Copyright © 2017 Lara Kermarec
|
||||
# Copyright © 2017 Augustin Lemesle
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or modify
|
||||
|
@ -28,14 +28,12 @@ from django.db import migrations, models
|
|||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('cotisations', '0004_auto_20160702_1528'),
|
||||
]
|
||||
dependencies = [("cotisations", "0004_auto_20160702_1528")]
|
||||
|
||||
operations = [
|
||||
migrations.AlterField(
|
||||
model_name='facture',
|
||||
name='cheque',
|
||||
model_name="facture",
|
||||
name="cheque",
|
||||
field=models.CharField(max_length=255, blank=True),
|
||||
),
|
||||
)
|
||||
]
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
# quelques clics.
|
||||
#
|
||||
# Copyright © 2017 Gabriel Détraz
|
||||
# Copyright © 2017 Goulven Kermarec
|
||||
# Copyright © 2017 Lara Kermarec
|
||||
# Copyright © 2017 Augustin Lemesle
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or modify
|
||||
|
@ -28,19 +28,19 @@ from django.db import migrations, models
|
|||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('cotisations', '0005_auto_20160702_1532'),
|
||||
]
|
||||
dependencies = [("cotisations", "0005_auto_20160702_1532")]
|
||||
|
||||
operations = [
|
||||
migrations.AlterField(
|
||||
model_name='facture',
|
||||
name='name',
|
||||
field=models.CharField(null=True, default='plop', max_length=255),
|
||||
model_name="facture",
|
||||
name="name",
|
||||
field=models.CharField(null=True, default="plop", max_length=255),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='facture',
|
||||
name='prix',
|
||||
field=models.DecimalField(null=True, decimal_places=2, default=1, max_digits=5),
|
||||
model_name="facture",
|
||||
name="prix",
|
||||
field=models.DecimalField(
|
||||
null=True, decimal_places=2, default=1, max_digits=5
|
||||
),
|
||||
),
|
||||
]
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
# quelques clics.
|
||||
#
|
||||
# Copyright © 2017 Gabriel Détraz
|
||||
# Copyright © 2017 Goulven Kermarec
|
||||
# Copyright © 2017 Lara Kermarec
|
||||
# Copyright © 2017 Augustin Lemesle
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or modify
|
||||
|
@ -28,20 +28,18 @@ from django.db import migrations, models
|
|||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('cotisations', '0006_auto_20160702_1534'),
|
||||
]
|
||||
dependencies = [("cotisations", "0006_auto_20160702_1534")]
|
||||
|
||||
operations = [
|
||||
migrations.AlterField(
|
||||
model_name='facture',
|
||||
name='name',
|
||||
field=models.CharField(default='plop', max_length=255),
|
||||
model_name="facture",
|
||||
name="name",
|
||||
field=models.CharField(default="plop", max_length=255),
|
||||
preserve_default=False,
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='facture',
|
||||
name='prix',
|
||||
model_name="facture",
|
||||
name="prix",
|
||||
field=models.DecimalField(default=1, max_digits=5, decimal_places=2),
|
||||
preserve_default=False,
|
||||
),
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
# quelques clics.
|
||||
#
|
||||
# Copyright © 2017 Gabriel Détraz
|
||||
# Copyright © 2017 Goulven Kermarec
|
||||
# Copyright © 2017 Lara Kermarec
|
||||
# Copyright © 2017 Augustin Lemesle
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or modify
|
||||
|
@ -30,43 +30,53 @@ import django.db.models.deletion
|
|||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('users', '0005_auto_20160702_0006'),
|
||||
('cotisations', '0007_auto_20160702_1543'),
|
||||
("users", "0005_auto_20160702_0006"),
|
||||
("cotisations", "0007_auto_20160702_1543"),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.CreateModel(
|
||||
name='Cotisation',
|
||||
name="Cotisation",
|
||||
fields=[
|
||||
('id', models.AutoField(verbose_name='ID', primary_key=True, serialize=False, auto_created=True)),
|
||||
('date_start', models.DateTimeField(auto_now_add=True)),
|
||||
('date_end', models.DateTimeField()),
|
||||
(
|
||||
"id",
|
||||
models.AutoField(
|
||||
verbose_name="ID",
|
||||
primary_key=True,
|
||||
serialize=False,
|
||||
auto_created=True,
|
||||
),
|
||||
),
|
||||
("date_start", models.DateTimeField(auto_now_add=True)),
|
||||
("date_end", models.DateTimeField()),
|
||||
],
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='article',
|
||||
name='cotisation',
|
||||
model_name="article",
|
||||
name="cotisation",
|
||||
field=models.BooleanField(default=True),
|
||||
preserve_default=False,
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='article',
|
||||
name='duration',
|
||||
model_name="article",
|
||||
name="duration",
|
||||
field=models.DurationField(blank=True, null=True),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='facture',
|
||||
name='valid',
|
||||
field=models.BooleanField(default=True),
|
||||
model_name="facture", name="valid", field=models.BooleanField(default=True)
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='cotisation',
|
||||
name='facture',
|
||||
field=models.ForeignKey(to='cotisations.Facture', on_delete=django.db.models.deletion.PROTECT),
|
||||
model_name="cotisation",
|
||||
name="facture",
|
||||
field=models.ForeignKey(
|
||||
to="cotisations.Facture", on_delete=django.db.models.deletion.PROTECT
|
||||
),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='cotisation',
|
||||
name='user',
|
||||
field=models.ForeignKey(to='users.User', on_delete=django.db.models.deletion.PROTECT),
|
||||
model_name="cotisation",
|
||||
name="user",
|
||||
field=models.ForeignKey(
|
||||
to="users.User", on_delete=django.db.models.deletion.PROTECT
|
||||
),
|
||||
),
|
||||
]
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
# quelques clics.
|
||||
#
|
||||
# Copyright © 2017 Gabriel Détraz
|
||||
# Copyright © 2017 Goulven Kermarec
|
||||
# Copyright © 2017 Lara Kermarec
|
||||
# Copyright © 2017 Augustin Lemesle
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or modify
|
||||
|
@ -28,13 +28,6 @@ from django.db import migrations, models
|
|||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('cotisations', '0008_auto_20160702_1614'),
|
||||
]
|
||||
dependencies = [("cotisations", "0008_auto_20160702_1614")]
|
||||
|
||||
operations = [
|
||||
migrations.RemoveField(
|
||||
model_name='cotisation',
|
||||
name='user',
|
||||
),
|
||||
]
|
||||
operations = [migrations.RemoveField(model_name="cotisation", name="user")]
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
# quelques clics.
|
||||
#
|
||||
# Copyright © 2017 Gabriel Détraz
|
||||
# Copyright © 2017 Goulven Kermarec
|
||||
# Copyright © 2017 Lara Kermarec
|
||||
# Copyright © 2017 Augustin Lemesle
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or modify
|
||||
|
@ -28,18 +28,15 @@ from django.db import migrations, models
|
|||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('cotisations', '0009_remove_cotisation_user'),
|
||||
]
|
||||
dependencies = [("cotisations", "0009_remove_cotisation_user")]
|
||||
|
||||
operations = [
|
||||
migrations.RemoveField(
|
||||
model_name='article',
|
||||
name='duration',
|
||||
),
|
||||
migrations.RemoveField(model_name="article", name="duration"),
|
||||
migrations.AddField(
|
||||
model_name='article',
|
||||
name='duration',
|
||||
field=models.IntegerField(null=True, help_text='Durée exprimée en mois entiers', blank=True),
|
||||
model_name="article",
|
||||
name="duration",
|
||||
field=models.IntegerField(
|
||||
null=True, help_text="Durée exprimée en mois entiers", blank=True
|
||||
),
|
||||
),
|
||||
]
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
# quelques clics.
|
||||
#
|
||||
# Copyright © 2017 Gabriel Détraz
|
||||
# Copyright © 2017 Goulven Kermarec
|
||||
# Copyright © 2017 Lara Kermarec
|
||||
# Copyright © 2017 Augustin Lemesle
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or modify
|
||||
|
@ -28,14 +28,10 @@ from django.db import migrations, models
|
|||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('cotisations', '0010_auto_20160702_1840'),
|
||||
]
|
||||
dependencies = [("cotisations", "0010_auto_20160702_1840")]
|
||||
|
||||
operations = [
|
||||
migrations.AlterField(
|
||||
model_name='cotisation',
|
||||
name='date_start',
|
||||
field=models.DateTimeField(),
|
||||
),
|
||||
model_name="cotisation", name="date_start", field=models.DateTimeField()
|
||||
)
|
||||
]
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
# quelques clics.
|
||||
#
|
||||
# Copyright © 2017 Gabriel Détraz
|
||||
# Copyright © 2017 Goulven Kermarec
|
||||
# Copyright © 2017 Lara Kermarec
|
||||
# Copyright © 2017 Augustin Lemesle
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or modify
|
||||
|
@ -29,14 +29,14 @@ import django.db.models.deletion
|
|||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('cotisations', '0011_auto_20160702_1911'),
|
||||
]
|
||||
dependencies = [("cotisations", "0011_auto_20160702_1911")]
|
||||
|
||||
operations = [
|
||||
migrations.AlterField(
|
||||
model_name='cotisation',
|
||||
name='facture',
|
||||
field=models.OneToOneField(on_delete=django.db.models.deletion.PROTECT, to='cotisations.Facture'),
|
||||
),
|
||||
model_name="cotisation",
|
||||
name="facture",
|
||||
field=models.OneToOneField(
|
||||
on_delete=django.db.models.deletion.PROTECT, to="cotisations.Facture"
|
||||
),
|
||||
)
|
||||
]
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
# quelques clics.
|
||||
#
|
||||
# Copyright © 2017 Gabriel Détraz
|
||||
# Copyright © 2017 Goulven Kermarec
|
||||
# Copyright © 2017 Lara Kermarec
|
||||
# Copyright © 2017 Augustin Lemesle
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or modify
|
||||
|
@ -29,32 +29,41 @@ import django.db.models.deletion
|
|||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('cotisations', '0012_auto_20160704_0118'),
|
||||
]
|
||||
dependencies = [("cotisations", "0012_auto_20160704_0118")]
|
||||
|
||||
operations = [
|
||||
migrations.CreateModel(
|
||||
name='Vente',
|
||||
name="Vente",
|
||||
fields=[
|
||||
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||
('name', models.CharField(max_length=255)),
|
||||
('prix', models.DecimalField(decimal_places=2, max_digits=5)),
|
||||
('cotisation', models.BooleanField()),
|
||||
('duration', models.IntegerField(null=True, blank=True, help_text='Durée exprimée en mois entiers')),
|
||||
(
|
||||
"id",
|
||||
models.AutoField(
|
||||
auto_created=True,
|
||||
primary_key=True,
|
||||
serialize=False,
|
||||
verbose_name="ID",
|
||||
),
|
||||
),
|
||||
("name", models.CharField(max_length=255)),
|
||||
("prix", models.DecimalField(decimal_places=2, max_digits=5)),
|
||||
("cotisation", models.BooleanField()),
|
||||
(
|
||||
"duration",
|
||||
models.IntegerField(
|
||||
null=True,
|
||||
blank=True,
|
||||
help_text="Durée exprimée en mois entiers",
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
migrations.RemoveField(
|
||||
model_name='facture',
|
||||
name='name',
|
||||
),
|
||||
migrations.RemoveField(
|
||||
model_name='facture',
|
||||
name='prix',
|
||||
),
|
||||
migrations.RemoveField(model_name="facture", name="name"),
|
||||
migrations.RemoveField(model_name="facture", name="prix"),
|
||||
migrations.AddField(
|
||||
model_name='vente',
|
||||
name='facture',
|
||||
field=models.ForeignKey(to='cotisations.Facture', on_delete=django.db.models.deletion.PROTECT),
|
||||
model_name="vente",
|
||||
name="facture",
|
||||
field=models.ForeignKey(
|
||||
to="cotisations.Facture", on_delete=django.db.models.deletion.PROTECT
|
||||
),
|
||||
),
|
||||
]
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
# quelques clics.
|
||||
#
|
||||
# Copyright © 2017 Gabriel Détraz
|
||||
# Copyright © 2017 Goulven Kermarec
|
||||
# Copyright © 2017 Lara Kermarec
|
||||
# Copyright © 2017 Augustin Lemesle
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or modify
|
||||
|
@ -28,18 +28,13 @@ from django.db import migrations, models
|
|||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('cotisations', '0013_auto_20160711_2240'),
|
||||
]
|
||||
dependencies = [("cotisations", "0013_auto_20160711_2240")]
|
||||
|
||||
operations = [
|
||||
migrations.RemoveField(
|
||||
model_name='facture',
|
||||
name='number',
|
||||
),
|
||||
migrations.RemoveField(model_name="facture", name="number"),
|
||||
migrations.AddField(
|
||||
model_name='vente',
|
||||
name='number',
|
||||
model_name="vente",
|
||||
name="number",
|
||||
field=models.IntegerField(default=1),
|
||||
preserve_default=False,
|
||||
),
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
# quelques clics.
|
||||
#
|
||||
# Copyright © 2017 Gabriel Détraz
|
||||
# Copyright © 2017 Goulven Kermarec
|
||||
# Copyright © 2017 Lara Kermarec
|
||||
# Copyright © 2017 Augustin Lemesle
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or modify
|
||||
|
@ -29,29 +29,29 @@ import django.core.validators
|
|||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('cotisations', '0014_auto_20160712_0245'),
|
||||
]
|
||||
dependencies = [("cotisations", "0014_auto_20160712_0245")]
|
||||
|
||||
operations = [
|
||||
migrations.AddField(
|
||||
model_name='facture',
|
||||
name='control',
|
||||
model_name="facture",
|
||||
name="control",
|
||||
field=models.BooleanField(default=False),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='cotisation',
|
||||
name='facture',
|
||||
field=models.OneToOneField(to='cotisations.Facture'),
|
||||
model_name="cotisation",
|
||||
name="facture",
|
||||
field=models.OneToOneField(to="cotisations.Facture"),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='vente',
|
||||
name='facture',
|
||||
field=models.ForeignKey(to='cotisations.Facture'),
|
||||
model_name="vente",
|
||||
name="facture",
|
||||
field=models.ForeignKey(to="cotisations.Facture"),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='vente',
|
||||
name='number',
|
||||
field=models.IntegerField(validators=[django.core.validators.MinValueValidator(1)]),
|
||||
model_name="vente",
|
||||
name="number",
|
||||
field=models.IntegerField(
|
||||
validators=[django.core.validators.MinValueValidator(1)]
|
||||
),
|
||||
),
|
||||
]
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
# quelques clics.
|
||||
#
|
||||
# Copyright © 2017 Gabriel Détraz
|
||||
# Copyright © 2017 Goulven Kermarec
|
||||
# Copyright © 2017 Lara Kermarec
|
||||
# Copyright © 2017 Augustin Lemesle
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or modify
|
||||
|
@ -28,29 +28,20 @@ from django.db import migrations, models
|
|||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('cotisations', '0015_auto_20160714_2142'),
|
||||
]
|
||||
dependencies = [("cotisations", "0015_auto_20160714_2142")]
|
||||
|
||||
operations = [
|
||||
migrations.RenameField(
|
||||
model_name='article',
|
||||
old_name='cotisation',
|
||||
new_name='iscotisation',
|
||||
model_name="article", old_name="cotisation", new_name="iscotisation"
|
||||
),
|
||||
migrations.RenameField(
|
||||
model_name='vente',
|
||||
old_name='cotisation',
|
||||
new_name='iscotisation',
|
||||
),
|
||||
migrations.RemoveField(
|
||||
model_name='cotisation',
|
||||
name='facture',
|
||||
model_name="vente", old_name="cotisation", new_name="iscotisation"
|
||||
),
|
||||
migrations.RemoveField(model_name="cotisation", name="facture"),
|
||||
migrations.AddField(
|
||||
model_name='cotisation',
|
||||
name='vente',
|
||||
field=models.OneToOneField(to='cotisations.Vente', null=True),
|
||||
model_name="cotisation",
|
||||
name="vente",
|
||||
field=models.OneToOneField(to="cotisations.Vente", null=True),
|
||||
preserve_default=False,
|
||||
),
|
||||
]
|
||||
|
|
|
@ -8,19 +8,22 @@ from django.db import migrations, models
|
|||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('cotisations', '0016_auto_20160715_0110'),
|
||||
]
|
||||
dependencies = [("cotisations", "0016_auto_20160715_0110")]
|
||||
|
||||
operations = [
|
||||
migrations.AlterField(
|
||||
model_name='article',
|
||||
name='duration',
|
||||
field=models.IntegerField(blank=True, help_text='Durée exprimée en mois entiers', null=True, validators=[django.core.validators.MinValueValidator(0)]),
|
||||
model_name="article",
|
||||
name="duration",
|
||||
field=models.IntegerField(
|
||||
blank=True,
|
||||
help_text="Durée exprimée en mois entiers",
|
||||
null=True,
|
||||
validators=[django.core.validators.MinValueValidator(0)],
|
||||
),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='article',
|
||||
name='name',
|
||||
model_name="article",
|
||||
name="name",
|
||||
field=models.CharField(max_length=255, unique=True),
|
||||
),
|
||||
]
|
||||
|
|
|
@ -7,15 +7,17 @@ from django.db import migrations, models
|
|||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('cotisations', '0017_auto_20170718_2329'),
|
||||
]
|
||||
dependencies = [("cotisations", "0017_auto_20170718_2329")]
|
||||
|
||||
operations = [
|
||||
migrations.AddField(
|
||||
model_name='paiement',
|
||||
name='type_paiement',
|
||||
field=models.CharField(choices=[('check', 'Chèque'), (None, 'Autre')], default=None, max_length=255),
|
||||
model_name="paiement",
|
||||
name="type_paiement",
|
||||
field=models.CharField(
|
||||
choices=[("check", "Chèque"), (None, "Autre")],
|
||||
default=None,
|
||||
max_length=255,
|
||||
),
|
||||
preserve_default=False,
|
||||
),
|
||||
)
|
||||
]
|
||||
|
|
|
@ -7,14 +7,14 @@ from django.db import migrations, models
|
|||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('cotisations', '0018_paiement_type_paiement'),
|
||||
]
|
||||
dependencies = [("cotisations", "0018_paiement_type_paiement")]
|
||||
|
||||
operations = [
|
||||
migrations.AlterField(
|
||||
model_name='paiement',
|
||||
name='type_paiement',
|
||||
field=models.CharField(choices=[(0, 'Autre'), (1, 'Chèque')], default=0, max_length=255),
|
||||
),
|
||||
model_name="paiement",
|
||||
name="type_paiement",
|
||||
field=models.CharField(
|
||||
choices=[(0, "Autre"), (1, "Chèque")], default=0, max_length=255
|
||||
),
|
||||
)
|
||||
]
|
||||
|
|
|
@ -7,14 +7,14 @@ from django.db import migrations, models
|
|||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('cotisations', '0019_auto_20170819_0055'),
|
||||
]
|
||||
dependencies = [("cotisations", "0019_auto_20170819_0055")]
|
||||
|
||||
operations = [
|
||||
migrations.AlterField(
|
||||
model_name='paiement',
|
||||
name='type_paiement',
|
||||
field=models.IntegerField(choices=[(0, 'Autre'), (1, 'Chèque')], default=0, max_length=255),
|
||||
),
|
||||
model_name="paiement",
|
||||
name="type_paiement",
|
||||
field=models.IntegerField(
|
||||
choices=[(0, "Autre"), (1, "Chèque")], default=0, max_length=255
|
||||
),
|
||||
)
|
||||
]
|
||||
|
|
|
@ -7,14 +7,12 @@ from django.db import migrations, models
|
|||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('cotisations', '0020_auto_20170819_0057'),
|
||||
]
|
||||
dependencies = [("cotisations", "0020_auto_20170819_0057")]
|
||||
|
||||
operations = [
|
||||
migrations.AlterField(
|
||||
model_name='paiement',
|
||||
name='type_paiement',
|
||||
field=models.IntegerField(choices=[(0, 'Autre'), (1, 'Chèque')], default=0),
|
||||
),
|
||||
model_name="paiement",
|
||||
name="type_paiement",
|
||||
field=models.IntegerField(choices=[(0, "Autre"), (1, "Chèque")], default=0),
|
||||
)
|
||||
]
|
||||
|
|
|
@ -7,14 +7,14 @@ from django.db import migrations, models
|
|||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('cotisations', '0021_auto_20170819_0104'),
|
||||
]
|
||||
dependencies = [("cotisations", "0021_auto_20170819_0104")]
|
||||
|
||||
operations = [
|
||||
migrations.AlterField(
|
||||
model_name='paiement',
|
||||
name='type_paiement',
|
||||
field=models.IntegerField(choices=[(0, 'Autre'), (1, 'Chèque')], default=0, max_length=255),
|
||||
),
|
||||
model_name="paiement",
|
||||
name="type_paiement",
|
||||
field=models.IntegerField(
|
||||
choices=[(0, "Autre"), (1, "Chèque")], default=0, max_length=255
|
||||
),
|
||||
)
|
||||
]
|
||||
|
|
|
@ -7,14 +7,12 @@ from django.db import migrations, models
|
|||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('cotisations', '0022_auto_20170824_0128'),
|
||||
]
|
||||
dependencies = [("cotisations", "0022_auto_20170824_0128")]
|
||||
|
||||
operations = [
|
||||
migrations.AlterField(
|
||||
model_name='paiement',
|
||||
name='type_paiement',
|
||||
field=models.IntegerField(choices=[(0, 'Autre'), (1, 'Chèque')], default=0),
|
||||
),
|
||||
model_name="paiement",
|
||||
name="type_paiement",
|
||||
field=models.IntegerField(choices=[(0, "Autre"), (1, "Chèque")], default=0),
|
||||
)
|
||||
]
|
||||
|
|
|
@ -8,19 +8,24 @@ from django.db import migrations, models
|
|||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('cotisations', '0023_auto_20170902_1303'),
|
||||
]
|
||||
dependencies = [("cotisations", "0023_auto_20170902_1303")]
|
||||
|
||||
operations = [
|
||||
migrations.AlterField(
|
||||
model_name='article',
|
||||
name='duration',
|
||||
field=models.PositiveIntegerField(blank=True, help_text='Durée exprimée en mois entiers', null=True, validators=[django.core.validators.MinValueValidator(0)]),
|
||||
model_name="article",
|
||||
name="duration",
|
||||
field=models.PositiveIntegerField(
|
||||
blank=True,
|
||||
help_text="Durée exprimée en mois entiers",
|
||||
null=True,
|
||||
validators=[django.core.validators.MinValueValidator(0)],
|
||||
),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='vente',
|
||||
name='duration',
|
||||
field=models.PositiveIntegerField(blank=True, help_text='Durée exprimée en mois entiers', null=True),
|
||||
model_name="vente",
|
||||
name="duration",
|
||||
field=models.PositiveIntegerField(
|
||||
blank=True, help_text="Durée exprimée en mois entiers", null=True
|
||||
),
|
||||
),
|
||||
]
|
||||
|
|
|
@ -7,14 +7,16 @@ from django.db import migrations, models
|
|||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('cotisations', '0024_auto_20171015_2033'),
|
||||
]
|
||||
dependencies = [("cotisations", "0024_auto_20171015_2033")]
|
||||
|
||||
operations = [
|
||||
migrations.AddField(
|
||||
model_name='article',
|
||||
name='type_user',
|
||||
field=models.CharField(choices=[('Adherent', 'Adherent'), ('Club', 'Club'), ('All', 'All')], default='All', max_length=255),
|
||||
),
|
||||
model_name="article",
|
||||
name="type_user",
|
||||
field=models.CharField(
|
||||
choices=[("Adherent", "Adherent"), ("Club", "Club"), ("All", "All")],
|
||||
default="All",
|
||||
max_length=255,
|
||||
),
|
||||
)
|
||||
]
|
||||
|
|
|
@ -6,73 +6,94 @@ from django.db import migrations, models
|
|||
|
||||
|
||||
def create_type(apps, schema_editor):
|
||||
Cotisation = apps.get_model('cotisations', 'Cotisation')
|
||||
Vente = apps.get_model('cotisations', 'Vente')
|
||||
Article = apps.get_model('cotisations', 'Article')
|
||||
Cotisation = apps.get_model("cotisations", "Cotisation")
|
||||
Vente = apps.get_model("cotisations", "Vente")
|
||||
Article = apps.get_model("cotisations", "Article")
|
||||
db_alias = schema_editor.connection.alias
|
||||
articles = Article.objects.using(db_alias).all()
|
||||
ventes = Vente.objects.using(db_alias).all()
|
||||
cotisations = Cotisation.objects.using(db_alias).all()
|
||||
for article in articles:
|
||||
if article.iscotisation:
|
||||
article.type_cotisation='All'
|
||||
article.type_cotisation = "All"
|
||||
article.save(using=db_alias)
|
||||
for vente in ventes:
|
||||
if vente.iscotisation:
|
||||
vente.type_cotisation='All'
|
||||
vente.type_cotisation = "All"
|
||||
vente.save(using=db_alias)
|
||||
for cotisation in cotisations:
|
||||
cotisation.type_cotisation='All'
|
||||
cotisation.type_cotisation = "All"
|
||||
cotisation.save(using=db_alias)
|
||||
|
||||
|
||||
def delete_type(apps, schema_editor):
|
||||
Vente = apps.get_model('cotisations', 'Vente')
|
||||
Article = apps.get_model('cotisations', 'Article')
|
||||
Vente = apps.get_model("cotisations", "Vente")
|
||||
Article = apps.get_model("cotisations", "Article")
|
||||
db_alias = schema_editor.connection.alias
|
||||
articles = Articles.objects.using(db_alias).all()
|
||||
articles = Article.objects.using(db_alias).all()
|
||||
ventes = Vente.objects.using(db_alias).all()
|
||||
for article in articles:
|
||||
if article.type_cotisation:
|
||||
article.iscotisation=True
|
||||
article.iscotisation = True
|
||||
else:
|
||||
article.iscotisation=False
|
||||
article.iscotisation = False
|
||||
article.save(using=db_alias)
|
||||
for vente in ventes:
|
||||
if vente.iscotisation:
|
||||
vente.iscotisation=True
|
||||
vente.iscotisation = True
|
||||
else:
|
||||
vente.iscotisation=False
|
||||
vente.iscotisation = False
|
||||
vente.save(using=db_alias)
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('cotisations', '0025_article_type_user'),
|
||||
]
|
||||
dependencies = [("cotisations", "0025_article_type_user")]
|
||||
|
||||
operations = [
|
||||
migrations.AddField(
|
||||
model_name='article',
|
||||
name='type_cotisation',
|
||||
field=models.CharField(blank=True, choices=[('Connexion', 'Connexion'), ('Adhesion', 'Adhesion'), ('All', 'All')], default=None, max_length=255, null=True),
|
||||
model_name="article",
|
||||
name="type_cotisation",
|
||||
field=models.CharField(
|
||||
blank=True,
|
||||
choices=[
|
||||
("Connexion", "Connexion"),
|
||||
("Adhesion", "Adhesion"),
|
||||
("All", "All"),
|
||||
],
|
||||
default=None,
|
||||
max_length=255,
|
||||
null=True,
|
||||
),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='cotisation',
|
||||
name='type_cotisation',
|
||||
field=models.CharField(choices=[('Connexion', 'Connexion'), ('Adhesion', 'Adhesion'), ('All', 'All')], max_length=255, default='All'),
|
||||
model_name="cotisation",
|
||||
name="type_cotisation",
|
||||
field=models.CharField(
|
||||
choices=[
|
||||
("Connexion", "Connexion"),
|
||||
("Adhesion", "Adhesion"),
|
||||
("All", "All"),
|
||||
],
|
||||
max_length=255,
|
||||
default="All",
|
||||
),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='vente',
|
||||
name='type_cotisation',
|
||||
field=models.CharField(blank=True, choices=[('Connexion', 'Connexion'), ('Adhesion', 'Adhesion'), ('All', 'All')], max_length=255, null=True),
|
||||
model_name="vente",
|
||||
name="type_cotisation",
|
||||
field=models.CharField(
|
||||
blank=True,
|
||||
choices=[
|
||||
("Connexion", "Connexion"),
|
||||
("Adhesion", "Adhesion"),
|
||||
("All", "All"),
|
||||
],
|
||||
max_length=255,
|
||||
null=True,
|
||||
),
|
||||
),
|
||||
migrations.RunPython(create_type, delete_type),
|
||||
migrations.RemoveField(
|
||||
model_name='article',
|
||||
name='iscotisation',
|
||||
),
|
||||
migrations.RemoveField(
|
||||
model_name='vente',
|
||||
name='iscotisation',
|
||||
),
|
||||
migrations.RemoveField(model_name="article", name="iscotisation"),
|
||||
migrations.RemoveField(model_name="vente", name="iscotisation"),
|
||||
]
|
||||
|
|
|
@ -7,14 +7,10 @@ from django.db import migrations, models
|
|||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('cotisations', '0026_auto_20171028_0126'),
|
||||
]
|
||||
dependencies = [("cotisations", "0026_auto_20171028_0126")]
|
||||
|
||||
operations = [
|
||||
migrations.AlterField(
|
||||
model_name='article',
|
||||
name='name',
|
||||
field=models.CharField(max_length=255),
|
||||
),
|
||||
model_name="article", name="name", field=models.CharField(max_length=255)
|
||||
)
|
||||
]
|
||||
|
|
|
@ -7,33 +7,56 @@ from django.db import migrations
|
|||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('cotisations', '0027_auto_20171029_1156'),
|
||||
]
|
||||
dependencies = [("cotisations", "0027_auto_20171029_1156")]
|
||||
|
||||
operations = [
|
||||
migrations.AlterModelOptions(
|
||||
name='article',
|
||||
options={'permissions': (('view_article', 'Peut voir un objet article'),)},
|
||||
name="article",
|
||||
options={"permissions": (("view_article", "Peut voir un objet article"),)},
|
||||
),
|
||||
migrations.AlterModelOptions(
|
||||
name='banque',
|
||||
options={'permissions': (('view_banque', 'Peut voir un objet banque'),)},
|
||||
name="banque",
|
||||
options={"permissions": (("view_banque", "Peut voir un objet banque"),)},
|
||||
),
|
||||
migrations.AlterModelOptions(
|
||||
name='cotisation',
|
||||
options={'permissions': (('view_cotisation', 'Peut voir un objet cotisation'), ('change_all_cotisation', 'Superdroit, peut modifier toutes les cotisations'))},
|
||||
name="cotisation",
|
||||
options={
|
||||
"permissions": (
|
||||
("view_cotisation", "Peut voir un objet cotisation"),
|
||||
(
|
||||
"change_all_cotisation",
|
||||
"Superdroit, peut modifier toutes les cotisations",
|
||||
),
|
||||
)
|
||||
},
|
||||
),
|
||||
migrations.AlterModelOptions(
|
||||
name='facture',
|
||||
options={'permissions': (('change_facture_control', "Peut changer l'etat de controle"), ('change_facture_pdf', 'Peut éditer une facture pdf'), ('view_facture', 'Peut voir un objet facture'), ('change_all_facture', 'Superdroit, peut modifier toutes les factures'))},
|
||||
name="facture",
|
||||
options={
|
||||
"permissions": (
|
||||
("change_facture_control", "Peut changer l'etat de controle"),
|
||||
("change_facture_pdf", "Peut éditer une facture pdf"),
|
||||
("view_facture", "Peut voir un objet facture"),
|
||||
(
|
||||
"change_all_facture",
|
||||
"Superdroit, peut modifier toutes les factures",
|
||||
),
|
||||
)
|
||||
},
|
||||
),
|
||||
migrations.AlterModelOptions(
|
||||
name='paiement',
|
||||
options={'permissions': (('view_paiement', 'Peut voir un objet paiement'),)},
|
||||
name="paiement",
|
||||
options={
|
||||
"permissions": (("view_paiement", "Peut voir un objet paiement"),)
|
||||
},
|
||||
),
|
||||
migrations.AlterModelOptions(
|
||||
name='vente',
|
||||
options={'permissions': (('view_vente', 'Peut voir un objet vente'), ('change_all_vente', 'Superdroit, peut modifier toutes les ventes'))},
|
||||
name="vente",
|
||||
options={
|
||||
"permissions": (
|
||||
("view_vente", "Peut voir un objet vente"),
|
||||
("change_all_vente", "Superdroit, peut modifier toutes les ventes"),
|
||||
)
|
||||
},
|
||||
),
|
||||
]
|
||||
|
|
|
@ -9,143 +9,242 @@ import django.db.models.deletion
|
|||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('cotisations', '0028_auto_20171231_0007'),
|
||||
]
|
||||
dependencies = [("cotisations", "0028_auto_20171231_0007")]
|
||||
|
||||
operations = [
|
||||
migrations.AlterModelOptions(
|
||||
name='article',
|
||||
options={'permissions': (('view_article', "Can see an article's details"),), 'verbose_name': 'Article', 'verbose_name_plural': 'Articles'},
|
||||
name="article",
|
||||
options={
|
||||
"permissions": (("view_article", "Can see an article's details"),),
|
||||
"verbose_name": "Article",
|
||||
"verbose_name_plural": "Articles",
|
||||
},
|
||||
),
|
||||
migrations.AlterModelOptions(
|
||||
name='banque',
|
||||
options={'permissions': (('view_banque', "Can see a bank's details"),), 'verbose_name': 'Bank', 'verbose_name_plural': 'Banks'},
|
||||
name="banque",
|
||||
options={
|
||||
"permissions": (("view_banque", "Can see a bank's details"),),
|
||||
"verbose_name": "Bank",
|
||||
"verbose_name_plural": "Banks",
|
||||
},
|
||||
),
|
||||
migrations.AlterModelOptions(
|
||||
name='cotisation',
|
||||
options={'permissions': (('view_cotisation', "Can see a cotisation's details"), ('change_all_cotisation', 'Can edit the previous cotisations'))},
|
||||
name="cotisation",
|
||||
options={
|
||||
"permissions": (
|
||||
("view_cotisation", "Can see a cotisation's details"),
|
||||
("change_all_cotisation", "Can edit the previous cotisations"),
|
||||
)
|
||||
},
|
||||
),
|
||||
migrations.AlterModelOptions(
|
||||
name='facture',
|
||||
options={'permissions': (('change_facture_control', 'Can change the "controlled" state'), ('change_facture_pdf', 'Can create a custom PDF invoice'), ('view_facture', "Can see an invoice's details"), ('change_all_facture', 'Can edit all the previous invoices')), 'verbose_name': 'Invoice', 'verbose_name_plural': 'Invoices'},
|
||||
name="facture",
|
||||
options={
|
||||
"permissions": (
|
||||
("change_facture_control", 'Can change the "controlled" state'),
|
||||
("change_facture_pdf", "Can create a custom PDF invoice"),
|
||||
("view_facture", "Can see an invoice's details"),
|
||||
("change_all_facture", "Can edit all the previous invoices"),
|
||||
),
|
||||
"verbose_name": "Invoice",
|
||||
"verbose_name_plural": "Invoices",
|
||||
},
|
||||
),
|
||||
migrations.AlterModelOptions(
|
||||
name='paiement',
|
||||
options={'permissions': (('view_paiement', "Can see a payement's details"),), 'verbose_name': 'Payment method', 'verbose_name_plural': 'Payment methods'},
|
||||
name="paiement",
|
||||
options={
|
||||
"permissions": (("view_paiement", "Can see a payement's details"),),
|
||||
"verbose_name": "Payment method",
|
||||
"verbose_name_plural": "Payment methods",
|
||||
},
|
||||
),
|
||||
migrations.AlterModelOptions(
|
||||
name='vente',
|
||||
options={'permissions': (('view_vente', "Can see a purchase's details"), ('change_all_vente', 'Can edit all the previous purchases')), 'verbose_name': 'Purchase', 'verbose_name_plural': 'Purchases'},
|
||||
name="vente",
|
||||
options={
|
||||
"permissions": (
|
||||
("view_vente", "Can see a purchase's details"),
|
||||
("change_all_vente", "Can edit all the previous purchases"),
|
||||
),
|
||||
"verbose_name": "Purchase",
|
||||
"verbose_name_plural": "Purchases",
|
||||
},
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='article',
|
||||
name='duration',
|
||||
field=models.PositiveIntegerField(blank=True, null=True, validators=[django.core.validators.MinValueValidator(0)], verbose_name='Duration (in whole month)'),
|
||||
model_name="article",
|
||||
name="duration",
|
||||
field=models.PositiveIntegerField(
|
||||
blank=True,
|
||||
null=True,
|
||||
validators=[django.core.validators.MinValueValidator(0)],
|
||||
verbose_name="Duration (in whole month)",
|
||||
),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='article',
|
||||
name='name',
|
||||
field=models.CharField(max_length=255, verbose_name='Designation'),
|
||||
model_name="article",
|
||||
name="name",
|
||||
field=models.CharField(max_length=255, verbose_name="Designation"),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='article',
|
||||
name='prix',
|
||||
field=models.DecimalField(decimal_places=2, max_digits=5, verbose_name='Unitary price'),
|
||||
model_name="article",
|
||||
name="prix",
|
||||
field=models.DecimalField(
|
||||
decimal_places=2, max_digits=5, verbose_name="Unitary price"
|
||||
),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='article',
|
||||
name='type_cotisation',
|
||||
field=models.CharField(blank=True, choices=[('Connexion', 'Connexion'), ('Adhesion', 'Membership'), ('All', 'Both of them')], default=None, max_length=255, null=True, verbose_name='Type of cotisation'),
|
||||
model_name="article",
|
||||
name="type_cotisation",
|
||||
field=models.CharField(
|
||||
blank=True,
|
||||
choices=[
|
||||
("Connexion", "Connexion"),
|
||||
("Adhesion", "Membership"),
|
||||
("All", "Both of them"),
|
||||
],
|
||||
default=None,
|
||||
max_length=255,
|
||||
null=True,
|
||||
verbose_name="Type of cotisation",
|
||||
),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='article',
|
||||
name='type_user',
|
||||
field=models.CharField(choices=[('Adherent', 'Member'), ('Club', 'Club'), ('All', 'Both of them')], default='All', max_length=255, verbose_name='Type of users concerned'),
|
||||
model_name="article",
|
||||
name="type_user",
|
||||
field=models.CharField(
|
||||
choices=[
|
||||
("Adherent", "Member"),
|
||||
("Club", "Club"),
|
||||
("All", "Both of them"),
|
||||
],
|
||||
default="All",
|
||||
max_length=255,
|
||||
verbose_name="Type of users concerned",
|
||||
),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='banque',
|
||||
name='name',
|
||||
field=models.CharField(max_length=255, verbose_name='Name'),
|
||||
model_name="banque",
|
||||
name="name",
|
||||
field=models.CharField(max_length=255, verbose_name="Name"),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='cotisation',
|
||||
name='date_end',
|
||||
field=models.DateTimeField(verbose_name='Ending date'),
|
||||
model_name="cotisation",
|
||||
name="date_end",
|
||||
field=models.DateTimeField(verbose_name="Ending date"),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='cotisation',
|
||||
name='date_start',
|
||||
field=models.DateTimeField(verbose_name='Starting date'),
|
||||
model_name="cotisation",
|
||||
name="date_start",
|
||||
field=models.DateTimeField(verbose_name="Starting date"),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='cotisation',
|
||||
name='type_cotisation',
|
||||
field=models.CharField(choices=[('Connexion', 'Connexion'), ('Adhesion', 'Membership'), ('All', 'Both of them')], default='All', max_length=255, verbose_name='Type of cotisation'),
|
||||
model_name="cotisation",
|
||||
name="type_cotisation",
|
||||
field=models.CharField(
|
||||
choices=[
|
||||
("Connexion", "Connexion"),
|
||||
("Adhesion", "Membership"),
|
||||
("All", "Both of them"),
|
||||
],
|
||||
default="All",
|
||||
max_length=255,
|
||||
verbose_name="Type of cotisation",
|
||||
),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='cotisation',
|
||||
name='vente',
|
||||
field=models.OneToOneField(null=True, on_delete=django.db.models.deletion.CASCADE, to='cotisations.Vente', verbose_name='Purchase'),
|
||||
model_name="cotisation",
|
||||
name="vente",
|
||||
field=models.OneToOneField(
|
||||
null=True,
|
||||
on_delete=django.db.models.deletion.CASCADE,
|
||||
to="cotisations.Vente",
|
||||
verbose_name="Purchase",
|
||||
),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='facture',
|
||||
name='cheque',
|
||||
field=models.CharField(blank=True, max_length=255, verbose_name='Cheque number'),
|
||||
model_name="facture",
|
||||
name="cheque",
|
||||
field=models.CharField(
|
||||
blank=True, max_length=255, verbose_name="Cheque number"
|
||||
),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='facture',
|
||||
name='control',
|
||||
field=models.BooleanField(default=False, verbose_name='Controlled'),
|
||||
model_name="facture",
|
||||
name="control",
|
||||
field=models.BooleanField(default=False, verbose_name="Controlled"),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='facture',
|
||||
name='date',
|
||||
field=models.DateTimeField(auto_now_add=True, verbose_name='Date'),
|
||||
model_name="facture",
|
||||
name="date",
|
||||
field=models.DateTimeField(auto_now_add=True, verbose_name="Date"),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='facture',
|
||||
name='valid',
|
||||
field=models.BooleanField(default=True, verbose_name='Validated'),
|
||||
model_name="facture",
|
||||
name="valid",
|
||||
field=models.BooleanField(default=True, verbose_name="Validated"),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='paiement',
|
||||
name='moyen',
|
||||
field=models.CharField(max_length=255, verbose_name='Method'),
|
||||
model_name="paiement",
|
||||
name="moyen",
|
||||
field=models.CharField(max_length=255, verbose_name="Method"),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='paiement',
|
||||
name='type_paiement',
|
||||
field=models.IntegerField(choices=[(0, 'Standard'), (1, 'Cheque')], default=0, verbose_name='Payment type'),
|
||||
model_name="paiement",
|
||||
name="type_paiement",
|
||||
field=models.IntegerField(
|
||||
choices=[(0, "Standard"), (1, "Cheque")],
|
||||
default=0,
|
||||
verbose_name="Payment type",
|
||||
),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='vente',
|
||||
name='duration',
|
||||
field=models.PositiveIntegerField(blank=True, null=True, verbose_name='Duration (in whole month)'),
|
||||
model_name="vente",
|
||||
name="duration",
|
||||
field=models.PositiveIntegerField(
|
||||
blank=True, null=True, verbose_name="Duration (in whole month)"
|
||||
),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='vente',
|
||||
name='facture',
|
||||
field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='cotisations.Facture', verbose_name='Invoice'),
|
||||
model_name="vente",
|
||||
name="facture",
|
||||
field=models.ForeignKey(
|
||||
on_delete=django.db.models.deletion.CASCADE,
|
||||
to="cotisations.Facture",
|
||||
verbose_name="Invoice",
|
||||
),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='vente',
|
||||
name='name',
|
||||
field=models.CharField(max_length=255, verbose_name='Article'),
|
||||
model_name="vente",
|
||||
name="name",
|
||||
field=models.CharField(max_length=255, verbose_name="Article"),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='vente',
|
||||
name='number',
|
||||
field=models.IntegerField(validators=[django.core.validators.MinValueValidator(1)], verbose_name='Amount'),
|
||||
model_name="vente",
|
||||
name="number",
|
||||
field=models.IntegerField(
|
||||
validators=[django.core.validators.MinValueValidator(1)],
|
||||
verbose_name="Amount",
|
||||
),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='vente',
|
||||
name='prix',
|
||||
field=models.DecimalField(decimal_places=2, max_digits=5, verbose_name='Price'),
|
||||
model_name="vente",
|
||||
name="prix",
|
||||
field=models.DecimalField(
|
||||
decimal_places=2, max_digits=5, verbose_name="Price"
|
||||
),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='vente',
|
||||
name='type_cotisation',
|
||||
field=models.CharField(blank=True, choices=[('Connexion', 'Connexion'), ('Adhesion', 'Membership'), ('All', 'Both of them')], max_length=255, null=True, verbose_name='Type of cotisation'),
|
||||
model_name="vente",
|
||||
name="type_cotisation",
|
||||
field=models.CharField(
|
||||
blank=True,
|
||||
choices=[
|
||||
("Connexion", "Connexion"),
|
||||
("Adhesion", "Membership"),
|
||||
("All", "Both of them"),
|
||||
],
|
||||
max_length=255,
|
||||
null=True,
|
||||
verbose_name="Type of cotisation",
|
||||
),
|
||||
),
|
||||
]
|
||||
|
|
|
@ -9,8 +9,8 @@ import django.db.models.deletion
|
|||
|
||||
|
||||
def add_cheque(apps, schema_editor):
|
||||
ChequePayment = apps.get_model('cotisations', 'ChequePayment')
|
||||
Payment = apps.get_model('cotisations', 'Paiement')
|
||||
ChequePayment = apps.get_model("cotisations", "ChequePayment")
|
||||
Payment = apps.get_model("cotisations", "Paiement")
|
||||
for p in Payment.objects.filter(type_paiement=1):
|
||||
cheque = ChequePayment()
|
||||
cheque.payment = p
|
||||
|
@ -18,14 +18,12 @@ def add_cheque(apps, schema_editor):
|
|||
|
||||
|
||||
def add_comnpay(apps, schema_editor):
|
||||
ComnpayPayment = apps.get_model('cotisations', 'ComnpayPayment')
|
||||
Payment = apps.get_model('cotisations', 'Paiement')
|
||||
AssoOption = apps.get_model('preferences', 'AssoOption')
|
||||
ComnpayPayment = apps.get_model("cotisations", "ComnpayPayment")
|
||||
Payment = apps.get_model("cotisations", "Paiement")
|
||||
AssoOption = apps.get_model("preferences", "AssoOption")
|
||||
options, _created = AssoOption.objects.get_or_create()
|
||||
try:
|
||||
payment = Payment.objects.get(
|
||||
moyen='Rechargement en ligne'
|
||||
)
|
||||
payment = Payment.objects.get(moyen="Rechargement en ligne")
|
||||
except Payment.DoesNotExist:
|
||||
return
|
||||
comnpay = ComnpayPayment()
|
||||
|
@ -38,11 +36,11 @@ def add_comnpay(apps, schema_editor):
|
|||
|
||||
|
||||
def add_solde(apps, schema_editor):
|
||||
OptionalUser = apps.get_model('preferences', 'OptionalUser')
|
||||
OptionalUser = apps.get_model("preferences", "OptionalUser")
|
||||
options, _created = OptionalUser.objects.get_or_create()
|
||||
|
||||
Payment = apps.get_model('cotisations', 'Paiement')
|
||||
BalancePayment = apps.get_model('cotisations', 'BalancePayment')
|
||||
Payment = apps.get_model("cotisations", "Paiement")
|
||||
BalancePayment = apps.get_model("cotisations", "BalancePayment")
|
||||
|
||||
try:
|
||||
solde = Payment.objects.get(moyen="solde")
|
||||
|
@ -60,73 +58,191 @@ def add_solde(apps, schema_editor):
|
|||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('preferences', '0044_remove_payment_pass'),
|
||||
('cotisations', '0029_auto_20180414_2056'),
|
||||
("preferences", "0044_remove_payment_pass"),
|
||||
("cotisations", "0029_auto_20180414_2056"),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AlterModelOptions(
|
||||
name='paiement',
|
||||
options={'permissions': (('view_paiement', "Can see a payement's details"), ('use_every_payment', 'Can use every payement')), 'verbose_name': 'Payment method', 'verbose_name_plural': 'Payment methods'},
|
||||
name="paiement",
|
||||
options={
|
||||
"permissions": (
|
||||
("view_paiement", "Can see a payement's details"),
|
||||
("use_every_payment", "Can use every payement"),
|
||||
),
|
||||
"verbose_name": "Payment method",
|
||||
"verbose_name_plural": "Payment methods",
|
||||
},
|
||||
),
|
||||
migrations.AlterModelOptions(
|
||||
name='article',
|
||||
options={'permissions': (('view_article', "Can see an article's details"), ('buy_every_article', 'Can buy every_article')), 'verbose_name': 'Article', 'verbose_name_plural': 'Articles'},
|
||||
name="article",
|
||||
options={
|
||||
"permissions": (
|
||||
("view_article", "Can see an article's details"),
|
||||
("buy_every_article", "Can buy every_article"),
|
||||
),
|
||||
"verbose_name": "Article",
|
||||
"verbose_name_plural": "Articles",
|
||||
},
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='paiement',
|
||||
name='available_for_everyone',
|
||||
field=models.BooleanField(default=False, verbose_name='Is available for every user'),
|
||||
model_name="paiement",
|
||||
name="available_for_everyone",
|
||||
field=models.BooleanField(
|
||||
default=False, verbose_name="Is available for every user"
|
||||
),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='paiement',
|
||||
name='is_balance',
|
||||
field=models.BooleanField(default=False, editable=False, help_text='There should be only one balance payment method.', verbose_name='Is user balance', validators=[cotisations.models.check_no_balance]),
|
||||
model_name="paiement",
|
||||
name="is_balance",
|
||||
field=models.BooleanField(
|
||||
default=False,
|
||||
editable=False,
|
||||
help_text="There should be only one balance payment method.",
|
||||
verbose_name="Is user balance",
|
||||
validators=[cotisations.models.check_no_balance],
|
||||
),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='article',
|
||||
name='available_for_everyone',
|
||||
field=models.BooleanField(default=False, verbose_name='Is available for every user'),
|
||||
model_name="article",
|
||||
name="available_for_everyone",
|
||||
field=models.BooleanField(
|
||||
default=False, verbose_name="Is available for every user"
|
||||
),
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name='ChequePayment',
|
||||
name="ChequePayment",
|
||||
fields=[
|
||||
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||
('payment', models.OneToOneField(editable=False, on_delete=django.db.models.deletion.CASCADE, related_name='payment_method', to='cotisations.Paiement')),
|
||||
(
|
||||
"id",
|
||||
models.AutoField(
|
||||
auto_created=True,
|
||||
primary_key=True,
|
||||
serialize=False,
|
||||
verbose_name="ID",
|
||||
),
|
||||
),
|
||||
(
|
||||
"payment",
|
||||
models.OneToOneField(
|
||||
editable=False,
|
||||
on_delete=django.db.models.deletion.CASCADE,
|
||||
related_name="payment_method",
|
||||
to="cotisations.Paiement",
|
||||
),
|
||||
),
|
||||
],
|
||||
bases=(cotisations.payment_methods.mixins.PaymentMethodMixin, models.Model),
|
||||
options={'verbose_name': 'Cheque'},
|
||||
options={"verbose_name": "Cheque"},
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name='ComnpayPayment',
|
||||
name="ComnpayPayment",
|
||||
fields=[
|
||||
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||
('payment_credential', models.CharField(blank=True, default='', max_length=255, verbose_name='ComNpay VAD Number')),
|
||||
('payment_pass', re2o.aes_field.AESEncryptedField(blank=True, max_length=255, null=True, verbose_name='ComNpay Secret Key')),
|
||||
('payment', models.OneToOneField(editable=False, on_delete=django.db.models.deletion.CASCADE, related_name='payment_method', to='cotisations.Paiement')),
|
||||
('minimum_payment', models.DecimalField(decimal_places=2, default=1, help_text='The minimal amount of money you have to use when paying with ComNpay', max_digits=5, verbose_name='Minimum payment')),
|
||||
(
|
||||
"id",
|
||||
models.AutoField(
|
||||
auto_created=True,
|
||||
primary_key=True,
|
||||
serialize=False,
|
||||
verbose_name="ID",
|
||||
),
|
||||
),
|
||||
(
|
||||
"payment_credential",
|
||||
models.CharField(
|
||||
blank=True,
|
||||
default="",
|
||||
max_length=255,
|
||||
verbose_name="ComNpay VAD Number",
|
||||
),
|
||||
),
|
||||
(
|
||||
"payment_pass",
|
||||
re2o.aes_field.AESEncryptedField(
|
||||
blank=True,
|
||||
max_length=255,
|
||||
null=True,
|
||||
verbose_name="ComNpay Secret Key",
|
||||
),
|
||||
),
|
||||
(
|
||||
"payment",
|
||||
models.OneToOneField(
|
||||
editable=False,
|
||||
on_delete=django.db.models.deletion.CASCADE,
|
||||
related_name="payment_method",
|
||||
to="cotisations.Paiement",
|
||||
),
|
||||
),
|
||||
(
|
||||
"minimum_payment",
|
||||
models.DecimalField(
|
||||
decimal_places=2,
|
||||
default=1,
|
||||
help_text="The minimal amount of money you have to use when paying with ComNpay",
|
||||
max_digits=5,
|
||||
verbose_name="Minimum payment",
|
||||
),
|
||||
),
|
||||
],
|
||||
bases=(cotisations.payment_methods.mixins.PaymentMethodMixin, models.Model),
|
||||
options={'verbose_name': 'ComNpay'},
|
||||
options={"verbose_name": "ComNpay"},
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name='BalancePayment',
|
||||
name="BalancePayment",
|
||||
fields=[
|
||||
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||
('minimum_balance', models.DecimalField(decimal_places=2, default=0, help_text='The minimal amount of money allowed for the balance at the end of a payment. You can specify negative amount.', max_digits=5, verbose_name='Minimum balance')),
|
||||
('payment', models.OneToOneField(editable=False, on_delete=django.db.models.deletion.CASCADE, related_name='payment_method', to='cotisations.Paiement')),
|
||||
('maximum_balance', models.DecimalField(decimal_places=2, default=50, help_text='The maximal amount of money allowed for the balance.', max_digits=5, verbose_name='Maximum balance', null=True, blank=True)),
|
||||
('credit_balance_allowed', models.BooleanField(default=False, verbose_name='Allow user to credit their balance')),
|
||||
(
|
||||
"id",
|
||||
models.AutoField(
|
||||
auto_created=True,
|
||||
primary_key=True,
|
||||
serialize=False,
|
||||
verbose_name="ID",
|
||||
),
|
||||
),
|
||||
(
|
||||
"minimum_balance",
|
||||
models.DecimalField(
|
||||
decimal_places=2,
|
||||
default=0,
|
||||
help_text="The minimal amount of money allowed for the balance at the end of a payment. You can specify negative amount.",
|
||||
max_digits=5,
|
||||
verbose_name="Minimum balance",
|
||||
),
|
||||
),
|
||||
(
|
||||
"payment",
|
||||
models.OneToOneField(
|
||||
editable=False,
|
||||
on_delete=django.db.models.deletion.CASCADE,
|
||||
related_name="payment_method",
|
||||
to="cotisations.Paiement",
|
||||
),
|
||||
),
|
||||
(
|
||||
"maximum_balance",
|
||||
models.DecimalField(
|
||||
decimal_places=2,
|
||||
default=50,
|
||||
help_text="The maximal amount of money allowed for the balance.",
|
||||
max_digits=5,
|
||||
verbose_name="Maximum balance",
|
||||
null=True,
|
||||
blank=True,
|
||||
),
|
||||
),
|
||||
(
|
||||
"credit_balance_allowed",
|
||||
models.BooleanField(
|
||||
default=False, verbose_name="Allow user to credit their balance"
|
||||
),
|
||||
),
|
||||
],
|
||||
bases=(cotisations.payment_methods.mixins.PaymentMethodMixin, models.Model),
|
||||
options={'verbose_name': 'User Balance'},
|
||||
options={"verbose_name": "User Balance"},
|
||||
),
|
||||
migrations.RunPython(add_comnpay),
|
||||
migrations.RunPython(add_cheque),
|
||||
migrations.RunPython(add_solde),
|
||||
migrations.RemoveField(
|
||||
model_name='paiement',
|
||||
name='type_paiement',
|
||||
),
|
||||
|
||||
migrations.RemoveField(model_name="paiement", name="type_paiement"),
|
||||
]
|
||||
|
|
|
@ -7,14 +7,15 @@ from django.db import migrations, models
|
|||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('cotisations', '0030_custom_payment'),
|
||||
]
|
||||
dependencies = [("cotisations", "0030_custom_payment")]
|
||||
|
||||
operations = [
|
||||
migrations.AddField(
|
||||
model_name='comnpaypayment',
|
||||
name='production',
|
||||
field=models.BooleanField(default=True, verbose_name='Production mode enabled (production url, instead of homologation)'),
|
||||
),
|
||||
model_name="comnpaypayment",
|
||||
name="production",
|
||||
field=models.BooleanField(
|
||||
default=True,
|
||||
verbose_name="Production mode enabled (production url, instead of homologation)",
|
||||
),
|
||||
)
|
||||
]
|
||||
|
|
|
@ -10,8 +10,8 @@ import re2o.mixins
|
|||
|
||||
|
||||
def reattribute_ids(apps, schema_editor):
|
||||
Facture = apps.get_model('cotisations', 'Facture')
|
||||
BaseInvoice = apps.get_model('cotisations', 'BaseInvoice')
|
||||
Facture = apps.get_model("cotisations", "Facture")
|
||||
BaseInvoice = apps.get_model("cotisations", "BaseInvoice")
|
||||
|
||||
for f in Facture.objects.all():
|
||||
base = BaseInvoice.objects.create(id=f.pk)
|
||||
|
@ -22,21 +22,23 @@ def reattribute_ids(apps, schema_editor):
|
|||
|
||||
|
||||
def update_rights(apps, schema_editor):
|
||||
Permission = apps.get_model('auth', 'Permission')
|
||||
Permission = apps.get_model("auth", "Permission")
|
||||
|
||||
# creates needed permissions
|
||||
app = apps.get_app_config('cotisations')
|
||||
app = apps.get_app_config("cotisations")
|
||||
app.models_module = True
|
||||
create_permissions(app)
|
||||
app.models_module = False
|
||||
|
||||
ContentType = apps.get_model("contenttypes", "ContentType")
|
||||
content_type = ContentType.objects.get_for_model(Permission)
|
||||
former, created = Permission.objects.get_or_create(codename='change_facture_pdf', content_type=content_type)
|
||||
new_1 = Permission.objects.get(codename='add_custominvoice')
|
||||
new_2 = Permission.objects.get(codename='change_custominvoice')
|
||||
new_3 = Permission.objects.get(codename='view_custominvoice')
|
||||
new_4 = Permission.objects.get(codename='delete_custominvoice')
|
||||
former, created = Permission.objects.get_or_create(
|
||||
codename="change_facture_pdf", content_type=content_type
|
||||
)
|
||||
new_1 = Permission.objects.get(codename="add_custominvoice")
|
||||
new_2 = Permission.objects.get(codename="change_custominvoice")
|
||||
new_3 = Permission.objects.get(codename="view_custominvoice")
|
||||
new_4 = Permission.objects.get(codename="delete_custominvoice")
|
||||
for group in former.group_set.all():
|
||||
group.permissions.remove(former)
|
||||
group.permissions.add(new_1)
|
||||
|
@ -48,59 +50,105 @@ def update_rights(apps, schema_editor):
|
|||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('cotisations', '0031_comnpaypayment_production'),
|
||||
]
|
||||
dependencies = [("cotisations", "0031_comnpaypayment_production")]
|
||||
|
||||
operations = [
|
||||
migrations.CreateModel(
|
||||
name='BaseInvoice',
|
||||
name="BaseInvoice",
|
||||
fields=[
|
||||
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||
('date', models.DateTimeField(auto_now_add=True, verbose_name='Date')),
|
||||
(
|
||||
"id",
|
||||
models.AutoField(
|
||||
auto_created=True,
|
||||
primary_key=True,
|
||||
serialize=False,
|
||||
verbose_name="ID",
|
||||
),
|
||||
),
|
||||
("date", models.DateTimeField(auto_now_add=True, verbose_name="Date")),
|
||||
],
|
||||
bases=(re2o.mixins.RevMixin, re2o.mixins.AclMixin, re2o.field_permissions.FieldPermissionModelMixin, models.Model),
|
||||
bases=(
|
||||
re2o.mixins.RevMixin,
|
||||
re2o.mixins.AclMixin,
|
||||
re2o.field_permissions.FieldPermissionModelMixin,
|
||||
models.Model,
|
||||
),
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name='CustomInvoice',
|
||||
name="CustomInvoice",
|
||||
fields=[
|
||||
('baseinvoice_ptr', models.OneToOneField(auto_created=True, on_delete=django.db.models.deletion.CASCADE, parent_link=True, primary_key=True, serialize=False, to='cotisations.BaseInvoice')),
|
||||
('recipient', models.CharField(max_length=255, verbose_name='Recipient')),
|
||||
('payment', models.CharField(max_length=255, verbose_name='Payment type')),
|
||||
('address', models.CharField(max_length=255, verbose_name='Address')),
|
||||
('paid', models.BooleanField(verbose_name='Paid')),
|
||||
(
|
||||
"baseinvoice_ptr",
|
||||
models.OneToOneField(
|
||||
auto_created=True,
|
||||
on_delete=django.db.models.deletion.CASCADE,
|
||||
parent_link=True,
|
||||
primary_key=True,
|
||||
serialize=False,
|
||||
to="cotisations.BaseInvoice",
|
||||
),
|
||||
),
|
||||
(
|
||||
"recipient",
|
||||
models.CharField(max_length=255, verbose_name="Recipient"),
|
||||
),
|
||||
(
|
||||
"payment",
|
||||
models.CharField(max_length=255, verbose_name="Payment type"),
|
||||
),
|
||||
("address", models.CharField(max_length=255, verbose_name="Address")),
|
||||
("paid", models.BooleanField(verbose_name="Paid")),
|
||||
],
|
||||
bases=('cotisations.baseinvoice',),
|
||||
options={'permissions': (('view_custominvoice', 'Can view a custom invoice'),)},
|
||||
bases=("cotisations.baseinvoice",),
|
||||
options={
|
||||
"permissions": (("view_custominvoice", "Can view a custom invoice"),)
|
||||
},
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='facture',
|
||||
name='baseinvoice_ptr',
|
||||
field=models.OneToOneField(on_delete=django.db.models.deletion.CASCADE, to='cotisations.BaseInvoice', null=True),
|
||||
model_name="facture",
|
||||
name="baseinvoice_ptr",
|
||||
field=models.OneToOneField(
|
||||
on_delete=django.db.models.deletion.CASCADE,
|
||||
to="cotisations.BaseInvoice",
|
||||
null=True,
|
||||
),
|
||||
preserve_default=False,
|
||||
),
|
||||
migrations.RunPython(reattribute_ids),
|
||||
migrations.AlterField(
|
||||
model_name='vente',
|
||||
name='facture',
|
||||
field=models.ForeignKey(on_delete=models.CASCADE, verbose_name='Invoice', to='cotisations.BaseInvoice')
|
||||
),
|
||||
migrations.RemoveField(
|
||||
model_name='facture',
|
||||
name='id',
|
||||
),
|
||||
migrations.RemoveField(
|
||||
model_name='facture',
|
||||
name='date',
|
||||
model_name="vente",
|
||||
name="facture",
|
||||
field=models.ForeignKey(
|
||||
on_delete=models.CASCADE,
|
||||
verbose_name="Invoice",
|
||||
to="cotisations.BaseInvoice",
|
||||
),
|
||||
),
|
||||
migrations.RemoveField(model_name="facture", name="id"),
|
||||
migrations.RemoveField(model_name="facture", name="date"),
|
||||
migrations.AlterField(
|
||||
model_name='facture',
|
||||
name='baseinvoice_ptr',
|
||||
field=models.OneToOneField(auto_created=True, on_delete=django.db.models.deletion.CASCADE, parent_link=True, primary_key=True, serialize=False, to='cotisations.BaseInvoice'),
|
||||
model_name="facture",
|
||||
name="baseinvoice_ptr",
|
||||
field=models.OneToOneField(
|
||||
auto_created=True,
|
||||
on_delete=django.db.models.deletion.CASCADE,
|
||||
parent_link=True,
|
||||
primary_key=True,
|
||||
serialize=False,
|
||||
to="cotisations.BaseInvoice",
|
||||
),
|
||||
),
|
||||
migrations.RunPython(update_rights),
|
||||
migrations.AlterModelOptions(
|
||||
name='facture',
|
||||
options={'permissions': (('change_facture_control', 'Can change the "controlled" state'), ('view_facture', "Can see an invoice's details"), ('change_all_facture', 'Can edit all the previous invoices')), 'verbose_name': 'Invoice', 'verbose_name_plural': 'Invoices'},
|
||||
name="facture",
|
||||
options={
|
||||
"permissions": (
|
||||
("change_facture_control", 'Can change the "controlled" state'),
|
||||
("view_facture", "Can see an invoice's details"),
|
||||
("change_all_facture", "Can edit all the previous invoices"),
|
||||
),
|
||||
"verbose_name": "Invoice",
|
||||
"verbose_name_plural": "Invoices",
|
||||
},
|
||||
),
|
||||
]
|
||||
|
|
|
@ -11,171 +11,294 @@ import re2o.aes_field
|
|||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('cotisations', '0032_custom_invoice'),
|
||||
]
|
||||
dependencies = [("cotisations", "0032_custom_invoice")]
|
||||
|
||||
operations = [
|
||||
migrations.AlterModelOptions(
|
||||
name='article',
|
||||
options={'permissions': (('view_article', 'Can view an article object'), ('buy_every_article', 'Can buy every article')), 'verbose_name': 'article', 'verbose_name_plural': 'articles'},
|
||||
name="article",
|
||||
options={
|
||||
"permissions": (
|
||||
("view_article", "Can view an article object"),
|
||||
("buy_every_article", "Can buy every article"),
|
||||
),
|
||||
"verbose_name": "article",
|
||||
"verbose_name_plural": "articles",
|
||||
},
|
||||
),
|
||||
migrations.AlterModelOptions(
|
||||
name='balancepayment',
|
||||
options={'verbose_name': 'user balance'},
|
||||
name="balancepayment", options={"verbose_name": "user balance"}
|
||||
),
|
||||
migrations.AlterModelOptions(
|
||||
name='banque',
|
||||
options={'permissions': (('view_banque', 'Can view a bank object'),), 'verbose_name': 'bank', 'verbose_name_plural': 'banks'},
|
||||
name="banque",
|
||||
options={
|
||||
"permissions": (("view_banque", "Can view a bank object"),),
|
||||
"verbose_name": "bank",
|
||||
"verbose_name_plural": "banks",
|
||||
},
|
||||
),
|
||||
migrations.AlterModelOptions(
|
||||
name='cotisation',
|
||||
options={'permissions': (('view_cotisation', 'Can view a subscription object'), ('change_all_cotisation', 'Can edit the previous subscriptions')), 'verbose_name': 'subscription', 'verbose_name_plural': 'subscriptions'},
|
||||
name="cotisation",
|
||||
options={
|
||||
"permissions": (
|
||||
("view_cotisation", "Can view a subscription object"),
|
||||
("change_all_cotisation", "Can edit the previous subscriptions"),
|
||||
),
|
||||
"verbose_name": "subscription",
|
||||
"verbose_name_plural": "subscriptions",
|
||||
},
|
||||
),
|
||||
migrations.AlterModelOptions(
|
||||
name='custominvoice',
|
||||
options={'permissions': (('view_custominvoice', 'Can view a custom invoice object'),)},
|
||||
name="custominvoice",
|
||||
options={
|
||||
"permissions": (
|
||||
("view_custominvoice", "Can view a custom invoice object"),
|
||||
)
|
||||
},
|
||||
),
|
||||
migrations.AlterModelOptions(
|
||||
name='facture',
|
||||
options={'permissions': (('change_facture_control', 'Can edit the "controlled" state'), ('view_facture', 'Can view an invoice object'), ('change_all_facture', 'Can edit all the previous invoices')), 'verbose_name': 'invoice', 'verbose_name_plural': 'invoices'},
|
||||
name="facture",
|
||||
options={
|
||||
"permissions": (
|
||||
("change_facture_control", 'Can edit the "controlled" state'),
|
||||
("view_facture", "Can view an invoice object"),
|
||||
("change_all_facture", "Can edit all the previous invoices"),
|
||||
),
|
||||
"verbose_name": "invoice",
|
||||
"verbose_name_plural": "invoices",
|
||||
},
|
||||
),
|
||||
migrations.AlterModelOptions(
|
||||
name='paiement',
|
||||
options={'permissions': (('view_paiement', 'Can view a payment method object'), ('use_every_payment', 'Can use every payment method')), 'verbose_name': 'payment method', 'verbose_name_plural': 'payment methods'},
|
||||
name="paiement",
|
||||
options={
|
||||
"permissions": (
|
||||
("view_paiement", "Can view a payment method object"),
|
||||
("use_every_payment", "Can use every payment method"),
|
||||
),
|
||||
"verbose_name": "payment method",
|
||||
"verbose_name_plural": "payment methods",
|
||||
},
|
||||
),
|
||||
migrations.AlterModelOptions(
|
||||
name='vente',
|
||||
options={'permissions': (('view_vente', 'Can view a purchase object'), ('change_all_vente', 'Can edit all the previous purchases')), 'verbose_name': 'purchase', 'verbose_name_plural': 'purchases'},
|
||||
name="vente",
|
||||
options={
|
||||
"permissions": (
|
||||
("view_vente", "Can view a purchase object"),
|
||||
("change_all_vente", "Can edit all the previous purchases"),
|
||||
),
|
||||
"verbose_name": "purchase",
|
||||
"verbose_name_plural": "purchases",
|
||||
},
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='article',
|
||||
name='available_for_everyone',
|
||||
field=models.BooleanField(default=False, verbose_name='is available for every user'),
|
||||
model_name="article",
|
||||
name="available_for_everyone",
|
||||
field=models.BooleanField(
|
||||
default=False, verbose_name="is available for every user"
|
||||
),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='article',
|
||||
name='duration',
|
||||
field=models.PositiveIntegerField(blank=True, null=True, validators=[django.core.validators.MinValueValidator(0)], verbose_name='duration (in months)'),
|
||||
model_name="article",
|
||||
name="duration",
|
||||
field=models.PositiveIntegerField(
|
||||
blank=True,
|
||||
null=True,
|
||||
validators=[django.core.validators.MinValueValidator(0)],
|
||||
verbose_name="duration (in months)",
|
||||
),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='article',
|
||||
name='name',
|
||||
field=models.CharField(max_length=255, verbose_name='designation'),
|
||||
model_name="article",
|
||||
name="name",
|
||||
field=models.CharField(max_length=255, verbose_name="designation"),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='article',
|
||||
name='prix',
|
||||
field=models.DecimalField(decimal_places=2, max_digits=5, verbose_name='unit price'),
|
||||
model_name="article",
|
||||
name="prix",
|
||||
field=models.DecimalField(
|
||||
decimal_places=2, max_digits=5, verbose_name="unit price"
|
||||
),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='article',
|
||||
name='type_cotisation',
|
||||
field=models.CharField(blank=True, choices=[('Connexion', 'Connection'), ('Adhesion', 'Membership'), ('All', 'Both of them')], default=None, max_length=255, null=True, verbose_name='subscription type'),
|
||||
model_name="article",
|
||||
name="type_cotisation",
|
||||
field=models.CharField(
|
||||
blank=True,
|
||||
choices=[
|
||||
("Connexion", "Connection"),
|
||||
("Adhesion", "Membership"),
|
||||
("All", "Both of them"),
|
||||
],
|
||||
default=None,
|
||||
max_length=255,
|
||||
null=True,
|
||||
verbose_name="subscription type",
|
||||
),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='article',
|
||||
name='type_user',
|
||||
field=models.CharField(choices=[('Adherent', 'Member'), ('Club', 'Club'), ('All', 'Both of them')], default='All', max_length=255, verbose_name='type of users concerned'),
|
||||
model_name="article",
|
||||
name="type_user",
|
||||
field=models.CharField(
|
||||
choices=[
|
||||
("Adherent", "Member"),
|
||||
("Club", "Club"),
|
||||
("All", "Both of them"),
|
||||
],
|
||||
default="All",
|
||||
max_length=255,
|
||||
verbose_name="type of users concerned",
|
||||
),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='banque',
|
||||
name='name',
|
||||
field=models.CharField(max_length=255),
|
||||
model_name="banque", name="name", field=models.CharField(max_length=255)
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='comnpaypayment',
|
||||
name='payment_credential',
|
||||
field=models.CharField(blank=True, default='', max_length=255, verbose_name='ComNpay VAT Number'),
|
||||
model_name="comnpaypayment",
|
||||
name="payment_credential",
|
||||
field=models.CharField(
|
||||
blank=True,
|
||||
default="",
|
||||
max_length=255,
|
||||
verbose_name="ComNpay VAT Number",
|
||||
),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='comnpaypayment',
|
||||
name='payment_pass',
|
||||
field=re2o.aes_field.AESEncryptedField(blank=True, max_length=255, null=True, verbose_name='ComNpay secret key'),
|
||||
model_name="comnpaypayment",
|
||||
name="payment_pass",
|
||||
field=re2o.aes_field.AESEncryptedField(
|
||||
blank=True, max_length=255, null=True, verbose_name="ComNpay secret key"
|
||||
),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='comnpaypayment',
|
||||
name='production',
|
||||
field=models.BooleanField(default=True, verbose_name='Production mode enabled (production URL, instead of homologation)'),
|
||||
model_name="comnpaypayment",
|
||||
name="production",
|
||||
field=models.BooleanField(
|
||||
default=True,
|
||||
verbose_name="Production mode enabled (production URL, instead of homologation)",
|
||||
),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='cotisation',
|
||||
name='date_end',
|
||||
field=models.DateTimeField(verbose_name='end date'),
|
||||
model_name="cotisation",
|
||||
name="date_end",
|
||||
field=models.DateTimeField(verbose_name="end date"),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='cotisation',
|
||||
name='date_start',
|
||||
field=models.DateTimeField(verbose_name='start date'),
|
||||
model_name="cotisation",
|
||||
name="date_start",
|
||||
field=models.DateTimeField(verbose_name="start date"),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='cotisation',
|
||||
name='type_cotisation',
|
||||
field=models.CharField(choices=[('Connexion', 'Connection'), ('Adhesion', 'Membership'), ('All', 'Both of them')], default='All', max_length=255, verbose_name='subscription type'),
|
||||
model_name="cotisation",
|
||||
name="type_cotisation",
|
||||
field=models.CharField(
|
||||
choices=[
|
||||
("Connexion", "Connection"),
|
||||
("Adhesion", "Membership"),
|
||||
("All", "Both of them"),
|
||||
],
|
||||
default="All",
|
||||
max_length=255,
|
||||
verbose_name="subscription type",
|
||||
),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='cotisation',
|
||||
name='vente',
|
||||
field=models.OneToOneField(null=True, on_delete=django.db.models.deletion.CASCADE, to='cotisations.Vente', verbose_name='purchase'),
|
||||
model_name="cotisation",
|
||||
name="vente",
|
||||
field=models.OneToOneField(
|
||||
null=True,
|
||||
on_delete=django.db.models.deletion.CASCADE,
|
||||
to="cotisations.Vente",
|
||||
verbose_name="purchase",
|
||||
),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='facture',
|
||||
name='cheque',
|
||||
field=models.CharField(blank=True, max_length=255, verbose_name='cheque number'),
|
||||
model_name="facture",
|
||||
name="cheque",
|
||||
field=models.CharField(
|
||||
blank=True, max_length=255, verbose_name="cheque number"
|
||||
),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='facture',
|
||||
name='control',
|
||||
field=models.BooleanField(default=False, verbose_name='controlled'),
|
||||
model_name="facture",
|
||||
name="control",
|
||||
field=models.BooleanField(default=False, verbose_name="controlled"),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='facture',
|
||||
name='valid',
|
||||
field=models.BooleanField(default=True, verbose_name='validated'),
|
||||
model_name="facture",
|
||||
name="valid",
|
||||
field=models.BooleanField(default=True, verbose_name="validated"),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='paiement',
|
||||
name='available_for_everyone',
|
||||
field=models.BooleanField(default=False, verbose_name='is available for every user'),
|
||||
model_name="paiement",
|
||||
name="available_for_everyone",
|
||||
field=models.BooleanField(
|
||||
default=False, verbose_name="is available for every user"
|
||||
),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='paiement',
|
||||
name='is_balance',
|
||||
field=models.BooleanField(default=False, editable=False, help_text='There should be only one balance payment method.', validators=[cotisations.validators.check_no_balance], verbose_name='is user balance'),
|
||||
model_name="paiement",
|
||||
name="is_balance",
|
||||
field=models.BooleanField(
|
||||
default=False,
|
||||
editable=False,
|
||||
help_text="There should be only one balance payment method.",
|
||||
validators=[cotisations.validators.check_no_balance],
|
||||
verbose_name="is user balance",
|
||||
),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='paiement',
|
||||
name='moyen',
|
||||
field=models.CharField(max_length=255, verbose_name='method'),
|
||||
model_name="paiement",
|
||||
name="moyen",
|
||||
field=models.CharField(max_length=255, verbose_name="method"),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='vente',
|
||||
name='duration',
|
||||
field=models.PositiveIntegerField(blank=True, null=True, verbose_name='duration (in months)'),
|
||||
model_name="vente",
|
||||
name="duration",
|
||||
field=models.PositiveIntegerField(
|
||||
blank=True, null=True, verbose_name="duration (in months)"
|
||||
),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='vente',
|
||||
name='facture',
|
||||
field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='cotisations.BaseInvoice', verbose_name='invoice'),
|
||||
model_name="vente",
|
||||
name="facture",
|
||||
field=models.ForeignKey(
|
||||
on_delete=django.db.models.deletion.CASCADE,
|
||||
to="cotisations.BaseInvoice",
|
||||
verbose_name="invoice",
|
||||
),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='vente',
|
||||
name='name',
|
||||
field=models.CharField(max_length=255, verbose_name='article'),
|
||||
model_name="vente",
|
||||
name="name",
|
||||
field=models.CharField(max_length=255, verbose_name="article"),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='vente',
|
||||
name='number',
|
||||
field=models.IntegerField(validators=[django.core.validators.MinValueValidator(1)], verbose_name='amount'),
|
||||
model_name="vente",
|
||||
name="number",
|
||||
field=models.IntegerField(
|
||||
validators=[django.core.validators.MinValueValidator(1)],
|
||||
verbose_name="amount",
|
||||
),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='vente',
|
||||
name='prix',
|
||||
field=models.DecimalField(decimal_places=2, max_digits=5, verbose_name='price'),
|
||||
model_name="vente",
|
||||
name="prix",
|
||||
field=models.DecimalField(
|
||||
decimal_places=2, max_digits=5, verbose_name="price"
|
||||
),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='vente',
|
||||
name='type_cotisation',
|
||||
field=models.CharField(blank=True, choices=[('Connexion', 'Connection'), ('Adhesion', 'Membership'), ('All', 'Both of them')], max_length=255, null=True, verbose_name='subscription type'),
|
||||
model_name="vente",
|
||||
name="type_cotisation",
|
||||
field=models.CharField(
|
||||
blank=True,
|
||||
choices=[
|
||||
("Connexion", "Connection"),
|
||||
("Adhesion", "Membership"),
|
||||
("All", "Both of them"),
|
||||
],
|
||||
max_length=255,
|
||||
null=True,
|
||||
verbose_name="subscription type",
|
||||
),
|
||||
),
|
||||
]
|
||||
|
|
|
@ -7,14 +7,12 @@ from django.db import migrations, models
|
|||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('cotisations', '0033_auto_20180818_1319'),
|
||||
]
|
||||
dependencies = [("cotisations", "0033_auto_20180818_1319")]
|
||||
|
||||
operations = [
|
||||
migrations.AlterField(
|
||||
model_name='facture',
|
||||
name='valid',
|
||||
field=models.BooleanField(default=False, verbose_name='validated'),
|
||||
),
|
||||
model_name="facture",
|
||||
name="valid",
|
||||
field=models.BooleanField(default=False, verbose_name="validated"),
|
||||
)
|
||||
]
|
||||
|
|
|
@ -9,23 +9,35 @@ import django.db.models.deletion
|
|||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('cotisations', '0034_auto_20180831_1532'),
|
||||
]
|
||||
dependencies = [("cotisations", "0034_auto_20180831_1532")]
|
||||
|
||||
operations = [
|
||||
migrations.CreateModel(
|
||||
name='NotePayment',
|
||||
name="NotePayment",
|
||||
fields=[
|
||||
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||
('server', models.CharField(max_length=255, verbose_name='server')),
|
||||
('port', models.PositiveIntegerField(blank=True, null=True)),
|
||||
('id_note', models.PositiveIntegerField(blank=True, null=True)),
|
||||
('payment', models.OneToOneField(editable=False, on_delete=django.db.models.deletion.CASCADE, related_name='payment_method', to='cotisations.Paiement')),
|
||||
(
|
||||
"id",
|
||||
models.AutoField(
|
||||
auto_created=True,
|
||||
primary_key=True,
|
||||
serialize=False,
|
||||
verbose_name="ID",
|
||||
),
|
||||
),
|
||||
("server", models.CharField(max_length=255, verbose_name="server")),
|
||||
("port", models.PositiveIntegerField(blank=True, null=True)),
|
||||
("id_note", models.PositiveIntegerField(blank=True, null=True)),
|
||||
(
|
||||
"payment",
|
||||
models.OneToOneField(
|
||||
editable=False,
|
||||
on_delete=django.db.models.deletion.CASCADE,
|
||||
related_name="payment_method",
|
||||
to="cotisations.Paiement",
|
||||
),
|
||||
),
|
||||
],
|
||||
options={
|
||||
'verbose_name': 'NoteKfet',
|
||||
},
|
||||
options={"verbose_name": "NoteKfet"},
|
||||
bases=(cotisations.payment_methods.mixins.PaymentMethodMixin, models.Model),
|
||||
),
|
||||
)
|
||||
]
|
||||
|
|
|
@ -7,14 +7,12 @@ from django.db import migrations, models
|
|||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('cotisations', '0035_notepayment'),
|
||||
]
|
||||
dependencies = [("cotisations", "0035_notepayment")]
|
||||
|
||||
operations = [
|
||||
migrations.AddField(
|
||||
model_name='custominvoice',
|
||||
name='remark',
|
||||
field=models.TextField(blank=True, null=True, verbose_name='Remark'),
|
||||
),
|
||||
model_name="custominvoice",
|
||||
name="remark",
|
||||
field=models.TextField(blank=True, null=True, verbose_name="Remark"),
|
||||
)
|
||||
]
|
||||
|
|
|
@ -8,21 +8,40 @@ import django.db.models.deletion
|
|||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('cotisations', '0036_custominvoice_remark'),
|
||||
]
|
||||
dependencies = [("cotisations", "0036_custominvoice_remark")]
|
||||
|
||||
operations = [
|
||||
migrations.CreateModel(
|
||||
name='CostEstimate',
|
||||
name="CostEstimate",
|
||||
fields=[
|
||||
('custominvoice_ptr', models.OneToOneField(auto_created=True, on_delete=django.db.models.deletion.CASCADE, parent_link=True, primary_key=True, serialize=False, to='cotisations.CustomInvoice')),
|
||||
('validity', models.DurationField(verbose_name='Period of validity')),
|
||||
('final_invoice', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='origin_cost_estimate', to='cotisations.CustomInvoice')),
|
||||
(
|
||||
"custominvoice_ptr",
|
||||
models.OneToOneField(
|
||||
auto_created=True,
|
||||
on_delete=django.db.models.deletion.CASCADE,
|
||||
parent_link=True,
|
||||
primary_key=True,
|
||||
serialize=False,
|
||||
to="cotisations.CustomInvoice",
|
||||
),
|
||||
),
|
||||
("validity", models.DurationField(verbose_name="Period of validity")),
|
||||
(
|
||||
"final_invoice",
|
||||
models.ForeignKey(
|
||||
blank=True,
|
||||
null=True,
|
||||
on_delete=django.db.models.deletion.CASCADE,
|
||||
related_name="origin_cost_estimate",
|
||||
to="cotisations.CustomInvoice",
|
||||
),
|
||||
),
|
||||
],
|
||||
options={
|
||||
'permissions': (('view_costestimate', 'Can view a cost estimate object'),),
|
||||
"permissions": (
|
||||
("view_costestimate", "Can view a cost estimate object"),
|
||||
)
|
||||
},
|
||||
bases=('cotisations.custominvoice',),
|
||||
),
|
||||
bases=("cotisations.custominvoice",),
|
||||
)
|
||||
]
|
||||
|
|
|
@ -8,24 +8,30 @@ import django.db.models.deletion
|
|||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('cotisations', '0037_costestimate'),
|
||||
]
|
||||
dependencies = [("cotisations", "0037_costestimate")]
|
||||
|
||||
operations = [
|
||||
migrations.AlterField(
|
||||
model_name='costestimate',
|
||||
name='final_invoice',
|
||||
field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='origin_cost_estimate', to='cotisations.CustomInvoice'),
|
||||
model_name="costestimate",
|
||||
name="final_invoice",
|
||||
field=models.ForeignKey(
|
||||
blank=True,
|
||||
null=True,
|
||||
on_delete=django.db.models.deletion.SET_NULL,
|
||||
related_name="origin_cost_estimate",
|
||||
to="cotisations.CustomInvoice",
|
||||
),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='costestimate',
|
||||
name='validity',
|
||||
field=models.DurationField(help_text='DD HH:MM:SS', verbose_name='Period of validity'),
|
||||
model_name="costestimate",
|
||||
name="validity",
|
||||
field=models.DurationField(
|
||||
help_text="DD HH:MM:SS", verbose_name="Period of validity"
|
||||
),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='custominvoice',
|
||||
name='paid',
|
||||
field=models.BooleanField(default=False, verbose_name='Paid'),
|
||||
model_name="custominvoice",
|
||||
name="paid",
|
||||
field=models.BooleanField(default=False, verbose_name="Paid"),
|
||||
),
|
||||
]
|
||||
|
|
40
cotisations/migrations/0039_freepayment.py
Normal file
40
cotisations/migrations/0039_freepayment.py
Normal file
|
@ -0,0 +1,40 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
# Generated by Django 1.11.23 on 2019-09-30 09:19
|
||||
from __future__ import unicode_literals
|
||||
|
||||
import cotisations.payment_methods.mixins
|
||||
from django.db import migrations, models
|
||||
import django.db.models.deletion
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [("cotisations", "0038_auto_20181231_1657")]
|
||||
|
||||
operations = [
|
||||
migrations.CreateModel(
|
||||
name="FreePayment",
|
||||
fields=[
|
||||
(
|
||||
"id",
|
||||
models.AutoField(
|
||||
auto_created=True,
|
||||
primary_key=True,
|
||||
serialize=False,
|
||||
verbose_name="ID",
|
||||
),
|
||||
),
|
||||
(
|
||||
"payment",
|
||||
models.OneToOneField(
|
||||
editable=False,
|
||||
on_delete=django.db.models.deletion.CASCADE,
|
||||
related_name="payment_method",
|
||||
to="cotisations.Paiement",
|
||||
),
|
||||
),
|
||||
],
|
||||
options={"verbose_name": "Free payment"},
|
||||
bases=(cotisations.payment_methods.mixins.PaymentMethodMixin, models.Model),
|
||||
)
|
||||
]
|
34
cotisations/migrations/0040_auto_20191002_2335.py
Normal file
34
cotisations/migrations/0040_auto_20191002_2335.py
Normal file
|
@ -0,0 +1,34 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
# Generated by Django 1.11.23 on 2019-10-02 21:35
|
||||
from __future__ import unicode_literals
|
||||
|
||||
import django.core.validators
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [("cotisations", "0039_freepayment")]
|
||||
|
||||
operations = [
|
||||
migrations.AddField(
|
||||
model_name="article",
|
||||
name="duration_days",
|
||||
field=models.PositiveIntegerField(
|
||||
blank=True,
|
||||
null=True,
|
||||
validators=[django.core.validators.MinValueValidator(0)],
|
||||
verbose_name="duration (in days, will be added to duration in months)",
|
||||
),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name="vente",
|
||||
name="duration_days",
|
||||
field=models.PositiveIntegerField(
|
||||
blank=True,
|
||||
null=True,
|
||||
validators=[django.core.validators.MinValueValidator(0)],
|
||||
verbose_name="duration (in days, will be added to duration in months)",
|
||||
),
|
||||
),
|
||||
]
|
64
cotisations/migrations/0041_auto_20191103_2131.py
Normal file
64
cotisations/migrations/0041_auto_20191103_2131.py
Normal file
|
@ -0,0 +1,64 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
# Generated by Django 1.11.23 on 2019-11-03 20:31
|
||||
from __future__ import unicode_literals
|
||||
|
||||
from django.db import migrations, models
|
||||
import django.db.models.deletion
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [("cotisations", "0040_auto_20191002_2335")]
|
||||
|
||||
operations = [
|
||||
migrations.AlterField(
|
||||
model_name="balancepayment",
|
||||
name="payment",
|
||||
field=models.OneToOneField(
|
||||
editable=False,
|
||||
on_delete=django.db.models.deletion.CASCADE,
|
||||
related_name="payment_method_balance",
|
||||
to="cotisations.Paiement",
|
||||
),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name="chequepayment",
|
||||
name="payment",
|
||||
field=models.OneToOneField(
|
||||
editable=False,
|
||||
on_delete=django.db.models.deletion.CASCADE,
|
||||
related_name="payment_method_cheque",
|
||||
to="cotisations.Paiement",
|
||||
),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name="comnpaypayment",
|
||||
name="payment",
|
||||
field=models.OneToOneField(
|
||||
editable=False,
|
||||
on_delete=django.db.models.deletion.CASCADE,
|
||||
related_name="payment_method_comnpay",
|
||||
to="cotisations.Paiement",
|
||||
),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name="freepayment",
|
||||
name="payment",
|
||||
field=models.OneToOneField(
|
||||
editable=False,
|
||||
on_delete=django.db.models.deletion.CASCADE,
|
||||
related_name="payment_method_free",
|
||||
to="cotisations.Paiement",
|
||||
),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name="notepayment",
|
||||
name="payment",
|
||||
field=models.OneToOneField(
|
||||
editable=False,
|
||||
on_delete=django.db.models.deletion.CASCADE,
|
||||
related_name="payment_method_note",
|
||||
to="cotisations.Paiement",
|
||||
),
|
||||
),
|
||||
]
|
79
cotisations/migrations/0042_auto_20191120_0159.py
Normal file
79
cotisations/migrations/0042_auto_20191120_0159.py
Normal file
|
@ -0,0 +1,79 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
# Generated by Django 1.11.23 on 2019-11-20 00:59
|
||||
from __future__ import unicode_literals
|
||||
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('cotisations', '0041_auto_20191103_2131'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AlterModelOptions(
|
||||
name='chequepayment',
|
||||
options={'verbose_name': 'cheque'},
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='balancepayment',
|
||||
name='credit_balance_allowed',
|
||||
field=models.BooleanField(default=False, verbose_name='allow user to credit their balance'),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='balancepayment',
|
||||
name='maximum_balance',
|
||||
field=models.DecimalField(blank=True, decimal_places=2, default=50, help_text='The maximal amount of money allowed for the balance.', max_digits=5, null=True, verbose_name='maximum balance'),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='balancepayment',
|
||||
name='minimum_balance',
|
||||
field=models.DecimalField(decimal_places=2, default=0, help_text='The minimal amount of money allowed for the balance at the end of a payment. You can specify a negative amount.', max_digits=5, verbose_name='minimum balance'),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='baseinvoice',
|
||||
name='date',
|
||||
field=models.DateTimeField(auto_now_add=True, verbose_name='date'),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='comnpaypayment',
|
||||
name='minimum_payment',
|
||||
field=models.DecimalField(decimal_places=2, default=1, help_text='The minimal amount of money you have to use when paying with ComNpay.', max_digits=5, verbose_name='minimum payment'),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='comnpaypayment',
|
||||
name='production',
|
||||
field=models.BooleanField(default=True, verbose_name='production mode enabled (production URL, instead of homologation)'),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='costestimate',
|
||||
name='validity',
|
||||
field=models.DurationField(help_text='DD HH:MM:SS', verbose_name='period of validity'),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='custominvoice',
|
||||
name='address',
|
||||
field=models.CharField(max_length=255, verbose_name='address'),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='custominvoice',
|
||||
name='paid',
|
||||
field=models.BooleanField(default=False, verbose_name='paid'),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='custominvoice',
|
||||
name='payment',
|
||||
field=models.CharField(max_length=255, verbose_name='payment type'),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='custominvoice',
|
||||
name='recipient',
|
||||
field=models.CharField(max_length=255, verbose_name='recipient'),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='custominvoice',
|
||||
name='remark',
|
||||
field=models.TextField(blank=True, null=True, verbose_name='remark'),
|
||||
),
|
||||
]
|
|
@ -3,7 +3,7 @@
|
|||
# quelques clics.
|
||||
#
|
||||
# Copyright © 2017 Gabriel Détraz
|
||||
# Copyright © 2017 Goulven Kermarec
|
||||
# Copyright © 2017 Lara Kermarec
|
||||
# Copyright © 2017 Augustin Lemesle
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or modify
|
||||
|
@ -19,4 +19,3 @@
|
|||
# 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.
|
||||
|
||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -127,11 +127,6 @@ method to your model, where `form` is an instance of
|
|||
"""
|
||||
|
||||
|
||||
from . import comnpay, cheque, balance, note_kfet, urls
|
||||
from . import comnpay, cheque, balance, note_kfet, free, urls
|
||||
|
||||
PAYMENT_METHODS = [
|
||||
comnpay,
|
||||
cheque,
|
||||
balance,
|
||||
note_kfet
|
||||
]
|
||||
PAYMENT_METHODS = [comnpay, cheque, balance, note_kfet, free]
|
||||
|
|
|
@ -22,6 +22,7 @@
|
|||
This module contains a method to pay online using user balance.
|
||||
"""
|
||||
from . import models
|
||||
|
||||
NAME = "BALANCE"
|
||||
|
||||
PaymentMethod = models.BalancePayment
|
||||
|
|
|
@ -40,21 +40,21 @@ class BalancePayment(PaymentMethodMixin, models.Model):
|
|||
payment = models.OneToOneField(
|
||||
Paiement,
|
||||
on_delete=models.CASCADE,
|
||||
related_name='payment_method',
|
||||
editable=False
|
||||
related_name="payment_method_balance",
|
||||
editable=False,
|
||||
)
|
||||
minimum_balance = models.DecimalField(
|
||||
verbose_name=_("Minimum balance"),
|
||||
help_text=_("The minimal amount of money allowed for the balance"
|
||||
" at the end of a payment. You can specify negative "
|
||||
"amount."
|
||||
),
|
||||
verbose_name=_("minimum balance"),
|
||||
help_text=_(
|
||||
"The minimal amount of money allowed for the balance at the end"
|
||||
" of a payment. You can specify a negative amount."
|
||||
),
|
||||
max_digits=5,
|
||||
decimal_places=2,
|
||||
default=0,
|
||||
)
|
||||
maximum_balance = models.DecimalField(
|
||||
verbose_name=_("Maximum balance"),
|
||||
verbose_name=_("maximum balance"),
|
||||
help_text=_("The maximal amount of money allowed for the balance."),
|
||||
max_digits=5,
|
||||
decimal_places=2,
|
||||
|
@ -63,8 +63,7 @@ class BalancePayment(PaymentMethodMixin, models.Model):
|
|||
null=True,
|
||||
)
|
||||
credit_balance_allowed = models.BooleanField(
|
||||
verbose_name=_("Allow user to credit their balance"),
|
||||
default=False,
|
||||
verbose_name=_("allow user to credit their balance"), default=False
|
||||
)
|
||||
|
||||
def end_payment(self, invoice, request):
|
||||
|
@ -74,27 +73,17 @@ class BalancePayment(PaymentMethodMixin, models.Model):
|
|||
user = invoice.user
|
||||
total_price = invoice.prix_total()
|
||||
if user.solde - total_price < self.minimum_balance:
|
||||
messages.error(
|
||||
request,
|
||||
_("Your balance is too low for this operation.")
|
||||
)
|
||||
return redirect(reverse(
|
||||
'users:profil',
|
||||
kwargs={'userid': user.id}
|
||||
))
|
||||
return invoice.paiement.end_payment(
|
||||
invoice,
|
||||
request,
|
||||
use_payment_method=False
|
||||
)
|
||||
messages.error(request, _("Your balance is too low for this operation."))
|
||||
return redirect(reverse("users:profil", kwargs={"userid": user.id}))
|
||||
return invoice.paiement.end_payment(invoice, request, use_payment_method=False)
|
||||
|
||||
def valid_form(self, form):
|
||||
"""Checks that there is not already a balance payment method."""
|
||||
p = Paiement.objects.filter(is_balance=True)
|
||||
if len(p) > 0:
|
||||
form.add_error(
|
||||
'payment_method',
|
||||
_("There is already a payment method for user balance.")
|
||||
"payment_method",
|
||||
_("There is already a payment method for user balance."),
|
||||
)
|
||||
|
||||
def alter_payment(self, payment):
|
||||
|
@ -107,12 +96,11 @@ class BalancePayment(PaymentMethodMixin, models.Model):
|
|||
"""
|
||||
return (
|
||||
user.solde - price >= self.minimum_balance,
|
||||
_("Your balance is too low for this operation.")
|
||||
_("Your balance is too low for this operation."),
|
||||
)
|
||||
|
||||
def can_credit_balance(self, user_request):
|
||||
return (
|
||||
len(Paiement.find_allowed_payments(user_request)
|
||||
.exclude(is_balance=True)) > 0
|
||||
len(Paiement.find_allowed_payments(user_request).exclude(is_balance=True))
|
||||
> 0
|
||||
) and self.credit_balance_allowed
|
||||
|
||||
|
|
|
@ -22,6 +22,7 @@
|
|||
This module contains a method to pay online using cheque.
|
||||
"""
|
||||
from . import models, urls, views
|
||||
|
||||
NAME = "CHEQUE"
|
||||
|
||||
PaymentMethod = models.ChequePayment
|
||||
|
|
|
@ -26,6 +26,7 @@ from cotisations.models import Facture as Invoice
|
|||
|
||||
class InvoiceForm(FormRevMixin, forms.ModelForm):
|
||||
"""A simple form to get the bank a the cheque number."""
|
||||
|
||||
class Meta:
|
||||
model = Invoice
|
||||
fields = ['banque', 'cheque']
|
||||
fields = ["banque", "cheque"]
|
||||
|
|
|
@ -33,21 +33,19 @@ class ChequePayment(PaymentMethodMixin, models.Model):
|
|||
"""
|
||||
|
||||
class Meta:
|
||||
verbose_name = _("Cheque")
|
||||
verbose_name = _("cheque")
|
||||
|
||||
payment = models.OneToOneField(
|
||||
Paiement,
|
||||
on_delete=models.CASCADE,
|
||||
related_name='payment_method',
|
||||
editable=False
|
||||
related_name="payment_method_cheque",
|
||||
editable=False,
|
||||
)
|
||||
|
||||
def end_payment(self, invoice, request):
|
||||
"""Invalidates the invoice then redirect the user towards a view asking
|
||||
for informations to add to the invoice before validating it.
|
||||
"""
|
||||
return redirect(reverse(
|
||||
'cotisations:cheque:validate',
|
||||
kwargs={'invoice_pk': invoice.pk}
|
||||
))
|
||||
|
||||
return redirect(
|
||||
reverse("cotisations:cheque:validate", kwargs={"invoice_pk": invoice.pk})
|
||||
)
|
||||
|
|
|
@ -21,10 +21,4 @@
|
|||
from django.conf.urls import url
|
||||
from . import views
|
||||
|
||||
urlpatterns = [
|
||||
url(
|
||||
r'^validate/(?P<invoice_pk>[0-9]+)$',
|
||||
views.cheque,
|
||||
name='validate'
|
||||
)
|
||||
]
|
||||
urlpatterns = [url(r"^validate/(?P<invoice_pk>[0-9]+)$", views.cheque, name="validate")]
|
||||
|
|
|
@ -42,29 +42,17 @@ def cheque(request, invoice_pk):
|
|||
invoice = get_object_or_404(Invoice, pk=invoice_pk)
|
||||
payment_method = find_payment_method(invoice.paiement)
|
||||
if invoice.valid or not isinstance(payment_method, ChequePayment):
|
||||
messages.error(
|
||||
request,
|
||||
_("You can't pay this invoice with a cheque.")
|
||||
)
|
||||
return redirect(reverse(
|
||||
'users:profil',
|
||||
kwargs={'userid': request.user.pk}
|
||||
))
|
||||
messages.error(request, _("You can't pay this invoice with a cheque."))
|
||||
return redirect(reverse("users:profil", kwargs={"userid": request.user.pk}))
|
||||
form = InvoiceForm(request.POST or None, instance=invoice)
|
||||
if form.is_valid():
|
||||
form.instance.valid = True
|
||||
form.save()
|
||||
return form.instance.paiement.end_payment(
|
||||
form.instance,
|
||||
request,
|
||||
use_payment_method=False
|
||||
form.instance, request, use_payment_method=False
|
||||
)
|
||||
return render(
|
||||
request,
|
||||
'cotisations/payment.html',
|
||||
{
|
||||
'form': form,
|
||||
'amount': invoice.prix_total()
|
||||
}
|
||||
"cotisations/payment.html",
|
||||
{"form": form, "amount": invoice.prix_total()},
|
||||
)
|
||||
|
||||
|
|
|
@ -22,5 +22,6 @@
|
|||
This module contains a method to pay online using comnpay.
|
||||
"""
|
||||
from . import models, urls, views
|
||||
|
||||
NAME = "COMNPAY"
|
||||
PaymentMethod = models.ComnpayPayment
|
||||
|
|
|
@ -10,13 +10,21 @@ import hashlib
|
|||
from collections import OrderedDict
|
||||
|
||||
|
||||
class Transaction():
|
||||
class Transaction:
|
||||
""" The class representing a transaction with all the functions
|
||||
used during the negociation
|
||||
"""
|
||||
|
||||
def __init__(self, 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
|
||||
|
@ -26,8 +34,7 @@ class Transaction():
|
|||
self.typeTr = typeTr
|
||||
self.idTransaction = ""
|
||||
|
||||
def buildSecretHTML(self, produit="Produit", montant="0.00",
|
||||
idTransaction=""):
|
||||
def buildSecretHTML(self, produit="Produit", montant="0.00", idTransaction=""):
|
||||
""" Build an HTML hidden form with the different parameters for the
|
||||
transaction
|
||||
"""
|
||||
|
@ -43,30 +50,26 @@ class Transaction():
|
|||
idTPE=self.vad_number,
|
||||
idTransaction=self.idTransaction,
|
||||
devise="EUR",
|
||||
lang='fr',
|
||||
lang="fr",
|
||||
nom_produit=produit,
|
||||
source=self.source,
|
||||
urlRetourOK=self.urlRetourOK,
|
||||
urlRetourNOK=self.urlRetourNOK,
|
||||
typeTr=str(self.typeTr)
|
||||
typeTr=str(self.typeTr),
|
||||
)
|
||||
|
||||
if self.urlIPN != "":
|
||||
array_tpe['urlIPN'] = self.urlIPN
|
||||
array_tpe["urlIPN"] = self.urlIPN
|
||||
|
||||
array_tpe['key'] = self.secret_key
|
||||
strWithKey = base64.b64encode(bytes(
|
||||
'|'.join(array_tpe.values()),
|
||||
'utf-8'
|
||||
))
|
||||
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()
|
||||
array_tpe["sec"] = hashlib.sha512(strWithKey).hexdigest()
|
||||
|
||||
ret = ""
|
||||
for key in array_tpe:
|
||||
ret += '<input type="hidden" name="{k}" value="{v}"/>'.format(
|
||||
k=key,
|
||||
v=array_tpe[key]
|
||||
k=key, v=array_tpe[key]
|
||||
)
|
||||
|
||||
return ret
|
||||
|
@ -75,12 +78,13 @@ class Transaction():
|
|||
def validSec(values, secret_key):
|
||||
""" Check if the secret value is correct """
|
||||
if "sec" in values:
|
||||
sec = values['sec']
|
||||
sec = values["sec"]
|
||||
del values["sec"]
|
||||
strWithKey = hashlib.sha512(base64.b64encode(bytes(
|
||||
'|'.join(values.values()) + "|" + secret_key,
|
||||
'utf-8'
|
||||
))).hexdigest()
|
||||
strWithKey = hashlib.sha512(
|
||||
base64.b64encode(
|
||||
bytes("|".join(values.values()) + "|" + secret_key, "utf-8")
|
||||
)
|
||||
).hexdigest()
|
||||
return strWithKey.upper() == sec.upper()
|
||||
else:
|
||||
return False
|
||||
|
|
|
@ -41,39 +41,37 @@ class ComnpayPayment(PaymentMethodMixin, models.Model):
|
|||
payment = models.OneToOneField(
|
||||
Paiement,
|
||||
on_delete=models.CASCADE,
|
||||
related_name='payment_method',
|
||||
editable=False
|
||||
related_name="payment_method_comnpay",
|
||||
editable=False,
|
||||
)
|
||||
payment_credential = models.CharField(
|
||||
max_length=255,
|
||||
default='',
|
||||
blank=True,
|
||||
verbose_name=_("ComNpay VAT Number"),
|
||||
max_length=255, default="", blank=True, verbose_name=_("ComNpay VAT Number")
|
||||
)
|
||||
payment_pass = AESEncryptedField(
|
||||
max_length=255,
|
||||
null=True,
|
||||
blank=True,
|
||||
verbose_name=_("ComNpay secret key"),
|
||||
max_length=255, null=True, blank=True, verbose_name=_("ComNpay secret key")
|
||||
)
|
||||
minimum_payment = models.DecimalField(
|
||||
verbose_name=_("Minimum payment"),
|
||||
help_text=_("The minimal amount of money you have to use when paying"
|
||||
" with ComNpay"),
|
||||
verbose_name=_("minimum payment"),
|
||||
help_text=_(
|
||||
"The minimal amount of money you have to use when paying with"
|
||||
" ComNpay."
|
||||
),
|
||||
max_digits=5,
|
||||
decimal_places=2,
|
||||
default=1,
|
||||
)
|
||||
production = models.BooleanField(
|
||||
default=True,
|
||||
verbose_name=_("Production mode enabled (production URL, instead of homologation)"),
|
||||
verbose_name=_(
|
||||
"production mode enabled (production URL, instead of homologation)"
|
||||
),
|
||||
)
|
||||
|
||||
def return_url_comnpay(self):
|
||||
if self.production:
|
||||
return 'https://secure.comnpay.com'
|
||||
return "https://secure.comnpay.com"
|
||||
else:
|
||||
return 'https://secure.homologation.comnpay.com'
|
||||
return "https://secure.homologation.comnpay.com"
|
||||
|
||||
def end_payment(self, invoice, request):
|
||||
"""
|
||||
|
@ -85,32 +83,36 @@ class ComnpayPayment(PaymentMethodMixin, models.Model):
|
|||
p = Transaction(
|
||||
str(self.payment_credential),
|
||||
str(self.payment_pass),
|
||||
'https://' + host + reverse(
|
||||
'cotisations:comnpay:accept_payment',
|
||||
kwargs={'factureid': invoice.id}
|
||||
"https://"
|
||||
+ host
|
||||
+ reverse(
|
||||
"cotisations:comnpay:accept_payment", kwargs={"factureid": invoice.id}
|
||||
),
|
||||
'https://' + host + reverse('cotisations:comnpay:refuse_payment'),
|
||||
'https://' + host + reverse('cotisations:comnpay:ipn'),
|
||||
"https://" + host + reverse("cotisations:comnpay:refuse_payment"),
|
||||
"https://" + host + reverse("cotisations:comnpay:ipn"),
|
||||
"",
|
||||
"D"
|
||||
"D",
|
||||
)
|
||||
|
||||
r = {
|
||||
'action': self.return_url_comnpay(),
|
||||
'method': 'POST',
|
||||
'content': p.buildSecretHTML(
|
||||
_("Pay invoice number ")+str(invoice.id),
|
||||
"action": self.return_url_comnpay(),
|
||||
"method": "POST",
|
||||
"content": p.buildSecretHTML(
|
||||
_("Pay invoice number ") + str(invoice.id),
|
||||
invoice.prix_total(),
|
||||
idTransaction=str(invoice.id)
|
||||
idTransaction=str(invoice.id),
|
||||
),
|
||||
'amount': invoice.prix_total(),
|
||||
"amount": invoice.prix_total(),
|
||||
}
|
||||
return render(request, 'cotisations/payment.html', r)
|
||||
return render(request, "cotisations/payment.html", r)
|
||||
|
||||
def check_price(self, price, *args, **kwargs):
|
||||
"""Checks that the price meets the requirement to be paid with ComNpay.
|
||||
"""
|
||||
return ((price >= self.minimum_payment),
|
||||
_("In order to pay your invoice with ComNpay, the price must"
|
||||
" be greater than {} €.").format(self.minimum_payment))
|
||||
|
||||
return (
|
||||
(price >= self.minimum_payment),
|
||||
_(
|
||||
"In order to pay your invoice with ComNpay, the price must"
|
||||
" be greater than {} €."
|
||||
).format(self.minimum_payment),
|
||||
)
|
||||
|
|
|
@ -22,19 +22,7 @@ from django.conf.urls import url
|
|||
from . import views
|
||||
|
||||
urlpatterns = [
|
||||
url(
|
||||
r'^accept/(?P<factureid>[0-9]+)$',
|
||||
views.accept_payment,
|
||||
name='accept_payment'
|
||||
),
|
||||
url(
|
||||
r'^refuse/$',
|
||||
views.refuse_payment,
|
||||
name='refuse_payment'
|
||||
),
|
||||
url(
|
||||
r'^ipn/$',
|
||||
views.ipn,
|
||||
name='ipn'
|
||||
),
|
||||
url(r"^accept/(?P<factureid>[0-9]+)$", views.accept_payment, name="accept_payment"),
|
||||
url(r"^refuse/$", views.refuse_payment, name="refuse_payment"),
|
||||
url(r"^ipn/$", views.ipn, name="ipn"),
|
||||
]
|
||||
|
|
|
@ -50,26 +50,24 @@ def accept_payment(request, factureid):
|
|||
if invoice.valid:
|
||||
messages.success(
|
||||
request,
|
||||
_("The payment of %(amount)s € was accepted.") % {
|
||||
'amount': invoice.prix_total()
|
||||
}
|
||||
_("The payment of %(amount)s € was accepted.")
|
||||
% {"amount": invoice.prix_total()},
|
||||
)
|
||||
# In case a cotisation was bought, inform the user, the
|
||||
# cotisation time has been extended too
|
||||
if any(purchase.type_cotisation
|
||||
for purchase in invoice.vente_set.all()):
|
||||
if any(purchase.type_cotisation for purchase in invoice.vente_set.all()):
|
||||
messages.success(
|
||||
request,
|
||||
_("The subscription of %(member_name)s was extended to"
|
||||
" %(end_date)s.") % {
|
||||
'member_name': invoice.user.pseudo,
|
||||
'end_date': invoice.user.end_adhesion()
|
||||
}
|
||||
_(
|
||||
"The subscription of %(member_name)s was extended to"
|
||||
" %(end_date)s."
|
||||
)
|
||||
% {
|
||||
"member_name": invoice.user.pseudo,
|
||||
"end_date": invoice.user.end_adhesion(),
|
||||
},
|
||||
)
|
||||
return redirect(reverse(
|
||||
'users:profil',
|
||||
kwargs={'userid': invoice.user.id}
|
||||
))
|
||||
return redirect(reverse("users:profil", kwargs={"userid": invoice.user.id}))
|
||||
|
||||
|
||||
@csrf_exempt
|
||||
|
@ -79,14 +77,8 @@ def refuse_payment(request):
|
|||
The view where the user is redirected when a comnpay payment has been
|
||||
refused.
|
||||
"""
|
||||
messages.error(
|
||||
request,
|
||||
_("The payment was refused.")
|
||||
)
|
||||
return redirect(reverse(
|
||||
'users:profil',
|
||||
kwargs={'userid': request.user.id}
|
||||
))
|
||||
messages.error(request, _("The payment was refused."))
|
||||
return redirect(reverse("users:profil", kwargs={"userid": request.user.id}))
|
||||
|
||||
|
||||
@csrf_exempt
|
||||
|
@ -97,27 +89,26 @@ def ipn(request):
|
|||
Comnpay with 400 response if not or with a 200 response if yes.
|
||||
"""
|
||||
p = Transaction()
|
||||
order = ('idTpe', 'idTransaction', 'montant', 'result', 'sec', )
|
||||
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")
|
||||
|
||||
idTransaction = request.POST['idTransaction']
|
||||
idTransaction = request.POST["idTransaction"]
|
||||
try:
|
||||
factureid = int(idTransaction)
|
||||
except ValueError:
|
||||
return HttpResponseBadRequest("HTTP/1.1 400 Bad Request")
|
||||
|
||||
facture = get_object_or_404(Facture, id=factureid)
|
||||
payment_method = get_object_or_404(
|
||||
ComnpayPayment, payment=facture.paiement)
|
||||
payment_method = get_object_or_404(ComnpayPayment, payment=facture.paiement)
|
||||
|
||||
if not p.validSec(data, payment_method.payment_pass):
|
||||
return HttpResponseBadRequest("HTTP/1.1 400 Bad Request")
|
||||
|
||||
result = True if (request.POST['result'] == 'OK') else False
|
||||
idTpe = request.POST['idTpe']
|
||||
result = True if (request.POST["result"] == "OK") else False
|
||||
idTpe = request.POST["idTpe"]
|
||||
|
||||
# Checking that the payment is actually for us.
|
||||
if not idTpe == payment_method.payment_credential:
|
||||
|
@ -136,4 +127,3 @@ def ipn(request):
|
|||
# Everything worked we send a reponse to Comnpay indicating that
|
||||
# it's ok for them to proceed
|
||||
return HttpResponse("HTTP/1.0 200 OK")
|
||||
|
||||
|
|
|
@ -24,6 +24,7 @@ from django.utils.translation import ugettext_lazy as _
|
|||
from . import PAYMENT_METHODS
|
||||
from cotisations.utils import find_payment_method
|
||||
|
||||
|
||||
def payment_method_factory(payment, *args, creation=True, **kwargs):
|
||||
"""This function finds the right payment method form for a given payment.
|
||||
|
||||
|
@ -40,12 +41,10 @@ def payment_method_factory(payment, *args, creation=True, **kwargs):
|
|||
Returns:
|
||||
A form or None
|
||||
"""
|
||||
payment_method = kwargs.pop('instance', find_payment_method(payment))
|
||||
payment_method = kwargs.pop("instance", find_payment_method(payment))
|
||||
if payment_method is not None:
|
||||
return forms.modelform_factory(type(payment_method), fields='__all__')(
|
||||
*args,
|
||||
instance=payment_method,
|
||||
**kwargs
|
||||
return forms.modelform_factory(type(payment_method), fields="__all__")(
|
||||
*args, instance=payment_method, **kwargs
|
||||
)
|
||||
elif creation:
|
||||
return PaymentMethodForm(*args, **kwargs)
|
||||
|
@ -58,23 +57,24 @@ class PaymentMethodForm(forms.Form):
|
|||
|
||||
payment_method = forms.ChoiceField(
|
||||
label=_("Special payment method"),
|
||||
help_text=_("Warning: you will not be able to change the payment "
|
||||
"method later. But you will be allowed to edit the other "
|
||||
"options."
|
||||
help_text=_(
|
||||
"Warning: you will not be able to change the payment"
|
||||
" method later. But you will be allowed to edit the other"
|
||||
" options."
|
||||
),
|
||||
required=False
|
||||
required=False,
|
||||
)
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
super(PaymentMethodForm, self).__init__(*args, **kwargs)
|
||||
prefix = kwargs.get('prefix', None)
|
||||
self.fields['payment_method'].choices = [(i,p.NAME) for (i,p) in enumerate(PAYMENT_METHODS)]
|
||||
self.fields['payment_method'].choices.insert(0, ('', _('no')))
|
||||
self.fields['payment_method'].widget.attrs = {
|
||||
'id': 'paymentMethodSelect'
|
||||
}
|
||||
prefix = kwargs.get("prefix", None)
|
||||
self.fields["payment_method"].choices = [
|
||||
(i, p.NAME) for (i, p) in enumerate(PAYMENT_METHODS)
|
||||
]
|
||||
self.fields["payment_method"].choices.insert(0, ("", _("No")))
|
||||
self.fields["payment_method"].widget.attrs = {"id": "paymentMethodSelect"}
|
||||
self.templates = [
|
||||
forms.modelform_factory(p.PaymentMethod, fields='__all__')(prefix=prefix)
|
||||
forms.modelform_factory(p.PaymentMethod, fields="__all__")(prefix=prefix)
|
||||
for p in PAYMENT_METHODS
|
||||
]
|
||||
|
||||
|
@ -84,29 +84,29 @@ class PaymentMethodForm(forms.Form):
|
|||
found. Tries to call `payment_method.valid_form` if it exists.
|
||||
"""
|
||||
super(PaymentMethodForm, self).clean()
|
||||
choice = self.cleaned_data['payment_method']
|
||||
if choice=='':
|
||||
choice = self.cleaned_data["payment_method"]
|
||||
if choice == "":
|
||||
return
|
||||
choice = int(choice)
|
||||
model = PAYMENT_METHODS[choice].PaymentMethod
|
||||
form = forms.modelform_factory(model, fields='__all__')(self.data, prefix=self.prefix)
|
||||
form = forms.modelform_factory(model, fields="__all__")(
|
||||
self.data, prefix=self.prefix
|
||||
)
|
||||
self.payment_method = form.save(commit=False)
|
||||
if hasattr(self.payment_method, 'valid_form'):
|
||||
if hasattr(self.payment_method, "valid_form"):
|
||||
self.payment_method.valid_form(self)
|
||||
return self.cleaned_data
|
||||
|
||||
|
||||
|
||||
def save(self, payment, *args, **kwargs):
|
||||
"""Saves the payment method.
|
||||
|
||||
Tries to call `payment_method.alter_payment` if it exists.
|
||||
"""
|
||||
commit = kwargs.pop('commit', True)
|
||||
if not hasattr(self, 'payment_method'):
|
||||
commit = kwargs.pop("commit", True)
|
||||
if not hasattr(self, "payment_method"):
|
||||
return None
|
||||
self.payment_method.payment = payment
|
||||
if hasattr(self.payment_method, 'alter_payment'):
|
||||
if hasattr(self.payment_method, "alter_payment"):
|
||||
self.payment_method.alter_payment(payment)
|
||||
if commit:
|
||||
payment.save()
|
||||
|
|
|
@ -1,10 +1,9 @@
|
|||
# -*- mode: python; coding: utf-8 -*-
|
||||
# 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
|
||||
# Copyright © 2019 Hugo Levy-Falk
|
||||
#
|
||||
# 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
|
||||
|
@ -19,10 +18,11 @@
|
|||
# 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.
|
||||
"""cotisations.tests
|
||||
The tests for the Cotisations module.
|
||||
"""
|
||||
This module contains a method to pay online using user balance.
|
||||
"""
|
||||
from . import models
|
||||
|
||||
# from django.test import TestCase
|
||||
NAME = "FREE"
|
||||
|
||||
# Create your tests here.
|
||||
PaymentMethod = models.FreePayment
|
54
cotisations/payment_methods/free/models.py
Normal file
54
cotisations/payment_methods/free/models.py
Normal file
|
@ -0,0 +1,54 @@
|
|||
# -*- mode: python; coding: utf-8 -*-
|
||||
# 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 © 2018 Hugo Levy-Falk
|
||||
#
|
||||
# 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.
|
||||
from django.db import models
|
||||
from django.utils.translation import ugettext_lazy as _
|
||||
from django.contrib import messages
|
||||
|
||||
|
||||
from cotisations.models import Paiement
|
||||
from cotisations.payment_methods.mixins import PaymentMethodMixin
|
||||
|
||||
|
||||
class FreePayment(PaymentMethodMixin, models.Model):
|
||||
"""
|
||||
The model allowing you to bypass payment if the invoice is free.
|
||||
"""
|
||||
|
||||
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."))
|
|
@ -29,5 +29,4 @@ class PaymentMethodMixin:
|
|||
|
||||
Must return a HttpResponse-like object.
|
||||
"""
|
||||
return self.payment.end_payment(
|
||||
invoice, request, use_payment_method=False)
|
||||
return self.payment.end_payment(invoice, request, use_payment_method=False)
|
||||
|
|
|
@ -22,5 +22,6 @@
|
|||
This module contains a method to pay online using comnpay.
|
||||
"""
|
||||
from . import models, urls
|
||||
|
||||
NAME = "NOTE"
|
||||
PaymentMethod = models.NotePayment
|
||||
|
|
|
@ -24,15 +24,11 @@ from django.utils.translation import ugettext_lazy as _
|
|||
|
||||
from cotisations.utils import find_payment_method
|
||||
|
||||
|
||||
class NoteCredentialForm(forms.Form):
|
||||
"""A special form to get credential to connect to a NoteKfet2015 server throught his API
|
||||
object.
|
||||
"""
|
||||
login = forms.CharField(
|
||||
label=_("pseudo note")
|
||||
)
|
||||
password = forms.CharField(
|
||||
label=_("Password"),
|
||||
widget=forms.PasswordInput
|
||||
)
|
||||
|
||||
login = forms.CharField(label=_("Username"))
|
||||
password = forms.CharField(label=_("Password"), widget=forms.PasswordInput)
|
||||
|
|
|
@ -41,25 +41,17 @@ class NotePayment(PaymentMethodMixin, models.Model):
|
|||
|
||||
payment = models.OneToOneField(
|
||||
Paiement,
|
||||
on_delete = models.CASCADE,
|
||||
related_name = 'payment_method',
|
||||
editable = False
|
||||
)
|
||||
server = models.CharField(
|
||||
max_length=255,
|
||||
verbose_name=_("server")
|
||||
)
|
||||
port = models.PositiveIntegerField(
|
||||
blank = True,
|
||||
null = True
|
||||
)
|
||||
id_note = models.PositiveIntegerField(
|
||||
blank = True,
|
||||
null = True
|
||||
on_delete=models.CASCADE,
|
||||
related_name="payment_method_note",
|
||||
editable=False,
|
||||
)
|
||||
server = models.CharField(max_length=255, verbose_name=_("server"))
|
||||
port = models.PositiveIntegerField(blank=True, null=True)
|
||||
id_note = models.PositiveIntegerField(blank=True, null=True)
|
||||
|
||||
def end_payment(self, invoice, request):
|
||||
return redirect(reverse(
|
||||
'cotisations:note_kfet:note_payment',
|
||||
kwargs={'factureid': invoice.id}
|
||||
))
|
||||
return redirect(
|
||||
reverse(
|
||||
"cotisations:note_kfet:note_payment", kwargs={"factureid": invoice.id}
|
||||
)
|
||||
)
|
||||
|
|
|
@ -12,13 +12,14 @@ import traceback
|
|||
|
||||
|
||||
def get_response(socket):
|
||||
length_str = b''
|
||||
length_str = b""
|
||||
char = socket.recv(1)
|
||||
while char != b'\n':
|
||||
while char != b"\n":
|
||||
length_str += char
|
||||
char = socket.recv(1)
|
||||
total = int(length_str)
|
||||
return json.loads(socket.recv(total).decode('utf-8'))
|
||||
return json.loads(socket.recv(total).decode("utf-8"))
|
||||
|
||||
|
||||
def connect(server, port):
|
||||
sock = socket.socket()
|
||||
|
@ -35,7 +36,8 @@ def connect(server, port):
|
|||
return (False, sock, "Serveur indisponible")
|
||||
return (True, sock, "")
|
||||
|
||||
def login(server, port, username, password, masque = [[], [], True]):
|
||||
|
||||
def login(server, port, username, password, masque=[[], [], True]):
|
||||
result, sock, err = connect(server, port)
|
||||
if not result:
|
||||
return (False, None, err)
|
||||
|
@ -43,7 +45,7 @@ def login(server, port, username, password, masque = [[], [], True]):
|
|||
commande = ["login", [username, password, "bdd", masque]]
|
||||
sock.send(json.dumps(commande).encode("utf-8"))
|
||||
response = get_response(sock)
|
||||
retcode = response['retcode']
|
||||
retcode = response["retcode"]
|
||||
if retcode == 0:
|
||||
return (True, sock, "")
|
||||
elif retcode == 5:
|
||||
|
@ -60,11 +62,28 @@ def don(sock, montant, id_note, facture):
|
|||
Faire faire un don à l'id_note
|
||||
"""
|
||||
try:
|
||||
sock.send(json.dumps(["dons", [[id_note], round(montant*100), "Facture : id=%s, designation=%s" % (facture.id, facture.name())]]).encode("utf-8"))
|
||||
sock.send(
|
||||
json.dumps(
|
||||
[
|
||||
"dons",
|
||||
[
|
||||
[id_note],
|
||||
round(montant * 100),
|
||||
"Facture : id=%s, designation=%s"
|
||||
% (facture.id, facture.name()),
|
||||
],
|
||||
]
|
||||
).encode("utf-8")
|
||||
)
|
||||
response = get_response(sock)
|
||||
retcode = response['retcode']
|
||||
retcode = response["retcode"]
|
||||
transaction_retcode = response["msg"][0][0]
|
||||
if 0 < retcode < 100 or 200 <= retcode or 0 < transaction_retcode < 100 or 200 <= transaction_retcode:
|
||||
if (
|
||||
0 < retcode < 100
|
||||
or 200 <= retcode
|
||||
or 0 < transaction_retcode < 100
|
||||
or 200 <= transaction_retcode
|
||||
):
|
||||
return (False, "Transaction échouée. (Solde trop négatif ?)")
|
||||
elif retcode == 0:
|
||||
return (True, "")
|
||||
|
|
|
@ -23,8 +23,6 @@ from . import views
|
|||
|
||||
urlpatterns = [
|
||||
url(
|
||||
r'^note_payment/(?P<factureid>[0-9]+)$',
|
||||
views.note_payment,
|
||||
name='note_payment'
|
||||
),
|
||||
r"^note_payment/(?P<factureid>[0-9]+)$", views.note_payment, name="note_payment"
|
||||
)
|
||||
]
|
||||
|
|
|
@ -39,13 +39,11 @@ from cotisations.models import Facture
|
|||
from cotisations.utils import find_payment_method
|
||||
from .models import NotePayment
|
||||
from re2o.views import form
|
||||
from re2o.acl import (
|
||||
can_create,
|
||||
can_edit
|
||||
)
|
||||
from re2o.acl import can_create, can_edit
|
||||
from .note import login, don
|
||||
from .forms import NoteCredentialForm
|
||||
|
||||
|
||||
@login_required
|
||||
@can_edit(Facture)
|
||||
def note_payment(request, facture, factureid):
|
||||
|
@ -58,40 +56,38 @@ def note_payment(request, facture, factureid):
|
|||
payment_method = find_payment_method(facture.paiement)
|
||||
if not payment_method or not isinstance(payment_method, NotePayment):
|
||||
messages.error(request, _("Unknown error."))
|
||||
return redirect(reverse(
|
||||
'users:profil',
|
||||
kwargs={'userid': user.id}
|
||||
))
|
||||
return redirect(reverse("users:profil", kwargs={"userid": user.id}))
|
||||
noteform = NoteCredentialForm(request.POST or None)
|
||||
if noteform.is_valid():
|
||||
pseudo = noteform.cleaned_data['login']
|
||||
password = noteform.cleaned_data['password']
|
||||
result, sock, err = login(payment_method.server, payment_method.port, pseudo, password)
|
||||
pseudo = noteform.cleaned_data["login"]
|
||||
password = noteform.cleaned_data["password"]
|
||||
result, sock, err = login(
|
||||
payment_method.server, payment_method.port, pseudo, password
|
||||
)
|
||||
if not result:
|
||||
messages.error(request, err)
|
||||
return form(
|
||||
{'form': noteform, 'amount': facture.prix_total()},
|
||||
{"form": noteform, "amount": facture.prix_total()},
|
||||
"cotisations/payment.html",
|
||||
request
|
||||
request,
|
||||
)
|
||||
else:
|
||||
result, err = don(sock, facture.prix_total(), payment_method.id_note, facture)
|
||||
result, err = don(
|
||||
sock, facture.prix_total(), payment_method.id_note, facture
|
||||
)
|
||||
if not result:
|
||||
messages.error(request, err)
|
||||
return form(
|
||||
{'form': noteform, 'amount': facture.prix_total()},
|
||||
{"form": noteform, "amount": facture.prix_total()},
|
||||
"cotisations/payment.html",
|
||||
request
|
||||
request,
|
||||
)
|
||||
facture.valid = True
|
||||
facture.save()
|
||||
messages.success(request, _("The payment with note was done."))
|
||||
return redirect(reverse(
|
||||
'users:profil',
|
||||
kwargs={'userid': user.id}
|
||||
))
|
||||
return redirect(reverse("users:profil", kwargs={"userid": user.id}))
|
||||
return form(
|
||||
{'form': noteform, 'amount': facture.prix_total()},
|
||||
"cotisations/payment.html",
|
||||
request
|
||||
)
|
||||
{"form": noteform, "amount": facture.prix_total()},
|
||||
"cotisations/payment.html",
|
||||
request,
|
||||
)
|
||||
|
|
|
@ -22,7 +22,7 @@ from django.conf.urls import include, url
|
|||
from . import comnpay, cheque, note_kfet
|
||||
|
||||
urlpatterns = [
|
||||
url(r'^comnpay/', include(comnpay.urls, namespace='comnpay')),
|
||||
url(r'^cheque/', include(cheque.urls, namespace='cheque')),
|
||||
url(r'^note_kfet/', include(note_kfet.urls, namespace='note_kfet')),
|
||||
url(r"^comnpay/", include(comnpay.urls, namespace="comnpay")),
|
||||
url(r"^cheque/", include(cheque.urls, namespace="cheque")),
|
||||
url(r"^note_kfet/", include(note_kfet.urls, namespace="note_kfet")),
|
||||
]
|
||||
|
|
|
@ -4,7 +4,7 @@ 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 Lara Kermarec
|
||||
Copyright © 2017 Augustin Lemesle
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
|
@ -34,6 +34,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
|
|||
<th>{% trans "Price" %}</th>
|
||||
<th>{% trans "Subscription type" %}</th>
|
||||
<th>{% trans "Duration (in months)" %}</th>
|
||||
<th>{% trans "Duration (in days)" %}</th>
|
||||
<th>{% trans "Concerned users" %}</th>
|
||||
<th>{% trans "Available for everyone" %}</th>
|
||||
<th></th>
|
||||
|
@ -45,6 +46,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
|
|||
<td>{{ article.prix }}</td>
|
||||
<td>{{ article.type_cotisation }}</td>
|
||||
<td>{{ article.duration }}</td>
|
||||
<td>{{ article.duration_days }}</td>
|
||||
<td>{{ article.type_user }}</td>
|
||||
<td>{{ article.available_for_everyone | tick }}</td>
|
||||
<td class="text-right">
|
||||
|
|
|
@ -4,7 +4,7 @@ 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 Lara Kermarec
|
||||
Copyright © 2017 Augustin Lemesle
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
|
|
|
@ -4,7 +4,7 @@ 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 Lara Kermarec
|
||||
Copyright © 2017 Augustin Lemesle
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
|
|
|
@ -4,7 +4,7 @@ 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 Lara Kermarec
|
||||
Copyright © 2017 Augustin Lemesle
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
|
@ -31,7 +31,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
|
|||
<thead>
|
||||
<tr>
|
||||
<th>{% trans "Payment type" %}</th>
|
||||
<th>{% trans "Is available for everyone" %}</th>
|
||||
<th>{% trans "Available for everyone" %}</th>
|
||||
<th>{% trans "Custom payment method" %}</th>
|
||||
<th></th>
|
||||
</tr>
|
||||
|
|
|
@ -5,7 +5,7 @@ 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 Lara Kermarec
|
||||
Copyright © 2017 Augustin Lemesle
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
|
@ -45,12 +45,12 @@ with this program; if not, write to the Free Software Foundation, Inc.,
|
|||
<tr>
|
||||
<th>{% trans "Profile" %}</th>
|
||||
<th>
|
||||
{% trans "Last name" as tr_last_name %}
|
||||
{% include 'buttons/sort.html' with prefix='control' col='name' text=tr_last_name %}
|
||||
{% trans "First name" as tr_first_name %}
|
||||
{% include 'buttons/sort.html' with prefix='control' col='name' text=tr_first_name %}
|
||||
</th>
|
||||
<th>
|
||||
{% trans "First name" as tr_first_name %}
|
||||
{% include 'buttons/sort.html' with prefix='control' col='surname' text=tr_first_name %}
|
||||
{% trans "Surname" as tr_surname %}
|
||||
{% include 'buttons/sort.html' with prefix='control' col='surname' text=tr_surname %}
|
||||
</th>
|
||||
<th>
|
||||
{% trans "Invoice ID" as tr_invoice_id %}
|
||||
|
@ -104,8 +104,8 @@ with this program; if not, write to the Free Software Foundation, Inc.,
|
|||
</tr>
|
||||
{% endfor %}
|
||||
</table>
|
||||
{% trans "Edit" as tr_edit %}
|
||||
{% bootstrap_button tr_edit button_type='submit' icon='ok' button_class='btn-success' %}
|
||||
{% trans "Confirm" as tr_confirm %}
|
||||
{% bootstrap_button tr_confirm button_type='submit' icon='ok' button_class='btn-success' %}
|
||||
</form>
|
||||
|
||||
{% endblock %}
|
||||
|
|
|
@ -5,7 +5,7 @@ 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 Lara Kermarec
|
||||
Copyright © 2017 Augustin Lemesle
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
|
@ -33,7 +33,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
|
|||
<form class="form" method="post">
|
||||
{% csrf_token %}
|
||||
<h4>
|
||||
{% blocktrans %}Warning: are you sure you really want to delete this {{ object_name }} object ( {{ objet }} )?{% endblocktrans %}
|
||||
{% blocktrans %}Warning: are you sure you really want to delete this {{ objet_name }} object ( {{ objet }} )?{% endblocktrans %}
|
||||
</h4>
|
||||
{% trans "Confirm" as tr_confirm %}
|
||||
{% bootstrap_button tr_confirm button_type='submit' icon='trash' button_class='btn-danger' %}
|
||||
|
|
|
@ -5,7 +5,7 @@ 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 Lara Kermarec
|
||||
Copyright © 2017 Augustin Lemesle
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
|
|
|
@ -6,17 +6,17 @@ Nous vous remercions pour votre achat auprès de {{asso_name}} et nous vous en j
|
|||
|
||||
En cas de question, n’hésitez pas à nous contacter par mail à {{contact_mail}}.
|
||||
|
||||
Cordialement,
|
||||
L’équipe de {{asso_name}}
|
||||
Respectueusement,
|
||||
L’équipe de {{asso_name}}.
|
||||
|
||||
|
||||
=== English version ===
|
||||
|
||||
Dear {{name}},
|
||||
Hello {{name}},
|
||||
|
||||
Thank you for your purchase. Here is your invoice.
|
||||
Thank you for your purchase at {{asso_name}}. Here is your invoice.
|
||||
|
||||
Should you need extra information, you can email us at {{contact_mail}}.
|
||||
Should you need extra information, do not hesitate to email us at {{contact_mail}}.
|
||||
|
||||
Best regards,
|
||||
{{ asso_name }}'s team
|
||||
Regards,
|
||||
The {{ asso_name }} team.
|
||||
|
|
|
@ -1,22 +1,23 @@
|
|||
Bonjour {{name}} !
|
||||
|
||||
Nous vous informons que votre cotisation auprès de {{asso_name}} a été acceptée. Vous voilà donc membre de l'association.
|
||||
Nous vous informons que votre cotisation auprès de {{asso_name}} a été acceptée. Vous voilà donc membre de l'association jusqu'au {{ date_end|date:"d/m/Y" }}.
|
||||
|
||||
Vous trouverez en pièce jointe un reçu.
|
||||
|
||||
Pour nous faire part de toute remarque, suggestion ou problème vous pouvez nous envoyer un mail à {{asso_email}}.
|
||||
|
||||
À bientôt,
|
||||
Respectueusement,
|
||||
L'équipe de {{asso_name}}.
|
||||
|
||||
---
|
||||
|
||||
Your subscription to {{asso_name}} has just been accepted. You are now a full member of {{asso_name}}.
|
||||
Hello {{name}}!
|
||||
|
||||
Your subscription to {{asso_name}} has just been accepted. You are now a full member of {{asso_name}} until {{ date_end|date:"d/m/Y" }}.
|
||||
|
||||
You will find with this email a subscription voucher.
|
||||
|
||||
For any information, suggestion or problem, you can contact us via email at
|
||||
{{asso_email}}.
|
||||
To express any comment, suggestion or problem, you can send us an email to {{asso_email}}.
|
||||
|
||||
Regards,
|
||||
The {{asso_name}} team.
|
||||
|
|
|
@ -5,7 +5,7 @@ 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 Lara Kermarec
|
||||
Copyright © 2017 Augustin Lemesle
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
|
@ -44,9 +44,6 @@ with this program; if not, write to the Free Software Foundation, Inc.,
|
|||
{% blocktrans %}Current balance: {{ balance }} €{% endblocktrans %}
|
||||
</p>
|
||||
{% endif %}
|
||||
{% if factureform %}
|
||||
{% bootstrap_form_errors factureform %}
|
||||
{% endif %}
|
||||
{% if discount_form %}
|
||||
{% bootstrap_form_errors discount_form %}
|
||||
{% endif %}
|
||||
|
@ -90,7 +87,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
|
|||
{% if articlesformset %}
|
||||
var prices = {};
|
||||
{% for article in articlelist %}
|
||||
prices[{{ article.id|escapejs }}] = {{ article.prix }};
|
||||
prices[{{ article.id|escapejs }}] = "{{ article.prix }}";
|
||||
{% endfor %}
|
||||
|
||||
var template = `Article :
|
||||
|
@ -124,7 +121,7 @@ function update_price(){
|
|||
if (article == '') {
|
||||
continue;
|
||||
}
|
||||
article_price = prices[article];
|
||||
article_price = parseFloat(prices[article].replace(',', '.'));
|
||||
quantity = document.getElementById(
|
||||
'id_form-' + i.toString() + '-quantity').value;
|
||||
price += article_price * quantity;
|
||||
|
|
|
@ -5,7 +5,7 @@ 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 Lara Kermarec
|
||||
Copyright © 2017 Augustin Lemesle
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
|
|
|
@ -5,7 +5,7 @@ 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 Lara Kermarec
|
||||
Copyright © 2017 Augustin Lemesle
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
|
@ -30,14 +30,14 @@ with this program; if not, write to the Free Software Foundation, Inc.,
|
|||
{% block title %}{% trans "Articles" %}{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
<h2>{% trans "List of article types" %}</h2>
|
||||
<h2>{% trans "List of articles" %}</h2>
|
||||
{% can_create Article %}
|
||||
<a class="btn btn-primary btn-sm" role="button" href="{% url 'cotisations:add-article' %}">
|
||||
<i class="fa fa-cart-plus"></i> {% trans "Add an article type" %}
|
||||
<i class="fa fa-plus"></i> {% trans "Add an article" %}
|
||||
</a>
|
||||
{% acl_end %}
|
||||
<a class="btn btn-danger btn-sm" role="button" href="{% url 'cotisations:del-article' %}">
|
||||
<i class="fa fa-trash"></i> {% trans "Delete one or several article types" %}
|
||||
<i class="fa fa-trash"></i> {% trans "Delete one or several articles" %}
|
||||
</a>
|
||||
{% include 'cotisations/aff_article.html' with article_list=article_list %}
|
||||
{% endblock %}
|
||||
|
|
|
@ -5,7 +5,7 @@ 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 Lara Kermarec
|
||||
Copyright © 2017 Augustin Lemesle
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
|
@ -33,7 +33,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
|
|||
<h2>{% trans "List of banks" %}</h2>
|
||||
{% can_create Banque %}
|
||||
<a class="btn btn-primary btn-sm" role="button" href="{% url 'cotisations:add-banque' %}">
|
||||
<i class="fa fa-cart-plus"></i> {% trans "Add a bank" %}
|
||||
<i class="fa fa-plus"></i> {% trans "Add a bank" %}
|
||||
</a>
|
||||
{% acl_end %}
|
||||
<a class="btn btn-danger btn-sm" role="button" href="{% url 'cotisations:del-banque' %}">
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue