moex-vibe/apps/backend/src/modules/tbank/mappers/operation.mapper.ts

140 lines
4.2 KiB
TypeScript

import type {
BrokerOperation,
BrokerOperationCategory,
BrokerOperationsPage,
} from '../types/broker.types';
import type {
TBankOperationItem,
TBankOperationsByCursorResponse,
} from '../types/tbank-proto.types';
import { mapInteger, mapMoneyValue, mapTimestampToIso } from './money.mapper';
const TRADE_TYPES = new Set([
'OPERATION_TYPE_BUY',
'OPERATION_TYPE_BUY_CARD',
'OPERATION_TYPE_SELL',
'OPERATION_TYPE_SELL_CARD',
'OPERATION_TYPE_BUY_MARGIN',
'OPERATION_TYPE_SELL_MARGIN',
'OPERATION_TYPE_DELIVERY_BUY',
'OPERATION_TYPE_DELIVERY_SELL',
]);
const INCOME_TYPES = new Set([
'OPERATION_TYPE_DIVIDEND',
'OPERATION_TYPE_COUPON',
'OPERATION_TYPE_BOND_REPAYMENT',
'OPERATION_TYPE_BOND_REPAYMENT_FULL',
'OPERATION_TYPE_OVERNIGHT',
'OPERATION_TYPE_OVER_INCOME',
'OPERATION_TYPE_ACCRUING_VARMARGIN',
'OPERATION_TYPE_TAX_REPO_REFUND',
'OPERATION_TYPE_TAX_REPO_REFUND_PROGRESSIVE',
'OPERATION_TYPE_DIV_EXT',
'OPERATION_TYPE_DFA_REDEMPTION',
]);
const TAX_TYPES = new Set([
'OPERATION_TYPE_TAX',
'OPERATION_TYPE_BOND_TAX',
'OPERATION_TYPE_DIVIDEND_TAX',
'OPERATION_TYPE_TAX_CORRECTION',
'OPERATION_TYPE_BENEFIT_TAX',
'OPERATION_TYPE_TAX_PROGRESSIVE',
'OPERATION_TYPE_BOND_TAX_PROGRESSIVE',
'OPERATION_TYPE_DIVIDEND_TAX_PROGRESSIVE',
'OPERATION_TYPE_BENEFIT_TAX_PROGRESSIVE',
'OPERATION_TYPE_TAX_CORRECTION_PROGRESSIVE',
'OPERATION_TYPE_TAX_REPO',
'OPERATION_TYPE_TAX_REPO_PROGRESSIVE',
'OPERATION_TYPE_TAX_REPO_HOLD',
'OPERATION_TYPE_TAX_REPO_HOLD_PROGRESSIVE',
'OPERATION_TYPE_TAX_CORRECTION_COUPON',
]);
const FEE_TYPES = new Set([
'OPERATION_TYPE_SERVICE_FEE',
'OPERATION_TYPE_MARGIN_FEE',
'OPERATION_TYPE_BROKER_FEE',
'OPERATION_TYPE_SUCCESS_FEE',
'OPERATION_TYPE_TRACK_MFEE',
'OPERATION_TYPE_TRACK_PFEE',
'OPERATION_TYPE_CASH_FEE',
'OPERATION_TYPE_OUT_FEE',
'OPERATION_TYPE_OUT_STAMP_DUTY',
'OPERATION_TYPE_OUTPUT_PENALTY',
'OPERATION_TYPE_ADVICE_FEE',
'OPERATION_TYPE_OVER_COM',
'OPERATION_TYPE_OTHER_FEE',
'OPERATION_TYPE_FUNDING',
]);
const TRANSFER_TYPES = new Set([
'OPERATION_TYPE_INPUT',
'OPERATION_TYPE_OUTPUT',
'OPERATION_TYPE_INPUT_SECURITIES',
'OPERATION_TYPE_OUTPUT_SECURITIES',
'OPERATION_TYPE_OUTPUT_SWIFT',
'OPERATION_TYPE_INPUT_SWIFT',
'OPERATION_TYPE_OUTPUT_ACQUIRING',
'OPERATION_TYPE_INPUT_ACQUIRING',
'OPERATION_TYPE_TRANS_IIS_BS',
'OPERATION_TYPE_TRANS_BS_BS',
'OPERATION_TYPE_OUT_MULTI',
'OPERATION_TYPE_INP_MULTI',
'OPERATION_TYPE_OVER_PLACEMENT',
]);
export function categorizeOperationType(type: string | null | undefined): BrokerOperationCategory {
if (!type) return 'other';
if (TRADE_TYPES.has(type)) return 'trade';
if (INCOME_TYPES.has(type)) return 'income';
if (TAX_TYPES.has(type)) return 'tax';
if (FEE_TYPES.has(type)) return 'fee';
if (TRANSFER_TYPES.has(type)) return 'transfer';
return 'other';
}
export function mapOperation(item: TBankOperationItem, accountId: string): BrokerOperation {
const type = item.type || 'OPERATION_TYPE_UNSPECIFIED';
return {
cursor: item.cursor ?? null,
accountId: item.brokerAccountId || accountId,
id: item.id ?? null,
parentOperationId: item.parentOperationId ?? null,
date: mapTimestampToIso(item.date),
type,
category: categorizeOperationType(type),
description: item.description || item.name || null,
name: item.name ?? null,
state: item.state ?? null,
instrumentUid: item.instrumentUid ?? null,
figi: item.figi ?? null,
ticker: item.ticker ?? null,
classCode: item.classCode ?? null,
instrumentType: item.instrumentType ?? null,
payment: mapMoneyValue(item.payment),
price: mapMoneyValue(item.price),
commission: mapMoneyValue(item.commission),
yield: mapMoneyValue(item.yield),
accruedInt: mapMoneyValue(item.accruedInt),
quantity: mapInteger(item.quantity),
quantityDone: mapInteger(item.quantityDone),
};
}
export function mapOperationsPage(
accountId: string,
response: TBankOperationsByCursorResponse,
): BrokerOperationsPage {
return {
accountId,
items: (response.items ?? []).map((item) => mapOperation(item, accountId)),
nextCursor: response.nextCursor || null,
hasNext: response.hasNext ?? false,
asOf: new Date().toISOString(),
};
}