commit5
tests / ci (push) Canceled after 0s

This commit is contained in:
2026-10-29 22:03:09 +02:00
parent 57f6b3cc36
commit 413c201d97
54 changed files with 2753 additions and 14 deletions
+10
View File
@@ -48,10 +48,12 @@ export default function Invoices({
invoices,
orders,
canManage,
payablesAvailable = false,
}: {
invoices: Page<Invoice>;
orders: { id: number; number: string; supplier: string; items: Source[] }[];
canManage: boolean;
payablesAvailable?: boolean;
}) {
const { auth } = usePage().props;
const [orderId, setOrderId] = useState('');
@@ -69,6 +71,7 @@ export default function Invoices({
return (
<>
<Head title="Facturas" />
{payablesAvailable && <a className="m-6 inline-block underline" href="/obrigacoes-fornecedores">Obrigações a fornecedores — ensaio sintético</a>}
<div className="mx-auto grid w-full max-w-6xl gap-6 p-6">
<PageTitle
eyebrow="SGC · Finanças"
@@ -282,6 +285,13 @@ export default function Invoices({
{money(invoice.tax_minor)} · Total{' '}
{money(invoice.total_minor)}
</p>
{payablesAvailable && (
<p className="my-3">
<a className="underline" href={`/obrigacoes-fornecedores?invoice=${invoice.id}`}>
Consultar ou preparar obrigação desta factura
</a>
</p>
)}
<ul className="my-3 space-y-2">
{invoice.items.map((l) => (
<li key={l.id}>
+46 -4
View File
@@ -20,21 +20,48 @@ type Props = {
next_page_url: string | null;
total: number;
};
filters: { search?: string; status?: string };
filters: { search?: string; status?: string; view?: string };
};
export default function Index({ requisitions, filters }: Props) {
const form = useForm({
search: filters.search ?? '',
status: filters.status ?? '',
view: filters.view ?? 'all',
});
const views: Record<string, { title: string; description: string }> = {
all: {
title: 'Requisições autorizadas',
description:
'Consulte os pedidos disponíveis para o seu perfil e acompanhe o estado de cada processo.',
},
mine: {
title:
filters.status === 'draft'
? 'Os meus rascunhos'
: 'Minhas requisições',
description:
'Pedidos criados por si, desde o rascunho até à decisão.',
},
approvals: {
title: 'Pendentes para mim',
description:
'Pedidos em que a próxima etapa pode ser decidida por si. A elegibilidade é conferida pelo servidor.',
},
decided: {
title: 'Minhas decisões',
description:
'Histórico dos pedidos em que registou uma aprovação ou rejeição.',
},
};
const view = views[filters.view ?? 'all'] ?? views.all;
return (
<>
<Head title="Requisições" />
<Head title={view.title} />
<div className="mx-auto flex w-full max-w-7xl flex-col gap-7 p-5 lg:p-8">
<PageTitle
eyebrow="Compras"
title="Requisições"
description="Registe necessidades e acompanhe cada pedido até à aprovação."
title={view.title}
description={view.description}
action={
<Button asChild>
<Link href="/requisicoes/criar">
@@ -52,6 +79,21 @@ export default function Index({ requisitions, filters }: Props) {
form.get('/requisicoes', { preserveState: true });
}}
>
<select
className={`${controlClass} max-w-60`}
aria-label="Conjunto de pedidos"
value={form.data.view}
onChange={(e) =>
form.setData('view', e.target.value)
}
>
<option value="all">Todas as autorizadas</option>
<option value="mine">Minhas requisições</option>
<option value="approvals">
Pendentes para mim
</option>
<option value="decided">Minhas decisões</option>
</select>
<Input
className="max-w-xs"
aria-label="Pesquisar pela referência"