commit
tests / ci (push) Canceled after 0s

This commit is contained in:
2026-10-28 12:06:05 +02:00
parent 90a6848721
commit 4d42f083ce
82 changed files with 7538 additions and 76 deletions
+7
View File
@@ -2,6 +2,13 @@ export type User = {
id: number;
name: string;
email: string;
purchasing_role?:
| 'requester'
| 'department_head'
| 'procurement'
| 'finance'
| 'warehouse'
| 'admin';
avatar?: string;
email_verified_at: string | null;
created_at: string;
+22
View File
@@ -0,0 +1,22 @@
export type ConflictDeclaration = {
id: number;
user_id: number;
supplier_id: number | null;
requisition_id: number | null;
has_conflict: boolean;
known_since: string;
declared_at: string;
reason: string;
previous_id: number | null;
root_id: number | null;
author: { name: string };
supplier: { name: string } | null;
requisition: { number: string } | null;
successor?: { id: number } | null;
};
export function conflictScope(declaration: ConflictDeclaration) {
return [declaration.supplier?.name, declaration.requisition?.number]
.filter(Boolean)
.join(' · ');
}
+87
View File
@@ -0,0 +1,87 @@
export type Department = { id: number; name: string };
export type CostCenter = {
id: number;
department_id: number;
code: string;
name: string;
};
export type Company = {
id: number;
name: string;
first_limit_minor: number;
second_limit_minor: number;
approval_includes_tax: boolean;
rules_provisional: boolean;
};
export type RequisitionItem = {
id?: number;
description: string;
category: string;
purchase_type: string;
quantity: string;
unit: string;
unit_price_minor: number;
tax_rate: string;
subtotal_minor: number;
tax_minor: number;
total_minor: number;
};
export type ApprovalStep = {
id: number;
position: number;
role: string;
decision: string;
approver_id: number | null;
comment: string | null;
decided_at: string | null;
};
export type Requisition = {
id: number;
number: string;
status: string;
priority: string;
needed_by: string;
justification: string;
cost_center_id: number;
subtotal_minor: number;
tax_minor: number;
total_minor: number;
created_at: string;
requester?: { name: string };
department?: Department;
cost_center?: CostCenter;
items: RequisitionItem[];
steps: ApprovalStep[];
approval_snapshot?: {
rules_provisional: boolean;
approval_includes_tax: boolean;
} | null;
};
export const roleLabels: Record<string, string> = {
requester: 'Solicitante',
department_head: 'Chefe de departamento',
procurement: 'Procurement',
finance: 'Finanças',
warehouse: 'Recepção / Armazém',
admin: 'Administrador',
};
export const statusLabels: Record<string, string> = {
draft: 'Rascunho',
pending: 'Em aprovação',
approved: 'Aprovada',
rejected: 'Rejeitada',
};
export const priorityLabels: Record<string, string> = {
normal: 'Normal',
high: 'Alta',
urgent: 'Urgente',
};
export const money = (minor: number) =>
new Intl.NumberFormat('pt-MZ', {
style: 'currency',
currency: 'MZN',
}).format(minor / 100);
export const date = (value: string) =>
new Intl.DateTimeFormat('pt-MZ').format(
new Date(value.slice(0, 10) + 'T12:00:00'),
);
+25
View File
@@ -0,0 +1,25 @@
export type MatrixRow = {
id: number; reference: string; supplier: { name: string }; supplier_id: number;
eligible: boolean; ineligibility_reasons: string[]; evaluation_count: number;
score: number | null; score_minor: number | null; subtotal_minor: number; tax_minor: number; total_minor: number;
evaluations: { evaluator_id: number; quality: string; history: string; payment: string; comment: string }[];
};
export type AwardApproval = { id: number; position: number; role: string; decision: string; approver_id: number | null; comment: string | null };
export type PurchaseAward = {
id: number; requisition_id: number; quotation_id: number; status: string; justification: string;
subtotal_minor: number; tax_minor: number; total_minor: number; delivery_date: string; delivery_location: string;
approval_snapshot: { approval_includes_tax: boolean; rules_provisional: boolean }; approvals: AwardApproval[];
};
export type OrderItem = { id: number; description: string; quantity: string; unit: string; unit_price_minor: number; tax_rate: string; subtotal_minor: number; tax_minor: number; total_minor: number };
export type PurchaseOrder = {
id: number; number: string; requisition_id: number; issued_at: string; currency: string;
subtotal_minor: number; tax_minor: number; total_minor: number; items: OrderItem[];
snapshot: {
company: { name: string }; department: { name: string }; cost_center: { code: string; name: string };
requisition: { number: string }; issuer: { name: string }; requester: { name: string };
supplier: { name: string; nuit: string; contact: string; phone: string; email: string; address: string };
quotation: { reference: string; payment_terms: string }; award: { justification: string; delivery_date: string; delivery_location: string };
approval_rules: { approval_includes_tax: boolean; rules_provisional: boolean };
decision_matrix: MatrixRow[]; final_approvals: AwardApproval[];
};
};
+43
View File
@@ -0,0 +1,43 @@
export type Supplier = {
id: number;
name: string;
nuit: string;
contact: string;
email: string;
phone: string;
address: string;
category: string;
beneficiaries: string;
document_references: string;
diligence_notes: string;
blocked: boolean;
next_review: string;
status: string;
review_comment: string | null;
version: number;
};
export const supplierFields = {
name: 'Nome legal',
nuit: 'NUIT (9 dígitos)',
contact: 'Pessoa de contacto',
email: 'Email',
phone: 'Telefone',
address: 'Morada',
category: 'Categoria de fornecimento',
beneficiaries: 'Beneficiários efectivos',
document_references: 'Referências dos documentos verificados',
diligence_notes: 'Resultado da diligência devida',
next_review: 'Próxima revisão',
};
export const supplierStatuses: Record<string, string> = {
pending: 'Pendente de validação',
active: 'Activo',
suspended: 'Suspenso',
};
export const documentTypes: Record<string, string> = {
license: 'Alvará / licença',
tax: 'Situação fiscal',
conflict: 'Declaração de conflitos',
other: 'Outro documento',
};