feat: add cashin bill counter
fix: fiat amount formatting
This commit is contained in:
parent
219dca7f90
commit
98a2797494
17 changed files with 239 additions and 218 deletions
|
|
@ -68,4 +68,10 @@ function getBillsByBatchId (id) {
|
|||
return db.any(sql, [id])
|
||||
}
|
||||
|
||||
module.exports = { createCashboxBatch, updateMachineWithBatch, getBatches, getBillsByBatchId, editBatchById }
|
||||
module.exports = {
|
||||
createCashboxBatch,
|
||||
updateMachineWithBatch,
|
||||
getBatches,
|
||||
getBillsByBatchId,
|
||||
editBatchById
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,7 +2,9 @@ const bills = require('../../services/bills')
|
|||
|
||||
const resolvers = {
|
||||
Query: {
|
||||
bills: () => bills.getBills()
|
||||
bills: () => bills.getBills(),
|
||||
looseBills: () => bills.getLooseBills(),
|
||||
looseBillsByMachine: (...[, { deviceId }]) => bills.getLooseBillsByMachine(deviceId)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -2,14 +2,17 @@ const { gql } = require('apollo-server-express')
|
|||
|
||||
const typeDef = gql`
|
||||
type Bill {
|
||||
id: ID
|
||||
fiat: Int
|
||||
deviceId: ID
|
||||
created: Date
|
||||
cashbox: Int
|
||||
cashboxBatchId: ID
|
||||
}
|
||||
|
||||
type Query {
|
||||
bills: [Bill] @auth
|
||||
looseBills: [Bill] @auth
|
||||
looseBillsByMachine(deviceId: ID): [Bill] @auth
|
||||
}
|
||||
`
|
||||
|
||||
|
|
|
|||
|
|
@ -1,25 +1,37 @@
|
|||
const _ = require('lodash/fp')
|
||||
|
||||
const db = require('../../db')
|
||||
|
||||
// Get all bills with device id
|
||||
const getBills = () => {
|
||||
return Promise.reject(new Error('This functionality hasn\'t been implemented yet'))
|
||||
/* return db.any(`
|
||||
SELECT d.device_id, b.fiat, b.created, d.cashbox
|
||||
FROM cash_in_txs
|
||||
INNER JOIN bills AS b ON b.cash_in_txs_id = cash_in_txs.id
|
||||
INNER JOIN devices as d ON d.device_id = cash_in_txs.device_id
|
||||
ORDER BY device_id, created DESC`
|
||||
)
|
||||
.then(res => {
|
||||
return res.map(item => ({
|
||||
fiat: item.fiat,
|
||||
deviceId: item.device_id,
|
||||
cashbox: item.cashbox,
|
||||
created: item.created
|
||||
}))
|
||||
}) */
|
||||
const sql = `SELECT b.id, b.fiat, b.fiat_code, b.created, b.cashbox_batch_id, cit.device_id AS device_id FROM bills b LEFT OUTER JOIN (
|
||||
SELECT id, device_id FROM cash_in_txs
|
||||
) AS cit ON cit.id = b.cash_in_txs_id`
|
||||
|
||||
return db.any(sql)
|
||||
.then(res => _.map(_.mapKeys(_.camelCase), res))
|
||||
}
|
||||
|
||||
function getLooseBills () {
|
||||
const sql = `SELECT b.id, b.fiat, b.fiat_code, b.created, b.cashbox_batch_id, cit.device_id AS device_id FROM bills b LEFT OUTER JOIN (
|
||||
SELECT id, device_id FROM cash_in_txs
|
||||
) AS cit ON cit.id = b.cash_in_txs_id WHERE b.cashbox_batch_id IS NULL`
|
||||
|
||||
return db.any(sql)
|
||||
.then(res => _.map(_.mapKeys(_.camelCase), res))
|
||||
}
|
||||
|
||||
function getLooseBillsByMachine (machineId) {
|
||||
const sql = `SELECT b.id, b.fiat, b.fiat_code, b.created, b.cashbox_batch_id, cit.device_id AS device_id FROM bills b LEFT OUTER JOIN (
|
||||
SELECT id, device_id FROM cash_in_txs WHERE device_id = $1
|
||||
) AS cit ON cit.id = b.cash_in_txs_id WHERE b.cashbox_batch_id IS NULL`
|
||||
|
||||
return db.any(sql, [machineId])
|
||||
.then(res => _.map(_.mapKeys(_.camelCase), res))
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
getBills
|
||||
getBills,
|
||||
getLooseBills,
|
||||
getLooseBillsByMachine
|
||||
}
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@ import React from 'react'
|
|||
|
||||
import Chip from 'src/components/Chip'
|
||||
import { Info2, Label1, Label2 } from 'src/components/typography'
|
||||
import { numberToFiatAmount } from 'src/utils/number'
|
||||
|
||||
import { cashboxStyles, gridStyles } from './Cashbox.styles'
|
||||
|
||||
|
|
@ -64,11 +65,9 @@ const CashIn = ({ currency, notes, total }) => {
|
|||
<Info2 className={classes.noMarginText}>{notes} notes</Info2>
|
||||
</div>
|
||||
<div className={classes.innerRow}>
|
||||
{/* Feature on hold until this can be calculated
|
||||
<Label1 className={classes.noMarginText}>
|
||||
{total} {currency.code}
|
||||
</Label1>
|
||||
*/}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
|
@ -112,7 +111,7 @@ const CashOut = ({
|
|||
</div>
|
||||
<div className={classes.innerRow}>
|
||||
<Label1 className={classes.noMarginText}>
|
||||
{notes * denomination} {currency.code}
|
||||
{numberToFiatAmount(notes * denomination)} {currency.code}
|
||||
</Label1>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -15,6 +15,7 @@ import { ReactComponent as DashLogo } from 'src/styling/logos/icon-dash-colour.s
|
|||
import { ReactComponent as EthereumLogo } from 'src/styling/logos/icon-ethereum-colour.svg'
|
||||
import { ReactComponent as LitecoinLogo } from 'src/styling/logos/icon-litecoin-colour.svg'
|
||||
import { ReactComponent as ZCashLogo } from 'src/styling/logos/icon-zcash-colour.svg'
|
||||
import { numberToFiatAmount } from 'src/utils/number'
|
||||
|
||||
import styles from './ATMWallet.styles'
|
||||
|
||||
|
|
@ -51,9 +52,6 @@ const GET_OPERATOR_BY_USERNAME = gql`
|
|||
}
|
||||
`
|
||||
|
||||
const formatCurrency = amount =>
|
||||
amount.toLocaleString('en-US', { maximumFractionDigits: 2 })
|
||||
|
||||
const CHIPS_PER_ROW = 6
|
||||
|
||||
const Assets = ({ balance, wallets, currency }) => {
|
||||
|
|
@ -69,7 +67,7 @@ const Assets = ({ balance, wallets, currency }) => {
|
|||
<P className={classes.fieldHeader}>Available balance</P>
|
||||
<div className={classes.totalAssetWrapper}>
|
||||
<Info2 noMargin className={classes.fieldValue}>
|
||||
{formatCurrency(balance)}
|
||||
{numberToFiatAmount(balance)}
|
||||
</Info2>
|
||||
<Info2 noMargin className={classes.fieldCurrency}>
|
||||
{R.toUpper(currency)}
|
||||
|
|
@ -81,7 +79,7 @@ const Assets = ({ balance, wallets, currency }) => {
|
|||
<P className={classes.fieldHeader}>Total balance in wallets</P>
|
||||
<div className={classes.totalAssetWrapper}>
|
||||
<Info2 noMargin className={classes.fieldValue}>
|
||||
{formatCurrency(walletFiatSum())}
|
||||
{numberToFiatAmount(walletFiatSum())}
|
||||
</Info2>
|
||||
<Info2 noMargin className={classes.fieldCurrency}>
|
||||
{R.toUpper(currency)}
|
||||
|
|
@ -93,7 +91,7 @@ const Assets = ({ balance, wallets, currency }) => {
|
|||
<P className={classes.fieldHeader}>Total assets</P>
|
||||
<div className={classes.totalAssetWrapper}>
|
||||
<Info2 noMargin className={classes.fieldValue}>
|
||||
{formatCurrency(balance)}
|
||||
{numberToFiatAmount(balance)}
|
||||
</Info2>
|
||||
<Info2 noMargin className={classes.fieldCurrency}>
|
||||
{R.toUpper(currency)}
|
||||
|
|
@ -144,17 +142,11 @@ const WalletInfoChip = ({ wallet, currency }) => {
|
|||
<div className={classes.walletValueWrapper}>
|
||||
<Label2 className={classes.fieldHeader}>{wallet.name} value</Label2>
|
||||
<Label2 className={classes.walletValue}>
|
||||
{wallet.amount.toFixed(1).toLocaleString('en-US', {
|
||||
maximumFractionDigits: 2
|
||||
})}{' '}
|
||||
{wallet.cryptoCode}
|
||||
{numberToFiatAmount(wallet.amount.toFixed(1))} {wallet.cryptoCode}
|
||||
</Label2>
|
||||
<Label2 className={classes.fieldHeader}>Hedged value</Label2>
|
||||
<Label2 className={classes.walletValue}>
|
||||
{wallet.fiatValue.toLocaleString('en-US', {
|
||||
maximumFractionDigits: 2
|
||||
})}{' '}
|
||||
{currency}
|
||||
{numberToFiatAmount(wallet.fiatValue)} {currency}
|
||||
</Label2>
|
||||
</div>
|
||||
</Paper>
|
||||
|
|
|
|||
|
|
@ -9,13 +9,11 @@ import { Tooltip } from 'src/components/Tooltip'
|
|||
import TitleSection from 'src/components/layout/TitleSection'
|
||||
import DataTable from 'src/components/tables/DataTable'
|
||||
import { H4, Info2, P } from 'src/components/typography'
|
||||
import { numberToFiatAmount } from 'src/utils/number'
|
||||
import { formatDate } from 'src/utils/timezones'
|
||||
|
||||
import styles from './Accounting.styles'
|
||||
|
||||
const formatCurrency = amount =>
|
||||
amount.toLocaleString('en-US', { maximumFractionDigits: 2 })
|
||||
|
||||
const useStyles = makeStyles(styles)
|
||||
|
||||
const GET_OPERATOR_BY_USERNAME = gql`
|
||||
|
|
@ -64,7 +62,7 @@ const Assets = ({ balance, hedgingReserve, currency }) => {
|
|||
<P className={classes.fieldHeader}>Pazuz fiat balance</P>
|
||||
<div className={classes.totalAssetWrapper}>
|
||||
<Info2 noMargin className={classes.fieldValue}>
|
||||
{formatCurrency(balance)}
|
||||
{numberToFiatAmount(balance)}
|
||||
</Info2>
|
||||
<Info2 noMargin className={classes.fieldCurrency}>
|
||||
{R.toUpper(currency)}
|
||||
|
|
@ -76,7 +74,7 @@ const Assets = ({ balance, hedgingReserve, currency }) => {
|
|||
<P className={classes.fieldHeader}>Hedging reserve</P>
|
||||
<div className={classes.totalAssetWrapper}>
|
||||
<Info2 noMargin className={classes.fieldValue}>
|
||||
{formatCurrency(hedgingReserve)}
|
||||
{numberToFiatAmount(hedgingReserve)}
|
||||
</Info2>
|
||||
<Info2 noMargin className={classes.fieldCurrency}>
|
||||
{R.toUpper(currency)}
|
||||
|
|
@ -88,7 +86,7 @@ const Assets = ({ balance, hedgingReserve, currency }) => {
|
|||
<P className={classes.fieldHeader}>Available balance</P>
|
||||
<div className={classes.totalAssetWrapper}>
|
||||
<Info2 noMargin className={classes.fieldValue}>
|
||||
{formatCurrency(balance - hedgingReserve)}
|
||||
{numberToFiatAmount(balance - hedgingReserve)}
|
||||
</Info2>
|
||||
<Info2 noMargin className={classes.fieldCurrency}>
|
||||
{R.toUpper(currency)}
|
||||
|
|
@ -143,7 +141,7 @@ const Accounting = () => {
|
|||
size: 'sm',
|
||||
textAlign: 'right',
|
||||
view: it =>
|
||||
`${formatCurrency(it.fiatAmount)} ${R.toUpper(it.fiatCurrency)}`
|
||||
`${numberToFiatAmount(it.fiatAmount)} ${R.toUpper(it.fiatCurrency)}`
|
||||
},
|
||||
{
|
||||
header: 'Balance after operation',
|
||||
|
|
@ -151,7 +149,9 @@ const Accounting = () => {
|
|||
size: 'sm',
|
||||
textAlign: 'right',
|
||||
view: it =>
|
||||
`${formatCurrency(it.fiatBalanceAfter)} ${R.toUpper(it.fiatCurrency)}`
|
||||
`${numberToFiatAmount(it.fiatBalanceAfter)} ${R.toUpper(
|
||||
it.fiatCurrency
|
||||
)}`
|
||||
},
|
||||
{
|
||||
header: 'Date',
|
||||
|
|
|
|||
|
|
@ -13,6 +13,7 @@ import { ReactComponent as DownIcon } from 'src/styling/icons/dashboard/down.svg
|
|||
import { ReactComponent as EqualIcon } from 'src/styling/icons/dashboard/equal.svg'
|
||||
import { ReactComponent as UpIcon } from 'src/styling/icons/dashboard/up.svg'
|
||||
import { fromNamespace } from 'src/utils/config'
|
||||
import { numberToFiatAmount } from 'src/utils/number'
|
||||
import { DAY, WEEK, MONTH } from 'src/utils/time'
|
||||
|
||||
import styles from './Analytics.styles'
|
||||
|
|
@ -97,9 +98,7 @@ const OverviewEntry = ({ label, value, oldValue, currency }) => {
|
|||
<div className={classes.overviewEntry}>
|
||||
<P noMargin>{label}</P>
|
||||
<Info2 noMargin className={classes.overviewFieldWrapper}>
|
||||
<span>
|
||||
{value.toLocaleString('en-US', { maximumFractionDigits: 2 })}
|
||||
</span>
|
||||
<span>{numberToFiatAmount(value)}</span>
|
||||
{!!currency && ` ${currency}`}
|
||||
</Info2>
|
||||
<span className={classes.overviewGrowth}>
|
||||
|
|
@ -107,7 +106,7 @@ const OverviewEntry = ({ label, value, oldValue, currency }) => {
|
|||
{R.lt(growthRate, 0) && <DownIcon height={10} />}
|
||||
{R.equals(growthRate, 0) && <EqualIcon height={10} />}
|
||||
<P noMargin className={classnames(growthClasses)}>
|
||||
{growthRate.toLocaleString('en-US', { maximumFractionDigits: 2 })}%
|
||||
{numberToFiatAmount(growthRate)}%
|
||||
</P>
|
||||
</span>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -6,6 +6,7 @@ import React, { memo } from 'react'
|
|||
import { Info2, Label3, P } from 'src/components/typography'
|
||||
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 { numberToFiatAmount } from 'src/utils/number'
|
||||
import { singularOrPlural } from 'src/utils/string'
|
||||
import { formatDate, formatDateNonUtc } from 'src/utils/timezones'
|
||||
|
||||
|
|
@ -13,9 +14,6 @@ import styles from './GraphTooltip.styles'
|
|||
|
||||
const useStyles = makeStyles(styles)
|
||||
|
||||
const formatCurrency = amount =>
|
||||
amount.toLocaleString('en-US', { maximumFractionDigits: 2 })
|
||||
|
||||
const GraphTooltip = ({
|
||||
coords,
|
||||
data,
|
||||
|
|
@ -67,7 +65,7 @@ const GraphTooltip = ({
|
|||
{singularOrPlural(R.length(data), 'transaction', 'transactions')}
|
||||
</P>
|
||||
<P noMargin className={classes.dotOtTransactionVolume}>
|
||||
{formatCurrency(transactions.volume)} {currency} in volume
|
||||
{numberToFiatAmount(transactions.volume)} {currency} in volume
|
||||
</P>
|
||||
<div className={classes.dotOtTransactionClasses}>
|
||||
<Label3 noMargin>
|
||||
|
|
|
|||
|
|
@ -14,8 +14,10 @@ import React, { useContext } from 'react'
|
|||
import AppContext from 'src/AppContext'
|
||||
import TitleSection from 'src/components/layout/TitleSection'
|
||||
import { H4, Label2, P, Info2 } from 'src/components/typography'
|
||||
import { numberToFiatAmount } from 'src/utils/number'
|
||||
|
||||
import styles from './Assets.styles'
|
||||
|
||||
const useStyles = makeStyles(styles)
|
||||
|
||||
const GET_OPERATOR_BY_USERNAME = gql`
|
||||
|
|
@ -105,7 +107,7 @@ const AssetsAmountTable = ({ title, data = [], numToRender }) => {
|
|||
</Cell>
|
||||
<Cell align="right">
|
||||
<P>{`${selectAmountPrefix(asset)}
|
||||
${formatCurrency(Math.abs(asset.amount))} ${
|
||||
${numberToFiatAmount(Math.abs(asset.amount))} ${
|
||||
asset.currency
|
||||
}`}</P>
|
||||
</Cell>
|
||||
|
|
@ -117,7 +119,9 @@ const AssetsAmountTable = ({ title, data = [], numToRender }) => {
|
|||
<Info2>{`Total ${R.toLower(title)}`}</Info2>
|
||||
</Cell>
|
||||
<Cell align="right">
|
||||
<Info2>{`${formatCurrency(totalAmount)} ${currency}`}</Info2>
|
||||
<Info2>{`${numberToFiatAmount(
|
||||
totalAmount
|
||||
)} ${currency}`}</Info2>
|
||||
</Cell>
|
||||
</TableRow>
|
||||
</TableBody>
|
||||
|
|
@ -128,9 +132,6 @@ const AssetsAmountTable = ({ title, data = [], numToRender }) => {
|
|||
)
|
||||
}
|
||||
|
||||
const formatCurrency = amount =>
|
||||
amount.toLocaleString('en-US', { maximumFractionDigits: 2 })
|
||||
|
||||
const Assets = () => {
|
||||
const classes = useStyles()
|
||||
const { userData } = useContext(AppContext)
|
||||
|
|
|
|||
|
|
@ -82,7 +82,7 @@ const SET_CASSETTE_BILLS = gql`
|
|||
}
|
||||
`
|
||||
|
||||
const CashCassettes = ({ machine, config, refetchData }) => {
|
||||
const CashCassettes = ({ machine, config, refetchData, bills }) => {
|
||||
const classes = useStyles()
|
||||
|
||||
const [wizard, setWizard] = useState(false)
|
||||
|
|
@ -105,7 +105,11 @@ const CashCassettes = ({ machine, config, refetchData }) => {
|
|||
width: widthsByNumberOfCassettes[numberOfCassettes].cashbox,
|
||||
stripe: false,
|
||||
view: value => (
|
||||
<CashIn currency={{ code: fiatCurrency }} notes={value} total={0} />
|
||||
<CashIn
|
||||
currency={{ code: fiatCurrency }}
|
||||
notes={value}
|
||||
total={R.sum(R.map(it => it.fiat)(bills))}
|
||||
/>
|
||||
),
|
||||
input: NumberInput,
|
||||
inputProps: {
|
||||
|
|
|
|||
|
|
@ -46,6 +46,12 @@ const GET_INFO = gql`
|
|||
note
|
||||
}
|
||||
}
|
||||
looseBillsByMachine(deviceId: $deviceId) {
|
||||
id
|
||||
fiat
|
||||
deviceId
|
||||
created
|
||||
}
|
||||
config
|
||||
}
|
||||
`
|
||||
|
|
@ -59,12 +65,14 @@ const Machines = () => {
|
|||
deviceId: getMachineID(location.pathname)
|
||||
}
|
||||
})
|
||||
|
||||
const classes = useStyles()
|
||||
|
||||
const timezone = R.path(['config', 'locale_timezone'], data) ?? {}
|
||||
|
||||
const machine = R.path(['machine'])(data) ?? {}
|
||||
const config = R.path(['config'])(data) ?? {}
|
||||
const bills = R.path(['looseBillsByMachine'])(data) ?? []
|
||||
|
||||
const machineName = R.path(['name'])(machine) ?? null
|
||||
const machineID = R.path(['deviceId'])(machine) ?? null
|
||||
|
|
@ -102,6 +110,7 @@ const Machines = () => {
|
|||
refetchData={refetch}
|
||||
machine={machine}
|
||||
config={config ?? false}
|
||||
bills={bills}
|
||||
/>
|
||||
</div>
|
||||
<div className={classes.transactionsItem}>
|
||||
|
|
|
|||
|
|
@ -75,24 +75,21 @@ const GET_MACHINES_AND_CONFIG = gql`
|
|||
numberOfCassettes
|
||||
}
|
||||
config
|
||||
looseBills {
|
||||
id
|
||||
fiat
|
||||
created
|
||||
deviceId
|
||||
}
|
||||
}
|
||||
`
|
||||
|
||||
const SAVE_CONFIG = gql`
|
||||
mutation Save($config: JSONObject) {
|
||||
saveConfig(config: $config)
|
||||
}
|
||||
`
|
||||
|
||||
/*
|
||||
// for cash in total calculation
|
||||
bills {
|
||||
fiat
|
||||
deviceId
|
||||
created
|
||||
cashbox
|
||||
}
|
||||
*/
|
||||
|
||||
const SET_CASSETTE_BILLS = gql`
|
||||
mutation MachineAction(
|
||||
$deviceId: ID!
|
||||
|
|
@ -128,7 +125,7 @@ const CashCassettes = () => {
|
|||
const [editingSchema, setEditingSchema] = useState(null)
|
||||
const [selectedRadio, setSelectedRadio] = useState(null)
|
||||
|
||||
const { data } = useQuery(GET_MACHINES_AND_CONFIG)
|
||||
const { data, loading: dataLoading } = useQuery(GET_MACHINES_AND_CONFIG)
|
||||
const [wizard, setWizard] = useState(false)
|
||||
const [machineId, setMachineId] = useState('')
|
||||
|
||||
|
|
@ -143,9 +140,11 @@ const CashCassettes = () => {
|
|||
refetchQueries: () => ['getData']
|
||||
})
|
||||
|
||||
const bills = R.groupBy(bill => bill.deviceId)(R.path(['bills'])(data) ?? [])
|
||||
const bills = R.groupBy(bill => bill.deviceId)(
|
||||
R.path(['looseBills'])(data) ?? []
|
||||
)
|
||||
const deviceIds = R.uniq(
|
||||
R.map(R.prop('deviceId'))(R.path(['bills'])(data) ?? [])
|
||||
R.map(R.prop('deviceId'))(R.path(['looseBills'])(data) ?? [])
|
||||
)
|
||||
const cashout = data?.config && fromNamespace('cashOut')(data.config)
|
||||
const locale = data?.config && fromNamespace('locale')(data.config)
|
||||
|
|
@ -206,8 +205,12 @@ const CashCassettes = () => {
|
|||
name: 'cashbox',
|
||||
header: 'Cash box',
|
||||
width: maxNumberOfCassettes > 2 ? 140 : 280,
|
||||
view: value => (
|
||||
<CashIn currency={{ code: fiatCurrency }} notes={value} total={0} />
|
||||
view: (value, { id }) => (
|
||||
<CashIn
|
||||
currency={{ code: fiatCurrency }}
|
||||
notes={value}
|
||||
total={R.sum(R.map(it => it.fiat, bills[id]))}
|
||||
/>
|
||||
),
|
||||
input: NumberInput,
|
||||
inputProps: {
|
||||
|
|
@ -222,7 +225,7 @@ const CashCassettes = () => {
|
|||
elements.push({
|
||||
name: `cassette${it}`,
|
||||
header: `Cassette ${it}`,
|
||||
width: (maxNumberOfCassettes > 2 ? 700 : 560) / maxNumberOfCassettes,
|
||||
width: (maxNumberOfCassettes > 2 ? 560 : 650) / maxNumberOfCassettes,
|
||||
stripe: true,
|
||||
doubleHeader: 'Cash-out',
|
||||
view: (value, { id }) => (
|
||||
|
|
@ -268,121 +271,124 @@ const CashCassettes = () => {
|
|||
})
|
||||
|
||||
return (
|
||||
<>
|
||||
<TitleSection
|
||||
title="Cash Boxes & Cassettes"
|
||||
button={{
|
||||
text: 'Cash box history',
|
||||
icon: HistoryIcon,
|
||||
inverseIcon: ReverseHistoryIcon,
|
||||
toggle: setShowHistory
|
||||
}}
|
||||
iconClassName={classes.listViewButton}
|
||||
className={classes.tableWidth}>
|
||||
{!showHistory && (
|
||||
<Box alignItems="center" justifyContent="flex-end">
|
||||
<Label1 className={classes.cashboxReset}>Cash box resets</Label1>
|
||||
<Box
|
||||
display="flex"
|
||||
alignItems="center"
|
||||
justifyContent="flex-end"
|
||||
mr="-4px">
|
||||
{cashboxReset && (
|
||||
<P className={classes.selection}>
|
||||
{onlyFirstToUpper(cashboxReset)}
|
||||
</P>
|
||||
)}
|
||||
<IconButton
|
||||
onClick={() => setEditingSchema(true)}
|
||||
className={classes.button}>
|
||||
<EditIcon />
|
||||
</IconButton>
|
||||
</Box>
|
||||
</Box>
|
||||
)}
|
||||
</TitleSection>
|
||||
<div className={classes.tableContainer}>
|
||||
{!showHistory && (
|
||||
<>
|
||||
<EditableTable
|
||||
error={error?.message}
|
||||
name="cashboxes"
|
||||
stripeWhen={isCashOutDisabled}
|
||||
elements={elements}
|
||||
data={machines}
|
||||
validationSchema={ValidationSchema}
|
||||
tbodyWrapperClass={classes.tBody}
|
||||
/>
|
||||
|
||||
{data && R.isEmpty(machines) && (
|
||||
<EmptyTable message="No machines so far" />
|
||||
)}
|
||||
</>
|
||||
)}
|
||||
{showHistory && (
|
||||
<CashboxHistory machines={machines} currency={fiatCurrency} />
|
||||
)}
|
||||
</div>
|
||||
<CashCassettesFooter
|
||||
currencyCode={fiatCurrency}
|
||||
machines={machines}
|
||||
config={config}
|
||||
bills={bills}
|
||||
deviceIds={deviceIds}
|
||||
/>
|
||||
{wizard && (
|
||||
<Wizard
|
||||
machine={R.find(R.propEq('id', machineId))(machines)}
|
||||
cashoutSettings={getCashoutSettings(machineId)}
|
||||
onClose={() => {
|
||||
setWizard(false)
|
||||
!dataLoading && (
|
||||
<>
|
||||
<TitleSection
|
||||
title="Cash Boxes & Cassettes"
|
||||
button={{
|
||||
text: 'Cash box history',
|
||||
icon: HistoryIcon,
|
||||
inverseIcon: ReverseHistoryIcon,
|
||||
toggle: setShowHistory
|
||||
}}
|
||||
error={error?.message}
|
||||
save={onSave}
|
||||
locale={locale}
|
||||
iconClassName={classes.listViewButton}
|
||||
className={classes.tableWidth}>
|
||||
{!showHistory && (
|
||||
<Box alignItems="center" justifyContent="flex-end">
|
||||
<Label1 className={classes.cashboxReset}>Cash box resets</Label1>
|
||||
<Box
|
||||
display="flex"
|
||||
alignItems="center"
|
||||
justifyContent="end"
|
||||
mr="-4px">
|
||||
{cashboxReset && (
|
||||
<P className={classes.selection}>
|
||||
{onlyFirstToUpper(cashboxReset)}
|
||||
</P>
|
||||
)}
|
||||
<IconButton
|
||||
onClick={() => setEditingSchema(true)}
|
||||
className={classes.button}>
|
||||
<EditIcon />
|
||||
</IconButton>
|
||||
</Box>
|
||||
</Box>
|
||||
)}
|
||||
</TitleSection>
|
||||
<div className={classes.tableContainer}>
|
||||
{!showHistory && (
|
||||
<>
|
||||
<EditableTable
|
||||
error={error?.message}
|
||||
name="cashboxes"
|
||||
stripeWhen={isCashOutDisabled}
|
||||
elements={elements}
|
||||
data={machines}
|
||||
validationSchema={ValidationSchema}
|
||||
tbodyWrapperClass={classes.tBody}
|
||||
/>
|
||||
|
||||
{data && R.isEmpty(machines) && (
|
||||
<EmptyTable message="No machines so far" />
|
||||
)}
|
||||
</>
|
||||
)}
|
||||
{showHistory && (
|
||||
<CashboxHistory machines={machines} currency={fiatCurrency} />
|
||||
)}
|
||||
</div>
|
||||
<CashCassettesFooter
|
||||
currencyCode={fiatCurrency}
|
||||
machines={machines}
|
||||
config={config}
|
||||
bills={bills}
|
||||
deviceIds={deviceIds}
|
||||
/>
|
||||
)}
|
||||
{editingSchema && (
|
||||
<Modal
|
||||
title={'Cash box resets'}
|
||||
width={478}
|
||||
handleClose={() => setEditingSchema(null)}
|
||||
open={true}>
|
||||
<P className={classes.descriptions}>
|
||||
We can automatically assume you emptied a bill validator's cash box
|
||||
when the machine detects that it has been removed.
|
||||
</P>
|
||||
<RadioGroup
|
||||
name="set-automatic-reset"
|
||||
value={selectedRadio ?? cashboxReset}
|
||||
options={[radioButtonOptions[0]]}
|
||||
onChange={handleRadioButtons}
|
||||
className={classes.radioButtons}
|
||||
{wizard && (
|
||||
<Wizard
|
||||
machine={R.find(R.propEq('id', machineId), machines)}
|
||||
cashoutSettings={getCashoutSettings(machineId)}
|
||||
onClose={() => {
|
||||
setWizard(false)
|
||||
}}
|
||||
error={error?.message}
|
||||
save={onSave}
|
||||
locale={locale}
|
||||
/>
|
||||
<P className={classes.descriptions}>
|
||||
Assume the cash box is emptied whenever it's removed, creating a new
|
||||
batch on the history screen and setting its current balance to zero.
|
||||
</P>
|
||||
<RadioGroup
|
||||
name="set-manual-reset"
|
||||
value={selectedRadio ?? cashboxReset}
|
||||
options={[radioButtonOptions[1]]}
|
||||
onChange={handleRadioButtons}
|
||||
className={classes.radioButtons}
|
||||
/>
|
||||
<P className={classes.descriptions}>
|
||||
Cash boxes won't be assumed emptied when removed, nor their counts
|
||||
modified. Instead, to update the count and create a new batch,
|
||||
you'll click the 'Edit' button on this panel.
|
||||
</P>
|
||||
<DialogActions className={classes.actions}>
|
||||
<Button onClick={() => saveCashboxOption(selectedRadio)}>
|
||||
Confirm
|
||||
</Button>
|
||||
</DialogActions>
|
||||
</Modal>
|
||||
)}
|
||||
</>
|
||||
)}
|
||||
{editingSchema && (
|
||||
<Modal
|
||||
title={'Cash box resets'}
|
||||
width={478}
|
||||
handleClose={() => setEditingSchema(null)}
|
||||
open={true}>
|
||||
<P className={classes.descriptions}>
|
||||
We can automatically assume you emptied a bill validator's cash
|
||||
box when the machine detects that it has been removed.
|
||||
</P>
|
||||
<RadioGroup
|
||||
name="set-automatic-reset"
|
||||
value={selectedRadio ?? cashboxReset}
|
||||
options={[radioButtonOptions[0]]}
|
||||
onChange={handleRadioButtons}
|
||||
className={classes.radioButtons}
|
||||
/>
|
||||
<P className={classes.descriptions}>
|
||||
Assume the cash box is emptied whenever it's removed, creating a
|
||||
new batch on the history screen and setting its current balance to
|
||||
zero.
|
||||
</P>
|
||||
<RadioGroup
|
||||
name="set-manual-reset"
|
||||
value={selectedRadio ?? cashboxReset}
|
||||
options={[radioButtonOptions[1]]}
|
||||
onChange={handleRadioButtons}
|
||||
className={classes.radioButtons}
|
||||
/>
|
||||
<P className={classes.descriptions}>
|
||||
Cash boxes won't be assumed emptied when removed, nor their counts
|
||||
modified. Instead, to update the count and create a new batch,
|
||||
you'll click the 'Edit' button on this panel.
|
||||
</P>
|
||||
<DialogActions className={classes.actions}>
|
||||
<Button onClick={() => saveCashboxOption(selectedRadio)}>
|
||||
Confirm
|
||||
</Button>
|
||||
</DialogActions>
|
||||
</Modal>
|
||||
)}
|
||||
</>
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,20 +1,17 @@
|
|||
import { makeStyles } from '@material-ui/core'
|
||||
// import BigNumber from 'bignumber.js'
|
||||
import BigNumber from 'bignumber.js'
|
||||
import * as R from 'ramda'
|
||||
import React from 'react'
|
||||
|
||||
import { Info1, Info2, Info3 } from 'src/components/typography/index'
|
||||
// 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 { fromNamespace } from 'src/utils/config'
|
||||
import { numberToFiatAmount } from 'src/utils/number.js'
|
||||
|
||||
import styles from './CashCassettesFooter.styles.js'
|
||||
const useStyles = makeStyles(styles)
|
||||
|
||||
/* const sortDate = function(a, b) {
|
||||
return new Date(b.created).getTime() - new Date(a.created).getTime()
|
||||
} */
|
||||
|
||||
const CashCassettesFooter = ({
|
||||
machines,
|
||||
config,
|
||||
|
|
@ -43,44 +40,34 @@ const CashCassettesFooter = ({
|
|||
|
||||
const totalInCassettes = R.sum(R.reduce(reducerFn, [0, 0, 0, 0], machines))
|
||||
|
||||
/* const totalInCashBox = R.sum(
|
||||
R.flatten(
|
||||
R.map(id => {
|
||||
const sliceIdx = R.path([id, 0, 'cashbox'])(bills) ?? 0
|
||||
return R.map(
|
||||
R.prop('fiat'),
|
||||
R.slice(0, sliceIdx, R.sort(sortDate, bills[id] ?? []))
|
||||
)
|
||||
}, deviceIds)
|
||||
)
|
||||
) */
|
||||
const totalInCashBox = R.sum(R.map(it => it.fiat)(bills))
|
||||
|
||||
// const total = new BigNumber(totalInCassettes + totalInCashBox).toFormat(0)
|
||||
const total = new BigNumber(totalInCassettes + totalInCashBox).toFormat(0)
|
||||
|
||||
return (
|
||||
<div className={classes.footerContainer}>
|
||||
<div className={classes.footerContent}>
|
||||
<Info3 className={classes.footerLabel}>Cash value in System</Info3>
|
||||
{/* <div className={classes.flex}>
|
||||
<div className={classes.flex}>
|
||||
<TxInIcon className={classes.icon} />
|
||||
<Info2 className={classes.iconLabel}>Cash-in:</Info2>
|
||||
<Info1 className={classes.valueDisplay}>
|
||||
{totalInCashBox} {currencyCode}
|
||||
{numberToFiatAmount(totalInCashBox)} {currencyCode}
|
||||
</Info1>
|
||||
</div> */}
|
||||
</div>
|
||||
<div className={classes.flex}>
|
||||
<TxOutIcon className={classes.icon} />
|
||||
<Info2 className={classes.iconLabel}>Cash-out:</Info2>
|
||||
<Info1 className={classes.valueDisplay}>
|
||||
{totalInCassettes} {currencyCode}
|
||||
{numberToFiatAmount(totalInCassettes)} {currencyCode}
|
||||
</Info1>
|
||||
</div>
|
||||
{/* <div className={classes.flex}>
|
||||
<div className={classes.flex}>
|
||||
<Info2 className={classes.iconLabel}>Total:</Info2>
|
||||
<Info1 className={classes.valueDisplay}>
|
||||
{total} {currencyCode}
|
||||
{numberToFiatAmount(total)} {currencyCode}
|
||||
</Info1>
|
||||
</div> */}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
|
|
|
|||
|
|
@ -24,9 +24,7 @@ export default {
|
|||
boxShadow: [[0, -1, 10, 0, 'rgba(50, 50, 50, 0.1)']]
|
||||
},
|
||||
flex: {
|
||||
display: 'flex',
|
||||
// temp marginLeft until cashIn square is enabled
|
||||
marginLeft: -640
|
||||
display: 'flex'
|
||||
},
|
||||
icon: {
|
||||
alignSelf: 'center',
|
||||
|
|
|
|||
|
|
@ -22,6 +22,7 @@ import tejo4CassetteThree from 'src/styling/icons/cassettes/tejo/4-cassettes/4-c
|
|||
import tejo4CassetteFour from 'src/styling/icons/cassettes/tejo/4-cassettes/4-cassettes-open-4-left.svg'
|
||||
import { ReactComponent as TxOutIcon } from 'src/styling/icons/direction/cash-out.svg'
|
||||
import { comet, errorColor } from 'src/styling/variables'
|
||||
import { numberToFiatAmount } from 'src/utils/number'
|
||||
|
||||
const styles = {
|
||||
content: {
|
||||
|
|
@ -279,7 +280,8 @@ const WizardStep = ({
|
|||
</P>
|
||||
</div>
|
||||
<P noMargin className={classes.fiatTotal}>
|
||||
= {cassetteTotal(values)} {fiatCurrency}
|
||||
= {numberToFiatAmount(cassetteTotal(values))}{' '}
|
||||
{fiatCurrency}
|
||||
</P>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -7,4 +7,7 @@ const transformNumber = value => (isValidNumber(value) ? value : null)
|
|||
const defaultToZero = value =>
|
||||
isValidNumber(parseInt(value)) ? parseInt(value) : 0
|
||||
|
||||
export { defaultToZero, transformNumber }
|
||||
const numberToFiatAmount = value =>
|
||||
value.toLocaleString('en-US', { maximumFractionDigits: 2 })
|
||||
|
||||
export { defaultToZero, transformNumber, numberToFiatAmount }
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue