Skip to content

Commit

Permalink
Merge pull request #775 from alexstotsky/pdf-export4tax
Browse files Browse the repository at this point in the history
(feature) Export to PDF for ledgers and tax reports
  • Loading branch information
ezewer authored Feb 20, 2024
2 parents 54a9f54 + a71ab06 commit ee5aad2
Show file tree
Hide file tree
Showing 12 changed files with 149 additions and 64 deletions.
7 changes: 4 additions & 3 deletions public/locales/en/translations.json
Original file line number Diff line number Diff line change
Expand Up @@ -274,7 +274,7 @@
},
"download": {
"query": "Prepare Export",
"title": "Export CSV",
"title": "Export",
"prepare": "Bitfinex will prepare your data during",
"send": "and send to {{email}}.",
"store": "and store to your local folder.",
Expand All @@ -283,11 +283,12 @@
"okay": "Okay",
"remoteStorage": "Remote storage",
"status": {
"local": "Export csv generated, files are saved in: ",
"local": "Export generated, files are saved in: ",
"email": "Generating your CSV report, we'll send it to you via email as soon as it's ready..."
},
"success": "Success",
"targets": "Data to Export"
"targets": "Data to Export",
"exportAsPdf": "Export as PDF"
},
"fcredit": {
"title": "Funding Credits (Used)",
Expand Down
13 changes: 13 additions & 0 deletions src/components/ExportDialog/ExportDialog.helpers.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
import config from 'config'
import queryConstants from 'state/query/constants'

const { showFrameworkMode } = config

const EXPORT_TO_PDF_WHITELIST = [
queryConstants.MENU_LEDGERS,
queryConstants.MENU_TAX_REPORT,
]

export const getShowPdfSwitcher = (targets) => (
showFrameworkMode && EXPORT_TO_PDF_WHITELIST.some(target => targets.includes(target))
)
15 changes: 13 additions & 2 deletions src/components/ExportDialog/ExportDialog.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,10 +13,12 @@ import config from 'config'
import { tracker } from 'utils/trackers'
import { formatDate } from 'state/utils'
import { getTarget } from 'state/query/utils'
import ExportToPdf from 'ui/ExportToPdf'
import ShowMilliseconds from 'ui/ShowMilliseconds'
import queryConstants from 'state/query/constants'
import DateFormatSelector from 'ui/DateFormatSelector'

import { getShowPdfSwitcher } from './ExportDialog.helpers'
import ExportTargetsSelector from './ExportDialog.TargetsSelector'

const { showFrameworkMode } = config
Expand Down Expand Up @@ -123,6 +125,7 @@ class ExportDialog extends PureComponent {
if (!isOpen) {
return null
}
const showPdfSwitcher = getShowPdfSwitcher(currentTargets)
const showLoader = showFrameworkMode && isExporting
const target = getTarget(location.pathname)
const isWallets = location && location.pathname && target === queryConstants.MENU_WALLETS
Expand Down Expand Up @@ -182,8 +185,16 @@ class ExportDialog extends PureComponent {
</div>
</div>
<div className='export-dialog-row'>
<span>{t('preferences.milliseconds')}</span>
<ShowMilliseconds />
{showPdfSwitcher && (
<div className='export-dialog-item'>
<span>{t('download.exportAsPdf')}</span>
<ExportToPdf />
</div>
)}
<div className='export-dialog-item'>
<span>{t('preferences.milliseconds')}</span>
<ShowMilliseconds />
</div>
</div>
</div>
<div className={Classes.DIALOG_FOOTER}>
Expand Down
68 changes: 66 additions & 2 deletions src/components/TaxReport/Result/Result.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import React, { PureComponent } from 'react'
import PropTypes from 'prop-types'
import _isNumber from 'lodash/isNumber'

import NoData from 'ui/NoData'
Expand All @@ -10,7 +11,6 @@ import { checkFetch, checkInit } from 'state/utils'
import { getFrameworkPositionsColumns } from 'utils/columns'
import getMovementsColumns from 'components/Movements/Movements.columns'

import { propTypes } from './Result.props'
import getBalancesColumns from './Balances.columns'
import TAX_REPORT_SECTIONS from '../TaxReport.sections'

Expand Down Expand Up @@ -218,6 +218,70 @@ class Result extends PureComponent {
}
}

Result.propTypes = propTypes
Result.propTypes = {
data: PropTypes.shape({
startingPositionsSnapshot: PropTypes.arrayOf(
PropTypes.shape({
amount: PropTypes.number,
basePrice: PropTypes.number,
liquidationPrice: PropTypes.number,
marginFunding: PropTypes.number,
marginFundingType: PropTypes.number,
mtsUpdate: PropTypes.number,
pair: PropTypes.string.isRequired,
pl: PropTypes.number,
plPerc: PropTypes.number,
}),
).isRequired,
endingPositionsSnapshot: PropTypes.arrayOf(
PropTypes.shape({
amount: PropTypes.number,
basePrice: PropTypes.number,
liquidationPrice: PropTypes.number,
marginFunding: PropTypes.number,
marginFundingType: PropTypes.number,
mtsUpdate: PropTypes.number,
pair: PropTypes.string.isRequired,
pl: PropTypes.number,
plPerc: PropTypes.number,
}),
).isRequired,
finalState: PropTypes.shape({
startingPeriodBalances: PropTypes.shape({
walletsTotalBalanceUsd: PropTypes.number,
positionsTotalPlUsd: PropTypes.number,
totalResult: PropTypes.number,
}),
movements: PropTypes.arrayOf(PropTypes.shape({
amount: PropTypes.number,
amountUsd: PropTypes.number,
currency: PropTypes.string,
currencyName: PropTypes.string,
destinationAddress: PropTypes.string,
fees: PropTypes.number,
id: PropTypes.number,
mtsStarted: PropTypes.number,
mtsUpdated: PropTypes.number,
note: PropTypes.string,
status: PropTypes.string,
subUserId: PropTypes.number,
transactionId: PropTypes.string,
})).isRequired,
movementsTotalAmount: PropTypes.number,
endingPeriodBalances: PropTypes.shape({
walletsTotalBalanceUsd: PropTypes.number,
positionsTotalPlUsd: PropTypes.number,
totalResult: PropTypes.number,
}),
totalResult: PropTypes.number,
}).isRequired,
}).isRequired,
pageLoading: PropTypes.bool.isRequired,
dataReceived: PropTypes.bool.isRequired,
getFullTime: PropTypes.func.isRequired,
timeOffset: PropTypes.string.isRequired,
refresh: PropTypes.func.isRequired,
t: PropTypes.func.isRequired,
}

export default Result
53 changes: 0 additions & 53 deletions src/components/TaxReport/Result/Result.props.js

This file was deleted.

8 changes: 8 additions & 0 deletions src/state/query/actions.js
Original file line number Diff line number Diff line change
Expand Up @@ -60,11 +60,19 @@ export function setIsCsvExporting(isExporting) {
}
}

export function setIsPdfRequired(isPdfRequired) {
return {
type: types.SET_IS_PDF_REQUIRED,
payload: isPdfRequired,
}
}

export default {
exportCsv,
setRemoteUrn,
prepareExport,
setExportEmail,
setIsPdfRequired,
setIsCsvExporting,
setLocalExportPath,
}
1 change: 1 addition & 0 deletions src/state/query/constants.js
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ export default {
SET_LOCAL_EXPORT_PATH: 'BITFINEX/EXPORT/CSV_FOLDER_PATH',
SET_REMOTE_CSV_URN: 'BITFINEX/EXPORT/CSV_REMOTE_URN',
SET_IS_CSV_EXPORTING: 'BITFINEX/EXPORT/IS_CSV_EXPORTING',
SET_IS_PDF_REQUIRED: 'BITFINEX/EXPORT/IS_PDF_REQUIRED',
PREPARE_EXPORT: 'BITFINEX/EXPORT/PREPARE',
SET_EXPORT_EMAIL: 'BITFINEX/EMAIL/EXPORT',
FILTER_ID: 'id',
Expand Down
6 changes: 6 additions & 0 deletions src/state/query/reducer.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ const initialState = {
localExportPath: null,
remoteUrn: null,
isCsvExporting: false,
isPDFRequired: true,
}

export function queryReducer(state = initialState, action) {
Expand All @@ -32,6 +33,11 @@ export function queryReducer(state = initialState, action) {
...state,
isCsvExporting: payload,
}
case types.SET_IS_PDF_REQUIRED:
return {
...state,
isPDFRequired: payload,
}
case authTypes.LOGOUT:
return initialState
default:
Expand Down
12 changes: 8 additions & 4 deletions src/state/query/saga.js
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ import config from 'config'

import actions from './actions'
import types from './constants'
import { getExportEmail } from './selectors'
import { getExportEmail, getIsPdfExportRequired } from './selectors'
import {
getQueryLimit,
NO_TIME_FRAME_TARGETS,
Expand Down Expand Up @@ -129,7 +129,7 @@ const {
}
*/

const getMultipleCsv = params => makeFetchCall('getMultipleCsv', params)
const getMultipleCsv = params => makeFetchCall('getMultipleFile', params)

function getSelector(target) {
switch (target) {
Expand Down Expand Up @@ -250,6 +250,7 @@ function* getOptions({ target }) {
const isVSPrevDayBalance = showFrameworkMode ? yield select(getIsVSPrevDayBalance) : ''
const isUnrealizedProfitExcluded = showFrameworkMode ? yield select(getIsUnrealizedProfitExcluded) : ''
const isVsAccountBalanceSelected = showFrameworkMode ? yield select(getIsVsAccountBalanceSelected) : ''
const isPdfExportRequired = showFrameworkMode ? yield select(getIsPdfExportRequired) : false

switch (target) {
case MENU_ACCOUNT_BALANCE:
Expand Down Expand Up @@ -288,6 +289,8 @@ function* getOptions({ target }) {
options.symbol = formatSymbol(target, sign.targetSymbols)
break
case MENU_TAX_REPORT:
options.isPDFRequired = isPdfExportRequired
break
case MENU_LOGINS:
case MENU_CHANGE_LOGS:
break
Expand Down Expand Up @@ -338,7 +341,8 @@ function* getOptions({ target }) {
options.method = 'getPayInvoiceListCsv'
break
case MENU_LEDGERS:
options.method = 'getLedgersCsv'
options.method = 'getLedgersFile'
options.isPDFRequired = isPdfExportRequired
options.category = yield select(getLedgersCategory)
break
case MENU_LOAN_REPORT:
Expand Down Expand Up @@ -385,7 +389,7 @@ function* getOptions({ target }) {
options.method = 'getFullSnapshotReportCsv'
break
case MENU_TAX_REPORT:
options.method = 'getFullTaxReportCsv'
options.method = 'getFullTaxReportFile'
break
case MENU_TRADED_VOLUME:
options.method = 'getTradedVolumeCsv'
Expand Down
2 changes: 2 additions & 0 deletions src/state/query/selectors.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,13 @@ export const getRemoteUrn = state => getQuery(state).remoteUrn
export const getExportEmail = state => getQuery(state).exportEmail
export const getLocalExportPath = state => getQuery(state).localExportPath
export const getIsCsvExporting = state => getQuery(state)?.isCsvExporting ?? false
export const getIsPdfExportRequired = state => getQuery(state)?.isPDFRequired ?? false

export default {
getQuery,
getRemoteUrn,
getExportEmail,
getIsCsvExporting,
getLocalExportPath,
getIsPdfExportRequired,
}
27 changes: 27 additions & 0 deletions src/ui/ExportToPdf/ExportToPdf.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
import React, { useCallback } from 'react'
import { useDispatch, useSelector } from 'react-redux'
import { Checkbox } from '@blueprintjs/core'

import { tracker } from 'utils/trackers'
import { setIsPdfRequired } from 'state/query/actions'
import { getIsPdfExportRequired } from 'state/query/selectors'

const ExportToPdf = () => {
const dispatch = useDispatch()
const isPdfExportRequired = useSelector(getIsPdfExportRequired)

const handleChange = useCallback(() => {
tracker.trackEvent('Export as PDF')
dispatch(setIsPdfRequired(!isPdfExportRequired))
}, [dispatch, tracker, isPdfExportRequired])

return (
<Checkbox
large
onChange={handleChange}
checked={isPdfExportRequired}
/>
)
}

export default ExportToPdf
1 change: 1 addition & 0 deletions src/ui/ExportToPdf/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export { default } from './ExportToPdf'

0 comments on commit ee5aad2

Please sign in to comment.