Files
SGF/resources/js/StockPeriodReportWorkspace.jsx
2026-11-04 09:37:20 +02:00

30 lines
3.8 KiB
React
Raw Permalink 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.
import React,{useEffect,useState} from 'react';
import {milliQuantity} from './StockReadWorkspace.jsx';
import {requestStockPeriod} from './stock-period-request.js';
export function StockPeriodTable({rows}) {
return <div className="table-wrap"><table><thead><tr><th>Artigo / unidade</th><th>Armazém</th><th>Abertura</th><th>Entradas</th><th>Saídas</th><th>Fecho</th><th>Movimentos no período</th></tr></thead>
<tbody>{rows.map(row=><tr key={`${row.stock_item_id}:${row.warehouse_id}`}><td>{row.code} · {row.name} · {row.unit}</td><td>{row.warehouse_code} · {row.warehouse_name}</td>
{['opening_milli','incoming_milli','outgoing_milli','closing_milli'].map(key=><td key={key}>{milliQuantity(row[key])}</td>)}<td>{row.period_movements}</td></tr>)}</tbody></table></div>;
}
export default function StockPeriodReportWorkspace({api,context}) {
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 values=Object.fromEntries(new FormData(e.currentTarget));setData(null);setQuery({view:'period',from:values.from,to:values.to,search:values.search,warehouse_id:values.warehouse_id||undefined,per_page:Number(values.per_page),page:1});};
return <section aria-label="Relatório físico por período"><h3>Resumo físico por artigo e armazém</h3>
<p>Escolha as datas do registo em UTC. Abertura antes do primeiro dia; fecho até ao fim do último dia. As designações são as actuais.</p>
<form onSubmit={submit}><label>Primeiro dia (UTC)<input name="from" type="date" min="1900-01-01" max="9998-12-31" required/></label><label>Último dia (UTC)<input name="to" type="date" min="1900-01-01" max="9998-12-31" required/></label>
<label>Artigo por código ou nome<input name="search" maxLength={100}/></label><label>Identificador do armazém autorizado<input name="warehouse_id" type="number" min="1"/></label>
<label>Linhas por página<select name="per_page" defaultValue="25"><option value="25">25</option><option value="100">100</option></select></label><button disabled={loading}>Consultar período</button></form>
{!query&&<p>Seleccione o período; não foi consultada nem escolhida uma data automaticamente.</p>}
{loading&&<p role="status">A consultar o período autorizado…</p>}
{error&&<div role="alert"><p>{error}</p><button onClick={()=>{setData(null);setQuery({...query,page:1,snapshot:undefined});}}>Actualizar relatório</button></div>}
{data&&<><p role="status">{data.notice}</p><p>{data.period.from} a {data.period.to} · {data.period.timezone} · referência {data.observed_at}. Página {data.pagination.page} de {data.pagination.last_page}; {data.pagination.total} pares artigo/armazém.</p>
<StockPeriodTable rows={data.rows}/>{data.rows.length===0&&<p>Sem pares com história elegível até ao fecho para estes filtros. Não se inventam existências 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={()=>{setData(null);setQuery({...query,page:1,snapshot:undefined});}}>Nova referência de leitura</button></>}
<p>Fecho = abertura + entradas − saídas, por linha e unidade. Sem valorização, reservas, bloqueios ou disponibilidade calculada.</p>
</section>;
}