diff --git a/src/components/Dashboard/Inventory/ProductStocks/NewProductStock.jsx b/src/components/Dashboard/Inventory/ProductStocks/NewProductStock.jsx index 4e40425..3ea1822 100644 --- a/src/components/Dashboard/Inventory/ProductStocks/NewProductStock.jsx +++ b/src/components/Dashboard/Inventory/ProductStocks/NewProductStock.jsx @@ -8,7 +8,7 @@ const NewProductStock = ({ onOk, reset, defaultValues }) => { {({ handleSubmit, submitLoading, objectData, formValid }) => { const steps = [ diff --git a/src/components/Dashboard/Inventory/ProductStocks/PostProductStock.jsx b/src/components/Dashboard/Inventory/ProductStocks/PostProductStock.jsx new file mode 100644 index 0000000..339edb6 --- /dev/null +++ b/src/components/Dashboard/Inventory/ProductStocks/PostProductStock.jsx @@ -0,0 +1,46 @@ +import { useState, useContext } from 'react' +import PropTypes from 'prop-types' +import { ApiServerContext } from '../../context/ApiServerContext' +import { message } from 'antd' +import MessageDialogView from '../../common/MessageDialogView.jsx' + +const PostProductStock = ({ onOk, objectData }) => { + const [postLoading, setPostLoading] = useState(false) + const { sendObjectFunction } = useContext(ApiServerContext) + + const handlePost = async () => { + setPostLoading(true) + try { + const result = await sendObjectFunction( + objectData._id, + 'ProductStock', + 'post' + ) + if (result) { + message.success('Product stock posted successfully') + onOk(result) + } + } catch (error) { + console.error('Error posting product stock:', error) + } finally { + setPostLoading(false) + } + } + + return ( + + ) +} + +PostProductStock.propTypes = { + onOk: PropTypes.func.isRequired, + objectData: PropTypes.object +} + +export default PostProductStock diff --git a/src/components/Dashboard/Inventory/ProductStocks/ProductStockInfo.jsx b/src/components/Dashboard/Inventory/ProductStocks/ProductStockInfo.jsx index 8eb262d..fb55fc4 100644 --- a/src/components/Dashboard/Inventory/ProductStocks/ProductStockInfo.jsx +++ b/src/components/Dashboard/Inventory/ProductStocks/ProductStockInfo.jsx @@ -1,6 +1,6 @@ import { useRef, useState } from 'react' import { useLocation } from 'react-router-dom' -import { Space, Flex, Card } from 'antd' +import { Space, Flex, Card, Modal } from 'antd' import { LoadingOutlined } from '@ant-design/icons' import loglevel from 'loglevel' import config from '../../../../config.js' @@ -10,7 +10,8 @@ import InfoCollapse from '../../common/InfoCollapse.jsx' import ObjectInfo from '../../common/ObjectInfo.jsx' import ObjectProperty from '../../common/ObjectProperty.jsx' import ViewButton from '../../common/ViewButton.jsx' -import { getModelProperty } from '../../../../database/ObjectModels.js' +import { getModelProperty, getModelByName } from '../../../../database/ObjectModels.js' +import PostProductStock from './PostProductStock.jsx' import InfoCircleIcon from '../../../Icons/InfoCircleIcon.jsx' import NoteIcon from '../../../Icons/NoteIcon.jsx' import AuditLogIcon from '../../../Icons/AuditLogIcon.jsx' @@ -36,6 +37,7 @@ const ProductStockInfo = () => { const productStockId = new URLSearchParams(location.search).get( 'productStockId' ) + const [postProductStockOpen, setPostProductStockOpen] = useState(false) const [collapseState, updateCollapseState] = useCollapseState( 'ProductStockInfo', { @@ -71,9 +73,22 @@ const ProductStockInfo = () => { finishEdit: () => { objectFormRef?.current.handleUpdate() return true + }, + delete: () => { + objectFormRef?.current.handleDelete?.() + return true + }, + post: () => { + setPostProductStockOpen(true) + return true } } + const editDisabled = + getModelByName('productStock') + ?.actions?.find((action) => action.name === 'edit') + ?.disabled(objectFormState.objectData) ?? false + return ( <> { }} editLoading={objectFormState.editLoading} formValid={objectFormState.formValid} - disabled={objectFormState.lock?.locked || objectFormState.loading} + disabled={ + objectFormState.lock?.locked || + objectFormState.loading || + editDisabled + } loading={objectFormState.editLoading} /> @@ -230,6 +249,24 @@ const ProductStockInfo = () => { + { + setPostProductStockOpen(false) + }} + width={500} + footer={null} + destroyOnHidden={true} + centered={true} + > + { + setPostProductStockOpen(false) + actions.reload() + }} + objectData={objectFormState.objectData} + /> + ) } diff --git a/src/database/models/ProductStock.js b/src/database/models/ProductStock.js index 540e05e..bce886c 100644 --- a/src/database/models/ProductStock.js +++ b/src/database/models/ProductStock.js @@ -1,5 +1,9 @@ import ProductStockIcon from '../../components/Icons/ProductStockIcon' 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 BinIcon from '../../components/Icons/BinIcon' export const ProductStock = { name: 'productStock', @@ -15,6 +19,69 @@ export const ProductStock = { icon: InfoCircleIcon, url: (_id) => `/dashboard/inventory/productstocks/info?productStockId=${_id}` + }, + { + name: 'edit', + label: 'Edit', + type: 'button', + icon: EditIcon, + url: (_id) => + `/dashboard/inventory/productstocks/info?productStockId=${_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/productstocks/info?productStockId=${_id}&action=cancelEdit`, + visible: (objectData) => { + return objectData?._isEditing && objectData?._isEditing == true + } + }, + { + name: 'finishEdit', + label: 'Finish Edit', + type: 'button', + icon: CheckIcon, + url: (_id) => + `/dashboard/inventory/productstocks/info?productStockId=${_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/productstocks/info?productStockId=${_id}&action=delete`, + visible: (objectData) => { + return !(objectData?._isEditing && objectData?._isEditing == true) + }, + disabled: (objectData) => { + return objectData?.state?.type != 'draft' + } + }, + { type: 'divider' }, + { + name: 'post', + label: 'Post', + type: 'button', + icon: CheckIcon, + url: (_id) => + `/dashboard/inventory/productstocks/info?productStockId=${_id}&action=post`, + visible: (objectData) => { + return objectData?.state?.type == 'draft' + } } ], url: (id) => `/dashboard/inventory/productstocks/info?productStockId=${id}`, @@ -50,6 +117,12 @@ export const ProductStock = { readOnly: true, columnWidth: 120 }, + { + name: 'postedAt', + label: 'Posted At', + type: 'dateTime', + readOnly: true + }, { name: 'updatedAt', label: 'Updated At', @@ -109,6 +182,18 @@ export const ProductStock = { } ], stats: [ + { + name: 'draft.count', + label: 'Draft', + type: 'number', + color: 'default' + }, + { + name: 'posted.count', + label: 'Posted', + type: 'number', + color: 'success' + }, { name: 'totalCurrentQuantity.sum', label: 'Total Current Quantity',