fix: inventory adjustment

This commit is contained in:
ferdiansyah783 2025-08-04 12:42:18 +07:00
parent 86a4a19209
commit 87880dcdd5
16 changed files with 948 additions and 240 deletions

View File

@ -155,6 +155,7 @@ export const all_routes = {
taxreport: "/tax-report", taxreport: "/tax-report",
profitloss: "/profit-loss-report", profitloss: "/profit-loss-report",
notes: "/notes", notes: "/notes",
outletlist: "/outlet-list",
filemanager: "/file-manager", filemanager: "/file-manager",
profile: "/profile", profile: "/profile",
signin: "/signin", signin: "/signin",

View File

@ -206,6 +206,7 @@ import ProductList3 from "../feature-module/inventory/productlist3";
import { all_routes } from "./all_routes"; import { all_routes } from "./all_routes";
import PaymentMethodList from "../feature-module/FinanceAccounts/paymentmethodlist"; import PaymentMethodList from "../feature-module/FinanceAccounts/paymentmethodlist";
import CompanyList from "../feature-module/superadmin/companylist"; import CompanyList from "../feature-module/superadmin/companylist";
import OutletList from "../feature-module/inventory/outletlist";
export const publicRoutes = [ export const publicRoutes = [
{ {
@ -1499,13 +1500,20 @@ export const publicRoutes = [
route: Route, route: Route,
}, },
{ {
id: 1, id: 121,
path: routes.companylist, path: routes.companylist,
name: "companies", name: "companies",
element: <CompanyList />, element: <CompanyList />,
route: Route, route: Route,
role: 'superadmin' role: 'superadmin'
} },
{
id: 122,
path: routes.outletlist,
name: "outlets",
element: <OutletList />,
route: Route
},
]; ];
export const posRoutes = [ export const posRoutes = [

View File

@ -10,7 +10,6 @@ import { useSelector } from "react-redux";
const CustomPagination = ({ const CustomPagination = ({
currentPage = 1, currentPage = 1,
pageSize = 10, pageSize = 10,
totalCount = 0,
totalPages = 1, totalPages = 1,
loading = false, loading = false,
onPageChange, onPageChange,
@ -70,8 +69,6 @@ const CustomPagination = ({
}; };
}, []); }, []);
console.log(totalCount);
// Handle page change // Handle page change
const handlePageClick = (page) => { const handlePageClick = (page) => {
if (!loading && page !== currentPage && onPageChange) { if (!loading && page !== currentPage && onPageChange) {

View File

@ -145,6 +145,13 @@ export const SidebarData = [
showSubRoute: false, showSubRoute: false,
submenu: false, submenu: false,
}, },
{
label: "Outlets",
link: "/outlet-list",
icon: <Icon.Home />,
showSubRoute: false,
submenu: false,
},
{ {
label: "Warranty", label: "Warranty",
link: "/warranty", link: "/warranty",

View 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;

View 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;

View 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;

View File

@ -5,9 +5,9 @@ import Swal from "sweetalert2";
import outletsApi from "../../../services/outletsApi"; import outletsApi from "../../../services/outletsApi";
import productsApi from "../../../services/productsApi"; import productsApi from "../../../services/productsApi";
import { import {
adjustInventory,
createInventory, createInventory,
fetchInventories, fetchInventories,
updateInventory,
} from "../../redux/actions/inventoryActions"; } from "../../redux/actions/inventoryActions";
const ManageStockModal = () => { const ManageStockModal = () => {
@ -21,8 +21,10 @@ const ManageStockModal = () => {
outlet_id: "", outlet_id: "",
product_id: "", product_id: "",
quantity: "", quantity: "",
delta: "",
min_stock_level: "", min_stock_level: "",
max_stock_level: "", max_stock_level: "",
reason: "",
}; };
}; };
@ -85,7 +87,7 @@ const ManageStockModal = () => {
e.preventDefault(); e.preventDefault();
try { try {
await dispatch(updateInventory(currentInventory?.id, formData)); await dispatch(adjustInventory(formData));
await dispatch(fetchInventories()); await dispatch(fetchInventories());
@ -107,7 +109,9 @@ const ManageStockModal = () => {
Swal.fire({ Swal.fire({
icon: "error", icon: "error",
title: "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="content">
<div className="modal-header"> <div className="modal-header">
<div className="page-title"> <div className="page-title">
<h4>Edit Stock</h4> <h4>Adjust Stock</h4>
</div> </div>
<button <button
type="button" type="button"
@ -285,33 +289,57 @@ const ManageStockModal = () => {
<div className="modal-body custom-modal-body"> <div className="modal-body custom-modal-body">
<form onSubmit={handleUpdate}> <form onSubmit={handleUpdate}>
<div className="mb-3"> <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 <input
type="number" type="number"
className="form-control border" className="form-control border"
name="quantity" name="delta"
value={formData.quantity} value={formData.delta}
onChange={handleInputChange} onChange={handleInputChange}
/> />
</div> </div>
<div className="mb-3"> <div className="mb-3">
<label className="form-label">Min Stock</label> <label className="form-label">Reason</label>
<input <textarea
type="number" className="form-control h-75 border"
className="form-control border" rows={5}
name="min_stock_level" name="reason"
value={formData.min_stock_level} value={formData.reason}
onChange={handleInputChange} onChange={(e) =>
/> setFormData({ ...formData, reason: e.target.value })
</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}
/> />
</div> </div>
@ -338,7 +366,7 @@ const ManageStockModal = () => {
Updating... Updating...
</> </>
) : ( ) : (
"Update" "Save"
)} )}
</button> </button>
</div> </div>

View File

@ -1,62 +1,72 @@
import { inventoryApi } from '../../../services/inventoriesApi'; import { inventoryApi } from "../../../services/inventoriesApi";
// Action Types // Action Types
export const INVENTORY_ACTIONS = { export const INVENTORY_ACTIONS = {
// Fetch Inventories // Fetch Inventories
FETCH_INVENTORIES_REQUEST: 'FETCH_INVENTORIES_REQUEST', FETCH_INVENTORIES_REQUEST: "FETCH_INVENTORIES_REQUEST",
FETCH_INVENTORIES_SUCCESS: 'FETCH_INVENTORIES_SUCCESS', FETCH_INVENTORIES_SUCCESS: "FETCH_INVENTORIES_SUCCESS",
FETCH_INVENTORIES_FAILURE: 'FETCH_INVENTORIES_FAILURE', FETCH_INVENTORIES_FAILURE: "FETCH_INVENTORIES_FAILURE",
// Fetch Single Inventory // Fetch Single Inventory
FETCH_INVENTORY_REQUEST: 'FETCH_INVENTORY_REQUEST', FETCH_INVENTORY_REQUEST: "FETCH_INVENTORY_REQUEST",
FETCH_INVENTORY_SUCCESS: 'FETCH_INVENTORY_SUCCESS', FETCH_INVENTORY_SUCCESS: "FETCH_INVENTORY_SUCCESS",
FETCH_INVENTORY_FAILURE: 'FETCH_INVENTORY_FAILURE', FETCH_INVENTORY_FAILURE: "FETCH_INVENTORY_FAILURE",
// Create Inventory // Create Inventory
CREATE_INVENTORY_REQUEST: 'CREATE_INVENTORY_REQUEST', CREATE_INVENTORY_REQUEST: "CREATE_INVENTORY_REQUEST",
CREATE_INVENTORY_SUCCESS: 'CREATE_INVENTORY_SUCCESS', CREATE_INVENTORY_SUCCESS: "CREATE_INVENTORY_SUCCESS",
CREATE_INVENTORY_FAILURE: 'CREATE_INVENTORY_FAILURE', 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
UPDATE_INVENTORY_REQUEST: 'UPDATE_INVENTORY_REQUEST', UPDATE_INVENTORY_REQUEST: "UPDATE_INVENTORY_REQUEST",
UPDATE_INVENTORY_SUCCESS: 'UPDATE_INVENTORY_SUCCESS', UPDATE_INVENTORY_SUCCESS: "UPDATE_INVENTORY_SUCCESS",
UPDATE_INVENTORY_FAILURE: 'UPDATE_INVENTORY_FAILURE', UPDATE_INVENTORY_FAILURE: "UPDATE_INVENTORY_FAILURE",
// Delete Inventory // Delete Inventory
DELETE_INVENTORY_REQUEST: 'DELETE_INVENTORY_REQUEST', DELETE_INVENTORY_REQUEST: "DELETE_INVENTORY_REQUEST",
DELETE_INVENTORY_SUCCESS: 'DELETE_INVENTORY_SUCCESS', DELETE_INVENTORY_SUCCESS: "DELETE_INVENTORY_SUCCESS",
DELETE_INVENTORY_FAILURE: 'DELETE_INVENTORY_FAILURE', DELETE_INVENTORY_FAILURE: "DELETE_INVENTORY_FAILURE",
// Search Inventories // Search Inventories
SEARCH_INVENTORIES_REQUEST: 'SEARCH_INVENTORIES_REQUEST', SEARCH_INVENTORIES_REQUEST: "SEARCH_INVENTORIES_REQUEST",
SEARCH_INVENTORIES_SUCCESS: 'SEARCH_INVENTORIES_SUCCESS', SEARCH_INVENTORIES_SUCCESS: "SEARCH_INVENTORIES_SUCCESS",
SEARCH_INVENTORIES_FAILURE: 'SEARCH_INVENTORIES_FAILURE', SEARCH_INVENTORIES_FAILURE: "SEARCH_INVENTORIES_FAILURE",
// Clear States // Clear States
CLEAR_INVENTORY_ERROR: 'CLEAR_INVENTORY_ERROR', CLEAR_INVENTORY_ERROR: "CLEAR_INVENTORY_ERROR",
CLEAR_CURRENT_INVENTORY: 'CLEAR_CURRENT_INVENTORY', CLEAR_CURRENT_INVENTORY: "CLEAR_CURRENT_INVENTORY",
}; };
// Action Creators // Action Creators
export const fetchInventories = (params = {}) => async (dispatch) => { export const fetchInventories =
dispatch({ type: INVENTORY_ACTIONS.FETCH_INVENTORIES_REQUEST }); (params = {}) =>
async (dispatch) => {
dispatch({ type: INVENTORY_ACTIONS.FETCH_INVENTORIES_REQUEST });
try { try {
const data = await inventoryApi.getAllInventories(params); const data = await inventoryApi.getAllInventories(params);
dispatch({ dispatch({
type: INVENTORY_ACTIONS.FETCH_INVENTORIES_SUCCESS, type: INVENTORY_ACTIONS.FETCH_INVENTORIES_SUCCESS,
payload: data, payload: data,
}); });
return data; return data;
} catch (error) { } catch (error) {
dispatch({ dispatch({
type: INVENTORY_ACTIONS.FETCH_INVENTORIES_FAILURE, type: INVENTORY_ACTIONS.FETCH_INVENTORIES_FAILURE,
payload: error.response?.data?.message || error.message || 'Failed to fetch inventories', payload:
}); error.response?.data?.message ||
throw error; error.message ||
} "Failed to fetch inventories",
}; });
throw error;
}
};
export const fetchInventory = (id) => async (dispatch) => { export const fetchInventory = (id) => async (dispatch) => {
dispatch({ type: INVENTORY_ACTIONS.FETCH_INVENTORY_REQUEST }); dispatch({ type: INVENTORY_ACTIONS.FETCH_INVENTORY_REQUEST });
@ -71,7 +81,10 @@ export const fetchInventory = (id) => async (dispatch) => {
} catch (error) { } catch (error) {
dispatch({ dispatch({
type: INVENTORY_ACTIONS.FETCH_INVENTORY_FAILURE, 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; throw error;
} }
@ -90,7 +103,32 @@ export const createInventory = (inventoryData) => async (dispatch) => {
} catch (error) { } catch (error) {
dispatch({ dispatch({
type: INVENTORY_ACTIONS.CREATE_INVENTORY_FAILURE, 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; throw error;
} }
@ -109,7 +147,10 @@ export const updateInventory = (id, inventoryData) => async (dispatch) => {
} catch (error) { } catch (error) {
dispatch({ dispatch({
type: INVENTORY_ACTIONS.UPDATE_INVENTORY_FAILURE, 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; throw error;
} }
@ -128,7 +169,10 @@ export const deleteInventory = (id) => async (dispatch) => {
} catch (error) { } catch (error) {
dispatch({ dispatch({
type: INVENTORY_ACTIONS.DELETE_INVENTORY_FAILURE, 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; throw error;
} }

View File

@ -1,4 +1,4 @@
import { INVENTORY_ACTIONS } from '../actions/inventoryActions'; import { INVENTORY_ACTIONS } from "../actions/inventoryActions";
const initialState = { const initialState = {
// Inventory list // Inventory list
@ -15,7 +15,7 @@ const initialState = {
// Search results // Search results
searchResults: [], searchResults: [],
searchQuery: '', searchQuery: "",
// Loading states // Loading states
loading: false, loading: false,
@ -115,6 +115,32 @@ const inventoryReducer = (state = initialState, action) => {
error: action.payload, 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 // Update Inventory
case INVENTORY_ACTIONS.UPDATE_INVENTORY_REQUEST: case INVENTORY_ACTIONS.UPDATE_INVENTORY_REQUEST:
return { return {
@ -127,7 +153,7 @@ const inventoryReducer = (state = initialState, action) => {
return { return {
...state, ...state,
updating: false, updating: false,
inventories: state.inventories.map(inv => inventories: state.inventories.map((inv) =>
inv.id === action.payload.data.id ? action.payload.data : inv inv.id === action.payload.data.id ? action.payload.data : inv
), ),
currentInventory: action.payload.data, currentInventory: action.payload.data,
@ -153,7 +179,9 @@ const inventoryReducer = (state = initialState, action) => {
return { return {
...state, ...state,
deleting: false, deleting: false,
inventories: state.inventories.filter(inv => inv.id !== action.payload), inventories: state.inventories.filter(
(inv) => inv.id !== action.payload
),
totalInventories: state.totalInventories - 1, totalInventories: state.totalInventories - 1,
error: null, error: null,
}; };

View File

@ -1,4 +1,4 @@
import { Select, Tag } from "antd"; import { Tag } from "antd";
import { import {
ChevronUp, ChevronUp,
PlusCircle, PlusCircle,
@ -13,11 +13,15 @@ import Swal from "sweetalert2";
import withReactContent from "sweetalert2-react-content"; import withReactContent from "sweetalert2-react-content";
import CustomPagination from "../../components/CustomPagination"; import CustomPagination from "../../components/CustomPagination";
import ImageWithBasePath from "../../core/img/imagewithbasebath"; import ImageWithBasePath from "../../core/img/imagewithbasebath";
import AddCategoryList from "../../core/modals/inventory/addcategorylist"; import AddPaymentMethod from "../../core/modals/financeaccount/addpaymentmethod";
import EditCategoryList from "../../core/modals/inventory/editcategorylist"; import EditPaymentMethod from "../../core/modals/financeaccount/editpaymentmethod";
import Table from "../../core/pagination/datatable"; import Table from "../../core/pagination/datatable";
import { setToogleHeader } from "../../core/redux/action"; 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"; import { formatDate } from "../../utils/date";
const PaymentMethodList = () => { const PaymentMethodList = () => {
@ -149,14 +153,15 @@ const PaymentMethodList = () => {
</Tooltip> </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 = [ 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", title: "Payment Method",
dataIndex: "paymentmethod", dataIndex: "paymentmethod",
@ -200,8 +205,13 @@ const PaymentMethodList = () => {
className="me-2 p-2" className="me-2 p-2"
to="#" to="#"
data-bs-toggle="modal" data-bs-toggle="modal"
data-bs-target="#edit-category" data-bs-target="#edit-payment-method"
onClick={() => dispatch(fetchPaymentMethod(record.id))} onClick={() =>
dispatch({
type: PAYMENT_METHOD_ACTIONS.FETCH_PAYMENT_METHOD_SUCCESS,
payload: { data: record },
})
}
> >
<i data-feather="edit" className="feather-edit"></i> <i data-feather="edit" className="feather-edit"></i>
</Link> </Link>
@ -234,7 +244,6 @@ const PaymentMethodList = () => {
]; ];
const MySwal = withReactContent(Swal); const MySwal = withReactContent(Swal);
return ( return (
<div> <div>
<div className="page-wrapper"> <div className="page-wrapper">
@ -302,10 +311,10 @@ const PaymentMethodList = () => {
to="#" to="#"
className="btn btn-added" className="btn btn-added"
data-bs-toggle="modal" data-bs-toggle="modal"
data-bs-target="#add-category" data-bs-target="#add-payment-method"
> >
<PlusCircle className="me-2" /> <PlusCircle className="me-2" />
Add New Category Add New
</Link> </Link>
</div> </div>
</div> </div>
@ -326,12 +335,6 @@ const PaymentMethodList = () => {
</Link> </Link>
</div> </div>
</div> </div>
<Select
style={{ height: 36 }}
defaultValue={dateOptions[0]?.value}
options={dateOptions}
/>
</div> </div>
<div className="table-responsive"> <div className="table-responsive">
@ -378,8 +381,8 @@ const PaymentMethodList = () => {
{/* /category list */} {/* /category list */}
</div> </div>
</div> </div>
<AddCategoryList /> <AddPaymentMethod />
<EditCategoryList /> <EditPaymentMethod />
</div> </div>
); );
}; };

View File

@ -1,7 +1,6 @@
import { Select, Tag } from "antd"; import { Select, Tag } from "antd";
import { import {
ChevronUp, ChevronUp,
PlusCircle,
RotateCcw, RotateCcw,
Trash2, Trash2,
} from "feather-icons-react/build/IconComponents"; } from "feather-icons-react/build/IconComponents";
@ -14,30 +13,30 @@ import withReactContent from "sweetalert2-react-content";
import CustomPagination from "../../components/CustomPagination"; import CustomPagination from "../../components/CustomPagination";
import ImageWithBasePath from "../../core/img/imagewithbasebath"; import ImageWithBasePath from "../../core/img/imagewithbasebath";
import AddCategoryList from "../../core/modals/inventory/addcategorylist"; 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 Table from "../../core/pagination/datatable";
import { setToogleHeader } from "../../core/redux/action"; import { setToogleHeader } from "../../core/redux/action";
import { import {
deleteCategory, deleteOutlet,
fetchCategories, fetchOutlets,
fetchCategory, OUTLET_ACTIONS,
} from "../../core/redux/actions/categoryActions"; } from "../../core/redux/actions/outletActions";
import { formatDate } from "../../utils/date"; import { formatRupiah } from "../../utils/currency";
const OutletList = () => { const OutletList = () => {
const { const {
categories: apiCategories, outlets: apiOutlets,
loading, loading,
error, error,
totalCategories, totalOutlets,
totalPages, totalPages,
pageSize: reduxPageSize, pageSize: reduxPageSize,
currentPage: reduxCurrentPage, currentPage: reduxCurrentPage,
} = useSelector((state) => state.categories); } = useSelector((state) => state.outlets);
const dispatch = useDispatch(); const dispatch = useDispatch();
const data = useSelector((state) => state.toggle_header); 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 [currentPage, setCurrentPage] = useState(reduxCurrentPage || 1);
const [pageSize, setPageSize] = useState(reduxPageSize || 10); const [pageSize, setPageSize] = useState(reduxPageSize || 10);
@ -46,7 +45,7 @@ const OutletList = () => {
const [debouncedSearchTerm, setDebouncedSearchTerm] = useState(""); const [debouncedSearchTerm, setDebouncedSearchTerm] = useState("");
useEffect(() => { useEffect(() => {
const loadCategories = async () => { const loadOutlets = async () => {
try { try {
const searchParams = { const searchParams = {
page: currentPage, page: currentPage,
@ -59,13 +58,13 @@ const OutletList = () => {
Object.entries(searchParams).filter(([, value]) => value !== "") Object.entries(searchParams).filter(([, value]) => value !== "")
); );
await dispatch(fetchCategories(cleanParams)); await dispatch(fetchOutlets(cleanParams));
} catch (error) { } catch (error) {
console.error("Failed to load categories", error); console.error("Failed to load categories", error);
} }
}; };
loadCategories(); loadOutlets();
}, [dispatch, currentPage, pageSize, debouncedSearchTerm]); }, [dispatch, currentPage, pageSize, debouncedSearchTerm]);
// Debounce search term // Debounce search term
@ -96,13 +95,13 @@ const OutletList = () => {
}; };
// Calculate pagination info // Calculate pagination info
const totalRecords = totalCategories || dataSource.length; const totalRecords = totalOutlets || dataSource.length;
const calculatedTotalPages = Math.ceil(totalRecords / pageSize); const calculatedTotalPages = Math.ceil(totalRecords / pageSize);
const actualTotalPages = totalPages || calculatedTotalPages; const actualTotalPages = totalPages || calculatedTotalPages;
const handleDeleteCategory = async (categoryId) => { const handleDeleteOutlet = async (categoryId) => {
try { try {
await dispatch(deleteCategory(categoryId)); await dispatch(deleteOutlet(categoryId));
// Show success message // Show success message
MySwal.fire({ MySwal.fire({
title: "Deleted!", title: "Deleted!",
@ -162,33 +161,57 @@ const OutletList = () => {
const columns = [ const columns = [
{ {
title: "Category", title: "Organization",
dataIndex: "category", dataIndex: "organization",
render: (_, record) => { render: (_, record) => {
return <span>{record.name}</span>; return <span>{record.organization_name || "-"}</span>;
}, },
sorter: (a, b) => a.category.length - b.category.length, sorter: (a, b) => a.category.length - b.category.length,
}, },
{ {
title: "Category Slug", title: "Name",
dataIndex: "categoryslug", dataIndex: "name",
render: (_, record) => { render: (_, record) => {
return <span>{record?.name?.toLowerCase()}</span>; return <span>{record?.name || "-"}</span>;
}, },
sorter: (a, b) => a.categoryslug.length - b.categoryslug.length, sorter: (a, b) => a.categoryslug.length - b.categoryslug.length,
}, },
{ {
title: "Created On", title: "Address",
dataIndex: "createdon", dataIndex: "address",
render: (_, record) => { render: (_, record) => {
return <span>{formatDate(record.created_at)}</span>; return <span>{record.address || "-"}</span>;
}, },
sorter: (a, b) => a.createdon.length - b.createdon.length, 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", title: "Status",
dataIndex: "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, sorter: (a, b) => a.status.length - b.status.length,
}, },
{ {
@ -202,8 +225,13 @@ const OutletList = () => {
className="me-2 p-2" className="me-2 p-2"
to="#" to="#"
data-bs-toggle="modal" data-bs-toggle="modal"
data-bs-target="#edit-category" data-bs-target="#edit-outlet"
onClick={() => dispatch(fetchCategory(record.id))} onClick={() =>
dispatch({
type: OUTLET_ACTIONS.FETCH_OUTLET_SUCCESS,
payload: { data: record },
})
}
> >
<i data-feather="edit" className="feather-edit"></i> <i data-feather="edit" className="feather-edit"></i>
</Link> </Link>
@ -222,7 +250,7 @@ const OutletList = () => {
cancelButtonText: "Cancel", cancelButtonText: "Cancel",
}).then((result) => { }).then((result) => {
if (result.isConfirmed) { if (result.isConfirmed) {
handleDeleteCategory(record.id || record.key); handleDeleteOutlet(record.id || record.key);
} }
}); });
}} }}
@ -234,6 +262,7 @@ const OutletList = () => {
), ),
}, },
]; ];
const MySwal = withReactContent(Swal); const MySwal = withReactContent(Swal);
return ( return (
@ -243,8 +272,8 @@ const OutletList = () => {
<div className="page-header"> <div className="page-header">
<div className="add-item d-flex"> <div className="add-item d-flex">
<div className="page-title"> <div className="page-title">
<h4>Category</h4> <h4>Outlet</h4>
<h6>Manage your categories</h6> <h6>Manage your outlets</h6>
</div> </div>
</div> </div>
<ul className="table-top-head"> <ul className="table-top-head">
@ -298,17 +327,6 @@ const OutletList = () => {
</OverlayTrigger> </OverlayTrigger>
</li> </li>
</ul> </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> </div>
{/* /product list */} {/* /product list */}
<div className="card table-list-card"> <div className="card table-list-card">
@ -348,7 +366,7 @@ const OutletList = () => {
<strong>Error:</strong> {error} <strong>Error:</strong> {error}
<button <button
className="btn btn-sm btn-outline-danger ms-2" className="btn btn-sm btn-outline-danger ms-2"
onClick={() => dispatch(fetchCategories())} onClick={() => dispatch(fetchOutlets())}
> >
Retry Retry
</button> </button>
@ -376,11 +394,11 @@ const OutletList = () => {
</div> </div>
</div> </div>
</div> </div>
{/* /category list */} {/* /outlet list */}
</div> </div>
</div> </div>
<AddCategoryList /> <AddCategoryList />
<EditCategoryList /> <EditOutletList />
</div> </div>
); );
}; };

View File

@ -1,7 +1,7 @@
import { Tag } from "antd"; import { Tag } from "antd";
import { useEffect, useState } from "react"; import { useEffect, useState } from "react";
import "react-datepicker/dist/react-datepicker.css"; 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 { useDispatch, useSelector } from "react-redux";
import { Link } from "react-router-dom"; import { Link } from "react-router-dom";
import Swal from "sweetalert2"; import Swal from "sweetalert2";
@ -13,8 +13,7 @@ import ManageStockModal from "../../core/modals/stocks/managestockModal";
import Table from "../../core/pagination/datatable"; import Table from "../../core/pagination/datatable";
import { import {
deleteInventory, deleteInventory,
fetchInventories, fetchInventories
INVENTORY_ACTIONS,
} from "../../core/redux/actions/inventoryActions"; } from "../../core/redux/actions/inventoryActions";
import { formatDate } from "../../utils/date"; import { formatDate } from "../../utils/date";
@ -180,21 +179,6 @@ const Managestock = () => {
<div className="edit-delete-action"> <div className="edit-delete-action">
<div className="input-block add-lists"></div> <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 <Link
className="confirm-text p-2" className="confirm-text p-2"
to="#" to="#"

View File

@ -1,18 +1,15 @@
import { Tag } from "antd";
import { useEffect, useState } from "react"; import { useEffect, useState } from "react";
import "react-datepicker/dist/react-datepicker.css"; 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 { useDispatch, useSelector } from "react-redux";
import { Link } from "react-router-dom"; import { Link } from "react-router-dom";
import Swal from "sweetalert2";
import withReactContent from "sweetalert2-react-content";
import CustomPagination from "../../components/CustomPagination"; import CustomPagination from "../../components/CustomPagination";
import Breadcrumbs from "../../core/breadcrumbs";
import ImageWithBasePath from "../../core/img/imagewithbasebath"; 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 Table from "../../core/pagination/datatable";
import { fetchInventories } from "../../core/redux/actions/inventoryActions"; import { fetchInventories } from "../../core/redux/actions/inventoryActions";
import { formatDate } from "../../utils/date"; import { formatDate } from "../../utils/date";
import { Tag } from "antd";
const StockAdjustment = () => { const StockAdjustment = () => {
const { const {
@ -149,73 +146,30 @@ const StockAdjustment = () => {
), ),
sorter: (a, b) => a.Quantity.length - b.Quantity.length, 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 ( return (
<div className="page-wrapper"> <div className="page-wrapper">
<div className="content"> <div className="content">
<Breadcrumbs <div className="page-header">
maintitle="Stock Adjustment" <div className="add-item d-flex">
subtitle=" Manage your stock adjustment" <div className="page-title">
addButton="Add New" <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 */} {/* /product list */}
<div className="card table-list-card"> <div className="card table-list-card">
<div className="card-body"> <div className="card-body">
@ -283,7 +237,7 @@ const StockAdjustment = () => {
</div> </div>
{/* /product list */} {/* /product list */}
</div> </div>
<StockadjustmentModal /> <ManageStockModal />
</div> </div>
); );
}; };

View File

@ -1,8 +1,9 @@
import api from './api'; import api from "./api";
const ENDPOINTS = { const ENDPOINTS = {
INVENTORIES: 'inventory', INVENTORIES: "inventory",
INVENTORY_BY_ID: (id) => `inventory/${id}`, INVENTORY_BY_ID: (id) => `inventory/${id}`,
INVENTORY_ADJUST: "inventory/adjust",
}; };
export const inventoryApi = { export const inventoryApi = {
@ -11,7 +12,7 @@ export const inventoryApi = {
const response = await api.get(ENDPOINTS.INVENTORIES, { params }); const response = await api.get(ENDPOINTS.INVENTORIES, { params });
return response.data; return response.data;
} catch (error) { } catch (error) {
console.error('Error fetching inventories:', error); console.error("Error fetching inventories:", error);
throw error; throw error;
} }
}, },
@ -31,14 +32,17 @@ export const inventoryApi = {
const response = await api.post(ENDPOINTS.INVENTORIES, inventoryData); const response = await api.post(ENDPOINTS.INVENTORIES, inventoryData);
return response.data; return response.data;
} catch (error) { } catch (error) {
console.error('Error creating inventory:', error); console.error("Error creating inventory:", error);
throw error; throw error;
} }
}, },
updateInventory: async (id, inventoryData) => { updateInventory: async (id, inventoryData) => {
try { 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; return response.data;
} catch (error) { } catch (error) {
console.error(`Error updating inventory ${id}:`, 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) => { deleteInventory: async (id) => {
try { try {
const response = await api.delete(ENDPOINTS.INVENTORY_BY_ID(id)); const response = await api.delete(ENDPOINTS.INVENTORY_BY_ID(id));

View File

@ -3,7 +3,7 @@ import api from './api';
// Outlets API endpoints // Outlets API endpoints
const ENDPOINTS = { const ENDPOINTS = {
OUTLETS: 'outlets/list', OUTLETS: 'outlets/list',
OUTLET_BY_ID: (id) => `outlets/${id}`, OUTLET_BY_ID: (id) => `outlets/detail/${id}`,
OUTLET_PRODUCTS: (id) => `outlets/${id}/products`, OUTLET_PRODUCTS: (id) => `outlets/${id}/products`,
}; };