refactor!: support RUB only (WealthLedger/main#55)
Filter non-RUB data at ingest, collapse per-currency collections into single RUB Money, drop currency from TbankPortfolioValuePoint, remove NON_RUB_ACTIVITY and screener currency filter. BREAKING CHANGE: per-currency API fields replaced with single RUB Money; stock screener currency param removed.
This commit is contained in:
@@ -80,7 +80,7 @@ describe('T-Bank value history persistence and visibility (SQLite)', () => {
|
||||
],
|
||||
});
|
||||
upstream.getPositions.mockResolvedValue({
|
||||
money: [{ units: '5', currency: 'usd' }],
|
||||
money: [{ units: '5', currency: 'rub' }],
|
||||
});
|
||||
});
|
||||
|
||||
@@ -123,7 +123,7 @@ describe('T-Bank value history persistence and visibility (SQLite)', () => {
|
||||
}
|
||||
|
||||
describe('1.1 Point persistence', () => {
|
||||
it('writes points for fully valued snapshot with two currencies', async () => {
|
||||
it('writes a single RUB point for a fully valued snapshot', async () => {
|
||||
await createUser('owner');
|
||||
await putConnection('owner', 'token-a').expect(200);
|
||||
await publishPortfolio('owner', 'a');
|
||||
@@ -133,12 +133,10 @@ describe('T-Bank value history persistence and visibility (SQLite)', () => {
|
||||
include: { points: true },
|
||||
});
|
||||
expect(history?.deletedAt).toBeNull();
|
||||
expect(history?.points).toHaveLength(2);
|
||||
expect(history?.points).toHaveLength(1);
|
||||
|
||||
const rubPoint = history?.points.find((p) => p.currency === 'RUB');
|
||||
const usdPoint = history?.points.find((p) => p.currency === 'USD');
|
||||
expect(rubPoint?.value).toBe('21');
|
||||
expect(usdPoint?.value).toBe('5');
|
||||
const rubPoint = history?.points[0];
|
||||
expect(rubPoint?.value).toBe('26');
|
||||
|
||||
const snapshot = await prisma.tbankPortfolio.findUniqueOrThrow({
|
||||
where: {
|
||||
@@ -201,7 +199,7 @@ describe('T-Bank value history persistence and visibility (SQLite)', () => {
|
||||
expect(points).toHaveLength(0);
|
||||
});
|
||||
|
||||
it('writes no points for empty account without currency', async () => {
|
||||
it('writes a zero point for an empty fully valued account', async () => {
|
||||
upstream.getPortfolio.mockResolvedValue({ positions: [] });
|
||||
upstream.getPositions.mockResolvedValue({ money: [] });
|
||||
|
||||
@@ -212,7 +210,8 @@ describe('T-Bank value history persistence and visibility (SQLite)', () => {
|
||||
const points = await prisma.tbankPortfolioValuePoint.findMany({
|
||||
where: { userId: 'owner', accountId: 'a' },
|
||||
});
|
||||
expect(points).toHaveLength(0);
|
||||
expect(points).toHaveLength(1);
|
||||
expect(points[0].value).toBe('0');
|
||||
});
|
||||
|
||||
it('deduplicates repeated publication of same attempt', async () => {
|
||||
@@ -258,7 +257,7 @@ describe('T-Bank value history persistence and visibility (SQLite)', () => {
|
||||
const points = await prisma.tbankPortfolioValuePoint.findMany({
|
||||
where: { userId: 'owner', accountId: 'a' },
|
||||
});
|
||||
expect(points).toHaveLength(2);
|
||||
expect(points).toHaveLength(1);
|
||||
});
|
||||
|
||||
it('late attempt after token replacement adds no points', async () => {
|
||||
@@ -282,10 +281,7 @@ describe('T-Bank value history persistence and visibility (SQLite)', () => {
|
||||
const published = {
|
||||
lastSuccessfulAt: new Date().toISOString(),
|
||||
isStale: false,
|
||||
totalsByCurrency: [
|
||||
{ currency: 'RUB', value: '100' },
|
||||
{ currency: 'USD', value: '50' },
|
||||
],
|
||||
totals: { currency: 'RUB', value: '100' },
|
||||
positions: [
|
||||
{
|
||||
figi: 'stock',
|
||||
@@ -302,8 +298,8 @@ describe('T-Bank value history persistence and visibility (SQLite)', () => {
|
||||
issuer: null,
|
||||
},
|
||||
],
|
||||
cashBalances: [{ currency: 'USD', value: '50' }],
|
||||
structure: { currencies: [], unvaluedCategories: [] },
|
||||
cash: { currency: 'RUB', value: '0' },
|
||||
structure: { totalValue: '100', hasNegativeValues: false, categories: [], unvaluedCategories: [] },
|
||||
};
|
||||
|
||||
const result = await app.get(PortfolioService)['repository'].publish(oldWork, 'a', published);
|
||||
@@ -323,7 +319,7 @@ describe('T-Bank value history persistence and visibility (SQLite)', () => {
|
||||
const pointsBefore = await prisma.tbankPortfolioValuePoint.findMany({
|
||||
where: { userId: 'owner', accountId: 'a' },
|
||||
});
|
||||
expect(pointsBefore).toHaveLength(2);
|
||||
expect(pointsBefore).toHaveLength(1);
|
||||
|
||||
upstream.getPortfolio.mockRejectedValue(new Error('Upstream failed'));
|
||||
await publishPortfolio('owner', 'a');
|
||||
@@ -331,7 +327,7 @@ describe('T-Bank value history persistence and visibility (SQLite)', () => {
|
||||
const pointsAfter = await prisma.tbankPortfolioValuePoint.findMany({
|
||||
where: { userId: 'owner', accountId: 'a' },
|
||||
});
|
||||
expect(pointsAfter).toHaveLength(2);
|
||||
expect(pointsAfter).toHaveLength(1);
|
||||
expect(pointsAfter).toEqual(pointsBefore);
|
||||
});
|
||||
});
|
||||
@@ -345,7 +341,7 @@ describe('T-Bank value history persistence and visibility (SQLite)', () => {
|
||||
const oldPoints = await prisma.tbankPortfolioValuePoint.findMany({
|
||||
where: { userId: 'owner', accountId: 'a' },
|
||||
});
|
||||
expect(oldPoints).toHaveLength(2);
|
||||
expect(oldPoints).toHaveLength(1);
|
||||
|
||||
upstream.validateToken.mockResolvedValue([accounts[0]]);
|
||||
await putConnection('owner', 'token-b').expect(200);
|
||||
@@ -361,8 +357,8 @@ describe('T-Bank value history persistence and visibility (SQLite)', () => {
|
||||
where: { userId: 'owner', accountId: 'a' },
|
||||
orderBy: { createdAt: 'asc' },
|
||||
});
|
||||
expect(newPoints.length).toBeGreaterThan(2);
|
||||
expect(newPoints.slice(0, 2)).toEqual(oldPoints);
|
||||
expect(newPoints.length).toBeGreaterThan(1);
|
||||
expect(newPoints.slice(0, 1)).toEqual(oldPoints);
|
||||
});
|
||||
|
||||
it('hides history when account disappears from membership', async () => {
|
||||
@@ -392,7 +388,7 @@ describe('T-Bank value history persistence and visibility (SQLite)', () => {
|
||||
const pointsB = await prisma.tbankPortfolioValuePoint.findMany({
|
||||
where: { userId: 'owner', accountId: 'b' },
|
||||
});
|
||||
expect(pointsB).toHaveLength(2);
|
||||
expect(pointsB).toHaveLength(1);
|
||||
});
|
||||
|
||||
it('leaves visibility unchanged on membership fetch error', async () => {
|
||||
@@ -424,7 +420,7 @@ describe('T-Bank value history persistence and visibility (SQLite)', () => {
|
||||
const points = await prisma.tbankPortfolioValuePoint.findMany({
|
||||
where: { userId: 'owner', accountId: 'a' },
|
||||
});
|
||||
expect(points).toHaveLength(2);
|
||||
expect(points).toHaveLength(1);
|
||||
|
||||
await request(app.getHttpServer())
|
||||
.delete('/api/v1/tbank-connection')
|
||||
@@ -450,7 +446,7 @@ describe('T-Bank value history persistence and visibility (SQLite)', () => {
|
||||
const pointsAfter = await prisma.tbankPortfolioValuePoint.findMany({
|
||||
where: { userId: 'owner', accountId: 'a' },
|
||||
});
|
||||
expect(pointsAfter.length).toBeGreaterThan(2);
|
||||
expect(pointsAfter.length).toBeGreaterThan(1);
|
||||
});
|
||||
|
||||
it('unhides when disappeared account returns in membership', async () => {
|
||||
@@ -530,7 +526,7 @@ describe('T-Bank value history persistence and visibility (SQLite)', () => {
|
||||
const points = await prisma.tbankPortfolioValuePoint.findMany({
|
||||
where: { userId: 'owner', accountId: 'a' },
|
||||
});
|
||||
expect(points).toHaveLength(2);
|
||||
expect(points).toHaveLength(1);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user