feat: expose logos and ISINs for upcoming events
This commit is contained in:
@@ -23,6 +23,12 @@ export class UpcomingEventDto {
|
|||||||
@ApiProperty()
|
@ApiProperty()
|
||||||
displayName: string;
|
displayName: string;
|
||||||
|
|
||||||
|
@ApiProperty({ type: String, nullable: true })
|
||||||
|
isin: string | null;
|
||||||
|
|
||||||
|
@ApiProperty({ type: String, nullable: true })
|
||||||
|
logoName: string | null;
|
||||||
|
|
||||||
@ApiProperty({ type: MoneyDto, nullable: true })
|
@ApiProperty({ type: MoneyDto, nullable: true })
|
||||||
projectedAmount: MoneyDto | null;
|
projectedAmount: MoneyDto | null;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -62,6 +62,11 @@ describe('UpcomingEventsService', () => {
|
|||||||
)
|
)
|
||||||
.toISOString()
|
.toISOString()
|
||||||
.slice(0, 10);
|
.slice(0, 10);
|
||||||
|
tbank.getInstrumentByFigi.mockResolvedValue({
|
||||||
|
name: 'Бумага',
|
||||||
|
isin: ' RU000A0JX0J2 ',
|
||||||
|
brand: { logoName: ' instrument-logo.png ' },
|
||||||
|
});
|
||||||
tbank.getPortfolio.mockResolvedValue({
|
tbank.getPortfolio.mockResolvedValue({
|
||||||
positions: [
|
positions: [
|
||||||
{
|
{
|
||||||
@@ -99,17 +104,52 @@ describe('UpcomingEventsService', () => {
|
|||||||
type: 'coupon',
|
type: 'coupon',
|
||||||
projectedAmount: { currency: 'RUB', value: '7.5' },
|
projectedAmount: { currency: 'RUB', value: '7.5' },
|
||||||
dateKind: 'event',
|
dateKind: 'event',
|
||||||
|
isin: 'RU000A0JX0J2',
|
||||||
|
logoName: 'instrument-logo.png',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
type: 'dividend',
|
type: 'dividend',
|
||||||
projectedAmount: { currency: 'RUB', value: '2.5' },
|
projectedAmount: { currency: 'RUB', value: '2.5' },
|
||||||
dateKind: 'registry',
|
dateKind: 'registry',
|
||||||
|
isin: 'RU000A0JX0J2',
|
||||||
|
logoName: 'instrument-logo.png',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'offer',
|
||||||
|
projectedAmount: null,
|
||||||
|
isin: 'RU000A0JX0J2',
|
||||||
|
logoName: 'instrument-logo.png',
|
||||||
},
|
},
|
||||||
{ type: 'offer', projectedAmount: null },
|
|
||||||
],
|
],
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it.each([undefined, ' '])(
|
||||||
|
'keeps events without optional metadata when it is %s',
|
||||||
|
async (metadata) => {
|
||||||
|
const today = new Date().toISOString().slice(0, 10);
|
||||||
|
tbank.getPortfolio.mockResolvedValue({
|
||||||
|
positions: [
|
||||||
|
{
|
||||||
|
instrumentUid: 'bond-uid',
|
||||||
|
ticker: 'BOND',
|
||||||
|
instrumentType: 'bond',
|
||||||
|
quantity: { units: 1 },
|
||||||
|
},
|
||||||
|
],
|
||||||
|
});
|
||||||
|
tbank.getInstrumentByUid.mockResolvedValue({
|
||||||
|
name: 'Bond',
|
||||||
|
isin: metadata,
|
||||||
|
brand: { logoName: metadata },
|
||||||
|
});
|
||||||
|
moex.bondEvents.mockResolvedValue([{ type: 'offer', date: today }]);
|
||||||
|
await expect(service.get('user', 'account')).resolves.toMatchObject({
|
||||||
|
events: [{ type: 'offer', isin: null, logoName: null }],
|
||||||
|
});
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
it('does not read upstream data for inaccessible accounts', async () => {
|
it('does not read upstream data for inaccessible accounts', async () => {
|
||||||
access.withAccount.mockRejectedValueOnce(new NotFoundException());
|
access.withAccount.mockRejectedValueOnce(new NotFoundException());
|
||||||
await expect(service.get('user', 'account')).rejects.toEqual(
|
await expect(service.get('user', 'account')).rejects.toEqual(
|
||||||
@@ -145,7 +185,12 @@ describe('UpcomingEventsService', () => {
|
|||||||
|
|
||||||
await expect(service.get('user', 'account')).resolves.toMatchObject({
|
await expect(service.get('user', 'account')).resolves.toMatchObject({
|
||||||
events: [
|
events: [
|
||||||
{ ticker: 'SBER', projectedAmount: { currency: 'RUB', value: '1' } },
|
{
|
||||||
|
ticker: 'SBER',
|
||||||
|
projectedAmount: { currency: 'RUB', value: '1' },
|
||||||
|
isin: null,
|
||||||
|
logoName: null,
|
||||||
|
},
|
||||||
],
|
],
|
||||||
});
|
});
|
||||||
expect(tbank.getInstrumentByFigi).toHaveBeenCalledWith('token', 'S');
|
expect(tbank.getInstrumentByFigi).toHaveBeenCalledWith('token', 'S');
|
||||||
|
|||||||
@@ -108,6 +108,8 @@ export class UpcomingEventsService {
|
|||||||
instrumentUid: position.instrumentUid?.trim() || null,
|
instrumentUid: position.instrumentUid?.trim() || null,
|
||||||
ticker: resolvedTicker,
|
ticker: resolvedTicker,
|
||||||
displayName: instrument?.name?.trim() || resolvedTicker,
|
displayName: instrument?.name?.trim() || resolvedTicker,
|
||||||
|
isin: instrument?.isin?.trim() || null,
|
||||||
|
logoName: instrument?.brand?.logoName?.trim() || null,
|
||||||
};
|
};
|
||||||
const quantity = decimal(position.quantity ?? {});
|
const quantity = decimal(position.quantity ?? {});
|
||||||
if (position.instrumentType?.toLowerCase() === 'share') {
|
if (position.instrumentType?.toLowerCase() === 'share') {
|
||||||
@@ -181,7 +183,7 @@ export class UpcomingEventsService {
|
|||||||
private dividend(
|
private dividend(
|
||||||
metadata: Pick<
|
metadata: Pick<
|
||||||
UpcomingEventDto,
|
UpcomingEventDto,
|
||||||
'figi' | 'instrumentUid' | 'ticker' | 'displayName'
|
'figi' | 'instrumentUid' | 'ticker' | 'displayName' | 'isin' | 'logoName'
|
||||||
>,
|
>,
|
||||||
quantity: ReturnType<typeof decimal>,
|
quantity: ReturnType<typeof decimal>,
|
||||||
event: TbankDividend,
|
event: TbankDividend,
|
||||||
@@ -206,7 +208,7 @@ export class UpcomingEventsService {
|
|||||||
private bond(
|
private bond(
|
||||||
metadata: Pick<
|
metadata: Pick<
|
||||||
UpcomingEventDto,
|
UpcomingEventDto,
|
||||||
'figi' | 'instrumentUid' | 'ticker' | 'displayName'
|
'figi' | 'instrumentUid' | 'ticker' | 'displayName' | 'isin' | 'logoName'
|
||||||
>,
|
>,
|
||||||
quantity: ReturnType<typeof decimal>,
|
quantity: ReturnType<typeof decimal>,
|
||||||
event: MoexBondEvent,
|
event: MoexBondEvent,
|
||||||
|
|||||||
Reference in New Issue
Block a user