Files
crm/templates/contact.html
T

274 lines
16 KiB
HTML
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
{% extends 'base.html' %}
{% block title %}{{ c.name }}{% endblock %}
{% block content %}
<div class="head">
<div>
<a class="label" href="{{ url_for('contacts') }}">← Contacten</a>
<h1>{{ c.name }}</h1>
<div class="muted"><span class="chip">{{ TYPE.get(c.type) }}</span>
{% if c.relation_id %}<a href="{{ url_for('relation_view', rid=c.relation_id) }}">{{ c.relation_name }}</a>{% if c.relation_role %} ({{ c.relation_role }}){% endif %} · {% endif %}{{ [c.company, c.city]|select|join(' · ') }}</div>
</div>
<div class="actions">
<form method="post" action="{{ url_for('contact_status', cid=c.id) }}" class="inline">
<select class="form-select w-auto" name="status" onchange="this.form.submit()" aria-label="Status">
{% for k, l in STATUSES %}<option value="{{ k }}" {{ 'selected' if c.status == k }}>{{ l }}</option>{% endfor %}
</select>
</form>
{% if c.type == 'lead' %}
<button class="btn btn-outline-primary" type="button" onclick="document.getElementById('convert').showModal()">Omzetten naar klant</button>
{% endif %}
<form method="post" action="{{ url_for('quote_new') }}" class="inline">
<input type="hidden" name="contact_id" value="{{ c.id }}">
<button class="btn btn-outline-primary">Nieuwe offerte</button>
</form>
<a class="btn btn-primary" href="{{ url_for('contact_edit', cid=c.id) }}">Bewerken</a>
</div>
</div>
<div class="row gx-4 stack">
<div class="col-lg-7 col-xl-8">
<div class="card"><div class="card-body">
<div class="card-top">
<h2>Gekozen model</h2>
{% if design %}
<div class="actions">
{% if designs|length > 1 %}
<form method="post" action="{{ url_for('contact_design', cid=c.id) }}" class="inline">
<select class="form-select form-select-sm w-auto" name="file_id" onchange="this.form.submit()" aria-label="Ander ontwerp kiezen">
{% for d in designs %}<option value="{{ d.id }}" {{ 'selected' if d.id == design.id }}>{{ d.title }} · {{ d.created_at|dt('%d-%m-%Y') }}</option>{% endfor %}
</select>
</form>
{% endif %}
<form method="post" action="{{ url_for('quote_new') }}" class="inline">
<input type="hidden" name="contact_id" value="{{ c.id }}"><input type="hidden" name="bestek" value="1">
<button class="btn btn-primary btn-sm">Offerte met bestek</button>
</form>
<a class="btn btn-outline-primary btn-sm" href="{{ url_for('design_viewer', fid=design.id) }}" target="_blank">Openen</a>
<a class="btn btn-outline-secondary btn-sm" href="{{ url_for('upload_file', name=design.stored) }}" download="{{ design.original }}">JSON</a>
</div>
{% endif %}
</div>
{% if design %}
<div class="viewer-frame"><iframe src="{{ url_for('design_viewer', fid=design.id) }}" title="3D-weergave {{ design.title }}" loading="lazy" allowfullscreen></iframe></div>
<p class="muted" style="margin:.75rem 0 0"><strong style="color:var(--ink)">{{ design.title }}</strong>
· {{ design_meta.units }} unit{{ 's' if design_meta.units != 1 }}{% if design_meta.address %} · {{ design_meta.address }}{% endif %}
· ontvangen {{ design.created_at|dt }}{% if design_meta.version %} · configurator {{ design_meta.version }}{% endif %}</p>
{% if design_meta.note %}<p style="white-space:pre-line;margin:.5rem 0 0">{{ design_meta.note }}</p>{% endif %}
<p class="pdf-links" style="margin:.5rem 0 0">Tekeningen:
{% for k, label in PDF_KINDS.items() %}{% set p = pdfs.get(k) %}
<a data-pdf="{{ k }}" href="{{ p.url if p else '#' }}" target="_blank" {{ 'hidden' if not p }}>{{ (label[:1]|upper) ~ label[1:] }}</a><span class="muted" data-pdf-wait="{{ k }}" {{ 'hidden' if p }}>{{ label }} wordt gemaakt…</span>{% if k == 'werk' %} <span class="muted">(intern)</span> ·{% endif %}
{% endfor %}
<span class="muted">· opnieuw maken via PDF in de weergave</span></p>
<script>
addEventListener('message', (e) => {
if (e.origin !== location.origin || !e.data || e.data.type !== 'tectum-pdf') return;
const a = document.querySelector(`[data-pdf="${e.data.kind}"]`), w = document.querySelector(`[data-pdf-wait="${e.data.kind}"]`);
if (a) { a.href = e.data.url; a.hidden = false; }
if (w) w.hidden = true;
});
</script>
{% elif designs %}
<p class="muted">Er is geen model gekozen.</p>
<form method="post" action="{{ url_for('contact_design', cid=c.id) }}" class="d-flex flex-wrap gap-2">
<select class="form-select w-auto" name="file_id" aria-label="Ontwerp">
{% for d in designs %}<option value="{{ d.id }}">{{ d.title }} · {{ d.created_at|dt('%d-%m-%Y') }}</option>{% endfor %}
</select>
<button class="btn btn-outline-primary">Kiezen</button>
</form>
{% else %}
<p class="empty">Nog geen model. Een ontwerp uit de configurator (Bestand › Opslaan, JSON) komt hier vanzelf als je het bij Bestanden uploadt of als het met het formulier meekomt.</p>
{% endif %}
</div></div>
<div class="card o-2"><div class="card-body">
<h2>Taken</h2>
{% for t in tasks %}
<form method="post" action="{{ url_for('task_done', tid=t.id) }}" class="task {{ 'done' if t.done }}">
<button class="check" aria-label="{{ 'Heropenen' if t.done else 'Afronden' }}"></button>
<div><div class="title">{{ t.title }}</div>
<div class="muted">{{ t.user_name or '' }}{% if t.due_date %} · <span class="{{ 'overdue' if not t.done and t.due_date < today }}">{{ t.due_date|dt('%d-%m-%Y') }}</span>{% endif %}</div></div>
</form>
{% endfor %}
<form method="post" action="{{ url_for('contact_task', cid=c.id) }}" class="row g-2 mt-2">
<div class="col-12 col-md"><input class="form-control" name="title" placeholder="Bijv. terugbellen, offerte nabellen" required aria-label="Taak"></div>
<div class="col-6 col-md-auto"><input class="form-control" type="date" name="due_date" aria-label="Datum"></div>
<div class="col-6 col-md-auto">
<select class="form-select" name="user_id" aria-label="Voor">
{% for u in USERS %}<option value="{{ u.id }}" {{ 'selected' if u.id == g.user.id }}>{{ u.name }}</option>{% endfor %}
</select>
</div>
<div class="col-12 col-md-auto"><button class="btn btn-outline-primary w-100">Taak toevoegen</button></div>
</form>
</div></div>
<div class="card o-3"><div class="card-body">
<h2>Notitie toevoegen</h2>
<form method="post" action="{{ url_for('contact_note', cid=c.id) }}">
<textarea class="form-control" name="body" required placeholder="Gebeld, afspraak gemaakt, wensen…" aria-label="Notitie"></textarea>
<div class="actions"><button class="btn btn-primary">Opslaan</button></div>
</form>
</div></div>
{% if c.email %}
<div class="card"><div class="card-body">
<details>
<summary>E-mail sturen</summary>
<form method="post" action="{{ url_for('mail_send') }}">
<input type="hidden" name="contact_id" value="{{ c.id }}">
<div class="row g-3">
<div class="col-12"><label class="form-label" for="m-to">Aan</label><input class="form-control" id="m-to" type="email" name="to" value="{{ c.email }}" required></div>
<div class="col-12"><label class="form-label" for="m-subject">Onderwerp</label><input class="form-control" id="m-subject" name="subject" required></div>
<div class="col-12"><label class="form-label" for="m-body">Bericht</label><textarea class="form-control" id="m-body" name="body" rows="8" required></textarea></div>
</div>
<div class="actions"><button class="btn btn-primary">Versturen</button></div>
</form>
</details>
</div></div>
{% endif %}
<div class="card"><div class="card-body">
<h2>Tijdlijn</h2>
<ul class="timeline">
{% for a in activities %}
<li>
<div class="meta">{{ ACT.get(a.type, a.type) }} · {{ a.created_at|dt }}{% if a.user_name %} · {{ a.user_name }}{% endif %}</div>
<div class="body">{{ a.body }}</div>
</li>
{% else %}
<li class="empty">Nog geen activiteit.</li>
{% endfor %}
</ul>
</div></div>
{% if emails %}
<div class="card"><div class="card-body">
<h2>E-mail</h2>
<div class="table-responsive"><table class="table table-hover table-stack">
<tbody>
{% for e in emails %}
<tr class="link" onclick="location='{{ url_for('inbox_view', eid=e.id) }}'">
<td class="stack-title"><a href="{{ url_for('inbox_view', eid=e.id) }}">{{ e.subject }}</a></td>
<td data-label="Richting"><span class="chip">{{ 'Ontvangen' if e.direction == 'in' else 'Verstuurd' }}</span></td>
<td data-label="Datum" class="muted num">{{ e.date|dt }}</td>
</tr>
{% endfor %}
</tbody>
</table></div>
</div></div>
{% endif %}
</div>
<div class="col-lg-5 col-xl-4">
<div class="card o-1"><div class="card-body">
<h2>Gegevens</h2>
<dl class="props">
<dt>Status</dt><dd><span class="chip {{ c.status }}">{{ STATUS.get(c.status, c.status) }}</span></dd>
<dt>Toegewezen</dt><dd>{{ c.user_name or '—' }}</dd>
{% if c.relation_id %}<dt>Relatie</dt><dd><a href="{{ url_for('relation_view', rid=c.relation_id) }}">{{ c.relation_name }}</a><br><span class="muted">{{ RKIND.get(c.relation_kind) }}{% if c.relation_type %} · {{ c.relation_type }}{% endif %}</span>
{% for h in housemates %}<br><a href="{{ url_for('contact_view', cid=h.id) }}">{{ h.name }}</a>{% if h.relation_role %} <span class="muted">({{ h.relation_role }})</span>{% endif %}{% endfor %}</dd>{% endif %}
{% if c.value %}<dt>Verwachte waarde</dt><dd>{{ c.value|euro }}</dd>{% endif %}
{% if c.email %}<dt>E-mail</dt><dd><a href="mailto:{{ c.email }}">{{ c.email }}</a></dd>{% endif %}
{% if c.phone %}<dt>Telefoon</dt><dd><a href="tel:{{ c.phone }}">{{ c.phone }}</a></dd>{% endif %}
{% if c.company %}<dt>Bedrijf</dt><dd>{{ c.company }}</dd>{% endif %}
{% if c.address or c.city %}<dt>Adres</dt><dd>{{ c.address }}{% if c.address %}
{% endif %}{{ c.postcode }} {{ c.city }}</dd>{% endif %}
{% if c.source %}<dt>Bron</dt><dd>{{ c.source }}</dd>{% endif %}
<dt>Aangemaakt</dt><dd>{{ c.created_at|dt }}</dd>
</dl>
{% if c.notes %}<h3>Notities</h3><p style="white-space:pre-line;margin:0">{{ c.notes }}</p>{% endif %}
{% if extra %}
<h3>Formuliervelden</h3>
<dl class="props">
{% for k, v in extra.items() %}<dt>{{ k }}</dt><dd>{{ v if v is string else v|tojson }}</dd>{% endfor %}
</dl>
{% endif %}
</div></div>
<div class="card"><div class="card-body">
<h2>Bestanden</h2>
{% if files %}
<div class="files">
{% for f in files %}
<div class="file">
<a href="{{ url_for('design_viewer', fid=f.id) if f.title else url_for('upload_file', name=f.stored) }}" target="_blank" class="thumb">
{% if f.mime.startswith('image/') %}<img src="{{ url_for('upload_file', name=f.stored) }}" alt="{{ f.original }}" loading="lazy">
{% elif f.title %}3D{% else %}{{ f.original.rsplit('.', 1)[-1][:4] if '.' in f.original else 'bestand' }}{% endif %}
</a>
<div class="name" title="{{ f.original }}">{{ f.title or f.original }}</div>
{% if f.kind == 'werk' %}<div class="muted">Intern, niet in portaal</div>{% endif %}
{% if f.title %}{% if c.design_file_id == f.id %}<div class="muted">Gekozen model</div>{% else %}
<form method="post" action="{{ url_for('contact_design', cid=c.id) }}"><input type="hidden" name="file_id" value="{{ f.id }}"><button class="linkbtn">Kies als model</button></form>
{% endif %}{% endif %}
<form method="post" action="{{ url_for('file_delete', fid=f.id) }}" onsubmit="return confirm('Bestand verwijderen?')">
<button class="linkbtn">Verwijderen</button>
</form>
</div>
{% endfor %}
</div>
{% endif %}
<form method="post" action="{{ url_for('contact_upload', cid=c.id) }}" enctype="multipart/form-data">
<input class="form-control" type="file" name="files" multiple required aria-label="Bestanden kiezen">
<div class="actions"><button class="btn btn-outline-primary btn-sm">Uploaden</button></div>
</form>
</div></div>
<div class="card"><div class="card-body">
<h2>Offertes</h2>
{% for qt in quotes %}
<p style="margin:0 0 .6rem"><a href="{{ url_for('quote_edit', qid=qt.id) }}">{{ qt.number }}</a> <span class="chip {{ qt.status }}">{{ QSTATUS.get(qt.status) }}</span><br>
<span class="muted">{{ qt.date|dt('%d-%m-%Y') }} · {{ qt.total|euro }} incl. btw</span></p>
{% else %}
<p class="empty">Nog geen offertes.</p>
{% endfor %}
</div></div>
<div class="card"><div class="card-body">
<h2>Klantportaal</h2>
{% if c.portal_password_hash %}
<p class="muted">Actief{% if c.portal_last_login %} · laatst ingelogd {{ c.portal_last_login|dt }}{% endif %}</p>
{% elif portal_link %}
<p class="muted">Uitnodiging klaar, nog niet geactiveerd:</p>
<p><code>{{ portal_link }}</code></p>
{% else %}
<p class="muted">De klant kan via het portaal offertes bekijken en accepteren, en bestanden en berichten sturen.</p>
{% endif %}
<form method="post" action="{{ url_for('contact_portal', cid=c.id) }}" class="actions">
{% if portal_link and c.email %}<button class="btn btn-primary btn-sm" name="action" value="mail">Mail uitnodiging</button>{% endif %}
{% if not c.portal_password_hash %}<button class="btn btn-outline-primary btn-sm" name="action" value="invite">{{ 'Nieuwe link' if portal_link else 'Uitnodiging maken' }}</button>{% endif %}
{% if c.portal_password_hash or portal_link %}<button class="btn btn-outline-secondary btn-sm" name="action" value="revoke">Toegang intrekken</button>{% endif %}
</form>
</div></div>
<form method="post" action="{{ url_for('contact_delete', cid=c.id) }}" class="mb-4" onsubmit="return confirm('Contact met alle notities en bestanden verwijderen?')">
<button class="btn btn-outline-secondary btn-sm">Contact verwijderen</button>
</form>
</div>
</div>
{% if c.type == 'lead' %}
<dialog id="convert" class="dialog">
<form method="post" action="{{ url_for('contact_convert', cid=c.id) }}">
<h2>Omzetten naar klant</h2>
<p class="muted">De contactpersoon komt in een klantrelatie, bijvoorbeeld een huishouden of familie.</p>
<div class="form-check">
<input class="form-check-input" type="radio" id="mode-new" name="mode" value="new" checked onchange="this.form.relation_id && (this.form.relation_id.disabled=true);this.form.new_relation.disabled=false">
<label class="form-check-label" for="mode-new">Nieuwe klantrelatie</label>
</div>
<input class="form-control" name="new_relation" value="{{ c.company or ('Familie ' ~ c.name.split(' ')[-1]) }}" aria-label="Naam relatie" style="margin:.4rem 0 1rem">
{% if klant_relations %}
<div class="form-check">
<input class="form-check-input" type="radio" id="mode-existing" name="mode" value="existing" onchange="this.form.relation_id.disabled=false;this.form.new_relation.disabled=true">
<label class="form-check-label" for="mode-existing">Bestaande klantrelatie</label>
</div>
<select class="form-select" name="relation_id" disabled aria-label="Bestaande relatie" style="margin-top:.4rem">
{% for r in klant_relations %}<option value="{{ r.id }}">{{ r.name }}{% if r.type %} · {{ r.type }}{% endif %}</option>{% endfor %}
</select>
{% endif %}
<div class="actions">
<button class="btn btn-primary">Omzetten</button>
<button class="btn btn-outline-secondary" type="button" onclick="this.closest('dialog').close()">Annuleren</button>
</div>
</form>
</dialog>
{% endif %}
{% endblock %}