v0.0.1: eerste versie van de Van Emous CRM

Flask + SQLite, in de Van Emous-huisstijl (tokens uit het design system, GSAP-effecten
volgens de motion-regels, uit bij prefers-reduced-motion).

- Leads en contactpersonen: status, toewijzen, verwachte waarde, omzetten naar klant,
  tijdlijn, bestanden, taken/opvolging
- Relaties (zoals accounts in EspoCRM): klantbundels (huishouden/familie) en partners met
  type (leverancier, aannemer, ...); leveranciers van producten worden automatisch partners
- API voor formulieren (POST /api/leads) met dubbele-leaddetectie, bestanden en
  configurator-ontwerpen (house-design JSON)
- Import van CSV/JSON (leads, relaties, producten) met kolomkoppeling; configurator-formaat
- Producten met SKU als vaste sleutel, mutatiehistorie, POST /api/products, CSV-export;
  offerteregels houden hun eigen prijs
- Offertes met btw per tarief en afdrukversie (PDF via de browser)
- Inbox via IMAP/SMTP, gekoppeld aan contacten
- Gebruikers (beheerder/medewerker) en klantportaal (offertes accepteren, bestanden, berichten)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
Machiel
2026-10-14 21:56:55 +02:00
co-authored by Claude Opus 5.5
commit bffa053c05
33 changed files with 4111 additions and 0 deletions
+83
View File
@@ -0,0 +1,83 @@
# Van Emous CRM
Eenvoudige CRM in Python (Flask) met SQLite, in de Van Emous-huisstijl. Versie 0.0.1.
## Functies
- **Leads en klanten** (zoals in EspoCRM): status (nieuw → in behandeling → offerte → gewonnen/verloren),
toewijzen aan een gebruiker, verwachte waarde, bron, omzetten van lead naar klant, tijdlijn met
notities, e-mail, statuswissels en formulierinzendingen, bestanden en afbeeldingen, CSV-export.
- **Relaties** (zoals accounts in EspoCRM), in twee soorten: **klanten** (bundels zoals een huishouden,
familie of bedrijf, met meerdere contactpersonen en hun rol) en **partners** met een type (leverancier,
aannemer, installateur, ...; de typen pas je aan bij Instellingen). Een lead omzetten naar klant zet de
persoon in een nieuwe of bestaande klantrelatie. Leveranciers van producten worden automatisch partners.
- **Taken/opvolging** per contact met datum en eigenaar; "Mijn taken" op het dashboard.
- **API voor formulieren** (`POST /api/leads`): JSON, gewone formulieren en multipart met bestanden.
Nederlandse en Engelse veldnamen worden herkend, onbekende velden bewaard. Dubbele leads (zelfde
e-mail) komen bij het bestaande contact. Er is een honeypot (`_gotcha`) en een `redirect` naar een
bedankpagina. Een `house-design`-object uit de configurator wordt als ontwerp bij de lead opgeslagen.
Voorbeelden staan onder Instellingen.
- **Import** van CSV en JSON voor leads/contactpersonen, relaties en producten, met een voorbeeld en kolomkoppeling.
Het formaat van de configurator (`;`, komma-decimalen, BOM, `#`-regels) werkt direct.
- **Inbox**: IMAP ophalen en SMTP versturen, mails automatisch gekoppeld aan contacten (op e-mailadres),
contact aanmaken vanuit een mail, beantwoorden.
- **Producten** met SKU als vaste sleutel, prijs, btw, eenheid, leverancier (partner) en afbeelding.
Een import of `POST /api/products` werkt producten bij op SKU (alleen de meegegeven velden) en legt
elke mutatie vast met de oude en de nieuwe waarde. Optioneel worden producten die niet meer in de lijst
staan inactief gezet. Offerteregels bewaren hun eigen prijs, dus bestaande offertes veranderen niet. Een
product dat in offertes gebruikt is, wordt bij verwijderen gearchiveerd. Export naar CSV in hetzelfde
formaat als de import.
- **Offertes** met regels (product of vrije regel), btw per tarief en een afdrukversie die je als PDF
opslaat via de browser.
- **Gebruikers** met de rollen beheerder (ook gebruikers en instellingen) en medewerker.
- **Klantportaal** (`/portal`): de klant krijgt een uitnodigingslink (kopiëren of mailen vanaf het
contact), stelt een wachtwoord in en kan dan offertes bekijken, accepteren of afwijzen, bestanden
uploaden en berichten sturen. Een geaccepteerde offerte zet het contact op gewonnen/klant.
- **Effecten** met GSAP (cdnjs, 3.12.5) volgens de motion-regels van de huisstijl, in `static/fx.js`.
Ze staan uit bij `prefers-reduced-motion`, en na 3 seconden is de inhoud altijd zichtbaar.
## Starten
```sh
python3 -m venv .venv
.venv/bin/pip install -r requirements.txt
.venv/bin/python app.py # http://127.0.0.1:5000
```
Bij de eerste keer maak je het beheerdersaccount aan. Daarna vul je onder Instellingen de
bedrijfsgegevens, de e-mail en de toegestane websites voor de API in.
## Online zetten
Draai de app achter nginx/Apache met HTTPS, bijvoorbeeld met gunicorn:
```sh
.venv/bin/pip install gunicorn
.venv/bin/gunicorn -w 2 -b 127.0.0.1:8000 app:app
```
E-mail automatisch ophalen (cron, elke 10 minuten):
```
*/10 * * * * cd /pad/naar/crm && .venv/bin/python app.py sync
```
## Opslag
Alles staat in `data/`: `crm.db` (SQLite), `uploads/` (bestanden), `secret.key` (sessies).
Een back-up is een kopie van die map. Nieuwe kolommen worden bij het starten automatisch aan een
bestaande database toegevoegd (`MIGRATIONS` in `app.py`). Houd `data/` buiten de webroot: er staan ook
mailwachtwoorden in.
`CRM_DATA=/ander/pad` verplaatst de datamap, `HOST` en `PORT` stellen de ontwikkelserver in.
## Structuur
```
app.py routes en logica
importer.py CSV/JSON inlezen en kolommen herkennen
mail.py IMAP/SMTP
schema.sql database
templates/ pagina's (Jinja)
static/ style.css (huisstijltokens), fx.js (GSAP-effecten) en logo.svg
```