From 4c9d665ae2bd1aa93b89709345540fd1b3674b09 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mateusz=20Gruszczy=C5=84ski?= Date: Thu, 2 Apr 2026 08:25:07 +0200 Subject: [PATCH] zmiana waluty w .env --- .env.example | 8 +++++- config.py | 2 ++ shopping_app/helpers.py | 19 +++++++++++++ shopping_app/sockets.py | 2 +- shopping_app/static/js/expense_chart.js | 2 +- shopping_app/static/js/expense_table.js | 2 +- shopping_app/static/js/functions.js | 16 +++++++++++ shopping_app/static/js/live.js | 6 ++-- shopping_app/static/js/preview_list_modal.js | 2 +- shopping_app/static/js/receipt_analysis.js | 2 +- shopping_app/static/js/select_all_table.js | 2 +- shopping_app/templates/_list_progress.html | 2 +- shopping_app/templates/admin/admin_panel.html | 28 +++++++++---------- shopping_app/templates/admin/edit_list.html | 2 +- shopping_app/templates/base.html | 4 +++ shopping_app/templates/expenses.html | 4 +-- shopping_app/templates/list.html | 4 +-- shopping_app/templates/list_share.html | 10 +++---- shopping_app/templates/main.html | 2 +- shopping_app/web.py | 3 ++ 20 files changed, 86 insertions(+), 36 deletions(-) diff --git a/.env.example b/.env.example index 7983e53..3baffa4 100644 --- a/.env.example +++ b/.env.example @@ -195,4 +195,10 @@ UPLOADS_CACHE_CONTROL="max-age=3600, immutable" # UWAGA: wielkość liter w nazwach jest zachowywana, ale porównywanie odbywa się # bez rozróżniania wielkości liter (case-insensitive). # Domyślnie: poniższa lista -DEFAULT_CATEGORIES="Spożywcze,Budowlane,Zabawki,Chemia,Inne,Elektronika,Odzież i obuwie,Artykuły biurowe,Kosmetyki i higiena,Motoryzacja,Ogród i rośliny,Zwierzęta,Sprzęt sportowy,Książki i prasa,Narzędzia i majsterkowanie,RTV / AGD,Apteka i suplementy,Artykuły dekoracyjne,Gry i hobby,Usługi,Pieczywo" \ No newline at end of file +DEFAULT_CATEGORIES="Spożywcze,Budowlane,Zabawki,Chemia,Inne,Elektronika,Odzież i obuwie,Artykuły biurowe,Kosmetyki i higiena,Motoryzacja,Ogród i rośliny,Zwierzęta,Sprzęt sportowy,Książki i prasa,Narzędzia i majsterkowanie,RTV / AGD,Apteka i suplementy,Artykuły dekoracyjne,Gry i hobby,Usługi,Pieczywo" + +# Waluta używana w całej aplikacji (kwoty, paragony, analizy) +# Użyj kodu ISO 4217 (np. PLN, EUR, USD, GBP) +# Domyślnie: PLN (jeśli zmienna nie jest ustawiona) + +CURRENCY_CODE=PLN \ No newline at end of file diff --git a/config.py b/config.py index c960ac7..e0f6085 100644 --- a/config.py +++ b/config.py @@ -91,6 +91,8 @@ class Config: DEBUG_MODE = env_bool("DEBUG_MODE", True) DISABLE_ROBOTS = env_bool("DISABLE_ROBOTS", False) + CURRENCY_CODE = env_str("CURRENCY_CODE", "PLN").strip().upper() or "PLN" + JS_CACHE_CONTROL = env_str("JS_CACHE_CONTROL", "no-cache") CSS_CACHE_CONTROL = env_str("CSS_CACHE_CONTROL", "no-cache") LIB_JS_CACHE_CONTROL = env_str("LIB_JS_CACHE_CONTROL", "max-age=604800") diff --git a/shopping_app/helpers.py b/shopping_app/helpers.py index e061cc0..1c60371 100644 --- a/shopping_app/helpers.py +++ b/shopping_app/helpers.py @@ -2,6 +2,25 @@ from .deps import * from .app_setup import * from .models import * + +def get_currency_code() -> str: + code = str(app.config.get("CURRENCY_CODE", "PLN") or "PLN").strip().upper() + return code or "PLN" + + +def format_currency(amount, include_code: bool = True) -> str: + try: + normalized = float(amount or 0) + except (TypeError, ValueError): + normalized = 0.0 + formatted = f"{normalized:.2f}" + return f"{formatted} {get_currency_code()}" if include_code else formatted + + +def currency_placeholder(prefix: str = "Kwota") -> str: + return f"{prefix} ({get_currency_code()})" + + def get_setting(key: str, default: str | None = None) -> str | None: s = db.session.get(AppSetting, key) return s.value if s else default diff --git a/shopping_app/sockets.py b/shopping_app/sockets.py index bfa14ba..f28a199 100644 --- a/shopping_app/sockets.py +++ b/shopping_app/sockets.py @@ -453,7 +453,7 @@ def handle_add_expense(data): ) db.session.add(new_expense) - log_list_activity(list_id, 'expense_added', item_name=None, actor=current_user if current_user.is_authenticated else None, actor_name=current_user.username if current_user.is_authenticated else 'Gość', details=f'kwota: {float(amount):.2f} PLN') + log_list_activity(list_id, 'expense_added', item_name=None, actor=current_user if current_user.is_authenticated else None, actor_name=current_user.username if current_user.is_authenticated else 'Gość', details=f'kwota: {format_currency(amount)}') db.session.commit() total = ( diff --git a/shopping_app/static/js/expense_chart.js b/shopping_app/static/js/expense_chart.js index 2b8c918..bd8b19c 100644 --- a/shopping_app/static/js/expense_chart.js +++ b/shopping_app/static/js/expense_chart.js @@ -123,7 +123,7 @@ document.addEventListener("DOMContentLoaded", function () { data: { labels: data.labels || [], datasets: [{ - label: "Suma wydatków [PLN]", + label: `Suma wydatków [${getCurrencyCode()}]`, data: data.expenses || [], }], }, diff --git a/shopping_app/static/js/expense_table.js b/shopping_app/static/js/expense_table.js index 694c47f..0d46cf8 100644 --- a/shopping_app/static/js/expense_table.js +++ b/shopping_app/static/js/expense_table.js @@ -28,7 +28,7 @@ document.addEventListener('DOMContentLoaded', () => { total += parseFloat(cb.dataset.amount); } }); - totalEl.textContent = total.toFixed(2) + ' PLN'; + totalEl.textContent = formatCurrencyAmount(total); } function getISOWeek(date) { diff --git a/shopping_app/static/js/functions.js b/shopping_app/static/js/functions.js index e332151..09fc220 100644 --- a/shopping_app/static/js/functions.js +++ b/shopping_app/static/js/functions.js @@ -1,3 +1,19 @@ +function getCurrencyCode() { + return window.CURRENCY_CODE || 'PLN'; +} + +function formatCurrencyAmount(amount, options = {}) { + const includeCode = options.includeCode !== false; + const numeric = Number(amount || 0); + const safe = Number.isFinite(numeric) ? numeric : 0; + const formatted = safe.toFixed(2); + return includeCode ? `${formatted} ${getCurrencyCode()}` : formatted; +} + +function currencyLabel(prefix = 'Kwota') { + return `${prefix} (${getCurrencyCode()})`; +} + function updateItemState(itemId, isChecked) { const checkbox = document.querySelector(`#item-${itemId} input[type='checkbox']`); if (checkbox) { diff --git a/shopping_app/static/js/live.js b/shopping_app/static/js/live.js index 4538a12..22a11c7 100644 --- a/shopping_app/static/js/live.js +++ b/shopping_app/static/js/live.js @@ -113,7 +113,7 @@ function setupList(listId, username) { socket.on('expense_added', data => { const badgeEl = document.getElementById('total-expense1'); if (badgeEl) { - badgeEl.innerHTML = `💸 ${data.total.toFixed(2)} PLN`; + badgeEl.innerHTML = `💸 ${formatCurrencyAmount(data.total)}`; badgeEl.classList.remove('bg-secondary'); badgeEl.classList.add('bg-success'); badgeEl.style.display = ''; @@ -121,10 +121,10 @@ function setupList(listId, username) { const summaryEl = document.getElementById('total-expense2'); if (summaryEl) { - summaryEl.innerHTML = `💸 Łącznie wydano: ${data.total.toFixed(2)} PLN`; + summaryEl.innerHTML = `💸 Łącznie wydano: ${formatCurrencyAmount(data.total)}`; } - showToast(`Dodano wydatek: ${data.amount.toFixed(2)} PLN`, 'info'); + showToast(`Dodano wydatek: ${formatCurrencyAmount(data.amount)}`, 'info'); }); diff --git a/shopping_app/static/js/preview_list_modal.js b/shopping_app/static/js/preview_list_modal.js index 15e5349..77c66fa 100644 --- a/shopping_app/static/js/preview_list_modal.js +++ b/shopping_app/static/js/preview_list_modal.js @@ -99,7 +99,7 @@ document.addEventListener("DOMContentLoaded", function () { summary.innerHTML = `

📦 ${totalCount} produktów

✅ Kupione: ${purchasedCount} (${percent}%)

-

💸 Wydatek: ${totalExpense.toFixed(2)} zł

`; +

💸 Wydatek: ${formatCurrencyAmount(totalExpense)}

`; productList.appendChild(summary); const purchased = createSection("✔️ Kupione"); diff --git a/shopping_app/static/js/receipt_analysis.js b/shopping_app/static/js/receipt_analysis.js index 3717ebe..d939dd3 100644 --- a/shopping_app/static/js/receipt_analysis.js +++ b/shopping_app/static/js/receipt_analysis.js @@ -22,7 +22,7 @@ async function analyzeReceipts(listId) { let html = `
`; html += `

⏱ Czas analizy OCR: ${duration} sek.

`; - html += `

📊 Łącznie wykryto: ${data.total.toFixed(2)} PLN

`; + html += `

📊 Łącznie wykryto: ${formatCurrencyAmount(data.total)}

`; data.results.forEach((r, i) => { const disabled = r.already_added ? "disabled" : ""; diff --git a/shopping_app/static/js/select_all_table.js b/shopping_app/static/js/select_all_table.js index dc5a0d5..e2c9abf 100644 --- a/shopping_app/static/js/select_all_table.js +++ b/shopping_app/static/js/select_all_table.js @@ -12,7 +12,7 @@ document.addEventListener('DOMContentLoaded', () => { total += parseFloat(cb.dataset.amount); } }); - totalEl.textContent = total.toFixed(2) + ' PLN'; + totalEl.textContent = formatCurrencyAmount(total); } selectAllBtn.addEventListener('click', () => { diff --git a/shopping_app/templates/_list_progress.html b/shopping_app/templates/_list_progress.html index e304d4f..817a784 100644 --- a/shopping_app/templates/_list_progress.html +++ b/shopping_app/templates/_list_progress.html @@ -27,7 +27,7 @@ Produkty: {{ purchased_count }}/{{ total_count }} ({{ percent|round(0)|int }}%) - {% if total_expense > 0 %} — 💸 {{ '%.2f'|format(total_expense) }} PLN{% endif %} + {% if total_expense > 0 %} — 💸 {{ format_currency(total_expense) }}{% endif %}
\ No newline at end of file diff --git a/shopping_app/templates/admin/admin_panel.html b/shopping_app/templates/admin/admin_panel.html index 2be0e6f..1885ee4 100644 --- a/shopping_app/templates/admin/admin_panel.html +++ b/shopping_app/templates/admin/admin_panel.html @@ -51,7 +51,7 @@ 💸 Średnia kwota na listę - {{ avg_list_expense }} zł + {{ format_currency(avg_list_expense) }} @@ -115,30 +115,30 @@ Wszystkie - {{ '%.2f'|format(expense_summary.all.month) }} PLN - {{ '%.2f'|format(expense_summary.all.year) }} PLN - {{ '%.2f'|format(expense_summary.all.total) }} PLN + {{ format_currency(expense_summary.all.month) }} + {{ format_currency(expense_summary.all.year) }} + {{ format_currency(expense_summary.all.total) }} Aktywne - {{ '%.2f'|format(expense_summary.active.month) }} PLN - {{ '%.2f'|format(expense_summary.active.year) }} PLN - {{ '%.2f'|format(expense_summary.active.total) }} PLN + {{ format_currency(expense_summary.active.month) }} + {{ format_currency(expense_summary.active.year) }} + {{ format_currency(expense_summary.active.total) }} Archiwalne - {{ '%.2f'|format(expense_summary.archived.month) }} PLN - {{ '%.2f'|format(expense_summary.archived.year) }} PLN - {{ '%.2f'|format(expense_summary.archived.total) }} PLN + {{ format_currency(expense_summary.archived.month) }} + {{ format_currency(expense_summary.archived.year) }} + {{ format_currency(expense_summary.archived.total) }} Wygasłe - {{ '%.2f'|format(expense_summary.expired.month) }} PLN - {{ '%.2f'|format(expense_summary.expired.year) }} PLN - {{ '%.2f'|format(expense_summary.expired.total) }} PLN + {{ format_currency(expense_summary.expired.month) }} + {{ format_currency(expense_summary.expired.year) }} + {{ format_currency(expense_summary.expired.total) }} @@ -282,7 +282,7 @@ {% if e.total_expense >= 500 %}text-danger {% elif e.total_expense > 0 %}text-success{% endif %}"> {% if e.total_expense > 0 %} - {{ '%.2f'|format(e.total_expense) }} PLN + {{ format_currency(e.total_expense) }} {% else %} - {% endif %} diff --git a/shopping_app/templates/admin/edit_list.html b/shopping_app/templates/admin/edit_list.html index 0dfcca6..82904fe 100644 --- a/shopping_app/templates/admin/edit_list.html +++ b/shopping_app/templates/admin/edit_list.html @@ -25,7 +25,7 @@
- +
diff --git a/shopping_app/templates/base.html b/shopping_app/templates/base.html index 9463165..70dc0cc 100644 --- a/shopping_app/templates/base.html +++ b/shopping_app/templates/base.html @@ -173,6 +173,10 @@ }); + + {% if request.endpoint != 'system_auth' %} diff --git a/shopping_app/templates/expenses.html b/shopping_app/templates/expenses.html index ddadd12..21f86d7 100644 --- a/shopping_app/templates/expenses.html +++ b/shopping_app/templates/expenses.html @@ -88,7 +88,7 @@
-
💰 Suma: 0.00 PLN
+
💰 Suma: {{ format_currency(0) }}
@@ -101,7 +101,7 @@ Nazwa listy Właściciel Data - Wydatki (PLN) + Wydatki ({{ CURRENCY_CODE }}) diff --git a/shopping_app/templates/list.html b/shopping_app/templates/list.html index e87f24c..23501ee 100644 --- a/shopping_app/templates/list.html +++ b/shopping_app/templates/list.html @@ -96,11 +96,11 @@
{% if total_expense > 0 %}
- 💸 Łącznie wydano: {{ '%.2f'|format(total_expense) }} PLN + 💸 Łącznie wydano: {{ format_currency(total_expense) }}
{% else %}
- 💸 Łącznie wydano: 0.00 PLN + 💸 Łącznie wydano: {{ format_currency(0) }}
{% endif %} diff --git a/shopping_app/templates/list_share.html b/shopping_app/templates/list_share.html index eefe776..851f96e 100644 --- a/shopping_app/templates/list_share.html +++ b/shopping_app/templates/list_share.html @@ -12,11 +12,11 @@ {% if total_expense > 0 %} - 💸 {{ '%.2f'|format(total_expense) }} PLN + 💸 {{ format_currency(total_expense) }} {% else %} {% endif %} @@ -114,7 +114,7 @@ 💰 Dodaj wydatek - 💸 Łączna suma: {{ '%.2f'|format(total_expense) }} PLN + 💸 Łączna suma: {{ format_currency(total_expense) }} @@ -123,7 +123,7 @@
+ placeholder="{{ currency_placeholder() }}">
diff --git a/shopping_app/web.py b/shopping_app/web.py index 0b117bc..2494ed8 100644 --- a/shopping_app/web.py +++ b/shopping_app/web.py @@ -26,6 +26,9 @@ def inject_version(): return { "APP_VERSION": app.config["APP_VERSION"], + "CURRENCY_CODE": get_currency_code(), + "format_currency": format_currency, + "currency_placeholder": currency_placeholder, "static_asset_url": static_asset_url, }