Files
Mateusz Gruszczyński 659f04f05f zapamietanie akcji
2026-07-19 19:00:04 +02:00

133 lines
4.7 KiB
Python
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
from datetime import date, datetime
from decimal import Decimal, InvalidOperation
from .extensions import db
from .models import AppSetting
KEYS = {
"enabled": "global_vat_override_enabled",
"name": "global_vat_override_name",
"rate": "global_vat_override_rate",
"start": "global_vat_override_start",
"end": "global_vat_override_end",
}
def _value(key, default=""):
setting = db.session.get(AppSetting, KEYS[key])
return setting.value if setting else default
def global_vat_override():
rate_raw = _value("rate")
try:
rate = Decimal(rate_raw) if rate_raw != "" else None
except InvalidOperation:
rate = None
return {
"enabled": _value("enabled", "0") == "1",
"name": _value("name", "Projekt rządowy"),
"rate": rate,
"start": _parse_date(_value("start")),
"end": _parse_date(_value("end")),
}
def _parse_date(value):
if not value:
return None
try:
return date.fromisoformat(value)
except ValueError:
return None
def effective_vat_rate(nominal_rate, on_date=None):
override = global_vat_override()
if not override["enabled"] or override["rate"] is None:
return Decimal(str(nominal_rate))
if isinstance(on_date, datetime):
on_date = on_date.date()
on_date = on_date or date.today()
if override["start"] and on_date < override["start"]:
return Decimal(str(nominal_rate))
if override["end"] and on_date > override["end"]:
return Decimal(str(nominal_rate))
return override["rate"]
def vat_override_for_date(nominal_rate, on_date=None):
"""Return a complete, immutable VAT-action snapshot for a date."""
override = global_vat_override()
if isinstance(on_date, datetime):
on_date = on_date.date()
on_date = on_date or date.today()
applies = bool(
override["enabled"]
and override["rate"] is not None
and (not override["start"] or on_date >= override["start"])
and (not override["end"] or on_date <= override["end"])
)
return {
"applied": applies,
"name": override["name"] if applies else None,
"rate": override["rate"] if applies else Decimal(str(nominal_rate)),
"start": override["start"] if applies else None,
"end": override["end"] if applies else None,
}
def freeze_vat_action(entry, nominal_rate, previous_fueled_at=None):
"""Attach VAT action conditions to an entry without rewriting valid history."""
fueled_date = entry.fueled_at.date() if isinstance(entry.fueled_at, datetime) else entry.fueled_at
previous_date = previous_fueled_at.date() if isinstance(previous_fueled_at, datetime) else previous_fueled_at
if entry.vat_action_frozen and (previous_date is None or previous_date == fueled_date):
return
snapshot = vat_override_for_date(nominal_rate, fueled_date)
entry.vat_action_frozen = True
entry.vat_action_applied = snapshot["applied"]
entry.vat_action_name = snapshot["name"]
entry.vat_action_rate = snapshot["rate"] if snapshot["applied"] else None
entry.vat_action_start = snapshot["start"]
entry.vat_action_end = snapshot["end"]
def entry_vat_rate(entry, nominal_rate):
if entry.vat_action_frozen:
if entry.vat_action_applied and entry.vat_action_rate is not None:
return Decimal(str(entry.vat_action_rate))
return Decimal(str(nominal_rate))
return effective_vat_rate(nominal_rate, entry.fueled_at)
def save_global_vat_override(form):
enabled = "enabled" in form
name = (form.get("name") or "Projekt rządowy").strip()
rate_raw = (form.get("rate") or "").strip()
start_raw = (form.get("start") or "").strip()
end_raw = (form.get("end") or "").strip()
if enabled:
try:
rate = Decimal(rate_raw)
except InvalidOperation as exc:
raise ValueError("Podaj prawidłową globalną stawkę VAT.") from exc
if rate < 0 or rate > 100:
raise ValueError("Globalna stawka VAT musi mieścić się w zakresie 0100%.")
if start_raw and not _parse_date(start_raw):
raise ValueError("Nieprawidłowa data rozpoczęcia.")
if end_raw and not _parse_date(end_raw):
raise ValueError("Nieprawidłowa data zakończenia.")
if start_raw and end_raw and start_raw > end_raw:
raise ValueError("Data zakończenia nie może być wcześniejsza niż rozpoczęcia.")
values = {
KEYS["enabled"]: "1" if enabled else "0",
KEYS["name"]: name,
KEYS["rate"]: rate_raw,
KEYS["start"]: start_raw,
KEYS["end"]: end_raw,
}
for key, value in values.items():
db.session.merge(AppSetting(key=key, value=value))