import React, { useEffect, useState } from 'react';
const names = { issuer: 'Dados do emitente', client: 'Dados dos clientes', payment: 'Instruções de pagamento', service_drafts: 'Preparação de prestações', billing_drafts: 'Preparação de facturação' };
const profileFields = { nuit: 'NUIT', address: 'Morada', locality: 'Localidade', country: 'País' };
const paymentFields = { label: 'Designação das instruções', bank: 'Banco (se aplicável)', holder: 'Titular (se aplicável)', account_number: 'Identificador de conta (se aplicável)', nib: 'NIB (se aplicável)', iban: 'IBAN (se aplicável)', swift: 'SWIFT (se aplicável)', bank_code: 'Código bancário (se aplicável)', currency: 'Moeda das instruções (opcional)' };
const states = { missing: 'Por completar / confirmar aplicabilidade', filled_not_validated: 'Preenchido — não validado', validation_pending: 'Validação pendente', stale: 'Origem alterada — rever' };
const isDraft = kind => kind.endsWith('_drafts');
export default function DocumentPreparationWorkspace({ context, can, api, perform, busy }) {
const initial = can('issuer_documents.view') ? 'issuer' : can('client_documents.view') ? 'client' : 'billing_drafts';
const [kind, setKind] = useState(initial);
return ;
}
function DocumentPreparationArea({ kind, onSelect, context, can, api, perform, busy }) {
const prefix = kind => kind === 'client' ? 'client_documents' : isDraft(kind) ? 'draft_documents' : 'issuer_documents';
const permitted = (kind, action) => can(`${prefix(kind)}.${action}`, isDraft(kind) ? context.unit?.id ?? null : null);
const options = Object.keys(names).filter(kind => permitted(kind, 'view') && (!isDraft(kind) || context.unit));
const [records, setRecords] = useState([]); const [selectedId, setSelectedId] = useState(null);
const [record, setRecord] = useState(null); const [form, setForm] = useState({}); const [payments, setPayments] = useState([]); const [error, setError] = useState('');
const path = `/api/document-preparation/${kind}`;
async function load() { const result = await api(path); setRecords(result.records); }
async function open(id) {
setError('');
try {
const result = await api(`${path}/${id}`); setRecord(result); setSelectedId(id);
setForm({ ...result.data, ...(isDraft(kind) ? { currency: result.currency || '', price_mode: result.data.price_mode || 'undefined', units: result.lines.map((_, i) => result.data.units?.[i] || ''), payment_instruction_ids: result.data.payment_instruction_ids || [] } : {}) });
} catch (e) { setError(e.message); }
}
useEffect(() => { setRecord(null); setSelectedId(null); setError(''); load().then(() => { if (kind === 'issuer') open(context.company.id); }).catch(e => setError(e.message)); if (isDraft(kind) && can('issuer_documents.view')) api('/api/document-preparation/payment').then(data => setPayments(data.records)).catch(e => setError(e.message)); }, [kind, context.token]);
function change(field, value) { setForm(current => ({ ...current, [field]: value })); }
async function save(e) {
e.preventDefault();
const fields = kind === 'payment' ? [...Object.keys(paymentFields), 'instructions'] : isDraft(kind) ? ['service_date','period_start','period_end','payment_terms','proposed_due_date','price_mode','units','payment_instruction_ids','currency'] : Object.keys(profileFields);
const data = Object.fromEntries(fields.map(field => [field, form[field] === undefined || form[field] === '' ? null : form[field]]));
data.version = record?.version || 0;
if (isDraft(kind)) data.draft_version = record.draft_version;
await perform(async () => { const result = await api(`${path}/${selectedId ?? 0}`, 'PATCH', data, context.token); await load(); await open(result.id); }, 'Preparação guardada com histórico. Preenchido não significa validado.');
}
const editable = permitted(kind, 'edit') && !record?.locked;
const text = (field, label, type = 'text') => ;
return <>
PREPARAÇÃO DOCUMENTAL
Dados para facturação
Completar e reutilizar informação. Sem emissão fiscal, recebimentos ou lançamentos.
{options.map(option => )}
{error && {error}
}
{!options.length ? Sem acesso documental explícito neste contexto.
: {names[kind]}
{kind === 'payment' && editable && }{!records.length && Ainda não existem registos. Clientes e rascunhos são criados nos menus existentes.
}{records.map(item => )}
{record ? <>{record.name || names[kind]}
{record.origin || 'Instruções do emitente'} · Versão {record.version}
{record.locked && Confirmação B1 preservada. Esta preparação está bloqueada para edição.
}Completude e validações
Sem validação fiscal. Dados preenchidos não significam aptidão para emissão.
{Object.entries(record.related_profiles || {}).map(([profile,value]) => {profile === 'issuer' ? 'Emitente' : 'Cliente'}: {value.name} · versão documental {value.version} · reutilizado do cadastro
{value.review.map((check,i) => - {check.label}: {states[check.state]} — {check.next}
)}
)}> : Seleccione um registo para consultar ou preparar os dados existentes.
} }
>;
}