feat: Playtomic pricing/occupancy pipeline + email i18n + audience restructure

Three workstreams:

1. Playtomic full data extraction & transform pipeline:
   - Expand venue bounding boxes from 4 to 23 regions (global coverage)
   - New staging models for court resources, opening hours, and slot-level
     availability with real prices from the Playtomic API
   - Foundation fact tables for venue capacity and daily occupancy/revenue
   - City-level pricing benchmarks replacing hardcoded country estimates
   - Planner defaults now use 3-tier cascade: city data → country → fallback

2. Transactional email i18n:
   - _t() helper in worker.py with ~70 translation keys (EN + DE)
   - All 8 email handlers translated, lang passed in task payloads

3. Resend audiences restructured to 3 named audiences (free plan limit)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
Deeman
2026-02-23 00:54:53 +01:00
parent c25e20f83a
commit 79f7fc6fad
24 changed files with 1318 additions and 324 deletions

View File

@@ -28,7 +28,7 @@ logger = setup_logging("padelnomics.extract.playtomic_availability")
EXTRACTOR_NAME = "playtomic_availability"
AVAILABILITY_URL = "https://api.playtomic.io/v1/availability"
THROTTLE_SECONDS = 2
THROTTLE_SECONDS = 1
MAX_VENUES_PER_RUN = 10_000
MAX_RETRIES_PER_VENUE = 2

View File

@@ -24,16 +24,89 @@ EXTRACTOR_NAME = "playtomic_tenants"
PLAYTOMIC_TENANTS_URL = "https://api.playtomic.io/v1/tenants"
THROTTLE_SECONDS = 2
PAGE_SIZE = 20
PAGE_SIZE = 100
MAX_PAGES_PER_BBOX = 500 # safety bound — prevents infinite pagination
MAX_STALE_PAGES = 3 # stop after N consecutive pages with zero new results
# Target markets: Spain, UK/Ireland, Germany, France
# Global padel markets — bounding boxes sized to stay under API's internal result cap.
# Large countries (Spain, Italy, USA) are split into sub-regions.
BBOXES = [
{"min_latitude": 35.95, "min_longitude": -9.39, "max_latitude": 43.79, "max_longitude": 4.33},
# Spain — south (Andalusia, Murcia, Valencia)
{"min_latitude": 35.95, "min_longitude": -9.39, "max_latitude": 39.87, "max_longitude": 4.33},
# Spain — north (Madrid, Catalonia, Basque Country)
{"min_latitude": 39.87, "min_longitude": -9.39, "max_latitude": 43.79, "max_longitude": 4.33},
# UK & Ireland
{"min_latitude": 49.90, "min_longitude": -8.62, "max_latitude": 60.85, "max_longitude": 1.77},
# Germany
{"min_latitude": 47.27, "min_longitude": 5.87, "max_latitude": 55.06, "max_longitude": 15.04},
# France
{"min_latitude": 41.36, "min_longitude": -5.14, "max_latitude": 51.09, "max_longitude": 9.56},
# Italy — south (Rome, Naples, Sicily, Sardinia)
{"min_latitude": 36.35, "min_longitude": 6.62, "max_latitude": 42.00, "max_longitude": 18.51},
# Italy — north (Milan, Turin, Venice, Bologna)
{"min_latitude": 42.00, "min_longitude": 6.62, "max_latitude": 47.09, "max_longitude": 18.51},
# Portugal
{"min_latitude": 37.00, "min_longitude": -9.50, "max_latitude": 42.15, "max_longitude": -6.19},
# Netherlands
{"min_latitude": 50.75, "min_longitude": 3.37, "max_latitude": 53.47, "max_longitude": 7.21},
# Belgium
{"min_latitude": 49.50, "min_longitude": 2.55, "max_latitude": 51.50, "max_longitude": 6.40},
# Austria
{"min_latitude": 46.37, "min_longitude": 9.53, "max_latitude": 49.02, "max_longitude": 17.16},
# Switzerland
{"min_latitude": 45.82, "min_longitude": 5.96, "max_latitude": 47.80, "max_longitude": 10.49},
# Sweden
{"min_latitude": 55.34, "min_longitude": 11.11, "max_latitude": 69.06, "max_longitude": 24.16},
# Denmark
{"min_latitude": 54.56, "min_longitude": 8.09, "max_latitude": 57.75, "max_longitude": 12.69},
# Norway
{"min_latitude": 57.97, "min_longitude": 4.50, "max_latitude": 71.19, "max_longitude": 31.17},
# Finland
{"min_latitude": 59.81, "min_longitude": 20.55, "max_latitude": 70.09, "max_longitude": 31.59},
# Mexico
{
"min_latitude": 14.53,
"min_longitude": -118.37,
"max_latitude": 32.72,
"max_longitude": -86.71,
},
# Argentina
{
"min_latitude": -55.06,
"min_longitude": -73.56,
"max_latitude": -21.78,
"max_longitude": -53.63,
},
# Middle East (UAE, Qatar, Saudi Arabia, Bahrain)
{"min_latitude": 21.00, "min_longitude": 38.00, "max_latitude": 32.00, "max_longitude": 56.50},
# USA — southwest (California, Arizona, Texas west)
{
"min_latitude": 24.50,
"min_longitude": -125.00,
"max_latitude": 37.00,
"max_longitude": -100.00,
},
# USA — southeast (Florida, Texas east, Georgia)
{
"min_latitude": 24.50,
"min_longitude": -100.00,
"max_latitude": 37.00,
"max_longitude": -66.95,
},
# USA — northwest
{
"min_latitude": 37.00,
"min_longitude": -125.00,
"max_latitude": 49.38,
"max_longitude": -100.00,
},
# USA — northeast (New York, Chicago, Boston)
{
"min_latitude": 37.00,
"min_longitude": -100.00,
"max_latitude": 49.38,
"max_longitude": -66.95,
},
]