Sith/launderette/views.py

442 lines
18 KiB
Python
Raw Normal View History

# -*- coding:utf-8 -*
#
# Copyright 2016,2017
# - Skia <skia@libskia.so>
#
# Ce fichier fait partie du site de l'Association des Étudiants de l'UTBM,
# http://ae.utbm.fr.
#
# This program is free software; you can redistribute it and/or modify it under
# the terms of the GNU General Public License a published by the Free Software
# Foundation; either version 3 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 Sofware Foundation, Inc., 59 Temple
# Place - Suite 330, Boston, MA 02111-1307, USA.
#
#
2016-07-28 23:38:46 +00:00
from datetime import datetime, timedelta
from collections import OrderedDict
import pytz
2016-07-28 23:38:46 +00:00
2017-06-12 07:59:44 +00:00
from django.views.generic import ListView, DetailView, TemplateView
from django.views.generic.edit import UpdateView, CreateView, DeleteView, BaseFormView
2016-07-28 18:05:56 +00:00
from django.utils.translation import ugettext as _
2016-09-11 17:00:12 +00:00
from django.utils import dateparse, timezone
from django.core.urlresolvers import reverse_lazy
2016-07-28 18:05:56 +00:00
from django.conf import settings
2016-08-06 13:20:38 +00:00
from django.db import transaction, DataError
from django import forms
from django.template import defaultfilters
2016-07-28 18:05:56 +00:00
2016-12-11 15:22:16 +00:00
from core.models import Page, User
from club.models import Club
2016-07-28 18:05:56 +00:00
from core.views import CanViewMixin, CanEditMixin, CanEditPropMixin, CanCreateMixin
from launderette.models import Launderette, Token, Machine, Slot
2016-08-01 22:32:55 +00:00
from counter.models import Counter, Customer, Selling
from counter.views import GetUserForm
2016-07-28 18:05:56 +00:00
# For users
2017-06-12 07:59:44 +00:00
2016-07-28 18:05:56 +00:00
class LaunderetteMainView(TemplateView):
"""Main presentation view"""
template_name = 'launderette/launderette_main.jinja'
def get_context_data(self, **kwargs):
""" Add page to the context """
kwargs = super(LaunderetteMainView, self).get_context_data(**kwargs)
kwargs['page'] = Page.objects.filter(name='launderette').first()
return kwargs
2017-06-12 07:59:44 +00:00
2016-07-28 18:05:56 +00:00
class LaunderetteBookMainView(CanViewMixin, ListView):
"""Choose which launderette to book"""
model = Launderette
2016-07-28 23:38:46 +00:00
template_name = 'launderette/launderette_book_choose.jinja'
2016-07-28 18:05:56 +00:00
2017-06-12 07:59:44 +00:00
class LaunderetteBookView(CanViewMixin, DetailView):
2016-07-28 18:05:56 +00:00
"""Display the launderette schedule"""
model = Launderette
pk_url_kwarg = "launderette_id"
template_name = 'launderette/launderette_book.jinja'
def get(self, request, *args, **kwargs):
self.slot_type = "BOTH"
self.machines = {}
return super(LaunderetteBookView, self).get(request, *args, **kwargs)
2016-07-28 23:38:46 +00:00
def post(self, request, *args, **kwargs):
self.slot_type = "BOTH"
self.machines = {}
with transaction.atomic():
self.object = self.get_object()
if 'slot_type' in request.POST.keys():
self.slot_type = request.POST['slot_type']
if 'slot' in request.POST.keys() and request.user.is_authenticated():
2016-12-10 00:58:30 +00:00
self.subscriber = request.user
if self.subscriber.is_subscribed:
self.date = dateparse.parse_datetime(request.POST['slot']).replace(tzinfo=pytz.UTC)
if self.slot_type == "WASHING":
if self.check_slot(self.slot_type):
Slot(user=self.subscriber, start_date=self.date, machine=self.machines[self.slot_type], type=self.slot_type).save()
elif self.slot_type == "DRYING":
if self.check_slot(self.slot_type):
Slot(user=self.subscriber, start_date=self.date, machine=self.machines[self.slot_type], type=self.slot_type).save()
else:
if self.check_slot("WASHING") and self.check_slot("DRYING", self.date + timedelta(hours=1)):
Slot(user=self.subscriber, start_date=self.date, machine=self.machines["WASHING"], type="WASHING").save()
Slot(user=self.subscriber, start_date=self.date + timedelta(hours=1),
2017-06-12 07:59:44 +00:00
machine=self.machines["DRYING"], type="DRYING").save()
2016-07-28 23:38:46 +00:00
return super(LaunderetteBookView, self).get(request, *args, **kwargs)
def check_slot(self, type, date=None):
2017-06-12 07:59:44 +00:00
if date is None:
date = self.date
for m in self.object.machines.filter(is_working=True, type=type).all():
slot = Slot.objects.filter(start_date=date, machine=m).first()
if slot is None:
self.machines[type] = m
return True
return False
2016-07-28 23:38:46 +00:00
@staticmethod
def date_iterator(startDate, endDate, delta=timedelta(days=1)):
currentDate = startDate
while currentDate < endDate:
yield currentDate
currentDate += delta
def get_context_data(self, **kwargs):
""" Add page to the context """
kwargs = super(LaunderetteBookView, self).get_context_data(**kwargs)
kwargs['planning'] = OrderedDict()
kwargs['slot_type'] = self.slot_type
start_date = datetime.now().replace(hour=0, minute=0, second=0, microsecond=0, tzinfo=pytz.UTC)
2017-06-12 07:59:44 +00:00
for date in LaunderetteBookView.date_iterator(start_date, start_date + timedelta(days=6), timedelta(days=1)):
2016-07-28 23:38:46 +00:00
kwargs['planning'][date] = []
2017-06-12 07:59:44 +00:00
for h in LaunderetteBookView.date_iterator(date, date + timedelta(days=1), timedelta(hours=1)):
2016-07-28 23:38:46 +00:00
free = False
if self.slot_type == "BOTH" and self.check_slot("WASHING", h) and self.check_slot("DRYING", h + timedelta(hours=1)):
free = True
elif self.slot_type == "WASHING" and self.check_slot("WASHING", h):
free = True
elif self.slot_type == "DRYING" and self.check_slot("DRYING", h):
free = True
if free and datetime.now().replace(tzinfo=pytz.UTC) < h:
2016-07-28 23:38:46 +00:00
kwargs['planning'][date].append(h)
else:
kwargs['planning'][date].append(None)
return kwargs
2016-07-28 18:05:56 +00:00
2017-06-12 07:59:44 +00:00
2016-12-15 15:11:43 +00:00
class SlotDeleteView(CanEditPropMixin, DeleteView):
"""Delete a slot"""
model = Slot
pk_url_kwarg = "slot_id"
template_name = 'core/delete_confirm.jinja'
def get_success_url(self):
return self.request.user.get_absolute_url()
2016-07-28 18:05:56 +00:00
# For admins
class LaunderetteListView(CanEditPropMixin, ListView):
2016-07-28 18:05:56 +00:00
"""Choose which launderette to administer"""
model = Launderette
template_name = 'launderette/launderette_list.jinja'
2017-06-12 07:59:44 +00:00
class LaunderetteEditView(CanEditPropMixin, UpdateView):
2016-07-28 18:05:56 +00:00
"""Edit a launderette"""
model = Launderette
pk_url_kwarg = "launderette_id"
fields = ['name']
2016-07-28 18:05:56 +00:00
template_name = 'core/edit.jinja'
2017-06-12 07:59:44 +00:00
2016-07-28 18:05:56 +00:00
class LaunderetteCreateView(CanCreateMixin, CreateView):
"""Create a new launderette"""
model = Launderette
fields = ['name']
2016-07-28 18:05:56 +00:00
template_name = 'core/create.jinja'
def form_valid(self, form):
club = Club.objects.filter(unix_name=settings.SITH_LAUNDERETTE_MANAGER['unix_name']).first()
c = Counter(name=form.instance.name, club=club, type='OFFICE')
c.save()
form.instance.counter = c
return super(LaunderetteCreateView, self).form_valid(form)
2017-06-12 07:59:44 +00:00
2016-08-06 13:20:38 +00:00
class ManageTokenForm(forms.Form):
action = forms.ChoiceField(choices=[("BACK", _("Back")), ("ADD", _("Add")), ("DEL", _("Delete"))], initial="BACK",
2017-06-12 07:59:44 +00:00
label=_("Action"), widget=forms.RadioSelect)
token_type = forms.ChoiceField(choices=settings.SITH_LAUNDERETTE_MACHINE_TYPES, label=_("Type"), initial="WASHING",
2017-06-12 07:59:44 +00:00
widget=forms.RadioSelect)
2016-08-06 13:20:38 +00:00
tokens = forms.CharField(max_length=512, widget=forms.widgets.Textarea, label=_("Tokens, separated by spaces"))
def process(self, launderette):
cleaned_data = self.cleaned_data
token_list = cleaned_data['tokens'].strip(" \n\r").split(" ")
2016-08-06 13:20:38 +00:00
token_type = cleaned_data['token_type']
self.data = {}
if cleaned_data['action'] == "BACK":
for t in token_list:
try:
tok = Token.objects.filter(launderette=launderette, type=token_type, name=t).first()
tok.borrow_date = None
tok.user = None
tok.save()
except:
self.add_error(None, _("Token %(token_name)s does not exists") % {'token_name': t})
elif cleaned_data['action'] == "ADD":
for t in token_list:
try:
Token(launderette=launderette, type=token_type, name=t).save()
except DataError as e:
self.add_error(None, e)
except:
self.add_error(None, _("Token %(token_name)s already exists") % {'token_name': t})
elif cleaned_data['action'] == "DEL":
for t in token_list:
try:
Token.objects.filter(launderette=launderette, type=token_type, name=t).delete()
except:
self.add_error(None, _("Token %(token_name)s does not exists") % {'token_name': t})
2017-06-12 07:59:44 +00:00
2016-08-06 13:20:38 +00:00
class LaunderetteAdminView(CanEditPropMixin, BaseFormView, DetailView):
"""The admin page of the launderette"""
model = Launderette
pk_url_kwarg = "launderette_id"
2016-08-06 13:20:38 +00:00
template_name = 'launderette/launderette_admin.jinja'
form_class = ManageTokenForm
def get(self, request, *args, **kwargs):
self.object = self.get_object()
return super(LaunderetteAdminView, self).get(request, *args, **kwargs)
def post(self, request, *args, **kwargs):
self.object = self.get_object()
form = self.get_form()
return super(LaunderetteAdminView, self).post(request, *args, **kwargs)
form.launderette = self.object
if form.is_valid():
return self.form_valid(form)
else:
return self.form_invalid(form)
def form_valid(self, form):
"""
We handle here the redirection, passing the user id of the asked customer
"""
form.process(self.object)
if form.is_valid():
return super(LaunderetteAdminView, self).form_valid(form)
else:
return super(LaunderetteAdminView, self).form_invalid(form)
def get_context_data(self, **kwargs):
"""
We handle here the login form for the barman
"""
kwargs = super(LaunderetteAdminView, self).get_context_data(**kwargs)
if self.request.method == "GET":
kwargs['form'] = self.get_form()
return kwargs
def get_success_url(self):
return reverse_lazy('launderette:launderette_admin', args=self.args, kwargs=self.kwargs)
2017-06-12 07:59:44 +00:00
2016-08-01 22:32:55 +00:00
class GetLaunderetteUserForm(GetUserForm):
def clean(self):
cleaned_data = super(GetLaunderetteUserForm, self).clean()
2016-12-10 00:58:30 +00:00
sub = cleaned_data['user']
2016-08-01 22:32:55 +00:00
if sub.slots.all().count() <= 0:
raise forms.ValidationError(_("User has booked no slot"))
return cleaned_data
2017-06-12 07:59:44 +00:00
class LaunderetteMainClickView(CanEditMixin, BaseFormView, DetailView):
"""The click page of the launderette"""
model = Launderette
pk_url_kwarg = "launderette_id"
template_name = 'counter/counter_main.jinja'
2017-06-12 07:59:44 +00:00
form_class = GetLaunderetteUserForm # Form to enter a client code and get the corresponding user id
2016-08-01 22:32:55 +00:00
def get(self, request, *args, **kwargs):
self.object = self.get_object()
return super(LaunderetteMainClickView, self).get(request, *args, **kwargs)
def post(self, request, *args, **kwargs):
self.object = self.get_object()
return super(LaunderetteMainClickView, self).post(request, *args, **kwargs)
def form_valid(self, form):
"""
We handle here the redirection, passing the user id of the asked customer
"""
self.kwargs['user_id'] = form.cleaned_data['user_id']
return super(LaunderetteMainClickView, self).form_valid(form)
def get_context_data(self, **kwargs):
"""
We handle here the login form for the barman
"""
kwargs = super(LaunderetteMainClickView, self).get_context_data(**kwargs)
kwargs['counter'] = self.object.counter
kwargs['form'] = self.get_form()
kwargs['barmen'] = [self.request.user]
if 'last_basket' in self.request.session.keys():
kwargs['last_basket'] = self.request.session.pop('last_basket', None)
kwargs['last_customer'] = self.request.session.pop('last_customer', None)
kwargs['last_total'] = self.request.session.pop('last_total', None)
kwargs['new_customer_amount'] = self.request.session.pop('new_customer_amount', None)
return kwargs
def get_success_url(self):
return reverse_lazy('launderette:click', args=self.args, kwargs=self.kwargs)
2017-06-12 07:59:44 +00:00
class ClickTokenForm(forms.BaseForm):
2016-08-01 22:32:55 +00:00
def clean(self):
with transaction.atomic():
2016-12-10 00:58:30 +00:00
operator = User.objects.filter(id=self.operator_id).first()
2016-08-01 22:32:55 +00:00
customer = Customer.objects.filter(user__id=self.subscriber_id).first()
counter = Counter.objects.filter(id=self.counter_id).first()
2016-12-10 00:58:30 +00:00
subscriber = customer.user
2016-08-01 22:32:55 +00:00
self.last_basket = {
2017-06-12 07:59:44 +00:00
'last_basket': [],
'last_customer': customer.user.get_display_name(),
}
2016-08-01 22:32:55 +00:00
total = 0
2017-06-12 07:59:44 +00:00
for k, t in self.cleaned_data.items():
2016-08-01 22:32:55 +00:00
if t is not None:
slot_id = int(k[5:])
slot = Slot.objects.filter(id=slot_id).first()
slot.token = t
slot.save()
t.user = subscriber
t.borrow_date = datetime.now().replace(tzinfo=pytz.UTC)
t.save()
price = settings.SITH_LAUNDERETTE_PRICES[t.type]
2017-06-12 07:59:44 +00:00
s = Selling(label="Jeton " + t.get_type_display() + "" + t.name, club=counter.club, product=None, counter=counter, unit_price=price,
quantity=1, seller=operator, customer=customer)
2016-08-01 22:32:55 +00:00
s.save()
total += price
2017-06-12 07:59:44 +00:00
self.last_basket['last_basket'].append("Jeton " + t.get_type_display() + "" + t.name)
2016-08-01 22:32:55 +00:00
self.last_basket['new_customer_amount'] = str(customer.amount)
self.last_basket['last_total'] = str(total)
return self.cleaned_data
2017-06-12 07:59:44 +00:00
class LaunderetteClickView(CanEditMixin, DetailView, BaseFormView):
"""The click page of the launderette"""
model = Launderette
pk_url_kwarg = "launderette_id"
template_name = 'launderette/launderette_click.jinja'
def get_form_class(self):
fields = OrderedDict()
kwargs = {}
def clean_field_factory(field_name, slot):
def clean_field(self2):
t_name = str(self2.data[field_name])
if t_name != "":
2016-08-01 22:32:55 +00:00
t = Token.objects.filter(name=str(self2.data[field_name]), type=slot.type, launderette=self.object,
2017-06-12 07:59:44 +00:00
user=None).first()
if t is None:
raise forms.ValidationError(_("Token not found"))
2016-08-01 22:32:55 +00:00
return t
return clean_field
2016-09-11 17:00:12 +00:00
for s in self.subscriber.slots.filter(token=None, start_date__gte=timezone.now().replace(tzinfo=None)).all():
field_name = "slot-%s" % (str(s.id))
fields[field_name] = forms.CharField(max_length=5, required=False,
2017-06-12 07:59:44 +00:00
label="%s - %s" % (s.get_type_display(), defaultfilters.date(s.start_date, "j N Y H:i")))
2016-08-01 22:32:55 +00:00
# XXX l10n settings.DATETIME_FORMAT didn't work here :/
2017-06-12 07:59:44 +00:00
kwargs["clean_" + field_name] = clean_field_factory(field_name, s)
2016-08-01 22:32:55 +00:00
kwargs['subscriber_id'] = self.subscriber.id
kwargs['counter_id'] = self.object.counter.id
kwargs['operator_id'] = self.operator.id
kwargs['base_fields'] = fields
return type('ClickForm', (ClickTokenForm,), kwargs)
def get(self, request, *args, **kwargs):
"""Simple get view"""
self.customer = Customer.objects.filter(user__id=self.kwargs['user_id']).first()
2016-12-10 00:58:30 +00:00
self.subscriber = self.customer.user
2016-08-01 22:32:55 +00:00
self.operator = request.user
return super(LaunderetteClickView, self).get(request, *args, **kwargs)
def post(self, request, *args, **kwargs):
""" Handle the many possibilities of the post request """
self.object = self.get_object()
self.customer = Customer.objects.filter(user__id=self.kwargs['user_id']).first()
2016-12-10 00:58:30 +00:00
self.subscriber = self.customer.user
2016-08-01 22:32:55 +00:00
self.operator = request.user
return super(LaunderetteClickView, self).post(request, *args, **kwargs)
def form_valid(self, form):
"""
We handle here the redirection, passing the user id of the asked customer
"""
2016-08-01 22:32:55 +00:00
self.request.session.update(form.last_basket)
return super(LaunderetteClickView, self).form_valid(form)
def get_context_data(self, **kwargs):
"""
We handle here the login form for the barman
"""
kwargs = super(LaunderetteClickView, self).get_context_data(**kwargs)
if 'form' not in kwargs.keys():
kwargs['form'] = self.get_form()
kwargs['counter'] = self.object.counter
kwargs['customer'] = self.customer
return kwargs
def get_success_url(self):
self.kwargs.pop('user_id', None)
return reverse_lazy('launderette:main_click', args=self.args, kwargs=self.kwargs)
class MachineEditView(CanEditPropMixin, UpdateView):
"""Edit a machine"""
model = Machine
pk_url_kwarg = "machine_id"
fields = ['name', 'launderette', 'type', 'is_working']
template_name = 'core/edit.jinja'
2017-06-12 07:59:44 +00:00
class MachineDeleteView(CanEditPropMixin, DeleteView):
"""Edit a machine"""
model = Machine
pk_url_kwarg = "machine_id"
template_name = 'core/delete_confirm.jinja'
success_url = reverse_lazy('launderette:launderette_list')
2017-06-12 07:59:44 +00:00
class MachineCreateView(CanCreateMixin, CreateView):
"""Create a new machine"""
model = Machine
fields = ['name', 'launderette', 'type']
template_name = 'core/create.jinja'
def get_initial(self):
ret = super(MachineCreateView, self).get_initial()
if 'launderette' in self.request.GET.keys():
obj = Launderette.objects.filter(id=int(self.request.GET['launderette'])).first()
if obj is not None:
ret['launderette'] = obj.id
return ret