feat: allow for cashbox batch editing

This commit is contained in:
Sérgio Salgado 2021-04-12 19:28:57 +01:00 committed by Josh Harvey
parent 21708aa75c
commit d6d8280a36
5 changed files with 119 additions and 18 deletions

View file

@ -30,9 +30,14 @@ function getBatches () {
}), res)) }), res))
} }
function editBatchById (id, performedBy) {
const sql = `UPDATE cashbox_batches SET performed_by=$1 WHERE id=$2`
return db.none(sql, [performedBy, id])
}
function getBillsByBatchId (id) { function getBillsByBatchId (id) {
const sql = `SELECT * FROM bills WHERE cashbox_batch_id=$1` const sql = `SELECT * FROM bills WHERE cashbox_batch_id=$1`
return db.any(sql, [id]) return db.any(sql, [id])
} }
module.exports = { createCashboxBatch, getBatches, getBillsByBatchId } module.exports = { createCashboxBatch, getBatches, getBillsByBatchId, editBatchById }

View file

@ -3,6 +3,9 @@ const cashbox = require('../../../cashbox-batches')
const resolvers = { const resolvers = {
Query: { Query: {
cashboxBatches: () => cashbox.getBatches() cashboxBatches: () => cashbox.getBatches()
},
Mutation: {
editBatch: (...[, { id, performedBy }]) => cashbox.editBatchById(id, performedBy)
} }
} }

View file

@ -14,6 +14,10 @@ const typeDef = gql`
type Query { type Query {
cashboxBatches: [CashboxBatch] cashboxBatches: [CashboxBatch]
} }
type Mutation {
editBatch(id: ID, performedBy: String): CashboxBatch
}
` `
module.exports = typeDef module.exports = typeDef

View file

@ -12,8 +12,8 @@ import { NumberInput, CashCassetteInput } from 'src/components/inputs/formik'
import TitleSection from 'src/components/layout/TitleSection' import TitleSection from 'src/components/layout/TitleSection'
import { EmptyTable } from 'src/components/table' import { EmptyTable } from 'src/components/table'
import { ReactComponent as EditIcon } from 'src/styling/icons/action/edit/enabled.svg' import { ReactComponent as EditIcon } from 'src/styling/icons/action/edit/enabled.svg'
import { ReactComponent as ReverseListingViewIcon } from 'src/styling/icons/circle buttons/listing-view/white.svg' import { ReactComponent as ReverseHistoryIcon } from 'src/styling/icons/circle buttons/history/white.svg'
import { ReactComponent as ListingViewIcon } from 'src/styling/icons/circle buttons/listing-view/zodiac.svg' import { ReactComponent as HistoryIcon } from 'src/styling/icons/circle buttons/history/zodiac.svg'
import { fromNamespace } from 'src/utils/config' import { fromNamespace } from 'src/utils/config'
import styles from './CashCassettes.styles.js' import styles from './CashCassettes.styles.js'
@ -208,8 +208,8 @@ const CashCassettes = () => {
title="Cash Cassettes" title="Cash Cassettes"
button={{ button={{
text: 'Cashbox history', text: 'Cashbox history',
icon: ListingViewIcon, icon: HistoryIcon,
inverseIcon: ReverseListingViewIcon, inverseIcon: ReverseHistoryIcon,
toggle: setShowHistory toggle: setShowHistory
}} }}
iconClassName={classes.listViewButton} iconClassName={classes.listViewButton}
@ -234,7 +234,9 @@ const CashCassettes = () => {
)} )}
</> </>
)} )}
{showHistory && <CashboxHistory machines={machines} />} {showHistory && (
<CashboxHistory machines={machines} currency={fiatCurrency} />
)}
</div> </div>
<CashCassettesFooter <CashCassettesFooter
currencyCode={fiatCurrency} currencyCode={fiatCurrency}

View file

@ -1,12 +1,16 @@
import { useQuery } from '@apollo/react-hooks' import { useQuery, useMutation } from '@apollo/react-hooks'
import { makeStyles } from '@material-ui/core' import { makeStyles } from '@material-ui/core'
import gql from 'graphql-tag' import gql from 'graphql-tag'
import moment from 'moment' import moment from 'moment'
import * as R from 'ramda' import * as R from 'ramda'
import React from 'react' import React, { useState } from 'react'
import * as Yup from 'yup'
import { Link, IconButton } from 'src/components/buttons'
import { TextInput } from 'src/components/inputs'
import { NumberInput } from 'src/components/inputs/formik' import { NumberInput } from 'src/components/inputs/formik'
import DataTable from 'src/components/tables/DataTable' import DataTable from 'src/components/tables/DataTable'
import { ReactComponent as EditIcon } from 'src/styling/icons/action/edit/enabled.svg'
import { ReactComponent as TxInIcon } from 'src/styling/icons/direction/cash-in.svg' import { ReactComponent as TxInIcon } from 'src/styling/icons/direction/cash-in.svg'
import { ReactComponent as TxOutIcon } from 'src/styling/icons/direction/cash-out.svg' import { ReactComponent as TxOutIcon } from 'src/styling/icons/direction/cash-out.svg'
@ -29,6 +33,14 @@ const GET_BATCHES = gql`
} }
` `
const EDIT_BATCH = gql`
mutation editBatch($id: ID, $performedBy: String) {
editBatch(id: $id, performedBy: $performedBy) {
id
}
}
`
const styles = { const styles = {
operationType: { operationType: {
marginLeft: 8 marginLeft: 8
@ -37,14 +49,31 @@ const styles = {
display: 'flex', display: 'flex',
flexDirection: 'row', flexDirection: 'row',
alignItems: 'center' alignItems: 'center'
},
saveAndCancel: {
display: 'flex',
flexDirection: 'row',
justifyContent: 'space-between'
} }
} }
const schema = Yup.object().shape({
performedBy: Yup.string().nullable()
})
const useStyles = makeStyles(styles) const useStyles = makeStyles(styles)
const CashboxHistory = ({ machines }) => { const CashboxHistory = ({ machines, currency }) => {
const classes = useStyles() const classes = useStyles()
const { data } = useQuery(GET_BATCHES) const [editing, setEditing] = useState(false)
const [error, setError] = useState(false)
const [fields, setFields] = useState({})
const { data, loading } = useQuery(GET_BATCHES)
const [editBatch] = useMutation(EDIT_BATCH, {
refetchQueries: () => ['cashboxBatches']
})
const batches = R.path(['cashboxBatches'])(data) const batches = R.path(['cashboxBatches'])(data)
@ -81,6 +110,24 @@ const CashboxHistory = ({ machines }) => {
) )
} }
const save = row => {
schema
.isValid(fields)
.then(() => {
setError(false)
editBatch({
variables: { id: row.id, performedBy: fields?.performedBy }
})
})
.catch(setError(true))
return close()
}
const close = () => {
setFields({})
return setEditing(false)
}
const elements = [ const elements = [
{ {
name: 'operation', name: 'operation',
@ -96,7 +143,7 @@ const CashboxHistory = ({ machines }) => {
{ {
name: 'machine', name: 'machine',
header: 'Machine', header: 'Machine',
width: 190, width: 200,
textAlign: 'left', textAlign: 'left',
view: it => { view: it => {
return R.find(R.propEq('id', it.deviceId))(machines).name return R.find(R.propEq('id', it.deviceId))(machines).name
@ -117,9 +164,13 @@ const CashboxHistory = ({ machines }) => {
{ {
name: 'total', name: 'total',
header: 'Total', header: 'Total',
width: 125, width: 100,
textAlign: 'right', textAlign: 'right',
view: it => R.sum(R.map(b => R.prop('fiat', b), it.bills)) view: it => (
<span>
{R.sum(R.map(b => R.prop('fiat', b), it.bills))} {currency}
</span>
)
}, },
{ {
name: 'date', name: 'date',
@ -138,22 +189,58 @@ const CashboxHistory = ({ machines }) => {
{ {
name: 'performedBy', name: 'performedBy',
header: 'Performed by', header: 'Performed by',
width: 200, width: 190,
textAlign: 'left', textAlign: 'left',
view: it => (R.isNil(it.performedBy) ? 'Unknown entity' : it.performedBy) view: it => {
if (!editing)
return R.isNil(it.performedBy) ? 'Unknown entity' : it.performedBy
return (
<TextInput
onChange={e =>
setFields({ ...fields, performedBy: e.target.value })
}
error={error}
width={190 * 0.85}
value={fields.performedBy ?? ''}
/>
)
}
}, },
{ {
name: '', name: '',
header: 'Edit', header: 'Edit',
width: 120, width: 150,
textAlign: 'right', textAlign: 'right',
view: it => 'aaaaa' view: it => {
if (!editing)
return (
<IconButton
onClick={() => {
setFields({})
setEditing(true)
}}>
<EditIcon />
</IconButton>
)
return (
<div className={classes.saveAndCancel}>
<Link type="submit" color="primary" onClick={() => save(it)}>
Save
</Link>
<Link color="secondary" onClick={close}>
Cancel
</Link>
</div>
)
}
} }
] ]
return ( return (
<> <>
<DataTable name="cashboxHistory" elements={elements} data={batches} /> {!loading && (
<DataTable name="cashboxHistory" elements={elements} data={batches} />
)}
</> </>
) )
} }