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])
|
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 = {
|
const resolvers = {
|
||||||
Query: {
|
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`
|
const typeDef = gql`
|
||||||
type Bill {
|
type Bill {
|
||||||
|
id: ID
|
||||||
fiat: Int
|
fiat: Int
|
||||||
deviceId: ID
|
deviceId: ID
|
||||||
created: Date
|
created: Date
|
||||||
cashbox: Int
|
cashboxBatchId: ID
|
||||||
}
|
}
|
||||||
|
|
||||||
type Query {
|
type Query {
|
||||||
bills: [Bill] @auth
|
bills: [Bill] @auth
|
||||||
|
looseBills: [Bill] @auth
|
||||||
|
looseBillsByMachine(deviceId: ID): [Bill] @auth
|
||||||
}
|
}
|
||||||
`
|
`
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,25 +1,37 @@
|
||||||
|
const _ = require('lodash/fp')
|
||||||
|
|
||||||
const db = require('../../db')
|
const db = require('../../db')
|
||||||
|
|
||||||
// Get all bills with device id
|
// Get all bills with device id
|
||||||
const getBills = () => {
|
const getBills = () => {
|
||||||
return Promise.reject(new Error('This functionality hasn\'t been implemented yet'))
|
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 (
|
||||||
/* return db.any(`
|
SELECT id, device_id FROM cash_in_txs
|
||||||
SELECT d.device_id, b.fiat, b.created, d.cashbox
|
) AS cit ON cit.id = b.cash_in_txs_id`
|
||||||
FROM cash_in_txs
|
|
||||||
INNER JOIN bills AS b ON b.cash_in_txs_id = cash_in_txs.id
|
return db.any(sql)
|
||||||
INNER JOIN devices as d ON d.device_id = cash_in_txs.device_id
|
.then(res => _.map(_.mapKeys(_.camelCase), res))
|
||||||
ORDER BY device_id, created DESC`
|
}
|
||||||
)
|
|
||||||
.then(res => {
|
function getLooseBills () {
|
||||||
return res.map(item => ({
|
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 (
|
||||||
fiat: item.fiat,
|
SELECT id, device_id FROM cash_in_txs
|
||||||
deviceId: item.device_id,
|
) AS cit ON cit.id = b.cash_in_txs_id WHERE b.cashbox_batch_id IS NULL`
|
||||||
cashbox: item.cashbox,
|
|
||||||
created: item.created
|
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 = {
|
module.exports = {
|
||||||
getBills
|
getBills,
|
||||||
|
getLooseBills,
|
||||||
|
getLooseBillsByMachine
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -4,6 +4,7 @@ import React from 'react'
|
||||||
|
|
||||||
import Chip from 'src/components/Chip'
|
import Chip from 'src/components/Chip'
|
||||||
import { Info2, Label1, Label2 } from 'src/components/typography'
|
import { Info2, Label1, Label2 } from 'src/components/typography'
|
||||||
|
import { numberToFiatAmount } from 'src/utils/number'
|
||||||
|
|
||||||
import { cashboxStyles, gridStyles } from './Cashbox.styles'
|
import { cashboxStyles, gridStyles } from './Cashbox.styles'
|
||||||
|
|
||||||
|
|
@ -64,11 +65,9 @@ const CashIn = ({ currency, notes, total }) => {
|
||||||
<Info2 className={classes.noMarginText}>{notes} notes</Info2>
|
<Info2 className={classes.noMarginText}>{notes} notes</Info2>
|
||||||
</div>
|
</div>
|
||||||
<div className={classes.innerRow}>
|
<div className={classes.innerRow}>
|
||||||
{/* Feature on hold until this can be calculated
|
|
||||||
<Label1 className={classes.noMarginText}>
|
<Label1 className={classes.noMarginText}>
|
||||||
{total} {currency.code}
|
{total} {currency.code}
|
||||||
</Label1>
|
</Label1>
|
||||||
*/}
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
@ -112,7 +111,7 @@ const CashOut = ({
|
||||||
</div>
|
</div>
|
||||||
<div className={classes.innerRow}>
|
<div className={classes.innerRow}>
|
||||||
<Label1 className={classes.noMarginText}>
|
<Label1 className={classes.noMarginText}>
|
||||||
{notes * denomination} {currency.code}
|
{numberToFiatAmount(notes * denomination)} {currency.code}
|
||||||
</Label1>
|
</Label1>
|
||||||
</div>
|
</div>
|
||||||
</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 EthereumLogo } from 'src/styling/logos/icon-ethereum-colour.svg'
|
||||||
import { ReactComponent as LitecoinLogo } from 'src/styling/logos/icon-litecoin-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 { ReactComponent as ZCashLogo } from 'src/styling/logos/icon-zcash-colour.svg'
|
||||||
|
import { numberToFiatAmount } from 'src/utils/number'
|
||||||
|
|
||||||
import styles from './ATMWallet.styles'
|
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 CHIPS_PER_ROW = 6
|
||||||
|
|
||||||
const Assets = ({ balance, wallets, currency }) => {
|
const Assets = ({ balance, wallets, currency }) => {
|
||||||
|
|
@ -69,7 +67,7 @@ const Assets = ({ balance, wallets, currency }) => {
|
||||||
<P className={classes.fieldHeader}>Available balance</P>
|
<P className={classes.fieldHeader}>Available balance</P>
|
||||||
<div className={classes.totalAssetWrapper}>
|
<div className={classes.totalAssetWrapper}>
|
||||||
<Info2 noMargin className={classes.fieldValue}>
|
<Info2 noMargin className={classes.fieldValue}>
|
||||||
{formatCurrency(balance)}
|
{numberToFiatAmount(balance)}
|
||||||
</Info2>
|
</Info2>
|
||||||
<Info2 noMargin className={classes.fieldCurrency}>
|
<Info2 noMargin className={classes.fieldCurrency}>
|
||||||
{R.toUpper(currency)}
|
{R.toUpper(currency)}
|
||||||
|
|
@ -81,7 +79,7 @@ const Assets = ({ balance, wallets, currency }) => {
|
||||||
<P className={classes.fieldHeader}>Total balance in wallets</P>
|
<P className={classes.fieldHeader}>Total balance in wallets</P>
|
||||||
<div className={classes.totalAssetWrapper}>
|
<div className={classes.totalAssetWrapper}>
|
||||||
<Info2 noMargin className={classes.fieldValue}>
|
<Info2 noMargin className={classes.fieldValue}>
|
||||||
{formatCurrency(walletFiatSum())}
|
{numberToFiatAmount(walletFiatSum())}
|
||||||
</Info2>
|
</Info2>
|
||||||
<Info2 noMargin className={classes.fieldCurrency}>
|
<Info2 noMargin className={classes.fieldCurrency}>
|
||||||
{R.toUpper(currency)}
|
{R.toUpper(currency)}
|
||||||
|
|
@ -93,7 +91,7 @@ const Assets = ({ balance, wallets, currency }) => {
|
||||||
<P className={classes.fieldHeader}>Total assets</P>
|
<P className={classes.fieldHeader}>Total assets</P>
|
||||||
<div className={classes.totalAssetWrapper}>
|
<div className={classes.totalAssetWrapper}>
|
||||||
<Info2 noMargin className={classes.fieldValue}>
|
<Info2 noMargin className={classes.fieldValue}>
|
||||||
{formatCurrency(balance)}
|
{numberToFiatAmount(balance)}
|
||||||
</Info2>
|
</Info2>
|
||||||
<Info2 noMargin className={classes.fieldCurrency}>
|
<Info2 noMargin className={classes.fieldCurrency}>
|
||||||
{R.toUpper(currency)}
|
{R.toUpper(currency)}
|
||||||
|
|
@ -144,17 +142,11 @@ const WalletInfoChip = ({ wallet, currency }) => {
|
||||||
<div className={classes.walletValueWrapper}>
|
<div className={classes.walletValueWrapper}>
|
||||||
<Label2 className={classes.fieldHeader}>{wallet.name} value</Label2>
|
<Label2 className={classes.fieldHeader}>{wallet.name} value</Label2>
|
||||||
<Label2 className={classes.walletValue}>
|
<Label2 className={classes.walletValue}>
|
||||||
{wallet.amount.toFixed(1).toLocaleString('en-US', {
|
{numberToFiatAmount(wallet.amount.toFixed(1))} {wallet.cryptoCode}
|
||||||
maximumFractionDigits: 2
|
|
||||||
})}{' '}
|
|
||||||
{wallet.cryptoCode}
|
|
||||||
</Label2>
|
</Label2>
|
||||||
<Label2 className={classes.fieldHeader}>Hedged value</Label2>
|
<Label2 className={classes.fieldHeader}>Hedged value</Label2>
|
||||||
<Label2 className={classes.walletValue}>
|
<Label2 className={classes.walletValue}>
|
||||||
{wallet.fiatValue.toLocaleString('en-US', {
|
{numberToFiatAmount(wallet.fiatValue)} {currency}
|
||||||
maximumFractionDigits: 2
|
|
||||||
})}{' '}
|
|
||||||
{currency}
|
|
||||||
</Label2>
|
</Label2>
|
||||||
</div>
|
</div>
|
||||||
</Paper>
|
</Paper>
|
||||||
|
|
|
||||||
|
|
@ -9,13 +9,11 @@ import { Tooltip } from 'src/components/Tooltip'
|
||||||
import TitleSection from 'src/components/layout/TitleSection'
|
import TitleSection from 'src/components/layout/TitleSection'
|
||||||
import DataTable from 'src/components/tables/DataTable'
|
import DataTable from 'src/components/tables/DataTable'
|
||||||
import { H4, Info2, P } from 'src/components/typography'
|
import { H4, Info2, P } from 'src/components/typography'
|
||||||
|
import { numberToFiatAmount } from 'src/utils/number'
|
||||||
import { formatDate } from 'src/utils/timezones'
|
import { formatDate } from 'src/utils/timezones'
|
||||||
|
|
||||||
import styles from './Accounting.styles'
|
import styles from './Accounting.styles'
|
||||||
|
|
||||||
const formatCurrency = amount =>
|
|
||||||
amount.toLocaleString('en-US', { maximumFractionDigits: 2 })
|
|
||||||
|
|
||||||
const useStyles = makeStyles(styles)
|
const useStyles = makeStyles(styles)
|
||||||
|
|
||||||
const GET_OPERATOR_BY_USERNAME = gql`
|
const GET_OPERATOR_BY_USERNAME = gql`
|
||||||
|
|
@ -64,7 +62,7 @@ const Assets = ({ balance, hedgingReserve, currency }) => {
|
||||||
<P className={classes.fieldHeader}>Pazuz fiat balance</P>
|
<P className={classes.fieldHeader}>Pazuz fiat balance</P>
|
||||||
<div className={classes.totalAssetWrapper}>
|
<div className={classes.totalAssetWrapper}>
|
||||||
<Info2 noMargin className={classes.fieldValue}>
|
<Info2 noMargin className={classes.fieldValue}>
|
||||||
{formatCurrency(balance)}
|
{numberToFiatAmount(balance)}
|
||||||
</Info2>
|
</Info2>
|
||||||
<Info2 noMargin className={classes.fieldCurrency}>
|
<Info2 noMargin className={classes.fieldCurrency}>
|
||||||
{R.toUpper(currency)}
|
{R.toUpper(currency)}
|
||||||
|
|
@ -76,7 +74,7 @@ const Assets = ({ balance, hedgingReserve, currency }) => {
|
||||||
<P className={classes.fieldHeader}>Hedging reserve</P>
|
<P className={classes.fieldHeader}>Hedging reserve</P>
|
||||||
<div className={classes.totalAssetWrapper}>
|
<div className={classes.totalAssetWrapper}>
|
||||||
<Info2 noMargin className={classes.fieldValue}>
|
<Info2 noMargin className={classes.fieldValue}>
|
||||||
{formatCurrency(hedgingReserve)}
|
{numberToFiatAmount(hedgingReserve)}
|
||||||
</Info2>
|
</Info2>
|
||||||
<Info2 noMargin className={classes.fieldCurrency}>
|
<Info2 noMargin className={classes.fieldCurrency}>
|
||||||
{R.toUpper(currency)}
|
{R.toUpper(currency)}
|
||||||
|
|
@ -88,7 +86,7 @@ const Assets = ({ balance, hedgingReserve, currency }) => {
|
||||||
<P className={classes.fieldHeader}>Available balance</P>
|
<P className={classes.fieldHeader}>Available balance</P>
|
||||||
<div className={classes.totalAssetWrapper}>
|
<div className={classes.totalAssetWrapper}>
|
||||||
<Info2 noMargin className={classes.fieldValue}>
|
<Info2 noMargin className={classes.fieldValue}>
|
||||||
{formatCurrency(balance - hedgingReserve)}
|
{numberToFiatAmount(balance - hedgingReserve)}
|
||||||
</Info2>
|
</Info2>
|
||||||
<Info2 noMargin className={classes.fieldCurrency}>
|
<Info2 noMargin className={classes.fieldCurrency}>
|
||||||
{R.toUpper(currency)}
|
{R.toUpper(currency)}
|
||||||
|
|
@ -143,7 +141,7 @@ const Accounting = () => {
|
||||||
size: 'sm',
|
size: 'sm',
|
||||||
textAlign: 'right',
|
textAlign: 'right',
|
||||||
view: it =>
|
view: it =>
|
||||||
`${formatCurrency(it.fiatAmount)} ${R.toUpper(it.fiatCurrency)}`
|
`${numberToFiatAmount(it.fiatAmount)} ${R.toUpper(it.fiatCurrency)}`
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
header: 'Balance after operation',
|
header: 'Balance after operation',
|
||||||
|
|
@ -151,7 +149,9 @@ const Accounting = () => {
|
||||||
size: 'sm',
|
size: 'sm',
|
||||||
textAlign: 'right',
|
textAlign: 'right',
|
||||||
view: it =>
|
view: it =>
|
||||||
`${formatCurrency(it.fiatBalanceAfter)} ${R.toUpper(it.fiatCurrency)}`
|
`${numberToFiatAmount(it.fiatBalanceAfter)} ${R.toUpper(
|
||||||
|
it.fiatCurrency
|
||||||
|
)}`
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
header: 'Date',
|
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 EqualIcon } from 'src/styling/icons/dashboard/equal.svg'
|
||||||
import { ReactComponent as UpIcon } from 'src/styling/icons/dashboard/up.svg'
|
import { ReactComponent as UpIcon } from 'src/styling/icons/dashboard/up.svg'
|
||||||
import { fromNamespace } from 'src/utils/config'
|
import { fromNamespace } from 'src/utils/config'
|
||||||
|
import { numberToFiatAmount } from 'src/utils/number'
|
||||||
import { DAY, WEEK, MONTH } from 'src/utils/time'
|
import { DAY, WEEK, MONTH } from 'src/utils/time'
|
||||||
|
|
||||||
import styles from './Analytics.styles'
|
import styles from './Analytics.styles'
|
||||||
|
|
@ -97,9 +98,7 @@ const OverviewEntry = ({ label, value, oldValue, currency }) => {
|
||||||
<div className={classes.overviewEntry}>
|
<div className={classes.overviewEntry}>
|
||||||
<P noMargin>{label}</P>
|
<P noMargin>{label}</P>
|
||||||
<Info2 noMargin className={classes.overviewFieldWrapper}>
|
<Info2 noMargin className={classes.overviewFieldWrapper}>
|
||||||
<span>
|
<span>{numberToFiatAmount(value)}</span>
|
||||||
{value.toLocaleString('en-US', { maximumFractionDigits: 2 })}
|
|
||||||
</span>
|
|
||||||
{!!currency && ` ${currency}`}
|
{!!currency && ` ${currency}`}
|
||||||
</Info2>
|
</Info2>
|
||||||
<span className={classes.overviewGrowth}>
|
<span className={classes.overviewGrowth}>
|
||||||
|
|
@ -107,7 +106,7 @@ const OverviewEntry = ({ label, value, oldValue, currency }) => {
|
||||||
{R.lt(growthRate, 0) && <DownIcon height={10} />}
|
{R.lt(growthRate, 0) && <DownIcon height={10} />}
|
||||||
{R.equals(growthRate, 0) && <EqualIcon height={10} />}
|
{R.equals(growthRate, 0) && <EqualIcon height={10} />}
|
||||||
<P noMargin className={classnames(growthClasses)}>
|
<P noMargin className={classnames(growthClasses)}>
|
||||||
{growthRate.toLocaleString('en-US', { maximumFractionDigits: 2 })}%
|
{numberToFiatAmount(growthRate)}%
|
||||||
</P>
|
</P>
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
||||||
|
|
@ -6,6 +6,7 @@ import React, { memo } from 'react'
|
||||||
import { Info2, Label3, P } from 'src/components/typography'
|
import { Info2, Label3, P } from 'src/components/typography'
|
||||||
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'
|
||||||
|
import { numberToFiatAmount } from 'src/utils/number'
|
||||||
import { singularOrPlural } from 'src/utils/string'
|
import { singularOrPlural } from 'src/utils/string'
|
||||||
import { formatDate, formatDateNonUtc } from 'src/utils/timezones'
|
import { formatDate, formatDateNonUtc } from 'src/utils/timezones'
|
||||||
|
|
||||||
|
|
@ -13,9 +14,6 @@ import styles from './GraphTooltip.styles'
|
||||||
|
|
||||||
const useStyles = makeStyles(styles)
|
const useStyles = makeStyles(styles)
|
||||||
|
|
||||||
const formatCurrency = amount =>
|
|
||||||
amount.toLocaleString('en-US', { maximumFractionDigits: 2 })
|
|
||||||
|
|
||||||
const GraphTooltip = ({
|
const GraphTooltip = ({
|
||||||
coords,
|
coords,
|
||||||
data,
|
data,
|
||||||
|
|
@ -67,7 +65,7 @@ const GraphTooltip = ({
|
||||||
{singularOrPlural(R.length(data), 'transaction', 'transactions')}
|
{singularOrPlural(R.length(data), 'transaction', 'transactions')}
|
||||||
</P>
|
</P>
|
||||||
<P noMargin className={classes.dotOtTransactionVolume}>
|
<P noMargin className={classes.dotOtTransactionVolume}>
|
||||||
{formatCurrency(transactions.volume)} {currency} in volume
|
{numberToFiatAmount(transactions.volume)} {currency} in volume
|
||||||
</P>
|
</P>
|
||||||
<div className={classes.dotOtTransactionClasses}>
|
<div className={classes.dotOtTransactionClasses}>
|
||||||
<Label3 noMargin>
|
<Label3 noMargin>
|
||||||
|
|
|
||||||
|
|
@ -14,8 +14,10 @@ import React, { useContext } from 'react'
|
||||||
import AppContext from 'src/AppContext'
|
import AppContext from 'src/AppContext'
|
||||||
import TitleSection from 'src/components/layout/TitleSection'
|
import TitleSection from 'src/components/layout/TitleSection'
|
||||||
import { H4, Label2, P, Info2 } from 'src/components/typography'
|
import { H4, Label2, P, Info2 } from 'src/components/typography'
|
||||||
|
import { numberToFiatAmount } from 'src/utils/number'
|
||||||
|
|
||||||
import styles from './Assets.styles'
|
import styles from './Assets.styles'
|
||||||
|
|
||||||
const useStyles = makeStyles(styles)
|
const useStyles = makeStyles(styles)
|
||||||
|
|
||||||
const GET_OPERATOR_BY_USERNAME = gql`
|
const GET_OPERATOR_BY_USERNAME = gql`
|
||||||
|
|
@ -105,7 +107,7 @@ const AssetsAmountTable = ({ title, data = [], numToRender }) => {
|
||||||
</Cell>
|
</Cell>
|
||||||
<Cell align="right">
|
<Cell align="right">
|
||||||
<P>{`${selectAmountPrefix(asset)}
|
<P>{`${selectAmountPrefix(asset)}
|
||||||
${formatCurrency(Math.abs(asset.amount))} ${
|
${numberToFiatAmount(Math.abs(asset.amount))} ${
|
||||||
asset.currency
|
asset.currency
|
||||||
}`}</P>
|
}`}</P>
|
||||||
</Cell>
|
</Cell>
|
||||||
|
|
@ -117,7 +119,9 @@ const AssetsAmountTable = ({ title, data = [], numToRender }) => {
|
||||||
<Info2>{`Total ${R.toLower(title)}`}</Info2>
|
<Info2>{`Total ${R.toLower(title)}`}</Info2>
|
||||||
</Cell>
|
</Cell>
|
||||||
<Cell align="right">
|
<Cell align="right">
|
||||||
<Info2>{`${formatCurrency(totalAmount)} ${currency}`}</Info2>
|
<Info2>{`${numberToFiatAmount(
|
||||||
|
totalAmount
|
||||||
|
)} ${currency}`}</Info2>
|
||||||
</Cell>
|
</Cell>
|
||||||
</TableRow>
|
</TableRow>
|
||||||
</TableBody>
|
</TableBody>
|
||||||
|
|
@ -128,9 +132,6 @@ const AssetsAmountTable = ({ title, data = [], numToRender }) => {
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
const formatCurrency = amount =>
|
|
||||||
amount.toLocaleString('en-US', { maximumFractionDigits: 2 })
|
|
||||||
|
|
||||||
const Assets = () => {
|
const Assets = () => {
|
||||||
const classes = useStyles()
|
const classes = useStyles()
|
||||||
const { userData } = useContext(AppContext)
|
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 classes = useStyles()
|
||||||
|
|
||||||
const [wizard, setWizard] = useState(false)
|
const [wizard, setWizard] = useState(false)
|
||||||
|
|
@ -105,7 +105,11 @@ const CashCassettes = ({ machine, config, refetchData }) => {
|
||||||
width: widthsByNumberOfCassettes[numberOfCassettes].cashbox,
|
width: widthsByNumberOfCassettes[numberOfCassettes].cashbox,
|
||||||
stripe: false,
|
stripe: false,
|
||||||
view: value => (
|
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,
|
input: NumberInput,
|
||||||
inputProps: {
|
inputProps: {
|
||||||
|
|
|
||||||
|
|
@ -46,6 +46,12 @@ const GET_INFO = gql`
|
||||||
note
|
note
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
looseBillsByMachine(deviceId: $deviceId) {
|
||||||
|
id
|
||||||
|
fiat
|
||||||
|
deviceId
|
||||||
|
created
|
||||||
|
}
|
||||||
config
|
config
|
||||||
}
|
}
|
||||||
`
|
`
|
||||||
|
|
@ -59,12 +65,14 @@ const Machines = () => {
|
||||||
deviceId: getMachineID(location.pathname)
|
deviceId: getMachineID(location.pathname)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
const classes = useStyles()
|
const classes = useStyles()
|
||||||
|
|
||||||
const timezone = R.path(['config', 'locale_timezone'], data) ?? {}
|
const timezone = R.path(['config', 'locale_timezone'], data) ?? {}
|
||||||
|
|
||||||
const machine = R.path(['machine'])(data) ?? {}
|
const machine = R.path(['machine'])(data) ?? {}
|
||||||
const config = R.path(['config'])(data) ?? {}
|
const config = R.path(['config'])(data) ?? {}
|
||||||
|
const bills = R.path(['looseBillsByMachine'])(data) ?? []
|
||||||
|
|
||||||
const machineName = R.path(['name'])(machine) ?? null
|
const machineName = R.path(['name'])(machine) ?? null
|
||||||
const machineID = R.path(['deviceId'])(machine) ?? null
|
const machineID = R.path(['deviceId'])(machine) ?? null
|
||||||
|
|
@ -102,6 +110,7 @@ const Machines = () => {
|
||||||
refetchData={refetch}
|
refetchData={refetch}
|
||||||
machine={machine}
|
machine={machine}
|
||||||
config={config ?? false}
|
config={config ?? false}
|
||||||
|
bills={bills}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<div className={classes.transactionsItem}>
|
<div className={classes.transactionsItem}>
|
||||||
|
|
|
||||||
|
|
@ -75,24 +75,21 @@ const GET_MACHINES_AND_CONFIG = gql`
|
||||||
numberOfCassettes
|
numberOfCassettes
|
||||||
}
|
}
|
||||||
config
|
config
|
||||||
|
looseBills {
|
||||||
|
id
|
||||||
|
fiat
|
||||||
|
created
|
||||||
|
deviceId
|
||||||
|
}
|
||||||
}
|
}
|
||||||
`
|
`
|
||||||
|
|
||||||
const SAVE_CONFIG = gql`
|
const SAVE_CONFIG = gql`
|
||||||
mutation Save($config: JSONObject) {
|
mutation Save($config: JSONObject) {
|
||||||
saveConfig(config: $config)
|
saveConfig(config: $config)
|
||||||
}
|
}
|
||||||
`
|
`
|
||||||
|
|
||||||
/*
|
|
||||||
// for cash in total calculation
|
|
||||||
bills {
|
|
||||||
fiat
|
|
||||||
deviceId
|
|
||||||
created
|
|
||||||
cashbox
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
|
|
||||||
const SET_CASSETTE_BILLS = gql`
|
const SET_CASSETTE_BILLS = gql`
|
||||||
mutation MachineAction(
|
mutation MachineAction(
|
||||||
$deviceId: ID!
|
$deviceId: ID!
|
||||||
|
|
@ -128,7 +125,7 @@ const CashCassettes = () => {
|
||||||
const [editingSchema, setEditingSchema] = useState(null)
|
const [editingSchema, setEditingSchema] = useState(null)
|
||||||
const [selectedRadio, setSelectedRadio] = 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 [wizard, setWizard] = useState(false)
|
||||||
const [machineId, setMachineId] = useState('')
|
const [machineId, setMachineId] = useState('')
|
||||||
|
|
||||||
|
|
@ -143,9 +140,11 @@ const CashCassettes = () => {
|
||||||
refetchQueries: () => ['getData']
|
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(
|
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 cashout = data?.config && fromNamespace('cashOut')(data.config)
|
||||||
const locale = data?.config && fromNamespace('locale')(data.config)
|
const locale = data?.config && fromNamespace('locale')(data.config)
|
||||||
|
|
@ -206,8 +205,12 @@ const CashCassettes = () => {
|
||||||
name: 'cashbox',
|
name: 'cashbox',
|
||||||
header: 'Cash box',
|
header: 'Cash box',
|
||||||
width: maxNumberOfCassettes > 2 ? 140 : 280,
|
width: maxNumberOfCassettes > 2 ? 140 : 280,
|
||||||
view: value => (
|
view: (value, { id }) => (
|
||||||
<CashIn currency={{ code: fiatCurrency }} notes={value} total={0} />
|
<CashIn
|
||||||
|
currency={{ code: fiatCurrency }}
|
||||||
|
notes={value}
|
||||||
|
total={R.sum(R.map(it => it.fiat, bills[id]))}
|
||||||
|
/>
|
||||||
),
|
),
|
||||||
input: NumberInput,
|
input: NumberInput,
|
||||||
inputProps: {
|
inputProps: {
|
||||||
|
|
@ -222,7 +225,7 @@ const CashCassettes = () => {
|
||||||
elements.push({
|
elements.push({
|
||||||
name: `cassette${it}`,
|
name: `cassette${it}`,
|
||||||
header: `Cassette ${it}`,
|
header: `Cassette ${it}`,
|
||||||
width: (maxNumberOfCassettes > 2 ? 700 : 560) / maxNumberOfCassettes,
|
width: (maxNumberOfCassettes > 2 ? 560 : 650) / maxNumberOfCassettes,
|
||||||
stripe: true,
|
stripe: true,
|
||||||
doubleHeader: 'Cash-out',
|
doubleHeader: 'Cash-out',
|
||||||
view: (value, { id }) => (
|
view: (value, { id }) => (
|
||||||
|
|
@ -268,6 +271,7 @@ const CashCassettes = () => {
|
||||||
})
|
})
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
!dataLoading && (
|
||||||
<>
|
<>
|
||||||
<TitleSection
|
<TitleSection
|
||||||
title="Cash Boxes & Cassettes"
|
title="Cash Boxes & Cassettes"
|
||||||
|
|
@ -285,7 +289,7 @@ const CashCassettes = () => {
|
||||||
<Box
|
<Box
|
||||||
display="flex"
|
display="flex"
|
||||||
alignItems="center"
|
alignItems="center"
|
||||||
justifyContent="flex-end"
|
justifyContent="end"
|
||||||
mr="-4px">
|
mr="-4px">
|
||||||
{cashboxReset && (
|
{cashboxReset && (
|
||||||
<P className={classes.selection}>
|
<P className={classes.selection}>
|
||||||
|
|
@ -332,7 +336,7 @@ const CashCassettes = () => {
|
||||||
/>
|
/>
|
||||||
{wizard && (
|
{wizard && (
|
||||||
<Wizard
|
<Wizard
|
||||||
machine={R.find(R.propEq('id', machineId))(machines)}
|
machine={R.find(R.propEq('id', machineId), machines)}
|
||||||
cashoutSettings={getCashoutSettings(machineId)}
|
cashoutSettings={getCashoutSettings(machineId)}
|
||||||
onClose={() => {
|
onClose={() => {
|
||||||
setWizard(false)
|
setWizard(false)
|
||||||
|
|
@ -349,8 +353,8 @@ const CashCassettes = () => {
|
||||||
handleClose={() => setEditingSchema(null)}
|
handleClose={() => setEditingSchema(null)}
|
||||||
open={true}>
|
open={true}>
|
||||||
<P className={classes.descriptions}>
|
<P className={classes.descriptions}>
|
||||||
We can automatically assume you emptied a bill validator's cash box
|
We can automatically assume you emptied a bill validator's cash
|
||||||
when the machine detects that it has been removed.
|
box when the machine detects that it has been removed.
|
||||||
</P>
|
</P>
|
||||||
<RadioGroup
|
<RadioGroup
|
||||||
name="set-automatic-reset"
|
name="set-automatic-reset"
|
||||||
|
|
@ -360,8 +364,9 @@ const CashCassettes = () => {
|
||||||
className={classes.radioButtons}
|
className={classes.radioButtons}
|
||||||
/>
|
/>
|
||||||
<P className={classes.descriptions}>
|
<P className={classes.descriptions}>
|
||||||
Assume the cash box is emptied whenever it's removed, creating a new
|
Assume the cash box is emptied whenever it's removed, creating a
|
||||||
batch on the history screen and setting its current balance to zero.
|
new batch on the history screen and setting its current balance to
|
||||||
|
zero.
|
||||||
</P>
|
</P>
|
||||||
<RadioGroup
|
<RadioGroup
|
||||||
name="set-manual-reset"
|
name="set-manual-reset"
|
||||||
|
|
@ -384,6 +389,7 @@ const CashCassettes = () => {
|
||||||
)}
|
)}
|
||||||
</>
|
</>
|
||||||
)
|
)
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
export default CashCassettes
|
export default CashCassettes
|
||||||
|
|
|
||||||
|
|
@ -1,20 +1,17 @@
|
||||||
import { makeStyles } from '@material-ui/core'
|
import { makeStyles } from '@material-ui/core'
|
||||||
// import BigNumber from 'bignumber.js'
|
import BigNumber from 'bignumber.js'
|
||||||
import * as R from 'ramda'
|
import * as R from 'ramda'
|
||||||
import React from 'react'
|
import React from 'react'
|
||||||
|
|
||||||
import { Info1, Info2, Info3 } from 'src/components/typography/index'
|
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 { ReactComponent as TxOutIcon } from 'src/styling/icons/direction/cash-out.svg'
|
||||||
import { fromNamespace } from 'src/utils/config'
|
import { fromNamespace } from 'src/utils/config'
|
||||||
|
import { numberToFiatAmount } from 'src/utils/number.js'
|
||||||
|
|
||||||
import styles from './CashCassettesFooter.styles.js'
|
import styles from './CashCassettesFooter.styles.js'
|
||||||
const useStyles = makeStyles(styles)
|
const useStyles = makeStyles(styles)
|
||||||
|
|
||||||
/* const sortDate = function(a, b) {
|
|
||||||
return new Date(b.created).getTime() - new Date(a.created).getTime()
|
|
||||||
} */
|
|
||||||
|
|
||||||
const CashCassettesFooter = ({
|
const CashCassettesFooter = ({
|
||||||
machines,
|
machines,
|
||||||
config,
|
config,
|
||||||
|
|
@ -43,44 +40,34 @@ const CashCassettesFooter = ({
|
||||||
|
|
||||||
const totalInCassettes = R.sum(R.reduce(reducerFn, [0, 0, 0, 0], machines))
|
const totalInCassettes = R.sum(R.reduce(reducerFn, [0, 0, 0, 0], machines))
|
||||||
|
|
||||||
/* const totalInCashBox = R.sum(
|
const totalInCashBox = R.sum(R.map(it => it.fiat)(bills))
|
||||||
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 total = new BigNumber(totalInCassettes + totalInCashBox).toFormat(0)
|
const total = new BigNumber(totalInCassettes + totalInCashBox).toFormat(0)
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className={classes.footerContainer}>
|
<div className={classes.footerContainer}>
|
||||||
<div className={classes.footerContent}>
|
<div className={classes.footerContent}>
|
||||||
<Info3 className={classes.footerLabel}>Cash value in System</Info3>
|
<Info3 className={classes.footerLabel}>Cash value in System</Info3>
|
||||||
{/* <div className={classes.flex}>
|
<div className={classes.flex}>
|
||||||
<TxInIcon className={classes.icon} />
|
<TxInIcon className={classes.icon} />
|
||||||
<Info2 className={classes.iconLabel}>Cash-in:</Info2>
|
<Info2 className={classes.iconLabel}>Cash-in:</Info2>
|
||||||
<Info1 className={classes.valueDisplay}>
|
<Info1 className={classes.valueDisplay}>
|
||||||
{totalInCashBox} {currencyCode}
|
{numberToFiatAmount(totalInCashBox)} {currencyCode}
|
||||||
</Info1>
|
</Info1>
|
||||||
</div> */}
|
</div>
|
||||||
<div className={classes.flex}>
|
<div className={classes.flex}>
|
||||||
<TxOutIcon className={classes.icon} />
|
<TxOutIcon className={classes.icon} />
|
||||||
<Info2 className={classes.iconLabel}>Cash-out:</Info2>
|
<Info2 className={classes.iconLabel}>Cash-out:</Info2>
|
||||||
<Info1 className={classes.valueDisplay}>
|
<Info1 className={classes.valueDisplay}>
|
||||||
{totalInCassettes} {currencyCode}
|
{numberToFiatAmount(totalInCassettes)} {currencyCode}
|
||||||
</Info1>
|
</Info1>
|
||||||
</div>
|
</div>
|
||||||
{/* <div className={classes.flex}>
|
<div className={classes.flex}>
|
||||||
<Info2 className={classes.iconLabel}>Total:</Info2>
|
<Info2 className={classes.iconLabel}>Total:</Info2>
|
||||||
<Info1 className={classes.valueDisplay}>
|
<Info1 className={classes.valueDisplay}>
|
||||||
{total} {currencyCode}
|
{numberToFiatAmount(total)} {currencyCode}
|
||||||
</Info1>
|
</Info1>
|
||||||
</div> */}
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
|
|
|
||||||
|
|
@ -24,9 +24,7 @@ export default {
|
||||||
boxShadow: [[0, -1, 10, 0, 'rgba(50, 50, 50, 0.1)']]
|
boxShadow: [[0, -1, 10, 0, 'rgba(50, 50, 50, 0.1)']]
|
||||||
},
|
},
|
||||||
flex: {
|
flex: {
|
||||||
display: 'flex',
|
display: 'flex'
|
||||||
// temp marginLeft until cashIn square is enabled
|
|
||||||
marginLeft: -640
|
|
||||||
},
|
},
|
||||||
icon: {
|
icon: {
|
||||||
alignSelf: 'center',
|
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 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 { ReactComponent as TxOutIcon } from 'src/styling/icons/direction/cash-out.svg'
|
||||||
import { comet, errorColor } from 'src/styling/variables'
|
import { comet, errorColor } from 'src/styling/variables'
|
||||||
|
import { numberToFiatAmount } from 'src/utils/number'
|
||||||
|
|
||||||
const styles = {
|
const styles = {
|
||||||
content: {
|
content: {
|
||||||
|
|
@ -279,7 +280,8 @@ const WizardStep = ({
|
||||||
</P>
|
</P>
|
||||||
</div>
|
</div>
|
||||||
<P noMargin className={classes.fiatTotal}>
|
<P noMargin className={classes.fiatTotal}>
|
||||||
= {cassetteTotal(values)} {fiatCurrency}
|
= {numberToFiatAmount(cassetteTotal(values))}{' '}
|
||||||
|
{fiatCurrency}
|
||||||
</P>
|
</P>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
||||||
|
|
@ -7,4 +7,7 @@ const transformNumber = value => (isValidNumber(value) ? value : null)
|
||||||
const defaultToZero = value =>
|
const defaultToZero = value =>
|
||||||
isValidNumber(parseInt(value)) ? parseInt(value) : 0
|
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