Commit 01c39919 authored by Skia's avatar Skia
Browse files

Add cash register summaries

parent 9927310f
Pipeline #142 failed with stage
in 2 minutes and 17 seconds
......@@ -10,4 +10,5 @@ admin.site.register(Counter)
admin.site.register(Refilling)
admin.site.register(Selling)
admin.site.register(Permanency)
admin.site.register(CashRegisterSummary)
......@@ -287,7 +287,39 @@ class Permanency(models.Model):
verbose_name = _("permanency")
def __str__(self):
return "%s in %s from %s to %s" % (self.user, self.counter,
self.start.strftime("%Y-%m-%d %H:%M:%S"), self.end.strftime("%Y-%m-%d %H:%M:%S"))
return "%s in %s from %s" % (self.user, self.counter,
self.start.strftime("%Y-%m-%d %H:%M:%S"))
class CashRegisterSummary(models.Model):
user = models.ForeignKey(User, related_name="cash_summaries", verbose_name=_("user"))
counter = models.ForeignKey(Counter, related_name="cash_summaries", verbose_name=_("counter"))
date = models.DateTimeField(_('date'))
comment = models.TextField(_('comment'), null=True, blank=True)
emptied = models.BooleanField(_('emptied'), default=False)
class Meta:
verbose_name = _("cash register summary")
def __str__(self):
return "At %s by %s - Total: %s €" % (self.counter, self.user, self.get_total())
def get_total(self):
t = 0
for it in self.items.all():
t += it.quantity * it.value
return t
def save(self, *args, **kwargs):
if not self.id:
self.date = timezone.now()
return super(CashRegisterSummary, self).save(*args, **kwargs)
class CashRegisterSummaryItem(models.Model):
cash_summary = models.ForeignKey(CashRegisterSummary, related_name="items", verbose_name=_("cash summary"))
value = CurrencyField(_("value"))
quantity = models.IntegerField(_('quantity'), default=0)
check = models.BooleanField(_('check'), default=False)
class Meta:
verbose_name = _("cash register summary item")
{% extends "core/base.jinja" %}
{% block title %}
{% trans obj=object %}Edit {{ obj }}{% endtrans %}
{% endblock %}
{% block content %}
<h2>{% trans %}Make a cash register summary{% endtrans %}</h2>
<form action="" method="post" id="cash_summary_form">
{% csrf_token %}
{% for field in form %}
<p>
{% if field.name[:5] == "check" and field.name[8:] == "value" %}
{% set name = field.name[:7] + "_quantity" %}
{{ field.errors }}<label for="{{ field.name }}">{{ field.label }}</label> {{ field }}
{{ form[name].errors }}<label for="{{ form[name].name }}">{{ form[name].label }}</label> {{ form[name] }}
{% elif field.name[:5] != "check" %}
{{ field.errors }}<label for="{{ field.name }}">{{ field.label }}</label> {{ field }}
{% endif %}
</p>
{% endfor %}
<p><input type="submit" value="{% trans %}Save{% endtrans %}" /></p>
</form>
{% endblock %}
......@@ -2,16 +2,16 @@
{% from "core/macros.jinja" import user_mini_profile %}
{% macro add_product(id, content) %}
<form method="post" action="{{ url('counter:click', counter_id=counter.id, user_id=customer.user.id) }}" class="form_button">
{% macro add_product(id, content, class="") %}
<form method="post" action="{{ url('counter:click', counter_id=counter.id, user_id=customer.user.id) }}" class="{{ class }}">
{% csrf_token %}
<input type="hidden" name="action" value="add_product">
<button type="submit" name="product_id" value="{{ id }}"> {{ content|safe }} </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="form_button">
{% macro del_product(id, content, class="") %}
<form method="post" action="{{ url('counter:click', counter_id=counter.id, user_id=customer.user.id) }}" class="{{ class }}">
{% csrf_token %}
<input type="hidden" name="action" value="del_product">
<button type="submit" name="product_id" value="{{ id }}"> {{ content }} </button>
......@@ -53,7 +53,7 @@
{% 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'] + infos['bonus_qty'] }} {{ add_product(id, '+') }}
<li>{{ del_product(id, '-', "inline") }} {{ infos['qty'] + infos['bonus_qty'] }} {{ add_product(id, '+', "inline") }}
{{ product.name }}: {{ "%0.2f"|format(s) }}
{% if infos['bonus_qty'] %}
P
......@@ -105,7 +105,7 @@
{% set file = static('core/img/na.gif') %}
{% endif %}
{% set prod = '<strong>%s</strong><hr><img src="%s" /><span>%s €<br>%s</span>' % (p.name, file, p.selling_price, p.code) %}
{{ add_product(p.id, prod) }}
{{ add_product(p.id, prod, "form_button") }}
{%- endfor %}
</div>
{%- endif -%}
......
{% extends "core/base.jinja" %}
{% block title %}
{% trans obj=object %}Edit {{ obj }}{% endtrans %}
{% endblock %}
{% block content %}
<h2>{% trans obj=object %}Edit {{ obj }}{% endtrans %}</h2>
<form action="" method="post">
{% csrf_token %}
<p>{{ form.sellers.errors }}<label for="{{ form.sellers.name }}">{{ form.sellers.label }}</label> {{ form.sellers }}</p>
<p><input type="submit" value="{% trans %}Save{% endtrans %}" /></p>
<p>{{ form.products.errors }}<label for="{{ form.products.name }}">{{ form.products.label }}</label> {{ form.products }}</p>
<p><input type="submit" value="{% trans %}Save{% endtrans %}" /></p>
</form>
{% endblock %}
......@@ -39,13 +39,14 @@
{% endif %}
</div>
{% if counter.type == 'BAR' %}
{% if barmen %}
<p><a href="{{ url('counter:cash_summary', counter_id=counter.id) }}">{% trans %}Make a cash register summary{% endtrans %}</a></p>
{% endif %}
<div>
<h3>{% trans %}Barman: {% endtrans %}</h3>
<ul>
{% for b in barmen %}
<li>{{ barman_logout_link(b) }}</li>
<p>{{ barman_logout_link(b) }}</p>
{% endfor %}
</ul>
<form method="post" action="{{ url('counter:login', counter_id=counter.id) }}">
{% csrf_token %}
{{ login_form.as_p() }}
......
......@@ -5,6 +5,7 @@ from counter.views import *
urlpatterns = [
url(r'^(?P<counter_id>[0-9]+)$', CounterMain.as_view(), name='details'),
url(r'^(?P<counter_id>[0-9]+)/click/(?P<user_id>[0-9]+)$', CounterClick.as_view(), name='click'),
url(r'^(?P<counter_id>[0-9]+)/cash_summary$', CounterCashSummaryView.as_view(), name='cash_summary'),
url(r'^(?P<counter_id>[0-9]+)/login$', CounterLogin.as_view(), name='login'),
url(r'^(?P<counter_id>[0-9]+)/logout$', CounterLogout.as_view(), name='logout'),
url(r'^admin/(?P<counter_id>[0-9]+)$', CounterEditView.as_view(), name='admin'),
......
......@@ -529,3 +529,96 @@ class SellingDeleteView(CanEditPropMixin, DeleteView):
def get_success_url(self):
return reverse_lazy('core:user_account', kwargs={'user_id': self.object.customer.user.id})
# Cash register summaries
class CashRegisterSummaryForm(forms.Form):
"""
Provide the cash summary form
"""
ten_cents = forms.IntegerField(label=_("10 cents"), required=False)
twenty_cents = forms.IntegerField(label=_("20 cents"), required=False)
fifty_cents = forms.IntegerField(label=_("50 cents"), required=False)
one_euro = forms.IntegerField(label=_("1 euro"), required=False)
two_euros = forms.IntegerField(label=_("2 euros"), required=False)
five_euros = forms.IntegerField(label=_("5 euros"), required=False)
ten_euros = forms.IntegerField(label=_("10 euros"), required=False)
twenty_euros = forms.IntegerField(label=_("20 euros"), required=False)
fifty_euros = forms.IntegerField(label=_("50 euros"), required=False)
hundred_euros = forms.IntegerField(label=_("100 euros"), required=False)
check_1_value = forms.DecimalField(label=_("Check amount"), required=False)
check_1_quantity = forms.IntegerField(label=_("Check quantity"), required=False)
check_2_value = forms.DecimalField(label=_("Check amount"), required=False)
check_2_quantity = forms.IntegerField(label=_("Check quantity"), required=False)
check_3_value = forms.DecimalField(label=_("Check amount"), required=False)
check_3_quantity = forms.IntegerField(label=_("Check quantity"), required=False)
check_4_value = forms.DecimalField(label=_("Check amount"), required=False)
check_4_quantity = forms.IntegerField(label=_("Check quantity"), required=False)
check_5_value = forms.DecimalField(label=_("Check amount"), required=False)
check_5_quantity = forms.IntegerField(label=_("Check quantity"), required=False)
comment = forms.CharField(label=_("Comment"), required=False)
emptied = forms.BooleanField(label=_("Emptied"), required=False)
def save(self, counter):
cd = self.cleaned_data
summary = CashRegisterSummary(
counter=counter,
user=counter.get_random_barman(),
comment=cd['comment'],
emptied=cd['emptied'],
)
summary.save()
# Cash
if cd['ten_cents']: CashRegisterSummaryItem(cash_summary=summary, value=0.1, quantity=cd['ten_cents']).save()
if cd['twenty_cents']: CashRegisterSummaryItem(cash_summary=summary, value=0.2, quantity=cd['twenty_cents']).save()
if cd['fifty_cents']: CashRegisterSummaryItem(cash_summary=summary, value=0.5, quantity=cd['fifty_cents']).save()
if cd['one_euro']: CashRegisterSummaryItem(cash_summary=summary, value=1, quantity=cd['one_euro']).save()
if cd['two_euros']: CashRegisterSummaryItem(cash_summary=summary, value=2, quantity=cd['two_euros']).save()
if cd['five_euros']: CashRegisterSummaryItem(cash_summary=summary, value=5, quantity=cd['five_euros']).save()
if cd['ten_euros']: CashRegisterSummaryItem(cash_summary=summary, value=10, quantity=cd['ten_euros']).save()
if cd['twenty_euros']: CashRegisterSummaryItem(cash_summary=summary, value=20, quantity=cd['twenty_euros']).save()
if cd['fifty_euros']: CashRegisterSummaryItem(cash_summary=summary, value=50, quantity=cd['fifty_euros']).save()
if cd['hundred_euros']: CashRegisterSummaryItem(cash_summary=summary, value=100, quantity=cd['hundred_euros']).save()
# Checks
if cd['check_1_quantity']: CashRegisterSummaryItem(cash_summary=summary, value=cd['check_1_value'], quantity=cd['check_1_quantity']).save()
if cd['check_2_quantity']: CashRegisterSummaryItem(cash_summary=summary, value=cd['check_2_value'], quantity=cd['check_2_quantity']).save()
if cd['check_3_quantity']: CashRegisterSummaryItem(cash_summary=summary, value=cd['check_3_value'], quantity=cd['check_3_quantity']).save()
if cd['check_4_quantity']: CashRegisterSummaryItem(cash_summary=summary, value=cd['check_4_value'], quantity=cd['check_4_quantity']).save()
if cd['check_5_quantity']: CashRegisterSummaryItem(cash_summary=summary, value=cd['check_5_value'], quantity=cd['check_5_quantity']).save()
if summary.items.count() < 1:
summary.delete()
class CounterCashSummaryView(CanViewMixin, DetailView):
"""
Provide the cash summary form
"""
model = Counter
pk_url_kwarg = "counter_id"
template_name = 'counter/cash_register_summary.jinja'
def get(self, request, *args, **kwargs):
self.object = self.get_object()
if len(self.object.get_barmen_list()) < 1:
return HttpResponseRedirect(reverse_lazy('counter:details', args=self.args,
kwargs={'counter_id': self.object.id}))
self.form = CashRegisterSummaryForm()
return super(CounterCashSummaryView, self).get(request, *args, **kwargs)
def post(self, request, *args, **kwargs):
self.object = self.get_object()
if len(self.object.get_barmen_list()) < 1:
return HttpResponseRedirect(reverse_lazy('counter:details', args=self.args,
kwargs={'counter_id': self.object.id}))
self.form = CashRegisterSummaryForm(request.POST)
if self.form.is_valid():
self.form.save(self.object)
return HttpResponseRedirect(self.get_success_url())
return super(CounterCashSummaryView, self).get(request, *args, **kwargs)
def get_success_url(self):
return reverse_lazy('counter:details', kwargs={'counter_id': self.object.id})
def get_context_data(self, **kwargs):
""" Add form to the context """
kwargs = super(CounterCashSummaryView, self).get_context_data(**kwargs)
kwargs['form'] = self.form
return kwargs
......@@ -6,7 +6,7 @@
msgid ""
msgstr ""
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2016-08-24 21:38+0200\n"
"POT-Creation-Date: 2016-08-26 20: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"
......@@ -16,158 +16,186 @@ msgstr ""
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=2; plural=(n > 1);\n"
#: accounting/models.py:34 accounting/models.py:46 accounting/models.py:73
#: accounting/models.py:123 club/models.py:18 counter/models.py:52
#: accounting/models.py:36 accounting/models.py:55 accounting/models.py:82
#: accounting/models.py:132 club/models.py:18 counter/models.py:52
#: counter/models.py:77 counter/models.py:111 launderette/models.py:15
#: launderette/models.py:60 launderette/models.py:85
msgid "name"
msgstr "nom"
#: accounting/models.py:37
msgid "street"
msgstr "rue"
#: accounting/models.py:38
msgid "city"
msgstr "ville"
#: accounting/models.py:39
msgid "postcode"
msgstr "code postal"
#: accounting/models.py:40
msgid "country"
msgstr "pays"
#: accounting/models.py:41 core/models.py:166
msgid "phone"
msgstr "téléphone"
#: accounting/models.py:42
msgid "email"
msgstr "email"
#: accounting/models.py:43
msgid "website"
msgstr "site internet"
#: accounting/models.py:46
msgid "company"
msgstr "entreprise"
#: accounting/models.py:47
#: accounting/models.py:56
msgid "iban"
msgstr "IBAN"
#: accounting/models.py:48
#: accounting/models.py:57
msgid "account number"
msgstr "numero de compte"
#: accounting/models.py:49 accounting/models.py:74 club/models.py:146
#: counter/models.py:86
#: accounting/models.py:58 accounting/models.py:83 club/models.py:146
#: counter/models.py:86 counter/models.py:112
msgid "club"
msgstr "club"
#: accounting/models.py:52
#: accounting/models.py:61
msgid "Bank account"
msgstr "Compte en banque"
#: accounting/models.py:75
#: accounting/models.py:84
msgid "bank account"
msgstr "compte en banque"
#: accounting/models.py:78
#: accounting/models.py:87
msgid "Club account"
msgstr "Compte club"
#: accounting/models.py:114
#: accounting/models.py:123
#, python-format
msgid "%(club_account)s on %(bank_account)s"
msgstr "%(club_account)s sur %(bank_account)s"
#: accounting/models.py:121 club/models.py:147 counter/models.py:297
#: accounting/models.py:130 club/models.py:147 counter/models.py:282
#: launderette/models.py:122
msgid "start date"
msgstr "date de début"
#: accounting/models.py:122 club/models.py:148 counter/models.py:298
#: accounting/models.py:131 club/models.py:148 counter/models.py:283
msgid "end date"
msgstr "date de fin"
#: accounting/models.py:124
#: accounting/models.py:133
msgid "is closed"
msgstr "est fermé"
#: accounting/models.py:125
#: accounting/models.py:134
msgid "club account"
msgstr "compte club"
#: accounting/models.py:126 accounting/models.py:169 counter/models.py:25
#: counter/models.py:212
#: accounting/models.py:135 accounting/models.py:178 counter/models.py:25
#: counter/models.py:197
msgid "amount"
msgstr "montant"
#: accounting/models.py:127
#: accounting/models.py:136
msgid "effective_amount"
msgstr "montant effectif"
#: accounting/models.py:130
#: accounting/models.py:139
msgid "General journal"
msgstr "Classeur"
#: accounting/models.py:167
#: accounting/models.py:176
msgid "number"
msgstr "numéro"
#: accounting/models.py:168
#: accounting/models.py:177
msgid "journal"
msgstr "classeur"
#: accounting/models.py:170 core/models.py:437 core/models.py:713
#: counter/models.py:215 counter/models.py:261 eboutic/models.py:14
#: eboutic/models.py:47
#: accounting/models.py:179 core/models.py:437 core/models.py:713
#: counter/models.py:200 counter/models.py:246 counter/models.py:296
#: eboutic/models.py:14 eboutic/models.py:47
msgid "date"
msgstr "date"
#: accounting/models.py:171
#: accounting/models.py:180 counter/models.py:297
msgid "comment"
msgstr "commentaire"
#: accounting/models.py:172 counter/models.py:216 counter/models.py:262
#: accounting/models.py:181 counter/models.py:201 counter/models.py:247
#: subscription/models.py:34
msgid "payment method"
msgstr "méthode de paiement"
#: accounting/models.py:173
#: accounting/models.py:182
msgid "cheque number"
msgstr "numéro de chèque"
#: accounting/models.py:174 eboutic/models.py:115
#: accounting/models.py:183 eboutic/models.py:115
msgid "invoice"
msgstr "facture"
#: accounting/models.py:175
#: accounting/models.py:184
msgid "is done"
msgstr "est fait"
#: accounting/models.py:177
#: accounting/models.py:186
msgid "simple type"
msgstr "type simplifié"
#: accounting/models.py:179 accounting/models.py:278
#: accounting/models.py:188 accounting/models.py:287
msgid "accounting type"
msgstr "type comptable"
#: accounting/models.py:180
#: accounting/models.py:189
msgid "target type"
msgstr "type de cible"
#: accounting/models.py:181
#: accounting/models.py:190
#: launderette/templates/launderette/launderette_admin.jinja:44
msgid "User"
msgstr "Utilisateur"
#: accounting/models.py:181 club/templates/club/club_detail.jinja:4
#: accounting/models.py:190 club/templates/club/club_detail.jinja:4
msgid "Club"
msgstr "Club"
#: accounting/models.py:181 core/templates/core/user_base.jinja:18
#: accounting/models.py:190 core/templates/core/user_base.jinja:18
msgid "Account"
msgstr "Compte"
#: accounting/models.py:181
#: accounting/models.py:190
msgid "Company"
msgstr "Entreprise"
#: accounting/models.py:181 sith/settings.py:289 sith/settings_sample.py:272
#: accounting/models.py:190 sith/settings.py:290 sith/settings_sample.py:272
msgid "Other"
msgstr "Autre"
#: accounting/models.py:182
#: accounting/models.py:191
msgid "target id"
msgstr "id de la cible"
#: accounting/models.py:183
#: accounting/models.py:192
msgid "target label"
msgstr "nom de la cible"
#: accounting/models.py:184
#: accounting/models.py:193
msgid "linked operation"
msgstr "opération liée"
#: accounting/models.py:200
#: accounting/models.py:209
#, python-format
msgid ""
"The date can not be before the start date of the journal, which is\n"
......@@ -176,16 +204,16 @@ msgstr ""
"La date ne peut pas être avant la date de début du journal, qui est\n"
"%(start_date)s."
#: accounting/models.py:203
#: accounting/models.py:212
msgid "Target does not exists"
msgstr "La cible n'existe pas."
#: accounting/models.py:205
#: accounting/models.py:214
msgid "Please add a target label if you set no existing target"
msgstr ""
"Merci d'ajouter un nom de cible si vous ne spécifiez pas de cible existante"
#: accounting/models.py:207
#: accounting/models.py:216
msgid ""
"You need to provide ether a simplified accounting type or a standard "
"accounting type"
......@@ -193,39 +221,39 @@ msgstr ""
"Vous devez fournir soit un type comptable simplifié ou un type comptable "
"standard"
#: accounting/models.py:268 counter/models.py:81
#: accounting/models.py:277 counter/models.py:81
msgid "code"
msgstr "code"
#: accounting/models.py:270
#: accounting/models.py:279
msgid "An accounting type code contains only numbers"
msgstr "Un code comptable ne contient que des numéros"
#: accounting/models.py:273 accounting/models.py:299 counter/models.py:253
#: accounting/models.py:282 accounting/models.py:308 counter/models.py:238
msgid "label"
msgstr "intitulé"
#: accounting/models.py:274
#: accounting/models.py:283
msgid "movement type"
msgstr "type de mouvement"
#: accounting/models.py:274
#: accounting/models.py:283
msgid "Credit"
msgstr "Crédit"
#: accounting/models.py:274
#: accounting/models.py:283
msgid "Debit"
msgstr "Débit"
#: accounting/models.py:275
#: accounting/models.py:284
msgid "Neutral"
msgstr "Neutre"
#: accounting/models.py:301
#: accounting/models.py:310
msgid "simplified accounting types"
msgstr "type simplifié"
#: accounting/models.py:304
#: accounting/models.py:313
msgid "simplified type"
msgstr "type simplifié"
......@@ -264,26 +292,36 @@ msgstr "Il n'y a pas de types comptable dans ce site web."
msgid "Bank account: "
msgstr "Compte en banque : "
#: accounting/templates/accounting/bank_account_details.jinja:14
#: accounting/templates/accounting/bank_account_details.jinja:15
#: accounting/templates/accounting/club_account_details.jinja:16
#: core/templates/core/file_detail.jinja:43
#: core/templates/core/group_list.jinja:13
#: core/templates/core/user_edit.jinja:18
#: launderette/templates/launderette/launderette_admin.jinja:16
#: launderette/views.py:146
msgid "Delete"
msgstr "Supprimer"
#: accounting/templates/accounting/bank_account_details.jinja:17
#: core/templates/core/user_base.jinja:7
msgid "Infos"
msgstr "Infos"
#: accounting/templates/accounting/bank_account_details.jinja:16
#: accounting/templates/accounting/bank_account_details.jinja:19
msgid "IBAN: "
msgstr "IBAN : "
#: accounting/templates/accounting/bank_account_details.jinja:17
#: accounting/templates/accounting/bank_account_details.jinja:20
msgid "Number: "
msgstr "Numéro : "
#: accounting/templates/accounting/bank_account_details.jinja:19
#: accounting/templates/accounting/bank_account_details.jinja:22
msgid "New club account"
msgstr "Nouveau compte club"