diff --git a/assets/icons/financeicon.svg b/assets/icons/financeicon.svg
new file mode 100644
index 0000000..565e9cf
--- /dev/null
+++ b/assets/icons/financeicon.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/assets/icons/invoiceicon.svg b/assets/icons/invoiceicon.svg
new file mode 100644
index 0000000..77b14a6
--- /dev/null
+++ b/assets/icons/invoiceicon.svg
@@ -0,0 +1,14 @@
+
+
+
+
diff --git a/src/components/Dashboard/Finance/FinanceOverview.jsx b/src/components/Dashboard/Finance/FinanceOverview.jsx
new file mode 100644
index 0000000..5df8e4c
--- /dev/null
+++ b/src/components/Dashboard/Finance/FinanceOverview.jsx
@@ -0,0 +1,61 @@
+import { useContext } from 'react'
+import { Flex } from 'antd'
+import useCollapseState from '../hooks/useCollapseState'
+import StatsDisplay from '../common/StatsDisplay'
+import InfoCollapse from '../common/InfoCollapse'
+import ScrollBox from '../common/ScrollBox'
+
+import { ApiServerContext } from '../context/ApiServerContext'
+
+const FinanceOverview = () => {
+ const { connected } = useContext(ApiServerContext)
+
+ const [collapseState, updateCollapseState] = useCollapseState(
+ 'FinanceOverview',
+ {
+ invoiceStats: true
+ }
+ )
+
+ if (!connected) {
+ return null
+ }
+
+ return (
+
+
+
+
+ updateCollapseState('invoiceStats', isActive)
+ }
+ className='no-t-padding-collapse'
+ collapseKey='invoiceStats'
+ >
+
+
+
+
+
+
+
+ )
+}
+
+export default FinanceOverview
+
diff --git a/src/components/Dashboard/Finance/FinanceSidebar.jsx b/src/components/Dashboard/Finance/FinanceSidebar.jsx
new file mode 100644
index 0000000..7f763da
--- /dev/null
+++ b/src/components/Dashboard/Finance/FinanceSidebar.jsx
@@ -0,0 +1,46 @@
+import { useLocation } from 'react-router-dom'
+import DashboardSidebar from '../common/DashboardSidebar'
+import InvoiceIcon from '../../Icons/InvoiceIcon'
+import FinanceIcon from '../../Icons/FinanceIcon'
+
+const items = [
+ {
+ key: 'overview',
+ label: 'Overview',
+ icon: ,
+ path: '/dashboard/finance/overview'
+ },
+ { type: 'divider' },
+ {
+ key: 'invoices',
+ label: 'Invoices',
+ icon: ,
+ path: '/dashboard/finance/invoices'
+ }
+]
+
+const routeKeyMap = {
+ '/dashboard/finance/overview': 'overview',
+ '/dashboard/finance/invoices': 'invoices'
+}
+
+const FinanceSidebar = (props) => {
+ const location = useLocation()
+ const selectedKey = (() => {
+ const match = Object.keys(routeKeyMap).find((path) => {
+ const pathSplit = path.split('/')
+ const locationPathSplit = location.pathname.split('/')
+ if (pathSplit.length > locationPathSplit.length) return false
+ for (let i = 0; i < pathSplit.length; i++) {
+ if (pathSplit[i] !== locationPathSplit[i]) return false
+ }
+ return true
+ })
+ return match ? routeKeyMap[match] : 'overview'
+ })()
+
+ return
+}
+
+export default FinanceSidebar
+
diff --git a/src/components/Dashboard/Finance/Invoices.jsx b/src/components/Dashboard/Finance/Invoices.jsx
new file mode 100644
index 0000000..5f59c6e
--- /dev/null
+++ b/src/components/Dashboard/Finance/Invoices.jsx
@@ -0,0 +1,98 @@
+import { useState, useRef } from 'react'
+import { Button, Flex, Space, Dropdown, Modal } from 'antd'
+import NewInvoice from './Invoices/NewInvoice'
+import ObjectTable from '../common/ObjectTable'
+import PlusIcon from '../../Icons/PlusIcon'
+import ReloadIcon from '../../Icons/ReloadIcon'
+import useColumnVisibility from '../hooks/useColumnVisibility'
+import GridIcon from '../../Icons/GridIcon'
+import ListIcon from '../../Icons/ListIcon'
+import useViewMode from '../hooks/useViewMode'
+import ColumnViewButton from '../common/ColumnViewButton'
+
+const Invoices = () => {
+ const [newInvoiceOpen, setNewInvoiceOpen] = useState(false)
+ const tableRef = useRef()
+
+ const [viewMode, setViewMode] = useViewMode('invoices')
+
+ const [columnVisibility, setColumnVisibility] =
+ useColumnVisibility('invoices')
+
+ const actionItems = {
+ items: [
+ {
+ label: 'New Invoice',
+ key: 'newInvoice',
+ icon:
+ },
+ { type: 'divider' },
+ {
+ label: 'Reload List',
+ key: 'reloadList',
+ icon:
+ }
+ ],
+ onClick: ({ key }) => {
+ if (key === 'reloadList') {
+ tableRef.current?.reload()
+ } else if (key === 'newInvoice') {
+ setNewInvoiceOpen(true)
+ }
+ }
+ }
+
+ return (
+ <>
+
+
+
+
+
+
+
+
+
+ : }
+ onClick={() =>
+ setViewMode(viewMode === 'cards' ? 'list' : 'cards')
+ }
+ />
+
+
+
+
+ {
+ setNewInvoiceOpen(false)
+ }}
+ destroyOnHidden={true}
+ >
+ {
+ setNewInvoiceOpen(false)
+ tableRef.current?.reload()
+ }}
+ reset={newInvoiceOpen}
+ />
+
+ >
+ )
+}
+
+export default Invoices
diff --git a/src/components/Dashboard/Finance/Invoices/InvoiceInfo.jsx b/src/components/Dashboard/Finance/Invoices/InvoiceInfo.jsx
new file mode 100644
index 0000000..01d210e
--- /dev/null
+++ b/src/components/Dashboard/Finance/Invoices/InvoiceInfo.jsx
@@ -0,0 +1,218 @@
+import { useRef, useState } from 'react'
+import { useLocation } from 'react-router-dom'
+import { Space, Flex, Card } from 'antd'
+import { LoadingOutlined } from '@ant-design/icons'
+import loglevel from 'loglevel'
+import config from '../../../../config.js'
+import useCollapseState from '../../hooks/useCollapseState.js'
+import NotesPanel from '../../common/NotesPanel.jsx'
+import InfoCollapse from '../../common/InfoCollapse.jsx'
+import ObjectInfo from '../../common/ObjectInfo.jsx'
+import ViewButton from '../../common/ViewButton.jsx'
+import InfoCircleIcon from '../../../Icons/InfoCircleIcon.jsx'
+import NoteIcon from '../../../Icons/NoteIcon.jsx'
+import AuditLogIcon from '../../../Icons/AuditLogIcon.jsx'
+import ObjectForm from '../../common/ObjectForm.jsx'
+import EditButtons from '../../common/EditButtons.jsx'
+import LockIndicator from '../../common/LockIndicator.jsx'
+import ActionHandler from '../../common/ActionHandler.jsx'
+import ObjectActions from '../../common/ObjectActions.jsx'
+import ObjectTable from '../../common/ObjectTable.jsx'
+import InfoCollapsePlaceholder from '../../common/InfoCollapsePlaceholder.jsx'
+import DocumentPrintButton from '../../common/DocumentPrintButton.jsx'
+import ScrollBox from '../../common/ScrollBox.jsx'
+import { getModelByName } from '../../../../database/ObjectModels.js'
+
+const log = loglevel.getLogger('InvoiceInfo')
+log.setLevel(config.logLevel)
+
+const InvoiceInfo = () => {
+ const location = useLocation()
+ const objectFormRef = useRef(null)
+ const actionHandlerRef = useRef(null)
+ const invoiceId = new URLSearchParams(location.search).get('invoiceId')
+ const [collapseState, updateCollapseState] = useCollapseState(
+ 'InvoiceInfo',
+ {
+ info: true,
+ notes: true,
+ auditLogs: true
+ }
+ )
+
+ const [objectFormState, setEditFormState] = useState({
+ isEditing: false,
+ editLoading: false,
+ formValid: false,
+ lock: null,
+ loading: false,
+ objectData: {}
+ })
+
+ const actions = {
+ reload: () => {
+ objectFormRef?.current?.handleFetchObject?.()
+ return true
+ },
+ edit: () => {
+ objectFormRef?.current?.startEditing?.()
+ return false
+ },
+ cancelEdit: () => {
+ objectFormRef?.current?.cancelEditing?.()
+ return true
+ },
+ finishEdit: () => {
+ objectFormRef?.current?.handleUpdate?.()
+ return true
+ },
+ delete: () => {
+ objectFormRef?.current?.handleDelete?.()
+ return true
+ }
+ }
+
+ const editDisabled = getModelByName('invoice')
+ ?.actions?.find((action) => action.name === 'edit')
+ ?.disabled(objectFormState.objectData) ?? false
+
+ return (
+ <>
+
+
+
+
+
+
+
+
+
+
+
+ {
+ actionHandlerRef.current.callAction('finishEdit')
+ }}
+ cancelEditing={() => {
+ actionHandlerRef.current.callAction('cancelEdit')
+ }}
+ startEditing={() => {
+ actionHandlerRef.current.callAction('edit')
+ }}
+ editLoading={objectFormState.editLoading}
+ formValid={objectFormState.formValid}
+ disabled={
+ objectFormState.lock?.locked ||
+ objectFormState.loading ||
+ editDisabled
+ }
+ loading={objectFormState.editLoading}
+ />
+
+
+
+
+
+
+ {
+ setEditFormState((prev) => ({ ...prev, ...state }))
+ }}
+ >
+ {({ loading, isEditing, objectData }) => (
+
+ }
+ active={collapseState.info}
+ onToggle={(expanded) =>
+ updateCollapseState('info', expanded)
+ }
+ collapseKey='info'
+ >
+ }
+ isEditing={isEditing}
+ type='invoice'
+ labelWidth='225px'
+ objectData={objectData}
+ />
+
+
+ )}
+
+
+ }
+ active={collapseState.notes}
+ onToggle={(expanded) => updateCollapseState('notes', expanded)}
+ collapseKey='notes'
+ >
+
+
+
+
+ }
+ active={collapseState.auditLogs}
+ onToggle={(expanded) =>
+ updateCollapseState('auditLogs', expanded)
+ }
+ collapseKey='auditLogs'
+ >
+ {objectFormState.loading ? (
+
+ ) : (
+
+ )}
+
+
+
+
+ >
+ )
+}
+
+export default InvoiceInfo
+
diff --git a/src/components/Dashboard/Finance/Invoices/NewInvoice.jsx b/src/components/Dashboard/Finance/Invoices/NewInvoice.jsx
new file mode 100644
index 0000000..620cdaf
--- /dev/null
+++ b/src/components/Dashboard/Finance/Invoices/NewInvoice.jsx
@@ -0,0 +1,113 @@
+import PropTypes from 'prop-types'
+import ObjectInfo from '../../common/ObjectInfo'
+import NewObjectForm from '../../common/NewObjectForm'
+import WizardView from '../../common/WizardView'
+
+const NewInvoice = ({ onOk, reset, defaultValues }) => {
+ return (
+
+ {({ handleSubmit, submitLoading, objectData, formValid }) => {
+ const steps = [
+ {
+ title: 'Required',
+ key: 'required',
+ content: (
+
+ )
+ },
+ {
+ title: 'Optional',
+ key: 'optional',
+ content: (
+
+ )
+ },
+ {
+ title: 'Summary',
+ key: 'summary',
+ content: (
+
+ )
+ }
+ ]
+ return (
+ {
+ const result = await handleSubmit()
+ if (result) {
+ onOk()
+ }
+ }}
+ />
+ )
+ }}
+
+ )
+}
+
+NewInvoice.propTypes = {
+ onOk: PropTypes.func.isRequired,
+ reset: PropTypes.bool,
+ defaultValues: PropTypes.object
+}
+
+export default NewInvoice
diff --git a/src/components/Dashboard/common/DashboardBreadcrumb.jsx b/src/components/Dashboard/common/DashboardBreadcrumb.jsx
index 776a472..5a62ca9 100644
--- a/src/components/Dashboard/common/DashboardBreadcrumb.jsx
+++ b/src/components/Dashboard/common/DashboardBreadcrumb.jsx
@@ -10,6 +10,7 @@ const breadcrumbNameMap = {
inventory: 'Inventory',
management: 'Management',
developer: 'Developer',
+ finance: 'Finance',
overview: 'Overview',
info: 'Info',
design: 'Design',
diff --git a/src/components/Dashboard/common/DashboardNavigation.jsx b/src/components/Dashboard/common/DashboardNavigation.jsx
index 5672f7d..79799b2 100644
--- a/src/components/Dashboard/common/DashboardNavigation.jsx
+++ b/src/components/Dashboard/common/DashboardNavigation.jsx
@@ -30,6 +30,7 @@ import FarmControlLogoSmall from '../../Logos/FarmControlLogoSmall'
import MenuIcon from '../../Icons/MenuIcon'
import ProductionIcon from '../../Icons/ProductionIcon'
import InventoryIcon from '../../Icons/InventoryIcon'
+import FinanceIcon from '../../Icons/FinanceIcon'
import PersonIcon from '../../Icons/PersonIcon'
import CloudIcon from '../../Icons/CloudIcon'
import BellIcon from '../../Icons/BellIcon'
@@ -69,6 +70,11 @@ const DashboardNavigation = () => {
label: 'Inventory',
icon:
},
+ {
+ key: 'finance',
+ label: 'Finance',
+ icon:
+ },
{
key: 'management',
label: 'Management',
@@ -130,6 +136,8 @@ const DashboardNavigation = () => {
navigate('/dashboard/production/overview')
} else if (key === 'inventory') {
navigate('/dashboard/inventory/overview')
+ } else if (key === 'finance') {
+ navigate('/dashboard/finance/overview')
} else if (key === 'management') {
navigate('/dashboard/management/filaments')
}
diff --git a/src/components/Icons/InvoiceIcon.jsx b/src/components/Icons/InvoiceIcon.jsx
new file mode 100644
index 0000000..ac7e6f9
--- /dev/null
+++ b/src/components/Icons/InvoiceIcon.jsx
@@ -0,0 +1,9 @@
+import Icon from '@ant-design/icons'
+import CustomIconSvg from '../../../assets/icons/invoiceicon.svg?react'
+
+const InvoiceIcon = (props) => (
+
+)
+
+export default InvoiceIcon
+
diff --git a/src/database/models/Invoice.js b/src/database/models/Invoice.js
new file mode 100644
index 0000000..8aa8e52
--- /dev/null
+++ b/src/database/models/Invoice.js
@@ -0,0 +1,336 @@
+import InvoiceIcon from '../../components/Icons/InvoiceIcon'
+import InfoCircleIcon from '../../components/Icons/InfoCircleIcon'
+import CheckIcon from '../../components/Icons/CheckIcon'
+import EditIcon from '../../components/Icons/EditIcon'
+import XMarkIcon from '../../components/Icons/XMarkIcon'
+import BinIcon from '../../components/Icons/BinIcon'
+
+export const Invoice = {
+ name: 'invoice',
+ label: 'Invoice',
+ prefix: 'INV',
+ icon: InvoiceIcon,
+ actions: [
+ {
+ name: 'info',
+ label: 'Info',
+ default: true,
+ row: true,
+ icon: InfoCircleIcon,
+ url: (_id) => `/dashboard/finance/invoices/info?invoiceId=${_id}`
+ },
+ {
+ name: 'edit',
+ label: 'Edit',
+ type: 'button',
+ icon: EditIcon,
+ url: (_id) =>
+ `/dashboard/finance/invoices/info?invoiceId=${_id}&action=edit`,
+ visible: (objectData) => {
+ return !(objectData?._isEditing && objectData?._isEditing == true)
+ },
+ disabled: (objectData) => {
+ return objectData?.state?.type != 'draft'
+ }
+ },
+ {
+ name: 'cancelEdit',
+ label: 'Cancel Edit',
+ type: 'button',
+ icon: XMarkIcon,
+ url: (_id) =>
+ `/dashboard/finance/invoices/info?invoiceId=${_id}&action=cancelEdit`,
+ visible: (objectData) => {
+ return objectData?._isEditing && objectData?._isEditing == true
+ }
+ },
+ {
+ name: 'finishEdit',
+ label: 'Finish Edit',
+ type: 'button',
+ icon: CheckIcon,
+ url: (_id) =>
+ `/dashboard/finance/invoices/info?invoiceId=${_id}&action=finishEdit`,
+ visible: (objectData) => {
+ return objectData?._isEditing && objectData?._isEditing == true
+ }
+ },
+ {
+ name: 'delete',
+ label: 'Delete',
+ type: 'button',
+ icon: BinIcon,
+ danger: true,
+ url: (_id) =>
+ `/dashboard/finance/invoices/info?invoiceId=${_id}&action=delete`,
+ visible: (objectData) => {
+ return !(objectData?._isEditing && objectData?._isEditing == true)
+ },
+ disabled: (objectData) => {
+ return objectData?.state?.type != 'draft'
+ }
+ },
+ { type: 'divider' },
+ {
+ name: 'send',
+ label: 'Send',
+ type: 'button',
+ icon: CheckIcon,
+ url: (_id) =>
+ `/dashboard/finance/invoices/info?invoiceId=${_id}&action=send`,
+ visible: (objectData) => {
+ return objectData?.state?.type == 'draft'
+ }
+ },
+ {
+ name: 'markPaid',
+ label: 'Mark Paid',
+ type: 'button',
+ icon: CheckIcon,
+ url: (_id) =>
+ `/dashboard/finance/invoices/info?invoiceId=${_id}&action=markPaid`,
+ visible: (objectData) => {
+ return (
+ objectData?.state?.type == 'sent' ||
+ objectData?.state?.type == 'partiallyPaid'
+ )
+ }
+ },
+ {
+ name: 'cancel',
+ label: 'Cancel',
+ type: 'button',
+ icon: XMarkIcon,
+ danger: true,
+ url: (_id) =>
+ `/dashboard/finance/invoices/info?invoiceId=${_id}&action=cancel`,
+ disabled: (objectData) => {
+ return (
+ objectData?.state?.type == 'cancelled' ||
+ objectData?.state?.type == 'paid'
+ )
+ },
+ visible: (objectData) => {
+ return (
+ objectData?.state?.type == 'draft' ||
+ objectData?.state?.type == 'sent'
+ )
+ }
+ }
+ ],
+ group: ['vendor', 'customer', 'invoiceType'],
+ filters: ['vendor', 'customer', 'invoiceType'],
+ sorters: ['createdAt', 'state', 'updatedAt', 'invoiceDate', 'dueDate'],
+ columns: [
+ '_id',
+ '_reference',
+ 'state',
+ 'invoiceType',
+ 'vendor',
+ 'customer',
+ 'invoiceDate',
+ 'dueDate',
+ 'totalAmount',
+ 'totalAmountWithTax',
+ 'totalTaxAmount',
+ 'shippingAmount',
+ 'shippingAmountWithTax',
+ 'grandTotalAmount',
+ 'createdAt',
+ 'updatedAt'
+ ],
+ properties: [
+ {
+ name: '_id',
+ label: 'ID',
+ type: 'id',
+ columnFixed: 'left',
+ objectType: 'invoice',
+ columnWidth: 140,
+ showCopy: true
+ },
+ {
+ name: 'createdAt',
+ label: 'Created At',
+ type: 'dateTime',
+ readOnly: true
+ },
+ {
+ name: '_reference',
+ label: 'Reference',
+ type: 'reference',
+ required: true,
+ objectType: 'invoice',
+ showCopy: true,
+ readOnly: true
+ },
+ {
+ name: 'updatedAt',
+ label: 'Updated At',
+ type: 'dateTime',
+ readOnly: true
+ },
+ { name: 'state', label: 'State', type: 'state', readOnly: true },
+ {
+ name: 'invoiceDate',
+ label: 'Invoice Date',
+ type: 'date',
+ readOnly: false
+ },
+ {
+ name: 'dueDate',
+ label: 'Due Date',
+ type: 'date',
+ readOnly: false
+ },
+ {
+ name: 'vendor',
+ label: 'Vendor',
+ required: true,
+ type: 'object',
+ objectType: 'vendor',
+ showHyperlink: true,
+ visible: (objectData) => {
+ return objectData?.invoiceType === 'purchase' || objectData?.vendor
+ }
+ },
+ {
+ name: 'orderType',
+ label: 'Order Type',
+ type: 'objectType',
+ masterFilter: ['purchaseOrder', 'salesOrder'],
+ required: true
+ },
+ {
+ name: 'order',
+ label: 'Order',
+ type: 'object',
+ objectType: (objectData) => {
+ return objectData?.orderType
+ },
+ masterFilter: (objectData) => {
+ return {
+ vendor: objectData?.vendor?._id
+ }
+ },
+ required: true,
+ showHyperlink: true
+ },
+ {
+ name: 'sentAt',
+ label: 'Sent At',
+ type: 'dateTime',
+ readOnly: true
+ },
+ {
+ name: 'paidAt',
+ label: 'Paid At',
+ type: 'dateTime',
+ readOnly: true
+ },
+ {
+ name: 'cancelledAt',
+ label: 'Cancelled At',
+ type: 'dateTime',
+ readOnly: true
+ },
+ {
+ name: 'overdueAt',
+ label: 'Overdue At',
+ type: 'dateTime',
+ readOnly: true
+ },
+ {
+ name: 'totalTaxAmount',
+ label: 'Total Tax Amount',
+ type: 'number',
+ prefix: '£',
+ roundNumber: 2,
+ readOnly: true,
+ columnWidth: 175
+ },
+ {
+ name: 'totalAmountWithTax',
+ label: 'Total Amount w/ Tax',
+ type: 'number',
+ prefix: '£',
+ readOnly: true,
+ columnWidth: 175,
+ roundNumber: 2
+ },
+ {
+ name: 'shippingAmount',
+ label: 'Shipping Amount',
+ type: 'number',
+ prefix: '£',
+ roundNumber: 2,
+ readOnly: true,
+ columnWidth: 150
+ },
+ {
+ name: 'shippingAmountWithTax',
+ label: 'Shipping Amount w/ Tax',
+ type: 'number',
+ prefix: '£',
+ readOnly: true,
+ roundNumber: 2,
+ columnWidth: 200
+ },
+ {
+ name: 'totalAmount',
+ label: 'Total Amount',
+ type: 'number',
+ prefix: '£',
+ roundNumber: 2,
+ readOnly: true,
+ columnWidth: 150
+ },
+ {
+ name: 'grandTotalAmount',
+ label: 'Grand Total Amount',
+ type: 'number',
+ prefix: '£',
+ roundNumber: 2,
+ columnWidth: 175,
+ readOnly: true
+ }
+ ],
+ stats: [
+ {
+ name: 'draft.count',
+ label: 'Draft',
+ type: 'number',
+ color: 'default'
+ },
+ {
+ name: 'sent.count',
+ label: 'Sent',
+ type: 'number',
+ color: 'cyan'
+ },
+ {
+ name: 'partiallyPaid.count',
+ label: 'Partially Paid',
+ type: 'number',
+ color: 'processing'
+ },
+ {
+ name: 'paid.count',
+ label: 'Paid',
+ type: 'number',
+ color: 'success'
+ },
+ {
+ name: 'overdue.count',
+ label: 'Overdue',
+ type: 'number',
+ color: 'error'
+ },
+ {
+ name: 'cancelled.count',
+ label: 'Cancelled',
+ type: 'number',
+ color: 'default'
+ }
+ ]
+}
diff --git a/src/routes/FinanceRoutes.jsx b/src/routes/FinanceRoutes.jsx
new file mode 100644
index 0000000..35f975a
--- /dev/null
+++ b/src/routes/FinanceRoutes.jsx
@@ -0,0 +1,29 @@
+import { lazy } from 'react'
+import { Route } from 'react-router-dom'
+
+const Invoices = lazy(
+ () => import('../components/Dashboard/Finance/Invoices.jsx')
+)
+const InvoiceInfo = lazy(
+ () => import('../components/Dashboard/Finance/Invoices/InvoiceInfo.jsx')
+)
+const FinanceOverview = lazy(
+ () => import('../components/Dashboard/Finance/FinanceOverview.jsx')
+)
+
+const FinanceRoutes = [
+ }
+ />,
+ } />,
+ }
+ />
+]
+
+export default FinanceRoutes
+
diff --git a/src/routes/index.js b/src/routes/index.js
index a99b9ef..57c46ab 100644
--- a/src/routes/index.js
+++ b/src/routes/index.js
@@ -1,4 +1,5 @@
export { default as ProductionRoutes } from './ProductionRoutes'
export { default as InventoryRoutes } from './InventoryRoutes'
+export { default as FinanceRoutes } from './FinanceRoutes'
export { default as ManagementRoutes } from './ManagementRoutes'
export { default as DeveloperRoutes } from './DeveloperRoutes'