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>
84 lines
4.2 KiB
Markdown
84 lines
4.2 KiB
Markdown
# 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
|
|
```
|