107 lines
3.2 KiB
TypeScript
107 lines
3.2 KiB
TypeScript
import { Injectable, InternalServerErrorException } from '@nestjs/common';
|
|
import { PrismaService } from '../../prisma/prisma.service';
|
|
import type { BrokerOperation } from '../types/broker.types';
|
|
import { BrokerOperationsService } from './broker-operations.service';
|
|
|
|
type BrokerOperationSyncRange = {
|
|
from: string;
|
|
to: string;
|
|
};
|
|
|
|
@Injectable()
|
|
export class BrokerOperationSyncService {
|
|
constructor(
|
|
private readonly operationsService: BrokerOperationsService,
|
|
private readonly prisma: PrismaService,
|
|
) {}
|
|
|
|
async syncAccount(
|
|
accountId: string,
|
|
range: BrokerOperationSyncRange,
|
|
): Promise<{ upserted: number }> {
|
|
let cursor: string | undefined;
|
|
let lastCursor: string | null = null;
|
|
let upserted = 0;
|
|
|
|
do {
|
|
const page = await this.operationsService.getOperations(accountId, {
|
|
from: range.from,
|
|
to: range.to,
|
|
cursor,
|
|
limit: 1000,
|
|
state: 'OPERATION_STATE_EXECUTED',
|
|
});
|
|
|
|
for (const operation of page.data.items) {
|
|
await this.upsertOperation(accountId, operation);
|
|
upserted++;
|
|
}
|
|
|
|
const nextCursor = page.data.nextCursor ?? undefined;
|
|
if (page.data.hasNext && !nextCursor) {
|
|
throw new InternalServerErrorException('T-Bank returned hasNext without nextCursor');
|
|
}
|
|
|
|
if (nextCursor) {
|
|
lastCursor = nextCursor;
|
|
}
|
|
|
|
cursor = nextCursor;
|
|
if (!page.data.hasNext) {
|
|
break;
|
|
}
|
|
} while (cursor);
|
|
|
|
await this.prisma.brokerOperationSyncState.upsert({
|
|
where: { accountId },
|
|
create: {
|
|
accountId,
|
|
lastCursor,
|
|
lastSyncedFrom: new Date(range.from),
|
|
lastSyncedTo: new Date(range.to),
|
|
},
|
|
update: {
|
|
lastCursor,
|
|
lastSyncedFrom: new Date(range.from),
|
|
lastSyncedTo: new Date(range.to),
|
|
syncedAt: new Date(),
|
|
},
|
|
});
|
|
|
|
return { upserted };
|
|
}
|
|
|
|
private async upsertOperation(accountId: string, operation: BrokerOperation): Promise<void> {
|
|
const cursor =
|
|
operation.cursor || `${operation.id || 'operation'}:${operation.date || 'no-date'}`;
|
|
const data = {
|
|
accountId,
|
|
cursor,
|
|
operationId: operation.id,
|
|
parentOperationId: operation.parentOperationId,
|
|
date: operation.date ? new Date(operation.date) : null,
|
|
type: operation.type,
|
|
category: operation.category,
|
|
state: operation.state,
|
|
instrumentUid: operation.instrumentUid,
|
|
figi: operation.figi,
|
|
ticker: operation.ticker,
|
|
classCode: operation.classCode,
|
|
payment: operation.payment ? JSON.stringify(operation.payment) : null,
|
|
price: operation.price ? JSON.stringify(operation.price) : null,
|
|
commission: operation.commission ? JSON.stringify(operation.commission) : null,
|
|
yield: operation.yield ? JSON.stringify(operation.yield) : null,
|
|
accruedInt: operation.accruedInt ? JSON.stringify(operation.accruedInt) : null,
|
|
quantity: operation.quantity,
|
|
quantityDone: operation.quantityDone,
|
|
raw: JSON.stringify(operation),
|
|
};
|
|
|
|
await this.prisma.brokerOperation.upsert({
|
|
where: { accountId_cursor: { accountId, cursor } },
|
|
create: data,
|
|
update: data,
|
|
});
|
|
}
|
|
}
|