Compare commits
3
Commits
4a17f1fffd
..
v3.0.0
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
40479ac701 | ||
|
|
809936e62d | ||
|
|
85d65f8997 |
@@ -1,5 +1,23 @@
|
||||
# Changelog
|
||||
|
||||
## [3.0.0](https://git.personal.ksv741.ru/WealthLedger/backend/compare/v2.4.1...v3.0.0) (2026-11-11)
|
||||
|
||||
### ⚠ BREAKING CHANGES
|
||||
|
||||
* per-currency API fields replaced with single RUB Money.
|
||||
|
||||
### Features
|
||||
|
||||
* **performance:** investment performance vs Moscow Exchange index (WealthLedger/main[#54](https://git.personal.ksv741.ru/WealthLedger/backend/issues/54)) ([#200](https://git.personal.ksv741.ru/WealthLedger/backend/issues/200)) ([fee6153](https://git.personal.ksv741.ru/WealthLedger/backend/commit/fee61537b612cb5d1d0056e9e1b8044c91180b3b))
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **sync:** start hourly operations after portfolio works finish ([#201](https://git.personal.ksv741.ru/WealthLedger/backend/issues/201)) ([#202](https://git.personal.ksv741.ru/WealthLedger/backend/issues/202)) ([85d65f8](https://git.personal.ksv741.ru/WealthLedger/backend/commit/85d65f899790e9bf303619f3b13e4f04a45baa34))
|
||||
|
||||
### Refactoring
|
||||
|
||||
* support RUB only (WealthLedger/main[#55](https://git.personal.ksv741.ru/WealthLedger/backend/issues/55)) ([#204](https://git.personal.ksv741.ru/WealthLedger/backend/issues/204)) ([809936e](https://git.personal.ksv741.ru/WealthLedger/backend/commit/809936e62df40a5519ba7bebf900b0322e0c285a))
|
||||
|
||||
## [2.4.1](https://git.personal.ksv741.ru/WealthLedger/backend/compare/v2.4.0...v2.4.1) (2026-11-06)
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
Generated
+2
-2
@@ -1,12 +1,12 @@
|
||||
{
|
||||
"name": "wealth-ledger-backend",
|
||||
"version": "2.4.1",
|
||||
"version": "3.0.0",
|
||||
"lockfileVersion": 3,
|
||||
"requires": true,
|
||||
"packages": {
|
||||
"": {
|
||||
"name": "wealth-ledger-backend",
|
||||
"version": "2.4.1",
|
||||
"version": "3.0.0",
|
||||
"license": "UNLICENSED",
|
||||
"dependencies": {
|
||||
"@grpc/grpc-js": "1.14.6",
|
||||
|
||||
+1
-1
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "wealth-ledger-backend",
|
||||
"version": "2.4.1",
|
||||
"version": "3.0.0",
|
||||
"description": "",
|
||||
"author": "",
|
||||
"private": true,
|
||||
|
||||
@@ -244,16 +244,23 @@ export class TbankHourlyScheduler implements OnModuleDestroy, OnModuleInit {
|
||||
dispatchProblems: HourlySection[],
|
||||
walkStartedAt: Date,
|
||||
) {
|
||||
const portfolios: string[] = [];
|
||||
for (const account of accounts) {
|
||||
await this.dispatchPortfolio(
|
||||
userId,
|
||||
revision,
|
||||
account.accountId,
|
||||
dispatch,
|
||||
async (child) => {
|
||||
portfolios.push(child.id);
|
||||
await dispatch(child);
|
||||
},
|
||||
dispatchProblems,
|
||||
walkStartedAt,
|
||||
);
|
||||
}
|
||||
// Operations coverage must end after the Portfolio valuation it explains:
|
||||
// performance requires coverage up to the snapshot fetchedAt.
|
||||
await this.waitWorks(userId, portfolios);
|
||||
for (const account of accounts) {
|
||||
await this.dispatchOperations(
|
||||
userId,
|
||||
|
||||
@@ -167,6 +167,29 @@ describe('hourly attempt lifecycle (SQLite)', () => {
|
||||
expect(read?.state).toBe('succeeded');
|
||||
});
|
||||
|
||||
it('starts operations only after every portfolio work finished', async () => {
|
||||
const portfolios: string[] = [];
|
||||
portfolio.request.mockImplementation(
|
||||
async (_userId: string, _revision: string, accountId: string) => {
|
||||
const row = await child('running', null, `portfolio:${accountId}`);
|
||||
portfolios.push(row.id);
|
||||
return { id: row.id, done: Promise.resolve() };
|
||||
},
|
||||
);
|
||||
const scheduler = createScheduler();
|
||||
await scheduler.tick();
|
||||
await pump();
|
||||
expect(portfolios).toHaveLength(2);
|
||||
expect(operations.request).not.toHaveBeenCalled();
|
||||
await prisma.tbankSyncWork.updateMany({
|
||||
where: { id: { in: portfolios } },
|
||||
data: { state: 'complete' },
|
||||
});
|
||||
const row = await runWalk(scheduler);
|
||||
expect(operations.request).toHaveBeenCalledTimes(2);
|
||||
expect(row.state).toBe('complete');
|
||||
});
|
||||
|
||||
it('settles partial and keeps successful steps when one account fails', async () => {
|
||||
portfolio.request.mockImplementation(
|
||||
async (_userId: string, _revision: string, accountId: string) => {
|
||||
|
||||
Reference in New Issue
Block a user