feat(portfolio): store and publish instrument sector and issuer (WealthLedger/main#48) (#148)
Backend verify / commits (push) Skipped
Backend verify / security (push) Successful in 1m4s
Backend verify / verify (push) Failing after 7m15s

This commit was merged in pull request #148.
This commit is contained in:
2026-11-01 19:13:32 +03:00
parent 5e84e1e5f1
commit 17432dfee3
16 changed files with 529 additions and 11 deletions
@@ -236,6 +236,16 @@ describe('TbankClient metadata retries', () => {
jest.useRealTimers();
});
it.each([
['bondBy', (client: TbankClient, optIn: boolean) => client.getBond('token', 'uid', undefined, optIn)],
['etfBy', (client: TbankClient, optIn: boolean) => client.getEtf('token', 'uid', undefined, optIn)],
['getAssetBy', (client: TbankClient, optIn: boolean) => optIn ? client.getAssetBrand('token', 'uid') : client.getAssetDescription('token', 'uid')],
])('%s reports NOT_FOUND only for classification lookups', async (_method, invoke) => {
requestRpc.mockRejectedValue({ code: status.NOT_FOUND });
await expect(invoke(client, false)).rejects.toBeInstanceOf(ServiceUnavailableException);
await expect(invoke(client, true)).rejects.toBeInstanceOf(NotFoundException);
});
it.each([
status.UNAVAILABLE,
status.DEADLINE_EXCEEDED,
+24 -5
View File
@@ -375,18 +375,29 @@ export class TbankClient {
).then((response) => response.instruments ?? []);
}
getBond(token: string, uid: string): Promise<null | TbankBond> {
getBond(token: string, uid: string, idType = InstrumentIdType.Uid, notFound = false): Promise<null | TbankBond> {
return this.call<{ instrument?: TbankBond }>(
token,
this.sparseInstruments,
'bondBy',
{
idType: InstrumentIdType.Uid,
idType,
id: uid,
},
notFound,
).then((response) => response.instrument ?? null);
}
getEtf(
token: string,
id: string,
idType = InstrumentIdType.Uid,
notFound = false,
): Promise<null | Pick<TbankShare, 'assetUid' | 'figi' | 'sector' | 'uid'>> {
return this.call<{ instrument?: TbankShare }>(token, this.sparseInstruments, 'etfBy', { idType, id }, notFound)
.then((response) => response.instrument ?? null);
}
getBondCoupons(
token: string,
uid: string,
@@ -405,18 +416,25 @@ export class TbankClient {
).then((response) => response.events ?? []);
}
getShare(token: string, uid: string): Promise<null | TbankShare> {
getShare(token: string, uid: string, idType = InstrumentIdType.Uid, notFound = false): Promise<null | TbankShare> {
return this.call<{ instrument?: TbankShare }>(
token,
this.instruments,
'shareBy',
{
idType: InstrumentIdType.Uid,
idType,
id: uid,
},
notFound,
).then((response) => response.instrument ?? null);
}
getAssetBrand(token: string, assetUid: string): Promise<null | { assetUid?: string; brand?: { name?: string; uid?: string } }> {
return this.call<{ asset?: { brand?: { name?: string; uid?: string }; uid?: string } }>(
token, this.instruments, 'getAssetBy', { id: assetUid }, true,
).then((response) => response.asset ? { assetUid: response.asset.uid, brand: response.asset.brand } : null);
}
getAssetDescription(token: string, assetUid: string): Promise<null | string> {
return this.call<{ asset?: { description?: string } }>(
token,
@@ -514,6 +532,7 @@ export class TbankClient {
client: TbankClientService,
method: string,
request: object,
notFound = false,
): Promise<Response> {
const metadataCall = method === 'getInstrumentBy';
for (let attempts = FIRST_ATTEMPT; attempts <= RPC_MAX_ATTEMPTS; attempts += ATTEMPT_INCREMENT) {
@@ -576,7 +595,7 @@ export class TbankClient {
}
if (
grpcCode === status.NOT_FOUND &&
(method === 'shareBy' || metadataCall)
(notFound || method === 'shareBy' || metadataCall)
) {
throw new NotFoundException();
}