Added 'supply' page to create negative register transactions, updated translation

This commit is contained in:
W13R 2022-10-15 19:37:01 +02:00
parent 80b407069d
commit 86ea7c0000
10 changed files with 278 additions and 68 deletions

View file

@ -49,6 +49,10 @@ class CustomUserAdmin(UserAdmin):
{"fields": ("balance", "allow_order_with_negative_balance")},
))
fieldsets_.insert(2, (
"Supply",
{"fields": ("allowed_to_supply",)},
))
fieldsets_.insert(3, (
"Profile Picture",
{"fields": ("profile_picture_filename",)},
))

View file

@ -21,6 +21,7 @@ class User(AbstractUser):
balance = models.DecimalField(max_digits=8, decimal_places=2, default=0.00)
allow_order_with_negative_balance = models.BooleanField(default=False)
profile_picture_filename = models.CharField(default="default.svg", max_length=25)
allowed_to_supply = models.BooleanField(default=False)
def delete(self, *args, **kwargs):
self.balance = 0

View file

@ -0,0 +1,61 @@
{% extends "baseLayout.html" %}
{% load i18n %}
{% load l10n %}
{% block title %}
{% translate "Drinks - Supply" %}
{% endblock %}
{% block headAdditional %}
<link rel="stylesheet" href="/static/css/supply.css">
<link rel="stylesheet" href="/static/css/customNumberInput.css">
{% endblock %}
{% block heading %}
{% translate "Supply" %}
{% endblock %}
{% block content %}
{% if user.is_superuser or user.allowed_to_supply %}
<form id="supplyForm">
{% csrf_token %}
<div class="row">
<div class="column">{% translate "Description" %}:</div>
<input type="text" name="supplyDescription" id="supplyDescription" autofocus>
</div>
<div class="row">
<div class="column">{% translate "Price" %} ({{ currency_suffix }}):</div>
<div class="column">
<input type="number" name="supplyPrice" id="supplyPrice" max="9999.99" min="1.00" step="0.01">
</div>
</div>
<div id="statusInfo"></div>
<div class="horizontalButtonList">
<a href="/" class="button">{% translate "cancel" %}</a>
<input type="submit" id="supplySubmitBtn" class="button" value='{% translate "submit" %}'>
</div>
</form>
<script src="/static/js/supply.js"></script>
<script src="/static/js/customNumberInput.js"></script>
{% else %}
<div class="centeringFlex">
<p>{% translate "You are not allowed to view this site." %}</p>
<a href="/">{% translate "back" %}</a>
</div>
{% endif %}
<script src="/static/js/autoreload.js"></script>
{% endblock %}

View file

@ -32,6 +32,9 @@
{% if user.is_superuser or user.is_staff %}
<a class="button dropDownChoice" href="/admin/">Admin Panel</a>
{% endif %}
{% if user.is_superuser or user.allowed_to_supply %}
<a class="button dropDownChoice" href="/supply/">{% translate "Supply" %}</a>
{% endif %}
<a class="button dropDownChoice" href="/accounts/password_change/">{% translate "Change Password" %}</a>
</div>
</div>

View file

@ -10,6 +10,7 @@ urlpatterns = [
path('history/', views.history),
path('deposit/', views.deposit),
path('statistics/', views.statistics),
path('supply/', views.supply),
path('accounts/login/', views.login_page, name="login"),
path('accounts/logout/', auth_views.LogoutView.as_view(), name='logout'),
path('accounts/password_change/', auth_views.PasswordChangeView.as_view(), name='password_change'),
@ -18,5 +19,6 @@ urlpatterns = [
# API #
path('api/order-drink', views.api_order_drink),
path('api/deposit', views.api_deposit),
path('api/supply', views.api_supply)
#path('api/get-statistics', views.api_get_statistics)
]

View file

@ -103,6 +103,10 @@ def statistics(request):
}
return render(request, "statistics.html", context)
@login_required
def supply(request):
return render(request, "supply.html")
@login_required
def redirect_home(request):
return HttpResponseRedirect("/")
@ -132,7 +136,7 @@ def api_order_drink(request):
else:
return HttpResponse("notAvailable", status=400)
else: raise Exception("Balance below zero.")
else: raise Exception("Unexpected input or missing privileges.")
except Exception as e:
print(f"An exception occured while processing an order: User: {user.username} - Exception: {e}", file=sys.stderr)
@ -163,5 +167,33 @@ def api_deposit(request):
else: raise Exception("Deposit amount too big or small.")
except Exception as e:
print(f"An exception occured while processing an transaction: User: {user.username} - Exception: {e}", file=sys.stderr)
print(f"An exception occured while processing a transaction: User: {user.username} - Exception: {e}", file=sys.stderr)
return HttpResponse(b"", status=500)
@login_required
def api_supply(request):
# check request -> supply
user = request.user
try:
price = decimal.Decimal(request.POST["supplyPrice"])
description = str(request.POST["supplyDescription"])
if 0.00 < price < 9999.99 and (user.allowed_to_supply or user.is_superuser):
# create transaction
RegisterTransaction.objects.create(
transaction_sum=-price,
comment=f"Supply: {description}",
is_user_deposit=False,
user=user
)
#
return HttpResponse("success", status=200)
else: raise Exception("Unexpected input or missing privileges.")
except Exception as e:
print(f"An exception occured while processing a supply transaction: User: {user.username} - Exception: {e}", file=sys.stderr)
return HttpResponse(b"", status=500)

View file

@ -8,7 +8,7 @@ msgid ""
msgstr ""
"Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2022-06-13 19:01+0200\n"
"POT-Creation-Date: 2022-10-15 19:20+0200\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: Julian Müller (W13R)\n"
"Language: DE\n"
@ -17,221 +17,266 @@ msgstr ""
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
#: app/templates/admin/base_site.html:7
#: application/app/templates/admin/base_site.html:7
msgid "Django site admin"
msgstr "Django Administrator"
#: app/templates/admin/base_site.html:15
#: application/app/templates/admin/base_site.html:15
msgid "Django administration"
msgstr "Django Administration"
#: app/templates/baseLayout.html:41
#: application/app/templates/baseLayout.html:41
msgid "An error occured. Please log out and log in again."
msgstr "Ein Fehler ist aufgetreten. Bitte ab- und wieder anmelden."
#: app/templates/deposit.html:6
#: application/app/templates/deposit.html:6
msgid "Drinks - Deposit"
msgstr "Getränke - Einzahlen"
#: app/templates/deposit.html:14 app/templates/userPanel.html:19
#: application/app/templates/deposit.html:14
#: application/app/templates/userPanel.html:23
msgid "Deposit"
msgstr "Einzahlen"
#: app/templates/deposit.html:23
#: application/app/templates/deposit.html:23
msgid "Amount"
msgstr "Summe"
#: app/templates/deposit.html:31 app/templates/order.html:72
#: app/templates/registration/login.html:56
#: application/app/templates/deposit.html:31
#: application/app/templates/order.html:72
#: application/app/templates/registration/login.html:57
#: application/app/templates/supply.html:41
msgid "cancel"
msgstr "Abbrechen"
#: app/templates/deposit.html:32
#: application/app/templates/deposit.html:32
msgid "confirm"
msgstr "Bestätigen"
#: app/templates/history.html:6
#: application/app/templates/history.html:6
msgid "Drinks - History"
msgstr "Getränke - Verlauf"
#: app/templates/history.html:14 app/templates/userPanel.html:25
#: application/app/templates/history.html:14
#: application/app/templates/userPanel.html:30
msgid "History"
msgstr "Verlauf"
#: app/templates/history.html:22
#: application/app/templates/history.html:22
msgid "last 30 actions"
msgstr "letzte 30 Vorgänge"
#: app/templates/history.html:33 app/templates/statistics.html:41
#: app/templates/statistics.html:61 app/templates/statistics.html:81
#: app/templates/statistics.html:101 app/templates/statistics.html:121
#: app/templates/statistics.html:141
#: application/app/templates/history.html:33
#: application/app/templates/statistics.html:41
#: application/app/templates/statistics.html:61
#: application/app/templates/statistics.html:81
#: application/app/templates/statistics.html:101
#: application/app/templates/statistics.html:121
#: application/app/templates/statistics.html:141
msgid "No history."
msgstr "Kein Verlauf verfügbar."
#: app/templates/index.html:6
#: application/app/templates/index.html:6
msgid "Drinks - Home"
msgstr "Getränke - Home"
#: app/templates/index.html:14
#: application/app/templates/index.html:14
msgid "Available Drinks"
msgstr "Verfügbare Getränke"
#: app/templates/index.html:27 app/templates/index.html:34
#: application/app/templates/index.html:27
#: application/app/templates/index.html:34
msgid "available"
msgstr "verfügbar"
#: app/templates/index.html:43
#: application/app/templates/index.html:43
msgid "No drinks available."
msgstr "Es sind gerade keine Getränke verfügbar."
#: app/templates/order.html:7
#: application/app/templates/order.html:7
msgid "Drinks - Order"
msgstr "Getränke - Bestellen"
#: app/templates/order.html:16
#: application/app/templates/order.html:16
#: packages/django/forms/formsets.py:405 packages/django/forms/formsets.py:412
msgid "Order"
msgstr "Bestellung"
#: app/templates/order.html:29
#: application/app/templates/order.html:29
msgid "Drink"
msgstr "Getränk"
#: app/templates/order.html:34
#: application/app/templates/order.html:34
msgid "Price per Item"
msgstr "Preis pro Getränk"
#: app/templates/order.html:40
#: application/app/templates/order.html:40
msgid "Available"
msgstr "Verfügbar"
#: app/templates/order.html:46
#: application/app/templates/order.html:46
msgid "Count"
msgstr "Anzahl"
#: app/templates/order.html:63
#: application/app/templates/order.html:63
msgid "Sum"
msgstr "Summe"
#: app/templates/order.html:73
#: application/app/templates/order.html:73
msgid "order"
msgstr "Bestellen"
#: app/templates/order.html:85
#: application/app/templates/order.html:85
msgid "Your balance is too low to order a drink."
msgstr "Dein Saldo ist zu niedrig um Getränke zu bestellen."
#: app/templates/order.html:86 app/templates/order.html:95
#: application/app/templates/order.html:86
#: application/app/templates/order.html:95
#: application/app/templates/supply.html:54
msgid "back"
msgstr "zurück"
#: app/templates/order.html:94
#: application/app/templates/order.html:94
msgid "This drink is not available."
msgstr "Dieses Getränk ist gerade nicht verfügbar."
#: app/templates/registration/logged_out.html:7
#: application/app/templates/registration/logged_out.html:7
msgid "Drinks - Logged Out"
msgstr "Getränke - Abgemeldet"
#: app/templates/registration/logged_out.html:17
#: application/app/templates/registration/logged_out.html:17
msgid "Logged out! You will be redirected shortly."
msgstr "Du wurdest abgemeldet und wirst in Kürze weitergeleitet."
#: app/templates/registration/logged_out.html:19
#: application/app/templates/registration/logged_out.html:19
msgid "Click here if automatic redirection does not work."
msgstr ""
"Bitte klicke hier, wenn die automatische Weiterleitung nicht funktioniert."
#: app/templates/registration/login.html:7
#: application/app/templates/registration/login.html:8
msgid "Drinks - Login"
msgstr "Getränke - Anmeldung"
#: app/templates/registration/login.html:26
#: application/app/templates/registration/login.html:27
msgid "Log in"
msgstr "Anmelden"
#: app/templates/registration/login.html:28
#: application/app/templates/registration/login.html:29
msgid "Password/PIN"
msgstr "Passwort/PIN"
#: app/templates/registration/login.html:57
#: application/app/templates/registration/login.html:58
msgid "login"
msgstr "Anmelden"
#: app/templates/registration/login.html:65
#: application/app/templates/registration/login.html:66
msgid "Choose your account"
msgstr "Wähle deinen Account"
#: app/templates/statistics.html:6
#: application/app/templates/statistics.html:6
msgid "Drinks - Statistics"
msgstr "Getränke - Statistiken"
#: app/templates/statistics.html:15 app/templates/userPanel.html:26
#: application/app/templates/statistics.html:15
#: application/app/templates/userPanel.html:31
msgid "Statistics"
msgstr "Statistiken"
#: app/templates/statistics.html:26
#: application/app/templates/statistics.html:26
msgid "Your orders per drink"
msgstr "Deine Bestellungen pro Getränk"
#: app/templates/statistics.html:30 app/templates/statistics.html:50
#: application/app/templates/statistics.html:30
#: application/app/templates/statistics.html:50
msgid "drink"
msgstr "Getränk"
#: app/templates/statistics.html:31 app/templates/statistics.html:51
#: app/templates/statistics.html:71 app/templates/statistics.html:91
#: app/templates/statistics.html:111 app/templates/statistics.html:131
#: application/app/templates/statistics.html:31
#: application/app/templates/statistics.html:51
#: application/app/templates/statistics.html:71
#: application/app/templates/statistics.html:91
#: application/app/templates/statistics.html:111
#: application/app/templates/statistics.html:131
msgid "count"
msgstr "Anzahl"
#: app/templates/statistics.html:46
#: application/app/templates/statistics.html:46
msgid "All orders per drink"
msgstr "Alle Bestellungen pro Getränk"
#: app/templates/statistics.html:66
#: application/app/templates/statistics.html:66
msgid "Your orders per month (last 12 months)"
msgstr "Deine Bestellungen pro Monat (letzte 12 Monate)"
#: app/templates/statistics.html:70 app/templates/statistics.html:90
#: application/app/templates/statistics.html:70
#: application/app/templates/statistics.html:90
msgid "month"
msgstr "Monat"
#: app/templates/statistics.html:86
#: application/app/templates/statistics.html:86
msgid "All orders per month (last 12 months)"
msgstr "Alle Bestellungen pro Monat (letzte 12 Monate)"
#: app/templates/statistics.html:106
#: application/app/templates/statistics.html:106
msgid "Your orders per weekday"
msgstr "Deine Bestellungen pro Wochentag"
#: app/templates/statistics.html:110 app/templates/statistics.html:130
#: application/app/templates/statistics.html:110
#: application/app/templates/statistics.html:130
msgid "day"
msgstr "Tag"
#: app/templates/statistics.html:126
#: application/app/templates/statistics.html:126
msgid "All orders per weekday"
msgstr "Alle Bestellungen pro Wochentag"
#: app/templates/userPanel.html:6 app/templates/userPanel.html:8
#: application/app/templates/supply.html:7
msgid "Drinks - Supply"
msgstr "Getränke - Beschaffung"
#: application/app/templates/supply.html:16
#: application/app/templates/userPanel.html:36
msgid "Supply"
msgstr "Beschaffung"
#: application/app/templates/supply.html:27
msgid "Description"
msgstr "Beschreibung"
#: application/app/templates/supply.html:32
msgid "Price"
msgstr "Preis"
#: application/app/templates/supply.html:42
msgid "submit"
msgstr "Senden"
#: application/app/templates/supply.html:53
msgid "You are not allowed to view this site."
msgstr "Dir fehlt die Berechtigung, diese Seite anzuzeigen."
#: application/app/templates/userPanel.html:9
#: application/app/templates/userPanel.html:11
msgid "User"
msgstr "Benutzer"
#: app/templates/userPanel.html:12 app/templates/userPanel.html:14
#: application/app/templates/userPanel.html:15
#: application/app/templates/userPanel.html:17
msgid "Balance"
msgstr "Saldo"
#: app/templates/userPanel.html:22
msgid "Account"
msgstr "Account"
#: app/templates/userPanel.html:30
msgid "Change Password"
msgstr "Passwort ändern"
#: app/templates/userPanel.html:31
#: application/app/templates/userPanel.html:24
msgid "Logout"
msgstr "Abmelden"
#: app/views.py:47
#: application/app/templates/userPanel.html:27
msgid "Account"
msgstr "Account"
#: application/app/templates/userPanel.html:38
msgid "Change Password"
msgstr "Passwort ändern"
#: application/app/views.py:47
msgid "Invalid username or password."
msgstr "Benutzername oder Passwort ungültig."

6
static/css/supply.css Normal file
View file

@ -0,0 +1,6 @@
form {
width: 24rem;
}
#supplyPrice {
width: 10rem;
}

56
static/js/supply.js Normal file
View file

@ -0,0 +1,56 @@
document.addEventListener("DOMContentLoaded", () => {
// elements
let supply_description = document.getElementById("supplyDescription");
let supply_price = document.getElementById("supplyPrice");
let supply_form = document.getElementById("supplyForm");
let status_info = document.getElementById("statusInfo");
let supply_submit_button = document.getElementById("supplySubmitBtn");
// custom submit method
supply_form.addEventListener("submit", (event) => {
supply_submit_button.disabled = true;
event.preventDefault(); // Don't do the default submit action!
if (isNaN(parseFloat(supply_price.value)) || supply_description.value == "") {
status_info.innerText = "Please enter a description and price."
supply_submit_button.disabled = false;
}
let xhr = new XMLHttpRequest();
let formData = new FormData(supply_form);
xhr.addEventListener("load", (event) => {
status_ = event.target.status;
response_ = event.target.responseText;
if (status_ == 200 && response_ == "success") {
status_info.innerText = "Success.";
window.location.replace("/");
}
else {
status_info.classList.add("errorText");
status_info.innerText = "An error occured.";
window.setTimeout(() => { window.location.reload() }, 5000);
}
})
xhr.addEventListener("error", (event) => {
status_info.classList.add("errorText");
status_info.innerText = "An error occured.";
window.setTimeout(() => { window.location.reload() }, 5000);
})
xhr.open("POST", "/api/supply");
xhr.send(formData);
});
})