refactor: simplify investment data flow
This commit was merged in pull request #39.
This commit is contained in:
@@ -0,0 +1,68 @@
|
||||
import {
|
||||
decimalFromString,
|
||||
formatDecimal,
|
||||
multiply,
|
||||
} from '../../../common/decimal';
|
||||
import { ISO_DATE_LENGTH, ISO_DATE_START, MILLISECONDS_PER_SECOND } from '../../../common/time';
|
||||
import type { MoexBondEvent } from '../../../integrations/moex/moex.api';
|
||||
import { decimal } from '../../../integrations/tbank/decimal';
|
||||
import type { TbankDividend } from '../../../integrations/tbank/tbank.api';
|
||||
import { UpcomingEventDto } from './upcoming-events.dto';
|
||||
|
||||
export function dividendEvent(
|
||||
metadata: Pick<
|
||||
UpcomingEventDto,
|
||||
'displayName' | 'figi' | 'instrumentUid' | 'isin' | 'logoName' | 'ticker'
|
||||
>,
|
||||
quantity: ReturnType<typeof decimal>,
|
||||
event: TbankDividend,
|
||||
): UpcomingEventDto {
|
||||
return {
|
||||
...metadata,
|
||||
type: 'dividend',
|
||||
date: new Date(Number(event.recordDate?.seconds) * MILLISECONDS_PER_SECOND)
|
||||
.toISOString()
|
||||
.slice(ISO_DATE_START, ISO_DATE_LENGTH),
|
||||
dateKind: 'registry',
|
||||
projectedAmount: event.dividendNet
|
||||
? projectedMoney(
|
||||
quantity,
|
||||
formatDecimal(decimal(event.dividendNet)),
|
||||
event.dividendNet.currency,
|
||||
)
|
||||
: null,
|
||||
};
|
||||
}
|
||||
|
||||
export function bondEvent(
|
||||
metadata: Pick<
|
||||
UpcomingEventDto,
|
||||
'displayName' | 'figi' | 'instrumentUid' | 'isin' | 'logoName' | 'ticker'
|
||||
>,
|
||||
quantity: ReturnType<typeof decimal>,
|
||||
event: MoexBondEvent,
|
||||
): UpcomingEventDto {
|
||||
return {
|
||||
...metadata,
|
||||
type: event.type,
|
||||
date: event.date,
|
||||
dateKind: 'event',
|
||||
projectedAmount:
|
||||
'value' in event
|
||||
? projectedMoney(quantity, event.value, event.currency)
|
||||
: null,
|
||||
};
|
||||
}
|
||||
|
||||
function projectedMoney(
|
||||
quantity: ReturnType<typeof decimal>,
|
||||
value: string,
|
||||
currency: string | undefined,
|
||||
): UpcomingEventDto['projectedAmount'] {
|
||||
const normalizedCurrency = currency?.trim().toUpperCase();
|
||||
if (!normalizedCurrency) return null;
|
||||
return {
|
||||
currency: normalizedCurrency,
|
||||
value: formatDecimal(multiply(quantity, decimalFromString(value))),
|
||||
};
|
||||
}
|
||||
@@ -1,5 +1,5 @@
|
||||
import { decimalFromString } from '../../../common/decimal';
|
||||
import { bondEvent, dividendEvent } from './upcoming-events.service';
|
||||
import { bondEvent, dividendEvent } from './upcoming-event.mapper';
|
||||
jest.mock('../../../prisma/prisma.service', () => ({
|
||||
PrismaService: class {},
|
||||
}));
|
||||
|
||||
@@ -1,22 +1,17 @@
|
||||
import { BadRequestException, Injectable } from '@nestjs/common';
|
||||
|
||||
import type { MoexBondEvent } from '../../../integrations/moex/moex.api';
|
||||
|
||||
import {
|
||||
add,
|
||||
decimalFromString,
|
||||
formatDecimal,
|
||||
isZero,
|
||||
multiply,
|
||||
} from '../../../common/decimal';
|
||||
import { MoneyDto } from '../../../common/money.dto';
|
||||
import { ISO_DATE_LENGTH, ISO_DATE_START, MILLISECONDS_PER_SECOND } from '../../../common/time';
|
||||
import { decimal } from '../../../integrations/tbank/decimal';
|
||||
import { ISO_DATE_LENGTH, ISO_DATE_START } from '../../../common/time';
|
||||
import {
|
||||
InstrumentMetadataService,
|
||||
metadataKey,
|
||||
TbankAccessService,
|
||||
type TbankDividend,
|
||||
} from '../../../integrations/tbank/tbank.api';
|
||||
import { CatalogEnrichmentService } from '../instruments/instruments.api';
|
||||
import { investmentResourceMeta } from '../investment-resource.mapper';
|
||||
@@ -30,6 +25,7 @@ import {
|
||||
UpcomingEventsDto,
|
||||
UpcomingEventsQueryDto,
|
||||
} from './upcoming-events.dto';
|
||||
import { bondEvent, dividendEvent } from './upcoming-event.mapper';
|
||||
|
||||
enum EventsErrorCode { InvalidPeriod = 'INVALID_EVENTS_PERIOD' }
|
||||
|
||||
@@ -211,51 +207,6 @@ export class UpcomingEventsService {
|
||||
}
|
||||
}
|
||||
|
||||
export function dividendEvent(
|
||||
metadata: Pick<
|
||||
UpcomingEventDto,
|
||||
'displayName' | 'figi' | 'instrumentUid' | 'isin' | 'logoName' | 'ticker'
|
||||
>,
|
||||
quantity: ReturnType<typeof decimal>,
|
||||
event: TbankDividend,
|
||||
): UpcomingEventDto {
|
||||
return {
|
||||
...metadata,
|
||||
type: 'dividend',
|
||||
date: new Date(Number(event.recordDate?.seconds) * MILLISECONDS_PER_SECOND)
|
||||
.toISOString()
|
||||
.slice(ISO_DATE_START, ISO_DATE_LENGTH),
|
||||
dateKind: 'registry',
|
||||
projectedAmount: event.dividendNet
|
||||
? projectedMoney(
|
||||
quantity,
|
||||
formatDecimal(decimal(event.dividendNet)),
|
||||
event.dividendNet.currency,
|
||||
)
|
||||
: null,
|
||||
};
|
||||
}
|
||||
|
||||
export function bondEvent(
|
||||
metadata: Pick<
|
||||
UpcomingEventDto,
|
||||
'displayName' | 'figi' | 'instrumentUid' | 'isin' | 'logoName' | 'ticker'
|
||||
>,
|
||||
quantity: ReturnType<typeof decimal>,
|
||||
event: MoexBondEvent,
|
||||
): UpcomingEventDto {
|
||||
return {
|
||||
...metadata,
|
||||
type: event.type,
|
||||
date: event.date,
|
||||
dateKind: 'event',
|
||||
projectedAmount:
|
||||
'value' in event
|
||||
? projectedMoney(quantity, event.value, event.currency)
|
||||
: null,
|
||||
};
|
||||
}
|
||||
|
||||
function supported(position: Position): boolean {
|
||||
return (
|
||||
!isZero(decimalFromString(position.quantity)) &&
|
||||
@@ -274,19 +225,6 @@ function dateWindow(query: UpcomingEventsQueryDto) {
|
||||
return { from, to };
|
||||
}
|
||||
|
||||
function projectedMoney(
|
||||
quantity: ReturnType<typeof decimal>,
|
||||
value: string,
|
||||
currency: string | undefined,
|
||||
): MoneyDto | null {
|
||||
const normalizedCurrency = currency?.trim().toUpperCase();
|
||||
if (!normalizedCurrency) return null;
|
||||
return {
|
||||
currency: normalizedCurrency,
|
||||
value: formatDecimal(multiply(quantity, decimalFromString(value))),
|
||||
};
|
||||
}
|
||||
|
||||
function incomeTotals(events: UpcomingEventDto[]): MoneyDto[] {
|
||||
const totals = new Map<string, ReturnType<typeof decimal>>();
|
||||
for (const event of events) {
|
||||
|
||||
Reference in New Issue
Block a user