diff --git a/src/_nav.js b/src/_nav.js index 275b9d4..42588c3 100644 --- a/src/_nav.js +++ b/src/_nav.js @@ -63,110 +63,44 @@ const _nav = [ to: '/kyc', icon: , }, - - // { - // component: CNavTitle, - // name: 'Theme', - // }, - // { - // component: CNavItem, - // name: 'Colors', - // to: '/theme/colors', - // icon: , - // }, - // { - // component: CNavItem, - // name: 'Typography', - // to: '/theme/typography', - // icon: , - // }, - // { - // component: CNavTitle, - // name: 'Components', - // }, - // { - // component: CNavGroup, - // name: 'Base', - // to: '/base', - // icon: , - // items: [ - // { - // component: CNavItem, - // name: 'Accordion', - // to: '/base/accordion', - // }, - // { - // component: CNavItem, - // name: 'Breadcrumb', - // to: '/base/breadcrumbs', - // }, - // { - // component: CNavItem, - // name: 'Cards', - // to: '/base/cards', - // }, - // { - // component: CNavItem, - // name: 'Carousel', - // to: '/base/carousels', - // }, - // { - // component: CNavItem, - // name: 'Collapse', - // to: '/base/collapses', - // }, - // { - // component: CNavItem, - // name: 'List group', - // to: '/base/list-groups', - // }, - // { - // component: CNavItem, - // name: 'Navs & Tabs', - // to: '/base/navs', - // }, - // { - // component: CNavItem, - // name: 'Pagination', - // to: '/base/paginations', - // }, - // { - // component: CNavItem, - // name: 'Placeholders', - // to: '/base/placeholders', - // }, - // { - // component: CNavItem, - // name: 'Popovers', - // to: '/base/popovers', - // }, - // { - // component: CNavItem, - // name: 'Progress', - // to: '/base/progress', - // }, - // { - // component: CNavItem, - // name: 'Spinners', - // to: '/base/spinners', - // }, - // { - // component: CNavItem, - // name: 'Tables', - // to: '/base/tables', - // }, - // { - // component: CNavItem, - // name: 'Tabs', - // to: '/base/tabs', - // }, - // { - // component: CNavItem, - // name: 'Tooltips', - // to: '/base/tooltips', - // }, - // ], - // }, + { + component: CNavGroup, + name: 'RD Orders', + to: '/base', + icon: , + items: [ + { + component: CNavItem, + name: 'New', + to: '/new', + }, + { + component: CNavItem, + name: 'Pending', + to: '/pending', + }, + { + component: CNavItem, + name: 'Processing', + to: '/processing', + }, + { + component: CNavItem, + name: 'Dispathed', + to: '/dispatched', + }, + { + component: CNavItem, + name: 'Delivered', + to: '/delivered', + }, + { + component: CNavItem, + name: 'Cancelled', + to: 'cancelled', + }, + ], + }, // { // component: CNavGroup, // name: 'Buttons', diff --git a/src/routes.js b/src/routes.js index 9b69e9f..ee064a3 100644 --- a/src/routes.js +++ b/src/routes.js @@ -5,6 +5,11 @@ import Cart from './views/pages/cart/cart' import OrderDetails from './views/orders/OrderDetails' import ProductManual from './views/pages/productManual/productManual' import ViewProductManual from './views/pages/productManual/viewProductManual' +import NewOrders from './views/pages/rdOrders/newOrder' +import ViewOrders from './views/pages/rdOrders/viewOrders' + +import PendingOrders from './views/pages/rdOrders/pendingOrders' +import CancelledOrders from './views/pages/rdOrders/cancelledOrders' const Dashboard = React.lazy(() => import('./views/dashboard/Dashboard')) const Shop = React.lazy(() => import('./views/shops/Shop')) @@ -27,6 +32,11 @@ const routes = [ // Product manual { path: '/product-manual', name: 'Product Manual ', element: ProductManual }, { path: '/product-manual/:id', name: 'Product Manual ', element: ViewProductManual }, + //RD Orders + { path: '/new', name: 'New', element: NewOrders }, + { path: '/pending', name: 'New', element: PendingOrders }, + { path: '/cancelled', name: 'New', element: CancelledOrders }, + { path: '/:status/:id', name: 'New', element: ViewOrders }, { path: '/my-profile', name: 'Profile', element: MyProfile }, { path: '/change-password', name: 'Change password', element: ChangePassword }, diff --git a/src/views/orders/Order.js b/src/views/orders/Order.js index c75f44a..3cd18f5 100644 --- a/src/views/orders/Order.js +++ b/src/views/orders/Order.js @@ -57,6 +57,7 @@ const Order = () => { limit: rowsPerPage, // number of rows per page }, }) + console.log('total orders ', response) setOrders(response.data.plcaedOrders) setTotalOrders(response.data.totalOrders) // Ensure the API returns the total count of orders } catch (error) { diff --git a/src/views/orders/OrderDetails.js b/src/views/orders/OrderDetails.js index 4b51179..df8f462 100644 --- a/src/views/orders/OrderDetails.js +++ b/src/views/orders/OrderDetails.js @@ -193,37 +193,6 @@ const OrderDetails = () => { - - {/* Status History Table */} - {statusHistory.length > 0 && ( - - - Status History - - - - - - Status - Timestamp - - - - {statusHistory.map((status, index) => ( - - {status.status} - {new Date(status.timestamp).toLocaleString()} - - ))} - - - - - )} ) } diff --git a/src/views/pages/login/Login.js b/src/views/pages/login/Login.js index ff91102..f4d5603 100644 --- a/src/views/pages/login/Login.js +++ b/src/views/pages/login/Login.js @@ -104,6 +104,7 @@ const Login = () => { console.log(res) if (res.data.success === true && res.data.user.role === 'principal-Distributor') { localStorage.setItem('authToken', res.data.token) + console.log(res.data.token) dispatch(clearCart()) navigate('/dashboard') setLoading(false) diff --git a/src/views/pages/rdOrders/cancelledOrders.js b/src/views/pages/rdOrders/cancelledOrders.js new file mode 100644 index 0000000..63decfe --- /dev/null +++ b/src/views/pages/rdOrders/cancelledOrders.js @@ -0,0 +1,204 @@ +import React, { useState, useEffect } from 'react' +import { + Box, + Button, + Paper, + Table, + TableBody, + TableCell, + TableContainer, + TableHead, + TableRow, + Typography, + TablePagination, + TextField, + MenuItem, + FormControl, + InputLabel, + Select, + Skeleton, +} from '@mui/material' +import { useNavigate } from 'react-router-dom' + +import { isAutheticated } from 'src/auth' +import Axios from '../../../axios' + +const CancelledOrder = () => { + const [orders, setOrders] = useState([]) + const [loading, setLoading] = useState(true) + const [page, setPage] = useState(0) + const [rowsPerPage, setRowsPerPage] = useState(5) + const [totalOrders, setTotalOrders] = useState(0) + const [searchField, setSearchField] = useState('uniqueId') // Default search field + const [searchText, setSearchText] = useState('') // Default search text is empty + const navigate = useNavigate() + const token = isAutheticated() + + // Fetch orders based on page, limit, and search criteria + const fetchOrders = async (page, limit, searchField, searchText) => { + setLoading(true) + try { + const response = await Axios.get('/api/pd-get-cancelled-orders', { + headers: { + Authorization: `Bearer ${token}`, + }, + params: { + page: page + 1, // Pages are 1-indexed in backend + limit, + searchField: searchText ? searchField : undefined, // Only pass searchField if there's a searchText + searchText: searchText || undefined, // Only pass searchText if it's not empty + }, + }) + if (response?.status === 200) { + setOrders(response?.data?.plcaedOrders) + setTotalOrders(response?.data?.totalOrders) + } else { + setOrders([]) + setTotalOrders(0) + } + } catch (error) { + console.error('Error fetching orders:', error) + } finally { + setLoading(false) + } + } + + // Fetch all orders initially and when page/rowsPerPage changes + useEffect(() => { + fetchOrders(page, rowsPerPage, searchField, searchText) + }, [page, rowsPerPage]) + + // Trigger search when search text or search field changes + const handleSearchChange = (event) => { + setSearchText(event.target.value) + } + + useEffect(() => { + if (searchText.trim()) { + // Trigger search only when there is search text + fetchOrders(0, rowsPerPage, searchField, searchText) + } else { + // If searchText is cleared, fetch all orders again + fetchOrders(page, rowsPerPage, searchField, '') + } + }, [searchText, searchField]) + + const handleSearchFieldChange = (event) => { + setSearchField(event.target.value) + } + + const handleChangePage = (event, newPage) => { + setPage(newPage) + } + + const handleChangeRowsPerPage = (event) => { + setRowsPerPage(parseInt(event.target.value, 10)) + setPage(0) + } + + return ( + + + New Order Placed List + + + + Search By + + Order ID + Status + + + + + + + + + Order ID + Order Date + Items + Order Value + Status + Action + + + + {loading ? ( + Array.from(new Array(rowsPerPage)).map((_, index) => ( + + + + + + )) + ) : orders?.length > 0 ? ( + orders.map((order) => ( + + {order.uniqueId} + + {new Date(order.createdAt).toDateString()} + , {formatAMPM(order.createdAt)} + + {order.orderItem.length} + {order.grandTotal.toFixed(2)} + {order.status} + + navigate(`/${order.status}/${order._id}`)} + > + View + + + + )) + ) : ( + + + Data not found + + + )} + + + + + + ) +} + +// Helper function to format time as AM/PM +const formatAMPM = (date) => { + var hours = new Date(date).getHours() + var minutes = new Date(date).getMinutes() + var ampm = hours >= 12 ? 'PM' : 'AM' + hours = hours % 12 + hours = hours ? hours : 12 + minutes = minutes < 10 ? '0' + minutes : minutes + var strTime = hours + ':' + minutes + ' ' + ampm + return strTime +} + +export default CancelledOrder diff --git a/src/views/pages/rdOrders/invoiceTable.js b/src/views/pages/rdOrders/invoiceTable.js new file mode 100644 index 0000000..edfee1b --- /dev/null +++ b/src/views/pages/rdOrders/invoiceTable.js @@ -0,0 +1,73 @@ +import React, { useState, useEffect } from 'react' +import { + Table, + TableBody, + TableCell, + TableContainer, + TableHead, + TableRow, + Paper, + Button, + Chip, +} from '@mui/material' +import axios from 'axios' + +const InvoiceTable = ({ invoices }) => { + return ( + + + + + Invoice ID + + Items + Subtotal + GST Total + Invoice Amount + Courier Status + + + + {false ? ( + + + Loading... + + + ) : ( + invoices.map((invoice) => ( + + {invoice.invoiceId} + + + {invoice.items.map((item) => ( + + {item.name} ({item.SKU}) x {item.processquantity} + + ))} + + {invoice.subtotal} + {invoice.gstTotal} + {invoice.invoiceAmount} + + + + + )) + )} + + + + ) +} + +export default InvoiceTable diff --git a/src/views/pages/rdOrders/newOrder.js b/src/views/pages/rdOrders/newOrder.js new file mode 100644 index 0000000..124dd85 --- /dev/null +++ b/src/views/pages/rdOrders/newOrder.js @@ -0,0 +1,204 @@ +import React, { useState, useEffect } from 'react' +import { + Box, + Button, + Paper, + Table, + TableBody, + TableCell, + TableContainer, + TableHead, + TableRow, + Typography, + TablePagination, + TextField, + MenuItem, + FormControl, + InputLabel, + Select, + Skeleton, +} from '@mui/material' +import { useNavigate } from 'react-router-dom' + +import { isAutheticated } from 'src/auth' +import Axios from '../../../axios' + +const NewOrders = () => { + const [orders, setOrders] = useState([]) + const [loading, setLoading] = useState(true) + const [page, setPage] = useState(0) + const [rowsPerPage, setRowsPerPage] = useState(5) + const [totalOrders, setTotalOrders] = useState(0) + const [searchField, setSearchField] = useState('uniqueId') // Default search field + const [searchText, setSearchText] = useState('') // Default search text is empty + const navigate = useNavigate() + const token = isAutheticated() + + // Fetch orders based on page, limit, and search criteria + const fetchOrders = async (page, limit, searchField, searchText) => { + setLoading(true) + try { + const response = await Axios.get('/api/pd-get-new-orders', { + headers: { + Authorization: `Bearer ${token}`, + }, + params: { + page: page + 1, // Pages are 1-indexed in backend + limit, + searchField: searchText ? searchField : undefined, // Only pass searchField if there's a searchText + searchText: searchText || undefined, // Only pass searchText if it's not empty + }, + }) + if (response?.status === 200) { + setOrders(response?.data?.plcaedOrders) + setTotalOrders(response?.data?.totalOrders) + } else { + setOrders([]) + setTotalOrders(0) + } + } catch (error) { + console.error('Error fetching orders:', error) + } finally { + setLoading(false) + } + } + + // Fetch all orders initially and when page/rowsPerPage changes + useEffect(() => { + fetchOrders(page, rowsPerPage, searchField, searchText) + }, [page, rowsPerPage]) + + // Trigger search when search text or search field changes + const handleSearchChange = (event) => { + setSearchText(event.target.value) + } + + useEffect(() => { + if (searchText.trim()) { + // Trigger search only when there is search text + fetchOrders(0, rowsPerPage, searchField, searchText) + } else { + // If searchText is cleared, fetch all orders again + fetchOrders(page, rowsPerPage, searchField, '') + } + }, [searchText, searchField]) + + const handleSearchFieldChange = (event) => { + setSearchField(event.target.value) + } + + const handleChangePage = (event, newPage) => { + setPage(newPage) + } + + const handleChangeRowsPerPage = (event) => { + setRowsPerPage(parseInt(event.target.value, 10)) + setPage(0) + } + + return ( + + + New Order Placed List + + + + Search By + + Order ID + Status + + + + + + + + + Order ID + Order Date + Items + Order Value + Status + Action + + + + {loading ? ( + Array.from(new Array(rowsPerPage)).map((_, index) => ( + + + + + + )) + ) : orders?.length > 0 ? ( + orders.map((order) => ( + + {order.uniqueId} + + {new Date(order.createdAt).toDateString()} + , {formatAMPM(order.createdAt)} + + {order.orderItem.length} + {order.grandTotal.toFixed(2)} + {order.status} + + navigate(`/${order.status}/${order._id}`)} + > + View + + + + )) + ) : ( + + + Data not found + + + )} + + + + + + ) +} + +// Helper function to format time as AM/PM +const formatAMPM = (date) => { + var hours = new Date(date).getHours() + var minutes = new Date(date).getMinutes() + var ampm = hours >= 12 ? 'PM' : 'AM' + hours = hours % 12 + hours = hours ? hours : 12 + minutes = minutes < 10 ? '0' + minutes : minutes + var strTime = hours + ':' + minutes + ' ' + ampm + return strTime +} + +export default NewOrders diff --git a/src/views/pages/rdOrders/partialOrderModal.js b/src/views/pages/rdOrders/partialOrderModal.js new file mode 100644 index 0000000..fc7e6c5 --- /dev/null +++ b/src/views/pages/rdOrders/partialOrderModal.js @@ -0,0 +1,120 @@ +import React, { useState } from 'react' +import { + Dialog, + DialogActions, + DialogContent, + DialogTitle, + Button, + TextField, + Typography, + Table, + TableBody, + TableCell, + TableContainer, + TableHead, + TableRow, + Paper, + Grid, +} from '@mui/material' + +const OrderDetailsDialog = ({ open, onClose, order, onSubmit }) => { + // Create a state to store availability input for each product + console.log(order) + const [availability, setAvailability] = useState( + order?.orderItem.map((item) => ({ + ...item, // Keep all original properties from orderItem + processquantity: item.remainingQuantity, // Add availability field with default value equal to quantity + })), + ) + + // Handle input change for availability + const handleAvailabilityChange = (index, value) => { + const updatedAvailability = [...availability] + const newValue = Math.max(0, Math.min(value, updatedAvailability[index].remainingQuantity)) // Ensure value is between 0 and available quantity + updatedAvailability[index].processquantity = newValue + setAvailability(updatedAvailability) + } + + // Handle form submission + const handleSubmit = () => { + onSubmit(availability) // Pass updated availability to parent component + onClose() // Close modal + } + + return ( + + Modify Product Availability + + + + + + + + Product + Price (₹) + Quantity + Availability + Subtotal (₹) + GST (%) + GST Amount (₹) + Total with GST (₹) + + + + {order?.orderItem.map((item, index) => { + const subtotal = item.price * item.remainingQuantity + const gstAmount = ((item.GST * item.price) / 100) * item.remainingQuantity + const totalWithGST = subtotal + gstAmount + + return ( + + + + {item.productId.name} + + ₹{item.price} + {item.remainingQuantity} + + + handleAvailabilityChange(index, Number(e.target.value)) + } + inputProps={{ + min: 0, + max: item.remainingQuantity, + }} + style={{ width: '60px', textAlign: 'center' }} + /> + + ₹{subtotal} + {item.GST}% + ₹{gstAmount} + ₹{totalWithGST} + + ) + })} + + + + + + + + Cancel + + Submit + + + + ) +} + +export default OrderDetailsDialog diff --git a/src/views/pages/rdOrders/pendingOrderTable.js b/src/views/pages/rdOrders/pendingOrderTable.js new file mode 100644 index 0000000..5079338 --- /dev/null +++ b/src/views/pages/rdOrders/pendingOrderTable.js @@ -0,0 +1,76 @@ +import { + Box, + Grid, + TableContainer, + Paper, + Table, + TableHead, + TableRow, + TableCell, + TableBody, + Typography, +} from '@mui/material' +import React from 'react' + +const PendingOrderTable = ({ order }) => { + return ( + + + + + + + + Product + Price (₹) + Quantity + Subtotal (₹) + GST (%) + GST Amount (₹) + Total with GST (₹) + + + + {order?.orderItem.map((item, index) => { + // Check if remainingQuantity is greater than 0 + if (item.remainingQuantity > 0) { + const subtotal = item.price * item.remainingQuantity + const gstAmount = ((item.GST * item.price) / 100) * item.remainingQuantity + const totalWithGST = subtotal + gstAmount + + return ( + + + + {item.productId.name} + + ₹{item.price} + {item.remainingQuantity} + ₹{subtotal} + {item.GST}% + ₹{gstAmount} + ₹{totalWithGST} + + ) + } + // Return null if remainingQuantity is 0 + return null + })} + + + + + + + ) +} + +export default PendingOrderTable diff --git a/src/views/pages/rdOrders/pendingOrders.js b/src/views/pages/rdOrders/pendingOrders.js new file mode 100644 index 0000000..85a6d60 --- /dev/null +++ b/src/views/pages/rdOrders/pendingOrders.js @@ -0,0 +1,188 @@ +import React, { useState, useEffect } from 'react' +import { + Box, + Button, + Paper, + Table, + TableBody, + TableCell, + TableContainer, + TableHead, + TableRow, + Typography, + TablePagination, + TextField, + MenuItem, + FormControl, + InputLabel, + Select, + Skeleton, +} from '@mui/material' +import { useNavigate } from 'react-router-dom' + +import { isAutheticated } from 'src/auth' +import Axios from '../../../axios' + +const PendingOrders = () => { + const [orders, setOrders] = useState([]) + const [loading, setLoading] = useState(true) + const [page, setPage] = useState(0) + const [rowsPerPage, setRowsPerPage] = useState(5) + const [totalOrders, setTotalOrders] = useState(0) + const [searchField, setSearchField] = useState('Order ID') + const [searchText, setSearchText] = useState('') + const navigate = useNavigate() + const token = isAutheticated() + + // Fetch orders with pagination + const fetchOrders = async (page, limit) => { + setLoading(true) + try { + const response = await Axios.get('/api/pd-get-pending-orders', { + headers: { + Authorization: `Bearer ${token}`, + }, + params: { + page: page + 1, // Adjusting for zero-based index in the UI + limit, + searchField, + searchText, + }, + }) + console.log(response) + setOrders(response?.data?.plcaedOrders) + setTotalOrders(response?.data?.totalOrders) + } catch (error) { + console.error('Error fetching orders:', error) + } finally { + setLoading(false) + } + } + + useEffect(() => { + fetchOrders(page, rowsPerPage) + }, [page, rowsPerPage, searchField, searchText]) + + const handleSearchChange = (event) => { + setSearchText(event.target.value) + } + + const handleSearchFieldChange = (event) => { + setSearchField(event.target.value) + } + + const handleChangePage = (event, newPage) => { + setPage(newPage) + } + + const handleChangeRowsPerPage = (event) => { + setRowsPerPage(parseInt(event.target.value, 10)) + setPage(0) + } + + return ( + + + Pending Order List + + + + Search By + + Order ID + Status + + + + + + + + + Order ID + Order Date + Items + Order Value + Status + Action + + + + {loading ? ( + Array.from(new Array(rowsPerPage)).map((_, index) => ( + + + + + + )) + ) : orders?.length > 0 ? ( + orders?.map((order) => ( + + {order.uniqueId} + + {new Date(order.createdAt).toDateString()} + , {formatAMPM(order.createdAt)} + + {order.orderItem.length} + {order.grandTotal.toFixed(2)} + {order.status} + + navigate(`/${order.status}/${order._id}`)} + > + View + + + + )) + ) : ( + + + Data not found + + + )} + + + + + + ) +} + +// Helper function to format time as AM/PM +const formatAMPM = (date) => { + var hours = new Date(date).getHours() + var minutes = new Date(date).getMinutes() + var ampm = hours >= 12 ? 'PM' : 'AM' + hours = hours % 12 + hours = hours ? hours : 12 + minutes = minutes < 10 ? '0' + minutes : minutes + var strTime = hours + ':' + minutes + ' ' + ampm + return strTime +} + +export default PendingOrders diff --git a/src/views/pages/rdOrders/viewInvoices.js b/src/views/pages/rdOrders/viewInvoices.js new file mode 100644 index 0000000..d6c5ac2 --- /dev/null +++ b/src/views/pages/rdOrders/viewInvoices.js @@ -0,0 +1,481 @@ +import React, { useState, useEffect } from 'react' +import { + Box, + Typography, + Grid, + Button, + FormControl, + Dialog, + DialogActions, + DialogContent, + Table, + TableBody, + TableCell, + TableHead, + TableRow, + Paper, + DialogContentText, + DialogTitle, + TextField, + Divider, + Chip, +} from '@mui/material' +import onvoicesData from '../../assets/incoicedata.json' +import { useNavigate, useParams } from 'react-router-dom' +import { TableContainer } from '@material-ui/core' +import axios from 'axios' // Import axios for HTTP requests +import { isAutheticated } from 'src/auth' +import Swal from 'sweetalert2' +import OrderDetailsDialog from './partialOrderModal' +import InvoiceTable from './invoiceTable' +import PendingOrderTable from './pendingOrderTable' + +const ViewInvoices = () => { + const [invoice, setInvoice] = useState(null) // State to store order details + const [status, setStatus] = useState('') + const [openConfirmDialog, setOpenConfirmDialog] = useState(false) + const [openDispatchDialog, setOpenDispatchDialog] = useState(false) + + const [openDeliveredDialog, setOpenDeliveredDialog] = useState(false) // New dialog state for delivery confirmation + const [courierName, setCourierName] = useState('') + const [couriertrackingId, setCourierId] = useState('') + + const [deliveryDate, setDeliveryDate] = useState('') + const token = isAutheticated() // State for delivery date + const [invoiceStatus, setInvoiceStatus] = useState('') + const [loading, setLoading] = useState(true) // Loading state + const [error, setError] = useState(null) // Error state + const navigate = useNavigate() + const { id } = useParams() + + // Get order ID from URL params + + useEffect(() => { + const fetchOrderDetails = async () => { + try { + const response = await axios.get(`/api/invoice/details/${id}`, { + headers: { + Authorization: `Bearer ${token}`, + }, + }) + console.log(response) + setInvoice(response.data) + setStatus(response.data.courierStatus) + + setLoading(false) + } catch (err) { + console.log(err) + setError('Failed to fetch order details') + setLoading(false) + } + } + + fetchOrderDetails() + }, [id]) + + const handleStatusChange = (event) => { + setInvoiceStatus(event.target.value) + } + + const handleUpdateClick = () => { + if (invoiceStatus === 'dispatched') { + setOpenDispatchDialog(true) + } else if (invoiceStatus === 'delivered') { + setOpenDeliveredDialog(true) + } + } + + const handleConfirmUpdate = async (e) => { + e.preventDefault() + try { + if (invoiceStatus === 'dispatched') { + const res = await axios.put( + `/api/invoice/dispatched/${id}`, + { + courierName, + couriertrackingId, + }, + { + headers: { + Authorization: `Bearer ${token}`, + }, + }, + ) + + console.log(res) + if (res.status === 200) { + Swal.fire('Invoice Status updated', 'Invoice Dispatched', 'success') + navigate(`/orders/dispatched`) + } + } else if (invoiceStatus === 'delivered') { + const deli = await axios.put( + `/api/invoice/delivered/${id}`, + {}, + + { + headers: { + 'Access-Control-Allow-Origin': '*', + Authorization: `Bearer ${token}`, + }, + }, + ) + + if (deli.status === 200) { + Swal.fire('Order Status updated', `Order Dispatched`, 'success') + + navigate(`/orders/delivered`) + } + } + } catch (error) { + Swal.fire('Something went wrong ', error.message, 'error') + } + + setOpenDispatchDialog(false) + + setOpenDeliveredDialog(false) // Close delivered dialog + } + + const handleCancel = async () => { + setOpenDispatchDialog(false) + setOpenDeliveredDialog(false) // Close delivered dialog + } + + if (loading) { + return Loading... + } + + if (error) { + return {error} + } + + return ( + + + + Invoice Id : {invoice?.invoiceId} + + navigate(`/orders/${status}`)} variant="contained"> + Back + + + + + + + Invoice + + {/* */} + + + + + Invoice ID + + Items + Subtotal + GST Total + Invoice Amount + Courier Status + + + + + {invoice.invoiceId} + + + {invoice.items.map((item) => ( + + {item.name} ({item.SKU}) x {item.processquantity} + + ))} + + {invoice.subtotal} + {invoice.gstTotal} + {invoice.invoiceAmount} + + + + + + + + + {/* + Order Summary + + + + + + + + + Product + Price (₹) + Quantity + Subtotal (₹) + GST (%) + GST Amount (₹) + Total with GST (₹) + + + + {invoice?.orderId?.orderItem.map((item, index) => { + const subtotal = item.price * item.quantity; + const gstAmount = + ((item.GST * item.price) / 100) * item.quantity; + const totalWithGST = subtotal + gstAmount; + + return ( + + + + + {item.productId.name} + + + ₹{item.price} + {item.quantity} + ₹{subtotal} + {item.GST}% + ₹{gstAmount} + ₹{totalWithGST} + + ); + })} + + + + + */} + + + + + + Invoice Summary + + + Total Items: {invoice?.items.length} + + Total Subtotal: ₹{invoice?.subtotal} + Total GST: ₹{invoice?.gstTotal} + + Grand Total: ₹{invoice?.invoiceAmount} + + + + + + + + + + + + Customer Details + + + SBU: {invoice?.orderId?.addedBy.SBU} + + + Name: {invoice?.orderId?.addedBy.name} + + + Email id: {invoice?.orderId?.addedBy.email} + + + Number: {invoice?.orderId?.addedBy.phone} + + + + + Bill Address + + {invoice?.orderId?.billTo} + + + + Ship Address + + {invoice?.orderId?.shipTo} + + + + Payment mode + + {invoice?.orderId?.paymentMode} + + + {/* + + Order Status + + {order?.status} + {invoice?.courierStatus === "cancelled" && ( + + {order?.order_Cancelled_Reason} + + )} + */} + + + {invoice?.status !== 'delivered' && ( + + + {status === 'processing' && ( + <> + Processing + Dispatch + > + )} + {status === 'dispatched' && ( + <> + Dispatched + Delivered + > + )} + + + )} + + {invoiceStatus && ( + + Update Status + + )} + + + + {/* Dialogs for updating status */} + + Update Order Status + + + Are you sure you want to update the status to {invoiceStatus}? + + + + + Cancel + + + Confirm + + + + + {/* Dialog for dispatch details */} + + Dispatch Details + + + Please provide courier name and ID for dispatch: + + setCourierName(e.target.value)} + /> + setCourierId(e.target.value)} + /> + + + + Cancel + + + Confirm + + + + + + + Confirm Delivery + + + Please confirm the delivery details: + + setDeliveryDate(e.target.value)} + InputLabelProps={{ + shrink: true, + }} + /> + + + + + Cancel + + + Confirm + + + + + + ) +} +const formatAMPM = (date) => { + var hours = new Date(date).getHours() + var minutes = new Date(date).getMinutes() + var ampm = hours >= 12 ? 'PM' : 'AM' + hours = hours % 12 + hours = hours ? hours : 12 + minutes = minutes < 10 ? '0' + minutes : minutes + var strTime = hours + ':' + minutes + ' ' + ampm + return strTime +} +export default ViewInvoices diff --git a/src/views/pages/rdOrders/viewOrders.js b/src/views/pages/rdOrders/viewOrders.js new file mode 100644 index 0000000..81d006f --- /dev/null +++ b/src/views/pages/rdOrders/viewOrders.js @@ -0,0 +1,634 @@ +import React, { useState, useEffect } from 'react' +import { + Box, + Typography, + Grid, + Button, + FormControl, + Dialog, + DialogActions, + DialogContent, + Table, + TableBody, + TableCell, + TableHead, + TableRow, + Paper, + DialogContentText, + DialogTitle, + TextField, + Divider, +} from '@mui/material' + +import { useNavigate, useParams } from 'react-router-dom' +import { TableContainer } from '@mui/material' +import axios from 'axios' // Import axios for HTTP requests +import { isAutheticated } from 'src/auth' +import Swal from 'sweetalert2' +import OrderDetailsDialog from './partialOrderModal' +import InvoiceTable from './invoiceTable' +import PendingOrderTable from './pendingOrderTable' +import Axios from '../../../axios' + +const ViewOrders = () => { + const [order, setOrder] = useState(null) // State to store order details + const [status, setStatus] = useState('') + const [openConfirmDialog, setOpenConfirmDialog] = useState(false) + const [openDispatchDialog, setOpenDispatchDialog] = useState(false) + const [openCancelDialog, setOpenCancelDialog] = useState(false) + const [openDeliveredDialog, setOpenDeliveredDialog] = useState(false) // New dialog state for delivery confirmation + const [courierName, setCourierName] = useState('') + const [courierId, setCourierId] = useState('') + const [cancellationReason, setCancellationReason] = useState('') + const [deliveryDate, setDeliveryDate] = useState('') + const token = isAutheticated() // State for delivery date + const [orderStatus, setOrderStatus] = useState('') + const [loading, setLoading] = useState(true) // Loading state + const [error, setError] = useState(null) // Error state + const navigate = useNavigate() + const { id } = useParams() + const [parialModal, setOpnePartialModal] = useState(false) + // Get order ID from URL params + + useEffect(() => { + const fetchOrderDetails = async () => { + try { + const response = await Axios.get(`/api/pd-get-single-place-order/${id}`, { + headers: { + Authorization: `Bearer ${token}`, + }, + }) + console.log(response) + setOrder(response.data.singleOrder) + setStatus(response.data.singleOrder?.status) + + setLoading(false) + } catch (err) { + setError('Failed to fetch order details') + setLoading(false) + } + } + + fetchOrderDetails() + }, [id]) + + const handleStatusChange = (event) => { + setOrderStatus(event.target.value) + } + + const handleUpdateClick = () => { + if (orderStatus === 'dispatched') { + setOpenDispatchDialog(true) + } else if (orderStatus === 'partial-processing') { + setOpnePartialModal(true) + } else if (orderStatus === 'cancelled') { + setOpenCancelDialog(true) + } else if (orderStatus === 'delivered') { + setOpenDeliveredDialog(true) + } else { + setOpenConfirmDialog(true) + } + } + + const handleConfirmUpdate = async (e) => { + e.preventDefault() + try { + if (orderStatus === 'cancelled') { + if (!cancellationReason) { + Swal.fire('Please give the order cancellation reason') + } + const cancellationRes = await Axios.put( + `/api/pd-cancel-order/${id}`, + { + cancellationReason: cancellationReason, + }, + { + headers: { + 'Access-Control-Allow-Origin': '*', + Authorization: `Bearer ${token}`, + }, + }, + ) + if (cancellationRes.status === 200) { + Swal.fire( + 'Order Status updated', + `Order got cancelled due to${cancellationReason}`, + 'success', + ) + navigate(`/cancelled`) + } + } else if (orderStatus === 'processing') { + const processingOrderInvoice = order?.orderItem + .filter((item) => item.remainingQuantity > 0) // Only include items with remainingQuantity > 0 + .map((item) => ({ + ...item, + productId: item.productId, + processquantity: item.remainingQuantity, // Add processquantity only for items with remainingQuantity > 0 + })) + console.log(processingOrderInvoice) + const cancellationRes = await Axios.post( + `/api/pd-process-order`, + { + invoiceItems: processingOrderInvoice, + orderId: order._id, + }, + { + headers: { + 'Access-Control-Allow-Origin': '*', + Authorization: `Bearer ${token}`, + }, + }, + ) + if (cancellationRes.status === 200) { + Swal.fire('Order Status updated', `Order in processing`, 'success') + navigate(`/pending`) + } + } + } catch (error) { + Swal.fire('Something went wrong ', error.message, 'error') + } + // Perform update logic here + setOpnePartialModal(false) + setOpenConfirmDialog(false) + setOpenDispatchDialog(false) + setOpenCancelDialog(false) + setOpenDeliveredDialog(false) // Close delivered dialog + } + + const handleCancel = async () => { + setOpenConfirmDialog(false) + setOpenDispatchDialog(false) + setOpenCancelDialog(false) + setOpenDeliveredDialog(false) // Close delivered dialog + } + const handlePartialOrderClose = () => { + setOpnePartialModal(false) + } + const handlePartialProcess = async (availability) => { + console.log(availability) + const prepareData = availability + .filter(({ processquantity }) => processquantity > 0) + .map( + ({ + productId, + SKU, + name, + categoryName, + brandName, + price, + GST, + HSN_Code, + description, + processquantity, + }) => ({ + productId: productId, + SKU, + name, + categoryName, + brandName, + price, + GST, + HSN_Code, + description, + processquantity, + }), + ) + + try { + const cancellationRes = await Axios.post( + `/api/pd-process-order`, + { + invoiceItems: prepareData, + orderId: id, + }, + { + headers: { + 'Access-Control-Allow-Origin': '*', + Authorization: `Bearer ${token}`, + }, + }, + ) + if (cancellationRes.status === 200) { + Swal.fire('Order Status updated', `Order in processing`, 'success') + navigate(`/pending`) + } + } catch (error) { + Swal.fire('Something went wrong ', error.message, 'error') + } + } + + const timelineData = [ + { event: 'Order Placed On', date: order?.createdAt }, + { + event: 'Processing Started', + date: order?.status_timeline?.processing || '-', + }, + { event: 'Dispatched On', date: order?.status_timeline?.dispatched || '-' }, + { event: 'Delivered On', date: order?.status_timeline?.delivered || '-' }, + ] + + if (loading) { + return Loading... + } + + if (error) { + return {error} + } + + return ( + + + + Order ID: {order?.uniqueId} + + navigate(-1)} variant="contained"> + Back + + + + + + {order.invoices?.length > 0 && ( + <> + + Invoices + + + > + )} + + Order Summary + + + + + + + + + Product + Price (₹) + Quantity + Subtotal (₹) + GST (%) + GST Amount (₹) + Total with GST (₹) + + + + {order?.orderItem.map((item, index) => { + const subtotal = item.price * item.quantity + const gstAmount = ((item.GST * item.price) / 100) * item.quantity + const totalWithGST = subtotal + gstAmount + + return ( + + + + {item.productId.name} + + ₹{item.price} + {item.quantity} + ₹{subtotal} + {item.GST}% + ₹{gstAmount} + ₹{totalWithGST} + + ) + })} + + + + + + {order.invoices?.length > 0 && ( + <> + {' '} + + Order Itmes to processed + + + > + )} + + + + + + Order Summary + + + Total Items: {order?.orderItem.length} + + Total Subtotal: ₹{order?.subtotal} + Total GST: ₹{order?.gstTotal} + + Grand Total: ₹{order?.grandTotal} + + + + {/* + + + + + Status timeline + + + + {timelineData.map((row, index) => ( + + + {row.event} + + + {row.date !== "-" ? ( + <> + {new Date(row.date).toDateString()} + , {formatAMPM(row.date)} + > + ) : ( + "-" + )} + + + + + ))} + + + + */} + + + + + + + + + Customer Details + + + + Name: {order?.addedBy.name} + + + Email id: {order?.addedBy.email} + + + Number: {order?.addedBy.mobile_number} + + + + + Bill Address + + {order?.billTo} + + + + Ship Address + + {order?.shipTo} + + + + Payment mode + + {order?.paymentMode} + + + + + Order Status + + {order?.status} + {order?.status === 'cancelled' && ( + + {order?.order_Cancelled_Reason} + + )} + + + + {order?.status !== 'cancelled' && order?.status !== 'delivered' && ( + + + {status === 'new' && ( + <> + New + Processing + Partial Processing + Cancelled + > + )} + {status === 'pending' && ( + <> + Pending + Processing + Partial Processing + Cancelled + > + )} + {status === 'processing' && ( + <> + Processing + Dispatch + > + )} + {status === 'dispatched' && ( + <> + Dispatch + Delivered + > + )} + + + )} + + {orderStatus && ( + + Update Status + + )} + + + + {/* Dialogs for updating status */} + + Update Order Status + + + Are you sure you want to update the status to {orderStatus}? + + + + + Cancel + + + Confirm + + + + + {/* Dialog for dispatch details */} + + Dispatch Details + + + Please provide courier name and ID for dispatch: + + setCourierName(e.target.value)} + /> + setCourierId(e.target.value)} + /> + + + + Cancel + + + Confirm + + + + + + {/* Dialog for cancellation reason */} + + Cancellation Reason + + + Please provide a reason for cancelling the order: + setCancellationReason(e.target.value)} + /> + + + + Cancel + + + Confirm + + + + + + {/* Dialog for delivery confirmation */} + + Confirm Delivery + + + Please confirm the delivery details: + + setDeliveryDate(e.target.value)} + InputLabelProps={{ + shrink: true, + }} + /> + + + + + Cancel + + + Confirm + + + + + + {/* partial processing */} + + + ) +} +const formatAMPM = (date) => { + var hours = new Date(date).getHours() + var minutes = new Date(date).getMinutes() + var ampm = hours >= 12 ? 'PM' : 'AM' + hours = hours % 12 + hours = hours ? hours : 12 + minutes = minutes < 10 ? '0' + minutes : minutes + var strTime = hours + ':' + minutes + ' ' + ampm + return strTime +} +export default ViewOrders