diff --git a/src/Router/all_routes.jsx b/src/Router/all_routes.jsx
index 6657f59..37bb440 100644
--- a/src/Router/all_routes.jsx
+++ b/src/Router/all_routes.jsx
@@ -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",
diff --git a/src/Router/router.link.jsx b/src/Router/router.link.jsx
index bd08b5e..32e3d31 100644
--- a/src/Router/router.link.jsx
+++ b/src/Router/router.link.jsx
@@ -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: ,
route: Route,
role: 'superadmin'
- }
+ },
+ {
+ id: 122,
+ path: routes.outletlist,
+ name: "outlets",
+ element: ,
+ route: Route
+ },
];
export const posRoutes = [
diff --git a/src/components/CustomPagination.jsx b/src/components/CustomPagination.jsx
index 48a5ad2..ef92f1c 100644
--- a/src/components/CustomPagination.jsx
+++ b/src/components/CustomPagination.jsx
@@ -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) {
diff --git a/src/core/json/siderbar_data.jsx b/src/core/json/siderbar_data.jsx
index 945305e..5271045 100644
--- a/src/core/json/siderbar_data.jsx
+++ b/src/core/json/siderbar_data.jsx
@@ -145,6 +145,13 @@ export const SidebarData = [
showSubRoute: false,
submenu: false,
},
+ {
+ label: "Outlets",
+ link: "/outlet-list",
+ icon: ,
+ showSubRoute: false,
+ submenu: false,
+ },
{
label: "Warranty",
link: "/warranty",
diff --git a/src/core/modals/financeaccount/addpaymentmethod.jsx b/src/core/modals/financeaccount/addpaymentmethod.jsx
new file mode 100644
index 0000000..8c83558
--- /dev/null
+++ b/src/core/modals/financeaccount/addpaymentmethod.jsx
@@ -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 (
+
+ {/* Add Payment Method */}
+
+
+
+
+
+
+
+
Create Payment Method
+
+
+
+
+
+
+
+
+
+ {/* /Add Category */}
+
+ );
+};
+
+export default AddPaymentMethod;
diff --git a/src/core/modals/financeaccount/editpaymentmethod.jsx b/src/core/modals/financeaccount/editpaymentmethod.jsx
new file mode 100644
index 0000000..2ceee43
--- /dev/null
+++ b/src/core/modals/financeaccount/editpaymentmethod.jsx
@@ -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 (
+
+ {/* Edit Payment Method */}
+
+
+
+
+
+
+
+
Edit Payment Method
+
+
+
+
+
+
+
+
+
+ {/* /Add Category */}
+
+ );
+};
+
+export default EditPaymentMethod;
diff --git a/src/core/modals/inventory/editoutletlist.jsx b/src/core/modals/inventory/editoutletlist.jsx
new file mode 100644
index 0000000..28c2b2d
--- /dev/null
+++ b/src/core/modals/inventory/editoutletlist.jsx
@@ -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 (
+
+ {/* Edit Outlet */}
+
+ {/* /Edit Outlet */}
+
+ );
+};
+
+export default EditOutletList;
diff --git a/src/core/modals/stocks/managestockModal.jsx b/src/core/modals/stocks/managestockModal.jsx
index 367ce7c..1d1018a 100644
--- a/src/core/modals/stocks/managestockModal.jsx
+++ b/src/core/modals/stocks/managestockModal.jsx
@@ -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 = () => {
-
Edit Stock
+ Adjust Stock
-
-
@@ -378,8 +381,8 @@ const PaymentMethodList = () => {
{/* /category list */}
-
-
+
+
);
};
diff --git a/src/feature-module/inventory/outletlist.jsx b/src/feature-module/inventory/outletlist.jsx
index a0b4d50..ca4086f 100644
--- a/src/feature-module/inventory/outletlist.jsx
+++ b/src/feature-module/inventory/outletlist.jsx
@@ -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 {record.name};
+ return {record.organization_name || "-"};
},
sorter: (a, b) => a.category.length - b.category.length,
},
{
- title: "Category Slug",
- dataIndex: "categoryslug",
+ title: "Name",
+ dataIndex: "name",
render: (_, record) => {
- return {record?.name?.toLowerCase()};
+ return {record?.name || "-"};
},
sorter: (a, b) => a.categoryslug.length - b.categoryslug.length,
},
{
- title: "Created On",
- dataIndex: "createdon",
+ title: "Address",
+ dataIndex: "address",
render: (_, record) => {
- return {formatDate(record.created_at)};
+ return {record.address || "-"};
},
sorter: (a, b) => a.createdon.length - b.createdon.length,
},
+ {
+ title: "Phone Number",
+ dataIndex: "phonenumber",
+ render: (_, record) => {record.phone_number || "-"},
+ sorter: (a, b) => a.status.length - b.status.length,
+ },
{
title: "Status",
dataIndex: "status",
- render: () => active,
+ render: (_, record) => (
+
+ {record.is_active ? "Active" : "Inactive"}
+
+ ),
+ sorter: (a, b) => a.status.length - b.status.length,
+ },
+ {
+ title: "Tax",
+ dataIndex: "tax",
+ render: (_, record) => (
+ {formatRupiah(record.tax_rate) || "-"}
+ ),
+ sorter: (a, b) => a.status.length - b.status.length,
+ },
+ {
+ title: "Currency",
+ dataIndex: "currency",
+ render: (_, record) => {record.currency || "-"},
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 },
+ })
+ }
>
@@ -222,7 +250,7 @@ const OutletList = () => {
cancelButtonText: "Cancel",
}).then((result) => {
if (result.isConfirmed) {
- handleDeleteCategory(record.id || record.key);
+ handleDeleteOutlet(record.id || record.key);
}
});
}}
@@ -234,8 +262,9 @@ const OutletList = () => {
),
},
];
+
const MySwal = withReactContent(Swal);
-
+
return (
@@ -243,8 +272,8 @@ const OutletList = () => {
-
Category
- Manage your categories
+ Outlet
+ Manage your outlets
@@ -298,17 +327,6 @@ const OutletList = () => {
-
-
-
- Add New Category
-
-
{/* /product list */}
@@ -348,7 +366,7 @@ const OutletList = () => {
Error: {error}
@@ -376,11 +394,11 @@ const OutletList = () => {
- {/* /category list */}
+ {/* /outlet list */}
-
+
);
};
diff --git a/src/feature-module/stock/managestock.jsx b/src/feature-module/stock/managestock.jsx
index 46fe0f3..389fc32 100644
--- a/src/feature-module/stock/managestock.jsx
+++ b/src/feature-module/stock/managestock.jsx
@@ -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 = () => {
-
- dispatch({
- type: INVENTORY_ACTIONS.FETCH_INVENTORY_SUCCESS,
- payload: { data: record },
- })
- }
- >
-
-
-
{
const {
@@ -149,73 +146,30 @@ const StockAdjustment = () => {
),
sorter: (a, b) => a.Quantity.length - b.Quantity.length,
},
-
- {
- title: "Action",
- dataIndex: "action",
- render: () => (
-
-
- |
- ),
- 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 (
-
+
+
+
+
Stock Adjusment
+ Adjust your stocks
+
+
+
+
{/* /product list */}
@@ -283,7 +237,7 @@ const StockAdjustment = () => {
{/* /product list */}
-
+
);
};
diff --git a/src/services/inventoriesApi.js b/src/services/inventoriesApi.js
index 03e1ea6..9df99c9 100644
--- a/src/services/inventoriesApi.js
+++ b/src/services/inventoriesApi.js
@@ -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));
diff --git a/src/services/outletsApi.js b/src/services/outletsApi.js
index c4c0cbf..9b2aedb 100644
--- a/src/services/outletsApi.js
+++ b/src/services/outletsApi.js
@@ -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`,
};