Files
SGF/public/supplier-workspace.mjs
2026-11-04 09:37:20 +02:00

15 lines
7.3 KiB
JavaScript

import {rememberFocus} from './purchasing-focus.mjs';
import {evidence as renderEvidence,purchasingStatus} from './purchasing-presenter.mjs';
import {mountSupplierDocuments} from './supplier-documents.mjs';
import {beginWorkspace} from './purchasing-focus.mjs';
const root=document.querySelector('#suppliers'),status=document.querySelector('#status'),list=document.querySelector('#list'),detail=document.querySelector('#detail');let page=1,last=1,turn=0,busy=false,newRevision='';
const n=(tag,text)=>{const e=document.createElement(tag);if(text!==undefined)e.textContent=text;return e;};
async function api(path,data){const r=await fetch('/api/purchasing-suppliers'+path,{method:data===undefined?'GET':'POST',headers:{Accept:'application/json','X-SGF-Context':root.dataset.context,'X-CSRF-TOKEN':root.dataset.csrf,...(data===undefined?{}:{'Content-Type':'application/json'})},body:data===undefined?undefined:JSON.stringify(data)});const d=await r.json();if(!r.ok)throw Error(Object.values(d.errors||{}).flat().join(' ')||d.message||'Não foi possível concluir.');return d;}
function field(form,label,name,value='',type='text'){const l=n('label',label),e=n(type==='textarea'?'textarea':'input');if(type!=='textarea')e.type=type;e.name=name;e.required=type!=='checkbox';if(type==='checkbox')e.checked=Boolean(value);else e.value=value??'';l.append(e);form.append(l);return e;}
function command(id,revision,action,build){const form=n('form'),impact=n('section'),prepare=n('button','Conferir impacto'),confirm=n('button','Confirmar esta operação');let cut=null,version=0,key=crypto.randomUUID();const data=build(form);prepare.type='submit';confirm.type='button';confirm.disabled=true;impact.hidden=true;form.oninput=()=>{version++;key=crypto.randomUUID();cut=null;confirm.disabled=true;impact.hidden=true;};const own=turn;form.onsubmit=async e=>{e.preventDefault();if(busy)return;busy=true;prepare.disabled=true;const observed=version;try{const p=await api('/'+id+'/preview',{operation_key:key,revision,action,data:data()});if(own!==turn||observed!==version)return;cut=p.preview;impact.replaceChildren(n('h3','Estado anterior e posterior a confirmar'),renderEvidence(p.impact),n('p','A confirmação volta a conferir direitos, contexto, versão e regras de participação.'));impact.hidden=false;confirm.disabled=false;}catch(e){status.textContent=e.message;}finally{busy=false;prepare.disabled=false;}};confirm.onclick=async()=>{if(busy||!cut)return;busy=true;confirm.disabled=true;try{const d=await api('/'+id+'/confirm',{preview:cut});if(own===turn){await load();await open(d.supplier_id);}}catch(e){status.textContent=e.message+' Pode repetir a mesma confirmação se perdeu a resposta; uma operação já registada não se duplica.';confirm.disabled=false;}finally{busy=false;}};form.append(prepare,impact,confirm);detail.append(form);}
const labels={name:'Nome',nuit:'NUIT sintético — 9 algarismos',contact:'Pessoa de contacto',email:'Email sintético',phone:'Telefone',address:'Endereço',category:'Categoria',beneficiaries:'Beneficiários',document_references:'Referências documentais declaradas',diligence_notes:'Fundamento da diligência',next_review:'Próxima revisão'};
function editor(id,revision,s={}){command(id,revision,id?'update':'create',form=>{form.append(n('h2',id?'Preparar alteração da ficha':'Preparar fornecedor sintético'));const inputs={};for(const [key,label]of Object.entries(labels))inputs[key]=field(form,label,key,s[key],key==='next_review'?'date':key==='email'?'email':['beneficiaries','document_references','diligence_notes'].includes(key)?'textarea':'text');const blocked=field(form,'Fornecedor impedido','blocked',s.blocked,'checkbox');return ()=>({...Object.fromEntries(Object.entries(inputs).map(([k,e])=>[k,e.value])),blocked:blocked.checked,...(id?{version:s.version}:{})});});}
async function load(){const own=++turn;try{const params=new URLSearchParams(new FormData(document.querySelector('#filters')));params.set('page',String(page));const d=await api('?'+params);if(own!==turn)return;newRevision=d.new_revision;document.querySelector('#create').hidden=!d.can_prepare;list.replaceChildren();for(const s of d.suppliers.data){const b=n('button',s.name+' · '+s.nuit+' · '+s.status+' · versão '+s.version);b.onclick=()=>open(s.id);list.append(b);}last=d.suppliers.last_page;document.querySelector('#page').textContent=`Página ${page} de ${last}`;document.querySelector('#previous').disabled=page<=1;document.querySelector('#next').disabled=page>=last;}catch(e){status.textContent=e.message;}}
async function open(id){const own=++turn;detail.replaceChildren();status.textContent='A consultar a ficha…';try{const d=await api('/'+id);if(own!==turn)return;status.textContent='';rememberFocus('suppliers',{supplier:id});const s=d.supplier,panel=n('section');panel.append(n('h2',s.name),n('p',`Estado ${s.status} · versão ${s.version} · preparador #${s.created_by} · última alteração #${s.last_changed_by??s.created_by} · revisor #${s.reviewed_by??'pendente'}`));for(const [key,label]of Object.entries(labels))panel.append(n('p',label+': '+(s[key]??'')));panel.append(n('p','Impedido: '+(s.blocked?'sim':'não')),n('p','Fundamento da revisão: '+(s.review_comment??'pendente')));detail.append(panel);if(d.geography_enabled===true){const geo=n('a','Localiza\u00e7\u00e3o para segmenta\u00e7\u00e3o');geo.href='/geography/supplier/'+id;detail.append(geo);}if(d.documents_enabled===true)mountSupplierDocuments({id,revision:d.revision,canUpload:d.capabilities.prepare,root,detail,active:()=>own===turn,reload:()=>open(id),message:text=>status.textContent=text});if(d.capabilities.prepare)editor(id,d.revision,s);if(d.capabilities.review)command(id,d.revision,'review',form=>{form.append(n('h2','Decisão independente'));const label=n('label','Decisão'),decision=n('select');decision.required=true;for(const [v,t]of [['','Seleccione explicitamente'],['active','Activar'],['suspended','Suspender']])decision.append(new Option(t,v));label.append(decision);form.append(label);const comment=field(form,'Fundamento da decisão','comment','','textarea');return ()=>({status:decision.value,comment:comment.value,version:s.version});});const history=n('section');detail.append(history);const historyPage=async p=>{try{const h=await api('/'+id+'/history?page='+p);if(own!==turn)return;history.replaceChildren(n('h2','Histórico · página '+h.current_page+' de '+h.last_page));for(const event of h.data){const e=n('details');e.append(n('summary',event.created_at+' · '+event.action+' · autor #'+event.user_id),renderEvidence({anterior:event.before,posterior:event.after}));history.append(e);}for(const [enabled,p,text]of [[h.current_page>1,h.current_page-1,'Anterior'],[h.current_page<h.last_page,h.current_page+1,'Seguinte']])if(enabled){const b=n('button',text);b.onclick=()=>historyPage(p);history.append(b);}}catch(e){status.textContent=e.message;}};await historyPage(1);}catch(e){if(own===turn)status.textContent=e.message;}}
document.querySelector('#filters').onsubmit=e=>{e.preventDefault();page=1;load();};document.querySelector('#create').onclick=()=>{turn++;detail.replaceChildren();editor(0,newRevision);};document.querySelector('#previous').onclick=()=>{if(page>1){page--;load();}};document.querySelector('#next').onclick=()=>{if(page<last){page++;load();}};beginWorkspace({stage:'suppliers',root,load,open:f=>open(f.supplier),current:()=>turn,error:text=>{status.textContent=text;}});