Files
crm/templates/settings.html
T

159 lines
10 KiB
HTML

{% extends 'base.html' %}
{% block title %}Instellingen{% endblock %}
{% macro field(key, label, type='text', placeholder='', full=false) %}
<div class="{{ 'col-12' if full else 'col-md-6 col-xl-4' }}"><label class="form-label" for="{{ key }}">{{ label }}</label><input class="form-control" id="{{ key }}" type="{{ type }}" name="{{ key }}" value="{{ s.get(key, '') }}" placeholder="{{ placeholder }}"></div>
{% endmacro %}
{% macro security(key) %}
<div class="col-md-6 col-xl-4"><label class="form-label" for="{{ key }}">Beveiliging</label>
<select class="form-select" id="{{ key }}" name="{{ key }}">{% for v, label in SECURITY %}<option value="{{ v }}" {{ 'selected' if s.get(key, '') == v }}>{{ label }}</option>{% endfor %}</select></div>
{% endmacro %}
{% block content %}
<div class="head"><div><div class="kicker">Beheer</div><h1>Instellingen</h1></div></div>
<form method="post">
<div class="card"><div class="card-body">
<h2>Bedrijfsgegevens</h2>
<p class="hint" style="margin:-.4rem 0 1rem">Deze gegevens staan op de offertes.</p>
<div class="row g-3">
{{ field('company_name', 'Bedrijfsnaam', full=true) }}
{{ field('company_address', 'Adres') }}
{{ field('company_postcode_city', 'Postcode en plaats') }}
{{ field('company_phone', 'Telefoon') }}
{{ field('company_email', 'E-mail', 'email') }}
{{ field('company_website', 'Website') }}
{{ field('company_kvk', 'KvK-nummer') }}
{{ field('company_btw', 'Btw-nummer') }}
{{ field('company_iban', 'IBAN') }}
</div>
</div></div>
<div class="card"><div class="card-body">
<h2>Offertes</h2>
<div class="row g-3">
{{ field('quote_prefix', 'Voorvoegsel nummer', placeholder='OFF') }}
{{ field('quote_valid_days', 'Standaard geldig (dagen)', 'number') }}
<div class="col-12"><label class="form-label" for="quote_intro">Standaard inleiding</label><textarea class="form-control" id="quote_intro" name="quote_intro">{{ s.quote_intro }}</textarea></div>
<div class="col-12"><label class="form-label" for="quote_footer">Voettekst (bijv. betalingsvoorwaarden)</label><textarea class="form-control" id="quote_footer" name="quote_footer">{{ s.quote_footer }}</textarea></div>
</div>
</div></div>
<div class="card" id="mail"><div class="card-body">
<h2>E-mail koppelen</h2>
<p class="hint" style="margin:-.4rem 0 1rem">Eén gedeelde mailbox (bijv. info@) voor de inbox en het versturen vanuit de CRM. Bij OVHcloud
(Zimbra of MX Plan) is de gebruikersnaam het volledige e-mailadres; de afzender moet dat adres (of een alias ervan) zijn.
Gmail werkt met een app-wachtwoord. Wachtwoorden staan in de database: houd de map <code>data/</code> privé.</p>
<div class="row g-3">
<div class="col-md-6 col-xl-4"><label class="form-label" for="mail-provider">Aanbieder</label>
<select class="form-select" id="mail-provider" aria-describedby="mail-provider-hint">
<option value="">Kies om de servers in te vullen…</option>
{% for key, p in PROVIDERS.items() %}<option value="{{ key }}" data-preset="{{ p|tojson|forceescape }}">{{ p.label }}</option>{% endfor %}
</select>
<p class="hint" id="mail-provider-hint">Vult server, poort en beveiliging in; daarna kun je alles nog aanpassen.</p>
</div>
</div>
<h3>Ontvangen (IMAP)</h3>
<div class="row g-3">
{{ field('imap_host', 'Server', placeholder='imap.mail.ovh.net') }}
{{ field('imap_port', 'Poort', 'number', '993') }}
{{ security('imap_security') }}
{{ field('imap_user', 'Gebruikersnaam', placeholder='info@vanemouswoningen.nl') }}
<div class="col-md-6 col-xl-4"><label class="form-label" for="imap_pass">Wachtwoord</label><input class="form-control" id="imap_pass" type="password" name="imap_pass" placeholder="{{ '•••••••• (ingesteld)' if s.imap_pass else '' }}" autocomplete="new-password"></div>
{{ field('imap_folder', 'Map', placeholder='INBOX') }}
{{ field('imap_days', 'Aantal dagen terug ophalen', 'number', '30') }}
</div>
<h3>Versturen (SMTP)</h3>
<div class="row g-3">
{{ field('smtp_host', 'Server', placeholder='smtp.mail.ovh.net') }}
{{ field('smtp_port', 'Poort', 'number', '465') }}
{{ security('smtp_security') }}
{{ field('smtp_user', 'Gebruikersnaam', placeholder='leeg = zelfde als IMAP') }}
<div class="col-md-6 col-xl-4"><label class="form-label" for="smtp_pass">Wachtwoord</label><input class="form-control" id="smtp_pass" type="password" name="smtp_pass" placeholder="{{ '•••••••• (ingesteld)' if s.smtp_pass else 'leeg = zelfde als IMAP' }}" autocomplete="new-password"></div>
<div class="col-md-6 col-xl-4"><label class="form-label" for="smtp_sent_folder">Kopie in map</label><input class="form-control" id="smtp_sent_folder" name="smtp_sent_folder" value="{{ s.smtp_sent_folder or '' }}" placeholder="leeg = geen kopie" aria-describedby="sent-hint"><p class="hint" id="sent-hint">Bij Zimbra/MX Plan <code>Sent</code>, zodat verstuurde mail ook in de webmail staat. Gmail doet dit zelf.</p></div>
{{ field('smtp_from', 'Afzender', placeholder='Van Emous <info@vanemouswoningen.nl>', full=true) }}
</div>
<div class="actions"><button class="btn btn-outline-primary" name="action" value="mailtest">Opslaan en verbinding testen</button></div>
</div></div>
<div class="card"><div class="card-body">
<h2>Formulieren en API</h2>
<div class="row g-3">
{{ field('allowed_origins', 'Toegestane websites (komma-gescheiden)', placeholder='https://www.vanemous.nl', full=true) }}
<div class="col-md-6 col-xl-4"><label class="form-label" for="api_assign_user">Nieuwe leads toewijzen aan</label>
<select class="form-select" id="api_assign_user" name="api_assign_user">
<option value="">— Niemand —</option>
{% for u in USERS %}<option value="{{ u.id }}" {{ 'selected' if s.api_assign_user == u.id|string }}>{{ u.name }}</option>{% endfor %}
</select>
</div>
</div>
</div></div>
<div class="card"><div class="card-body">
<h2>Relatietypes</h2>
<p class="hint" style="margin:-.4rem 0 1rem">Komma-gescheiden. Bestaande relaties houden hun type als je er een weghaalt.</p>
<div class="row g-3">
<div class="col-12"><label class="form-label" for="klant_types">Klanten (bundels)</label><input class="form-control" id="klant_types" name="klant_types" value="{{ s.klant_types or 'Huishouden / familie, Particulier, Zakelijk, Zorginstelling' }}"></div>
<div class="col-12"><label class="form-label" for="partner_types">Partners</label><input class="form-control" id="partner_types" name="partner_types" value="{{ s.partner_types or 'Leverancier, Aannemer, Installateur, Architect / adviseur, Gemeente, Overig' }}"></div>
</div>
</div></div>
<div class="actions" style="margin-bottom:1.5rem"><button class="btn btn-primary">Instellingen opslaan</button></div>
</form>
<div class="card"><div class="card-body">
<h2>API-koppeling</h2>
<dl class="props">
<dt>Endpoint</dt><dd><code>POST {{ api_url }}</code></dd>
<dt>API-sleutel</dt><dd><code>{{ s.api_key }}</code></dd>
<dt>Klantportaal</dt><dd><code>{{ portal_url }}</code></dd>
</dl>
<p>Stuur de sleutel mee als header <code>X-API-Key</code> of als <code>?key=</code> in de URL. Herkende velden (ook in het Nederlands): naam, voornaam, achternaam, email, telefoon, bedrijf, adres, postcode, plaats, bericht, bron, waarde. Andere velden worden bewaard als extra gegevens. Bestanden (bijv. foto's) gaan mee als <code>multipart/form-data</code>. Een ontwerp uit de configurator (een object met <code>"type": "house-design"</code>) wordt als bestand bij de lead opgeslagen. Leads met een bekend e-mailadres worden bij het bestaande contact gezet.</p>
<h3>Gewoon HTML-formulier</h3>
<pre>{% filter forceescape %}<form action="{{ api_url }}?key={{ s.api_key }}" method="post" enctype="multipart/form-data">
<input name="naam" required>
<input name="email" type="email">
<input name="telefoon">
<textarea name="bericht"></textarea>
<input type="file" name="foto" multiple>
<input type="hidden" name="bron" value="Contactformulier">
<input type="hidden" name="redirect" value="https://www.vanemous.nl/bedankt">
<input name="_gotcha" style="display:none" tabindex="-1" autocomplete="off">
<button>Versturen</button>
</form>{% endfilter %}</pre>
<h3>JavaScript (fetch)</h3>
<pre>{% filter forceescape %}const res = await fetch('{{ api_url }}', {
method: 'POST',
headers: { 'X-API-Key': '{{ s.api_key }}' },
body: new FormData(document.querySelector('form'))
});
const { ok, id } = await res.json();{% endfilter %}</pre>
<h3>Vanaf een server (aanbevolen: de sleutel blijft geheim)</h3>
<pre>{% filter forceescape %}curl -X POST {{ api_url }} \
-H 'X-API-Key: {{ s.api_key }}' -H 'Content-Type: application/json' \
-d '{"naam": "Jan Jansen", "email": "jan@example.nl", "bericht": "Graag info", "model": "Amstel"}'{% endfilter %}</pre>
<h3>Producten bijwerken (prijsmutaties)</h3>
<p>Werkt producten bij op SKU, bijvoorbeeld vanuit een prijsscript van een leverancier. Veldnamen zoals bij de import. <code>?deactivate_missing=1</code> zet producten die niet in de lijst staan op inactief.</p>
<pre>{% filter forceescape %}curl -X POST '{{ url_for('api_products', _external=True) }}?source=Leverancier%20X' \
-H 'X-API-Key: {{ s.api_key }}' -H 'Content-Type: application/json' \
-d '[{"sku": "plaat.osbM2", "naam": "OSB", "prijs": "12,50", "eenheid": "m²", "leverancier": "Houthandel Y"}]'{% endfilter %}</pre>
<form method="post" onsubmit="return confirm('Nieuwe sleutel maken? Bestaande formulieren werken dan niet meer.')">
<input type="hidden" name="action" value="apikey">
<button class="btn btn-outline-secondary btn-sm">Nieuwe API-sleutel maken</button>
</form>
</div></div>
<script>
document.getElementById('mail-provider').addEventListener('change', (e) => {
const opt = e.target.selectedOptions[0];
if (!opt || !opt.dataset.preset) return;
Object.entries(JSON.parse(opt.dataset.preset)).forEach(([key, value]) => {
const el = document.getElementById(key);
if (el) el.value = value;
});
});
</script>
{% endblock %}