refactor: organize backend by business responsibility
This commit is contained in:
@@ -0,0 +1,94 @@
|
||||
import { Injectable } from '@nestjs/common';
|
||||
import type { TbankFundamentals } from '../../../../../integrations/tbank/tbank.api';
|
||||
import { TbankClient } from '../../../../../integrations/tbank/tbank.api';
|
||||
import { optional } from '../../application/instrument-market';
|
||||
import { StockCompanyDto, StockMetricDto } from '../presentation/stock.dto';
|
||||
|
||||
import { StockCatalogService } from './stock-catalog.service';
|
||||
@Injectable()
|
||||
export class GetStockCompanyUseCase {
|
||||
constructor(
|
||||
private readonly catalog: StockCatalogService,
|
||||
private readonly tbank: TbankClient,
|
||||
) {}
|
||||
execute(userId: string, uid: string): Promise<StockCompanyDto> {
|
||||
return this.catalog.cached(userId, `company:${uid}`, async (token) => {
|
||||
const share = await this.catalog.share(token, uid);
|
||||
const unavailable: string[] = [];
|
||||
const assetUid = share.assetUid;
|
||||
if (!assetUid)
|
||||
return {
|
||||
description: null,
|
||||
metrics: [],
|
||||
unavailable,
|
||||
observedAt: new Date().toISOString(),
|
||||
};
|
||||
const [description, fundamentals] = await Promise.all([
|
||||
optional(
|
||||
() => this.tbank.getAssetDescription(token, assetUid),
|
||||
'description',
|
||||
unavailable,
|
||||
),
|
||||
optional(
|
||||
() => this.tbank.getFundamentals(token, assetUid),
|
||||
'fundamentals',
|
||||
unavailable,
|
||||
),
|
||||
]);
|
||||
return {
|
||||
description,
|
||||
metrics: metrics(fundamentals, share.sector),
|
||||
unavailable,
|
||||
observedAt: new Date().toISOString(),
|
||||
};
|
||||
});
|
||||
}
|
||||
}
|
||||
function metrics(
|
||||
values: TbankFundamentals | null,
|
||||
sector?: string,
|
||||
): StockMetricDto[] {
|
||||
if (!values) return [];
|
||||
const bank = sector?.toLowerCase() === 'financial';
|
||||
const selection: [
|
||||
keyof TbankFundamentals,
|
||||
StockMetricDto['unit'],
|
||||
StockMetricDto['period'],
|
||||
][] = [
|
||||
['marketCapitalization', 'money', null],
|
||||
['peRatioTtm', 'ratio', 'TTM'],
|
||||
...(bank
|
||||
? ([
|
||||
['priceToBookTtm', 'ratio', 'TTM'],
|
||||
['roe', 'percent', null],
|
||||
] as typeof selection)
|
||||
: ([
|
||||
['revenueTtm', 'money', 'TTM'],
|
||||
['ebitdaTtm', 'money', 'TTM'],
|
||||
] as typeof selection)),
|
||||
['netIncomeTtm', 'money', 'TTM'],
|
||||
...(!bank
|
||||
? ([
|
||||
['totalDebtMrq', 'money', 'MRQ'],
|
||||
['netDebtToEbitda', 'ratio', null],
|
||||
] as typeof selection)
|
||||
: []),
|
||||
];
|
||||
return selection.flatMap(([key, unit, period]) => {
|
||||
const value = values[key];
|
||||
const currency = values.currency?.toUpperCase() || null;
|
||||
return typeof value === 'number' &&
|
||||
Number.isFinite(value) &&
|
||||
(unit !== 'money' || currency)
|
||||
? [
|
||||
{
|
||||
key,
|
||||
value,
|
||||
unit,
|
||||
period,
|
||||
currency: unit === 'money' ? currency : null,
|
||||
},
|
||||
]
|
||||
: [];
|
||||
});
|
||||
}
|
||||
Reference in New Issue
Block a user