fix: inventory adjustment
This commit is contained in:
parent
86a4a19209
commit
87880dcdd5
@ -155,6 +155,7 @@ export const all_routes = {
|
||||
taxreport: "/tax-report",
|
||||
profitloss: "/profit-loss-report",
|
||||
notes: "/notes",
|
||||
outletlist: "/outlet-list",
|
||||
filemanager: "/file-manager",
|
||||
profile: "/profile",
|
||||
signin: "/signin",
|
||||
|
||||
@ -206,6 +206,7 @@ import ProductList3 from "../feature-module/inventory/productlist3";
|
||||
import { all_routes } from "./all_routes";
|
||||
import PaymentMethodList from "../feature-module/FinanceAccounts/paymentmethodlist";
|
||||
import CompanyList from "../feature-module/superadmin/companylist";
|
||||
import OutletList from "../feature-module/inventory/outletlist";
|
||||
|
||||
export const publicRoutes = [
|
||||
{
|
||||
@ -1499,13 +1500,20 @@ export const publicRoutes = [
|
||||
route: Route,
|
||||
},
|
||||
{
|
||||
id: 1,
|
||||
id: 121,
|
||||
path: routes.companylist,
|
||||
name: "companies",
|
||||
element: <CompanyList />,
|
||||
route: Route,
|
||||
role: 'superadmin'
|
||||
}
|
||||
},
|
||||
{
|
||||
id: 122,
|
||||
path: routes.outletlist,
|
||||
name: "outlets",
|
||||
element: <OutletList />,
|
||||
route: Route
|
||||
},
|
||||
];
|
||||
|
||||
export const posRoutes = [
|
||||
|
||||
@ -10,7 +10,6 @@ import { useSelector } from "react-redux";
|
||||
const CustomPagination = ({
|
||||
currentPage = 1,
|
||||
pageSize = 10,
|
||||
totalCount = 0,
|
||||
totalPages = 1,
|
||||
loading = false,
|
||||
onPageChange,
|
||||
@ -70,8 +69,6 @@ const CustomPagination = ({
|
||||
};
|
||||
}, []);
|
||||
|
||||
console.log(totalCount);
|
||||
|
||||
// Handle page change
|
||||
const handlePageClick = (page) => {
|
||||
if (!loading && page !== currentPage && onPageChange) {
|
||||
|
||||
@ -145,6 +145,13 @@ export const SidebarData = [
|
||||
showSubRoute: false,
|
||||
submenu: false,
|
||||
},
|
||||
{
|
||||
label: "Outlets",
|
||||
link: "/outlet-list",
|
||||
icon: <Icon.Home />,
|
||||
showSubRoute: false,
|
||||
submenu: false,
|
||||
},
|
||||
{
|
||||
label: "Warranty",
|
||||
link: "/warranty",
|
||||
|
||||
211
src/core/modals/financeaccount/addpaymentmethod.jsx
Normal file
211
src/core/modals/financeaccount/addpaymentmethod.jsx
Normal file
@ -0,0 +1,211 @@
|
||||
import { useState } from "react";
|
||||
import { useDispatch, useSelector } from "react-redux";
|
||||
import Swal from "sweetalert2";
|
||||
import {
|
||||
createPaymentMethod,
|
||||
fetchPaymentMethods,
|
||||
} from "../../redux/actions/paymentMethodActions";
|
||||
import Select from "react-select";
|
||||
|
||||
const AddPaymentMethod = () => {
|
||||
const dispatch = useDispatch();
|
||||
const { creating } = useSelector((state) => state.paymentMethods);
|
||||
|
||||
const [formData, setFormData] = useState({
|
||||
name: "",
|
||||
is_active: false,
|
||||
requires_receipt: false,
|
||||
type: "",
|
||||
});
|
||||
|
||||
const handleInputChange = (e) => {
|
||||
setFormData({
|
||||
...formData,
|
||||
[e.target.name]: e.target.value,
|
||||
});
|
||||
};
|
||||
|
||||
const handleCheckboxChange = (e) => {
|
||||
setFormData((prevData) => ({
|
||||
...prevData,
|
||||
[e.target.name]: e.target.checked,
|
||||
}));
|
||||
};
|
||||
|
||||
const handleSelectChange = (field, selectedOption) => {
|
||||
setFormData((prevData) => ({
|
||||
...prevData,
|
||||
[field]: selectedOption.value,
|
||||
}));
|
||||
};
|
||||
|
||||
const handleSubmit = async (e) => {
|
||||
e.preventDefault();
|
||||
|
||||
try {
|
||||
await dispatch(createPaymentMethod(formData));
|
||||
|
||||
await dispatch(fetchPaymentMethods());
|
||||
|
||||
Swal.fire({
|
||||
title: "Success!",
|
||||
text: "Payment Method created successfully!",
|
||||
icon: "success",
|
||||
showConfirmButton: false,
|
||||
timer: 1500,
|
||||
}).then(() => {
|
||||
const closeButton = document.querySelector(
|
||||
"#add-payment-method .btn-close"
|
||||
);
|
||||
closeButton.click();
|
||||
});
|
||||
} catch (error) {
|
||||
console.error("Error creating Payment Method:", error);
|
||||
|
||||
// Show error message
|
||||
Swal.fire({
|
||||
icon: "error",
|
||||
title: "Error!",
|
||||
text:
|
||||
error?.response?.data?.errors[0]?.cause ||
|
||||
"Failed to create Payment Method. Please try again.",
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
const typeOptions = [
|
||||
{
|
||||
label: "Card",
|
||||
value: "card",
|
||||
},
|
||||
{
|
||||
label: "Cash",
|
||||
value: "cash",
|
||||
},
|
||||
{
|
||||
label: "Digital Wallet",
|
||||
value: "digital_wallet",
|
||||
},
|
||||
];
|
||||
|
||||
return (
|
||||
<div>
|
||||
{/* Add Payment Method */}
|
||||
<div className="modal fade" id="add-payment-method">
|
||||
<div className="modal-dialog modal-dialog-centered custom-modal-two">
|
||||
<div className="modal-content">
|
||||
<div className="page-wrapper-new p-0">
|
||||
<div className="content">
|
||||
<div className="modal-header">
|
||||
<div className="page-title">
|
||||
<h4>Create Payment Method</h4>
|
||||
</div>
|
||||
<button
|
||||
type="button"
|
||||
className="btn-close"
|
||||
data-bs-dismiss="modal"
|
||||
aria-label="Close"
|
||||
></button>
|
||||
</div>
|
||||
<div className="modal-body custom-modal-body">
|
||||
<form onSubmit={handleSubmit}>
|
||||
<div className="mb-3">
|
||||
<label className="form-label">Name</label>
|
||||
<input
|
||||
type="text"
|
||||
className="form-control border"
|
||||
name="name"
|
||||
value={formData.name}
|
||||
onChange={handleInputChange}
|
||||
required
|
||||
/>
|
||||
</div>
|
||||
<div className="mb-3">
|
||||
<label className="form-label">Type</label>
|
||||
|
||||
<Select
|
||||
className="select"
|
||||
options={typeOptions}
|
||||
placeholder="Choose"
|
||||
name="type"
|
||||
value={typeOptions.find(
|
||||
(option) => option.value === formData.type
|
||||
)}
|
||||
onChange={(selectedOption) =>
|
||||
handleSelectChange("type", selectedOption)
|
||||
}
|
||||
/>
|
||||
</div>
|
||||
<div className="mb-3">
|
||||
<div className="status-toggle modal-status d-flex justify-content-between align-items-center">
|
||||
<span className="status-label">Status</span>
|
||||
<input
|
||||
type="checkbox"
|
||||
id="is_active"
|
||||
className="check"
|
||||
defaultChecked="true"
|
||||
checked={formData.is_active}
|
||||
name="is_active"
|
||||
onChange={handleCheckboxChange}
|
||||
/>
|
||||
<label htmlFor="is_active" className="checktoggle" />
|
||||
</div>
|
||||
</div>
|
||||
<div className="mb-0">
|
||||
<div className="status-toggle modal-status d-flex justify-content-between align-items-center">
|
||||
<span className="status-label">Require Receipt</span>
|
||||
<input
|
||||
type="checkbox"
|
||||
id="requires_reciept"
|
||||
className="check"
|
||||
defaultChecked="true"
|
||||
checked={formData.requires_receipt}
|
||||
name="requires_receipt"
|
||||
onChange={handleCheckboxChange}
|
||||
/>
|
||||
<label
|
||||
htmlFor="requires_reciept"
|
||||
className="checktoggle"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div className="modal-footer-btn">
|
||||
<button
|
||||
type="button"
|
||||
className="btn btn-outline-dark me-2"
|
||||
data-bs-dismiss="modal"
|
||||
>
|
||||
Cancel
|
||||
</button>
|
||||
<button
|
||||
type="submit"
|
||||
disabled={creating}
|
||||
className="btn btn-submit"
|
||||
>
|
||||
{creating ? (
|
||||
<>
|
||||
<span
|
||||
className="spinner-border spinner-border-sm me-2"
|
||||
role="status"
|
||||
aria-hidden="true"
|
||||
></span>
|
||||
Creating...
|
||||
</>
|
||||
) : (
|
||||
"Create"
|
||||
)}
|
||||
</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{/* /Add Category */}
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default AddPaymentMethod;
|
||||
222
src/core/modals/financeaccount/editpaymentmethod.jsx
Normal file
222
src/core/modals/financeaccount/editpaymentmethod.jsx
Normal file
@ -0,0 +1,222 @@
|
||||
import { useEffect, useState } from "react";
|
||||
import { useDispatch, useSelector } from "react-redux";
|
||||
import Select from "react-select";
|
||||
import Swal from "sweetalert2";
|
||||
import {
|
||||
fetchPaymentMethods,
|
||||
updatePaymentMethod,
|
||||
} from "../../redux/actions/paymentMethodActions";
|
||||
|
||||
const EditPaymentMethod = () => {
|
||||
const dispatch = useDispatch();
|
||||
const { updating, currentPaymentMethod, currentPage, pageSize } = useSelector(
|
||||
(state) => state.paymentMethods
|
||||
);
|
||||
|
||||
const [formData, setFormData] = useState({
|
||||
name: "",
|
||||
is_active: false,
|
||||
requires_receipt: false,
|
||||
type: "",
|
||||
});
|
||||
|
||||
useEffect(() => {
|
||||
if (currentPaymentMethod) {
|
||||
setFormData(currentPaymentMethod);
|
||||
}
|
||||
}, [currentPaymentMethod]);
|
||||
|
||||
const handleInputChange = (e) => {
|
||||
setFormData({
|
||||
...formData,
|
||||
[e.target.name]: e.target.value,
|
||||
});
|
||||
};
|
||||
|
||||
const handleCheckboxChange = (e) => {
|
||||
setFormData((prevData) => ({
|
||||
...prevData,
|
||||
[e.target.name]: e.target.checked,
|
||||
}));
|
||||
};
|
||||
|
||||
const handleSelectChange = (field, selectedOption) => {
|
||||
setFormData((prevData) => ({
|
||||
...prevData,
|
||||
[field]: selectedOption.value,
|
||||
}));
|
||||
};
|
||||
|
||||
const handleSubmit = async (e) => {
|
||||
e.preventDefault();
|
||||
|
||||
try {
|
||||
await dispatch(updatePaymentMethod(currentPaymentMethod?.id, formData));
|
||||
|
||||
await dispatch(
|
||||
fetchPaymentMethods({ page: currentPage, limit: pageSize })
|
||||
);
|
||||
|
||||
Swal.fire({
|
||||
title: "Success!",
|
||||
text: "Payment Method Updated successfully!",
|
||||
icon: "success",
|
||||
showConfirmButton: false,
|
||||
timer: 1500,
|
||||
}).then(() => {
|
||||
const closeButton = document.querySelector(
|
||||
"#edit-payment-method .btn-close"
|
||||
);
|
||||
closeButton.click();
|
||||
});
|
||||
} catch (error) {
|
||||
console.error("Error updating Payment Method:", error);
|
||||
|
||||
// Show error message
|
||||
Swal.fire({
|
||||
icon: "error",
|
||||
title: "Error!",
|
||||
text:
|
||||
error?.response?.data?.errors[0]?.cause ||
|
||||
"Failed to Update Payment Method. Please try again.",
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
const typeOptions = [
|
||||
{
|
||||
label: "Card",
|
||||
value: "card",
|
||||
},
|
||||
{
|
||||
label: "Cash",
|
||||
value: "cash",
|
||||
},
|
||||
{
|
||||
label: "Digital Wallet",
|
||||
value: "digital_wallet",
|
||||
},
|
||||
];
|
||||
|
||||
return (
|
||||
<div>
|
||||
{/* Edit Payment Method */}
|
||||
<div className="modal fade" id="edit-payment-method">
|
||||
<div className="modal-dialog modal-dialog-centered custom-modal-two">
|
||||
<div className="modal-content">
|
||||
<div className="page-wrapper-new p-0">
|
||||
<div className="content">
|
||||
<div className="modal-header">
|
||||
<div className="page-title">
|
||||
<h4>Edit Payment Method</h4>
|
||||
</div>
|
||||
<button
|
||||
type="button"
|
||||
className="btn-close"
|
||||
data-bs-dismiss="modal"
|
||||
aria-label="Close"
|
||||
></button>
|
||||
</div>
|
||||
<div className="modal-body custom-modal-body">
|
||||
<form onSubmit={handleSubmit}>
|
||||
<div className="mb-3">
|
||||
<label className="form-label">Name</label>
|
||||
<input
|
||||
type="text"
|
||||
className="form-control border"
|
||||
name="name"
|
||||
value={formData.name}
|
||||
onChange={handleInputChange}
|
||||
required
|
||||
/>
|
||||
</div>
|
||||
<div className="mb-3">
|
||||
<label className="form-label">Type</label>
|
||||
|
||||
<Select
|
||||
className="select"
|
||||
options={typeOptions}
|
||||
isSearchable={false}
|
||||
placeholder="Choose"
|
||||
name="type"
|
||||
value={typeOptions.find(
|
||||
(option) => option.value === formData.type
|
||||
)}
|
||||
onChange={(selectedOption) =>
|
||||
handleSelectChange("type", selectedOption)
|
||||
}
|
||||
/>
|
||||
</div>
|
||||
<div className="mb-3">
|
||||
<div className="status-toggle modal-status d-flex justify-content-between align-items-center">
|
||||
<span className="status-label">Status</span>
|
||||
<input
|
||||
type="checkbox"
|
||||
id="is_active"
|
||||
className="check"
|
||||
defaultChecked="true"
|
||||
checked={formData.is_active}
|
||||
name="is_active"
|
||||
onChange={handleCheckboxChange}
|
||||
/>
|
||||
<label htmlFor="is_active" className="checktoggle" />
|
||||
</div>
|
||||
</div>
|
||||
<div className="mb-0">
|
||||
<div className="status-toggle modal-status d-flex justify-content-between align-items-center">
|
||||
<span className="status-label">Require Receipt</span>
|
||||
<input
|
||||
type="checkbox"
|
||||
id="requires_reciept"
|
||||
className="check"
|
||||
defaultChecked="true"
|
||||
checked={formData.requires_receipt}
|
||||
name="requires_receipt"
|
||||
onChange={handleCheckboxChange}
|
||||
/>
|
||||
<label
|
||||
htmlFor="requires_reciept"
|
||||
className="checktoggle"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div className="modal-footer-btn">
|
||||
<button
|
||||
type="button"
|
||||
className="btn btn-outline-dark me-2"
|
||||
data-bs-dismiss="modal"
|
||||
>
|
||||
Cancel
|
||||
</button>
|
||||
<button
|
||||
type="submit"
|
||||
disabled={updating}
|
||||
className="btn btn-submit"
|
||||
>
|
||||
{updating ? (
|
||||
<>
|
||||
<span
|
||||
className="spinner-border spinner-border-sm me-2"
|
||||
role="status"
|
||||
aria-hidden="true"
|
||||
></span>
|
||||
Updating...
|
||||
</>
|
||||
) : (
|
||||
"Update"
|
||||
)}
|
||||
</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{/* /Add Category */}
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default EditPaymentMethod;
|
||||
186
src/core/modals/inventory/editoutletlist.jsx
Normal file
186
src/core/modals/inventory/editoutletlist.jsx
Normal file
@ -0,0 +1,186 @@
|
||||
import { useEffect, useState } from "react";
|
||||
import { useDispatch, useSelector } from "react-redux";
|
||||
import Swal from "sweetalert2";
|
||||
import { fetchOutlets, updateOutlet } from "../../redux/actions/outletActions";
|
||||
|
||||
const EditOutletList = () => {
|
||||
const dispatch = useDispatch();
|
||||
|
||||
const { currentOutlet, updating, currentPage, pageSize } = useSelector(
|
||||
(state) => state.outlets
|
||||
);
|
||||
|
||||
const [formData, setFormData] = useState({
|
||||
name: "",
|
||||
address: "",
|
||||
phone_number: "",
|
||||
email: "",
|
||||
is_active: "",
|
||||
});
|
||||
|
||||
useEffect(() => {
|
||||
if (currentOutlet) {
|
||||
setFormData(currentOutlet);
|
||||
}
|
||||
}, [currentOutlet]);
|
||||
|
||||
const handleInputChange = (e) => {
|
||||
setFormData({
|
||||
...formData,
|
||||
[e.target.name]: e.target.value,
|
||||
});
|
||||
};
|
||||
|
||||
const handleCheckboxChange = (e) => {
|
||||
setFormData((prevData) => ({
|
||||
...prevData,
|
||||
[e.target.name]: e.target.checked,
|
||||
}));
|
||||
};
|
||||
|
||||
const handleSubmit = async (e) => {
|
||||
e.preventDefault();
|
||||
|
||||
try {
|
||||
await dispatch(updateOutlet(currentOutlet?.id, formData));
|
||||
|
||||
await dispatch(fetchOutlets({ page: currentPage, limit: pageSize }));
|
||||
|
||||
Swal.fire({
|
||||
title: "Success!",
|
||||
text: "Outlet updated successfully!",
|
||||
icon: "success",
|
||||
showConfirmButton: false,
|
||||
timer: 1500,
|
||||
}).then(() => {
|
||||
const closeButton = document.querySelector("#edit-outlet .btn-close");
|
||||
closeButton.click();
|
||||
});
|
||||
} catch (error) {
|
||||
console.error("Error updating outlet:", error);
|
||||
|
||||
// Show error message
|
||||
Swal.fire({
|
||||
icon: "error",
|
||||
title: "Error!",
|
||||
text: error?.response?.data?.errors[0]?.cause || "Failed to update outlet. Please try again.",
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<div>
|
||||
{/* Edit Outlet */}
|
||||
<div className="modal fade" id="edit-outlet">
|
||||
<div className="modal-dialog modal-dialog-centered custom-modal-two">
|
||||
<div className="modal-content">
|
||||
<div className="page-wrapper-new p-0">
|
||||
<div className="content">
|
||||
<div className="modal-header">
|
||||
<div className="page-title">
|
||||
<h4>Edit Outlet</h4>
|
||||
</div>
|
||||
<button
|
||||
type="button"
|
||||
className="btn-close"
|
||||
data-bs-dismiss="modal"
|
||||
aria-label="Close"
|
||||
></button>
|
||||
</div>
|
||||
<div className="modal-body custom-modal-body">
|
||||
<form onSubmit={handleSubmit}>
|
||||
<div className="mb-3">
|
||||
<label className="form-label">Name</label>
|
||||
<input
|
||||
type="text"
|
||||
className="form-control border"
|
||||
name="name"
|
||||
value={formData.name}
|
||||
onChange={handleInputChange}
|
||||
required
|
||||
/>
|
||||
</div>
|
||||
<div className="mb-3">
|
||||
<label className="form-label">Address</label>
|
||||
<input
|
||||
type="text"
|
||||
className="form-control border"
|
||||
name="address"
|
||||
value={formData.address}
|
||||
onChange={handleInputChange}
|
||||
/>
|
||||
</div>
|
||||
<div className="mb-3">
|
||||
<label className="form-label">Phone</label>
|
||||
<input
|
||||
type="text"
|
||||
className="form-control border"
|
||||
name="phone_number"
|
||||
value={formData.phone_number}
|
||||
onChange={handleInputChange}
|
||||
/>
|
||||
</div>
|
||||
<div className="mb-3">
|
||||
<label className="form-label">Email</label>
|
||||
<input
|
||||
type="email"
|
||||
className="form-control border"
|
||||
name="email"
|
||||
value={formData.email}
|
||||
onChange={handleInputChange}
|
||||
/>
|
||||
</div>
|
||||
<div className="mb-0">
|
||||
<div className="status-toggle modal-status d-flex justify-content-between align-items-center">
|
||||
<span className="status-label">Status</span>
|
||||
<input
|
||||
type="checkbox"
|
||||
id="user3"
|
||||
className="check"
|
||||
name="is_active"
|
||||
checked={formData.is_active}
|
||||
onChange={handleCheckboxChange}
|
||||
/>
|
||||
<label htmlFor="user3" className="checktoggle" />
|
||||
</div>
|
||||
</div>
|
||||
<div className="modal-footer-btn">
|
||||
<button
|
||||
type="button"
|
||||
className="btn btn-outline-dark me-2"
|
||||
data-bs-dismiss="modal"
|
||||
>
|
||||
Cancel
|
||||
</button>
|
||||
<button
|
||||
type="submit"
|
||||
disabled={updating}
|
||||
className="btn btn-submit"
|
||||
>
|
||||
{updating ? (
|
||||
<>
|
||||
<span
|
||||
className="spinner-border spinner-border-sm me-2"
|
||||
role="status"
|
||||
aria-hidden="true"
|
||||
></span>
|
||||
Updating...
|
||||
</>
|
||||
) : (
|
||||
"Update"
|
||||
)}
|
||||
</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{/* /Edit Outlet */}
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default EditOutletList;
|
||||
@ -5,9 +5,9 @@ import Swal from "sweetalert2";
|
||||
import outletsApi from "../../../services/outletsApi";
|
||||
import productsApi from "../../../services/productsApi";
|
||||
import {
|
||||
adjustInventory,
|
||||
createInventory,
|
||||
fetchInventories,
|
||||
updateInventory,
|
||||
} from "../../redux/actions/inventoryActions";
|
||||
|
||||
const ManageStockModal = () => {
|
||||
@ -21,8 +21,10 @@ const ManageStockModal = () => {
|
||||
outlet_id: "",
|
||||
product_id: "",
|
||||
quantity: "",
|
||||
delta: "",
|
||||
min_stock_level: "",
|
||||
max_stock_level: "",
|
||||
reason: "",
|
||||
};
|
||||
};
|
||||
|
||||
@ -85,7 +87,7 @@ const ManageStockModal = () => {
|
||||
e.preventDefault();
|
||||
|
||||
try {
|
||||
await dispatch(updateInventory(currentInventory?.id, formData));
|
||||
await dispatch(adjustInventory(formData));
|
||||
|
||||
await dispatch(fetchInventories());
|
||||
|
||||
@ -107,7 +109,9 @@ const ManageStockModal = () => {
|
||||
Swal.fire({
|
||||
icon: "error",
|
||||
title: "Error!",
|
||||
text: error.message || "Failed to update stock. Please try again.",
|
||||
text:
|
||||
error?.response?.data?.errors[0]?.cause ||
|
||||
"Failed to update stock. Please try again.",
|
||||
});
|
||||
}
|
||||
};
|
||||
@ -273,7 +277,7 @@ const ManageStockModal = () => {
|
||||
<div className="content">
|
||||
<div className="modal-header">
|
||||
<div className="page-title">
|
||||
<h4>Edit Stock</h4>
|
||||
<h4>Adjust Stock</h4>
|
||||
</div>
|
||||
<button
|
||||
type="button"
|
||||
@ -285,33 +289,57 @@ const ManageStockModal = () => {
|
||||
<div className="modal-body custom-modal-body">
|
||||
<form onSubmit={handleUpdate}>
|
||||
<div className="mb-3">
|
||||
<label className="form-label">Quantity</label>
|
||||
<label className="form-label">Outlet</label>
|
||||
<AsyncSelect
|
||||
className="select"
|
||||
loadOptions={loadOutlets}
|
||||
placeholder="Choose"
|
||||
isClearable
|
||||
cacheOptions={true}
|
||||
defaultOptions={true}
|
||||
value={selectedOutlet}
|
||||
onChange={(selectedOption) => {
|
||||
handleSelectChange("outlet_id", selectedOption);
|
||||
setSelectedOutlet(selectedOption);
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
<div className="mb-3">
|
||||
<label className="form-label">Product</label>
|
||||
<AsyncSelect
|
||||
className="select"
|
||||
loadOptions={loadProducts}
|
||||
placeholder="Choose"
|
||||
isClearable
|
||||
cacheOptions={true}
|
||||
defaultOptions={true}
|
||||
value={selectedProduct}
|
||||
onChange={(selectedOption) => {
|
||||
handleSelectChange("product_id", selectedOption);
|
||||
setSelectedProduct(selectedOption);
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
<div className="mb-3">
|
||||
<label className="form-label">Delta</label>
|
||||
<input
|
||||
type="number"
|
||||
className="form-control border"
|
||||
name="quantity"
|
||||
value={formData.quantity}
|
||||
name="delta"
|
||||
value={formData.delta}
|
||||
onChange={handleInputChange}
|
||||
/>
|
||||
</div>
|
||||
<div className="mb-3">
|
||||
<label className="form-label">Min Stock</label>
|
||||
<input
|
||||
type="number"
|
||||
className="form-control border"
|
||||
name="min_stock_level"
|
||||
value={formData.min_stock_level}
|
||||
onChange={handleInputChange}
|
||||
/>
|
||||
</div>
|
||||
<div className="mb-3">
|
||||
<label className="form-label">Max Stock</label>
|
||||
<input
|
||||
type="number"
|
||||
className="form-control border"
|
||||
name="max_stock_level"
|
||||
value={formData.max_stock_level}
|
||||
onChange={handleInputChange}
|
||||
<label className="form-label">Reason</label>
|
||||
<textarea
|
||||
className="form-control h-75 border"
|
||||
rows={5}
|
||||
name="reason"
|
||||
value={formData.reason}
|
||||
onChange={(e) =>
|
||||
setFormData({ ...formData, reason: e.target.value })
|
||||
}
|
||||
/>
|
||||
</div>
|
||||
|
||||
@ -338,7 +366,7 @@ const ManageStockModal = () => {
|
||||
Updating...
|
||||
</>
|
||||
) : (
|
||||
"Update"
|
||||
"Save"
|
||||
)}
|
||||
</button>
|
||||
</div>
|
||||
|
||||
@ -1,45 +1,52 @@
|
||||
import { inventoryApi } from '../../../services/inventoriesApi';
|
||||
import { inventoryApi } from "../../../services/inventoriesApi";
|
||||
|
||||
// Action Types
|
||||
export const INVENTORY_ACTIONS = {
|
||||
// Fetch Inventories
|
||||
FETCH_INVENTORIES_REQUEST: 'FETCH_INVENTORIES_REQUEST',
|
||||
FETCH_INVENTORIES_SUCCESS: 'FETCH_INVENTORIES_SUCCESS',
|
||||
FETCH_INVENTORIES_FAILURE: 'FETCH_INVENTORIES_FAILURE',
|
||||
FETCH_INVENTORIES_REQUEST: "FETCH_INVENTORIES_REQUEST",
|
||||
FETCH_INVENTORIES_SUCCESS: "FETCH_INVENTORIES_SUCCESS",
|
||||
FETCH_INVENTORIES_FAILURE: "FETCH_INVENTORIES_FAILURE",
|
||||
|
||||
// Fetch Single Inventory
|
||||
FETCH_INVENTORY_REQUEST: 'FETCH_INVENTORY_REQUEST',
|
||||
FETCH_INVENTORY_SUCCESS: 'FETCH_INVENTORY_SUCCESS',
|
||||
FETCH_INVENTORY_FAILURE: 'FETCH_INVENTORY_FAILURE',
|
||||
FETCH_INVENTORY_REQUEST: "FETCH_INVENTORY_REQUEST",
|
||||
FETCH_INVENTORY_SUCCESS: "FETCH_INVENTORY_SUCCESS",
|
||||
FETCH_INVENTORY_FAILURE: "FETCH_INVENTORY_FAILURE",
|
||||
|
||||
// Create Inventory
|
||||
CREATE_INVENTORY_REQUEST: 'CREATE_INVENTORY_REQUEST',
|
||||
CREATE_INVENTORY_SUCCESS: 'CREATE_INVENTORY_SUCCESS',
|
||||
CREATE_INVENTORY_FAILURE: 'CREATE_INVENTORY_FAILURE',
|
||||
CREATE_INVENTORY_REQUEST: "CREATE_INVENTORY_REQUEST",
|
||||
CREATE_INVENTORY_SUCCESS: "CREATE_INVENTORY_SUCCESS",
|
||||
CREATE_INVENTORY_FAILURE: "CREATE_INVENTORY_FAILURE",
|
||||
|
||||
// Adjust Inventory
|
||||
ADJUST_INVENTORY_REQUEST: "ADJUST_INVENTORY_REQUEST",
|
||||
ADJUST_INVENTORY_SUCCESS: "ADJUST_INVENTORY_SUCCESS",
|
||||
ADJUST_INVENTORY_FAILURE: "ADJUST_INVENTORY_FAILURE",
|
||||
|
||||
// Update Inventory
|
||||
UPDATE_INVENTORY_REQUEST: 'UPDATE_INVENTORY_REQUEST',
|
||||
UPDATE_INVENTORY_SUCCESS: 'UPDATE_INVENTORY_SUCCESS',
|
||||
UPDATE_INVENTORY_FAILURE: 'UPDATE_INVENTORY_FAILURE',
|
||||
UPDATE_INVENTORY_REQUEST: "UPDATE_INVENTORY_REQUEST",
|
||||
UPDATE_INVENTORY_SUCCESS: "UPDATE_INVENTORY_SUCCESS",
|
||||
UPDATE_INVENTORY_FAILURE: "UPDATE_INVENTORY_FAILURE",
|
||||
|
||||
// Delete Inventory
|
||||
DELETE_INVENTORY_REQUEST: 'DELETE_INVENTORY_REQUEST',
|
||||
DELETE_INVENTORY_SUCCESS: 'DELETE_INVENTORY_SUCCESS',
|
||||
DELETE_INVENTORY_FAILURE: 'DELETE_INVENTORY_FAILURE',
|
||||
DELETE_INVENTORY_REQUEST: "DELETE_INVENTORY_REQUEST",
|
||||
DELETE_INVENTORY_SUCCESS: "DELETE_INVENTORY_SUCCESS",
|
||||
DELETE_INVENTORY_FAILURE: "DELETE_INVENTORY_FAILURE",
|
||||
|
||||
// Search Inventories
|
||||
SEARCH_INVENTORIES_REQUEST: 'SEARCH_INVENTORIES_REQUEST',
|
||||
SEARCH_INVENTORIES_SUCCESS: 'SEARCH_INVENTORIES_SUCCESS',
|
||||
SEARCH_INVENTORIES_FAILURE: 'SEARCH_INVENTORIES_FAILURE',
|
||||
SEARCH_INVENTORIES_REQUEST: "SEARCH_INVENTORIES_REQUEST",
|
||||
SEARCH_INVENTORIES_SUCCESS: "SEARCH_INVENTORIES_SUCCESS",
|
||||
SEARCH_INVENTORIES_FAILURE: "SEARCH_INVENTORIES_FAILURE",
|
||||
|
||||
// Clear States
|
||||
CLEAR_INVENTORY_ERROR: 'CLEAR_INVENTORY_ERROR',
|
||||
CLEAR_CURRENT_INVENTORY: 'CLEAR_CURRENT_INVENTORY',
|
||||
CLEAR_INVENTORY_ERROR: "CLEAR_INVENTORY_ERROR",
|
||||
CLEAR_CURRENT_INVENTORY: "CLEAR_CURRENT_INVENTORY",
|
||||
};
|
||||
|
||||
// Action Creators
|
||||
|
||||
export const fetchInventories = (params = {}) => async (dispatch) => {
|
||||
export const fetchInventories =
|
||||
(params = {}) =>
|
||||
async (dispatch) => {
|
||||
dispatch({ type: INVENTORY_ACTIONS.FETCH_INVENTORIES_REQUEST });
|
||||
|
||||
try {
|
||||
@ -52,11 +59,14 @@ export const fetchInventories = (params = {}) => async (dispatch) => {
|
||||
} catch (error) {
|
||||
dispatch({
|
||||
type: INVENTORY_ACTIONS.FETCH_INVENTORIES_FAILURE,
|
||||
payload: error.response?.data?.message || error.message || 'Failed to fetch inventories',
|
||||
payload:
|
||||
error.response?.data?.message ||
|
||||
error.message ||
|
||||
"Failed to fetch inventories",
|
||||
});
|
||||
throw error;
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
export const fetchInventory = (id) => async (dispatch) => {
|
||||
dispatch({ type: INVENTORY_ACTIONS.FETCH_INVENTORY_REQUEST });
|
||||
@ -71,7 +81,10 @@ export const fetchInventory = (id) => async (dispatch) => {
|
||||
} catch (error) {
|
||||
dispatch({
|
||||
type: INVENTORY_ACTIONS.FETCH_INVENTORY_FAILURE,
|
||||
payload: error.response?.data?.message || error.message || 'Failed to fetch inventory',
|
||||
payload:
|
||||
error.response?.data?.message ||
|
||||
error.message ||
|
||||
"Failed to fetch inventory",
|
||||
});
|
||||
throw error;
|
||||
}
|
||||
@ -90,7 +103,32 @@ export const createInventory = (inventoryData) => async (dispatch) => {
|
||||
} catch (error) {
|
||||
dispatch({
|
||||
type: INVENTORY_ACTIONS.CREATE_INVENTORY_FAILURE,
|
||||
payload: error.response?.data?.message || error.message || 'Failed to create inventory',
|
||||
payload:
|
||||
error.response?.data?.message ||
|
||||
error.message ||
|
||||
"Failed to create inventory",
|
||||
});
|
||||
throw error;
|
||||
}
|
||||
};
|
||||
|
||||
export const adjustInventory = (inventoryData) => async (dispatch) => {
|
||||
dispatch({ type: INVENTORY_ACTIONS.ADJUST_INVENTORY_REQUEST });
|
||||
|
||||
try {
|
||||
const data = await inventoryApi.adjustInventory(inventoryData);
|
||||
dispatch({
|
||||
type: INVENTORY_ACTIONS.ADJUST_INVENTORY_SUCCESS,
|
||||
payload: data,
|
||||
});
|
||||
return data;
|
||||
} catch (error) {
|
||||
dispatch({
|
||||
type: INVENTORY_ACTIONS.ADJUST_INVENTORY_FAILURE,
|
||||
payload:
|
||||
error.response?.data?.message ||
|
||||
error.message ||
|
||||
"Failed to adjust inventory",
|
||||
});
|
||||
throw error;
|
||||
}
|
||||
@ -109,7 +147,10 @@ export const updateInventory = (id, inventoryData) => async (dispatch) => {
|
||||
} catch (error) {
|
||||
dispatch({
|
||||
type: INVENTORY_ACTIONS.UPDATE_INVENTORY_FAILURE,
|
||||
payload: error.response?.data?.message || error.message || 'Failed to update inventory',
|
||||
payload:
|
||||
error.response?.data?.message ||
|
||||
error.message ||
|
||||
"Failed to update inventory",
|
||||
});
|
||||
throw error;
|
||||
}
|
||||
@ -128,7 +169,10 @@ export const deleteInventory = (id) => async (dispatch) => {
|
||||
} catch (error) {
|
||||
dispatch({
|
||||
type: INVENTORY_ACTIONS.DELETE_INVENTORY_FAILURE,
|
||||
payload: error.response?.data?.message || error.message || 'Failed to delete inventory',
|
||||
payload:
|
||||
error.response?.data?.message ||
|
||||
error.message ||
|
||||
"Failed to delete inventory",
|
||||
});
|
||||
throw error;
|
||||
}
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
import { INVENTORY_ACTIONS } from '../actions/inventoryActions';
|
||||
import { INVENTORY_ACTIONS } from "../actions/inventoryActions";
|
||||
|
||||
const initialState = {
|
||||
// Inventory list
|
||||
@ -15,7 +15,7 @@ const initialState = {
|
||||
|
||||
// Search results
|
||||
searchResults: [],
|
||||
searchQuery: '',
|
||||
searchQuery: "",
|
||||
|
||||
// Loading states
|
||||
loading: false,
|
||||
@ -115,6 +115,32 @@ const inventoryReducer = (state = initialState, action) => {
|
||||
error: action.payload,
|
||||
};
|
||||
|
||||
// Adjust Inventory
|
||||
case INVENTORY_ACTIONS.ADJUST_INVENTORY_REQUEST:
|
||||
return {
|
||||
...state,
|
||||
updating: true,
|
||||
error: null,
|
||||
};
|
||||
|
||||
case INVENTORY_ACTIONS.ADJUST_INVENTORY_SUCCESS:
|
||||
return {
|
||||
...state,
|
||||
updating: false,
|
||||
inventories: state.inventories.map((inv) =>
|
||||
inv.id === action.payload.data.id ? action.payload.data : inv
|
||||
),
|
||||
currentInventory: action.payload.data,
|
||||
error: null,
|
||||
};
|
||||
|
||||
case INVENTORY_ACTIONS.ADJUST_INVENTORY_FAILURE:
|
||||
return {
|
||||
...state,
|
||||
updating: false,
|
||||
error: action.payload,
|
||||
};
|
||||
|
||||
// Update Inventory
|
||||
case INVENTORY_ACTIONS.UPDATE_INVENTORY_REQUEST:
|
||||
return {
|
||||
@ -127,7 +153,7 @@ const inventoryReducer = (state = initialState, action) => {
|
||||
return {
|
||||
...state,
|
||||
updating: false,
|
||||
inventories: state.inventories.map(inv =>
|
||||
inventories: state.inventories.map((inv) =>
|
||||
inv.id === action.payload.data.id ? action.payload.data : inv
|
||||
),
|
||||
currentInventory: action.payload.data,
|
||||
@ -153,7 +179,9 @@ const inventoryReducer = (state = initialState, action) => {
|
||||
return {
|
||||
...state,
|
||||
deleting: false,
|
||||
inventories: state.inventories.filter(inv => inv.id !== action.payload),
|
||||
inventories: state.inventories.filter(
|
||||
(inv) => inv.id !== action.payload
|
||||
),
|
||||
totalInventories: state.totalInventories - 1,
|
||||
error: null,
|
||||
};
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
import { Select, Tag } from "antd";
|
||||
import { Tag } from "antd";
|
||||
import {
|
||||
ChevronUp,
|
||||
PlusCircle,
|
||||
@ -13,11 +13,15 @@ import Swal from "sweetalert2";
|
||||
import withReactContent from "sweetalert2-react-content";
|
||||
import CustomPagination from "../../components/CustomPagination";
|
||||
import ImageWithBasePath from "../../core/img/imagewithbasebath";
|
||||
import AddCategoryList from "../../core/modals/inventory/addcategorylist";
|
||||
import EditCategoryList from "../../core/modals/inventory/editcategorylist";
|
||||
import AddPaymentMethod from "../../core/modals/financeaccount/addpaymentmethod";
|
||||
import EditPaymentMethod from "../../core/modals/financeaccount/editpaymentmethod";
|
||||
import Table from "../../core/pagination/datatable";
|
||||
import { setToogleHeader } from "../../core/redux/action";
|
||||
import { deletePaymentMethod, fetchPaymentMethod, fetchPaymentMethods } from "../../core/redux/actions/paymentMethodActions";
|
||||
import {
|
||||
deletePaymentMethod,
|
||||
fetchPaymentMethods,
|
||||
PAYMENT_METHOD_ACTIONS
|
||||
} from "../../core/redux/actions/paymentMethodActions";
|
||||
import { formatDate } from "../../utils/date";
|
||||
|
||||
const PaymentMethodList = () => {
|
||||
@ -149,14 +153,15 @@ const PaymentMethodList = () => {
|
||||
</Tooltip>
|
||||
);
|
||||
|
||||
const dateOptions = [
|
||||
{ label: "Sort By: Last 7 Days", value: "last7days" },
|
||||
{ label: "Sort By: Last Month", value: "lastmonth" },
|
||||
{ label: "Sort By: Ascending", value: "ascending" },
|
||||
{ label: "Sort By: Descending", value: "descending" },
|
||||
];
|
||||
|
||||
const columns = [
|
||||
{
|
||||
title: "Organization",
|
||||
dataIndex: "organization",
|
||||
render: (_, record) => {
|
||||
return <span>{record.ogrganization_name || "-"}</span>;
|
||||
},
|
||||
sorter: (a, b) => a.name.length - b.name.length,
|
||||
},
|
||||
{
|
||||
title: "Payment Method",
|
||||
dataIndex: "paymentmethod",
|
||||
@ -200,8 +205,13 @@ const PaymentMethodList = () => {
|
||||
className="me-2 p-2"
|
||||
to="#"
|
||||
data-bs-toggle="modal"
|
||||
data-bs-target="#edit-category"
|
||||
onClick={() => dispatch(fetchPaymentMethod(record.id))}
|
||||
data-bs-target="#edit-payment-method"
|
||||
onClick={() =>
|
||||
dispatch({
|
||||
type: PAYMENT_METHOD_ACTIONS.FETCH_PAYMENT_METHOD_SUCCESS,
|
||||
payload: { data: record },
|
||||
})
|
||||
}
|
||||
>
|
||||
<i data-feather="edit" className="feather-edit"></i>
|
||||
</Link>
|
||||
@ -234,7 +244,6 @@ const PaymentMethodList = () => {
|
||||
];
|
||||
const MySwal = withReactContent(Swal);
|
||||
|
||||
|
||||
return (
|
||||
<div>
|
||||
<div className="page-wrapper">
|
||||
@ -302,10 +311,10 @@ const PaymentMethodList = () => {
|
||||
to="#"
|
||||
className="btn btn-added"
|
||||
data-bs-toggle="modal"
|
||||
data-bs-target="#add-category"
|
||||
data-bs-target="#add-payment-method"
|
||||
>
|
||||
<PlusCircle className="me-2" />
|
||||
Add New Category
|
||||
Add New
|
||||
</Link>
|
||||
</div>
|
||||
</div>
|
||||
@ -326,12 +335,6 @@ const PaymentMethodList = () => {
|
||||
</Link>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<Select
|
||||
style={{ height: 36 }}
|
||||
defaultValue={dateOptions[0]?.value}
|
||||
options={dateOptions}
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div className="table-responsive">
|
||||
@ -378,8 +381,8 @@ const PaymentMethodList = () => {
|
||||
{/* /category list */}
|
||||
</div>
|
||||
</div>
|
||||
<AddCategoryList />
|
||||
<EditCategoryList />
|
||||
<AddPaymentMethod />
|
||||
<EditPaymentMethod />
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
@ -1,7 +1,6 @@
|
||||
import { Select, Tag } from "antd";
|
||||
import {
|
||||
ChevronUp,
|
||||
PlusCircle,
|
||||
RotateCcw,
|
||||
Trash2,
|
||||
} from "feather-icons-react/build/IconComponents";
|
||||
@ -14,30 +13,30 @@ import withReactContent from "sweetalert2-react-content";
|
||||
import CustomPagination from "../../components/CustomPagination";
|
||||
import ImageWithBasePath from "../../core/img/imagewithbasebath";
|
||||
import AddCategoryList from "../../core/modals/inventory/addcategorylist";
|
||||
import EditCategoryList from "../../core/modals/inventory/editcategorylist";
|
||||
import EditOutletList from "../../core/modals/inventory/editoutletlist";
|
||||
import Table from "../../core/pagination/datatable";
|
||||
import { setToogleHeader } from "../../core/redux/action";
|
||||
import {
|
||||
deleteCategory,
|
||||
fetchCategories,
|
||||
fetchCategory,
|
||||
} from "../../core/redux/actions/categoryActions";
|
||||
import { formatDate } from "../../utils/date";
|
||||
deleteOutlet,
|
||||
fetchOutlets,
|
||||
OUTLET_ACTIONS,
|
||||
} from "../../core/redux/actions/outletActions";
|
||||
import { formatRupiah } from "../../utils/currency";
|
||||
|
||||
const OutletList = () => {
|
||||
const {
|
||||
categories: apiCategories,
|
||||
outlets: apiOutlets,
|
||||
loading,
|
||||
error,
|
||||
totalCategories,
|
||||
totalOutlets,
|
||||
totalPages,
|
||||
pageSize: reduxPageSize,
|
||||
currentPage: reduxCurrentPage,
|
||||
} = useSelector((state) => state.categories);
|
||||
} = useSelector((state) => state.outlets);
|
||||
|
||||
const dispatch = useDispatch();
|
||||
const data = useSelector((state) => state.toggle_header);
|
||||
const dataSource = apiCategories?.length > 0 ? apiCategories : [];
|
||||
const dataSource = apiOutlets?.length > 0 ? apiOutlets : [];
|
||||
|
||||
const [currentPage, setCurrentPage] = useState(reduxCurrentPage || 1);
|
||||
const [pageSize, setPageSize] = useState(reduxPageSize || 10);
|
||||
@ -46,7 +45,7 @@ const OutletList = () => {
|
||||
const [debouncedSearchTerm, setDebouncedSearchTerm] = useState("");
|
||||
|
||||
useEffect(() => {
|
||||
const loadCategories = async () => {
|
||||
const loadOutlets = async () => {
|
||||
try {
|
||||
const searchParams = {
|
||||
page: currentPage,
|
||||
@ -59,13 +58,13 @@ const OutletList = () => {
|
||||
Object.entries(searchParams).filter(([, value]) => value !== "")
|
||||
);
|
||||
|
||||
await dispatch(fetchCategories(cleanParams));
|
||||
await dispatch(fetchOutlets(cleanParams));
|
||||
} catch (error) {
|
||||
console.error("Failed to load categories", error);
|
||||
}
|
||||
};
|
||||
|
||||
loadCategories();
|
||||
loadOutlets();
|
||||
}, [dispatch, currentPage, pageSize, debouncedSearchTerm]);
|
||||
|
||||
// Debounce search term
|
||||
@ -96,13 +95,13 @@ const OutletList = () => {
|
||||
};
|
||||
|
||||
// Calculate pagination info
|
||||
const totalRecords = totalCategories || dataSource.length;
|
||||
const totalRecords = totalOutlets || dataSource.length;
|
||||
const calculatedTotalPages = Math.ceil(totalRecords / pageSize);
|
||||
const actualTotalPages = totalPages || calculatedTotalPages;
|
||||
|
||||
const handleDeleteCategory = async (categoryId) => {
|
||||
const handleDeleteOutlet = async (categoryId) => {
|
||||
try {
|
||||
await dispatch(deleteCategory(categoryId));
|
||||
await dispatch(deleteOutlet(categoryId));
|
||||
// Show success message
|
||||
MySwal.fire({
|
||||
title: "Deleted!",
|
||||
@ -162,33 +161,57 @@ const OutletList = () => {
|
||||
|
||||
const columns = [
|
||||
{
|
||||
title: "Category",
|
||||
dataIndex: "category",
|
||||
title: "Organization",
|
||||
dataIndex: "organization",
|
||||
render: (_, record) => {
|
||||
return <span>{record.name}</span>;
|
||||
return <span>{record.organization_name || "-"}</span>;
|
||||
},
|
||||
sorter: (a, b) => a.category.length - b.category.length,
|
||||
},
|
||||
{
|
||||
title: "Category Slug",
|
||||
dataIndex: "categoryslug",
|
||||
title: "Name",
|
||||
dataIndex: "name",
|
||||
render: (_, record) => {
|
||||
return <span>{record?.name?.toLowerCase()}</span>;
|
||||
return <span>{record?.name || "-"}</span>;
|
||||
},
|
||||
sorter: (a, b) => a.categoryslug.length - b.categoryslug.length,
|
||||
},
|
||||
{
|
||||
title: "Created On",
|
||||
dataIndex: "createdon",
|
||||
title: "Address",
|
||||
dataIndex: "address",
|
||||
render: (_, record) => {
|
||||
return <span>{formatDate(record.created_at)}</span>;
|
||||
return <span>{record.address || "-"}</span>;
|
||||
},
|
||||
sorter: (a, b) => a.createdon.length - b.createdon.length,
|
||||
},
|
||||
{
|
||||
title: "Phone Number",
|
||||
dataIndex: "phonenumber",
|
||||
render: (_, record) => <span>{record.phone_number || "-"}</span>,
|
||||
sorter: (a, b) => a.status.length - b.status.length,
|
||||
},
|
||||
{
|
||||
title: "Status",
|
||||
dataIndex: "status",
|
||||
render: () => <Tag color="#87d068">active</Tag>,
|
||||
render: (_, record) => (
|
||||
<Tag color={record.is_active ? "green" : "red"}>
|
||||
{record.is_active ? "Active" : "Inactive"}
|
||||
</Tag>
|
||||
),
|
||||
sorter: (a, b) => a.status.length - b.status.length,
|
||||
},
|
||||
{
|
||||
title: "Tax",
|
||||
dataIndex: "tax",
|
||||
render: (_, record) => (
|
||||
<span>{formatRupiah(record.tax_rate) || "-"}</span>
|
||||
),
|
||||
sorter: (a, b) => a.status.length - b.status.length,
|
||||
},
|
||||
{
|
||||
title: "Currency",
|
||||
dataIndex: "currency",
|
||||
render: (_, record) => <span>{record.currency || "-"}</span>,
|
||||
sorter: (a, b) => a.status.length - b.status.length,
|
||||
},
|
||||
{
|
||||
@ -202,8 +225,13 @@ const OutletList = () => {
|
||||
className="me-2 p-2"
|
||||
to="#"
|
||||
data-bs-toggle="modal"
|
||||
data-bs-target="#edit-category"
|
||||
onClick={() => dispatch(fetchCategory(record.id))}
|
||||
data-bs-target="#edit-outlet"
|
||||
onClick={() =>
|
||||
dispatch({
|
||||
type: OUTLET_ACTIONS.FETCH_OUTLET_SUCCESS,
|
||||
payload: { data: record },
|
||||
})
|
||||
}
|
||||
>
|
||||
<i data-feather="edit" className="feather-edit"></i>
|
||||
</Link>
|
||||
@ -222,7 +250,7 @@ const OutletList = () => {
|
||||
cancelButtonText: "Cancel",
|
||||
}).then((result) => {
|
||||
if (result.isConfirmed) {
|
||||
handleDeleteCategory(record.id || record.key);
|
||||
handleDeleteOutlet(record.id || record.key);
|
||||
}
|
||||
});
|
||||
}}
|
||||
@ -234,6 +262,7 @@ const OutletList = () => {
|
||||
),
|
||||
},
|
||||
];
|
||||
|
||||
const MySwal = withReactContent(Swal);
|
||||
|
||||
return (
|
||||
@ -243,8 +272,8 @@ const OutletList = () => {
|
||||
<div className="page-header">
|
||||
<div className="add-item d-flex">
|
||||
<div className="page-title">
|
||||
<h4>Category</h4>
|
||||
<h6>Manage your categories</h6>
|
||||
<h4>Outlet</h4>
|
||||
<h6>Manage your outlets</h6>
|
||||
</div>
|
||||
</div>
|
||||
<ul className="table-top-head">
|
||||
@ -298,17 +327,6 @@ const OutletList = () => {
|
||||
</OverlayTrigger>
|
||||
</li>
|
||||
</ul>
|
||||
<div className="page-btn">
|
||||
<Link
|
||||
to="#"
|
||||
className="btn btn-added"
|
||||
data-bs-toggle="modal"
|
||||
data-bs-target="#add-category"
|
||||
>
|
||||
<PlusCircle className="me-2" />
|
||||
Add New Category
|
||||
</Link>
|
||||
</div>
|
||||
</div>
|
||||
{/* /product list */}
|
||||
<div className="card table-list-card">
|
||||
@ -348,7 +366,7 @@ const OutletList = () => {
|
||||
<strong>Error:</strong> {error}
|
||||
<button
|
||||
className="btn btn-sm btn-outline-danger ms-2"
|
||||
onClick={() => dispatch(fetchCategories())}
|
||||
onClick={() => dispatch(fetchOutlets())}
|
||||
>
|
||||
Retry
|
||||
</button>
|
||||
@ -376,11 +394,11 @@ const OutletList = () => {
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{/* /category list */}
|
||||
{/* /outlet list */}
|
||||
</div>
|
||||
</div>
|
||||
<AddCategoryList />
|
||||
<EditCategoryList />
|
||||
<EditOutletList />
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
import { Tag } from "antd";
|
||||
import { useEffect, useState } from "react";
|
||||
import "react-datepicker/dist/react-datepicker.css";
|
||||
import { Edit, Trash2 } from "react-feather";
|
||||
import { Trash2 } from "react-feather";
|
||||
import { useDispatch, useSelector } from "react-redux";
|
||||
import { Link } from "react-router-dom";
|
||||
import Swal from "sweetalert2";
|
||||
@ -13,8 +13,7 @@ import ManageStockModal from "../../core/modals/stocks/managestockModal";
|
||||
import Table from "../../core/pagination/datatable";
|
||||
import {
|
||||
deleteInventory,
|
||||
fetchInventories,
|
||||
INVENTORY_ACTIONS,
|
||||
fetchInventories
|
||||
} from "../../core/redux/actions/inventoryActions";
|
||||
import { formatDate } from "../../utils/date";
|
||||
|
||||
@ -180,21 +179,6 @@ const Managestock = () => {
|
||||
<div className="edit-delete-action">
|
||||
<div className="input-block add-lists"></div>
|
||||
|
||||
<Link
|
||||
className="me-2 p-2"
|
||||
to="#"
|
||||
data-bs-toggle="modal"
|
||||
data-bs-target="#edit-units"
|
||||
onClick={() =>
|
||||
dispatch({
|
||||
type: INVENTORY_ACTIONS.FETCH_INVENTORY_SUCCESS,
|
||||
payload: { data: record },
|
||||
})
|
||||
}
|
||||
>
|
||||
<Edit className="feather-edit" />
|
||||
</Link>
|
||||
|
||||
<Link
|
||||
className="confirm-text p-2"
|
||||
to="#"
|
||||
|
||||
@ -1,18 +1,15 @@
|
||||
import { Tag } from "antd";
|
||||
import { useEffect, useState } from "react";
|
||||
import "react-datepicker/dist/react-datepicker.css";
|
||||
import { Edit, Trash2 } from "react-feather";
|
||||
import { PlusCircle } from "react-feather";
|
||||
import { useDispatch, useSelector } from "react-redux";
|
||||
import { Link } from "react-router-dom";
|
||||
import Swal from "sweetalert2";
|
||||
import withReactContent from "sweetalert2-react-content";
|
||||
import CustomPagination from "../../components/CustomPagination";
|
||||
import Breadcrumbs from "../../core/breadcrumbs";
|
||||
import ImageWithBasePath from "../../core/img/imagewithbasebath";
|
||||
import StockadjustmentModal from "../../core/modals/stocks/stockadjustmentModal";
|
||||
import ManageStockModal from "../../core/modals/stocks/managestockModal";
|
||||
import Table from "../../core/pagination/datatable";
|
||||
import { fetchInventories } from "../../core/redux/actions/inventoryActions";
|
||||
import { formatDate } from "../../utils/date";
|
||||
import { Tag } from "antd";
|
||||
|
||||
const StockAdjustment = () => {
|
||||
const {
|
||||
@ -149,73 +146,30 @@ const StockAdjustment = () => {
|
||||
),
|
||||
sorter: (a, b) => a.Quantity.length - b.Quantity.length,
|
||||
},
|
||||
|
||||
{
|
||||
title: "Action",
|
||||
dataIndex: "action",
|
||||
render: () => (
|
||||
<td className="action-table-data">
|
||||
<div className="edit-delete-action">
|
||||
<div className="input-block add-lists"></div>
|
||||
|
||||
<Link
|
||||
className="me-2 p-2"
|
||||
to="#"
|
||||
data-bs-toggle="modal"
|
||||
data-bs-target="#edit-units"
|
||||
>
|
||||
<Edit className="feather-edit" />
|
||||
</Link>
|
||||
|
||||
<Link
|
||||
className="confirm-text p-2"
|
||||
to="#"
|
||||
onClick={showConfirmationAlert}
|
||||
>
|
||||
<Trash2 className="feather-trash-2" />
|
||||
</Link>
|
||||
</div>
|
||||
</td>
|
||||
),
|
||||
sorter: (a, b) => a.createdby.length - b.createdby.length,
|
||||
},
|
||||
];
|
||||
|
||||
const MySwal = withReactContent(Swal);
|
||||
|
||||
const showConfirmationAlert = () => {
|
||||
MySwal.fire({
|
||||
title: "Are you sure?",
|
||||
text: "You won't be able to revert this!",
|
||||
showCancelButton: true,
|
||||
confirmButtonColor: "#00ff00",
|
||||
confirmButtonText: "Yes, delete it!",
|
||||
cancelButtonColor: "#ff0000",
|
||||
cancelButtonText: "Cancel",
|
||||
}).then((result) => {
|
||||
if (result.isConfirmed) {
|
||||
MySwal.fire({
|
||||
title: "Deleted!",
|
||||
text: "Your file has been deleted.",
|
||||
className: "btn btn-success",
|
||||
confirmButtonText: "OK",
|
||||
customClass: {
|
||||
confirmButton: "btn btn-success",
|
||||
},
|
||||
});
|
||||
} else {
|
||||
MySwal.close();
|
||||
}
|
||||
});
|
||||
};
|
||||
return (
|
||||
<div className="page-wrapper">
|
||||
<div className="content">
|
||||
<Breadcrumbs
|
||||
maintitle="Stock Adjustment"
|
||||
subtitle=" Manage your stock adjustment"
|
||||
addButton="Add New"
|
||||
/>
|
||||
<div className="page-header">
|
||||
<div className="add-item d-flex">
|
||||
<div className="page-title">
|
||||
<h4>Stock Adjusment</h4>
|
||||
<h6>Adjust your stocks</h6>
|
||||
</div>
|
||||
</div>
|
||||
<div className="page-btn">
|
||||
<Link
|
||||
to="#"
|
||||
className="btn btn-added"
|
||||
data-bs-toggle="modal"
|
||||
data-bs-target="#edit-units"
|
||||
>
|
||||
<PlusCircle className="me-2" />
|
||||
Add New
|
||||
</Link>
|
||||
</div>
|
||||
</div>
|
||||
{/* /product list */}
|
||||
<div className="card table-list-card">
|
||||
<div className="card-body">
|
||||
@ -283,7 +237,7 @@ const StockAdjustment = () => {
|
||||
</div>
|
||||
{/* /product list */}
|
||||
</div>
|
||||
<StockadjustmentModal />
|
||||
<ManageStockModal />
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
@ -1,8 +1,9 @@
|
||||
import api from './api';
|
||||
import api from "./api";
|
||||
|
||||
const ENDPOINTS = {
|
||||
INVENTORIES: 'inventory',
|
||||
INVENTORIES: "inventory",
|
||||
INVENTORY_BY_ID: (id) => `inventory/${id}`,
|
||||
INVENTORY_ADJUST: "inventory/adjust",
|
||||
};
|
||||
|
||||
export const inventoryApi = {
|
||||
@ -11,7 +12,7 @@ export const inventoryApi = {
|
||||
const response = await api.get(ENDPOINTS.INVENTORIES, { params });
|
||||
return response.data;
|
||||
} catch (error) {
|
||||
console.error('Error fetching inventories:', error);
|
||||
console.error("Error fetching inventories:", error);
|
||||
throw error;
|
||||
}
|
||||
},
|
||||
@ -31,14 +32,17 @@ export const inventoryApi = {
|
||||
const response = await api.post(ENDPOINTS.INVENTORIES, inventoryData);
|
||||
return response.data;
|
||||
} catch (error) {
|
||||
console.error('Error creating inventory:', error);
|
||||
console.error("Error creating inventory:", error);
|
||||
throw error;
|
||||
}
|
||||
},
|
||||
|
||||
updateInventory: async (id, inventoryData) => {
|
||||
try {
|
||||
const response = await api.put(ENDPOINTS.INVENTORY_BY_ID(id), inventoryData);
|
||||
const response = await api.put(
|
||||
ENDPOINTS.INVENTORY_BY_ID(id),
|
||||
inventoryData
|
||||
);
|
||||
return response.data;
|
||||
} catch (error) {
|
||||
console.error(`Error updating inventory ${id}:`, error);
|
||||
@ -46,6 +50,19 @@ export const inventoryApi = {
|
||||
}
|
||||
},
|
||||
|
||||
adjustInventory: async (inventoryData) => {
|
||||
try {
|
||||
const response = await api.post(
|
||||
ENDPOINTS.INVENTORY_ADJUST,
|
||||
inventoryData
|
||||
);
|
||||
return response.data;
|
||||
} catch (error) {
|
||||
console.error("Error adjusting inventory:", error);
|
||||
throw error;
|
||||
}
|
||||
},
|
||||
|
||||
deleteInventory: async (id) => {
|
||||
try {
|
||||
const response = await api.delete(ENDPOINTS.INVENTORY_BY_ID(id));
|
||||
|
||||
@ -3,7 +3,7 @@ import api from './api';
|
||||
// Outlets API endpoints
|
||||
const ENDPOINTS = {
|
||||
OUTLETS: 'outlets/list',
|
||||
OUTLET_BY_ID: (id) => `outlets/${id}`,
|
||||
OUTLET_BY_ID: (id) => `outlets/detail/${id}`,
|
||||
OUTLET_PRODUCTS: (id) => `outlets/${id}/products`,
|
||||
};
|
||||
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user