{% block content %}<divclass="container-fluid workflow-page"><headerclass="workflow-heading"><div><divclass="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" %}<divclass="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><divid="resource-message"role="status"class="my-2"></div><labelclass="d-block my-3">Kunde<selectid="resource-customer"class="form-select"style="max-width:420px"><optionvalue="">Alle kunder</option></select></label><divid="resource-list"><divclass="workflow-empty">Henter aftaler og klippekort…</div></div></div>{% endblock %}
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');}}