bmc_hub/app/workflows/frontend/resources.html

15 lines
5.1 KiB
HTML
Raw 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 "shared/frontend/base.html" %}
{% set wp = workflow_permissions|default({}) %}
{% block title %}Aftaledækning – BMC Hub{% endblock %}
{% block extra_css %}{% include "workflows/frontend/_style.html" %}{% endblock %}
{% block content %}<div class="container-fluid workflow-page"><header class="workflow-heading"><div><div class="workflow-eyebrow">Administration · afregning</div><h1>Aftaler og klippekort</h1><p>Vælg hvilke tags aftalen eller klippekortet dækker. Gem dækning opretter og vedligeholder automatisk afregningsvalget. Du skal ikke oprette en separat workflowregel.</p></div></header>{% include "workflows/frontend/_nav.html" %}<div class="alert alert-info mt-3" id="resource-activation-help">Automatisk afregning bruges, når workflowmotoren og workflows for kunden er aktive. Aktivér kunden på kundekortet i CRM. Hvis flere aftaler eller klippekort matcher, skal afregningen vurderes manuelt. Tid godkendes og afregnes fortsat separat.</div><div id="resource-message" role="status" class="my-2"></div><label class="d-block my-3">Kunde<select id="resource-customer" class="form-select" style="max-width:420px"><option value="">Alle kunder</option></select></label><div id="resource-list"><div class="workflow-empty">Henter aftaler og klippekort…</div></div></div>{% endblock %}
{% block extra_js %}<script>
(()=>{'use strict';const $=id=>document.getElementById('resource-'+id);let tags=[],customers=[];
async function api(path,body){const r=await fetch('/api/v1/workflows'+path,{method:body?'PUT':'GET',credentials:'same-origin',headers:{'Content-Type':'application/json'},body:body?JSON.stringify(body):undefined});const d=await r.json();if(!r.ok)throw Error(typeof d.detail==='string'?d.detail:JSON.stringify(d.detail));return d;}
function el(tag,text,cls){const e=document.createElement(tag);if(text)e.textContent=text;if(cls)e.className=cls;return e;}
function choices(selected){const e=el('select','','form-select');e.multiple=true;e.size=6;for(const t of tags){const o=el('option',t.label||t.name);o.value=t.id;o.selected=(selected||[]).includes(t.id);e.append(o);}return e;}
async function load(){const data=await api('/resources'+($('customer').value?'?customer_id='+encodeURIComponent($('customer').value):''));$('list').replaceChildren();if(!data.agreements.length&&!data.cards.length)$('list').append(el('div','Ingen aftaler eller klippekort for det valgte firma.','workflow-empty'));for(const [kind,rows] of [['agreements',data.agreements],['cards',data.cards]])for(const row of rows){const coverage=row.workflow_coverage||{},card=el('section','','card p-3 my-3'),name=customers.find(c=>Number(c.id)===Number(row.customer_id))?.name||'Ukendt kunde';card.append(el('h5',`${kind==='agreements'?'Fastpris':'Klippekort'} ${row.agreement_number||row.card_number||row.id} · ${name}`),el('p','Status: '+row.status,'small text-muted'));const include=choices(coverage.tag_ids),exclude=choices(coverage.excluded_tag_ids),grid=el('div','','row g-2');for(const [title,control] of [['Dækker et af disse tags · tomt betyder alle',include],['Udelukker disse tags',exclude]]){const label=el('label',title,'col-md-6');label.append(control);grid.append(label);}card.append(grid);const label=el('label',' Medtag undertags','my-2'),descendants=el('input');descendants.type='checkbox';descendants.checked=!!coverage.include_descendants;label.prepend(descendants);card.append(label);let price=null;if(kind==='agreements'){const label=el('label','Månedspris (tom = eksisterende beregning)','d-block');price=el('input','','form-control');price.type='number';price.min='0';price.step='0.01';price.value=row.monthly_price??'';label.append(price);card.append(label);}const save=el('button','Gem dækning','btn btn-primary mt-2');save.onclick=()=>run(async()=>{const payload={workflow_coverage:{tag_ids:[...include.selectedOptions].map(o=>Number(o.value)),excluded_tag_ids:[...exclude.selectedOptions].map(o=>Number(o.value)),include_descendants:descendants.checked}};if(price)payload.monthly_price=price.value===''?null:Number(price.value);await api(`/resources/${kind}/${row.id}/coverage`,payload);$('message').className='alert alert-success';$('message').textContent='Dækningen er gemt og bruges automatisk ved afregningsvalg, når workflows er aktive for kunden. Ændringen er gemt i historikken.';await load();});card.append(save);$('list').append(card);}}
let requestBusy=false;async function run(fn){if(requestBusy)return;requestBusy=true;document.querySelector('.workflow-page').setAttribute('aria-busy','true');try{await fn();}catch(e){$('message').className='alert alert-danger';$('message').textContent=e.message;}finally{requestBusy=false;document.querySelector('.workflow-page').setAttribute('aria-busy','false');}}
$('customer').onchange=()=>run(load);run(async()=>{customers=await api('/customers');tags=await api('/tags');const map=new Map(tags.map(t=>[t.id,t]));function path(t,seen=new Set()){if(seen.has(t.id))return t.name;seen.add(t.id);const p=map.get(t.parent_id);return p?path(p,seen)+' › '+t.name:t.name;}tags=tags.map(t=>({...t,label:path(t)}));customers.forEach(c=>{const o=el('option',c.name);o.value=c.id;$('customer').append(o);});await load();});
})();</script>{% endblock %}