8
0
Fork 0
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:
Hugo Levy-Falk 2019-12-28 13:04:04 +01:00
commit 56fdfca1aa
759 changed files with 27074 additions and 16710 deletions

View file

@ -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;
```

View file

@ -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,),
)

View file

@ -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."))

View file

@ -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é."

View file

@ -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):

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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))]

View file

@ -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}
)

View file

@ -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

View 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

View file

@ -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

View file

@ -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",),
)

View file

@ -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

View file

@ -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

View file

@ -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
),
),
]

View file

@ -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")]

View file

@ -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,
),
)
]

View file

@ -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),
),
]

View file

@ -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),
),
)
]

View file

@ -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
),
),
]

View file

@ -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,
),

View file

@ -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
),
),
]

View file

@ -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")]

View file

@ -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
),
),
]

View file

@ -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()
)
]

View file

@ -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"
),
)
]

View file

@ -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
),
),
]

View file

@ -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,
),

View file

@ -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)]
),
),
]

View file

@ -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,
),
]

View file

@ -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),
),
]

View file

@ -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,
),
)
]

View file

@ -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
),
)
]

View file

@ -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
),
)
]

View file

@ -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),
)
]

View file

@ -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
),
)
]

View file

@ -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),
)
]

View file

@ -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
),
),
]

View file

@ -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,
),
)
]

View file

@ -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"),
]

View file

@ -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)
)
]

View file

@ -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"),
)
},
),
]

View file

@ -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",
),
),
]

View file

@ -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"),
]

View file

@ -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)",
),
)
]

View file

@ -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",
},
),
]

View file

@ -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",
),
),
]

View file

@ -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"),
)
]

View file

@ -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),
),
)
]

View file

@ -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"),
)
]

View file

@ -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",),
)
]

View file

@ -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"),
),
]

View 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),
)
]

View 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)",
),
),
]

View 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",
),
),
]

View 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'),
),
]

View file

@ -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

View file

@ -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]

View file

@ -22,6 +22,7 @@
This module contains a method to pay online using user balance.
"""
from . import models
NAME = "BALANCE"
PaymentMethod = models.BalancePayment

View file

@ -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

View file

@ -22,6 +22,7 @@
This module contains a method to pay online using cheque.
"""
from . import models, urls, views
NAME = "CHEQUE"
PaymentMethod = models.ChequePayment

View file

@ -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"]

View file

@ -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})
)

View file

@ -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")]

View file

@ -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()},
)

View file

@ -22,5 +22,6 @@
This module contains a method to pay online using comnpay.
"""
from . import models, urls, views
NAME = "COMNPAY"
PaymentMethod = models.ComnpayPayment

View file

@ -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

View file

@ -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),
)

View file

@ -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"),
]

View file

@ -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")

View file

@ -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()

View file

@ -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

View 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."))

View file

@ -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)

View file

@ -22,5 +22,6 @@
This module contains a method to pay online using comnpay.
"""
from . import models, urls
NAME = "NOTE"
PaymentMethod = models.NotePayment

View file

@ -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)

View file

@ -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}
)
)

View file

@ -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, "")

View file

@ -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"
)
]

View file

@ -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,
)

View file

@ -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")),
]

View file

@ -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">

View file

@ -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

View file

@ -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

View file

@ -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>

View file

@ -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 %}

View file

@ -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' %}

View file

@ -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

View file

@ -6,17 +6,17 @@ Nous vous remercions pour votre achat auprès de {{asso_name}} et nous vous en j
En cas de question, nhé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.

View file

@ -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.

View file

@ -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 : &nbsp;
@ -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;

View file

@ -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

View file

@ -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 %}

View file

@ -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