Commit 70021391 authored by Skia's avatar Skia

Finish the launderette click view

parent 2cf39671
Pipeline #81 failed with stage
in 2 minutes
......@@ -17,8 +17,7 @@
{# if the user is member of a club, he can view the subscription state #}
<p>
{% if get_subscriber(profile).is_subscribed() %}
{% trans subscription_end=get_subscriber(profile).subscriptions.last().subscription_end %}
User is subscriber until {{ subscription_end }}{% endtrans %}
{% trans subscription_end=get_subscriber(profile).subscriptions.last().subscription_end %}User is subscriber until {{ subscription_end }}{% endtrans %}
{% else %}
{% trans %}User is not subscribed. {% endtrans %}
<a href="{{ url('subscription:subscription') }}?member={{ profile.id }}">{% trans %}New subscription{% endtrans %}</a>
......
# -*- coding: utf-8 -*-
from __future__ import unicode_literals
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('counter', '0011_counter_sellers'),
]
operations = [
migrations.AddField(
model_name='refilling',
name='is_validated',
field=models.BooleanField(default=False, verbose_name='is validated'),
),
migrations.AddField(
model_name='selling',
name='is_validated',
field=models.BooleanField(default=False, verbose_name='is validated'),
),
migrations.AddField(
model_name='selling',
name='label',
field=models.CharField(max_length=30, default='troll', verbose_name='label'),
preserve_default=False,
),
migrations.AlterField(
model_name='selling',
name='product',
field=models.ForeignKey(related_name='sellings', to='counter.Product', blank=True),
),
]
# -*- coding: utf-8 -*-
from __future__ import unicode_literals
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('counter', '0012_auto_20160801_2016'),
]
operations = [
migrations.AlterField(
model_name='selling',
name='product',
field=models.ForeignKey(to='counter.Product', null=True, related_name='sellings', blank=True),
),
]
from django.db import models
from django.db import models, DataError
from django.utils.translation import ugettext_lazy as _
from django.utils import timezone
from django.conf import settings
from django.core.urlresolvers import reverse
from django.forms import ValidationError
from datetime import timedelta
from random import randrange
......@@ -32,6 +33,11 @@ class Customer(models.Model):
def generate_account_id():
return randrange(0, 4000) # TODO: improve me!
def save(self, *args, **kwargs):
if self.amount < 0:
raise ValidationError(_("Not enough money"))
super(Customer, self).save(*args, **kwargs)
class ProductType(models.Model):
"""
This describes a product type
......@@ -190,6 +196,7 @@ class Refilling(models.Model):
choices=settings.SITH_COUNTER_PAYMENT_METHOD, default='cash')
bank = models.CharField(_('bank'), max_length=255,
choices=settings.SITH_COUNTER_BANK, default='other')
is_validated = models.BooleanField(_('is validated'), default=False)
class Meta:
verbose_name = _("refilling")
......@@ -202,38 +209,41 @@ class Refilling(models.Model):
def save(self, *args, **kwargs):
self.full_clean()
self.customer.amount += self.amount
self.customer.save()
if not self.is_validated:
self.customer.amount += self.amount
self.customer.save()
self.is_validated = True
super(Refilling, self).save(*args, **kwargs)
class Selling(models.Model):
"""
Handle the sellings
"""
product = models.ForeignKey(Product, related_name="sellings", blank=False)
label = models.CharField(_("label"), max_length=30)
product = models.ForeignKey(Product, related_name="sellings", null=True, blank=True)
counter = models.ForeignKey(Counter, related_name="sellings", blank=False)
unit_price = CurrencyField(_('unit price'))
quantity = models.IntegerField(_('quantity'))
seller = models.ForeignKey(User, related_name="sellings_as_operator", blank=False)
customer = models.ForeignKey(Customer, related_name="buyings", blank=False)
date = models.DateTimeField(_('date'), auto_now=True)
is_validated = models.BooleanField(_('is validated'), default=False)
class Meta:
verbose_name = _("selling")
def __str__(self):
return "Selling: %d x %s (%f) for %s" % (self.quantity, self.product.name,
return "Selling: %d x %s (%f) for %s" % (self.quantity, self.label,
self.quantity*self.unit_price, self.customer.user.get_display_name())
def save(self, *args, **kwargs):
self.full_clean()
self.customer.amount -= self.quantity * self.unit_price
self.customer.save()
if not self.is_validated:
self.customer.amount -= self.quantity * self.unit_price
self.customer.save()
self.is_validated = True
super(Selling, self).save(*args, **kwargs)
# def get_absolute_url(self):
# return reverse('counter:details', kwargs={'counter_id': self.id})
class Permanency(models.Model):
"""
This class aims at storing a traceability of who was barman where and when
......
......@@ -35,7 +35,7 @@
<tr>
<td>{% trans %}Date{% endtrans %}</td>
<td>{% trans %}Barman{% endtrans %}</td>
<td>{% trans %}Product{% endtrans %}</td>
<td>{% trans %}Label{% endtrans %}</td>
<td>{% trans %}Quantity{% endtrans %}</td>
<td>{% trans %}Total{% endtrans %}</td>
</tr>
......@@ -45,7 +45,7 @@
<tr>
<td>{{ i.date|localtime|date(DATETIME_FORMAT) }} - {{ i.date|localtime|time(DATETIME_FORMAT) }}</td>
<td>{{ i.seller }}</td>
<td>{{ i.product }}</td>
<td>{{ i.label }}</td>
<td>{{ i.quantity }}</td>
<td>{{ i.quantity * i.unit_price }}</td>
</tr>
......
......@@ -13,9 +13,11 @@ from django.conf import settings
from django.db import DataError, transaction
import re
from datetime import date, timedelta
from core.views import CanViewMixin, CanEditMixin, CanEditPropMixin, CanCreateMixin
from subscription.models import Subscriber
from subscription.views import get_subscriber
from counter.models import Counter, Customer, Product, Selling, Refilling, ProductType
class GetUserForm(forms.Form):
......@@ -28,7 +30,7 @@ class GetUserForm(forms.Form):
"""
code = forms.CharField(label="Code", max_length=10, required=False)
id = forms.IntegerField(label="ID", required=False)
# TODO: add a nice JS widget to search for users
# TODO: add a nice JS widget to search for users
def as_p(self):
self.fields['code'].widget.attrs['autofocus'] = True
......@@ -36,14 +38,16 @@ class GetUserForm(forms.Form):
def clean(self):
cleaned_data = super(GetUserForm, self).clean()
user = None
cus = None
if cleaned_data['code'] != "":
user = Customer.objects.filter(account_id=cleaned_data['code']).first()
cus = Customer.objects.filter(account_id=cleaned_data['code']).first()
elif cleaned_data['id'] is not None:
user = Customer.objects.filter(user=cleaned_data['id']).first()
if user is None:
cus = Customer.objects.filter(user=cleaned_data['id']).first()
sub = get_subscriber(cus.user) if cus is not None else None
if cus is None or sub is None or (date.today() - sub.subscriptions.last().subscription_end) > timedelta(days=90):
raise forms.ValidationError(_("User not found"))
cleaned_data['user_id'] = user.user.id
cleaned_data['user_id'] = cus.user.id
cleaned_data['user'] = cus.user
return cleaned_data
class RefillForm(forms.ModelForm):
......@@ -238,7 +242,7 @@ class CounterClick(DetailView):
if uprice * infos['qty'] > self.customer.amount:
raise DataError(_("You have not enough money to buy all the basket"))
request.session['last_basket'].append("%d x %s" % (infos['qty'], p.name))
s = Selling(product=p, counter=self.object, unit_price=uprice,
s = Selling(label=p.name, product=p, counter=self.object, unit_price=uprice,
quantity=infos['qty'], seller=self.operator, customer=self.customer)
s.save()
request.session['last_customer'] = self.customer.user.get_display_name()
......
# -*- coding: utf-8 -*-
from __future__ import unicode_literals
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('counter', '0011_counter_sellers'),
('launderette', '0007_auto_20160801_1929'),
]
operations = [
migrations.AddField(
model_name='token',
name='product',
field=models.ForeignKey(related_name='tokens', to='counter.Product', default=1, verbose_name='product'),
preserve_default=False,
),
]
# -*- coding: utf-8 -*-
from __future__ import unicode_literals
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('launderette', '0008_token_product'),
]
operations = [
migrations.RemoveField(
model_name='token',
name='product',
),
]
......@@ -80,6 +80,9 @@ class Token(models.Model):
return True
return False
def __str__(self):
return self.__class__._meta.verbose_name + " " + self.get_type_display() + " #" + self.name + " (" + self.launderette.name + ")"
class Slot(models.Model):
start_date = models.DateTimeField(_('start date'))
type = models.CharField(_('type'), max_length=10, choices=[('WASHING', _('Washing')), ('DRYING', _('Drying'))])
......@@ -91,9 +94,6 @@ class Slot(models.Model):
verbose_name = _('Slot')
ordering = ['start_date']
def full_clean(self):
return super(Slot, self).full_clean()
def __str__(self):
return "User: %s - Date: %s - Type: %s - Machine: %s - Token: %s" % (self.user, self.start_date, self.get_type_display(),
self.machine.name, self.token)
......
......@@ -21,7 +21,8 @@ from club.models import Club
from core.views import CanViewMixin, CanEditMixin, CanEditPropMixin, CanCreateMixin
from launderette.models import Launderette, Token, Machine, Slot
from subscription.views import get_subscriber
from counter.models import Counter, Customer
from subscription.models import Subscriber
from counter.models import Counter, Customer, Selling
from counter.views import GetUserForm
# For users
......@@ -147,12 +148,35 @@ class LaunderetteDetailView(CanEditPropMixin, DetailView):
pk_url_kwarg = "launderette_id"
template_name = 'launderette/launderette_detail.jinja'
class GetLaunderetteUserForm(GetUserForm):
def clean(self):
cleaned_data = super(GetLaunderetteUserForm, self).clean()
sub = get_subscriber(cleaned_data['user'])
if sub.slots.all().count() <= 0:
raise forms.ValidationError(_("User has booked no slot"))
return cleaned_data
class LaunderetteMainClickView(CanEditMixin, BaseFormView, DetailView):
"""The click page of the launderette"""
model = Launderette
pk_url_kwarg = "launderette_id"
template_name = 'counter/counter_main.jinja'
form_class = GetUserForm # Form to enter a client code and get the corresponding user id
form_class = GetLaunderetteUserForm # Form to enter a client code and get the corresponding user id
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):
"""
......@@ -169,19 +193,39 @@ class LaunderetteMainClickView(CanEditMixin, BaseFormView, DetailView):
kwargs['new_customer_amount'] = self.request.session.pop('new_customer_amount', None)
return kwargs
def form_valid(self, form):
"""
We handle here the redirection, passing the user id of the asked customer
"""
self.object = self.get_object()
self.kwargs['user_id'] = form.cleaned_data['user_id']
return super(LaunderetteMainClickView, self).form_valid(form)
def get_success_url(self):
return reverse_lazy('launderette:click', args=self.args, kwargs=self.kwargs)
class ClickTokenForm(forms.BaseForm):
pass
def clean(self):
with transaction.atomic():
operator = Subscriber.objects.filter(id=self.operator_id).first()
customer = Customer.objects.filter(user__id=self.subscriber_id).first()
counter = Counter.objects.filter(id=self.counter_id).first()
subscriber = get_subscriber(customer.user)
self.last_basket = {
'last_basket': [],
'last_customer': customer.user.get_display_name(),
}
total = 0
for k,t in self.cleaned_data.items():
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]
s = Selling(label="Jeton "+t.get_type_display()+" N°"+t.name, product=None, counter=counter, unit_price=price,
quantity=1, seller=operator, customer=customer)
s.save()
total += price
self.last_basket['last_basket'].append("Jeton "+t.get_type_display()+" N°"+t.name)
self.last_basket['new_customer_amount'] = str(customer.amount)
self.last_basket['last_total'] = str(total)
return self.cleaned_data
class LaunderetteClickView(CanEditMixin, DetailView, BaseFormView):
"""The click page of the launderette"""
......@@ -196,30 +240,29 @@ class LaunderetteClickView(CanEditMixin, DetailView, BaseFormView):
def clean_field(self2):
t_name = str(self2.data[field_name])
if t_name != "":
t = Token.objects.filter(name=str(self2.data[field_name]), type=slot.type, launderette=self.object).first()
t = Token.objects.filter(name=str(self2.data[field_name]), type=slot.type, launderette=self.object,
user=None).first()
if t is None:
raise forms.ValidationError(_("Token not found"))
return t
return clean_field
for s in self.subscriber.slots.filter(token=None).all():
field_name = "slot-%s" % (str(s.id))
fields[field_name] = forms.CharField(max_length=5, required=False,
label="%s - %s" % (s.get_type_display(), defaultfilters.date(s.start_date, "j N Y H:i")))
# XXX l10n settings.DATETIME_FORMAT did'nt work here :/
# XXX l10n settings.DATETIME_FORMAT didn't work here :/
kwargs["clean_"+field_name] = clean_field_factory(field_name, s)
def clean_form(self2):
raise forms.ValidationError(_("Not enough money"))
return self2.cleaned_data
kwargs['subscriber_id'] = self.subscriber.id
kwargs['counter_id'] = self.object.counter.id
kwargs['operator_id'] = self.operator.id
kwargs['base_fields'] = fields
kwargs['clean'] = clean_form
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()
self.subscriber = get_subscriber(self.customer.user)
self.operator = request.user
return super(LaunderetteClickView, self).get(request, *args, **kwargs)
def post(self, request, *args, **kwargs):
......@@ -227,13 +270,14 @@ class LaunderetteClickView(CanEditMixin, DetailView, BaseFormView):
self.object = self.get_object()
self.customer = Customer.objects.filter(user__id=self.kwargs['user_id']).first()
self.subscriber = get_subscriber(self.customer.user)
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
"""
self.request.session['last_basket'] = ["GUY"]
self.request.session.update(form.last_basket)
return super(LaunderetteClickView, self).form_valid(form)
def get_context_data(self, **kwargs):
......
......@@ -6,7 +6,7 @@
msgid ""
msgstr ""
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2016-07-29 12:46+0200\n"
"POT-Creation-Date: 2016-08-02 00:28+0200\n"
"PO-Revision-Date: 2016-07-18\n"
"Last-Translator: Skia <skia@libskia.so>\n"
"Language-Team: AE info <ae.info@utbm.fr>\n"
......@@ -17,9 +17,9 @@ msgstr ""
"Plural-Forms: nplurals=2; plural=(n > 1);\n"
#: accounting/models.py:32 accounting/models.py:55 accounting/models.py:94
#: club/models.py:18 counter/models.py:38 counter/models.py:63
#: counter/models.py:91 launderette/models.py:12 launderette/models.py:36
#: launderette/models.py:59
#: club/models.py:18 counter/models.py:46 counter/models.py:71
#: counter/models.py:99 launderette/models.py:14 launderette/models.py:42
#: launderette/models.py:65
msgid "name"
msgstr "nom"
......@@ -31,12 +31,12 @@ msgstr "IBAN"
msgid "account number"
msgstr "numero de compte"
#: accounting/models.py:92 club/models.py:109 counter/models.py:237
#: launderette/models.py:62 launderette/models.py:76
#: accounting/models.py:92 club/models.py:109 counter/models.py:253
#: launderette/models.py:87
msgid "start date"
msgstr "date de début"
#: accounting/models.py:93 club/models.py:110 counter/models.py:238
#: accounting/models.py:93 club/models.py:110 counter/models.py:254
msgid "end date"
msgstr "date de fin"
......@@ -44,8 +44,8 @@ msgstr "date de fin"
msgid "is closed"
msgstr "est fermé"
#: accounting/models.py:97 accounting/models.py:136 counter/models.py:21
#: counter/models.py:179
#: accounting/models.py:97 accounting/models.py:136 counter/models.py:24
#: counter/models.py:191
msgid "amount"
msgstr "montant"
......@@ -57,12 +57,12 @@ msgstr "montant effectif"
msgid "number"
msgstr "numéro"
#: accounting/models.py:137 core/models.py:463 counter/models.py:182
#: counter/models.py:213 eboutic/models.py:13 eboutic/models.py:46
#: accounting/models.py:137 core/models.py:463 counter/models.py:194
#: counter/models.py:229 eboutic/models.py:13 eboutic/models.py:46
msgid "date"
msgstr "date"
#: accounting/models.py:138 accounting/models.py:198
#: accounting/models.py:138 accounting/models.py:198 counter/models.py:222
msgid "label"
msgstr "intitulé"
......@@ -70,7 +70,7 @@ msgstr "intitulé"
msgid "remark"
msgstr "remarque"
#: accounting/models.py:140 counter/models.py:183 eboutic/models.py:48
#: accounting/models.py:140 counter/models.py:195 eboutic/models.py:48
#: subscription/models.py:34
msgid "payment method"
msgstr "méthode de paiement"
......@@ -92,7 +92,7 @@ msgstr ""
"La date ne peut pas être avant la date de début du journal, qui est\n"
"%(start_date)s."
#: accounting/models.py:197 counter/models.py:66
#: accounting/models.py:197 counter/models.py:74
msgid "code"
msgstr "code"
......@@ -158,7 +158,7 @@ msgstr "Éditer"
#: accounting/templates/accounting/bank_account_details.jinja:19
#: accounting/templates/accounting/bank_account_list.jinja:16
#: core/templates/core/group_list.jinja:13
#: launderette/templates/launderette/launderette_detail.jinja:13
#: launderette/templates/launderette/launderette_detail.jinja:22
msgid "Delete"
msgstr "Supprimer"
......@@ -267,6 +267,7 @@ msgid "Date"
msgstr "Date"
#: accounting/templates/accounting/journal_details.jinja:22
#: counter/templates/counter/user_account.jinja:38
msgid "Label"
msgstr "Intitulé"
......@@ -315,7 +316,7 @@ msgid "You can not make loops in clubs"
msgstr "Vous ne pouvez pas faire de boucles dans les clubs"
#: club/models.py:107 eboutic/models.py:12 eboutic/models.py:45
#: launderette/models.py:80
#: launderette/models.py:69 launderette/models.py:91
msgid "user"
msgstr "nom d'utilisateur"
......@@ -327,8 +328,8 @@ msgstr "club"
msgid "role"
msgstr "rôle"
#: club/models.py:113 core/models.py:27 counter/models.py:39
#: counter/models.py:64
#: club/models.py:113 core/models.py:27 counter/models.py:47
#: counter/models.py:72
msgid "description"
msgstr "description"
......@@ -598,7 +599,7 @@ msgid "Confirm"
msgstr "Confirmation"
#: core/templates/core/delete_confirm.jinja:8
#: counter/templates/counter/counter_click.jinja:67
#: counter/templates/counter/counter_click.jinja:71
msgid "Cancel"
msgstr "Annuler"
......@@ -631,9 +632,7 @@ msgstr "Hello, world! Vous êtes sur la page d'accueil utilisant Jinja2."
#: core/templates/core/login.jinja:6
msgid "Your username and password didn't match. Please try again."
msgstr ""
"Votre nom d'utilisateur et votre mot de passe ne correspondent pas. Merci de "
"réessayer."
msgstr "Votre nom d'utilisateur et votre mot de passe ne correspondent pas. Merci de réessayer."
#: core/templates/core/login.jinja:11
msgid ""
......@@ -684,9 +683,7 @@ msgstr "La créer ?"
#: core/templates/core/page_detail.jinja:5
#, python-format
msgid "This may not be the last update, you are seeing revision %(rev_id)s!"
msgstr ""
"Ceci n'est peut-être pas la dernière version de la page. Vous consultez la "
"version %(rev_id)s."
msgstr "Ceci n'est peut-être pas la dernière version de la page. Vous consultez la version %(rev_id)s."
#: core/templates/core/page_hist.jinja:6
msgid "Page history"
......@@ -769,9 +766,7 @@ msgstr ""
#: core/templates/core/password_reset_email.jinja:4
msgid "Please go to the following page and choose a new password:"
msgstr ""
"Merci de vous rendre sur la page suivante et de choisir un nouveau mot de "
"passe :"
msgstr "Merci de vous rendre sur la page suivante et de choisir un nouveau mot de passe :"
#: core/templates/core/password_reset_email.jinja:8
msgid "Your username, in case you've forgotten: "
......@@ -796,11 +791,8 @@ msgid "Welcome %(user_name)s!"
msgstr "Bienvenue, %(user_name)s!"
#: core/templates/core/register.jinja:10
msgid ""
"You successfully registred and you will soon receive a confirmation mail."
msgstr ""
"Vous vous êtes correctement enregistré, et vous devriez recevoir rapidement "
"un email de confirmation."
msgid "You successfully registred and you will soon receive a confirmation mail."
msgstr "Vous vous êtes correctement enregistré, et vous devriez recevoir rapidement un email de confirmation."
#: core/templates/core/register.jinja:12
#, python-format
......@@ -830,19 +822,14 @@ msgid "Born: "
msgstr "Né le : "
#: core/templates/core/user_detail.jinja:20
#, python-format
msgid ""
"\n"
"User is subscriber until %(subscription_end)s"
msgstr ""
"\n"
"L'utilisateur est cotisant jusqu'au %(subscription_end)s"
msgid "User is subscriber until %(subscription_end)s"
msgstr "L'utilisateur est cotisant jusqu'au %(subscription_end)s"