Files
gogo-telefon/gogo/i18n.py
Senad Uka e855650f09 M1: backend core + proposal engine
- FastAPI skeleton, SQLAlchemy models (§13), Alembic initial migration
- SchedulingProvider interface with google_calendar (free/busy read-only),
  partner_api (Appendix B client) and mock implementations
- Proposal engine: create → provider-routed delivery → owner actions
  (resolve/confirm+SMS/reject) → expiry + reminders (§9)
- Signed single-use action links, .ics METHOD:REQUEST attachment
- Partner outcome webhook with HMAC verification + polling fallback
- SmsProvider (console) with Bosnian templates (§5.5), EmailProvider (console/SMTP)
- Fake partner API server in tests/ — Appendix B reference implementation
- 43 tests: slot math, proposal lifecycle, action links, partner contract

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-11 09:45:06 +02:00

66 lines
1.6 KiB
Python
Raw 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.
"""Bosnian (Latin) formatting helpers for client- and owner-facing text."""
from __future__ import annotations
from datetime import datetime
from zoneinfo import ZoneInfo
DAY_NAMES = [
"ponedjeljak",
"utorak",
"srijeda",
"četvrtak",
"petak",
"subota",
"nedjelja",
]
MONTH_NAMES = [
"januar",
"februar",
"mart",
"april",
"maj",
"juni",
"juli",
"august",
"septembar",
"oktobar",
"novembar",
"decembar",
]
def fmt_slot(dt: datetime, tz: str = "Europe/Sarajevo") -> str:
"""'srijeda, 15.07. u 17:00'"""
local = dt.astimezone(ZoneInfo(tz))
day = DAY_NAMES[local.weekday()]
return f"{day}, {local.day:02d}.{local.month:02d}. u {local:%H:%M}"
def fmt_date(dt: datetime, tz: str = "Europe/Sarajevo") -> str:
local = dt.astimezone(ZoneInfo(tz))
return f"{local.day:02d}.{local.month:02d}.{local.year}."
def fmt_time(dt: datetime, tz: str = "Europe/Sarajevo") -> str:
local = dt.astimezone(ZoneInfo(tz))
return f"{local:%H:%M}"
def fmt_price(price_min: float | None, price_max: float | None, currency: str = "KM") -> str:
cur = "KM" if currency == "BAM" else currency
if price_min is None and price_max is None:
return "cijena na upit"
if price_max is None or price_min == price_max:
return f"{_num(price_min)} {cur}"
if price_min is None:
return f"do {_num(price_max)} {cur}"
return f"{_num(price_min)}{_num(price_max)} {cur}"
def _num(x: float | None) -> str:
if x is None:
return "?"
return str(int(x)) if float(x).is_integer() else f"{x:.2f}".replace(".", ",")