perf(income): compute Moscow dates once
Backend verify / commits (pull_request) Successful in 30s
Backend verify / security (pull_request) Successful in 12s
Backend verify / verify (pull_request) Successful in 9m53s
Backend verify / commits (push) Skipped
Backend verify / security (push) Successful in 9s
Backend verify / verify (push) Failing after 10m3s
Backend verify / commits (pull_request) Successful in 30s
Backend verify / security (pull_request) Successful in 12s
Backend verify / verify (pull_request) Successful in 9m53s
Backend verify / commits (push) Skipped
Backend verify / security (push) Successful in 9s
Backend verify / verify (push) Failing after 10m3s
This commit was merged in pull request #43.
This commit is contained in:
@@ -189,6 +189,49 @@ describe('IncomeAnalyticsService', () => {
|
|||||||
).toEqual(['10.25', '-0.25']);
|
).toEqual(['10.25', '-0.25']);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('assigns signed payments to Moscow days and retains empty buckets', async () => {
|
||||||
|
seed([
|
||||||
|
{
|
||||||
|
...entry('before', 'OPERATION_TYPE_COUPON', '0.1', 'RUB'),
|
||||||
|
occurredAt: '2026-01-14T20:59:59.999Z',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
...entry('after', 'OPERATION_TYPE_COUPON', '0.2', 'RUB'),
|
||||||
|
occurredAt: '2026-01-14T21:00:00.000Z',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
...entry('reversal', 'OPERATION_TYPE_DIVIDEND', '-0.1', 'RUB'),
|
||||||
|
occurredAt: '2026-01-15T20:59:59.999Z',
|
||||||
|
},
|
||||||
|
]);
|
||||||
|
const response = await service.analytics(
|
||||||
|
'user',
|
||||||
|
'account',
|
||||||
|
'2026-01-14',
|
||||||
|
'2026-01-16',
|
||||||
|
);
|
||||||
|
expect(response.data?.buckets).toEqual([
|
||||||
|
{
|
||||||
|
period: { from: '2026-01-14', to: '2026-01-14' },
|
||||||
|
totalsByCurrency: [expect.objectContaining({
|
||||||
|
total: { currency: 'RUB', value: '0.1' },
|
||||||
|
})],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
period: { from: '2026-01-15', to: '2026-01-15' },
|
||||||
|
totalsByCurrency: [expect.objectContaining({
|
||||||
|
coupon: { currency: 'RUB', value: '0.2' },
|
||||||
|
dividend: { currency: 'RUB', value: '-0.1' },
|
||||||
|
total: { currency: 'RUB', value: '0.1' },
|
||||||
|
})],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
period: { from: '2026-01-16', to: '2026-01-16' },
|
||||||
|
totalsByCurrency: [],
|
||||||
|
},
|
||||||
|
]);
|
||||||
|
});
|
||||||
|
|
||||||
it('aggregates only exact coupon and dividend payments by source currency', async () => {
|
it('aggregates only exact coupon and dividend payments by source currency', async () => {
|
||||||
operations.collectRanges.mockImplementation(
|
operations.collectRanges.mockImplementation(
|
||||||
(
|
(
|
||||||
|
|||||||
@@ -232,13 +232,16 @@ function buckets(
|
|||||||
granularity: IncomeBucketGranularity,
|
granularity: IncomeBucketGranularity,
|
||||||
entries: BrokerageOperationDto[],
|
entries: BrokerageOperationDto[],
|
||||||
) {
|
) {
|
||||||
|
const datedEntries = entries.map((entry) => ({
|
||||||
|
entry,
|
||||||
|
date: moscowDate(new Date(entry.occurredAt)),
|
||||||
|
}));
|
||||||
return rangeBuckets(range, granularity).map((period) => ({
|
return rangeBuckets(range, granularity).map((period) => ({
|
||||||
period,
|
period,
|
||||||
totalsByCurrency: totals(
|
totalsByCurrency: totals(
|
||||||
entries.filter((entry) => {
|
datedEntries
|
||||||
const date = moscowDate(new Date(entry.occurredAt));
|
.filter(({ date }) => date >= period.from && date <= period.to)
|
||||||
return date >= period.from && date <= period.to;
|
.map(({ entry }) => entry),
|
||||||
}),
|
|
||||||
),
|
),
|
||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user