+ {objectData?.name ? (
+
+ {objectData.name}
+
+ ) : null}
{objectData?._id && !objectData?.name ? (
{
- if (initialized == false && id && token != null) {
+ if (connected == true && initialized == false && id && token != null) {
setInitialized(true)
handleFetchObject()
}
- }, [id, initialized, handleFetchObject, token])
+ }, [id, initialized, handleFetchObject, token, connected])
useEffect(() => {
if (id && connected) {
@@ -391,15 +391,19 @@ const ObjectForm = forwardRef(
try {
const value = await form.validateFields()
setEditLoading(true)
- onStateChangeRef.current({ editLoading: true })
- await updateObject(id, type, value)
+ const currentFormData = {
+ ...value,
+ ...objectData
+ }
+ onStateChangeRef.current({ editLoading: true })
+ await updateObject(id, type, currentFormData)
setIsEditing(false)
isEditingRef.current = false
onStateChangeRef.current({ isEditing: isEditingRef.current })
setObjectData({
...objectData,
- ...value,
+ ...currentFormData,
_isEditing: isEditingRef.current
})
messageApi.success('Information updated successfully')
diff --git a/src/components/Dashboard/common/ObjectInfo.jsx b/src/components/Dashboard/common/ObjectInfo.jsx
index 3811a24..8f96fc1 100644
--- a/src/components/Dashboard/common/ObjectInfo.jsx
+++ b/src/components/Dashboard/common/ObjectInfo.jsx
@@ -17,6 +17,7 @@ const ObjectInfo = ({
required = undefined,
visibleProperties = {},
objectPropertyProps = {},
+ labelWidth = '150px',
column = {
xs: 1,
sm: 1,
@@ -86,13 +87,15 @@ const ObjectInfo = ({
) : null,
children: (
-
+
+
+
),
span: item?.span || undefined
}
@@ -105,6 +108,8 @@ const ObjectInfo = ({
bordered={true}
{...rest}
items={descriptionItems}
+ styles={{ label: { width: labelWidth } }}
+ className='object-info-descriptions'
/>
)
@@ -124,7 +129,8 @@ ObjectInfo.propTypes = {
objectData: PropTypes.object,
required: PropTypes.bool,
visibleProperties: PropTypes.object,
- objectPropertyProps: PropTypes.object
+ objectPropertyProps: PropTypes.object,
+ labelWidth: PropTypes.string
}
export default ObjectInfo
diff --git a/src/components/Dashboard/common/ObjectProperty.jsx b/src/components/Dashboard/common/ObjectProperty.jsx
index cade529..a9a2031 100644
--- a/src/components/Dashboard/common/ObjectProperty.jsx
+++ b/src/components/Dashboard/common/ObjectProperty.jsx
@@ -45,6 +45,7 @@ import DataTree from './DataTree'
import FileList from './FileList'
import ObjectChildTable from './ObjectChildTable'
import MiscId from './MiscId'
+import { round } from '../utils/Utils'
const { Text } = Typography
@@ -265,7 +266,7 @@ const ObjectProperty = ({
} else {
var roundedValue = value
if (roundNumber != false && typeof value === 'number') {
- roundedValue = value.toFixed(roundNumber)
+ roundedValue = round(value, roundNumber)
}
return (
diff --git a/src/components/Dashboard/common/ObjectSelect.jsx b/src/components/Dashboard/common/ObjectSelect.jsx
index 3666554..d0e981e 100644
--- a/src/components/Dashboard/common/ObjectSelect.jsx
+++ b/src/components/Dashboard/common/ObjectSelect.jsx
@@ -35,7 +35,8 @@ const ObjectSelect = ({
disabled = false,
...rest
}) => {
- const { fetchObjectsByProperty, fetchObject } = useContext(ApiServerContext)
+ const { fetchObjectsByProperty, fetchObject, connected } =
+ useContext(ApiServerContext)
const { token } = useContext(AuthContext)
// --- State ---
const [treeData, setTreeData] = useState([])
@@ -373,11 +374,22 @@ const ObjectSelect = ({
setInitialized(true)
return
}
- if (!initialized && token != null && type != 'unknown') {
+ if (
+ !initialized &&
+ token != null &&
+ type != 'unknown' &&
+ type != undefined &&
+ connected == true
+ ) {
handleFetchObjectsProperties()
setInitialized(true)
}
- if (value == null || type == 'unknown') {
+ if (
+ value == null ||
+ type == 'unknown' ||
+ type == undefined ||
+ connected == false
+ ) {
setTreeSelectValue(null)
setInitialLoading(false)
setInitialized(true)
@@ -392,7 +404,8 @@ const ObjectSelect = ({
initialized,
token,
fetchFullObjectIfNeeded,
- type
+ type,
+ connected
])
const prevValuesRef = useRef({ type, masterFilter })
@@ -443,7 +456,7 @@ const ObjectSelect = ({
const placeholder = useMemo(
() =>
- type == 'unknown'
+ type == 'unknown' || type == undefined
? 'n/a'
: `Select a ${getModelByName(type).label.toLowerCase()}...`,
[type]
@@ -486,7 +499,7 @@ const ObjectSelect = ({
{...rest}
value={treeSelectValue}
onChange={onTreeSelectChange}
- disabled={disabled || type == 'unknown'}
+ disabled={disabled || type == 'unknown' || type == undefined}
/>
)
}
diff --git a/src/components/Dashboard/common/ObjectTable.jsx b/src/components/Dashboard/common/ObjectTable.jsx
index de8cf0f..f41dace 100644
--- a/src/components/Dashboard/common/ObjectTable.jsx
+++ b/src/components/Dashboard/common/ObjectTable.jsx
@@ -458,11 +458,16 @@ const ObjectTable = forwardRef(
}))
useEffect(() => {
- if (token != null && !pages.includes(initialPage) && !initialized) {
+ if (
+ connected == true &&
+ token != null &&
+ !pages.includes(initialPage) &&
+ !initialized
+ ) {
loadInitialPage()
setInitialized(true)
}
- }, [token, loadInitialPage, initialPage, pages, initialized])
+ }, [token, loadInitialPage, initialPage, pages, initialized, connected])
// Watch for changes in type and masterFilter, reset component state when they change
useEffect(() => {
diff --git a/src/components/Dashboard/common/PrinterPositionPanel.jsx b/src/components/Dashboard/common/PrinterPositionPanel.jsx
index 8995e6c..6a8f921 100644
--- a/src/components/Dashboard/common/PrinterPositionPanel.jsx
+++ b/src/components/Dashboard/common/PrinterPositionPanel.jsx
@@ -189,7 +189,12 @@ const PrinterPositionPanel = ({
GCode Position:
-
+
{' '}
{round(positionData.gcodePosition[0], 2)}mm
@@ -318,6 +323,7 @@ const PrinterPositionPanel = ({
size='small'
bordered
style={{ flexGrow: 1 }}
+ styles={{ label: { width: '40px' } }}
>
{round(positionData.homingOrigin[0], 2)}mm
@@ -343,7 +349,12 @@ const PrinterPositionPanel = ({
{positionData ? (
-
+
{round(positionData.livePosition[0], 2)}mm
@@ -430,7 +441,12 @@ const PrinterPositionPanel = ({
>
)}
-
+
{round(positionData.speed, 2)}mm/s
diff --git a/src/components/Dashboard/common/StateDisplay.jsx b/src/components/Dashboard/common/StateDisplay.jsx
index 2f71eee..02cbe95 100644
--- a/src/components/Dashboard/common/StateDisplay.jsx
+++ b/src/components/Dashboard/common/StateDisplay.jsx
@@ -49,7 +49,7 @@ const StateDisplay = ({
strokeColor={
orangeProgressTypes.includes(currentState.type) ? 'orange' : ''
}
- style={{ width: '150px', marginBottom: '2px' }}
+ style={{ maxWidth: '200px', marginBottom: '2px' }}
/>
) : null}
diff --git a/src/components/Dashboard/context/AuthContext.jsx b/src/components/Dashboard/context/AuthContext.jsx
index 297e3d7..efeb67f 100644
--- a/src/components/Dashboard/context/AuthContext.jsx
+++ b/src/components/Dashboard/context/AuthContext.jsx
@@ -307,7 +307,10 @@ const AuthProvider = ({ children }) => {
setExpiresAt(null)
setUserProfile(null)
clearAuthCookies()
- setShowUnauthorizedModal(true)
+ setAuthenticated(false)
+ if (showSessionExpiredModal == false) {
+ setShowUnauthorizedModal(true)
+ }
}
const refreshToken = useCallback(async () => {
@@ -489,7 +492,6 @@ const AuthProvider = ({ children }) => {
authCode == null
) {
setInitialized(true)
- console.log('Showing unauth', token, authCode)
setShowUnauthorizedModal(true)
setAuthenticated(false)
}
diff --git a/src/components/Icons/TaxRateIcon.jsx b/src/components/Icons/TaxRateIcon.jsx
new file mode 100644
index 0000000..98f4550
--- /dev/null
+++ b/src/components/Icons/TaxRateIcon.jsx
@@ -0,0 +1,6 @@
+import Icon from '@ant-design/icons'
+import CustomIconSvg from '../../../assets/icons/taxrateicon.svg?react'
+
+const TaxRateIcon = (props) =>
+
+export default TaxRateIcon
diff --git a/src/components/Icons/TaxRecordIcon.jsx b/src/components/Icons/TaxRecordIcon.jsx
new file mode 100644
index 0000000..7334d5c
--- /dev/null
+++ b/src/components/Icons/TaxRecordIcon.jsx
@@ -0,0 +1,6 @@
+import Icon from '@ant-design/icons'
+import CustomIconSvg from '../../../assets/icons/taxrecordicon.svg?react'
+
+const TaxRecordIcon = (props) =>
+
+export default TaxRecordIcon
diff --git a/src/database/ObjectModels.js b/src/database/ObjectModels.js
index 6ea58f0..6e90e32 100644
--- a/src/database/ObjectModels.js
+++ b/src/database/ObjectModels.js
@@ -26,6 +26,8 @@ import { DocumentSize } from './models/DocumentSize.js'
import { DocumentTemplate } from './models/DocumentTemplate.js'
import { DocumentPrinter } from './models/DocumentPrinter.js'
import { DocumentJob } from './models/DocumentJob.js'
+import { TaxRate } from './models/TaxRate.js'
+import { TaxRecord } from './models/TaxRecord.js'
import QuestionCircleIcon from '../components/Icons/QuestionCircleIcon'
export const objectModels = [
@@ -56,7 +58,9 @@ export const objectModels = [
DocumentSize,
DocumentTemplate,
DocumentPrinter,
- DocumentJob
+ DocumentJob,
+ TaxRate,
+ TaxRecord
]
// Re-export individual models for direct access
@@ -88,7 +92,9 @@ export {
DocumentSize,
DocumentTemplate,
DocumentPrinter,
- DocumentJob
+ DocumentJob,
+ TaxRate,
+ TaxRecord
}
export function getModelByName(name, ignoreCase = false) {
diff --git a/src/database/models/Job.js b/src/database/models/Job.js
index a953596..bb626ed 100644
--- a/src/database/models/Job.js
+++ b/src/database/models/Job.js
@@ -41,8 +41,9 @@ export const Job = {
'_id',
'gcodeFile',
'gcodeFile._id',
- 'state',
'quantity',
+ 'state',
+
'createdAt'
],
filters: ['state', '_id', 'gcodeFile._id', 'quantity'],
diff --git a/src/database/models/Part.js b/src/database/models/Part.js
index e87d080..b9f30fb 100644
--- a/src/database/models/Part.js
+++ b/src/database/models/Part.js
@@ -4,7 +4,6 @@ import PartIcon from '../../components/Icons/PartIcon'
import ReloadIcon from '../../components/Icons/ReloadIcon'
import CheckIcon from '../../components/Icons/CheckIcon'
import XMarkIcon from '../../components/Icons/XMarkIcon'
-
export const Part = {
name: 'part',
label: 'Part',
@@ -132,28 +131,47 @@ export const Part = {
step: 0.01
},
{
- name: 'priceMode',
- label: 'Price Mode',
+ name: 'costWithTax',
+ label: 'Cost with Tax',
+ columnWidth: 150,
required: true,
- type: 'priceMode',
- disabled: (objectData) => {
- return objectData.globalPricing == true
+ readOnly: true,
+ type: 'number',
+ prefix: '£',
+ min: 0,
+ step: 0.01,
+ value: (objectData) => {
+ if (objectData?.costTaxRate?.rateType == 'percentage') {
+ return (
+ (
+ objectData?.cost *
+ (1 + objectData?.costTaxRate?.rate / 100)
+ ).toFixed(2) || undefined
+ )
+ } else if (objectData?.costTaxRate?.rateType == 'amount') {
+ return (
+ (objectData?.cost + objectData?.costTaxRate?.rate).toFixed(2) ||
+ undefined
+ )
+ } else {
+ return objectData?.cost || undefined
+ }
}
},
{
- name: 'margin',
- label: 'Margin',
+ name: 'costTaxRate',
+ label: 'Cost Tax Rate',
required: true,
- type: 'number',
- disabled: (objectData) => {
- return (
- objectData.globalPricing == true || objectData.priceMode == 'amount'
- )
- },
- suffix: '%',
- min: 0,
- max: 100,
- step: 0.01
+ type: 'object',
+ objectType: 'taxRate'
+ },
+ {
+ name: 'costTaxRate._id',
+ label: 'Cost Tax Rate ID',
+ readOnly: true,
+ type: 'id',
+ showHyperlink: true,
+ objectType: 'taxRate'
},
{
name: 'price',
@@ -163,15 +181,87 @@ export const Part = {
prefix: '£',
min: 0,
step: 0.1,
- roundNumber: 2,
+ readOnly: (objectData) => {
+ return objectData?.priceMode == 'margin'
+ },
value: (objectData) => {
- if (objectData?.priceMode == 'margin') {
- return objectData?.cost * (1 + objectData?.margin / 100) || undefined
+ if (
+ objectData?.priceMode == 'margin' &&
+ objectData?.margin !== undefined &&
+ objectData?.margin !== null
+ ) {
+ return (
+ (objectData?.cost * (1 + objectData?.margin / 100)).toFixed(2) ||
+ undefined
+ )
} else {
return objectData?.price || undefined
}
}
},
+ {
+ name: 'priceWithTax',
+ label: 'Price with Tax',
+ columnWidth: 150,
+ required: true,
+ readOnly: true,
+ type: 'number',
+ prefix: '£',
+ min: 0,
+ step: 0.01,
+ value: (objectData) => {
+ if (objectData?.priceTaxRate?.rateType == 'percentage') {
+ return (
+ (
+ objectData?.price *
+ (1 + objectData?.priceTaxRate?.rate / 100)
+ ).toFixed(2) || undefined
+ )
+ } else if (objectData?.priceTaxRate?.rateType == 'amount') {
+ return (
+ (objectData?.price + objectData?.priceTaxRate?.rate).toFixed(2) ||
+ undefined
+ )
+ } else {
+ return objectData?.price
+ }
+ }
+ },
+ {
+ name: 'priceMode',
+ label: 'Price Mode',
+ required: true,
+ type: 'priceMode'
+ },
+ {
+ name: 'margin',
+ label: 'Margin',
+ required: true,
+ type: 'number',
+ disabled: (objectData) => {
+ return objectData.priceMode == 'amount'
+ },
+ suffix: '%',
+ min: 0,
+ max: 100,
+ step: 0.01
+ },
+ {
+ name: 'priceTaxRate',
+ label: 'Price Tax Rate',
+ required: true,
+ type: 'object',
+ objectType: 'taxRate'
+ },
+ {
+ name: 'priceTaxRate._id',
+ label: 'Price Tax Rate ID',
+ readOnly: true,
+ type: 'id',
+ showHyperlink: true,
+ objectType: 'taxRate'
+ },
+
{
name: 'file',
label: 'File',
diff --git a/src/database/models/PurchaseOrder.js b/src/database/models/PurchaseOrder.js
index 865d0ed..1294577 100644
--- a/src/database/models/PurchaseOrder.js
+++ b/src/database/models/PurchaseOrder.js
@@ -59,21 +59,6 @@ export const PurchaseOrder = {
showHyperlink: true,
objectType: 'vendor'
},
- {
- name: 'courierService',
- label: 'Courier Service',
- required: true,
- type: 'object',
- objectType: 'courierService'
- },
- {
- name: 'courierService._id',
- label: 'Courier Service ID',
- readOnly: true,
- type: 'id',
- showHyperlink: true,
- objectType: 'courierService'
- },
{
name: 'items',
label: 'Order Items',
@@ -108,29 +93,97 @@ export const PurchaseOrder = {
return objectData?.item?._id
}
},
+
{
- name: 'quantity',
- label: 'Quantity',
- type: 'number',
- required: true
- },
- {
- name: 'price',
- label: 'Price',
+ name: 'itemCost',
+ label: 'Item Cost',
type: 'number',
required: true,
prefix: '£',
min: 0,
step: 0.01,
+ columnWidth: 150,
value: (objectData) => {
- if (objectData?.price == undefined) {
- console.log('PurchaseOrder.js', objectData)
+ if (objectData?.item) {
+ return objectData?.item?.cost || undefined
+ } else {
+ return undefined
+ }
+ }
+ },
+ {
+ name: 'quantity',
+ label: 'Quantity',
+ type: 'number',
+ required: true,
+ columnWidth: 150
+ },
+ {
+ name: 'totalCost',
+ label: 'Total Cost',
+ type: 'number',
+ required: true,
+ prefix: '£',
+ min: 0,
+ step: 0.01,
+ columnWidth: 150,
+ value: (objectData) => {
+ return (
+ (objectData?.itemCost || 0) * (objectData?.quantity || 0) ||
+ undefined
+ )
+ }
+ },
+ {
+ name: 'taxRate',
+ label: 'Tax Rate',
+ type: 'object',
+ objectType: 'taxRate',
+ value: (objectData) => {
+ if (objectData?.item) {
+ console.log(objectData?.item)
+ return objectData?.item?.costTaxRate || undefined
+ } else {
+ return undefined
+ }
+ }
+ },
+ {
+ name: 'taxRate._id',
+ label: 'Tax Rate ID',
+ type: 'id',
+ showHyperlink: true,
+ objectType: 'taxRate',
+ value: (objectData) => {
+ return objectData?.taxRate?._id || undefined
+ }
+ },
+ {
+ name: 'totalCostWithTax',
+ label: 'Total Cost With Tax',
+ type: 'number',
+ required: true,
+ readOnly: true,
+ prefix: '£',
+ min: 0,
+ step: 0.01,
+ columnWidth: 175,
+ value: (objectData) => {
+ if (objectData?.taxRate?.rateType == 'percentage') {
return (
- (objectData?.item?.cost || 0) * (objectData?.quantity || 0) ||
- undefined
+ (
+ (objectData?.totalCost || 0) *
+ (1 + objectData?.taxRate?.rate / 100)
+ ).toFixed(2) || undefined
+ )
+ } else if (objectData?.taxRate?.rateType == 'amount') {
+ return (
+ (
+ (objectData?.totalCost || 0) + objectData?.taxRate?.rate
+ ).toFixed(2) || undefined
)
} else {
- return objectData?.part?.price || undefined
+ return objectData?.totalCost || undefined
}
}
}
@@ -149,13 +202,27 @@ export const PurchaseOrder = {
}
},
{
- name: 'totalPrice',
+ name: 'totalCost',
label: 'Total',
type: 'number',
prefix: '£',
- property: 'price',
+ property: 'totalCost',
value: (objectData) => {
- return objectData?.items?.reduce((acc, item) => acc + item.price, 0)
+ return objectData?.items
+ ?.reduce((acc, item) => acc + (item.totalCost || 0), 0)
+ .toFixed(2)
+ }
+ },
+ {
+ name: 'totalCostWithTax',
+ label: 'Total',
+ type: 'number',
+ prefix: '£',
+ property: 'totalCostWithTax',
+ value: (objectData) => {
+ return objectData?.items
+ ?.reduce((acc, item) => acc + (item.totalCostWithTax || 0), 0)
+ .toFixed(2)
}
}
]
diff --git a/src/database/models/SubJob.js b/src/database/models/SubJob.js
index 2f856a4..277d67a 100644
--- a/src/database/models/SubJob.js
+++ b/src/database/models/SubJob.js
@@ -68,6 +68,36 @@ export const SubJob = {
readOnly: true,
columnWidth: 175
},
+
+ {
+ name: 'moonrakerJobId',
+ label: 'Moonraker Job ID',
+ type: 'miscId',
+ columnWidth: 140,
+ showCopy: true
+ },
+
+ {
+ name: 'startedAt',
+ label: 'Started At',
+ type: 'dateTime',
+ readOnly: true
+ },
+
+ {
+ name: 'createdPartStock',
+ label: 'Created Part Stock',
+ type: 'bool',
+ readOnly: true
+ },
+
+ {
+ name: 'finishedAt',
+ label: 'Finished At',
+ type: 'dateTime',
+ readOnly: true
+ },
+
{
name: 'job',
label: 'Job',
@@ -83,27 +113,6 @@ export const SubJob = {
objectType: 'job'
},
- {
- name: 'startedAt',
- label: 'Started At',
- type: 'dateTime',
- readOnly: true
- },
-
- {
- name: 'moonrakerJobId',
- label: 'Moonraker Job ID',
- type: 'miscId',
- columnWidth: 140,
- showCopy: true
- },
-
- {
- name: 'finishedAt',
- label: 'Finished At',
- type: 'dateTime',
- readOnly: true
- },
{
name: 'printer',
label: 'Printer',
diff --git a/src/database/models/TaxRate.js b/src/database/models/TaxRate.js
new file mode 100644
index 0000000..82e49f3
--- /dev/null
+++ b/src/database/models/TaxRate.js
@@ -0,0 +1,181 @@
+import TaxRateIcon from '../../components/Icons/TaxRateIcon'
+import InfoCircleIcon from '../../components/Icons/InfoCircleIcon'
+import EditIcon from '../../components/Icons/EditIcon'
+import CheckIcon from '../../components/Icons/CheckIcon'
+import XMarkIcon from '../../components/Icons/XMarkIcon'
+import ReloadIcon from '../../components/Icons/ReloadIcon'
+import BinIcon from '../../components/Icons/BinIcon'
+
+export const TaxRate = {
+ name: 'taxRate',
+ label: 'Tax Rate',
+ prefix: 'TXR',
+ icon: TaxRateIcon,
+ actions: [
+ {
+ name: 'info',
+ label: 'Info',
+ default: true,
+ row: true,
+ icon: InfoCircleIcon,
+ url: (_id) => `/dashboard/management/taxrates/info?taxRateId=${_id}`
+ },
+ {
+ name: 'reload',
+ label: 'Reload',
+ icon: ReloadIcon,
+ url: (_id) =>
+ `/dashboard/management/taxrates/info?taxRateId=${_id}&action=reload`
+ },
+ {
+ name: 'edit',
+ label: 'Edit',
+ row: true,
+ icon: EditIcon,
+ url: (_id) =>
+ `/dashboard/management/taxrates/info?taxRateId=${_id}&action=edit`,
+ visible: (objectData) => {
+ return !(objectData?._isEditing && objectData?._isEditing == true)
+ }
+ },
+ {
+ name: 'finishEdit',
+ label: 'Save Edits',
+ icon: CheckIcon,
+ url: (_id) =>
+ `/dashboard/management/taxrates/info?taxRateId=${_id}&action=finishEdit`,
+ visible: (objectData) => {
+ return objectData?._isEditing && objectData?._isEditing == true
+ }
+ },
+ {
+ name: 'cancelEdit',
+ label: 'Cancel Edits',
+ icon: XMarkIcon,
+ url: (_id) =>
+ `/dashboard/management/taxrates/info?taxRateId=${_id}&action=cancelEdit`,
+ visible: (objectData) => {
+ return objectData?._isEditing && objectData?._isEditing == true
+ }
+ },
+ { type: 'divider' },
+ {
+ name: 'delete',
+ label: 'Delete',
+ icon: BinIcon,
+ danger: true,
+ url: (_id) =>
+ `/dashboard/management/taxrates/info?taxRateId=${_id}&action=delete`
+ }
+ ],
+ columns: [
+ 'name',
+ '_id',
+ 'rate',
+ 'rateType',
+ 'active',
+ 'country',
+ 'createdAt'
+ ],
+ filters: ['name', '_id', 'rate', 'rateType', 'active', 'country'],
+ sorters: [
+ 'name',
+ 'rate',
+ 'rateType',
+ 'active',
+ 'country',
+ 'createdAt',
+ '_id'
+ ],
+ group: ['country', 'rateType'],
+ properties: [
+ {
+ name: '_id',
+ label: 'ID',
+ columnFixed: 'left',
+ type: 'id',
+ objectType: 'taxRate',
+ showCopy: true
+ },
+ {
+ name: 'createdAt',
+ label: 'Created At',
+ type: 'dateTime',
+ readOnly: true
+ },
+ {
+ name: 'name',
+ label: 'Name',
+ columnFixed: 'left',
+ required: true,
+ type: 'text'
+ },
+ {
+ name: 'updatedAt',
+ label: 'Updated At',
+ type: 'dateTime',
+ readOnly: true
+ },
+ {
+ name: 'active',
+ label: 'Active',
+ required: true,
+ type: 'bool',
+ default: true
+ },
+ {
+ name: 'effectiveFrom',
+ label: 'Effective From',
+ type: 'date',
+ readOnly: false,
+ required: false
+ },
+ {
+ name: 'rate',
+ label: 'Rate',
+ required: true,
+ type: 'number',
+ min: 0,
+ step: 0.01,
+ prefix: (objectData) => {
+ return objectData?.rateType == 'amount' ? '£' : undefined
+ },
+ suffix: (objectData) => {
+ return objectData?.rateType == 'percentage' ? '%' : undefined
+ }
+ },
+
+ {
+ name: 'effectiveTo',
+ label: 'Effective To',
+ type: 'date',
+ readOnly: false,
+ required: false
+ },
+
+ {
+ name: 'rateType',
+ label: 'Rate Type',
+ required: true,
+ type: 'select',
+ options: [
+ { label: 'Percentage', value: 'percentage' },
+ { label: 'Amount', value: 'amount' }
+ ]
+ },
+ {
+ name: 'country',
+ label: 'Country',
+ type: 'country',
+ readOnly: false,
+ required: false
+ },
+ {
+ name: 'description',
+ label: 'Description',
+ type: 'text',
+ readOnly: false,
+ required: false
+ }
+ ]
+}
diff --git a/src/database/models/TaxRecord.js b/src/database/models/TaxRecord.js
new file mode 100644
index 0000000..07f163d
--- /dev/null
+++ b/src/database/models/TaxRecord.js
@@ -0,0 +1,174 @@
+import TaxRecordIcon from '../../components/Icons/TaxRecordIcon'
+import InfoCircleIcon from '../../components/Icons/InfoCircleIcon'
+import EditIcon from '../../components/Icons/EditIcon'
+import CheckIcon from '../../components/Icons/CheckIcon'
+import XMarkIcon from '../../components/Icons/XMarkIcon'
+import ReloadIcon from '../../components/Icons/ReloadIcon'
+import BinIcon from '../../components/Icons/BinIcon'
+
+export const TaxRecord = {
+ name: 'taxRecord',
+ label: 'Tax Record',
+ prefix: 'TXR',
+ icon: TaxRecordIcon,
+ actions: [
+ {
+ name: 'info',
+ label: 'Info',
+ default: true,
+ row: true,
+ icon: InfoCircleIcon,
+ url: (_id) => `/dashboard/management/taxrecords/info?taxRecordId=${_id}`
+ },
+ {
+ name: 'reload',
+ label: 'Reload',
+ icon: ReloadIcon,
+ url: (_id) =>
+ `/dashboard/management/taxrecords/info?taxRecordId=${_id}&action=reload`
+ },
+ {
+ name: 'edit',
+ label: 'Edit',
+ row: true,
+ icon: EditIcon,
+ url: (_id) =>
+ `/dashboard/management/taxrecords/info?taxRecordId=${_id}&action=edit`,
+ visible: (objectData) => {
+ return !(objectData?._isEditing && objectData?._isEditing == true)
+ }
+ },
+ {
+ name: 'finishEdit',
+ label: 'Save Edits',
+ icon: CheckIcon,
+ url: (_id) =>
+ `/dashboard/management/taxrecords/info?taxRecordId=${_id}&action=finishEdit`,
+ visible: (objectData) => {
+ return objectData?._isEditing && objectData?._isEditing == true
+ }
+ },
+ {
+ name: 'cancelEdit',
+ label: 'Cancel Edits',
+ icon: XMarkIcon,
+ url: (_id) =>
+ `/dashboard/management/taxrecords/info?taxRecordId=${_id}&action=cancelEdit`,
+ visible: (objectData) => {
+ return objectData?._isEditing && objectData?._isEditing == true
+ }
+ },
+ { type: 'divider' },
+ {
+ name: 'delete',
+ label: 'Delete',
+ icon: BinIcon,
+ danger: true,
+ url: (_id) =>
+ `/dashboard/management/taxrecords/info?taxRecordId=${_id}&action=delete`
+ }
+ ],
+ columns: [
+ '_id',
+ 'taxRate',
+ 'transactionType',
+ 'transaction',
+ 'amount',
+ 'taxAmount',
+ 'transactionDate',
+ 'createdAt'
+ ],
+ filters: ['taxRate', 'transactionType', 'transaction', 'transactionDate'],
+ sorters: ['transactionDate', 'amount', 'taxAmount', 'createdAt', '_id'],
+ group: ['transactionType'],
+ properties: [
+ {
+ name: '_id',
+ label: 'ID',
+ columnFixed: 'left',
+ type: 'id',
+ objectType: 'taxRecord',
+ showCopy: true
+ },
+ {
+ name: 'createdAt',
+ label: 'Created At',
+ type: 'dateTime',
+ readOnly: true
+ },
+ {
+ name: 'taxRate',
+ label: 'Tax Rate',
+ required: true,
+ type: 'object',
+ objectType: 'taxRate'
+ },
+ {
+ name: 'taxRate._id',
+ label: 'Tax Rate ID',
+ readOnly: true,
+ type: 'id',
+ showHyperlink: true,
+ objectType: 'taxRate'
+ },
+ {
+ name: 'transactionType',
+ label: 'Transaction Type',
+ required: true,
+ type: 'select',
+ options: [
+ { label: 'Purchase Order', value: 'purchaseOrder' },
+ { label: 'Sales Order', value: 'salesOrder' },
+ { label: 'Other', value: 'other' }
+ ]
+ },
+ {
+ name: 'transaction',
+ label: 'Transaction',
+ required: true,
+ type: 'object',
+ objectType: (objectData) => {
+ return objectData?.transactionType || 'purchaseOrder'
+ }
+ },
+ {
+ name: 'transaction._id',
+ label: 'Transaction ID',
+ readOnly: true,
+ type: 'id',
+ showHyperlink: true,
+ objectType: (objectData) => {
+ return objectData?.transactionType || 'purchaseOrder'
+ }
+ },
+ {
+ name: 'amount',
+ label: 'Amount',
+ required: true,
+ type: 'currency',
+ min: 0,
+ step: 0.01
+ },
+ {
+ name: 'taxAmount',
+ label: 'Tax Amount',
+ required: true,
+ type: 'currency',
+ min: 0,
+ step: 0.01
+ },
+ {
+ name: 'transactionDate',
+ label: 'Transaction Date',
+ required: true,
+ type: 'date',
+ default: () => new Date()
+ },
+ {
+ name: 'updatedAt',
+ label: 'Updated At',
+ type: 'dateTime',
+ readOnly: true
+ }
+ ]
+}
diff --git a/src/routes/ManagementRoutes.jsx b/src/routes/ManagementRoutes.jsx
index 5ceb824..16b84d4 100644
--- a/src/routes/ManagementRoutes.jsx
+++ b/src/routes/ManagementRoutes.jsx
@@ -33,6 +33,10 @@ import DocumentJobInfo from '../components/Dashboard/Management/DocumentJobs/Doc
import DocumentTemplateDesign from '../components/Dashboard/Management/DocumentTemplates/DocumentTemplateDesign.jsx'
import Files from '../components/Dashboard/Management/Files.jsx'
import FileInfo from '../components/Dashboard/Management/Files/FileInfo.jsx'
+import TaxRates from '../components/Dashboard/Management/TaxRates.jsx'
+import TaxRateInfo from '../components/Dashboard/Management/TaxRates/TaxRateInfo.jsx'
+import TaxRecords from '../components/Dashboard/Management/TaxRecords.jsx'
+import TaxRecordInfo from '../components/Dashboard/Management/TaxRecords/TaxRecordInfo.jsx'
const ManagementRoutes = [
} />,
@@ -147,7 +151,23 @@ const ManagementRoutes = [
/>,
} />,
} />,
- } />
+ } />,
+ } />,
+ }
+ />,
+ }
+ />,
+ }
+ />
]
export default ManagementRoutes