fix: scope income and ledger sync to requested intervals (WealthLedger/backend#57) (#147)
This commit was merged in pull request #147.
This commit is contained in:
@@ -6,13 +6,11 @@ import { MILLISECONDS_PER_SECOND } from '../../../../common/time';
|
||||
import { isTbankErrorCode, TbankErrorCode } from '../../../../integrations/tbank/tbank-error-code';
|
||||
import { TbankOperationState } from '../../../../integrations/tbank/tbank-protocol';
|
||||
import { TbankAccessService, TbankClient } from '../../../../integrations/tbank/tbank.api';
|
||||
import { accountHistory } from '../../investment-sync-plan';
|
||||
import {
|
||||
type OperationInterval,
|
||||
operationIntervals,
|
||||
operationsSyncPriority,
|
||||
planOperationRead,
|
||||
uncoveredOperationIntervals,
|
||||
} from '../domain/operations-sync-plan';
|
||||
import {
|
||||
BrokerageOperationsRepository,
|
||||
@@ -48,7 +46,6 @@ export class BrokerageOperationsSyncService {
|
||||
intervals: OperationInterval[],
|
||||
options: {
|
||||
force?: boolean;
|
||||
history?: boolean;
|
||||
movingEnd?: boolean;
|
||||
observe?: boolean;
|
||||
revision?: string;
|
||||
@@ -99,30 +96,6 @@ export class BrokerageOperationsSyncService {
|
||||
connection.revision,
|
||||
)
|
||||
: null;
|
||||
if (!options.observe && !options.force && options.history) {
|
||||
const accountIds = new Set(
|
||||
intervals.map((interval) => interval.accountId),
|
||||
);
|
||||
const history = accountHistory(
|
||||
connection.accounts.filter((account) =>
|
||||
accountIds.has(account.accountId),
|
||||
),
|
||||
now,
|
||||
);
|
||||
const missing = planOperationRead(history, coverage, now, {
|
||||
movingEnd: true,
|
||||
}).load;
|
||||
const remaining = uncoveredOperationIntervals(missing, targets);
|
||||
if (remaining.length) {
|
||||
await this.request(
|
||||
userId,
|
||||
remaining,
|
||||
false,
|
||||
'history',
|
||||
connection.revision,
|
||||
);
|
||||
}
|
||||
}
|
||||
return { plan, handle };
|
||||
}
|
||||
|
||||
|
||||
@@ -6,17 +6,12 @@ import {
|
||||
InstrumentMetadataService,
|
||||
metadataKey,
|
||||
TbankAccessService,
|
||||
TbankMembershipService,
|
||||
type TbankOperationItem,
|
||||
tbankSourceTtlMs,
|
||||
} from '../../../../integrations/tbank/tbank.api';
|
||||
import { dateOnlyBounds, DateOnlyRange } from '../../investment-calendar';
|
||||
import { investmentResourceMeta } from '../../investment-resource.mapper';
|
||||
import {
|
||||
accountHistory,
|
||||
ledgerRange,
|
||||
planInvestmentScreen,
|
||||
} from '../../investment-sync-plan';
|
||||
import { accountHistory, ledgerRange } from '../../investment-sync-plan';
|
||||
import {
|
||||
hourlyAttempt,
|
||||
TbankSyncRepository,
|
||||
@@ -37,7 +32,6 @@ import {
|
||||
} from '../presentation/brokerage-operation.dto';
|
||||
import { BrokerageOperationsSyncService } from './brokerage-operations-sync.service';
|
||||
|
||||
const EXCLUSIVE_END_OFFSET_MS = 1;
|
||||
const FIRST_RESULT_OFFSET = 0;
|
||||
const MISSING_MEMBERSHIP_REVISION = 0;
|
||||
const STALE_FRESHNESS_MS = 0;
|
||||
@@ -61,7 +55,6 @@ export class BrokerageOperationsService {
|
||||
private readonly metadata: InstrumentMetadataService,
|
||||
private readonly repository: BrokerageOperationsRepository,
|
||||
private readonly sync: BrokerageOperationsSyncService,
|
||||
private readonly membership: TbankMembershipService,
|
||||
private readonly config: ConfigService,
|
||||
private readonly hourlySync: TbankSyncRepository,
|
||||
) {}
|
||||
@@ -117,35 +110,14 @@ export class BrokerageOperationsService {
|
||||
cursor,
|
||||
};
|
||||
if (cursor) await this.repository.readPage(readInput);
|
||||
const screen = planInvestmentScreen(
|
||||
{
|
||||
screen: 'operations',
|
||||
accountId,
|
||||
from: from.toISOString(),
|
||||
to: new Date(to.valueOf() - EXCLUSIVE_END_OFFSET_MS).toISOString(),
|
||||
},
|
||||
{
|
||||
accounts: selected,
|
||||
instruments: [],
|
||||
membershipKnown: Boolean(connection.membershipAt),
|
||||
},
|
||||
now,
|
||||
);
|
||||
const intervals = screen.sources.flatMap((source) =>
|
||||
source.kind === 'operations' &&
|
||||
source.priority === 'screen' &&
|
||||
source.accountId &&
|
||||
source.from &&
|
||||
source.to
|
||||
? [{ accountId: source.accountId, from: source.from, to: source.to }]
|
||||
: [],
|
||||
const intervals = selected.flatMap((account) =>
|
||||
from < to ? [{ accountId: account.accountId, from, to }] : [],
|
||||
);
|
||||
// The ledger only starts the first-time load of missing intervals; the
|
||||
// mutable tail belongs to the hourly walk and membership is not rechecked.
|
||||
if (intervals.length) {
|
||||
await this.sync.readPlan(userId, intervals, {
|
||||
movingEnd,
|
||||
history: true,
|
||||
revision: connection.revision,
|
||||
});
|
||||
}
|
||||
@@ -406,32 +378,19 @@ export class BrokerageOperationsService {
|
||||
periods: ranges,
|
||||
};
|
||||
let saved = await this.repository.readPage(input);
|
||||
const schedule = async () => {
|
||||
const current = await this.access.local(userId, accountId);
|
||||
if (current.revision !== connection.revision) return;
|
||||
const snapshot = await this.repository.readPage(input);
|
||||
if (!snapshot?.connection.membershipAt) return;
|
||||
const targets = snapshot.connection.accounts.flatMap((account) =>
|
||||
(snapshot.periods ?? []).map((period) => ({
|
||||
if (!observe) {
|
||||
const targets = (saved?.connection.accounts ?? []).flatMap((account) =>
|
||||
(saved?.periods ?? []).map((period) => ({
|
||||
accountId: account.accountId,
|
||||
...period,
|
||||
})),
|
||||
);
|
||||
if (targets.length) {
|
||||
await this.sync.readPlan(userId, targets, {
|
||||
movingEnd: snapshot.periods?.some((period) => period.movingEnd),
|
||||
history: true,
|
||||
movingEnd: saved?.periods?.some((period) => period.movingEnd),
|
||||
revision: connection.revision,
|
||||
});
|
||||
}
|
||||
};
|
||||
if (!observe) {
|
||||
const discovery = await this.membership.request(
|
||||
userId,
|
||||
connection.revision,
|
||||
);
|
||||
if (discovery) void discovery.done.then(schedule).catch(() => undefined);
|
||||
else await schedule();
|
||||
saved = await this.repository.readPage(input);
|
||||
}
|
||||
const now = new Date();
|
||||
|
||||
Reference in New Issue
Block a user