chore: strengthen backend eslint profile
This commit is contained in:
@@ -1,43 +1,45 @@
|
||||
import {
|
||||
Injectable,
|
||||
ConflictException,
|
||||
Injectable,
|
||||
NotFoundException,
|
||||
ServiceUnavailableException,
|
||||
} from '@nestjs/common';
|
||||
import { randomUUID } from 'node:crypto';
|
||||
|
||||
import type { InvestmentResourceMetaDto } from '../investment-resource.dto';
|
||||
|
||||
import {
|
||||
InstrumentMetadataService,
|
||||
TbankAccessService,
|
||||
TbankMembershipService,
|
||||
InstrumentMetadataService,
|
||||
type TbankSyncAttempt,
|
||||
} from '../../../integrations/tbank/tbank.api';
|
||||
import { PortfolioService } from '../portfolio/portfolio.api';
|
||||
import { BrokerageAccountsService } from '../brokerage-accounts/brokerage-accounts-read.api';
|
||||
import { IncomeAnalyticsService } from '../income/income-read.api';
|
||||
import {
|
||||
BrokerageOperationsService,
|
||||
BrokerageOperationsSyncService,
|
||||
type OperationInterval,
|
||||
} from '../operations/operations.api';
|
||||
BondIncomeService,
|
||||
StockIncomeService,
|
||||
} from '../instruments/instrument-income.api';
|
||||
import {
|
||||
CandleService,
|
||||
CatalogDiscoveryService,
|
||||
CatalogEnrichmentService,
|
||||
} from '../instruments/instruments.api';
|
||||
import {
|
||||
StockIncomeService,
|
||||
BondIncomeService,
|
||||
} from '../instruments/instrument-income.api';
|
||||
import { BrokerageAccountsService } from '../brokerage-accounts/brokerage-accounts-read.api';
|
||||
import { IncomeAnalyticsService } from '../income/income-read.api';
|
||||
import { UpcomingEventsService } from '../upcoming-events/upcoming-events-read.api';
|
||||
import { planInvestmentScreen } from '../investment-sync-plan';
|
||||
import type { InvestmentResourceMetaDto } from '../investment-resource.dto';
|
||||
import {
|
||||
TbankSyncRepository,
|
||||
type ScreenIntent,
|
||||
} from './tbank-sync.repository';
|
||||
import { InvestmentScreenDto, TbankSyncStatusDto } from './tbank-sync.dto';
|
||||
import { normalizeScreen } from './tbank-screen';
|
||||
import { investmentResourceMeta } from '../investment-resource.mapper';
|
||||
import { planInvestmentScreen } from '../investment-sync-plan';
|
||||
import {
|
||||
BrokerageOperationsService,
|
||||
BrokerageOperationsSyncService,
|
||||
type OperationInterval,
|
||||
} from '../operations/operations.api';
|
||||
import { PortfolioService } from '../portfolio/portfolio.api';
|
||||
import { UpcomingEventsService } from '../upcoming-events/upcoming-events-read.api';
|
||||
import { normalizeScreen } from './tbank-screen';
|
||||
import { InvestmentScreenDto, TbankSyncStatusDto } from './tbank-sync.dto';
|
||||
import {
|
||||
type ScreenIntent,
|
||||
TbankSyncRepository,
|
||||
} from './tbank-sync.repository';
|
||||
|
||||
@Injectable()
|
||||
export class TbankSyncService {
|
||||
@@ -88,7 +90,7 @@ export class TbankSyncService {
|
||||
|
||||
private async dispatch(attempt: TbankSyncAttempt, intent: ScreenIntent) {
|
||||
const children: string[] = [];
|
||||
const add = async (ids: (string | null | undefined)[]) => {
|
||||
const add = async (ids: (null | string | undefined)[]) => {
|
||||
children.push(...ids.filter((id): id is string => Boolean(id)));
|
||||
await this.repository.progress(attempt, children, false);
|
||||
};
|
||||
@@ -107,14 +109,14 @@ export class TbankSyncService {
|
||||
accountScope === 'all' || account.accountId === accountScope,
|
||||
);
|
||||
if (
|
||||
['accounts', 'account', 'events', 'stock', 'bond'].includes(
|
||||
['account', 'accounts', 'bond', 'events', 'stock'].includes(
|
||||
scope.screen,
|
||||
)
|
||||
) {
|
||||
for (const account of scope.screen === 'stock' ||
|
||||
scope.screen === 'bond'
|
||||
? current.accounts
|
||||
: selectedAccounts) {
|
||||
scope.screen === 'bond' ?
|
||||
current.accounts :
|
||||
selectedAccounts) {
|
||||
const work = await this.portfolio.request(
|
||||
userId,
|
||||
revision,
|
||||
@@ -127,9 +129,9 @@ export class TbankSyncService {
|
||||
}
|
||||
const saved = await this.portfolio.read(
|
||||
userId,
|
||||
scope.screen === 'stock' || scope.screen === 'bond'
|
||||
? 'all'
|
||||
: accountScope,
|
||||
scope.screen === 'stock' || scope.screen === 'bond' ?
|
||||
'all' :
|
||||
accountScope,
|
||||
true,
|
||||
);
|
||||
const positions = saved.data?.positions ?? [];
|
||||
@@ -137,8 +139,8 @@ export class TbankSyncService {
|
||||
...new Map(
|
||||
positions.flatMap((position) =>
|
||||
position.instrumentUid &&
|
||||
(position.type === 'STOCK' || position.type === 'BOND')
|
||||
? [
|
||||
(position.type === 'STOCK' || position.type === 'BOND') ?
|
||||
[
|
||||
[
|
||||
position.instrumentUid,
|
||||
{
|
||||
@@ -147,27 +149,27 @@ export class TbankSyncService {
|
||||
historyFrom: null,
|
||||
},
|
||||
] as const,
|
||||
]
|
||||
: [],
|
||||
] :
|
||||
[],
|
||||
),
|
||||
).values(),
|
||||
];
|
||||
const plan = planInvestmentScreen(
|
||||
{
|
||||
...scope,
|
||||
candleRange: scope.candleRange
|
||||
? {
|
||||
candleRange: scope.candleRange ?
|
||||
{
|
||||
from: new Date(scope.candleRange.from),
|
||||
to: new Date(scope.candleRange.to),
|
||||
}
|
||||
: undefined,
|
||||
} :
|
||||
undefined,
|
||||
},
|
||||
{
|
||||
accounts: selectedAccounts,
|
||||
instruments:
|
||||
scope.screen === 'stocks' || scope.screen === 'bonds'
|
||||
? []
|
||||
: instruments,
|
||||
scope.screen === 'stocks' || scope.screen === 'bonds' ?
|
||||
[] :
|
||||
instruments,
|
||||
membershipKnown: Boolean(current.membershipAt),
|
||||
},
|
||||
now,
|
||||
@@ -177,20 +179,20 @@ export class TbankSyncService {
|
||||
source.kind === 'operations' &&
|
||||
source.accountId &&
|
||||
source.from &&
|
||||
source.to
|
||||
? [
|
||||
source.to ?
|
||||
[
|
||||
{
|
||||
accountId: source.accountId,
|
||||
from: source.from,
|
||||
to: source.to,
|
||||
...(source.instrumentUid
|
||||
? { instrumentUid: source.instrumentUid }
|
||||
: {}),
|
||||
...(source.instrumentUid ?
|
||||
{ instrumentUid: source.instrumentUid } :
|
||||
{}),
|
||||
},
|
||||
]
|
||||
: [],
|
||||
] :
|
||||
[],
|
||||
);
|
||||
if (intervals.length)
|
||||
if (intervals.length) {
|
||||
await add([
|
||||
await this.operations.request(
|
||||
userId,
|
||||
@@ -200,24 +202,27 @@ export class TbankSyncService {
|
||||
revision,
|
||||
),
|
||||
]);
|
||||
}
|
||||
for (const source of plan.sources) {
|
||||
const uid = source.instrumentUid;
|
||||
const type = source.instrumentType === 'BOND' ? 'bond' : 'share';
|
||||
if (source.kind === 'catalog')
|
||||
if (source.kind === 'catalog') {
|
||||
await add(
|
||||
await this.discovery.refresh(userId, revision, {
|
||||
instrumentType: type,
|
||||
query: source.query ?? '',
|
||||
}),
|
||||
);
|
||||
}
|
||||
if (!uid) continue;
|
||||
if (source.kind === 'metadata')
|
||||
if (source.kind === 'metadata') {
|
||||
await add([
|
||||
await this.metadata.request(userId, revision, {
|
||||
instrumentUid: uid,
|
||||
}),
|
||||
]);
|
||||
if (source.kind === 'quote')
|
||||
}
|
||||
if (source.kind === 'quote') {
|
||||
await add(
|
||||
await this.sources.requestMany(
|
||||
userId,
|
||||
@@ -233,7 +238,8 @@ export class TbankSyncService {
|
||||
],
|
||||
),
|
||||
);
|
||||
if (source.kind === 'company')
|
||||
}
|
||||
if (source.kind === 'company') {
|
||||
await add(
|
||||
await this.sources.requestMany(
|
||||
userId,
|
||||
@@ -244,7 +250,8 @@ export class TbankSyncService {
|
||||
['description', 'fundamentals'],
|
||||
),
|
||||
);
|
||||
if (source.kind === 'metrics')
|
||||
}
|
||||
if (source.kind === 'metrics') {
|
||||
await add(
|
||||
await this.sources.requestMany(
|
||||
userId,
|
||||
@@ -255,7 +262,8 @@ export class TbankSyncService {
|
||||
['coupons', 'yield', 'rating'],
|
||||
),
|
||||
);
|
||||
if (source.kind === 'calendar' && source.from && source.to)
|
||||
}
|
||||
if (source.kind === 'calendar' && source.from && source.to) {
|
||||
await add(
|
||||
await this.sources.requestMany(
|
||||
userId,
|
||||
@@ -264,11 +272,11 @@ export class TbankSyncService {
|
||||
[uid],
|
||||
true,
|
||||
[
|
||||
type === 'share'
|
||||
? 'dividends'
|
||||
: scope.screen === 'bond'
|
||||
? 'coupons'
|
||||
: 'bond-events',
|
||||
type === 'share' ?
|
||||
'dividends' :
|
||||
scope.screen === 'bond' ?
|
||||
'coupons' :
|
||||
'bond-events',
|
||||
],
|
||||
{
|
||||
from: source.from.toISOString().slice(0, 10),
|
||||
@@ -279,6 +287,7 @@ export class TbankSyncService {
|
||||
},
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
if (
|
||||
(scope.screen === 'stock' || scope.screen === 'bond') &&
|
||||
@@ -292,14 +301,14 @@ export class TbankSyncService {
|
||||
uid: scope.instrumentUid,
|
||||
instrumentType: scope.screen === 'bond' ? 'bond' : 'share',
|
||||
period: scope.candlePeriod ?? 'month',
|
||||
...(scope.candleRange
|
||||
? {
|
||||
...(scope.candleRange ?
|
||||
{
|
||||
range: {
|
||||
from: new Date(scope.candleRange.from),
|
||||
to: new Date(scope.candleRange.to),
|
||||
},
|
||||
}
|
||||
: {}),
|
||||
} :
|
||||
{}),
|
||||
},
|
||||
now,
|
||||
true,
|
||||
@@ -324,15 +333,16 @@ export class TbankSyncService {
|
||||
});
|
||||
const saved = await this.repository.read(userId, connection.revision, id);
|
||||
if (!saved) throw new NotFoundException();
|
||||
if (!saved.work.scopeKey.startsWith('screen:'))
|
||||
if (!saved.work.scopeKey.startsWith('screen:')) {
|
||||
return this.sourceStatus(userId, saved.work);
|
||||
}
|
||||
const intent = saved.work.intent as unknown as ScreenIntent;
|
||||
await this.access.local(userId, intent.scope.accountId);
|
||||
const children = await Promise.all(
|
||||
saved.children.map((child) =>
|
||||
child.state === 'superseded'
|
||||
? this.operations.observe(userId, child.id)
|
||||
: Promise.resolve(child),
|
||||
child.state === 'superseded' ?
|
||||
this.operations.observe(userId, child.id) :
|
||||
Promise.resolve(child),
|
||||
),
|
||||
);
|
||||
const running = children.some((child) => child.state === 'running');
|
||||
@@ -342,21 +352,22 @@ export class TbankSyncService {
|
||||
null;
|
||||
const state =
|
||||
saved.work.processRunId !== this.runId &&
|
||||
(!saved.progress.dispatched || running)
|
||||
? 'cancelled'
|
||||
: !saved.progress.dispatched || running
|
||||
? 'running'
|
||||
: failed
|
||||
? 'failed'
|
||||
: children.some((child) => child.state === 'cancelled')
|
||||
? 'cancelled'
|
||||
: 'succeeded';
|
||||
(!saved.progress.dispatched || running) ?
|
||||
'cancelled' :
|
||||
!saved.progress.dispatched || running ?
|
||||
'running' :
|
||||
failed ?
|
||||
'failed' :
|
||||
children.some((child) => child.state === 'cancelled') ?
|
||||
'cancelled' :
|
||||
'succeeded';
|
||||
const resources = await this.observe(userId, intent.scope);
|
||||
if (
|
||||
(await this.access.local(userId, intent.scope.accountId)).revision !==
|
||||
connection.revision
|
||||
)
|
||||
) {
|
||||
throw new NotFoundException();
|
||||
}
|
||||
return {
|
||||
id,
|
||||
...intent,
|
||||
@@ -380,16 +391,16 @@ export class TbankSyncService {
|
||||
const add = async (read: Promise<{ meta: InvestmentResourceMetaDto }>) => {
|
||||
resources.push((await read).meta);
|
||||
};
|
||||
if (work.scopeKey === 'membership')
|
||||
if (work.scopeKey === 'membership') {
|
||||
await add(this.accounts.list(userId, true));
|
||||
else if (
|
||||
} else if (
|
||||
input.source === 'portfolio' &&
|
||||
typeof input.accountId === 'string'
|
||||
)
|
||||
) {
|
||||
await add(this.portfolio.read(userId, input.accountId, true));
|
||||
else if (input.source === 'catalog') {
|
||||
} else if (input.source === 'catalog') {
|
||||
const type = input.instrumentType === 'bond' ? 'bond' : 'share';
|
||||
if (typeof input.query === 'string')
|
||||
if (typeof input.query === 'string') {
|
||||
await add(
|
||||
this.discovery.search(
|
||||
userId,
|
||||
@@ -401,14 +412,14 @@ export class TbankSyncService {
|
||||
true,
|
||||
),
|
||||
);
|
||||
else if (
|
||||
} else if (
|
||||
typeof input.uid === 'string' &&
|
||||
typeof input.kind === 'string'
|
||||
) {
|
||||
const range =
|
||||
typeof input.rangeKey === 'string' && input.rangeKey.startsWith('[')
|
||||
? (JSON.parse(input.rangeKey) as string[])
|
||||
: null;
|
||||
typeof input.rangeKey === 'string' && input.rangeKey.startsWith('[') ?
|
||||
(JSON.parse(input.rangeKey) as string[]) :
|
||||
null;
|
||||
const sources = await this.sources.readMany(
|
||||
userId,
|
||||
type,
|
||||
@@ -417,9 +428,9 @@ export class TbankSyncService {
|
||||
[
|
||||
input.kind as Parameters<
|
||||
CatalogEnrichmentService['readMany']
|
||||
>[4] extends (infer K)[] | undefined
|
||||
? K
|
||||
: never,
|
||||
>[4] extends (infer K)[] | undefined ?
|
||||
K :
|
||||
never,
|
||||
],
|
||||
range ? { from: range[0], to: range[1] } : undefined,
|
||||
);
|
||||
@@ -452,7 +463,7 @@ export class TbankSyncService {
|
||||
{
|
||||
uid: input.uid,
|
||||
instrumentType: input.instrumentType === 'bond' ? 'bond' : 'share',
|
||||
period: input.period as 'month' | 'halfYear' | 'year' | 'all',
|
||||
period: input.period as 'all' | 'halfYear' | 'month' | 'year',
|
||||
},
|
||||
true,
|
||||
),
|
||||
@@ -475,21 +486,22 @@ export class TbankSyncService {
|
||||
);
|
||||
}
|
||||
}
|
||||
const observed = work.scopeKey.startsWith('operations:')
|
||||
? await this.operations.observe(userId, work.id)
|
||||
: work;
|
||||
const observed = work.scopeKey.startsWith('operations:') ?
|
||||
await this.operations.observe(userId, work.id) :
|
||||
work;
|
||||
const state =
|
||||
observed.state === 'running'
|
||||
? observed.updatedAt < this.startedAt
|
||||
? 'cancelled'
|
||||
: 'running'
|
||||
: observed.state === 'failed'
|
||||
? 'failed'
|
||||
: observed.state === 'cancelled'
|
||||
? 'cancelled'
|
||||
: 'succeeded';
|
||||
if ((await this.access.local(userId)).revision !== work.revision)
|
||||
observed.state === 'running' ?
|
||||
observed.updatedAt < this.startedAt ?
|
||||
'cancelled' :
|
||||
'running' :
|
||||
observed.state === 'failed' ?
|
||||
'failed' :
|
||||
observed.state === 'cancelled' ?
|
||||
'cancelled' :
|
||||
'succeeded';
|
||||
if ((await this.access.local(userId)).revision !== work.revision) {
|
||||
throw new NotFoundException();
|
||||
}
|
||||
return {
|
||||
id: work.id,
|
||||
scope: null,
|
||||
@@ -511,14 +523,15 @@ export class TbankSyncService {
|
||||
resources.push((await read).meta);
|
||||
};
|
||||
const account = scope.accountId ?? 'all';
|
||||
if (scope.screen === 'accounts')
|
||||
if (scope.screen === 'accounts') {
|
||||
await add(this.accounts.list(userId, true));
|
||||
}
|
||||
if (scope.screen === 'account') {
|
||||
await add(this.portfolio.read(userId, account, true));
|
||||
await add(this.income.summary(userId, account, true));
|
||||
await add(this.events.get(userId, account, { sync: 'observe' }));
|
||||
}
|
||||
if (['account', 'operations', 'stock', 'bond'].includes(scope.screen))
|
||||
if (['account', 'bond', 'operations', 'stock'].includes(scope.screen)) {
|
||||
await add(
|
||||
this.ledger.read(userId, account, {
|
||||
from: scope.from,
|
||||
@@ -529,11 +542,13 @@ export class TbankSyncService {
|
||||
sync: 'observe',
|
||||
}),
|
||||
);
|
||||
if (scope.screen === 'income')
|
||||
}
|
||||
if (scope.screen === 'income') {
|
||||
await add(
|
||||
this.income.analytics(userId, account, scope.from, scope.to, true),
|
||||
);
|
||||
if (scope.screen === 'events')
|
||||
}
|
||||
if (scope.screen === 'events') {
|
||||
await add(
|
||||
this.events.get(userId, account, {
|
||||
from: scope.from,
|
||||
@@ -541,9 +556,10 @@ export class TbankSyncService {
|
||||
sync: 'observe',
|
||||
}),
|
||||
);
|
||||
}
|
||||
const type =
|
||||
scope.screen === 'bond' || scope.screen === 'bonds' ? 'bond' : 'share';
|
||||
if (scope.screen === 'stocks' || scope.screen === 'bonds')
|
||||
if (scope.screen === 'stocks' || scope.screen === 'bonds') {
|
||||
await add(
|
||||
this.discovery.search(
|
||||
userId,
|
||||
@@ -551,6 +567,7 @@ export class TbankSyncService {
|
||||
true,
|
||||
),
|
||||
);
|
||||
}
|
||||
if (
|
||||
(scope.screen === 'stock' || scope.screen === 'bond') &&
|
||||
scope.instrumentUid
|
||||
@@ -574,27 +591,27 @@ export class TbankSyncService {
|
||||
uid,
|
||||
instrumentType: type,
|
||||
period: scope.candlePeriod ?? 'month',
|
||||
...(scope.candleRange
|
||||
? {
|
||||
...(scope.candleRange ?
|
||||
{
|
||||
range: {
|
||||
from: new Date(scope.candleRange.from),
|
||||
to: new Date(scope.candleRange.to),
|
||||
},
|
||||
}
|
||||
: {}),
|
||||
} :
|
||||
{}),
|
||||
},
|
||||
true,
|
||||
),
|
||||
);
|
||||
await add(
|
||||
type === 'share'
|
||||
? this.stockIncome.readPosition(userId, uid, true)
|
||||
: this.bondIncome.readPosition(userId, uid, true),
|
||||
type === 'share' ?
|
||||
this.stockIncome.readPosition(userId, uid, true) :
|
||||
this.bondIncome.readPosition(userId, uid, true),
|
||||
);
|
||||
await add(
|
||||
type === 'share'
|
||||
? this.stockIncome.dividends(userId, uid, true)
|
||||
: this.bondIncome.coupons(userId, uid, true),
|
||||
type === 'share' ?
|
||||
this.stockIncome.dividends(userId, uid, true) :
|
||||
this.bondIncome.coupons(userId, uid, true),
|
||||
);
|
||||
}
|
||||
return resources;
|
||||
|
||||
Reference in New Issue
Block a user