Merge pull request #1176 from chaotixkilla/feat-cashbox-history-download

Add cashbox batches log downloader
This commit is contained in:
Rafael Taranto 2022-03-31 10:17:01 +01:00 committed by GitHub
commit 51665b2b8f
8 changed files with 60 additions and 30 deletions

View file

@ -47,15 +47,16 @@ function updateMachineWithBatch (machineContext, oldCashboxCount) {
}) })
} }
function getBatches () { function getBatches (from = new Date(0).toISOString(), until = new Date().toISOString()) {
const sql = ` const sql = `
SELECT cb.id, cb.device_id, cb.created, cb.operation_type, cb.bill_count_override, cb.performed_by, json_agg(b.*) AS bills SELECT cb.id, cb.device_id, cb.created, cb.operation_type, cb.bill_count_override, cb.performed_by, json_agg(b.*) AS bills
FROM cashbox_batches AS cb FROM cashbox_batches AS cb
LEFT JOIN bills AS b ON cb.id = b.cashbox_batch_id LEFT JOIN bills AS b ON cb.id = b.cashbox_batch_id
WHERE cb.created >= $1 AND cb.created <= $2
GROUP BY cb.id GROUP BY cb.id
ORDER BY cb.created DESC ORDER BY cb.created DESC
` `
return db.any(sql).then(res => _.map(it => _.mapKeys(ite => _.camelCase(ite), it), res)) return db.any(sql, [from, until]).then(res => _.map(it => _.mapKeys(ite => _.camelCase(ite), it), res))
} }
function editBatchById (id, performedBy) { function editBatchById (id, performedBy) {

View file

@ -1,8 +1,11 @@
const { parseAsync } = require('json2csv')
const cashbox = require('../../../cashbox-batches') const cashbox = require('../../../cashbox-batches')
const logDateFormat = require('../../../logs').logDateFormat
const resolvers = { const resolvers = {
Query: { Query: {
cashboxBatches: () => cashbox.getBatches() cashboxBatches: () => cashbox.getBatches(),
cashboxBatchesCsv: (...[, { from, until, timezone }]) => cashbox.getBatches(from, until).then(data => parseAsync(logDateFormat(timezone, data, ['created'])))
}, },
Mutation: { Mutation: {
createBatch: (...[, { deviceId, cashboxCount }]) => cashbox.createCashboxBatch(deviceId, cashboxCount), createBatch: (...[, { deviceId, cashboxCount }]) => cashbox.createCashboxBatch(deviceId, cashboxCount),

View file

@ -12,12 +12,13 @@ const typeDef = gql`
} }
type Query { type Query {
cashboxBatches: [CashboxBatch] cashboxBatches: [CashboxBatch] @auth
cashboxBatchesCsv(from: Date, until: Date, timezone: String): String @auth
} }
type Mutation { type Mutation {
createBatch(deviceId: ID, cashboxCount: Int): CashboxBatch createBatch(deviceId: ID, cashboxCount: Int): CashboxBatch @auth
editBatch(id: ID, performedBy: String): CashboxBatch editBatch(id: ID, performedBy: String): CashboxBatch @auth
} }
` `

View file

@ -140,7 +140,8 @@ const LogsDownloaderPopover = ({
title, title,
getLogs, getLogs,
timezone, timezone,
simplified simplified,
className
}) => { }) => {
const [selectedRadio, setSelectedRadio] = useState(ALL) const [selectedRadio, setSelectedRadio] = useState(ALL)
const [selectedAdvancedRadio, setSelectedAdvancedRadio] = useState(ADVANCED) const [selectedAdvancedRadio, setSelectedAdvancedRadio] = useState(ADVANCED)
@ -245,7 +246,7 @@ const LogsDownloaderPopover = ({
return ( return (
<ClickAwayListener onClickAway={handleClickAway}> <ClickAwayListener onClickAway={handleClickAway}>
<div> <div className={className}>
<FeatureButton <FeatureButton
Icon={Download} Icon={Download}
InverseIcon={DownloadInverseIcon} InverseIcon={DownloadInverseIcon}

View file

@ -1,5 +1,6 @@
import { makeStyles, Box } from '@material-ui/core' import { makeStyles, Box } from '@material-ui/core'
import classnames from 'classnames' import classnames from 'classnames'
import * as R from 'ramda'
import React from 'react' import React from 'react'
import ErrorMessage from 'src/components/ErrorMessage' import ErrorMessage from 'src/components/ErrorMessage'
@ -32,17 +33,21 @@ const TitleSection = ({
)} )}
{buttons.length > 0 && ( {buttons.length > 0 && (
<> <>
{buttons.map((button, idx) => ( {buttons.map((button, idx) =>
<SubpageButton !R.isNil(button.component) ? (
key={idx} button.component
className={classes.subpageButton} ) : (
Icon={button.icon} <SubpageButton
InverseIcon={button.inverseIcon} key={idx}
toggle={button.toggle} className={classes.subpageButton}
forceDisable={button.forceDisable}> Icon={button.icon}
<Info1 className={classes.buttonText}>{button.text}</Info1> InverseIcon={button.inverseIcon}
</SubpageButton> toggle={button.toggle}
))} forceDisable={button.forceDisable}>
<Info1 className={classes.buttonText}>{button.text}</Info1>
</SubpageButton>
)
)}
</> </>
)} )}
</div> </div>

View file

@ -5,6 +5,7 @@ import * as R from 'ramda'
import React, { useState } from 'react' import React, { useState } from 'react'
import * as Yup from 'yup' import * as Yup from 'yup'
import LogsDowloaderPopover from 'src/components/LogsDownloaderPopper'
import Modal from 'src/components/Modal' import Modal from 'src/components/Modal'
import { IconButton, Button } from 'src/components/buttons' import { IconButton, Button } from 'src/components/buttons'
import { Table as EditableTable } from 'src/components/editableTable' import { Table as EditableTable } from 'src/components/editableTable'
@ -147,6 +148,12 @@ const SET_CASSETTE_BILLS = gql`
} }
` `
const GET_BATCHES_CSV = gql`
query cashboxBatchesCsv($from: Date, $until: Date, $timezone: String) {
cashboxBatchesCsv(from: $from, until: $until, timezone: $timezone)
}
`
const CashCassettes = () => { const CashCassettes = () => {
const classes = useStyles() const classes = useStyles()
const [showHistory, setShowHistory] = useState(false) const [showHistory, setShowHistory] = useState(false)
@ -175,6 +182,8 @@ const CashCassettes = () => {
refetchQueries: () => ['getData'] refetchQueries: () => ['getData']
}) })
const timezone = R.path(['config', 'locale_timezone'], data)
const bills = R.groupBy(bill => bill.deviceId)(R.path(['bills'])(data) ?? []) const bills = R.groupBy(bill => bill.deviceId)(R.path(['bills'])(data) ?? [])
const deviceIds = R.uniq( const deviceIds = R.uniq(
R.map(R.prop('deviceId'))(R.path(['bills'])(data) ?? []) R.map(R.prop('deviceId'))(R.path(['bills'])(data) ?? [])
@ -317,6 +326,21 @@ const CashCassettes = () => {
icon: HistoryIcon, icon: HistoryIcon,
inverseIcon: ReverseHistoryIcon, inverseIcon: ReverseHistoryIcon,
toggle: setShowHistory toggle: setShowHistory
},
{
component: showHistory ? (
<LogsDowloaderPopover
className={classes.downloadLogsButton}
title="Download logs"
name="cashboxHistory"
query={GET_BATCHES_CSV}
getLogs={logs => R.path(['cashboxBatchesCsv'])(logs)}
timezone={timezone}
args={{ timezone }}
/>
) : (
<></>
)
} }
]} ]}
iconClassName={classes.listViewButton} iconClassName={classes.listViewButton}
@ -364,6 +388,7 @@ const CashCassettes = () => {
<CashboxHistory <CashboxHistory
machines={R.concat(machines, unpairedMachines)} machines={R.concat(machines, unpairedMachines)}
currency={fiatCurrency} currency={fiatCurrency}
timezone={timezone}
/> />
)} )}
<CashCassettesFooter <CashCassettesFooter

View file

@ -23,5 +23,8 @@ export default {
}, },
selection: { selection: {
marginRight: 12 marginRight: 12
},
downloadLogsButton: {
marginLeft: 13
} }
} }

View file

@ -41,12 +41,6 @@ const GET_BATCHES = gql`
} }
` */ ` */
const GET_DATA = gql`
query getData {
config
}
`
const styles = { const styles = {
operationType: { operationType: {
marginLeft: 8 marginLeft: 8
@ -69,7 +63,7 @@ const styles = {
const useStyles = makeStyles(styles) const useStyles = makeStyles(styles)
const CashboxHistory = ({ machines, currency }) => { const CashboxHistory = ({ machines, currency, timezone }) => {
const classes = useStyles() const classes = useStyles()
/* const [error, setError] = useState(false) /* const [error, setError] = useState(false)
@ -82,10 +76,7 @@ const CashboxHistory = ({ machines, currency }) => {
refetchQueries: () => ['cashboxBatches'] refetchQueries: () => ['cashboxBatches']
}) */ }) */
const { data: configData, loading: configLoading } = useQuery(GET_DATA) const loading = batchesLoading
const timezone = R.path(['config', 'locale_timezone'], configData)
const loading = batchesLoading || configLoading
const batches = R.path(['cashboxBatches'])(batchesData) const batches = R.path(['cashboxBatches'])(batchesData)