fix: harden auth and investment synchronization
Backend security / security (push) Successful in 8s
Backend verify / verify (push) Successful in 11m9s
Conventional commits / commits (pull_request) Successful in 28s
Backend security / security (pull_request) Successful in 7s
Backend verify / verify (pull_request) Successful in 10m38s
Backend security / security (push) Successful in 8s
Backend verify / verify (push) Successful in 11m9s
Conventional commits / commits (pull_request) Successful in 28s
Backend security / security (pull_request) Successful in 7s
Backend verify / verify (pull_request) Successful in 10m38s
Resolve A01-A10 and C01-C07 from the backend audit. Preserve auth failures, forced candle reconciliation and forecast freshness. Validate MOEX responses and nested HTTP errors; remove unused legacy paths. Verified: 209 unit tests, 262 SQLite e2e tests on Linux, OpenAPI and durability. Record the remaining macOS native SQLite abort in the audit.
This commit is contained in:
@@ -116,7 +116,9 @@ describe('bank card calculations', () => {
|
||||
amountKopecks: 5000n,
|
||||
},
|
||||
];
|
||||
expect(bankSummary('2026-09', operations)).toEqual({
|
||||
expect(
|
||||
bankSummary({ from: '2026-09-01', to: '2026-09-30' }, operations),
|
||||
).toEqual({
|
||||
expenses: 120n,
|
||||
refunds: 500n,
|
||||
net: -380n,
|
||||
@@ -125,7 +127,9 @@ describe('bank card calculations', () => {
|
||||
{ categoryId: 'travel', expenses: 20n, refunds: 0n, net: 20n },
|
||||
],
|
||||
});
|
||||
expect(bankSummary('2026-07', operations)).toEqual({
|
||||
expect(
|
||||
bankSummary({ from: '2026-07-01', to: '2026-07-31' }, operations),
|
||||
).toEqual({
|
||||
expenses: 0n,
|
||||
refunds: 0n,
|
||||
net: 0n,
|
||||
@@ -141,7 +145,12 @@ describe('bank card calculations', () => {
|
||||
amountKopecks: 2n ** 63n - 1n,
|
||||
};
|
||||
const total = 2n * (2n ** 63n - 1n);
|
||||
expect(bankSummary('2026-09', [operation, operation])).toEqual({
|
||||
expect(
|
||||
bankSummary({ from: '2026-09-01', to: '2026-09-30' }, [
|
||||
operation,
|
||||
operation,
|
||||
]),
|
||||
).toEqual({
|
||||
expenses: total,
|
||||
refunds: 0n,
|
||||
net: total,
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
import { BankOperationKind } from './bank-operation-kind';
|
||||
|
||||
const ISO_MONTH_LENGTH = 7;
|
||||
export function moscowToday(now = new Date()): string {
|
||||
return new Intl.DateTimeFormat('en-CA', {
|
||||
timeZone: 'Europe/Moscow',
|
||||
@@ -54,7 +53,7 @@ export function bankBalance(
|
||||
}
|
||||
|
||||
export function bankSummary(
|
||||
period: string | { from: string; to: string },
|
||||
period: { from: string; to: string },
|
||||
operations: Array<{
|
||||
kind: string;
|
||||
date: string;
|
||||
@@ -70,12 +69,7 @@ export function bankSummary(
|
||||
>();
|
||||
// ponytail: O(N) history fold; optimize only after measuring growing histories.
|
||||
for (const operation of operations) {
|
||||
if (
|
||||
typeof period === 'string'
|
||||
? operation.date.slice(0, ISO_MONTH_LENGTH) !== period
|
||||
: operation.date < period.from || operation.date > period.to
|
||||
)
|
||||
continue;
|
||||
if (operation.date < period.from || operation.date > period.to) continue;
|
||||
if (
|
||||
operation.kind !== BankOperationKind.Expense &&
|
||||
operation.kind !== BankOperationKind.Refund
|
||||
|
||||
Reference in New Issue
Block a user