Begin launderette

This commit is contained in:
Skia
2016-07-28 20:05:56 +02:00
parent 4c62816816
commit a01fc63a82
31 changed files with 871 additions and 61 deletions

0
launderette/__init__.py Normal file
View File

3
launderette/admin.py Normal file
View File

@ -0,0 +1,3 @@
from django.contrib import admin
# Register your models here.

View File

@ -0,0 +1,47 @@
# -*- coding: utf-8 -*-
from __future__ import unicode_literals
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
]
operations = [
migrations.CreateModel(
name='Launderette',
fields=[
('id', models.AutoField(serialize=False, auto_created=True, verbose_name='ID', primary_key=True)),
('name', models.CharField(max_length=30, verbose_name='name')),
],
options={
'verbose_name': 'Launderette',
},
),
migrations.CreateModel(
name='Machine',
fields=[
('id', models.AutoField(serialize=False, auto_created=True, verbose_name='ID', primary_key=True)),
('name', models.CharField(max_length=30, verbose_name='name')),
('is_working', models.BooleanField(default=True, verbose_name='is working')),
('launderette', models.ForeignKey(to='launderette.Launderette', related_name='machines', verbose_name='launderette')),
],
options={
'verbose_name': 'Machine',
},
),
migrations.CreateModel(
name='Token',
fields=[
('id', models.AutoField(serialize=False, auto_created=True, verbose_name='ID', primary_key=True)),
('name', models.CharField(max_length=30, verbose_name='name')),
('type', models.CharField(choices=[('WASHING', 'Washing'), ('DRYING', 'Drying')], max_length=10, verbose_name='type')),
('launderette', models.ForeignKey(to='launderette.Launderette', related_name='tokens', verbose_name='launderette')),
],
options={
'verbose_name': 'Token',
},
),
]

View File

@ -0,0 +1,39 @@
# -*- coding: utf-8 -*-
from __future__ import unicode_literals
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('subscription', '0002_auto_20160718_1805'),
('launderette', '0001_initial'),
]
operations = [
migrations.CreateModel(
name='Slot',
fields=[
('id', models.AutoField(primary_key=True, serialize=False, verbose_name='ID', auto_created=True)),
('start_date', models.DateTimeField(verbose_name='start date')),
('type', models.CharField(max_length=10, verbose_name='type', choices=[('WASHING', 'Washing'), ('DRYING', 'Drying')])),
('machine', models.ForeignKey(verbose_name='machine', related_name='slots', to='launderette.Machine')),
],
),
migrations.AlterField(
model_name='token',
name='name',
field=models.IntegerField(verbose_name='name'),
),
migrations.AddField(
model_name='slot',
name='token',
field=models.ForeignKey(verbose_name='token', related_name='slots', to='launderette.Token'),
),
migrations.AddField(
model_name='slot',
name='user',
field=models.ForeignKey(verbose_name='user', related_name='slots', to='subscription.Subscriber'),
),
]

View File

@ -0,0 +1,20 @@
# -*- coding: utf-8 -*-
from __future__ import unicode_literals
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('subscription', '0002_auto_20160718_1805'),
('launderette', '0002_auto_20160728_1858'),
]
operations = [
migrations.AddField(
model_name='launderette',
name='sellers',
field=models.ManyToManyField(to='subscription.Subscriber', verbose_name='sellers', related_name='launderettes'),
),
]

View File

@ -0,0 +1,19 @@
# -*- coding: utf-8 -*-
from __future__ import unicode_literals
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('launderette', '0003_launderette_sellers'),
]
operations = [
migrations.AlterField(
model_name='launderette',
name='sellers',
field=models.ManyToManyField(blank=True, to='subscription.Subscriber', verbose_name='sellers', related_name='launderettes'),
),
]

View File

76
launderette/models.py Normal file
View File

@ -0,0 +1,76 @@
from django.db import models
from django.utils.translation import ugettext_lazy as _
from django.conf import settings
from django.core.urlresolvers import reverse
from core.models import User
from subscription.models import Subscriber
# Create your models here.
class Launderette(models.Model):
name = models.CharField(_('name'), max_length=30)
sellers = models.ManyToManyField(Subscriber, verbose_name=_('sellers'), related_name='launderettes', blank=True)
class Meta:
verbose_name = _('Launderette')
def is_owned_by(self, user):
"""
Method to see if that object can be edited by the given user
"""
if user.is_in_group(settings.SITH_GROUPS['launderette-admin']['name']):
return True
return False
def can_be_viewed_by(self, user):
return user.is_in_group(settings.SITH_MAIN_MEMBERS_GROUP)
def __str__(self):
return self.name
def get_absolute_url(self):
return reverse('launderette:launderette_list')
class Machine(models.Model):
name = models.CharField(_('name'), max_length=30)
launderette = models.ForeignKey(Launderette, related_name='machines', verbose_name=_('launderette'))
is_working = models.BooleanField(_('is working'), default=True)
class Meta:
verbose_name = _('Machine')
def is_owned_by(self, user):
"""
Method to see if that object can be edited by the given user
"""
if user.is_in_group(settings.SITH_GROUPS['launderette-admin']['name']):
return True
return False
class Token(models.Model):
name = models.IntegerField(_('name'))
launderette = models.ForeignKey(Launderette, related_name='tokens', verbose_name=_('launderette'))
type = models.CharField(_('type'), max_length=10, choices=[('WASHING', _('Washing')), ('DRYING', _('Drying'))])
class Meta:
verbose_name = _('Token')
def is_owned_by(self, user):
"""
Method to see if that object can be edited by the given user
"""
if user.is_in_group(settings.SITH_GROUPS['launderette-admin']['name']):
return True
return False
class Slot(models.Model):
start_date = models.DateTimeField(_('start date'))
type = models.CharField(_('type'), max_length=10, choices=[('WASHING', _('Washing')), ('DRYING', _('Drying'))])
machine = models.ForeignKey(Machine, related_name='slots', verbose_name=_('machine'))
token = models.ForeignKey(Token, related_name='slots', verbose_name=_('token'))
user = models.ForeignKey(Subscriber, related_name='slots', verbose_name=_('user'))
def full_clean(self):
return super(Slot, self).full_clean()

View File

@ -0,0 +1,79 @@
{% extends "core/base.jinja" %}
{% macro add_product(id, content) %}
<form method="post" action="{{ url('counter:click', counter_id=counter.id, user_id=customer.user.id) }}" class="inline" style="display:inline">
{% csrf_token %}
<input type="hidden" name="action" value="add_product">
<button type="submit" name="product_id" value="{{ id }}"> {{ content }} </button>
</form>
{% endmacro %}
{% macro del_product(id, content) %}
<form method="post" action="{{ url('counter:click', counter_id=counter.id, user_id=customer.user.id) }}" class="inline" style="display:inline">
{% csrf_token %}
<input type="hidden" name="action" value="del_product">
<button type="submit" name="product_id" value="{{ id }}"> {{ content }} </button>
</form>
{% endmacro %}
{% block content %}
<h3>{% trans %}Counter{% endtrans %}</h3>
<h4>{{ counter }}</h4>
<p><strong>{% trans %}Club: {% endtrans %}</strong> {{ counter.club }}</p>
<div>
<h5>{% trans %}Customer{% endtrans %}</h5>
<p>{{ customer.user.get_display_name() }}, {{ customer.amount }} €</p>
</div>
{% if counter.type == 'BAR' %}
<div>
<h5>{% trans %}Refilling{% endtrans %}</h5>
<form method="post" action="{{ url('counter:click', counter_id=counter.id, user_id=customer.user.id) }}">
{% csrf_token %}
{{ refill_form.as_p() }}
<input type="hidden" name="action" value="refill">
<input type="submit" value="{% trans %}Go{% endtrans %}" />
</form>
</div>
{% endif %}
<div>
<h5>{% trans %}Selling{% endtrans %}</h5>
{% if request.session['not_enough'] %}
<p><strong>{% trans %}Not enough money{% endtrans %}</strong></p>
{% endif %}
<form method="post" action="{{ url('counter:click', counter_id=counter.id, user_id=customer.user.id) }}">
{% csrf_token %}
<input type="hidden" name="action" value="code">
<input type="input" name="code" value="" autofocus />
<input type="submit" value="{% trans %}Go{% endtrans %}" />
</form>
<p>{% trans %}Basket: {% endtrans %}</p>
<ul>
{% for id,infos in request.session['basket']|dictsort %}
{% set product = counter.products.filter(id=id).first() %}
{% set s = infos['qty'] * infos['price'] / 100 %}
<li>{{ del_product(id, '-') }} {{ infos['qty'] }} {{ add_product(id, '+') }} {{ product.name }}: {{ "%0.2f"|format(s) }} €</li>
{% endfor %}
</ul>
<p><strong>{% trans %}Total: {% endtrans %}{{ "%0.2f"|format(basket_total) }} €</strong></p>
<form method="post" action="{{ url('counter:click', counter_id=counter.id, user_id=customer.user.id) }}">
{% csrf_token %}
<input type="hidden" name="action" value="finish">
<input type="submit" value="{% trans %}Finish{% endtrans %}" />
</form>
<form method="post" action="{{ url('counter:click', counter_id=counter.id, user_id=customer.user.id) }}">
{% csrf_token %}
<input type="hidden" name="action" value="cancel">
<input type="submit" value="{% trans %}Cancel{% endtrans %}" />
</form>
<p><strong>{% trans %}Products: {% endtrans %}</strong>
{% for p in counter.products.all() %}
{{ add_product(p.id, p.name) }}
{% endfor %}
</p>
</div>
{% endblock %}

View File

@ -0,0 +1,13 @@
{% extends "core/base.jinja" %}
{% block content %}
<h2>{% trans %}Edit counter{% endtrans %}</h2>
<form action="" method="post">
{% csrf_token %}
{{ form.as_p() }}
<p><input type="submit" value="{% trans %}Save{% endtrans %}" /></p>
</form>
{% endblock %}

View File

@ -0,0 +1,55 @@
{% extends "core/base.jinja" %}
{% macro barman_logout_link(user) %}
<form method="post" action="{{ url('counter:logout', counter_id=counter.id) }}" class="inline">
{% csrf_token %}
<input type="hidden" name="user_id" value="{{ user.id }}">
<button type="submit" name="submit_param" value="submit_value" class="link-button">{{ user.get_display_name() }}</button>
</form>
{% endmacro %}
{% block content %}
<h3>{% trans counter_name=counter %}{{ counter_name }} counter{% endtrans %}</h3>
<div>
<h3>{% trans %}Sellings{% endtrans %}</h3>
{% if last_basket %}
<h4>{% trans %}Last selling: {% endtrans %}</h4>
<p>{% trans %}Client: {% endtrans %}{{ last_customer }} - {% trans %}New amount: {% endtrans %}{{ new_customer_amount }} €.</p>
<ul>
{% for s in last_basket %}
<li>{{ s }}</li>
{% endfor %}
</ul>
<p><strong>{% trans %}Total: {% endtrans %}{{ last_total }} €</strong></p>
{% endif %}
{% if barmen %}
<p>{% trans %}Enter client code:{% endtrans %}</p>
<form method="post" action="{{ url('counter:details', counter_id=counter.id) }}">
{% csrf_token %}
{{ form.as_p() }}
<p><input type="submit" value="{% trans %}validate{% endtrans %}" /></p>
</form>
{% else %}
<p>{% trans %}Please, login{% endtrans %}</p>
{% endif %}
</div>
{% if counter.type == 'BAR' %}
<div>
<h3>{% trans %}Barman: {% endtrans %}</h3>
<ul>
{% for b in barmen %}
<li>{{ barman_logout_link(b) }}</li>
{% endfor %}
</ul>
<form method="post" action="{{ url('counter:login', counter_id=counter.id) }}">
{% csrf_token %}
{{ login_form.as_p() }}
<p><input type="submit" value="{% trans %}login{% endtrans %}" /></p>
</form>
</div>
{% endif %}
{% endblock %}

View File

@ -0,0 +1,21 @@
{% extends "core/base.jinja" %}
{% block title %}
{% trans %}Launderette{% endtrans %}
{% endblock %}
{% block content %}
{% if request.user.is_in_group(settings.SITH_MAIN_MEMBERS_GROUP) %}
<ul>
{% for l in launderette_list %}
<li><a href="{{ url('launderette:book_slot', launderette_id=l.id) }}">{{ l }}</a></li>
{% endfor %}
</ul>
{% endif %}
{% endblock %}

View File

@ -0,0 +1,13 @@
{% extends "core/base.jinja" %}
{% block title %}
{% trans %}Launderette admin{% endtrans %}
{% endblock %}
{% block content %}
Admin
{% endblock %}

View File

@ -0,0 +1,23 @@
{% extends "core/base.jinja" %}
{% block title %}
{% trans %}Launderette admin list{% endtrans %}
{% endblock %}
{% block content %}
<p><a href="{{ url('launderette:launderette_new') }}">{% trans %}New launderette{% endtrans %}</a></p>
{% if launderette_list %}
<h3>{% trans %}Launderette admin list{% endtrans %}</h3>
<ul>
{% for l in launderette_list %}
<li><a href="{{ url('launderette:launderette_details', launderette_id=l.id) }}">{{ l }}</a> -
<a href="{{ url('launderette:launderette_edit', launderette_id=l.id) }}">{% trans %}Edit{% endtrans %}</a></li>
{% endfor %}
</ul>
{% else %}
{% trans %}There is no launderette in this website.{% endtrans %}
{% endif %}
{% endblock %}

View File

@ -0,0 +1,21 @@
{% extends "core/base.jinja" %}
{% block title %}
{% trans %}Launderette{% endtrans %}
{% endblock %}
{% block content %}
{% if request.user.is_in_group(settings.SITH_GROUPS['launderette-admin']['name']) %}
<p><a href="{{ url('core:page_edit', page_name=page.get_full_name()) }}">{% trans %}Edit presentation page{% endtrans %}</a></p>
{% endif %}
{% if request.user.is_in_group(settings.SITH_MAIN_MEMBERS_GROUP) %}
<p><a href="{{ url('launderette:book_main') }}">{% trans %}Book launderette slot{% endtrans %}</a></p>
{% endif %}
{{ page.revisions.last().content|markdown }}
{% endblock %}

View File

@ -0,0 +1,23 @@
{% extends "core/base.jinja" %}
{% block title %}
{% trans %}Product list{% endtrans %}
{% endblock %}
{% block content %}
<p><a href="{{ url('counter:new_product') }}">{% trans %}New product{% endtrans %}</a></p>
{% if product_list %}
<h3>{% trans %}Product list{% endtrans %}</h3>
<ul>
{% for p in product_list %}
<li><a href="{{ url('counter:product_edit', product_id=p.id) }}">{{ p }}</a></li>
{% endfor %}
</ul>
{% else %}
{% trans %}There is no products in this website.{% endtrans %}
{% endif %}
{% endblock %}

View File

@ -0,0 +1,24 @@
{% extends "core/base.jinja" %}
{% block title %}
{% trans %}Product type list{% endtrans %}
{% endblock %}
{% block content %}
<p><a href="{{ url('counter:new_producttype') }}">{% trans %}New product type{% endtrans %}</a></p>
{% if producttype_list %}
<h3>{% trans %}Product type list{% endtrans %}</h3>
<ul>
{% for t in producttype_list %}
<li><a href="{{ url('counter:producttype_edit', type_id=t.id) }}">{{ t }}</a></li>
{% endfor %}
</ul>
{% else %}
{% trans %}There is no product types in this website.{% endtrans %}
{% endif %}
{% endblock %}

View File

@ -0,0 +1,86 @@
{% extends "core/user_base.jinja" %}
{% block title %}
{% trans user_name=profile.get_display_name() %}{{ user_name }}'s account{% endtrans %}
{% endblock %}
{% block infos %}
<h3>{% trans %}User account{% endtrans %}</h3>
<p>{% trans %}Amount: {% endtrans %}{{ customer.amount }} €</p>
{% if customer.refillings.exists() %}
<h4>{% trans %}Refillings{% endtrans %}</h4>
<table>
<thead>
<tr>
<td>{% trans %}Date{% endtrans %}</td>
<td>{% trans %}Barman{% endtrans %}</td>
<td>{% trans %}Amount{% endtrans %}</td>
</tr>
</thead>
<tbody>
{% for i in customer.refillings.all() %}
<tr>
<td>{{ i.date|localtime|date(DATETIME_FORMAT) }} - {{ i.date|localtime|time(DATETIME_FORMAT) }}</td>
<td>{{ i.operator }}</td>
<td>{{ i.amount }} €</td>
</tr>
{% endfor %}
</tbody>
</table>
{% endif %}
{% if customer.buyings.exists() %}
<h4>{% trans %}Buyings{% endtrans %}</h4>
<table>
<thead>
<tr>
<td>{% trans %}Date{% endtrans %}</td>
<td>{% trans %}Barman{% endtrans %}</td>
<td>{% trans %}Product{% endtrans %}</td>
<td>{% trans %}Quantity{% endtrans %}</td>
<td>{% trans %}Total{% endtrans %}</td>
</tr>
</thead>
<tbody>
{% for i in customer.buyings.all() %}
<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.quantity }}</td>
<td>{{ i.quantity * i.unit_price }} €</td>
</tr>
{% endfor %}
</tbody>
</table>
{% endif %}
{% if customer.user.invoices.exists() %}
<h4>{% trans %}Invoices{% endtrans %}</h4>
<table>
<thead>
<tr>
<td>{% trans %}Date{% endtrans %}</td>
<td>{% trans %}Items{% endtrans %}</td>
<td>{% trans %}Amount{% endtrans %}</td>
</tr>
</thead>
<tbody>
{% for i in customer.user.invoices.all() %}
<tr>
<td>{{ i.date|localtime|date(DATETIME_FORMAT) }} - {{ i.date|localtime|time(DATETIME_FORMAT) }}</td>
<td>
<ul>
{% for it in i.items.all() %}
<li>{{ it.product_name }} - {{ it.product_unit_price }} €</li>
{% endfor %}
</ul>
</td>
<td>{{ i.get_total() }} €</td>
</tr>
{% endfor %}
</tbody>
</table>
{% endif %}
{% endblock %}

3
launderette/tests.py Normal file
View File

@ -0,0 +1,3 @@
from django.test import TestCase
# Create your tests here.

17
launderette/urls.py Normal file
View File

@ -0,0 +1,17 @@
from django.conf.urls import url, include
from launderette.views import *
urlpatterns = [
# views
url(r'^$', LaunderetteMainView.as_view(), name='launderette_main'),
url(r'^book$', LaunderetteBookMainView.as_view(), name='book_main'),
url(r'^book/(?P<launderette_id>[0-9]+)$', LaunderetteBookView.as_view(), name='book_slot'),
url(r'^admin$', LaunderetteListView.as_view(), name='launderette_list'),
url(r'^admin/(?P<launderette_id>[0-9]+)$', LaunderetteDetailView.as_view(), name='launderette_details'),
url(r'^admin/(?P<launderette_id>[0-9]+)/edit$', LaunderetteEditView.as_view(), name='launderette_edit'),
url(r'^admin/new$', LaunderetteCreateView.as_view(), name='launderette_new'),
]

62
launderette/views.py Normal file
View File

@ -0,0 +1,62 @@
from django.shortcuts import render
from django.views.generic import ListView, DetailView, RedirectView, TemplateView
from django.views.generic.edit import UpdateView, CreateView, DeleteView, ProcessFormView, FormMixin
from django.forms.models import modelform_factory
from django.forms import CheckboxSelectMultiple
from django.utils.translation import ugettext as _
from django.conf import settings
from core.models import Page
from core.views import CanViewMixin, CanEditMixin, CanEditPropMixin, CanCreateMixin
from launderette.models import Launderette, Token, Machine, Slot
# For users
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
class LaunderetteBookMainView(CanViewMixin, ListView):
"""Choose which launderette to book"""
model = Launderette
template_name = 'launderette/launderette_book.jinja'
class LaunderetteBookView(TemplateView):
"""Display the launderette schedule"""
model = Launderette
pk_url_kwarg = "launderette_id"
template_name = 'launderette/launderette_book.jinja'
# For admins
class LaunderetteListView(CanViewMixin, ListView):
"""Choose which launderette to administer"""
model = Launderette
template_name = 'launderette/launderette_list.jinja'
class LaunderetteDetailView(CanViewMixin, DetailView):
"""The admin page of the launderette"""
model = Launderette
pk_url_kwarg = "launderette_id"
template_name = 'launderette/launderette_detail.jinja'
class LaunderetteEditView(CanViewMixin, UpdateView):
"""Edit a launderette"""
model = Launderette
pk_url_kwarg = "launderette_id"
form_class = modelform_factory(Launderette, fields=['name', 'sellers'],
widgets={'sellers':CheckboxSelectMultiple})
template_name = 'core/edit.jinja'
class LaunderetteCreateView(CanCreateMixin, CreateView):
"""Create a new launderette"""
model = Launderette
fields = ['name', 'sellers']
template_name = 'core/create.jinja'