Enhance Purchase Order management with new actions and UI updates

- Updated NewPurchaseOrder component to set default state to 'draft'.
- Removed unnecessary item property display and added new properties for total amounts and shipping details.
- Introduced new PurchaseOrderInfo component to manage order items and shipments, including modals for creating new items and shipments, posting, acknowledging, and canceling orders.
- Enhanced PurchaseOrder model with new actions for editing, canceling edits, finishing edits, and deleting orders, along with updated visibility and disabled states based on order status.
- Added new properties to the PurchaseOrder model for better tracking of order states and financial details.
This commit is contained in:
Tom Butcher 2025-12-27 13:52:50 +00:00
parent 62a494509a
commit 4a605ddc09
4 changed files with 777 additions and 35 deletions

View File

@ -2,15 +2,15 @@ import PropTypes from 'prop-types'
import ObjectInfo from '../../common/ObjectInfo' import ObjectInfo from '../../common/ObjectInfo'
import NewObjectForm from '../../common/NewObjectForm' import NewObjectForm from '../../common/NewObjectForm'
import WizardView from '../../common/WizardView' import WizardView from '../../common/WizardView'
import { getModelProperty } from '../../../../database/ObjectModels.js'
import ObjectProperty from '../../common/ObjectProperty.jsx'
const NewPurchaseOrder = ({ onOk, reset, defaultValues }) => { const NewPurchaseOrder = ({ onOk, reset, defaultValues }) => {
return ( return (
<NewObjectForm <NewObjectForm
type={'purchaseOrder'} type={'purchaseOrder'}
reset={reset} reset={reset}
defaultValues={{ state: { type: 'new' }, ...defaultValues }} defaultValues={{
state: { type: 'draft' },
...defaultValues
}}
> >
{({ handleSubmit, submitLoading, objectData, formValid }) => { {({ handleSubmit, submitLoading, objectData, formValid }) => {
const steps = [ const steps = [
@ -26,24 +26,13 @@ const NewPurchaseOrder = ({ onOk, reset, defaultValues }) => {
required={true} required={true}
objectData={objectData} objectData={objectData}
visibleProperties={{ visibleProperties={{
_reference: false,
items: false, items: false,
cost: false cost: false
}} }}
/> />
) )
}, },
{
title: 'Items',
key: 'items',
content: (
<ObjectProperty
{...getModelProperty('purchaseOrder', 'items')}
isEditing={true}
objectData={objectData}
loading={submitLoading}
/>
)
},
{ {
title: 'Summary', title: 'Summary',
key: 'summary', key: 'summary',
@ -56,7 +45,15 @@ const NewPurchaseOrder = ({ onOk, reset, defaultValues }) => {
_id: false, _id: false,
createdAt: false, createdAt: false,
updatedAt: false, updatedAt: false,
items: false _reference: false,
totalAmount: false,
totalAmountWithTax: false,
totalTaxAmount: false,
postedAt: false,
acknowledgedAt: false,
shippingAmount: false,
shippingAmountWithTax: false,
grandTotalAmount: false
}} }}
isEditing={false} isEditing={false}
objectData={objectData} objectData={objectData}

View File

@ -23,6 +23,12 @@ import DocumentPrintButton from '../../common/DocumentPrintButton.jsx'
import ScrollBox from '../../common/ScrollBox.jsx' import ScrollBox from '../../common/ScrollBox.jsx'
import OrderItemsIcon from '../../../Icons/OrderItemIcon.jsx' import OrderItemsIcon from '../../../Icons/OrderItemIcon.jsx'
import NewOrderItem from '../OrderItems/NewOrderItem.jsx' import NewOrderItem from '../OrderItems/NewOrderItem.jsx'
import NewShipment from '../Shipments/NewShipment.jsx'
import PostPurchaseOrder from './PostPurchaseOrder.jsx'
import AcknowledgePurchaseOrder from './AcknowledgePurchaseOrder.jsx'
import CancelPurchaseOrder from './CancelPurchaseOrder.jsx'
import ShipmentIcon from '../../../Icons/ShipmentIcon.jsx'
import { getModelByName } from '../../../../database/ObjectModels.js'
const log = loglevel.getLogger('PurchaseOrderInfo') const log = loglevel.getLogger('PurchaseOrderInfo')
log.setLevel(config.logLevel) log.setLevel(config.logLevel)
@ -30,8 +36,15 @@ log.setLevel(config.logLevel)
const PurchaseOrderInfo = () => { const PurchaseOrderInfo = () => {
const location = useLocation() const location = useLocation()
const objectFormRef = useRef(null) const objectFormRef = useRef(null)
const orderItemsTableRef = useRef(null)
const shipmentsTableRef = useRef(null)
const actionHandlerRef = useRef(null) const actionHandlerRef = useRef(null)
const [newOrderItemOpen, setNewOrderItemOpen] = useState(false) const [newOrderItemOpen, setNewOrderItemOpen] = useState(false)
const [newShipmentOpen, setNewShipmentOpen] = useState(false)
const [postPurchaseOrderOpen, setPostPurchaseOrderOpen] = useState(false)
const [acknowledgePurchaseOrderOpen, setAcknowledgePurchaseOrderOpen] =
useState(false)
const [cancelPurchaseOrderOpen, setCancelPurchaseOrderOpen] = useState(false)
const purchaseOrderId = new URLSearchParams(location.search).get( const purchaseOrderId = new URLSearchParams(location.search).get(
'purchaseOrderId' 'purchaseOrderId'
) )
@ -59,14 +72,17 @@ const PurchaseOrderInfo = () => {
return true return true
}, },
edit: () => { edit: () => {
orderItemsTableRef?.current?.startEditing?.()
objectFormRef?.current?.startEditing?.() objectFormRef?.current?.startEditing?.()
return false return false
}, },
cancelEdit: () => { cancelEdit: () => {
orderItemsTableRef?.current?.cancelEditing?.()
objectFormRef?.current?.cancelEditing?.() objectFormRef?.current?.cancelEditing?.()
return true return true
}, },
finishEdit: () => { finishEdit: () => {
orderItemsTableRef?.current?.handleUpdate?.()
objectFormRef?.current?.handleUpdate?.() objectFormRef?.current?.handleUpdate?.()
return true return true
}, },
@ -77,9 +93,29 @@ const PurchaseOrderInfo = () => {
newOrderItem: () => { newOrderItem: () => {
setNewOrderItemOpen(true) setNewOrderItemOpen(true)
return true return true
},
newShipment: () => {
setNewShipmentOpen(true)
return true
},
post: () => {
setPostPurchaseOrderOpen(true)
return true
},
acknowledge: () => {
setAcknowledgePurchaseOrderOpen(true)
return true
},
cancel: () => {
setCancelPurchaseOrderOpen(true)
return true
} }
} }
const editDisabled = getModelByName('purchaseOrder')
.actions.find((action) => action.name === 'edit')
.disabled(objectFormState.objectData)
return ( return (
<> <>
<Flex <Flex
@ -103,6 +139,8 @@ const PurchaseOrderInfo = () => {
disabled={objectFormState.loading} disabled={objectFormState.loading}
items={[ items={[
{ key: 'info', label: 'Purchase Order Information' }, { key: 'info', label: 'Purchase Order Information' },
{ key: 'orderItems', label: 'Order Items' },
{ key: 'shipments', label: 'Shipments' },
{ key: 'notes', label: 'Notes' }, { key: 'notes', label: 'Notes' },
{ key: 'auditLogs', label: 'Audit Logs' } { key: 'auditLogs', label: 'Audit Logs' }
]} ]}
@ -131,7 +169,11 @@ const PurchaseOrderInfo = () => {
}} }}
editLoading={objectFormState.editLoading} editLoading={objectFormState.editLoading}
formValid={objectFormState.formValid} formValid={objectFormState.formValid}
disabled={objectFormState.lock?.locked || objectFormState.loading} disabled={
objectFormState.lock?.locked ||
objectFormState.loading ||
editDisabled
}
loading={objectFormState.editLoading} loading={objectFormState.editLoading}
/> />
</Space> </Space>
@ -169,6 +211,7 @@ const PurchaseOrderInfo = () => {
indicator={<LoadingOutlined />} indicator={<LoadingOutlined />}
isEditing={isEditing} isEditing={isEditing}
type='purchaseOrder' type='purchaseOrder'
labelWidth='225px'
objectData={objectData} objectData={objectData}
visibleProperties={{ visibleProperties={{
items: false items: false
@ -178,16 +221,39 @@ const PurchaseOrderInfo = () => {
<InfoCollapse <InfoCollapse
title='Purchase Order Items' title='Purchase Order Items'
icon={<OrderItemsIcon />} icon={<OrderItemsIcon />}
active={collapseState.info} active={collapseState.orderItems}
onToggle={(expanded) => onToggle={(expanded) =>
updateCollapseState('info', expanded) updateCollapseState('orderItems', expanded)
} }
collapseKey='info' collapseKey='orderItems'
> >
<ObjectTable <ObjectTable
type='orderItem' type='orderItem'
masterFilter={{ 'order._id': purchaseOrderId }} masterFilter={{
'order._id': purchaseOrderId,
orderType: 'purchaseOrder'
}}
visibleColumns={{ order: false }} visibleColumns={{ order: false }}
ref={orderItemsTableRef}
/>
</InfoCollapse>
<InfoCollapse
title='Shipments'
icon={<ShipmentIcon />}
active={collapseState.shipments}
onToggle={(expanded) =>
updateCollapseState('shipments', expanded)
}
collapseKey='shipments'
>
<ObjectTable
type='shipment'
masterFilter={{
'order._id': purchaseOrderId,
orderType: 'purchaseOrder'
}}
visibleColumns={{ order: false }}
ref={shipmentsTableRef}
/> />
</InfoCollapse> </InfoCollapse>
</Flex> </Flex>
@ -248,6 +314,80 @@ const PurchaseOrderInfo = () => {
}} }}
/> />
</Modal> </Modal>
<Modal
open={newShipmentOpen}
onCancel={() => {
setNewShipmentOpen(false)
}}
width={800}
footer={null}
destroyOnHidden={true}
>
<NewShipment
onOk={() => {
setNewShipmentOpen(false)
}}
reset={newShipmentOpen}
defaultValues={{
orderType: 'purchaseOrder',
order: { _id: purchaseOrderId }
}}
/>
</Modal>
<Modal
open={postPurchaseOrderOpen}
onCancel={() => {
setPostPurchaseOrderOpen(false)
}}
width={500}
footer={null}
destroyOnHidden={true}
centered={true}
>
<PostPurchaseOrder
onOk={() => {
setPostPurchaseOrderOpen(false)
actions.reload()
}}
objectData={objectFormState.objectData}
/>
</Modal>
<Modal
open={acknowledgePurchaseOrderOpen}
onCancel={() => {
setAcknowledgePurchaseOrderOpen(false)
}}
width={515}
footer={null}
destroyOnHidden={true}
centered={true}
>
<AcknowledgePurchaseOrder
onOk={() => {
setAcknowledgePurchaseOrderOpen(false)
actions.reload()
}}
objectData={objectFormState.objectData}
/>
</Modal>
<Modal
open={cancelPurchaseOrderOpen}
onCancel={() => {
setCancelPurchaseOrderOpen(false)
}}
width={515}
footer={null}
destroyOnHidden={true}
centered={true}
>
<CancelPurchaseOrder
onOk={() => {
setCancelPurchaseOrderOpen(false)
actions.reload()
}}
objectData={objectFormState.objectData}
/>
</Modal>
</> </>
) )
} }

View File

@ -0,0 +1,362 @@
import { useRef, useState } from 'react'
import { useLocation } from 'react-router-dom'
import { Space, Flex, Card, Modal } 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 OrderItemsIcon from '../../../Icons/OrderItemIcon.jsx'
import NewOrderItem from '../OrderItems/NewOrderItem.jsx'
import NewShipment from './NewShipment.jsx'
import PostPurchaseOrder from '../PurchaseOrders/PostPurchaseOrder.jsx'
import AcknowledgePurchaseOrder from '../PurchaseOrders/AcknowledgePurchaseOrder.jsx'
import ShipmentIcon from '../../../Icons/ShipmentIcon.jsx'
const log = loglevel.getLogger('PurchaseOrderInfo')
log.setLevel(config.logLevel)
const PurchaseOrderInfo = () => {
const location = useLocation()
const objectFormRef = useRef(null)
const orderItemsTableRef = useRef(null)
const shipmentsTableRef = useRef(null)
const actionHandlerRef = useRef(null)
const [newOrderItemOpen, setNewOrderItemOpen] = useState(false)
const [newShipmentOpen, setNewShipmentOpen] = useState(false)
const [postPurchaseOrderOpen, setPostPurchaseOrderOpen] = useState(false)
const [acknowledgePurchaseOrderOpen, setAcknowledgePurchaseOrderOpen] =
useState(false)
const purchaseOrderId = new URLSearchParams(location.search).get(
'purchaseOrderId'
)
const [collapseState, updateCollapseState] = useCollapseState(
'PurchaseOrderInfo',
{
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: () => {
orderItemsTableRef?.current?.startEditing?.()
objectFormRef?.current?.startEditing?.()
return false
},
cancelEdit: () => {
orderItemsTableRef?.current?.cancelEditing?.()
objectFormRef?.current?.cancelEditing?.()
return true
},
finishEdit: () => {
orderItemsTableRef?.current?.handleUpdate?.()
objectFormRef?.current?.handleUpdate?.()
return true
},
delete: () => {
objectFormRef?.current?.handleDelete?.()
return true
},
newOrderItem: () => {
setNewOrderItemOpen(true)
return true
},
newShipment: () => {
setNewShipmentOpen(true)
return true
},
post: () => {
setPostPurchaseOrderOpen(true)
return true
},
acknowledge: () => {
setAcknowledgePurchaseOrderOpen(true)
return true
}
}
return (
<>
<Flex
gap='large'
vertical='true'
style={{
maxHeight: '100%',
minHeight: 0
}}
>
<Flex justify={'space-between'}>
<Space size='middle'>
<Space size='small'>
<ObjectActions
type='purchaseOrder'
id={purchaseOrderId}
disabled={objectFormState.loading}
objectData={objectFormState.objectData}
/>
<ViewButton
disabled={objectFormState.loading}
items={[
{ key: 'info', label: 'Purchase Order Information' },
{ key: 'orderItems', label: 'Order Items' },
{ key: 'shipments', label: 'Shipments' },
{ key: 'notes', label: 'Notes' },
{ key: 'auditLogs', label: 'Audit Logs' }
]}
visibleState={collapseState}
updateVisibleState={updateCollapseState}
/>
<DocumentPrintButton
type='purchaseOrder'
objectData={objectFormState.objectData}
disabled={objectFormState.loading}
/>
</Space>
<LockIndicator lock={objectFormState.lock} />
</Space>
<Space>
<EditButtons
isEditing={objectFormState.isEditing}
handleUpdate={() => {
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}
loading={objectFormState.editLoading}
/>
</Space>
</Flex>
<ScrollBox>
<Flex vertical gap={'large'}>
<ActionHandler
actions={actions}
loading={objectFormState.loading}
ref={actionHandlerRef}
>
<ObjectForm
id={purchaseOrderId}
type='purchaseOrder'
style={{ height: '100%' }}
ref={objectFormRef}
onStateChange={(state) => {
setEditFormState((prev) => ({ ...prev, ...state }))
}}
>
{({ loading, isEditing, objectData }) => (
<Flex vertical gap={'large'}>
<InfoCollapse
title='Purchase Order Information'
icon={<InfoCircleIcon />}
active={collapseState.info}
onToggle={(expanded) =>
updateCollapseState('info', expanded)
}
collapseKey='info'
>
<ObjectInfo
loading={loading}
indicator={<LoadingOutlined />}
isEditing={isEditing}
type='purchaseOrder'
labelWidth='225px'
objectData={objectData}
visibleProperties={{
items: false
}}
/>
</InfoCollapse>
<InfoCollapse
title='Purchase Order Items'
icon={<OrderItemsIcon />}
active={collapseState.orderItems}
onToggle={(expanded) =>
updateCollapseState('orderItems', expanded)
}
collapseKey='orderItems'
>
<ObjectTable
type='orderItem'
masterFilter={{
'order._id': purchaseOrderId,
orderType: 'purchaseOrder'
}}
visibleColumns={{ order: false }}
ref={orderItemsTableRef}
/>
</InfoCollapse>
<InfoCollapse
title='Shipments'
icon={<ShipmentIcon />}
active={collapseState.shipments}
onToggle={(expanded) =>
updateCollapseState('shipments', expanded)
}
collapseKey='shipments'
>
<ObjectTable
type='shipment'
masterFilter={{
'order._id': purchaseOrderId,
orderType: 'purchaseOrder'
}}
visibleColumns={{ order: false }}
ref={shipmentsTableRef}
/>
</InfoCollapse>
</Flex>
)}
</ObjectForm>
</ActionHandler>
<InfoCollapse
title='Notes'
icon={<NoteIcon />}
active={collapseState.notes}
onToggle={(expanded) => updateCollapseState('notes', expanded)}
collapseKey='notes'
>
<Card>
<NotesPanel _id={purchaseOrderId} type='purchaseOrder' />
</Card>
</InfoCollapse>
<InfoCollapse
title='Audit Logs'
icon={<AuditLogIcon />}
active={collapseState.auditLogs}
onToggle={(expanded) =>
updateCollapseState('auditLogs', expanded)
}
collapseKey='auditLogs'
>
{objectFormState.loading ? (
<InfoCollapsePlaceholder />
) : (
<ObjectTable
type='auditLog'
masterFilter={{ 'parent._id': purchaseOrderId }}
visibleColumns={{ _id: false, 'parent._id': false }}
/>
)}
</InfoCollapse>
</Flex>
</ScrollBox>
</Flex>
<Modal
open={newOrderItemOpen}
onCancel={() => {
setNewOrderItemOpen(false)
}}
width={800}
footer={null}
destroyOnHidden={true}
>
<NewOrderItem
onOk={() => {
setNewOrderItemOpen(false)
}}
reset={newOrderItemOpen}
defaultValues={{
order: { _id: purchaseOrderId },
orderType: 'purchaseOrder',
syncAmount: 'itemCost'
}}
/>
</Modal>
<Modal
open={newShipmentOpen}
onCancel={() => {
setNewShipmentOpen(false)
}}
width={800}
footer={null}
destroyOnHidden={true}
>
<NewShipment
onOk={() => {
setNewShipmentOpen(false)
}}
reset={newShipmentOpen}
defaultValues={{
orderType: 'purchaseOrder',
order: { _id: purchaseOrderId }
}}
/>
</Modal>
<Modal
open={postPurchaseOrderOpen}
onCancel={() => {
setPostPurchaseOrderOpen(false)
}}
width={500}
footer={null}
destroyOnHidden={true}
centered={true}
>
<PostPurchaseOrder
onOk={() => {
setPostPurchaseOrderOpen(false)
actions.reload()
}}
objectData={objectFormState.objectData}
/>
</Modal>
<Modal
open={acknowledgePurchaseOrderOpen}
onCancel={() => {
setAcknowledgePurchaseOrderOpen(false)
}}
width={515}
footer={null}
destroyOnHidden={true}
centered={true}
>
<AcknowledgePurchaseOrder
onOk={() => {
setAcknowledgePurchaseOrderOpen(false)
actions.reload()
}}
objectData={objectFormState.objectData}
/>
</Modal>
</>
)
}
export default PurchaseOrderInfo

View File

@ -1,6 +1,10 @@
import PurchaseOrderIcon from '../../components/Icons/PurchaseOrderIcon' import PurchaseOrderIcon from '../../components/Icons/PurchaseOrderIcon'
import InfoCircleIcon from '../../components/Icons/InfoCircleIcon' import InfoCircleIcon from '../../components/Icons/InfoCircleIcon'
import PlusIcon from '../../components/Icons/PlusIcon' import PlusIcon from '../../components/Icons/PlusIcon'
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 PurchaseOrder = { export const PurchaseOrder = {
name: 'purchaseOrder', name: 'purchaseOrder',
@ -17,19 +21,168 @@ export const PurchaseOrder = {
url: (_id) => url: (_id) =>
`/dashboard/inventory/purchaseorders/info?purchaseOrderId=${_id}` `/dashboard/inventory/purchaseorders/info?purchaseOrderId=${_id}`
}, },
{
name: 'edit',
label: 'Edit',
type: 'button',
icon: EditIcon,
url: (_id) =>
`/dashboard/inventory/purchaseorders/info?purchaseOrderId=${_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/inventory/purchaseorders/info?purchaseOrderId=${_id}&action=cancelEdit`,
visible: (objectData) => {
return objectData?._isEditing && objectData?._isEditing == true
}
},
{
name: 'finishEdit',
label: 'Finish Edit',
type: 'button',
icon: CheckIcon,
url: (_id) =>
`/dashboard/inventory/purchaseorders/info?purchaseOrderId=${_id}&action=finishEdit`,
visible: (objectData) => {
return objectData?._isEditing && objectData?._isEditing == true
}
},
{
name: 'delete',
label: 'Delete',
type: 'button',
icon: BinIcon,
danger: true,
url: (_id) =>
`/dashboard/inventory/purchaseorders/info?purchaseOrderId=${_id}&action=delete`,
visible: (objectData) => {
return !(objectData?._isEditing && objectData?._isEditing == true)
},
disabled: (objectData) => {
return objectData?.state?.type != 'draft'
}
},
{ type: 'divider' },
{ {
name: 'New Order Item', name: 'New Order Item',
label: 'New Order Item', label: 'New Order Item',
type: 'button', type: 'button',
icon: PlusIcon, icon: PlusIcon,
url: (_id) => url: (_id) =>
`/dashboard/inventory/purchaseorders/info?purchaseOrderId=${_id}&action=newOrderItem` `/dashboard/inventory/purchaseorders/info?purchaseOrderId=${_id}&action=newOrderItem`,
disabled: (objectData) => {
return objectData?.state?.type != 'draft'
}
},
{
name: 'New Shipment',
label: 'New Shipment',
type: 'button',
icon: PlusIcon,
url: (_id) =>
`/dashboard/inventory/purchaseorders/info?purchaseOrderId=${_id}&action=newShipment`,
disabled: (objectData) => {
return objectData?.state?.type != 'draft'
}
},
{
name: 'New Invoice',
label: 'New Invoice',
type: 'button',
icon: PlusIcon,
url: (_id) =>
`/dashboard/inventory/purchaseorders/info?purchaseOrderId=${_id}&action=newInvoice`,
disabled: (objectData) => {
return objectData?.state?.type != 'received'
}
},
{
type: 'divider'
},
{
name: 'post',
label: 'Post',
type: 'button',
icon: CheckIcon,
url: (_id) =>
`/dashboard/inventory/purchaseorders/info?purchaseOrderId=${_id}&action=post`,
visible: (objectData) => {
return objectData?.state?.type == 'draft'
}
},
{
name: 'acknowledge',
label: 'Acknowledge',
type: 'button',
icon: CheckIcon,
url: (_id) =>
`/dashboard/inventory/purchaseorders/info?purchaseOrderId=${_id}&action=acknowledge`,
visible: (objectData) => {
return objectData?.state?.type == 'sent'
}
},
{
name: 'complete',
label: 'Complete',
type: 'button',
icon: CheckIcon,
url: (_id) =>
`/dashboard/inventory/shipments/info?shipmentId=${_id}&action=complete`,
disabled: (objectData) => {
return objectData?.state?.type != 'received'
},
visible: (objectData) => {
return objectData?.state?.type == 'received'
}
},
{
name: 'cancel',
label: 'Cancel',
type: 'button',
icon: XMarkIcon,
danger: true,
url: (_id) =>
`/dashboard/inventory/purchaseorders/info?purchaseOrderId=${_id}&action=cancel`,
disabled: (objectData) => {
return objectData?.state?.type == 'cancelled'
},
visible: (objectData) => {
return (
objectData?.state?.type != 'draft' &&
objectData?.state?.type != 'completed' &&
objectData?.state?.type != 'received'
)
}
} }
], ],
group: ['vendor'], group: ['vendor'],
filters: ['vendor'], filters: ['vendor'],
sorters: ['createdAt', 'state', 'updatedAt'], sorters: ['createdAt', 'state', 'updatedAt'],
columns: ['_id', 'createdAt', 'state', 'updatedAt', 'vendor'], columns: [
'_id',
'_reference',
'state',
'vendor',
'totalAmount',
'totalAmountWithTax',
'totalTaxAmount',
'shippingAmount',
'shippingAmountWithTax',
'grandTotalAmount',
'createdAt',
'updatedAt',
'vendor'
],
properties: [ properties: [
{ {
name: '_id', name: '_id',
@ -62,6 +215,7 @@ export const PurchaseOrder = {
readOnly: true readOnly: true
}, },
{ name: 'state', label: 'State', type: 'state', readOnly: true }, { name: 'state', label: 'State', type: 'state', readOnly: true },
{ name: 'postedAt', label: 'Posted At', type: 'dateTime', readOnly: true },
{ {
name: 'vendor', name: 'vendor',
label: 'Vendor', label: 'Vendor',
@ -71,17 +225,9 @@ export const PurchaseOrder = {
showHyperlink: true showHyperlink: true
}, },
{ {
name: 'totalAmount', name: 'acknowledgedAt',
label: 'Total Amount', label: 'Acknowledged At',
type: 'number', type: 'dateTime',
prefix: '£',
readOnly: true
},
{
name: 'totalAmountWithTax',
label: 'Total Amount w/ Tax',
type: 'number',
prefix: '£',
readOnly: true readOnly: true
}, },
{ {
@ -89,7 +235,104 @@ export const PurchaseOrder = {
label: 'Total Tax Amount', label: 'Total Tax Amount',
type: 'number', type: 'number',
prefix: '£', prefix: '£',
roundNumber: 2,
readOnly: true,
columnWidth: 175
},
{
name: 'CompletedAt',
label: 'Completed At',
type: 'dateTime',
readOnly: true readOnly: true
},
{
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: 'acknowledged.count',
label: 'Acknowledged',
type: 'number',
color: 'processing'
},
{
name: 'partiallyShipped.count',
label: 'Partially Shipped',
type: 'number',
color: 'processing'
},
{
name: 'shipped.count',
label: 'Shipped',
type: 'number',
color: 'processing'
},
{
name: 'partiallyReceived.count',
label: 'Partially Received',
type: 'number',
color: 'success'
},
{
name: 'received.count',
label: 'Received',
type: 'number',
color: 'success'
} }
] ]
} }