Files
SGF/resources/js/StockInactiveReportWorkspace.jsx
2026-11-11 09:00:17 +02:00

17 lines
4.6 KiB
React

import React,{useEffect,useState} from 'react';
import {milliQuantity} from './StockReadWorkspace.jsx';
import {requestStockPeriod} from './stock-period-request.js';
export default function StockInactiveReportWorkspace({api,context}) {
const [warehouseQuery,setWarehouseQuery]=useState({view:'warehouses',page:1,per_page:100}),[warehouses,setWarehouses]=useState(null),[warehouseError,setWarehouseError]=useState(''),[warehouseLoading,setWarehouseLoading]=useState(false),[warehouse,setWarehouse]=useState('');
useEffect(()=>requestStockPeriod({query:warehouseQuery,api,data:setWarehouses,error:setWarehouseError,loading:setWarehouseLoading}),[warehouseQuery,context.token]);
const [query,setQuery]=useState(null),[data,setData]=useState(null),[error,setError]=useState(''),[loading,setLoading]=useState(false);
useEffect(()=>{if(!query)return;return requestStockPeriod({query,api,data:setData,error:setError,loading:setLoading});},[query,context.token]);
const submit=e=>{e.preventDefault();const f=Object.fromEntries(new FormData(e.currentTarget));setQuery({view:'inactive',as_of:f.as_of,days:Number(f.days),search:f.search,warehouse_id:f.warehouse_id||undefined,per_page:Number(f.per_page),page:1});};
return <section aria-label="Produtos sem movimento"><h3>Pares artigo/armazém com história conhecida</h3><p>Escolha o corte UTC e o número de dias consecutivos sem registo físico, incluindo o dia de corte. Artigos sem história conhecida ficam fora desta conclusão.</p>
<form onSubmit={submit}><label>Dia de corte (UTC)<input name="as_of" type="date" min="1900-01-01" max="9998-12-31" required/></label><label>Dias sem movimento<input name="days" type="number" min="1" max="3650" defaultValue="30" required/></label><label>Código ou nome<input name="search" maxLength={100}/></label><label>Armazém<select name="warehouse_id" value={warehouse} onChange={e=>setWarehouse(e.target.value)}><option value="">Todos os autorizados</option>{warehouse&&!warehouses?.rows.some(r=>String(r.id)===warehouse)&&<option value={warehouse}>Armazém seleccionado #{warehouse}</option>}{warehouses?.rows.map(r=><option key={r.id} value={r.id}>{r.code} · {r.name}</option>)}</select></label><label>Linhas por página<select name="per_page" defaultValue="25"><option>25</option><option>100</option></select></label><button disabled={loading}>Consultar inactividade</button></form>{warehouseError&&<p role="alert">{warehouseError}<button onClick={()=>setWarehouseQuery({view:'warehouses',page:1,per_page:100})}>Actualizar armazéns</button></p>}{warehouses&&warehouses.pagination.last_page>1&&<nav aria-label="Páginas de armazéns"><button disabled={warehouseLoading||warehouses.pagination.page<=1} onClick={()=>setWarehouseQuery({...warehouseQuery,page:warehouses.pagination.page-1,snapshot:warehouses.snapshot})}>Armazéns anteriores</button><button disabled={warehouseLoading||warehouses.pagination.page>=warehouses.pagination.last_page} onClick={()=>setWarehouseQuery({...warehouseQuery,page:warehouses.pagination.page+1,snapshot:warehouses.snapshot})}>Mais armazéns</button></nav>}
{loading&&<p role="status">A consultar a história autorizada…</p>}{error&&<div role="alert"><p>{error}</p><button onClick={()=>setQuery({...query,page:1,snapshot:undefined})}>Actualizar relatório</button></div>}
{data&&<><p>{data.notice}</p><p>Corte {data.as_of} UTC · mínimo {data.minimum_days} dias · {data.pagination.total} pares · página {data.pagination.page} de {data.pagination.last_page} · observado {data.observed_at}</p><div className="table-wrap"><table><thead><tr><th>Artigo / unidade</th><th>Armazém</th><th>Último registo UTC</th><th>Dias sem registo</th><th>Quantidade física no corte</th></tr></thead><tbody>{data.rows.map(r=><tr key={r.stock_item_id+':'+r.warehouse_id}><td>{r.code} · {r.name} · {r.unit}</td><td>{r.warehouse_code} · {r.warehouse_name}</td><td>{r.last_registered_at}</td><td>{r.days_without_record}</td><td>{milliQuantity(r.physical_quantity_milli)}</td></tr>)}</tbody></table></div>{!data.rows.length&&<p>Sem pares elegíveis para estes filtros. Não significa ausência de actividade ou stock zero.</p>}<button disabled={loading||data.pagination.page<=1} onClick={()=>setQuery({...query,page:data.pagination.page-1,snapshot:data.snapshot})}>Anterior</button><button disabled={loading||data.pagination.page>=data.pagination.last_page} onClick={()=>setQuery({...query,page:data.pagination.page+1,snapshot:data.snapshot})}>Seguinte</button><button disabled={loading} onClick={()=>setQuery({...query,page:1,snapshot:undefined})}>Nova referência de leitura</button></>}
</section>;
}