import React,{useEffect,useRef,useState} from 'react';
const names={material:'Consumo material',labour:'Trabalho efectivo',pool:'Origem do conjunto indirecto',machine:'Utilização de máquina',production:'Produção boa concluída',material_rate:'Taxa de material',labour_rate:'Taxa de trabalho',criterion:'Critério de imputação'};
const units={material:'KG',labour:'MIN',pool:'MZN',machine:'HM',production:'UN',material_rate:'KG',labour_rate:'H'};
const money=v=>v===null?'Indisponível':`${v} MZN`;
export default function IndustrialCostsWorkspace({context,can,api,busy}){
const [data,setData]=useState(null),[error,setError]=useState(''),[lotId,setLotId]=useState(''),[kind,setKind]=useState('criterion'),[selection,setSelection]=useState({}),[working,setWorking]=useState(false);const retry=useRef(null);
const allowed=r=>can(`industrial_costs.${r}`,context.unit?.id??null);const disabled=busy||working;
const load=async()=>{const r=await api('/api/industrial-costs');setData(r);};useEffect(()=>{setSelection({});load().catch(e=>setError(e.message));},[context.token]);
const lot=data?.lots.find(l=>String(l.id)===lotId)??data?.lots[0];const latest=lot?.results.at(-1);const lastInput=lot?.inputs.filter(i=>i.kind===kind).at(-1);
const options=k=>lot?.inputs.filter(i=>i.kind===k&&i.current&&i.decision?.decision==='approved')??[];
const reference=v=>{const r=lot.inputs.find(i=>String(i.id)===String(v));return r?{id:r.id,version:r.version}:null;};
async function send(path,input){setWorking(true);setError('');const signature=JSON.stringify([path,input]);if(retry.current?.signature!==signature)retry.current={signature,key:crypto.randomUUID()};try{await api(path,'POST',input,context.token,retry.current.key);retry.current=null;await load();}catch(e){setError(e.message);}finally{setWorking(false);}}
const decide=(type,row,decision,reason)=>send(`/api/industrial-costs/lots/${lot.id}/decisions`,{type,id:row.id,version:row.version,decision,reason});
const inputForm=e=>{e.preventDefault();const f=new FormData(e.currentTarget);let d;
if(kind==='criterion'){const p=reference(f.get('pool')),m=reference(f.get('machine'));if(!p||!m){setError('Escolher versões explícitas do conjunto e utilização.');return;}d={pool_id:p.id,pool_version:p.version,machine_id:m.id,machine_version:m.version,capacity:f.get('capacity'),driver_unit:'HM',hypothesis:'synthetic_only'};}
else if(kind.endsWith('_rate')){const source=reference(f.get('source'));if(!source){setError('Escolher origem exacta.');return;}d={source_id:source.id,source_version:source.version,amount:f.get('amount'),currency:'MZN',unit:units[kind]};}
else {d={quantity:f.get('quantity'),unit:units[kind],event_date:f.get('event_date')};if(kind==='production')d.completed=f.get('completed')==='on';}
send(`/api/industrial-costs/lots/${lot.id}/inputs`,{kind,source_ref:lastInput?.source_ref??f.get('source_ref'),version:(lastInput?.version??0)+1,previous_id:lastInput?.id??null,data:d,evidence:f.get('evidence')});};
return
INDUSTRIAL-COST-SIM-v1
Ensaio de custos industriais
ENSAIO INDUSTRIAL — SEM UTILIZAÇÃO OPERACIONAL. Critério sintético; não configura método contabilístico real. Sem stock, facturação, margens ou lançamentos.
{error&&
{error}
}
{!data?
A carregar…
:data.blocked?
Custeio industrial real bloqueado nesta instância.
:<>
{allowed('prepare')&&Abrir lote sintético e produto próprios}
{!lot?
Sem lotes no âmbito autorizado.
:<>
{lot.product.name} · {lot.centre} · {lot.period_start} a {lot.period_end} · {lot.currency}
{({quantity:'Quantidade',unit:'Unidade',event_date:'Data',amount:'Taxa',currency:'Moeda',capacity:'Capacidade',driver_unit:'Unidade da base',hypothesis:'Hipótese',source_id:'Origem #',source_version:'Versão da origem',pool_id:'Conjunto #',pool_version:'Versão do conjunto',machine_id:'Utilização #',machine_version:'Versão da utilização',completed:'Concluído'})[k]??k}
{r.snapshot.incomplete?'TOTAL INCOMPLETO — material pendente':'Total do perímetro sintético: '+money(r.snapshot.selected_total_exact)}
{r.snapshot.good_units} UN boas · Custo unitário do cenário: {r.snapshot.unit_cost_exact===null?'Indisponível':money(r.snapshot.unit_cost_exact)+'/UN'}
Residual separado: {money(r.snapshot.residual_exact)} por imputar
Conjunto: {r.snapshot.pool_exact} = {r.snapshot.allocated_exact} imputados + {r.snapshot.residual_exact} por imputar.
Reconciliação {r.snapshot.reconciliation.coverage==='partial_known_only'?'PARCIAL — só valores conhecidos':'do perímetro'}: {r.snapshot.reconciliation.known_origins_exact} = {r.snapshot.reconciliation.assigned_exact} atribuídos + {r.snapshot.reconciliation.unassigned_exact} por imputar.
{allowed('validate')&&r.current&&!r.decision&&decide('result',r,d,reason)}/>})}
>}>};
}
function SourceSelect({label,name,rows}){return ;}
function DecisionForm({disabled,onDecision}){return