Files
gogo-telefon/tests/test_units.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

68 lines
2.3 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.
"""Small unit tests: working hours, Bosnian formatting, SMS templates, crypto."""
from datetime import datetime
from zoneinfo import ZoneInfo
from gogo import crypto
from gogo.hours import DEFAULT_WORKING_HOURS, hours_summary_bs, is_open_at
from gogo.i18n import fmt_price, fmt_slot
from gogo.models import Tenant
from gogo.sms.templates import render_sms
TZ = ZoneInfo("Europe/Sarajevo")
def test_is_open_at():
wh = DEFAULT_WORKING_HOURS
assert is_open_at(wh, datetime(2026, 7, 15, 10, 0, tzinfo=TZ), TZ) # Wed 10:00
assert not is_open_at(wh, datetime(2026, 7, 15, 20, 0, tzinfo=TZ), TZ) # Wed 20:00
assert not is_open_at(wh, datetime(2026, 7, 19, 10, 0, tzinfo=TZ), TZ) # Sun
assert is_open_at(wh, datetime(2026, 7, 18, 13, 59, tzinfo=TZ), TZ) # Sat 13:59
assert not is_open_at(wh, datetime(2026, 7, 18, 14, 0, tzinfo=TZ), TZ) # Sat 14:00
def test_hours_summary_bs():
s = hours_summary_bs(DEFAULT_WORKING_HOURS)
assert "ponedjeljak: 09:0018:00" in s
assert "nedjelja: zatvoreno" in s
def test_fmt_slot_bosnian():
dt = datetime(2026, 7, 15, 17, 0, tzinfo=TZ) # Wednesday
assert fmt_slot(dt) == "srijeda, 15.07. u 17:00"
def test_fmt_price():
assert fmt_price(60, 90) == "6090 KM"
assert fmt_price(25, 25) == "25 KM"
assert fmt_price(30, None) == "30 KM"
assert fmt_price(None, None) == "cijena na upit"
def make_tenant(**kw):
defaults = dict(name="Salon Merima", sms_templates={})
defaults.update(kw)
return Tenant(**defaults)
def test_sms_default_templates():
t = make_tenant()
body = render_sms(
t, "confirmation", usluga="Manikir", dan="srijeda", datum="15.07.2026.", vrijeme="17:00"
)
assert body == "Potvrđen termin: Manikir, srijeda 15.07.2026. u 17:00h — Salon Merima."
def test_sms_tenant_override():
t = make_tenant(sms_templates={"rejection": "{salon}: ne može, žao nam je."})
assert render_sms(t, "rejection") == "Salon Merima: ne može, žao nam je."
def test_sms_unknown_placeholder_left_intact():
t = make_tenant(sms_templates={"missed_call": "Pozovite {salon}{nepoznato}"})
assert render_sms(t, "missed_call", link="x") == "Pozovite Salon Merima — {nepoznato}"
def test_crypto_roundtrip():
assert crypto.decrypt(crypto.encrypt("tajna-lozinka")) == "tajna-lozinka"