fix: stabilize broker display models
This commit is contained in:
parent
2462f2122c
commit
6d2df6a12b
@ -95,6 +95,22 @@ describe('buildBrokerAllocation', () => {
|
||||
]);
|
||||
});
|
||||
|
||||
it('ignores a tiny negative residual caused by decimal arithmetic', () => {
|
||||
const result = buildBrokerAllocation(portfolio({ shares: 0.1, bonds: 0.2, portfolio: 0.3 }));
|
||||
|
||||
expect(result.sectors.map(({ key }) => key)).toEqual(['shares', 'bonds']);
|
||||
expect(result.negative).toEqual([]);
|
||||
});
|
||||
|
||||
it('ignores a tiny positive residual caused by decimal arithmetic', () => {
|
||||
const result = buildBrokerAllocation(
|
||||
portfolio({ shares: 0.3, portfolio: 0.30000000000000004 }),
|
||||
);
|
||||
|
||||
expect(result.sectors.map(({ key }) => key)).toEqual(['shares']);
|
||||
expect(result.negative).toEqual([]);
|
||||
});
|
||||
|
||||
it('returns no allocation for missing or nonpositive portfolio totals', () => {
|
||||
expect(buildBrokerAllocation(portfolio({ shares: 100, portfolio: null }))).toEqual({
|
||||
total: 0,
|
||||
|
||||
@ -32,12 +32,22 @@ export function buildBrokerAllocation(portfolio: BrokerPortfolio): {
|
||||
const bonds = portfolio.totals.bonds?.value ?? 0;
|
||||
const etf = portfolio.totals.etf?.value ?? 0;
|
||||
const cash = portfolio.totals.currencies?.value ?? 0;
|
||||
const mappedTotal = shares + bonds + etf + cash;
|
||||
const residual = total - mappedTotal;
|
||||
const residualTolerance =
|
||||
Number.EPSILON *
|
||||
Math.max(
|
||||
1,
|
||||
Math.abs(total),
|
||||
Math.abs(shares) + Math.abs(bonds) + Math.abs(etf) + Math.abs(cash),
|
||||
) *
|
||||
8;
|
||||
const values: Record<BrokerAllocationKey, number> = {
|
||||
shares,
|
||||
bonds,
|
||||
etf,
|
||||
cash,
|
||||
other: total - shares - bonds - etf - cash,
|
||||
other: Math.abs(residual) <= residualTolerance ? 0 : residual,
|
||||
};
|
||||
|
||||
const sectors: BrokerAllocationItem[] = [];
|
||||
|
||||
@ -138,6 +138,11 @@ describe('broker display helpers', () => {
|
||||
expect(labels).toEqual([...labels].sort((left, right) => left.localeCompare(right, 'ru')));
|
||||
});
|
||||
|
||||
it('keeps operation type options immutable at runtime', () => {
|
||||
expect(Object.isFrozen(BROKER_OPERATION_TYPE_OPTIONS)).toBe(true);
|
||||
expect(BROKER_OPERATION_TYPE_OPTIONS.every((option) => Object.isFrozen(option))).toBe(true);
|
||||
});
|
||||
|
||||
it('validates only exact known operation type values', () => {
|
||||
expect(isBrokerOperationType('OPERATION_TYPE_COUPON')).toBe(true);
|
||||
expect(isBrokerOperationType('operation_type_coupon')).toBe(false);
|
||||
|
||||
@ -94,9 +94,13 @@ const OPERATION_TYPE_LABELS: Record<string, string> = {
|
||||
OPERATION_TYPE_OUTPUT_SECURITIES: 'Списание бумаг',
|
||||
};
|
||||
|
||||
export const BROKER_OPERATION_TYPE_OPTIONS = Object.entries(OPERATION_TYPE_LABELS)
|
||||
.map(([value, label]) => ({ value, label }))
|
||||
.sort((left, right) => left.label.localeCompare(right.label, 'ru'));
|
||||
export const BROKER_OPERATION_TYPE_OPTIONS: ReadonlyArray<
|
||||
Readonly<{ value: string; label: string }>
|
||||
> = Object.freeze(
|
||||
Object.entries(OPERATION_TYPE_LABELS)
|
||||
.map(([value, label]) => Object.freeze({ value, label }))
|
||||
.sort((left, right) => left.label.localeCompare(right.label, 'ru')),
|
||||
);
|
||||
|
||||
const BROKER_OPERATION_TYPES = new Set(BROKER_OPERATION_TYPE_OPTIONS.map(({ value }) => value));
|
||||
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user