256 lines
9.8 KiB
TypeScript
256 lines
9.8 KiB
TypeScript
import { useState } from 'react';
|
|
import type { CurrencyEventRow } from '@/lib/iva-currency-events';
|
|
import {
|
|
emptyFxSelection,
|
|
selectFx,
|
|
fxTempoSource,
|
|
type FxSelection,
|
|
} from '@/lib/iva-fx-selection';
|
|
const columnLabels: Record<string, string> = {
|
|
buy: 'Compra',
|
|
sell: 'Venda',
|
|
mean: 'Média de referência BM',
|
|
exception: 'Excepção fiscal identificada',
|
|
};
|
|
const directionLabels: Record<string, string> = {
|
|
mzn_per_unit: 'MZN por unidade da moeda original',
|
|
units_per_mzn: 'unidades da moeda original por MZN',
|
|
};
|
|
export function SimulationFxSelection({
|
|
row,
|
|
onChange,
|
|
}: {
|
|
row: CurrencyEventRow;
|
|
onChange: (patch: Partial<CurrencyEventRow>) => void;
|
|
}) {
|
|
const [error, setError] = useState(''),
|
|
[preview, setPreview] = useState<ReturnType<typeof selectFx> | null>(
|
|
null,
|
|
);
|
|
const s = row.fxSelection ?? {
|
|
...emptyFxSelection(),
|
|
sourceCurrency: row.sourceCurrency,
|
|
direction: row.fxDirection,
|
|
};
|
|
const edit = (patch: Partial<FxSelection>) => {
|
|
setPreview(null);
|
|
onChange({ fxSelection: { ...s, ...patch } });
|
|
};
|
|
const text = (
|
|
key:
|
|
| 'submissionDate'
|
|
| 'bulletinDate'
|
|
| 'bulletinRef'
|
|
| 'source'
|
|
| 'sourceCurrency'
|
|
| 'bulletinPerspective'
|
|
| 'buy'
|
|
| 'sell'
|
|
| 'mean'
|
|
| 'exceptionRef'
|
|
| 'exceptionScope'
|
|
| 'exceptionDate'
|
|
| 'exceptionRate',
|
|
label: string,
|
|
) => (
|
|
<label className="block" key={key}>
|
|
{label}
|
|
<input
|
|
value={s[key]}
|
|
type={key.endsWith('Date') ? 'date' : 'text'}
|
|
onChange={(e) => edit({ [key]: e.target.value })}
|
|
/>
|
|
</label>
|
|
);
|
|
return (
|
|
<fieldset className="rounded border p-3">
|
|
<legend>P104 — selecção da taxa segundo orientação da Tempo</legend>
|
|
<p>{fxTempoSource}</p>
|
|
<label>
|
|
Natureza da operação declarada
|
|
<select
|
|
value={s.nature}
|
|
onChange={(e) =>
|
|
edit({
|
|
nature: e.target.value as FxSelection['nature'],
|
|
})
|
|
}
|
|
>
|
|
<option value="">Por indicar</option>
|
|
<option value="purchase">Compra de moeda</option>
|
|
<option value="sale">Venda de moeda</option>
|
|
<option value="commercial">Operação comercial</option>
|
|
</select>
|
|
</label>
|
|
{text('submissionDate', 'Data de submissão indicada')}
|
|
{text('sourceCurrency', 'Moeda original já declarada')}
|
|
{text('bulletinRef', 'Boletim,edição e série de referência')}
|
|
{text(
|
|
'source',
|
|
'Fonte do boletim;URL do Banco de Moçambique para operações comerciais',
|
|
)}
|
|
{text('bulletinDate', 'Data do boletim')}
|
|
<label>
|
|
Emitente identificado do boletim,quando a fonte é um exemplar
|
|
arquivado
|
|
<input
|
|
value={s.issuer ?? ''}
|
|
onChange={(e) => edit({ issuer: e.target.value })}
|
|
/>
|
|
</label>
|
|
<label>
|
|
Sentido da cotação
|
|
<select
|
|
value={s.direction}
|
|
onChange={(e) =>
|
|
edit({
|
|
direction: e.target
|
|
.value as FxSelection['direction'],
|
|
})
|
|
}
|
|
>
|
|
<option value="">Por indicar</option>
|
|
<option value="mzn_per_unit">
|
|
MZN por unidade da moeda original
|
|
</option>
|
|
<option value="units_per_mzn">
|
|
Unidades da moeda original porMZN
|
|
</option>
|
|
</select>
|
|
</label>
|
|
<button
|
|
type="button"
|
|
onClick={() =>
|
|
edit({
|
|
sourceCurrency: s.sourceCurrency || row.sourceCurrency,
|
|
direction: s.direction || row.fxDirection,
|
|
submissionDate: s.submissionDate || row.fxDate,
|
|
bulletinDate: s.bulletinDate || row.fxDate,
|
|
source: s.source || row.fxSource,
|
|
})
|
|
}
|
|
>
|
|
Reutilizar moeda,sentido e data já indicados nos campos
|
|
vazios;conferir a data de submissão
|
|
</button>
|
|
<label>
|
|
Regra aplicável
|
|
<select
|
|
value={s.mode}
|
|
onChange={(e) =>
|
|
edit({ mode: e.target.value as FxSelection['mode'] })
|
|
}
|
|
>
|
|
<option value="general">Procedimento geral da Tempo</option>
|
|
<option value="exception">
|
|
Excepção fiscal específica identificada
|
|
</option>
|
|
</select>
|
|
</label>
|
|
{s.mode === 'exception' ? (
|
|
<>
|
|
{text(
|
|
'exceptionRef',
|
|
'Disposição fiscal que impõe outra data/taxa',
|
|
)}
|
|
{text('exceptionScope', 'Âmbito da excepção')}
|
|
{text('exceptionDate', 'Data imposta pela disposição')}
|
|
{text(
|
|
'exceptionRate',
|
|
'Taxa da excepção,com fonte no boletim indicado',
|
|
)}
|
|
</>
|
|
) : s.nature === 'commercial' ? (
|
|
text(
|
|
'mean',
|
|
'Coluna Média da série de referênciaBM;sem calcular média própria',
|
|
)
|
|
) : (
|
|
<>
|
|
{text(
|
|
'bulletinPerspective',
|
|
'Perspectiva de compra/venda indicada no boletim',
|
|
)}
|
|
<label>
|
|
Relação da natureza declarada com a perspectiva do
|
|
boletim
|
|
<select
|
|
value={s.relation}
|
|
onChange={(e) =>
|
|
edit({
|
|
relation: e.target
|
|
.value as FxSelection['relation'],
|
|
})
|
|
}
|
|
>
|
|
<option value="">Por conferir</option>
|
|
<option value="same">Mesma perspectiva</option>
|
|
<option value="opposite">
|
|
Perspectiva contrária:compra do cliente
|
|
corresponde a venda do emitente,ou inversamente
|
|
</option>
|
|
</select>
|
|
</label>
|
|
{text('buy', 'Taxa da coluna Compra do boletim')}
|
|
{text('sell', 'Taxa da coluna Venda do boletim')}
|
|
</>
|
|
)}
|
|
{error && <p role="alert">{error}</p>}
|
|
<button
|
|
type="button"
|
|
onClick={() => {
|
|
try {
|
|
setPreview(selectFx(s));
|
|
setError('');
|
|
} catch (e) {
|
|
setError(String(e));
|
|
}
|
|
}}
|
|
>
|
|
Conferir selecção e impacto
|
|
</button>
|
|
{preview && (
|
|
<div>
|
|
<p>
|
|
Coluna:{columnLabels[preview.column]};taxa:
|
|
{preview.rate};data:{preview.date};sentido:
|
|
{directionLabels[s.direction]}. Confirmação substitui os
|
|
campos cambiais desta linha:{row.fxRate || 'taxa vazia'}{' '}
|
|
→ {preview.rate};{row.fxDate || 'data vazia'} →{' '}
|
|
{preview.date};{row.sourceCurrency || 'moeda vazia'} →{' '}
|
|
{s.sourceCurrency}. O resultado e os históricos
|
|
permanecem até usar «Conferir moeda/eventos e guardar
|
|
versão».
|
|
</p>
|
|
<button
|
|
type="button"
|
|
onClick={() => {
|
|
onChange({
|
|
fxSelection: { ...s, applied: preview },
|
|
sourceCurrency: s.sourceCurrency,
|
|
fxDirection: s.direction,
|
|
fxRate: preview.rate,
|
|
fxDate: preview.date,
|
|
fxSource: preview.source,
|
|
fxRuleRef:
|
|
s.mode === 'exception'
|
|
? s.exceptionRef
|
|
: fxTempoSource,
|
|
});
|
|
setPreview(null);
|
|
}}
|
|
>
|
|
Confirmar selecção nesta linha
|
|
</button>
|
|
</div>
|
|
)}
|
|
<p>
|
|
Não usar taxa de apresentação nem a mais recente como substituto
|
|
de boletim ausente. Compra/venda são interpretadas pela
|
|
perspectiva indicada;relação desconhecida fica por esclarecer.
|
|
Alterações não recalculam versões anteriores.
|
|
</p>
|
|
</fieldset>
|
|
);
|
|
}
|