diff --git a/kfet/forms.py b/kfet/forms.py index 729ba9e2..61d4e525 100644 --- a/kfet/forms.py +++ b/kfet/forms.py @@ -1,6 +1,7 @@ from django import forms from django.contrib.auth.models import User -from kfet.models import Account, Checkout, Article +from django.forms import modelformset_factory +from kfet.models import Account, Checkout, Article, OperationGroup, Operation from gestioncof.models import CofProfile # ----- @@ -107,3 +108,41 @@ class ArticleForm(forms.ModelForm): class ArticleRestrictForm(ArticleForm): class Meta(ArticleForm.Meta): fields = ['name', 'is_sold', 'price', 'category'] + +# ----- +# K-Psul forms +# ----- + +class KPsulOperationGroupForm(forms.ModelForm): + class Meta: + model = OperationGroup + fields = ['on_acc', 'checkout'] + widgets = { + 'on_acc' : forms.HiddenInput(), + 'checkout': forms.HiddenInput(), + } + +class KPsulAccountForm(forms.ModelForm): + class Meta: + model = Account + fields = ['trigramme'] + widgets = { + 'trigramme': forms.TextInput(attrs={'autocomplete': 'off'}), + } + +class KPsulCheckoutForm(forms.Form): + checkout = forms.ModelChoiceField( + queryset=Checkout.objects.filter(is_protected=False), + widget=forms.Select(attrs={'id':'id_checkout_select'})) + +class KPsulOperationForm(forms.ModelForm): + class Meta: + model = Operation + fields = ['type', 'amount', 'is_checkout', 'article', 'article_nb'] +""" +OperationFormSet = modelformset_factory( + Operation, + form = KPsulOperationForm, + extra = 0, + min_num = 1, validate_min = True) +""" diff --git a/kfet/migrations/0009_auto_20160805_0720.py b/kfet/migrations/0009_auto_20160805_0720.py new file mode 100644 index 00000000..8e9a4db9 --- /dev/null +++ b/kfet/migrations/0009_auto_20160805_0720.py @@ -0,0 +1,24 @@ +# -*- coding: utf-8 -*- +from __future__ import unicode_literals + +from django.db import models, migrations + + +class Migration(migrations.Migration): + + dependencies = [ + ('kfet', '0008_auto_20160804_1736'), + ] + + operations = [ + migrations.RenameField( + model_name='operation', + old_name='on_checkout', + new_name='is_checkout', + ), + migrations.AddField( + model_name='operation', + name='article_nb', + field=models.PositiveSmallIntegerField(default=None, null=True, blank=True), + ), + ] diff --git a/kfet/models.py b/kfet/models.py index ad51383a..0e3af79b 100644 --- a/kfet/models.py +++ b/kfet/models.py @@ -355,7 +355,9 @@ class OperationGroup(models.Model): Checkout, on_delete = models.PROTECT, related_name = "operations") at = models.DateTimeField(auto_now_add = True) - amount = models.IntegerField() + amount = models.DecimalField( + max_digits = 6, decimal_places = 2, + default = 0) is_cof = models.BooleanField(default = False) # Optional comment = models.CharField( @@ -364,7 +366,7 @@ class OperationGroup(models.Model): valid_by = models.ForeignKey( Account, on_delete = models.PROTECT, related_name = "+", - blank = True, null = True, default = True) + blank = True, null = True, default = None) class Operation(models.Model): PURCHASE = 'purchase' @@ -384,12 +386,14 @@ class Operation(models.Model): choices = TYPE_ORDER_CHOICES, max_length = choices_length(TYPE_ORDER_CHOICES)) amount = models.DecimalField(max_digits = 6, decimal_places = 2) - on_checkout = models.BooleanField(default = True) + is_checkout = models.BooleanField(default = True) # Optional article = models.ForeignKey( Article, on_delete = models.PROTECT, related_name = "operations", blank = True, null = True, default = None) + article_nb = models.PositiveSmallIntegerField( + blank = True, null = True, default = None) canceled_by = models.ForeignKey( Account, on_delete = models.PROTECT, related_name = "+", @@ -400,7 +404,9 @@ class Operation(models.Model): Account, on_delete = models.PROTECT, related_name = "addcosts", blank = True, null = True, default = None) - addcost_amount = models.DecimalField(max_digits = 6, decimal_places = 2) + addcost_amount = models.DecimalField( + max_digits = 6, decimal_places = 2, + default = 0) class GlobalPermissions(models.Model): class Meta: diff --git a/kfet/static/kfet/js.cookie.js b/kfet/static/kfet/js.cookie.js new file mode 100644 index 00000000..7f3dffde --- /dev/null +++ b/kfet/static/kfet/js.cookie.js @@ -0,0 +1,151 @@ +/*! + * JavaScript Cookie v2.1.2 + * https://github.com/js-cookie/js-cookie + * + * Copyright 2006, 2015 Klaus Hartl & Fagner Brack + * Released under the MIT license + */ +;(function (factory) { + if (typeof define === 'function' && define.amd) { + define(factory); + } else if (typeof exports === 'object') { + module.exports = factory(); + } else { + var OldCookies = window.Cookies; + var api = window.Cookies = factory(); + api.noConflict = function () { + window.Cookies = OldCookies; + return api; + }; + } +}(function () { + function extend () { + var i = 0; + var result = {}; + for (; i < arguments.length; i++) { + var attributes = arguments[ i ]; + for (var key in attributes) { + result[key] = attributes[key]; + } + } + return result; + } + + function init (converter) { + function api (key, value, attributes) { + var result; + if (typeof document === 'undefined') { + return; + } + + // Write + + if (arguments.length > 1) { + attributes = extend({ + path: '/' + }, api.defaults, attributes); + + if (typeof attributes.expires === 'number') { + var expires = new Date(); + expires.setMilliseconds(expires.getMilliseconds() + attributes.expires * 864e+5); + attributes.expires = expires; + } + + try { + result = JSON.stringify(value); + if (/^[\{\[]/.test(result)) { + value = result; + } + } catch (e) {} + + if (!converter.write) { + value = encodeURIComponent(String(value)) + .replace(/%(23|24|26|2B|3A|3C|3E|3D|2F|3F|40|5B|5D|5E|60|7B|7D|7C)/g, decodeURIComponent); + } else { + value = converter.write(value, key); + } + + key = encodeURIComponent(String(key)); + key = key.replace(/%(23|24|26|2B|5E|60|7C)/g, decodeURIComponent); + key = key.replace(/[\(\)]/g, escape); + + return (document.cookie = [ + key, '=', value, + attributes.expires && '; expires=' + attributes.expires.toUTCString(), // use expires attribute, max-age is not supported by IE + attributes.path && '; path=' + attributes.path, + attributes.domain && '; domain=' + attributes.domain, + attributes.secure ? '; secure' : '' + ].join('')); + } + + // Read + + if (!key) { + result = {}; + } + + // To prevent the for loop in the first place assign an empty array + // in case there are no cookies at all. Also prevents odd result when + // calling "get()" + var cookies = document.cookie ? document.cookie.split('; ') : []; + var rdecode = /(%[0-9A-Z]{2})+/g; + var i = 0; + + for (; i < cookies.length; i++) { + var parts = cookies[i].split('='); + var cookie = parts.slice(1).join('='); + + if (cookie.charAt(0) === '"') { + cookie = cookie.slice(1, -1); + } + + try { + var name = parts[0].replace(rdecode, decodeURIComponent); + cookie = converter.read ? + converter.read(cookie, name) : converter(cookie, name) || + cookie.replace(rdecode, decodeURIComponent); + + if (this.json) { + try { + cookie = JSON.parse(cookie); + } catch (e) {} + } + + if (key === name) { + result = cookie; + break; + } + + if (!key) { + result[name] = cookie; + } + } catch (e) {} + } + + return result; + } + + api.set = api; + api.get = function (key) { + return api(key); + }; + api.getJSON = function () { + return api.apply({ + json: true + }, [].slice.call(arguments)); + }; + api.defaults = {}; + + api.remove = function (key, attributes) { + api(key, '', extend(attributes, { + expires: -1 + })); + }; + + api.withConverter = init; + + return api; + } + + return init(function () {}); +})); diff --git a/kfet/templates/kfet/kpsul.html b/kfet/templates/kfet/kpsul.html new file mode 100644 index 00000000..a33c55a3 --- /dev/null +++ b/kfet/templates/kfet/kpsul.html @@ -0,0 +1,214 @@ +{% extends 'kfet/base.html' %} +{% load staticfiles %} + +{% block extra_head %} + +{% endblock %} + +{% block title %}K-Psul{% endblock %} + +{% block content %} + +{% csrf_token %} + +
{{ operationgroup_form }}
+ +{{ trigramme_form.as_p }} +
+

+

+

+

+

+

+

+

+
+ +{{ checkout_form.as_p }} +
+

+

+

+

+
+ +
+ {{ operation_formset.as_p }} +
+ + + + + +{% endblock %} diff --git a/kfet/urls.py b/kfet/urls.py index e32f7119..43701ef6 100644 --- a/kfet/urls.py +++ b/kfet/urls.py @@ -78,4 +78,16 @@ urlpatterns = [ url('^article/(?P\d+)/edit$', permission_required('kfet.is_team')(views.ArticleUpdate.as_view()), name = 'kfet.article.update'), + + # ----- + # K-Psul urls + # ----- + + url('^k-psul/$', views.kpsul, name = 'kfet.kpsul'), + url('^k-psul/account_data$', views.kpsul_account_data, + name = 'kfet.kpsul.account_data'), + url('^k-psul/checkout_data$', views.kpsul_checkout_data, + name = 'kfet.kpsul.checkout_data'), + url('^k-psul/perform_operations$', views.kpsul_perform_operations, + name = 'kfet.kpsul.perform_operations'), ] diff --git a/kfet/views.py b/kfet/views.py index 41cc1dee..b7d6cdde 100644 --- a/kfet/views.py +++ b/kfet/views.py @@ -7,11 +7,12 @@ from django.contrib import messages from django.contrib.messages.views import SuccessMessageMixin from django.contrib.auth.decorators import login_required, permission_required from django.contrib.auth.models import User -from django.http import HttpResponse, Http404 -import json +from django.http import HttpResponse, JsonResponse, Http404 +from django.forms import modelformset_factory from gestioncof.models import CofProfile, Clipper from kfet.models import Account, Checkout, Article from kfet.forms import * +from collections import defaultdict @login_required def home(request): @@ -40,7 +41,7 @@ def account_is_validandfree_ajax(request): raise Http404 trigramme = request.GET.get("trigramme") data = Account.is_validandfree(trigramme) - return HttpResponse(json.dumps(data), content_type = 'application/json') + return JsonResponse(data) # Account - Create @@ -349,3 +350,74 @@ class ArticleUpdate(UpdateView): raise PermissionDenied # Updating return super(ArticleUpdate, self).form_valid(form) + +# ----- +# K-Psul +# ----- + +@permission_required('kfet.is_team') +def kpsul(request): + data = {} + data['operationgroup_form'] = KPsulOperationGroupForm() + data['trigramme_form'] = KPsulAccountForm() + data['checkout_form'] = KPsulCheckoutForm() + OperationFormSet = modelformset_factory( + Operation, + form = KPsulOperationForm, + extra = 0, + min_num = 1, validate_min = True) + operation_formset = OperationFormSet(queryset=Operation.objects.none()) + data['operation_formset'] = operation_formset + return render(request, 'kfet/kpsul.html', data) + +@permission_required('kfet.is_team') +def kpsul_account_data(request): + trigramme = request.POST.get('trigramme', '') + account = get_object_or_404(Account, trigramme=trigramme) + data = { 'pk': account.pk, 'name': account.name, 'email': account.email, + 'is_cof': account.is_cof, 'promo': account.promo, + 'balance': account.balance, 'is_frozen': account.is_frozen, + 'departement': account.departement, 'nickname': account.nickname } + return JsonResponse(data) + +@permission_required('kfet.is_team') +def kpsul_checkout_data(request): + pk = request.POST.get('pk', 0) + checkout = get_object_or_404(Checkout, pk=pk) + data = { 'pk': checkout.pk, 'name': checkout.name, 'balance': checkout.balance, + 'valid_from': checkout.valid_from, 'valid_to': checkout.valid_to } + return JsonResponse(data) + +@permission_required('kfet.is_team') +def kpsul_perform_operations(request): + # Initializing + data = defaultdict(list) + + # Checking operationgroup data + try: + account_pk = request.POST.get('on_acc', 0) + account = Account.objects.get(pk=account_pk) + except (Account.DoesNotExist, ValueError): + data['errors'].append('Trigramme invalide') + try: + checkout_pk = request.POST.get('checkout', 0) + checkout = Checkout.objects.get(pk=checkout_pk) + except (Checkout.DoesNotExist, ValueError): + data['errors'].append('Caisse invalide') + if 'errors' in data: + return JsonResponse(data, status=400) + + operationgroup_form = KPsulOperationGroupForm(request.POST) + operationgroup = operationgroup_form.save(commit = False) + operation_formset = OperationFormSet(request.POST) + operations = operation_formset.save(commit = False) + for operation in operations: + operationgroup.amount += operation.amount + operationgroup.save() + data['operationgroup'] = operationgroup.pk + for operation in operations: + operation.group = operationgroup + operation.save() + data['operations'].append(operation.pk) + + return JsonResponse(data)