diff --git a/frontend/src/components/logistics/dm/DMButtons.tsx b/frontend/src/components/logistics/dm/DMButtons.tsx new file mode 100644 index 0000000..a7a95bd --- /dev/null +++ b/frontend/src/components/logistics/dm/DMButtons.tsx @@ -0,0 +1,80 @@ +import { + DropdownMenu, + DropdownMenuContent, + DropdownMenuItem, + DropdownMenuLabel, + DropdownMenuSeparator, + DropdownMenuTrigger, +} from "@/components/ui/dropdown-menu"; +import OrderImport from "./OrderImport"; +import StandardOrderTemplate from "./StandardOrderTemplate"; +import { Button } from "@/components/ui/button"; +import StandardForecastTemplate from "./StandardForecastTemplate"; +import ForecastImport from "./ForecastImport"; +import { useSettingStore } from "@/lib/store/useSettings"; + +export default function DMButtons() { + const { settings } = useSettingStore(); + + const plantToken = settings.filter((n) => n.name === "plantToken"); + console.log(plantToken); + return ( +
+
+ + + + + + + Standard templates and imports + + + + + + + + + + + + + + + + + +
+ {plantToken[0]?.value === "usday1" && ( +
+ + + + + + + Custom import templates + + + + + + + + + +
+ )} +
+ ); +} diff --git a/frontend/src/components/logistics/dm/ForecastImport.tsx b/frontend/src/components/logistics/dm/ForecastImport.tsx new file mode 100644 index 0000000..3b67bee --- /dev/null +++ b/frontend/src/components/logistics/dm/ForecastImport.tsx @@ -0,0 +1,66 @@ +import { Button } from "@/components/ui/button"; +import axios from "axios"; +import { useRef, useState } from "react"; +import { toast } from "sonner"; + +export default function ForecastImport(props: any) { + const fileInputRef: any = useRef(null); + const [posting, setPosting] = useState(false); + const token = localStorage.getItem("auth_token"); + //const [fileType, setFileType] = useState(""); + const importOrders = async (e: any) => { + const file = e.target.files[0]; + if (!file) { + toast.error("Missing file please try again"); + setPosting(false); + return; + } + + // create the form data with the correct fileType + const formData = new FormData(); + formData.append("postOrders", e.target.files[0]); + formData.append("fileType", props.fileType); // extra field + // console.log(formData); + + try { + const response = await axios.post( + "/api/logistics/postforecastin", + formData, + { + headers: { + "Content-Type": "multipart/form-data", + Authorization: `Bearer ${token}`, + }, + } + ); + console.log("Upload successful:", response.data); + toast.success( + "File Uploaded, please validate processing in alplaprod 2.0" + ); + setPosting(false); + } catch (error) { + console.log(error); + toast.error("Upload failed"); + } + setPosting(false); + }; + + const handleButtonClick = () => { + setPosting(true); + fileInputRef.current.click(); + }; + return ( +
+ + +
+ ); +} diff --git a/frontend/src/components/logistics/dm/OrderImport.tsx b/frontend/src/components/logistics/dm/OrderImport.tsx new file mode 100644 index 0000000..b092dfe --- /dev/null +++ b/frontend/src/components/logistics/dm/OrderImport.tsx @@ -0,0 +1,66 @@ +import { Button } from "@/components/ui/button"; +import axios from "axios"; +import { useRef, useState } from "react"; +import { toast } from "sonner"; + +export default function OrderImport(props: any) { + const fileInputRef: any = useRef(null); + const [posting, setPosting] = useState(false); + const token = localStorage.getItem("auth_token"); + //const [fileType, setFileType] = useState(""); + const importOrders = async (e: any) => { + const file = e.target.files[0]; + if (!file) { + toast.error("Missing file please try again"); + setPosting(false); + return; + } + + // create the form data with the correct fileType + const formData = new FormData(); + formData.append("postOrders", e.target.files[0]); + formData.append("fileType", props.fileType); // extra field + // console.log(formData); + + try { + const response = await axios.post( + "/api/logistics/postbulkorders", + formData, + { + headers: { + "Content-Type": "multipart/form-data", + Authorization: `Bearer ${token}`, + }, + } + ); + console.log("Upload successful:", response.data); + toast.success( + "File Uploaded, please validate processing in alplaprod 2.0" + ); + setPosting(false); + } catch (error) { + console.log(error); + toast.error("Upload failed"); + } + setPosting(false); + }; + + const handleButtonClick = () => { + setPosting(true); + fileInputRef.current.click(); + }; + return ( +
+ + +
+ ); +} diff --git a/frontend/src/components/logistics/dm/StandardForecastTemplate.tsx b/frontend/src/components/logistics/dm/StandardForecastTemplate.tsx new file mode 100644 index 0000000..8e45fbb --- /dev/null +++ b/frontend/src/components/logistics/dm/StandardForecastTemplate.tsx @@ -0,0 +1,41 @@ +import { Button } from "@/components/ui/button"; +import axios from "axios"; +import { format } from "date-fns"; +import { useState } from "react"; +import { toast } from "sonner"; + +export default function StandardForecastTemplate() { + const [template, setTemplate] = useState(false); + const getTemplate = async () => { + setTemplate(true); + try { + const res = await axios.get(`/api/logistics/bulkforcasttemplate`, { + responseType: "blob", + }); + + const blob = new Blob([res.data], { + type: "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet", + }); + + const link = document.createElement("a"); + link.href = window.URL.createObjectURL(blob); + link.download = `ForecastTemplate-${format(new Date(Date.now()), "M-d-yyyy")}.xlsx`; // You can make this dynamic + document.body.appendChild(link); + link.click(); + + // Clean up + document.body.removeChild(link); + window.URL.revokeObjectURL(link.href); + toast.success(`Forecast template`); + setTemplate(false); + } catch (error) { + setTemplate(false); + toast.error("There was an error getting the template"); + } + }; + return ( + + ); +} diff --git a/frontend/src/components/logistics/dm/StandardOrderTemplate.tsx b/frontend/src/components/logistics/dm/StandardOrderTemplate.tsx new file mode 100644 index 0000000..5ba8f2a --- /dev/null +++ b/frontend/src/components/logistics/dm/StandardOrderTemplate.tsx @@ -0,0 +1,41 @@ +import { Button } from "@/components/ui/button"; +import axios from "axios"; +import { format } from "date-fns"; +import { useState } from "react"; +import { toast } from "sonner"; + +export default function StandardOrderTemplate() { + const [template, setTemplate] = useState(false); + const getTemplate = async () => { + setTemplate(true); + try { + const res = await axios.get(`/api/logistics/bulkorderstemplate`, { + responseType: "blob", + }); + + const blob = new Blob([res.data], { + type: "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet", + }); + + const link = document.createElement("a"); + link.href = window.URL.createObjectURL(blob); + link.download = `BulkOrderTemplate-${format(new Date(Date.now()), "M-d-yyyy")}.xlsx`; // You can make this dynamic + document.body.appendChild(link); + link.click(); + + // Clean up + document.body.removeChild(link); + window.URL.revokeObjectURL(link.href); + toast.success(`Bulk Order template`); + setTemplate(false); + } catch (error) { + setTemplate(false); + toast.error("There was an error getting the tempalte"); + } + }; + return ( + + ); +} diff --git a/frontend/src/components/logistics/dm/dmPage.tsx b/frontend/src/components/logistics/dm/dmPage.tsx new file mode 100644 index 0000000..9129530 --- /dev/null +++ b/frontend/src/components/logistics/dm/dmPage.tsx @@ -0,0 +1,129 @@ +import { LstCard } from "@/components/extendedUI/LstCard"; +import { Separator } from "@/components/ui/separator"; + +export default function DmPage() { + return ( +
+ +
+

+ Simple instructions for creating/updating orders +

+ +
+ + + + +
+

+ Some notes to consider +

+
    +
  • + No longer need to add in the invoice id, we take the + default one. +
  • +
  • + You can have as many customers you want in the file + and in any order. +
  • +
  • + Orders created Manually, can not be updated with + this process. +
  • +
  • + If you desire you can send up to 1000 orders at one + time... or more.... +
  • +
  • + Customer mappings can be added, this means that you + can upload your customer file and it will parse + onces mapped, you need to request this. +
  • +
  • + Custom imports will be at the top right under + custom, here you will just upload the customer file + once mapped. +
  • +
+
+ +

Example order

+
+ orders in example +
+
+ +
+

+ Simple instructions for creating forecast +

+ +
+
+
    +
  • + Download the template if you have not yet done so. +
  • +
  • + Add in the forecast like you see in the example + below. +
  • + +
  • + Once you have all the forecast enters click the + upload button on the top right +
  • +
+
+ +
+

+ Some notes to consider. +

+
    +
  • You can only use one customer at a time.
  • + +
  • + If you desire you can send up to 1000 orders at one + time... +
  • +
+
+ +

+ Example forecast +

+
+ orders in example +
+
+
+ ); +} diff --git a/frontend/src/routes/(logistics)/dm/index.tsx b/frontend/src/routes/(logistics)/dm/index.tsx index 4a02caf..4234de0 100644 --- a/frontend/src/routes/(logistics)/dm/index.tsx +++ b/frontend/src/routes/(logistics)/dm/index.tsx @@ -1,3 +1,4 @@ +import DmPage from "@/components/logistics/dm/dmPage"; import { createFileRoute, redirect } from "@tanstack/react-router"; export const Route = createFileRoute("/(logistics)/dm/")({ @@ -19,5 +20,9 @@ export const Route = createFileRoute("/(logistics)/dm/")({ }); function RouteComponent() { - return
Hello "/(logistics)/dm/"!
; + return ( +
+ +
+ ); } diff --git a/frontend/src/routes/__root.tsx b/frontend/src/routes/__root.tsx index 21d6ff8..8b4eb68 100644 --- a/frontend/src/routes/__root.tsx +++ b/frontend/src/routes/__root.tsx @@ -27,6 +27,7 @@ import { useSession } from "@/hooks/useSession"; import { useLogout } from "@/hooks/useLogout"; import ExportInventoryData from "@/components/logistics/warehouse/ExportInventoryData"; import { AddCards } from "@/components/dashboard/AddCards"; +import DMButtons from "@/components/logistics/dm/DMButtons"; //import { AddCards } from "@/components/dashboard/AddCards"; // same as the layout @@ -44,12 +45,19 @@ export const Route = createRootRoute({