diff --git a/workers/loc.api/sync/movements/index.js b/workers/loc.api/sync/movements/index.js index 1576d5b11..52b575a03 100644 --- a/workers/loc.api/sync/movements/index.js +++ b/workers/loc.api/sync/movements/index.js @@ -97,7 +97,8 @@ class Movements { end, sort: ledgersOrder, isWithdrawals, - isDeposits + isDeposits, + isExcludePrivate }) const [ @@ -182,7 +183,9 @@ class Movements { currency, amount, amountUsd, - subUserId + subUserId, + _id, + exactUsdValue } = ledger return { @@ -199,7 +202,9 @@ class Movements { transactionId: '', note: '', subUserId, - _isFromLedgers: true + isLedgers: true, + _id, + exactUsdValue } }) } diff --git a/workers/loc.api/sync/transaction.tax.report/helpers/index.js b/workers/loc.api/sync/transaction.tax.report/helpers/index.js index 71c804c7b..7761b3c11 100644 --- a/workers/loc.api/sync/transaction.tax.report/helpers/index.js +++ b/workers/loc.api/sync/transaction.tax.report/helpers/index.js @@ -1,7 +1,11 @@ 'use strict' const TRX_TAX_STRATEGIES = require('./trx.tax.strategies') +const remapTrades = require('./remap-trades') +const remapMovements = require('./remap-movements') module.exports = { - TRX_TAX_STRATEGIES + TRX_TAX_STRATEGIES, + remapTrades, + remapMovements } diff --git a/workers/loc.api/sync/transaction.tax.report/helpers/remap-movements.js b/workers/loc.api/sync/transaction.tax.report/helpers/remap-movements.js new file mode 100644 index 000000000..f22393f28 --- /dev/null +++ b/workers/loc.api/sync/transaction.tax.report/helpers/remap-movements.js @@ -0,0 +1,69 @@ +'use strict' + +const { + isForexSymb +} = require('../../helpers') + +module.exports = (movements, params) => { + const { + remappedTrxs, + remappedTrxsForConvToUsd + } = params + + for (const movement of movements) { + if ( + !movement?.currency || + isForexSymb(movement.currency) || + !Number.isFinite(movement?.amount) || + movement.amount === 0 || + !Number.isFinite(movement?.mtsUpdated) + ) { + continue + } + + const firstSymb = movement.currency + const lastSymb = 'USD' + const symbSeparator = firstSymb.length > 3 + ? ':' + : '' + + const remappedMovement = { + _id: movement._id, + // NOTE: it means entries are not taken form trades table + isAdditionalTrxMovements: true, + // NOTE: movements can have sub-account transfer entries from ledgers table + isMovements: !movement.isLedgers, + isLedgers: !!movement.isLedgers, + isTrades: false, + symbol: `t${firstSymb}${symbSeparator}${lastSymb}`, + mtsCreate: movement.mtsUpdated, + firstSymb, + lastSymb, + firstSymbPriceUsd: null, + lastSymbPriceUsd: 1, + execAmount: movement.amount, + // NOTE: execPrice = firstSymbPriceUsd and should be set when converting currencies + execPrice: 0, + // NOTE: exactUsdValue can be null on the first launch, for warm-up it's filling from pub-trades + exactUsdValue: movement.exactUsdValue + } + + remappedTrxs.push(remappedMovement) + + if ( + Number.isFinite(movement.exactUsdValue) && + movement.exactUsdValue > 0 + ) { + const price = movement.exactUsdValue / movement.amount + + remappedMovement.firstSymbPriceUsd = price + remappedMovement.execPrice = price + + continue + } + + remappedTrxsForConvToUsd.push(remappedMovement) + } + + return params +} diff --git a/workers/loc.api/sync/transaction.tax.report/helpers/remap-trades.js b/workers/loc.api/sync/transaction.tax.report/helpers/remap-trades.js new file mode 100644 index 000000000..722290295 --- /dev/null +++ b/workers/loc.api/sync/transaction.tax.report/helpers/remap-trades.js @@ -0,0 +1,57 @@ +'use strict' + +const splitSymbolPairs = require( + 'bfx-report/workers/loc.api/helpers/split-symbol-pairs' +) + +module.exports = (trades, params) => { + const { + remappedTrxs, + remappedTrxsForConvToUsd + } = params + + for (const trade of trades) { + if ( + !trade?.symbol || + !Number.isFinite(trade?.execAmount) || + trade.execAmount === 0 || + !Number.isFinite(trade?.execPrice) || + trade.execPrice === 0 || + !Number.isFinite(trade?.mtsCreate) + ) { + continue + } + + const [firstSymb, lastSymb] = splitSymbolPairs(trade.symbol) + trade.firstSymb = firstSymb + trade.lastSymb = lastSymb + trade.firstSymbPriceUsd = null + trade.lastSymbPriceUsd = null + trade.isAdditionalTrxMovements = false + trade.isMovements = false + trade.isLedgers = false + trade.isTrades = true + + remappedTrxs.push(trade) + + if (lastSymb === 'USD') { + trade.firstSymbPriceUsd = trade.execPrice + trade.lastSymbPriceUsd = 1 + + continue + } + if ( + Number.isFinite(trade.exactUsdValue) && + trade.exactUsdValue > 0 + ) { + trade.firstSymbPriceUsd = trade.exactUsdValue / trade.execAmount + trade.lastSymbPriceUsd = trade.exactUsdValue / trade.execPrice + + continue + } + + remappedTrxsForConvToUsd.push(trade) + } + + return params +} diff --git a/workers/loc.api/sync/transaction.tax.report/index.js b/workers/loc.api/sync/transaction.tax.report/index.js index 497472f93..93ddde252 100644 --- a/workers/loc.api/sync/transaction.tax.report/index.js +++ b/workers/loc.api/sync/transaction.tax.report/index.js @@ -1,7 +1,9 @@ 'use strict' const { - TRX_TAX_STRATEGIES + TRX_TAX_STRATEGIES, + remapTrades, + remapMovements } = require('./helpers') const { decorateInjectable } = require('../../di/utils') @@ -74,9 +76,122 @@ class TransactionTaxReport { const isFIFO = strategy === TRX_TAX_STRATEGIES.FIFO const isLIFO = strategy === TRX_TAX_STRATEGIES.LIFO + const { + trxs: trxsForCurrPeriod, + trxsForConvToUsd + } = await this.#getTrxs({ + user, + start, + end + }) + + if ( + !Array.isArray(trxsForCurrPeriod) || + trxsForCurrPeriod.length === 0 + ) { + return [] + } + + const { + trxs: trxsForPrevPeriod + } = start > 0 + ? await this.#getTrxs({ + user, + start: 0, + end: start - 1 + }) + : { trxs: [] } + // TODO: return [] } + + async #getTrxs (params) { + const { + user, + start, + end + } = params ?? {} + + const tradesPromise = this.#getTrades(params) + const withdrawalsPromise = this.movements.getMovements({ + auth: user, + start, + end, + isWithdrawals: true, + isExcludePrivate: false + }) + const depositsPromise = this.movements.getMovements({ + auth: user, + start, + end, + isDeposits: true, + isExcludePrivate: false + }) + + const [ + trades, + withdrawals, + deposits + ] = await Promise.all([ + tradesPromise, + withdrawalsPromise, + depositsPromise + ]) + + const movements = [...withdrawals, ...deposits] + const remappedTrxs = [] + const remappedTrxsForConvToUsd = [] + + remapTrades( + trades, + { remappedTrxs, remappedTrxsForConvToUsd } + ) + remapMovements( + movements, + { remappedTrxs, remappedTrxsForConvToUsd } + ) + + const trxs = remappedTrxs + .sort((a, b) => b?.mtsCreate - a?.mtsCreate) + const trxsForConvToUsd = remappedTrxsForConvToUsd + .sort((a, b) => b?.mtsCreate - a?.mtsCreate) + + return { + trxs, + trxsForConvToUsd + } + } + + async #getTrades ({ + user, + start, + end, + symbol + }) { + const symbFilter = ( + Array.isArray(symbol) && + symbol.length !== 0 + ) + ? { $in: { symbol } } + : {} + + return this.dao.getElemsInCollBy( + this.ALLOWED_COLLS.TRADES, + { + filter: { + user_id: user._id, + $lte: { mtsCreate: end }, + $gte: { mtsCreate: start }, + ...symbFilter + }, + sort: [['mtsCreate', -1]], + projection: this.tradesModel, + exclude: ['user_id'], + isExcludePrivate: false + } + ) + } } decorateInjectable(TransactionTaxReport, depsTypes)