feat: revamp cash units screen

fix: bill math
This commit is contained in:
Sérgio Salgado 2023-05-30 13:49:11 +01:00
parent e194509d10
commit 6474017563
12 changed files with 487 additions and 309 deletions

View file

@ -56,17 +56,16 @@ const buildBillList = (units, mode) => {
units units
) )
const _units = _.cloneDeep(units) const _units = _.filter(it => it.count > 0)(_.cloneDeep(units))
const bills = [] const bills = []
for(let i = 0; i < amountOfBills; i++) { for(let i = 0; i < amountOfBills; i++) {
const idx = i % _.size(_units) const idx = i % _.size(_units)
if (_units[idx].count > 0) { if (_units[idx].count > 0) {
bills.push(_units[idx].denomination) bills.push(_units[idx].denomination)
_units[idx].count--
} }
_units[idx].count--
if (_units[idx].count === 0) { if (_units[idx].count === 0) {
_units.splice(idx, 1) _units.splice(idx, 1)
} }
@ -82,17 +81,16 @@ const buildBillList = (units, mode) => {
units units
) )
const _units = _.orderBy(['denomination'], ['asc'])(_.cloneDeep(units)) const _units = _.flow([_.filter(it => it.count > 0), _.orderBy(['denomination'], ['asc'])])(_.cloneDeep(units))
const bills = [] const bills = []
for(let i = 0; i < amountOfBills; i++) { for(let i = 0; i < amountOfBills; i++) {
const idx = i % _.size(_units) const idx = i % _.size(_units)
if (_units[idx].count > 0) { if (_units[idx].count > 0) {
bills.push(_units[idx].denomination) bills.push(_units[idx].denomination)
_units[idx].count--
} }
_units[idx].count--
if (_units[idx].count === 0) { if (_units[idx].count === 0) {
_units.splice(idx, 1) _units.splice(idx, 1)
} }
@ -107,6 +105,10 @@ const buildBillList = (units, mode) => {
const getSolution = (units, amount, mode) => { const getSolution = (units, amount, mode) => {
const billList = buildBillList(units, mode) const billList = buildBillList(units, mode)
if (_.sum(billList) < amount.toNumber()) {
return []
}
const solver = sumService.subsetSum(billList, amount.toNumber()) const solver = sumService.subsetSum(billList, amount.toNumber())
const solution = _.countBy(Math.floor, solver.next().value) const solution = _.countBy(Math.floor, solver.next().value)

View file

@ -15,6 +15,7 @@ const Cashbox = ({
percent = 0, percent = 0,
cashOut = false, cashOut = false,
width, width,
height,
className, className,
emptyPartClassName, emptyPartClassName,
labelClassName, labelClassName,
@ -27,6 +28,7 @@ const Cashbox = ({
percent, percent,
cashOut, cashOut,
width, width,
height,
applyColorVariant, applyColorVariant,
isLow isLow
}) })
@ -55,35 +57,17 @@ const Cashbox = ({
// https://support.lamassu.is/hc/en-us/articles/360025595552-Installing-the-Sintra-Forte // https://support.lamassu.is/hc/en-us/articles/360025595552-Installing-the-Sintra-Forte
// Sintra and Sintra Forte can have up to 500 notes per cashOut box and up to 1000 per cashIn box // Sintra and Sintra Forte can have up to 500 notes per cashOut box and up to 1000 per cashIn box
const CashIn = ({ currency, notes, total }) => { const CashIn = ({
const classes = gridClasses()
return (
<>
<div className={classes.row}>
<div>
<div className={classes.innerRow}>
<Info2 className={classes.noMarginText}>{notes} notes</Info2>
</div>
<div className={classes.innerRow}>
<Label1 className={classes.noMarginText}>
{total} {currency.code}
</Label1>
</div>
</div>
</div>
</>
)
}
const CashOut = ({
capacity = 500, capacity = 500,
denomination = 0,
currency, currency,
notes, notes,
className, className,
editingMode = false, editingMode = false,
threshold, threshold,
width width,
height,
total,
omitInnerPercentage
}) => { }) => {
const percent = (100 * notes) / capacity const percent = (100 * notes) / capacity
const isLow = percent < threshold const isLow = percent < threshold
@ -98,6 +82,54 @@ const CashOut = ({
cashOut cashOut
isLow={isLow} isLow={isLow}
width={width} width={width}
height={height}
omitInnerPercentage={omitInnerPercentage}
/>
</div>
{!editingMode && (
<div className={classes.col2}>
<div className={classes.innerRow}>
<Info2 className={classes.noMarginText}>{notes} notes</Info2>
</div>
<div className={classes.innerRow}>
<Label1 className={classes.noMarginText}>
{total} {currency.code}
</Label1>
</div>
</div>
)}
</div>
</>
)
}
const CashOut = ({
capacity = 500,
denomination = 0,
currency,
notes,
className,
editingMode = false,
threshold,
width,
height,
omitInnerPercentage
}) => {
const percent = (100 * notes) / capacity
const isLow = percent < threshold
const classes = gridClasses()
return (
<>
<div className={classes.row}>
<div className={classes.col}>
<Cashbox
className={className}
percent={percent}
cashOut
isLow={isLow}
width={width}
height={height}
omitInnerPercentage={omitInnerPercentage}
/> />
</div> </div>
{!editingMode && ( {!editingMode && (
@ -121,4 +153,30 @@ const CashOut = ({
) )
} }
export { Cashbox, CashIn, CashOut } const CashOutLite = ({
capacity = 500,
denomination = 0,
currency,
notes,
threshold,
width
}) => {
const percent = (100 * notes) / capacity
const isLow = percent < threshold
const classes = gridClasses()
return (
<div className={classes.col}>
<Cashbox
percent={percent}
cashOut
isLow={isLow}
width={width}
height={15}
omitInnerPercentage
/>
<Chip label={`${denomination} ${currency.code}`} />
</div>
)
}
export { Cashbox, CashIn, CashOut, CashOutLite }

View file

@ -21,7 +21,7 @@ const cashboxStyles = {
cashbox: { cashbox: {
borderColor: colorPicker, borderColor: colorPicker,
backgroundColor: colorPicker, backgroundColor: colorPicker,
height: 118, height: ({ height }) => height ?? 118,
width: ({ width }) => width ?? 80, width: ({ width }) => width ?? 80,
border: '2px solid', border: '2px solid',
textAlign: 'end', textAlign: 'end',
@ -58,7 +58,13 @@ const cashboxStyles = {
const gridStyles = { const gridStyles = {
row: { row: {
display: 'flex' display: 'flex',
alignItems: 'center'
},
col: {
display: 'flex',
flexDirection: 'column',
alignItems: 'center'
}, },
innerRow: { innerRow: {
display: 'flex', display: 'flex',

View file

@ -1,30 +0,0 @@
import { offColor } from 'src/styling/variables'
export default {
cashbox: {
height: 36
},
tBody: {
maxHeight: '65vh',
overflow: 'auto'
},
tableWidth: {
display: 'flex',
alignItems: 'center',
marginRight: 1
},
descriptions: {
color: offColor,
marginTop: 0
},
cashboxReset: {
color: offColor,
margin: [[13, 0, -5, 20]]
},
selection: {
marginRight: 12
},
downloadLogsButton: {
marginLeft: 13
}
}

View file

@ -0,0 +1,211 @@
import { makeStyles } from '@material-ui/core/styles'
import * as R from 'ramda'
import React from 'react'
import Chip from 'src/components/Chip'
import { CashOut } from 'src/components/inputs'
import { Label1, TL2 } from 'src/components/typography'
import { offDarkColor } from 'src/styling/variables'
import { fromNamespace } from 'src/utils/config'
import { cashUnitCapacity, modelPrettifier } from 'src/utils/machine'
const styles = {
wrapper: {
display: 'flex',
flexDirection: 'row',
marginTop: 12,
marginBottom: 16,
'& > *': {
marginRight: 40
},
'& > *:last-child': {
marginRight: 0
},
minHeight: 120
},
row: {
display: 'flex',
flexDirection: 'row'
},
col: {
display: 'flex',
flexDirection: 'column'
},
machineData: {
display: 'flex',
flexDirection: 'column',
minWidth: 210
},
billList: {
display: 'flex',
flexDirection: 'column',
minWidth: 160,
'& > span': {
display: 'flex',
flexDirection: 'row',
alignItems: 'center',
'& > p': {
minWidth: 30
}
}
},
unitList: {
display: 'flex',
flexDirection: 'row',
'& > *': {
marginRight: 20
},
'& > *:last-child': {
marginRight: 0
},
marginTop: 10
},
verticalLine: {
height: '100%',
width: 1,
backgroundColor: offDarkColor
},
label: {
marginBottom: 10
},
loadingBoxes: {
display: 'flex',
flexDirection: 'column',
'& > *': {
marginBottom: 20
},
'& > *:last-child': {
marginBottom: 0
}
}
}
const useStyles = makeStyles(styles)
const CashUnitDetails = ({ machine, bills, currency, config }) => {
const classes = useStyles()
const billCount = R.countBy(it => it.fiat)(bills)
const fillingPercentageSettings = fromNamespace('notifications', config)
const cashout = fromNamespace('cashOut')(config)
const getCashoutSettings = id => fromNamespace(id)(cashout)
return (
<div className={classes.wrapper}>
<div className={classes.machineData}>
<Label1>Machine Model</Label1>
<span>{modelPrettifier[machine.model]}</span>
</div>
<div className={classes.billList}>
<Label1>Cash box</Label1>
{R.isEmpty(billCount) && <TL2 noMargin>Empty</TL2>}
{R.map(it => (
<span>
<TL2 noMargin>{billCount[it]}</TL2>
<Chip label={`${it} ${currency}`} />
</span>
))(R.keys(billCount))}
</div>
<div className={classes.unitList}>
{machine.numberOfStackers === 0 &&
R.map(it => (
<>
<div className={classes.col}>
<Label1
noMargin
className={classes.label}>{`Cassette ${it}`}</Label1>
<CashOut
width={60}
height={40}
currency={{ code: currency }}
notes={machine.cashUnits[`cassette${it}`]}
denomination={getCashoutSettings(machine.id)[`cassette${it}`]}
threshold={
fillingPercentageSettings[`fillingPercentageCassette${it}`]
}
capacity={cashUnitCapacity[machine.model].cassette}
/>
</div>
{it !== machine.numberOfCassettes && (
<span className={classes.verticalLine} />
)}
</>
))(R.range(1, machine.numberOfCassettes + 1))}
{machine.numberOfStackers > 0 && (
<>
<div className={classes.col}>
<Label1
noMargin
className={classes.label}>{`Loading boxes`}</Label1>
<div className={classes.loadingBoxes}>
{R.map(it => (
<CashOut
width={60}
height={40}
currency={{ code: currency }}
notes={machine.cashUnits[`cassette${it}`]}
denomination={
getCashoutSettings(machine.id)[`cassette${it}`]
}
threshold={
fillingPercentageSettings[
`fillingPercentageCassette${it}`
]
}
capacity={cashUnitCapacity[machine.model].cassette}
/>
))(R.range(1, machine.numberOfCassettes + 1))}
</div>
</div>
<span className={classes.verticalLine} />
{R.map(it => (
<>
<div className={classes.col}>
<Label1
noMargin
className={classes.label}>{`Stacker ${it}`}</Label1>
<div className={classes.loadingBoxes}>
<CashOut
width={60}
height={40}
currency={{ code: currency }}
notes={machine.cashUnits[`stacker${it}f`]}
denomination={
getCashoutSettings(machine.id)[`stacker${it}f`]
}
threshold={
fillingPercentageSettings[
`fillingPercentageStacker${it}f`
]
}
capacity={cashUnitCapacity[machine.model].stacker}
/>
<CashOut
width={60}
height={40}
currency={{ code: currency }}
notes={machine.cashUnits[`stacker${it}r`]}
denomination={
getCashoutSettings(machine.id)[`stacker${it}r`]
}
threshold={
fillingPercentageSettings[
`fillingPercentageStacker${it}r`
]
}
capacity={cashUnitCapacity[machine.model].stacker}
/>
</div>
</div>
{it !== machine.numberOfStackers && (
<span className={classes.verticalLine} />
)}
</>
))(R.range(1, machine.numberOfStackers + 1))}
</>
)}
</div>
</div>
)
}
export default CashUnitDetails

View file

@ -7,10 +7,10 @@ import React, { useState } from 'react'
import LogsDowloaderPopover from 'src/components/LogsDownloaderPopper' 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 { RadioGroup } from 'src/components/inputs' import { RadioGroup } from 'src/components/inputs'
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 DataTable from 'src/components/tables/DataTable'
import { P, Label1 } from 'src/components/typography' import { P, Label1 } from 'src/components/typography'
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 ReverseHistoryIcon } from 'src/styling/icons/circle buttons/history/white.svg' import { ReactComponent as ReverseHistoryIcon } from 'src/styling/icons/circle buttons/history/white.svg'
@ -19,8 +19,9 @@ import { fromNamespace, toNamespace } from 'src/utils/config'
import { MANUAL, AUTOMATIC } from 'src/utils/constants' import { MANUAL, AUTOMATIC } from 'src/utils/constants'
import { onlyFirstToUpper } from 'src/utils/string' import { onlyFirstToUpper } from 'src/utils/string'
import styles from './CashCassettes.styles' import CashUnitDetails from './CashUnitDetails'
import CashCassettesFooter from './CashCassettesFooter' import styles from './CashUnits.styles'
import CashCassettesFooter from './CashUnitsFooter'
import CashboxHistory from './CashboxHistory' import CashboxHistory from './CashboxHistory'
import Wizard from './Wizard/Wizard' import Wizard from './Wizard/Wizard'
import helper from './helper' import helper from './helper'
@ -117,9 +118,6 @@ const CashCassettes = () => {
const [machineId, setMachineId] = useState('') const [machineId, setMachineId] = useState('')
const machines = R.path(['machines'])(data) ?? [] const machines = R.path(['machines'])(data) ?? []
const [stackerMachines, nonStackerMachines] = R.partition(
it => it.numberOfStackers > 0
)(machines)
const unpairedMachines = R.path(['unpairedMachines'])(data) ?? [] const unpairedMachines = R.path(['unpairedMachines'])(data) ?? []
const config = R.path(['config'])(data) ?? {} const config = R.path(['config'])(data) ?? {}
const [setCassetteBills, { error }] = useMutation(SET_CASSETTE_BILLS, { const [setCassetteBills, { error }] = useMutation(SET_CASSETTE_BILLS, {
@ -141,7 +139,6 @@ const CashCassettes = () => {
const fiatCurrency = locale?.fiatCurrency const fiatCurrency = locale?.fiatCurrency
const getCashoutSettings = id => fromNamespace(id)(cashout) const getCashoutSettings = id => fromNamespace(id)(cashout)
const isCashOutDisabled = ({ id }) => !getCashoutSettings(id).active
const onSave = (id, cashUnits) => { const onSave = (id, cashUnits) => {
return setCassetteBills({ return setCassetteBills({
@ -178,8 +175,8 @@ const CashCassettes = () => {
setSelectedRadio(selectedRadio) setSelectedRadio(selectedRadio)
} }
const nonStackerElements = helper.getElements( const elements = helper.getElements(
nonStackerMachines, machines,
classes, classes,
config, config,
bills, bills,
@ -187,13 +184,13 @@ const CashCassettes = () => {
setWizard setWizard
) )
const stackerElements = helper.getElements( const InnerCashUnitDetails = ({ it }) => (
stackerMachines, <CashUnitDetails
classes, machine={it}
config, bills={bills[it.id] ?? []}
bills, currency={fiatCurrency}
setMachineId, config={config}
setWizard />
) )
return ( return (
@ -250,22 +247,13 @@ const CashCassettes = () => {
</TitleSection> </TitleSection>
{!showHistory && ( {!showHistory && (
<> <>
<EditableTable <DataTable
error={error?.message} loading={dataLoading}
name="cashboxes" elements={elements}
stripeWhen={isCashOutDisabled} data={machines}
elements={nonStackerElements} Details={InnerCashUnitDetails}
data={nonStackerMachines} emptyText="No machines so far"
tbodyWrapperClass={classes.tBody} expandable
/>
<EditableTable
error={error?.message}
name="recyclerCashboxes"
stripeWhen={isCashOutDisabled}
elements={stackerElements}
data={stackerMachines}
tbodyWrapperClass={classes.tBody}
/> />
{data && R.isEmpty(machines) && ( {data && R.isEmpty(machines) && (

View file

@ -0,0 +1,56 @@
import { offColor, offDarkColor } from 'src/styling/variables'
export default {
cashbox: {
height: 36
},
tBody: {
maxHeight: '65vh',
overflow: 'auto'
},
tableWidth: {
display: 'flex',
alignItems: 'center',
marginRight: 1
},
descriptions: {
color: offColor,
marginTop: 0
},
cashboxReset: {
color: offColor,
margin: [[13, 0, -5, 20]]
},
selection: {
marginRight: 12
},
downloadLogsButton: {
marginLeft: 13
},
unitsRow: {
display: 'flex',
flexDirection: 'row',
margin: [[10, 0]],
'& > *': {
marginRight: 30
},
'& > *:last-child': {
marginRight: 0
}
},
units: {
display: 'flex',
flexDirection: 'row',
'& > *': {
marginRight: 10
},
'& > *:last-child': {
marginRight: 0
}
},
verticalLine: {
height: '100%',
width: 1,
backgroundColor: offDarkColor
}
}

View file

@ -9,7 +9,8 @@ import { ReactComponent as TxOutIcon } from 'src/styling/icons/direction/cash-ou
import { fromNamespace } from 'src/utils/config' import { fromNamespace } from 'src/utils/config'
import { numberToFiatAmount } from 'src/utils/number.js' import { numberToFiatAmount } from 'src/utils/number.js'
import styles from './CashCassettesFooter.styles.js' import styles from './CashUnitsFooter.styles.js'
const useStyles = makeStyles(styles) const useStyles = makeStyles(styles)
const CashCassettesFooter = ({ const CashCassettesFooter = ({

View file

@ -1,77 +1,11 @@
import * as R from 'ramda' import * as R from 'ramda'
import { IconButton } from 'src/components/buttons' import { IconButton } from 'src/components/buttons'
import { CashOut, CashIn } from 'src/components/inputs/cashbox/Cashbox' import { CashIn, CashOutLite } from 'src/components/inputs/cashbox/Cashbox'
import { NumberInput, CashCassetteInput } from 'src/components/inputs/formik'
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 { fromNamespace } from 'src/utils/config' import { fromNamespace } from 'src/utils/config'
import { cashUnitCapacity } from 'src/utils/machine' import { cashUnitCapacity } from 'src/utils/machine'
const widthsByCashUnits = {
2: {
machine: 250,
cashbox: 260,
cassette: 300,
unitGraph: 80,
editWidth: 90
},
3: {
machine: 220,
cashbox: 215,
cassette: 225,
unitGraph: 60,
editWidth: 90
},
4: {
machine: 190,
cashbox: 180,
cassette: 185,
unitGraph: 50,
editWidth: 90
},
5: {
machine: 170,
cashbox: 140,
cassette: 160,
unitGraph: 45,
editWidth: 90
},
6: {
machine: 150,
cashbox: 130,
cassette: 142,
unitGraph: 45,
editWidth: 70
},
7: {
machine: 140,
cashbox: 115,
cassette: 125,
unitGraph: 40,
editWidth: 70
},
8: {
machine: 100,
cashbox: 115,
cassette: 122,
unitGraph: 35,
editWidth: 70
}
}
const getMaxNumberOfCassettesMap = machines =>
Math.max(...R.map(it => it.numberOfCassettes, machines), 0)
const getMaxNumberOfStackersMap = machines =>
Math.max(...R.map(it => it.numberOfStackers, machines), 0)
// Each stacker counts as two cash units (front and rear)
const getMaxNumberOfCashUnits = machines =>
Math.max(
...R.map(it => it.numberOfCassettes + it.numberOfStackers * 2, machines),
0
)
const getElements = ( const getElements = (
machines, machines,
classes, classes,
@ -91,157 +25,109 @@ const getElements = (
{ {
name: 'name', name: 'name',
header: 'Machine', header: 'Machine',
width: widthsByCashUnits[getMaxNumberOfCashUnits(machines)]?.machine, width: 250,
view: name => <>{name}</>, view: m => <>{m.name}</>,
input: ({ field: { value: name } }) => <>{name}</> input: ({ field: { value: name } }) => <>{name}</>
}, },
{ {
name: 'cashbox', name: 'cashbox',
header: 'Cash box', header: 'Cashbox',
width: widthsByCashUnits[getMaxNumberOfCashUnits(machines)]?.cashbox, width: 200,
view: (_, { id, cashUnits }) => ( view: m => (
<CashIn <CashIn
currency={{ code: fiatCurrency }} currency={{ code: fiatCurrency }}
notes={cashUnits.cashbox} notes={m.cashUnits.cashbox}
total={R.sum(R.map(it => it.fiat, bills[id] ?? []))} total={R.sum(R.map(it => it.fiat, bills[m.id] ?? []))}
width={25}
height={45}
omitInnerPercentage
className={classes.padding}
/> />
), ),
input: NumberInput,
inputProps: { inputProps: {
decimalPlaces: 0 decimalPlaces: 0
} }
},
{
name: 'cassettes',
header: 'Cassettes & Recyclers',
width: 575,
view: m => {
return (
<div className={classes.unitsRow}>
<div className={classes.units}>
{R.map(it => (
<CashOutLite
width={'100%'}
currency={{ code: fiatCurrency }}
notes={m.cashUnits[`cassette${it}`]}
denomination={getCashoutSettings(m.id)[`cassette${it}`]}
threshold={
fillingPercentageSettings[`fillingPercentageCassette${it}`]
}
capacity={cashUnitCapacity[m.model].cassette}
/>
))(R.range(1, m.numberOfCassettes + 1))}
</div>
<div className={classes.units}>
{R.map(it => (
<>
<CashOutLite
width={'100%'}
currency={{ code: fiatCurrency }}
notes={m.cashUnits[`stacker${it}f`]}
denomination={getCashoutSettings(m.id)[`stacker${it}f`]}
threshold={
fillingPercentageSettings[
`fillingPercentageStacker${it}f`
]
}
capacity={cashUnitCapacity[m.model].stacker}
/>
<CashOutLite
width={'100%'}
currency={{ code: fiatCurrency }}
notes={m.cashUnits[`stacker${it}r`]}
denomination={getCashoutSettings(m.id)[`stacker${it}r`]}
threshold={
fillingPercentageSettings[
`fillingPercentageStacker${it}r`
]
}
capacity={cashUnitCapacity[m.model].stacker}
/>
{it !== m.numberOfStackers && (
<span className={classes.verticalLine} />
)}
</>
))(R.range(1, m.numberOfStackers + 1))}
</div>
</div>
)
},
inputProps: {
decimalPlaces: 0
}
},
{
name: 'edit',
header: 'Edit',
width: 90,
textAlign: 'center',
view: m => {
return (
<IconButton
onClick={() => {
setMachineId(m.id)
setWizard(true)
}}>
<EditIcon />
</IconButton>
)
}
} }
] ]
R.until(
R.gt(R.__, getMaxNumberOfCassettesMap(machines)),
it => {
elements.push({
name: `cassette${it}`,
header: `Cassette ${it}`,
width: widthsByCashUnits[getMaxNumberOfCashUnits(machines)]?.cassette,
stripe: true,
doubleHeader: 'Cash-out',
view: (_, { id, model, cashUnits }) => (
<CashOut
className={classes.cashbox}
denomination={getCashoutSettings(id)?.[`cassette${it}`]}
currency={{ code: fiatCurrency }}
notes={cashUnits[`cassette${it}`]}
capacity={cashUnitCapacity[model].cassette}
width={
widthsByCashUnits[getMaxNumberOfCashUnits(machines)]?.unitGraph
}
threshold={
fillingPercentageSettings[`fillingPercentageCassette${it}`]
}
/>
),
isHidden: ({ numberOfCassettes }) => it > numberOfCassettes,
input: CashCassetteInput,
inputProps: {
decimalPlaces: 0,
width:
widthsByCashUnits[getMaxNumberOfCashUnits(machines)]?.unitGraph,
inputClassName: classes.cashbox
}
})
return R.add(1, it)
},
1
)
R.until(
R.gt(R.__, getMaxNumberOfStackersMap(machines)),
it => {
elements.push(
{
name: `stacker${it}f`,
header: `Stacker ${it}F`,
width: widthsByCashUnits[getMaxNumberOfCashUnits(machines)]?.cassette,
stripe: true,
view: (_, { id, model, cashUnits }) => (
<CashOut
className={classes.cashbox}
denomination={getCashoutSettings(id)?.[`stacker${it}f`]}
currency={{ code: fiatCurrency }}
notes={cashUnits[`stacker${it}f`]}
capacity={
it === 1
? cashUnitCapacity[model].stacker -
cashUnitCapacity[model].escrow
: cashUnitCapacity[model].stacker
}
width={
widthsByCashUnits[getMaxNumberOfCashUnits(machines)]?.unitGraph
}
threshold={
fillingPercentageSettings[`fillingPercentageStacker${it}f`]
}
/>
),
isHidden: ({ numberOfStackers }) => it > numberOfStackers,
input: CashCassetteInput,
inputProps: {
decimalPlaces: 0,
width:
widthsByCashUnits[getMaxNumberOfCashUnits(machines)]?.unitGraph,
inputClassName: classes.cashbox
}
},
{
name: `stacker${it}r`,
header: `Stacker ${it}R`,
width: widthsByCashUnits[getMaxNumberOfCashUnits(machines)]?.cassette,
stripe: true,
view: (_, { id, model, cashUnits }) => (
<CashOut
className={classes.cashbox}
denomination={getCashoutSettings(id)?.[`stacker${it}r`]}
currency={{ code: fiatCurrency }}
notes={cashUnits[`stacker${it}r`]}
capacity={cashUnitCapacity[model].stacker}
width={
widthsByCashUnits[getMaxNumberOfCashUnits(machines)]?.unitGraph
}
threshold={
fillingPercentageSettings[`fillingPercentageStacker${it}r`]
}
/>
),
isHidden: ({ numberOfStackers }) => it > numberOfStackers,
input: CashCassetteInput,
inputProps: {
decimalPlaces: 0,
width:
widthsByCashUnits[getMaxNumberOfCashUnits(machines)]?.unitGraph,
inputClassName: classes.cashbox
}
}
)
return R.add(1, it)
},
1
)
elements.push({
name: 'edit',
header: 'Edit',
width: widthsByCashUnits[getMaxNumberOfCashUnits(machines)]?.editWidth,
textAlign: 'center',
view: (_, { id }) => {
return (
<IconButton
onClick={() => {
setMachineId(id)
setWizard(true)
}}>
<EditIcon />
</IconButton>
)
}
})
return elements return elements
} }

View file

@ -11,7 +11,7 @@ import Locales from 'src/pages/Locales'
import IndividualDiscounts from 'src/pages/LoyaltyPanel/IndividualDiscounts' import IndividualDiscounts from 'src/pages/LoyaltyPanel/IndividualDiscounts'
import PromoCodes from 'src/pages/LoyaltyPanel/PromoCodes' import PromoCodes from 'src/pages/LoyaltyPanel/PromoCodes'
import MachineLogs from 'src/pages/MachineLogs' import MachineLogs from 'src/pages/MachineLogs'
import CashCassettes from 'src/pages/Maintenance/CashCassettes' import CashUnits from 'src/pages/Maintenance/CashUnits'
import MachineStatus from 'src/pages/Maintenance/MachineStatus' import MachineStatus from 'src/pages/Maintenance/MachineStatus'
import Notifications from 'src/pages/Notifications/Notifications' import Notifications from 'src/pages/Notifications/Notifications'
import CoinAtmRadar from 'src/pages/OperatorInfo/CoinATMRadar' import CoinAtmRadar from 'src/pages/OperatorInfo/CoinATMRadar'
@ -48,11 +48,11 @@ const getLamassuRoutes = () => [
}, },
children: [ children: [
{ {
key: 'cash_cassettes', key: 'cash_units',
label: 'Cash Cassettes', label: 'Cash Units',
route: '/maintenance/cash-cassettes', route: '/maintenance/cash-units',
allowedRoles: [ROLES.USER, ROLES.SUPERUSER], allowedRoles: [ROLES.USER, ROLES.SUPERUSER],
component: CashCassettes component: CashUnits
}, },
{ {
key: 'funding', key: 'funding',

View file

@ -13,7 +13,7 @@ import Locales from 'src/pages/Locales'
import IndividualDiscounts from 'src/pages/LoyaltyPanel/IndividualDiscounts' import IndividualDiscounts from 'src/pages/LoyaltyPanel/IndividualDiscounts'
import PromoCodes from 'src/pages/LoyaltyPanel/PromoCodes' import PromoCodes from 'src/pages/LoyaltyPanel/PromoCodes'
import MachineLogs from 'src/pages/MachineLogs' import MachineLogs from 'src/pages/MachineLogs'
import CashCassettes from 'src/pages/Maintenance/CashCassettes' import CashUnits from 'src/pages/Maintenance/CashUnits'
import MachineStatus from 'src/pages/Maintenance/MachineStatus' import MachineStatus from 'src/pages/Maintenance/MachineStatus'
import Notifications from 'src/pages/Notifications/Notifications' import Notifications from 'src/pages/Notifications/Notifications'
import CoinAtmRadar from 'src/pages/OperatorInfo/CoinATMRadar' import CoinAtmRadar from 'src/pages/OperatorInfo/CoinATMRadar'
@ -48,11 +48,11 @@ const getPazuzRoutes = () => [
}, },
children: [ children: [
{ {
key: 'cash_cassettes', key: 'cash_units',
label: 'Cash Cassettes', label: 'Cash Units',
route: '/maintenance/cash-cassettes', route: '/maintenance/cash-units',
allowedRoles: [ROLES.USER, ROLES.SUPERUSER], allowedRoles: [ROLES.USER, ROLES.SUPERUSER],
component: CashCassettes component: CashUnits
}, },
{ {
key: 'logs', key: 'logs',