#!/usr/bin/env python3 """ atlas_seasonal_strategy.py — Generate context-aware strategic recommendations based on calendar season, NL economic windows, local Tilburg events, and Google Trends signals where available. Output: atlas-strategy.json — consumed by Atlas Command BRIEF tab "Strategy" card. The engine knows about: - Vakantiegeld payouts (25 mei – 5 juni) - Belastingteruggaaf windows (Mar-Apr) - Schoolstart (late aug / early sept) - Sint/Kerst spending (Nov-Dec) - Tilburgse Kermis (juli) - Q1/Q2/Q3/Q4 BTW aangifte deadlines - Ramadan / Suikerfeest (year-variable) Per current window, recommends: - Which revenue stream to prioritize - Which prospects to push - Which framing to use - What NOT to do """ import json import subprocess import sys import urllib.request from pathlib import Path from datetime import datetime, date, timedelta OUT_LOCAL = Path(r"C:\Users\Gebruiker\AppData\Local\Atlas\analyses\atlas-strategy.json") SSH = "root@" REMOTE = "/opt/atlas/dashboard/atlas-strategy.json" # Calendar windows (year-relative — adjusted to 2026) WINDOWS_2026 = [ { "name": "Vakantiegeld", "start": "2026-05-25", "end": "2026-06-05", "signal": "Consumer cash boost (€1.500-3.000 per consumer)", "push": [ "Werkplek STARTER €799 (consumer-friendly price)", "Kapper / horeca consumer-facing zaak-eigenaars (zij ervaren spend-piek)", "Atlas Agency retainers (klanten hebben budget voor pakketten)" ], "framing": "\"Vakantiegeld al binnen? Nieuwe werkplek-set is nu beste timing.\"", "avoid": ["Geen B2B-koud sales — owners distracted door consumer-rush"], "channels": ["WhatsApp", "Instagram", "Tilburg community"], }, { "name": "Pre-zomer rust", "start": "2026-06-06", "end": "2026-07-05", "signal": "Stabiele B2B window, vóór schoolvakantie", "push": [ "Atlas Agency cold-outreach (max response rate)", "POS Support Lite contract conversions (existing klanten)", "Werkplek PRO + KASSA (besluitvorming-tijd)" ], "framing": "\"Inrichten vóór zomerstop — na zomer = nieuwe kalender, schone start.\"", "avoid": ["Geen consumer-spend campagnes — vakantiegeld op"], "channels": ["WhatsApp", "Email B2B", "LinkedIn (1×/wk max)"], }, { "name": "Tilburgse Kermis", "start": "2026-07-17", "end": "2026-07-26", "signal": "Lokale horeca-piek (10 dagen)", "push": [ "POS Support Lite NU verkopen voor july readiness", "Kermis-tijdelijke POS rental aanbieden (€50/dag) — test market", "WhatsApp campagne richting kermis-deelnemers vóór kermis" ], "framing": "\"Kermis = jouw drukste week. Atlas Support Lite zorgt dat je POS niet stilvalt.\"", "avoid": ["Geen large-budget B2B proposals — operationele focus"], "channels": ["WhatsApp horeca", "Instagram Tilburg-tags"], }, { "name": "Schoolvakantie", "start": "2026-07-06", "end": "2026-08-17", "signal": "MKB-eigenaars meer tijd voor strategie + nieuwe leveranciers", "push": [ "Atlas Agency cold-outreach (BEST window — owners hebben tijd)", "Werkplek follow-ups op bestaande quotes", "Workshop POS voor Horeca (eerste editie juli)" ], "framing": "\"Tijd voor de zaak achter de zaak — Atlas helpt het systeem rond te krijgen.\"", "avoid": ["Geen sales-druk eerste 2 weken juli (vakantie-spirit)"], "channels": ["WhatsApp", "Instagram zaak-eigenaar netwerken", "Charif referral"], }, { "name": "Back to school + work", "start": "2026-08-18", "end": "2026-08-31", "signal": "Nieuwe office-setups, MKB equipment-piek", "push": [ "Werkplek PRO + KASSA push (office-upgrade tijd)", "Group-buy aanbod (5+ werkplekken voor MKB)", "Studenten-werkplekken (TilburgU/Avans semesterstart)" ], "framing": "\"Begin het nieuwe seizoen met systemen die werken.\"", "avoid": ["Geen low-budget peripherals — push hoog-marge bundels"], "channels": ["WhatsApp MKB", "TilburgU community", "Avans-area outreach"], }, { "name": "Najaar groei", "start": "2026-09-01", "end": "2026-10-31", "signal": "Najaars-momentum, beslissingen-tijd", "push": [ "Atlas Agency retainers (€250/mo) — vol momentum", "Bisogno + andere bestaande klanten verdieping", "Workshops 2×/mo schaal" ], "framing": "\"Voor december komt: maak je systeem klaar voor jaar-eind drukte.\"", "avoid": [], "channels": ["Alles open"], }, { "name": "Sint/Kerst opmaat", "start": "2026-11-01", "end": "2026-11-30", "signal": "B2C horeca-piek voorbereiden + boekhouders druk", "push": [ "Werkplek KASSA voor horeca die met sint/kerst druk gaat krijgen", "Cross-sell naar boekhouders (referral network — zij zien hun klanten worstelen)", "Year-end Atlas Support Lite incentives" ], "framing": "\"December = duurste maand om POS te laten falen. Nu is het tijd.\"", "avoid": [], "channels": ["Alles open"], }, { "name": "Eindejaarsspecial", "start": "2026-12-01", "end": "2026-12-23", "signal": "Cash + planning + 'kerstcadeau voor jezelf'-framing", "push": [ "Werkplek STARTER €799 als kerstcadeau voor zzp'er", "Q4 retainer-vernieuwingen + annual prepay deals", "Atlas Support Lite jaarcontracten (12% korting bij vooruitbetaling)" ], "framing": "\"Kerstcadeau aan jezelf én aan je zaak.\"", "avoid": ["Geen B2B sales na 23 dec — niemand bereikbaar"], "channels": ["WhatsApp warm-list", "Email bestaande klanten", "IG"], }, { "name": "Kerst-doodweek", "start": "2026-12-24", "end": "2027-01-04", "signal": "Holiday lull — minimaal contact", "push": ["Eigen administratie afronden", "2027 plan schrijven", "Cluster onderhoud"], "framing": "n.v.t. — geen sales", "avoid": ["Alle externe outreach"], "channels": [], }, { "name": "Q1 freshness", "start": "2027-01-05", "end": "2027-01-31", "signal": "\"Nieuw jaar nieuw systeem\" — annual contract renewals", "push": [ "Werkplek upgrade calls naar Q1 klanten", "Atlas Agency jaarcontracten ipv maandelijks", "POS Support Lite hernieuwingen + uitbreidingen" ], "framing": "\"Begin 2027 met systemen die in 2026 hebben bewezen te werken.\"", "avoid": [], "channels": ["Alles open"], }, ] def current_window(today=None): today = today or date.today() for w in WINDOWS_2026: start = date.fromisoformat(w["start"]) end = date.fromisoformat(w["end"]) if start <= today <= end: days_in = (today - start).days days_left = (end - today).days return {**w, "days_in": days_in, "days_left": days_left} return None def upcoming_windows(today=None, n=3): today = today or date.today() upcoming = [] for w in WINDOWS_2026: start = date.fromisoformat(w["start"]) if start > today: upcoming.append({**w, "days_until": (start - today).days}) if len(upcoming) >= n: break return upcoming def btw_deadline(today=None): """Quarterly NL BTW aangifte deadlines: end of month after quarter end.""" today = today or date.today() q_ends = [ (date(today.year, 4, 30), "Q1"), (date(today.year, 7, 31), "Q2"), (date(today.year, 10, 31), "Q3"), (date(today.year + 1, 1, 31), "Q4"), ] for d, q in q_ends: if d >= today: return {"quarter": q, "deadline": d.isoformat(), "days_until": (d - today).days} return None def days_to_next_payday(): """Most NL employers pay 25th of month — quick proxy.""" today = date.today() if today.day < 25: nxt = date(today.year, today.month, 25) else: m = today.month + 1 y = today.year if m > 12: m = 1; y += 1 nxt = date(y, m, 25) return (nxt - today).days def build_summary(): today = date.today() curr = current_window(today) upcoming = upcoming_windows(today, 3) btw = btw_deadline(today) summary = { "generated_at": datetime.now().isoformat(timespec="seconds"), "as_of": today.isoformat(), "current_window": curr, "upcoming_windows": upcoming, "btw_aangifte": btw, "days_to_next_payday": days_to_next_payday(), "weekday": today.strftime("%A"), "is_weekend": today.weekday() >= 5, # Action triggers "primary_recommendation": curr["push"][0] if curr and curr["push"] else "Geen actieve window — gebruik default plan", "primary_framing": curr["framing"] if curr else "n.v.t.", "avoid_today": curr["avoid"] if curr else [], "channels_today": curr["channels"] if curr else [], } return summary def push_to_atlas01(summary): OUT_LOCAL.parent.mkdir(parents=True, exist_ok=True) OUT_LOCAL.write_text(json.dumps(summary, indent=2, ensure_ascii=False), encoding="utf-8") print(f"wrote {OUT_LOCAL}") try: subprocess.run(["scp", str(OUT_LOCAL), f"{SSH}:{REMOTE}"], check=True, timeout=20) print(f"pushed to {SSH}:{REMOTE}") except Exception as e: print(f"scp fail: {e}") def main(): s = build_summary() push_to_atlas01(s) print(f"\nCurrent window: {s['current_window']['name'] if s['current_window'] else 'none'}") if s['current_window']: print(f" Days in: {s['current_window']['days_in']}, days left: {s['current_window']['days_left']}") print(f" Push: {s['primary_recommendation']}") print(f"BTW deadline: {s['btw_aangifte']['quarter']} on {s['btw_aangifte']['deadline']} ({s['btw_aangifte']['days_until']}d)") print(f"Next payday (25th): {s['days_to_next_payday']}d") if __name__ == "__main__": main()