Skip to content

Commit

Permalink
Merge pull request #382 from ZIMkaRU/feature/add-transaction-tax-repo…
Browse files Browse the repository at this point in the history
…rt-v2

[PART-3] Add transaction tax report
  • Loading branch information
ezewer authored May 24, 2024
2 parents 6aa4483 + 3753a31 commit f8b6da5
Show file tree
Hide file tree
Showing 5 changed files with 255 additions and 5 deletions.
11 changes: 8 additions & 3 deletions workers/loc.api/sync/movements/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -97,7 +97,8 @@ class Movements {
end,
sort: ledgersOrder,
isWithdrawals,
isDeposits
isDeposits,
isExcludePrivate
})

const [
Expand Down Expand Up @@ -182,7 +183,9 @@ class Movements {
currency,
amount,
amountUsd,
subUserId
subUserId,
_id,
exactUsdValue
} = ledger

return {
Expand All @@ -199,7 +202,9 @@ class Movements {
transactionId: '',
note: '',
subUserId,
_isFromLedgers: true
isLedgers: true,
_id,
exactUsdValue
}
})
}
Expand Down
6 changes: 5 additions & 1 deletion workers/loc.api/sync/transaction.tax.report/helpers/index.js
Original file line number Diff line number Diff line change
@@ -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
}
Original file line number Diff line number Diff line change
@@ -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
}
Original file line number Diff line number Diff line change
@@ -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
}
117 changes: 116 additions & 1 deletion workers/loc.api/sync/transaction.tax.report/index.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
'use strict'

const {
TRX_TAX_STRATEGIES
TRX_TAX_STRATEGIES,
remapTrades,
remapMovements
} = require('./helpers')

const { decorateInjectable } = require('../../di/utils')
Expand Down Expand Up @@ -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)
Expand Down

0 comments on commit f8b6da5

Please sign in to comment.