Translate app

This commit is contained in:
Gabriel Augendre 2022-04-25 23:04:49 +02:00
parent d16d9307f4
commit bc3b06bc17
19 changed files with 651 additions and 47 deletions

View file

@ -0,0 +1,61 @@
# SOME DESCRIPTIVE TITLE.
# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
# This file is distributed under the same license as the PACKAGE package.
# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
#
#, fuzzy
msgid ""
msgstr ""
"Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2022-04-25 23:04+0200\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: LANGUAGE <LL@li.org>\n"
"Language: \n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
#: src/common/templates/403.html:4
msgid "Permission denied"
msgstr ""
#: src/common/templates/403.html:5
msgid "You're not allowed to access this page."
msgstr ""
#: src/common/templates/404.html:4
msgid "Page not found"
msgstr ""
#: src/common/templates/404.html:5
msgid "We tried and tried but couldn't find the page you're looking for."
msgstr ""
#: src/common/templates/500.html:11
msgid "Server error (500)"
msgstr ""
#: src/common/templates/500.html:12
msgid ""
"There's an error on our end. Don't worry though, our engineers are already "
"working to fix it!"
msgstr ""
#: src/common/templates/common/navbar.html:12
msgid "New basket"
msgstr ""
#: src/common/templates/common/navbar.html:17
msgid "Baskets"
msgstr ""
#: src/common/templates/common/navbar.html:20
msgid "Reports"
msgstr ""
#: src/common/templates/common/navbar.html:25
msgid "Admin"
msgstr ""

View file

@ -0,0 +1,62 @@
# Copyright (C) 2022 Gabriel Augendre
# This file is distributed under the same license as the package.
# Gabriel Augendre <gabriel@augendre.info>, 2022.
msgid ""
msgstr ""
"Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2022-04-25 23:04+0200\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: LANGUAGE <LL@li.org>\n"
"Language: \n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=2; plural=(n > 1);\n"
#: src/common/templates/403.html:4
msgid "Permission denied"
msgstr "Permission refusée"
#: src/common/templates/403.html:5
msgid "You're not allowed to access this page."
msgstr "Vous n'avez pas le droit d'accéder à cette page"
#: src/common/templates/404.html:4
msgid "Page not found"
msgstr "Page non trouvée"
#: src/common/templates/404.html:5
msgid "We tried and tried but couldn't find the page you're looking for."
msgstr ""
"Nous avons cherché partout mais nous n'avons pas trouvé la page que vous "
"cherchiez."
#: src/common/templates/500.html:11
msgid "Server error (500)"
msgstr "Erreur serveur (500)"
#: src/common/templates/500.html:12
msgid ""
"There's an error on our end. Don't worry though, our engineers are already "
"working to fix it!"
msgstr ""
"Il y a une erreur de notre côté. Ne vous inquiétez pas, nos ingénieurs "
"travaillent déjà à sa résolution !"
#: src/common/templates/common/navbar.html:12
msgid "New basket"
msgstr "Nouveau panier"
#: src/common/templates/common/navbar.html:17
msgid "Baskets"
msgstr "Paniers"
#: src/common/templates/common/navbar.html:20
msgid "Reports"
msgstr "Rapports"
#: src/common/templates/common/navbar.html:25
msgid "Admin"
msgstr "Admin"

View file

@ -1,5 +1,6 @@
{% extends "common/base.html" %}
{% load i18n %}
{% block content %}
<h1>Permission denied</h1>
<p>You're not allowed to access this page.</p>
<h1>{% translate "Permission denied" %}</h1>
<p>{% translate "You're not allowed to access this page." %}</p>
{% endblock %}

View file

@ -1,5 +1,6 @@
{% extends "common/base.html" %}
{% load i18n %}
{% block content %}
<h1>Page not found</h1>
<p>We tried and tried but couldn't find the page you're looking for.</p>
<h1>{% translate "Page not found" %}</h1>
<p>{% translate "We tried and tried but couldn't find the page you're looking for." %}</p>
{% endblock %}

View file

@ -1,3 +1,4 @@
{% load i18n %}
<!DOCTYPE html>
<html lang="en">
<head>
@ -7,7 +8,7 @@
<style>html { font-family: sans-serif; }</style>
</head>
<body>
<h1>Server error (500)</h1>
<p>There's an error on our end. Don't worry, our engineers are already working on it!</p>
<h1>{% translate "Server error (500)" %}</h1>
<p>{% translate "There's an error on our end. Don't worry though, our engineers are already working to fix it!" %}</p>
</body>
</html>

View file

@ -1,3 +1,4 @@
{% load i18n %}
<nav class="navbar navbar-expand-lg navbar-light bg-light">
<div class="container-fluid">
<a class="navbar-brand" href="{% url "purchase:list" %}">Checkout</a>
@ -8,20 +9,20 @@
<ul class="navbar-nav me-auto mb-2 mb-lg-0">
{% if perms.purchase.add_basket %}
<li class="nav-item">
<a href="{% url "purchase:new" %}" class="nav-link">New basket</a>
<a href="{% url "purchase:new" %}" class="nav-link">{% translate "New basket" %}</a>
</li>
{% endif %}
{% if perms.purchase.view_basket %}
<li class="nav-item">
<a href="{% url "purchase:list" %}" class="nav-link">Baskets</a>
<a href="{% url "purchase:list" %}" class="nav-link">{% translate "Baskets" %}</a>
</li>
<li class="nav-item">
<a href="{% url "purchase:reports" %}" class="nav-link">Reports</a>
<a href="{% url "purchase:reports" %}" class="nav-link">{% translate "Reports" %}</a>
</li>
{% endif %}
{% if user.is_staff %}
<li class="nav-item">
<a class="nav-link" href="{% url "admin:index" %}">Admin</a>
<a class="nav-link" href="{% url "admin:index" %}">{% translate "Admin" %}</a>
</li>
{% endif %}
</ul>

View file

@ -1,5 +1,6 @@
from django.contrib import admin
from django.contrib.admin import register
from django.utils.translation import gettext_lazy as _
from purchase.models import Basket, BasketItem, PaymentMethod, Product
from purchase.templatetags.purchase import currency
@ -14,12 +15,15 @@ class ProductAdmin(admin.ModelAdmin):
def get_queryset(self, request):
return super().get_queryset(request).with_sold().with_turnover()
@admin.display(description=_("unit price"))
def unit_price(self, instance: Product):
return currency(instance.unit_price_cents)
@admin.display(description=_("sold"))
def sold(self, instance: Product):
return instance.sold
@admin.display(description=_("turnover"))
def turnover(self, instance: Product):
return currency(instance.turnover)
@ -32,6 +36,7 @@ class PaymentMethodAdmin(admin.ModelAdmin):
def get_queryset(self, request):
return super().get_queryset(request).with_turnover()
@admin.display(description=_("turnover"))
def turnover(self, instance: Product):
return currency(instance.turnover)
@ -45,6 +50,7 @@ class BasketItemInline(admin.TabularInline):
def get_queryset(self, request):
return super().get_queryset(request).priced()
@admin.display(description=_("price"))
def price(self, instance) -> str:
return currency(instance.price)
@ -61,5 +67,6 @@ class BasketAdmin(admin.ModelAdmin):
def get_queryset(self, request):
return super().get_queryset(request).priced()
@admin.display(description=_("price"))
def price(self, instance) -> str:
return currency(instance.price)

View file

@ -1,6 +1,7 @@
from crispy_forms.helper import FormHelper
from crispy_forms.layout import Div, Field, Layout, Submit
from django import forms
from django.utils.translation import gettext as _
from purchase.layout import BasketItemField
from purchase.models import Basket, Product
@ -19,7 +20,7 @@ class BasketForm(forms.ModelForm):
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.helper = FormHelper()
self.helper.add_input(Submit("submit", "Save"))
self.helper.add_input(Submit("submit", _("Save")))
self.helper.layout = Layout()
products = {}
basket = kwargs.get("instance")

View file

@ -0,0 +1,210 @@
# SOME DESCRIPTIVE TITLE.
# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
# This file is distributed under the same license as the PACKAGE package.
# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
#
#, fuzzy
msgid ""
msgstr ""
"Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2022-04-25 23:04+0200\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: LANGUAGE <LL@li.org>\n"
"Language: \n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
#: src/purchase/admin.py:18
msgid "unit price"
msgstr ""
#: src/purchase/admin.py:22
msgid "sold"
msgstr ""
#: src/purchase/admin.py:26 src/purchase/admin.py:39
msgid "turnover"
msgstr ""
#: src/purchase/admin.py:53 src/purchase/admin.py:70
msgid "price"
msgstr ""
#: src/purchase/forms.py:23
msgid "Save"
msgstr ""
#: src/purchase/models.py:10
msgid "created at"
msgstr ""
#: src/purchase/models.py:11
msgid "updated at"
msgstr ""
#: src/purchase/models.py:31 src/purchase/models.py:58
msgid "name"
msgstr ""
#: src/purchase/models.py:36 src/purchase/models.py:128
msgid "payment method"
msgstr ""
#: src/purchase/models.py:37
msgid "payment methods"
msgstr ""
#: src/purchase/models.py:59
msgid "image"
msgstr ""
#: src/purchase/models.py:61
msgid "unit price (cents)"
msgstr ""
#: src/purchase/models.py:61
msgid "unit price in cents"
msgstr ""
#: src/purchase/models.py:64
msgid "display order"
msgstr ""
#: src/purchase/models.py:71 src/purchase/models.py:154
msgid "product"
msgstr ""
#: src/purchase/models.py:72
msgid "products"
msgstr ""
#: src/purchase/models.py:134 src/purchase/models.py:160
msgid "basket"
msgstr ""
#: src/purchase/models.py:135
msgid "baskets"
msgstr ""
#: src/purchase/models.py:138
#, python-format
msgid "Basket #%(id)s"
msgstr ""
#: src/purchase/models.py:162
msgid "quantity"
msgstr ""
#: src/purchase/models.py:167
msgid "basket item"
msgstr ""
#: src/purchase/models.py:168
msgid "basket items"
msgstr ""
#: src/purchase/templates/purchase/basket_confirm_delete.html:7
#, python-format
msgid "Are you sure you want to delete \"%(basket)s\"?"
msgstr ""
#: src/purchase/templates/purchase/basket_form.html:11
msgid "Missing payment method."
msgstr ""
#: src/purchase/templates/purchase/basket_form.html:14
msgid "New basket"
msgstr ""
#: src/purchase/templates/purchase/basket_form.html:18
msgid "New"
msgstr ""
#: src/purchase/templates/purchase/basket_list.html:5
msgid "Baskets"
msgstr ""
#: src/purchase/templates/purchase/basket_list.html:11
#, python-format
msgid "Basket #%(basket_id)s"
msgstr ""
#: src/purchase/templates/purchase/basket_list.html:13
#, python-format
msgid "1 item"
msgid_plural "%(counter)s items"
msgstr[0] ""
msgstr[1] ""
#: src/purchase/templates/purchase/reports.html:6
msgid "Reports"
msgstr ""
#: src/purchase/templates/purchase/reports.html:7
msgid "General"
msgstr ""
#: src/purchase/templates/purchase/reports.html:9
msgid "Total turnover:"
msgstr ""
#: src/purchase/templates/purchase/reports.html:10
msgid "Average basket:"
msgstr ""
#: src/purchase/templates/purchase/reports.html:13
msgid "Products"
msgstr ""
#: src/purchase/templates/purchase/reports.html:16
msgid "Turnover by payment method"
msgstr ""
#: src/purchase/templates/purchase/reports.html:19
msgid "Baskets without payment method"
msgstr ""
#: src/purchase/templates/purchase/snippets/report_no_payment_method.html:6
msgid "Basket ID"
msgstr ""
#: src/purchase/templates/purchase/snippets/report_no_payment_method.html:7
msgid "Price"
msgstr ""
#: src/purchase/templates/purchase/snippets/report_payment_methods.html:6
msgid "Payment method"
msgstr ""
#: src/purchase/templates/purchase/snippets/report_payment_methods.html:7
msgid "# baskets"
msgstr ""
#: src/purchase/templates/purchase/snippets/report_payment_methods.html:8
#: src/purchase/templates/purchase/snippets/report_products.html:8
msgid "Turnover"
msgstr ""
#: src/purchase/templates/purchase/snippets/report_products.html:6
msgid "Product"
msgstr ""
#: src/purchase/templates/purchase/snippets/report_products.html:7
msgid "# sold"
msgstr ""
#: src/purchase/views/basket.py:15
msgid "Successfully created basket."
msgstr ""
#: src/purchase/views/basket.py:30
msgid "Successfully updated basket."
msgstr ""
#: src/purchase/views/basket.py:45
msgid "Basket successfully deleted."
msgstr ""

View file

@ -0,0 +1,223 @@
# Copyright (C) 2022 Gabriel Augendre
# This file is distributed under the same license as the package.
# Gabriel Augendre <gabriel@augendre.info>, 2022.
msgid ""
msgstr ""
"Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2022-04-25 23:04+0200\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: LANGUAGE <LL@li.org>\n"
"Language: \n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=2; plural=(n > 1);\n"
#: src/purchase/admin.py:18
msgid "unit price"
msgstr "prix unitaire"
#: src/purchase/admin.py:22
msgid "sold"
msgstr "vendu"
#: src/purchase/admin.py:26 src/purchase/admin.py:39
msgid "turnover"
msgstr "chiffre d'affaires"
#: src/purchase/admin.py:53 src/purchase/admin.py:70
msgid "price"
msgstr "prix"
#: src/purchase/forms.py:23
msgid "Save"
msgstr "Enregistrer"
#: src/purchase/models.py:10
msgid "created at"
msgstr "créé à"
#: src/purchase/models.py:11
msgid "updated at"
msgstr "mis à jour à"
#: src/purchase/models.py:31 src/purchase/models.py:58
msgid "name"
msgstr "nom"
#: src/purchase/models.py:36 src/purchase/models.py:128
msgid "payment method"
msgstr "moyen de paiement"
#: src/purchase/models.py:37
msgid "payment methods"
msgstr "moyens de paiement"
#: src/purchase/models.py:59
msgid "image"
msgstr "image"
#: src/purchase/models.py:61
msgid "unit price (cents)"
msgstr "prix unitaire (centimes)"
#: src/purchase/models.py:61
msgid "unit price in cents"
msgstr "prix unitaire en centimes"
#: src/purchase/models.py:64
msgid "display order"
msgstr "ordre d'affichage"
#: src/purchase/models.py:71 src/purchase/models.py:154
msgid "product"
msgstr "produit"
#: src/purchase/models.py:72
msgid "products"
msgstr "produits"
#: src/purchase/models.py:134 src/purchase/models.py:160
msgid "basket"
msgstr "panier"
#: src/purchase/models.py:135
msgid "baskets"
msgstr "paniers"
#: src/purchase/models.py:138
#, python-format
msgid "Basket #%(id)s"
msgstr "Panier n°%(id)s"
#: src/purchase/models.py:162
msgid "quantity"
msgstr "quantité"
#: src/purchase/models.py:167
msgid "basket item"
msgstr "article de panier"
#: src/purchase/models.py:168
msgid "basket items"
msgstr "articles de panier"
#: src/purchase/templates/purchase/basket_confirm_delete.html:7
#, python-format
msgid "Are you sure you want to delete \"%(basket)s\"?"
msgstr "Êtes-vous sûr de vouloir supprimer \"%(basket)s\" ?"
#: src/purchase/templates/purchase/basket_form.html:11
msgid "Missing payment method."
msgstr "Moyen de paiement manquant."
#: src/purchase/templates/purchase/basket_form.html:14
msgid "New basket"
msgstr "Nouveau panier"
#: src/purchase/templates/purchase/basket_form.html:18
msgid "New"
msgstr "Nouveau"
#: src/purchase/templates/purchase/basket_list.html:5
msgid "Baskets"
msgstr "Paniers"
#: src/purchase/templates/purchase/basket_list.html:11
#, python-format
msgid "Basket #%(basket_id)s"
msgstr "Panier n°%(basket_id)s"
#: src/purchase/templates/purchase/basket_list.html:13
#, python-format
msgid "1 item"
msgid_plural "%(counter)s items"
msgstr[0] "1 article"
msgstr[1] "%(counter)s articles"
#: src/purchase/templates/purchase/reports.html:6
msgid "Reports"
msgstr "Rapports"
#: src/purchase/templates/purchase/reports.html:7
msgid "General"
msgstr "Général"
#: src/purchase/templates/purchase/reports.html:9
msgid "Total turnover:"
msgstr "Chiffre d'affaires total :"
#: src/purchase/templates/purchase/reports.html:10
msgid "Average basket:"
msgstr "Panier moyen :"
#: src/purchase/templates/purchase/reports.html:13
msgid "Products"
msgstr "Produits"
#: src/purchase/templates/purchase/reports.html:16
msgid "Turnover by payment method"
msgstr "Chiffre d'affaires par moyen de paiement"
#: src/purchase/templates/purchase/reports.html:19
msgid "Baskets without payment method"
msgstr "Paniers sans moyen de paiement"
#: src/purchase/templates/purchase/snippets/report_no_payment_method.html:6
msgid "Basket ID"
msgstr "Id de panier"
#: src/purchase/templates/purchase/snippets/report_no_payment_method.html:7
msgid "Price"
msgstr "Prix"
#: src/purchase/templates/purchase/snippets/report_payment_methods.html:6
msgid "Payment method"
msgstr "Moyen de paiement"
#: src/purchase/templates/purchase/snippets/report_payment_methods.html:7
msgid "# baskets"
msgstr "Nb. de paniers"
#: src/purchase/templates/purchase/snippets/report_payment_methods.html:8
#: src/purchase/templates/purchase/snippets/report_products.html:8
msgid "Turnover"
msgstr "Chiffre d'affaires"
#: src/purchase/templates/purchase/snippets/report_products.html:6
msgid "Product"
msgstr "Produit"
#: src/purchase/templates/purchase/snippets/report_products.html:7
msgid "# sold"
msgstr "Nb. vendus"
#: src/purchase/views/basket.py:15
msgid "Successfully created basket."
msgstr "Panier correctement créé."
#: src/purchase/views/basket.py:30
msgid "Successfully updated basket."
msgstr "Panier correctement modifié."
#: src/purchase/views/basket.py:45
msgid "Basket successfully deleted."
msgstr "Panier correctement supprimé."
#, python-format
#~ msgid "Total turnover: %(total|currency)s"
#~ msgstr "Chiffre d'affaires total : %(total|currency)s"
#, python-format
#~ msgid "Average basket: %(average_basket|currency)s"
#~ msgstr "Panier moyen : %(average_basket|currency)s"
#, python-brace-format
#~ msgid "Basket #{self.id}"
#~ msgstr "Panier n°{self.id}"
#, python-format
#~ msgid "%(basket.items.count)s items"
#~ msgstr "%(basket.items.count)s articles"

View file

@ -1,12 +1,14 @@
from django.db import models
from django.db.models import Count, F, Sum
from django.urls import reverse
from django.utils.translation import gettext
from django.utils.translation import gettext_lazy as _
from PIL import Image, ImageOps
class Model(models.Model):
created_at = models.DateTimeField(auto_now_add=True)
updated_at = models.DateTimeField(auto_now=True)
created_at = models.DateTimeField(auto_now_add=True, verbose_name=_("created at"))
updated_at = models.DateTimeField(auto_now=True, verbose_name=_("updated at"))
class Meta:
abstract = True
@ -26,10 +28,14 @@ class PaymentMethodQuerySet(models.QuerySet):
class PaymentMethod(Model):
name = models.CharField(max_length=50, unique=True)
name = models.CharField(max_length=50, unique=True, verbose_name=_("name"))
objects = PaymentMethodQuerySet.as_manager()
class Meta:
verbose_name = _("payment method")
verbose_name_plural = _("payment methods")
def __str__(self):
return self.name
@ -49,15 +55,21 @@ class ProductQuerySet(models.QuerySet):
class Product(Model):
name = models.CharField(max_length=250, unique=True)
image = models.ImageField(null=True, blank=True)
unit_price_cents = models.PositiveIntegerField()
display_order = models.PositiveIntegerField(default=default_product_display_order)
name = models.CharField(max_length=250, unique=True, verbose_name=_("name"))
image = models.ImageField(null=True, blank=True, verbose_name=_("image"))
unit_price_cents = models.PositiveIntegerField(
verbose_name=_("unit price (cents)"), help_text=_("unit price in cents")
)
display_order = models.PositiveIntegerField(
default=default_product_display_order, verbose_name=_("display order")
)
objects = ProductQuerySet.as_manager()
class Meta:
ordering = ["display_order", "name"]
verbose_name = _("product")
verbose_name_plural = _("products")
def __str__(self):
return self.name
@ -113,12 +125,17 @@ class Basket(Model):
related_name="baskets",
null=True,
blank=True,
verbose_name=_("payment method"),
)
objects = BasketQuerySet.as_manager()
class Meta:
verbose_name = _("basket")
verbose_name_plural = _("baskets")
def __str__(self):
return f"Basket #{self.id}"
return gettext("Basket #%(id)s") % {"id": self.id}
def get_absolute_url(self):
return reverse("purchase:update", args=(self.pk,))
@ -131,11 +148,21 @@ class BasketItemQuerySet(models.QuerySet):
class BasketItem(Model):
product = models.ForeignKey(
to=Product, on_delete=models.PROTECT, related_name="basket_items"
to=Product,
on_delete=models.PROTECT,
related_name="basket_items",
verbose_name=_("product"),
)
basket = models.ForeignKey(
to=Basket, on_delete=models.CASCADE, related_name="items"
to=Basket,
on_delete=models.CASCADE,
related_name="items",
verbose_name=_("basket"),
)
quantity = models.PositiveIntegerField()
quantity = models.PositiveIntegerField(verbose_name=_("quantity"))
objects = BasketItemQuerySet.as_manager()
class Meta:
verbose_name = _("basket item")
verbose_name_plural = _("basket items")

View file

@ -1,9 +1,10 @@
{% extends "common/base.html" %}
{% load i18n %}
{% block content %}
<h1>{{ object }}</h1>
<form method="post">
{% csrf_token %}
<p>Are you sure you want to delete "{{ object }}"?</p>
<p>{% blocktranslate %}Are you sure you want to delete "{{ basket }}"?{% endblocktranslate %}</p>
{{ form }}
<input class="btn btn-danger" type="submit" value="Confirm">
</form>

View file

@ -1,4 +1,5 @@
{% extends "common/base.html" %}
{% load i18n %}
{% load crispy_forms_tags purchase %}
{% block content %}
{% if object %}
@ -7,13 +8,13 @@
{{ object.created_at }}
</p>
{% if not object.payment_method %}
<div class="alert alert-danger" role="alert">Missing payment method.</div>
<div class="alert alert-danger" role="alert">{% translate "Missing payment method." %}</div>
{% endif %}
{% else %}
<h1>New basket</h1>
<h1>{% translate "New basket" %}</h1>
{% endif %}
{% crispy form %}
{% if object %}
<a href="{% url "purchase:new" %}" class="btn btn-secondary">New</a>
<a href="{% url "purchase:new" %}" class="btn btn-secondary">{% translate "New" %}</a>
{% endif %}
{% endblock %}

View file

@ -1,15 +1,16 @@
{% extends "common/base.html" %}
{% load i18n %}
{% load purchase %}
{% block content %}
<h1>Baskets</h1>
<h1>{% translate "Baskets" %}</h1>
<div class="row row-cols-auto g-4">
{% for basket in baskets %}
<div class="col">
<div class="card h-100 {% if not basket.payment_method %}bg-warning text-black{% endif %}">
<div class="card-body">
<h5 class="card-title">Basket #{{ basket.id }}</h5>
<h5 class="card-title">{% blocktranslate with basket_id=basket.id %}Basket #{{ basket_id }}{% endblocktranslate %}</h5>
<p class="card-text">
{{ basket.items.count }} items<br>
{% blocktranslate count counter=basket.items.count %}1 item{% plural %}{{ counter }} items{% endblocktranslate %}<br>
{{ basket.price|currency }}<br>
{{ basket.payment_method|default:"-" }}
</p>

View file

@ -1,21 +1,22 @@
{% extends "common/base.html" %}
{% load i18n %}
{% load purchase %}
{% block content %}
<h1>Reports</h1>
<h2>General</h2>
<h1>{% translate "Reports" %}</h1>
<h2>{% translate "General" %}</h2>
<ul>
<li>Total turnover: {{ total|currency }}</li>
<li>Average basket: {{ average_basket|currency }}</li>
<li>{% translate "Total turnover:" %} {{ total|currency }}</li>
<li>{% translate "Average basket:" %} {{ average_basket|currency }}</li>
</ul>
<h2>Products</h2>
<h2>{% translate "Products" %}</h2>
{% include "purchase/snippets/report_products.html" %}
<h2>Turnover by payment method</h2>
<h2>{% translate "Turnover by payment method" %}</h2>
{% include "purchase/snippets/report_payment_methods.html" %}
<h2>Baskets without payment method</h2>
<h2>{% translate "Baskets without payment method" %}</h2>
{% include "purchase/snippets/report_no_payment_method.html" %}
{% endblock %}

View file

@ -1,9 +1,10 @@
{% load i18n %}
{% load purchase %}
<table class="table table-hover table-sm">
<thead><tr>
<th scope="col">Basket ID</th>
<th scope="col">Price</th>
<th scope="col">{% translate "Basket ID" %}</th>
<th scope="col">{% translate "Price" %}</th>
</tr></thead>
<tbody>
{% for basket in no_payment_method %}

View file

@ -1,10 +1,11 @@
{% load i18n %}
{% load purchase %}
<table class="table table-hover table-sm">
<thead><tr>
<th scope="col">Payment method</th>
<th scope="col"># baskets</th>
<th scope="col">Turnover</th>
<th scope="col">{% translate "Payment method" %}</th>
<th scope="col">{% translate "# baskets" %}</th>
<th scope="col">{% translate "Turnover" %}</th>
</tr></thead>
<tbody>
{% for payment_method in payment_methods %}

View file

@ -1,10 +1,11 @@
{% load i18n %}
{% load purchase %}
<table class="table table-hover table-sm">
<thead><tr>
<th scope="col">Product</th>
<th scope="col"># sold</th>
<th scope="col">Turnover</th>
<th scope="col">{% translate "Product" %}</th>
<th scope="col">{% translate "# sold" %}</th>
<th scope="col">{% translate "Turnover" %}</th>
</tr></thead>
<tbody>
{% for product in products %}

View file

@ -1,5 +1,6 @@
from django.contrib.messages.views import SuccessMessageMixin
from django.urls import reverse
from django.utils.translation import gettext_lazy as _
from django.views.generic import CreateView, DeleteView, ListView, UpdateView
from purchase.forms import BasketForm
@ -11,7 +12,7 @@ class NewBasketView(ProtectedViewsMixin, SuccessMessageMixin, CreateView):
permission_required = ["purchase.add_basket"]
model = Basket
form_class = BasketForm
success_message = "Successfully created basket."
success_message = _("Successfully created basket.")
queryset = Basket.objects.priced()
@ -26,7 +27,7 @@ class UpdateBasketView(ProtectedViewsMixin, SuccessMessageMixin, UpdateView):
permission_required = ["purchase.change_basket", "purchase.view_basket"]
model = Basket
form_class = BasketForm
success_message = "Successfully updated basket."
success_message = _("Successfully updated basket.")
queryset = Basket.objects.priced()
@ -41,8 +42,9 @@ class ListBasketsView(ProtectedViewsMixin, ListView):
class DeleteBasketView(ProtectedViewsMixin, SuccessMessageMixin, DeleteView):
permission_required = ["purchase.delete_basket"]
model = Basket
success_message = "Basket successfully deleted."
success_message = _("Basket successfully deleted.")
queryset = Basket.objects.priced()
context_object_name = "basket"
def get_success_url(self):
return reverse("purchase:list")