| @@ -135,26 +135,55 @@ export default function M18SynPage() { | |||||
| } | } | ||||
| }; | }; | ||||
| /** 送貨訂單:手動按 code 同步(可輸入多個 code,用逗號或換行分隔) */ | |||||
| const handleSyncM18DoByCode = async () => { | const handleSyncM18DoByCode = async () => { | ||||
| if (m18DoInFlightRef.current) return; | if (m18DoInFlightRef.current) return; | ||||
| if (!m18DoCode.trim()) { | |||||
| alert("Please enter DO / shop PO code."); | |||||
| const raw = m18DoCode.trim(); | |||||
| if (!raw) { | |||||
| alert("Please enter DO / shop PO code(s)."); | |||||
| return; | |||||
| } | |||||
| const codes = raw | |||||
| .split(/[\n,]+/g) | |||||
| .map((s) => s.trim()) | |||||
| .filter(Boolean); | |||||
| if (codes.length === 0) { | |||||
| alert("Please enter at least one code."); | |||||
| return; | return; | ||||
| } | } | ||||
| m18DoInFlightRef.current = true; | m18DoInFlightRef.current = true; | ||||
| setIsSyncingM18Do(true); | setIsSyncingM18Do(true); | ||||
| setM18DoSyncResult(""); | setM18DoSyncResult(""); | ||||
| try { | try { | ||||
| const response = await clientAuthFetch( | |||||
| `${NEXT_PUBLIC_API_URL}/m18/test/do-by-code?code=${encodeURIComponent(m18DoCode.trim())}`, | |||||
| { method: "GET" }, | |||||
| ); | |||||
| if (response.status === 401 || response.status === 403) return; | |||||
| const text = await response.text(); | |||||
| setM18DoSyncResult(formatSyncResultText("送貨訂單", text)); | |||||
| if (!response.ok) { | |||||
| alert(`Sync failed: ${response.status}`); | |||||
| const outputs: string[] = []; | |||||
| const okCodes: string[] = []; | |||||
| const notFoundCodes: string[] = []; | |||||
| const otherFailCodes: string[] = []; | |||||
| for (const code of codes) { | |||||
| const response = await clientAuthFetch( | |||||
| `${NEXT_PUBLIC_API_URL}/m18/test/do-by-code?code=${encodeURIComponent(code)}`, | |||||
| { method: "GET" }, | |||||
| ); | |||||
| if (response.status === 401 || response.status === 403) return; | |||||
| const text = await response.text(); | |||||
| const parsed = parseSyncResult("送貨訂單", text || ""); | |||||
| if (parsed.kind === "success") okCodes.push(code); | |||||
| else if (parsed.kind === "not_found") notFoundCodes.push(code); | |||||
| else otherFailCodes.push(code); | |||||
| const perCodeMsg = | |||||
| parsed.kind === "success" ? "成功同步" : | |||||
| parsed.kind === "not_found" ? parsed.message : | |||||
| parsed.message; | |||||
| outputs.push(`${code}: ${perCodeMsg}${response.ok ? "" : ` (HTTP ${response.status})`}`); | |||||
| } | } | ||||
| outputs.push(""); | |||||
| outputs.push(`共${okCodes.length}張送貨訂單成功`); | |||||
| if (notFoundCodes.length > 0) outputs.push(`共${notFoundCodes.length}張在M18找不到訂單 (${notFoundCodes.join(", ")})`); | |||||
| if (otherFailCodes.length > 0) outputs.push(`共${otherFailCodes.length}張同步失敗 (${otherFailCodes.join(", ")})`); | |||||
| setM18DoSyncResult(outputs.join("\n")); | |||||
| } catch (e) { | } catch (e) { | ||||
| console.error("M18 DO Sync By Code Error:", e); | console.error("M18 DO Sync By Code Error:", e); | ||||
| alert("M18 DO sync failed. Check console/network."); | alert("M18 DO sync failed. Check console/network."); | ||||
| @@ -312,18 +341,22 @@ export default function M18SynPage() { | |||||
| <TabPanel value={tabValue} index={1}> | <TabPanel value={tabValue} index={1}> | ||||
| <Section title="M18 送貨訂單 — sync by code"> | <Section title="M18 送貨訂單 — sync by code"> | ||||
| <Stack direction="row" spacing={2} sx={{ mb: 2, alignItems: "center" }}> | |||||
| <Stack spacing={2} sx={{ mb: 2 }}> | |||||
| <TextField | <TextField | ||||
| size="small" | |||||
| label="DO / Shop PO Code" | label="DO / Shop PO Code" | ||||
| value={m18DoCode} | value={m18DoCode} | ||||
| onChange={(e) => setM18DoCode(e.target.value)} | onChange={(e) => setM18DoCode(e.target.value)} | ||||
| placeholder="e.g. same document code as M18 shop PO" | |||||
| sx={{ minWidth: 320 }} | |||||
| placeholder="可輸入多個 code,用逗號或換行分隔" | |||||
| fullWidth | |||||
| multiline | |||||
| minRows={6} | |||||
| maxRows={14} | |||||
| /> | /> | ||||
| <Button variant="contained" color="primary" onClick={handleSyncM18DoByCode} disabled={isSyncingM18Do}> | |||||
| {isSyncingM18Do ? "Syncing..." : "Sync DO from M18"} | |||||
| </Button> | |||||
| <Box sx={{ display: "flex", justifyContent: "flex-end" }}> | |||||
| <Button variant="contained" color="primary" onClick={handleSyncM18DoByCode} disabled={isSyncingM18Do}> | |||||
| {isSyncingM18Do ? "Syncing..." : "Sync DO from M18"} | |||||
| </Button> | |||||
| </Box> | |||||
| </Stack> | </Stack> | ||||
| {m18DoSyncResult ? ( | {m18DoSyncResult ? ( | ||||
| <TextField | <TextField | ||||