import { inputText } from '../lib/input-text.ts'; import { useState } from 'react'; import { travelEventBook, travelEventCurrent, travelEventReportRows, travelEventSource, travelEventSources, newTravelEvent, recordTravelEvents, saveTravelEventBook, switchTravelEvent, type TravelEventBook, type TravelEventRow, } from '@/lib/iva-travel-events'; export function SimulationTravelEvents({ draft, onChange, }: { draft: Record; onChange: (field: string, value: string) => void; }) { const [error, setError] = useState(''); let book: TravelEventBook; try { book = travelEventBook(draft); } catch (e) { return

{String(e)}

; } const save = (next: TravelEventBook) => { try { onChange('modelo_a_snapshot', saveTravelEventBook(draft, next)); setError(''); } catch (e) { setError(String(e)); } }; const change = (id: string, patch: Partial) => save({ ...book, rows: book.rows.map((r) => (r.id === id ? { ...r, ...patch } : r)), }); const fields = ( row: TravelEventRow, list: ReadonlyArray< readonly [Exclude, string] >, ) => list.map(([key, label]) => ( )); const select = ( row: TravelEventRow, key: Exclude, label: string, options: ReadonlyArray, ) => ( ); const yn = [ ['yes', 'Sim'], ['no', 'Não'], ] as const; let sources: ReturnType = []; try { sources = travelEventSources(draft); } catch { /* Origin reader preserves originals. */ } return (
Eventos de viagens e cessação de regimes suspensivos

Conserve separados facto gerador e exigibilidade. Não inferir pagamento integral por um sinal, início pela emissão do bilhete ou cessação do regime por mudança de armazém. Estes eventos não calculam imposto nem concedem benefício.

{travelEventSource}

{error &&

{error}

} {book.rows.map((row) => { const source = sources.find((s) => s.id === row.travelRowId); return (
{row.description || 'Evento por identificar'} —{' '} {row.period || 'período por indicar'} {fields(row, [ ['description', 'Evento ou operação identificada'], [ 'operationRef', 'Referência da operação existente', ], ['period', 'Mês de contexto do evento'], [ 'documentRef', 'Documento disponível / referência da previsão', ], ['documentDate', 'Data do documento / prevista'], [ 'reviewDate', 'Data até à qual os eventos são conferidos', ], [ 'scope', 'Âmbito e parcela efectivamente abrangidos', ], ['evidence', 'Factos ou pressupostos expressos'], ])} {select(row, 'origin', 'Natureza dos dados', [ ['projected', 'Projectados / pressupostos'], ['effective', 'Efectivos declarados'], ])} {select( row, 'factsConfirmed', 'Factos correspondem ao percurso e âmbito identificados', yn, )} {row.treatment === 'suspensive_exit' && ( <> {select( row, 'regimeClause', 'Regime/procedimento identificado no artigo14(1)', [ [ 'a', 'a — Importação/colocação em regimes ou depósitos indicados', ], [ 'b', 'b — Expedição/transporte para as zonas ou depósitos e conexos', ], [ 'c', 'c — Transmissão e serviços conexos sob o regime', ], [ 'd', 'd — Trânsito, transbordo, draubaque ou importação temporária e conexos', ], ], )} {fields(row, [ [ 'entryDate', 'Data de colocação sob o regime/procedimento', ], [ 'entryRef', 'Referência do regime, bens e operação de entrada', ], ])} {select( row, 'regimeStatus', 'Situação do regime na conferência', [ [ 'still', 'Continua abrangido pelo regime', ], [ 'ceased', 'Cessou efectivamente o regime', ], ], )} {row.regimeStatus === 'ceased' && ( <> {fields(row, [ [ 'exitDate', 'Data da cessação efectiva', ], [ 'exitRef', 'Referência e âmbito da cessação', ], ])} {select( row, 'cessationConfirmed', 'Confirmada cessação fiscal, distinguida de transferência entre regimes ou mudança física', yn, )} )}

A referência demonstra o facto e o âmbito. Não se exige certificado ou autorização inventados; não há desembaraço, valor aduaneiro, direitos ou ICE automáticos.

)} {row.treatment === 'travel_special' && ( <> {source && ( <>

Origem: {source.operationRef};{' '} {source.scope}. Período do registo:{' '} {source.period}.{' '} {source.classification.reason}

Referências já preenchidas são conservadas; divergências precisam de conferência. O período do evento pode diferir do período da margem.

)} {select( row, 'fullPaymentState', 'Estado do pagamento da contraprestação', [ [ 'full', 'Pagamento integral confirmado', ], ['partial', 'Apenas pagamento parcial'], ['none', 'Sem pagamentos'], ], )} {row.fullPaymentState === 'full' && fields(row, [ [ 'fullPaymentDate', 'Data do pagamento integral', ], [ 'fullPaymentRef', 'Referência da liquidação integral / conjunto de recebimentos', ], ])} {select( row, 'startState', 'Início da viagem/alojamento e primeiro serviço', [ [ 'started', 'Primeiro serviço/início ocorrido no cenário conferido', ], ['not_started', 'Ainda não iniciado'], ], )} {row.startState === 'started' && fields(row, [ [ 'startDate', 'Data do primeiro serviço ao cliente', ], [ 'startRef', 'Referência do primeiro serviço e âmbito', ], ])}

«Imediatamente antes» identifica o momento; não se subtrai um dia à data. Pagamento e início na mesma data não demonstram ordem intradiária.

{fields(row, [ [ 'amount', 'Contraprestação total da parcela analisada', ], ['currency', 'Moeda da contraprestação'], ])} {select( row, 'invoiceRequired', 'Operação com obrigação de emitir factura25', yn, )} {row.invoiceRequired === 'yes' && ( <> {fields(row, [ [ 'legalDeadline', 'Termo do prazo legal de emissão aplicável', ], [ 'deadlineRef', 'Disposição, calendário e âmbito que fundamentam o prazo', ], ])} {select( row, 'invoiceState', 'Factura até à conferência', [ ['issued', 'Emitida'], ['not_issued', 'Não emitida'], ], )} {row.invoiceState === 'issued' && fields(row, [ [ 'invoiceDate', 'Data de emissão da factura', ], [ 'invoiceRef', 'Referência da factura', ], ])} )} {select( row, 'paymentState', 'Recebimento ou parcela anterior à liquidação integral', [ ['none', 'Sem recebimento'], [ 'received', 'Recebimento identificado', ], ], )} {row.paymentState === 'received' && fields(row, [ [ 'paymentDate', 'Data do recebimento identificado', ], [ 'paymentAmount', 'Montante recebido nessa parcela', ], [ 'paymentRef', 'Referência e âmbito da parcela recebida', ], ])}

Se existe sinal anterior e posterior liquidação integral, identifique ambos: a parcela e o saldo não são somados duas vezes. A menção «IVA incluído» não é factura emitida por este simulador.

)}

Mudar percurso conserva campos ocultos e referências; reveja as confirmações próprias.

); })} {!!book.rows.length && ( )} {book.result && ( <>

{travelEventCurrent(draft, book) ? 'Resultados correspondem às entradas e origens guardadas.' : 'Entradas/origens alteradas; resultado histórico conservado. Reveja o delta.'}{' '} {book.history?.length ?? 0} versões anteriores. Sem base/IVA/dedução calculados.

{travelEventReportRows(draft).map( ([, label, value, origin], i) => (
{label}
{value} {origin}
), )}
)}
); }