PageSourceSearch

https://bomber-admin.web.app/assets/ErpInventory-Dit5u6Zm.js

js bomber-admin.web.app collected 2026-10-03 12:19:11 UTC 8,513 bytes, 1 lines download raw bytes

1import{r as l,j as e}from"./vendor-react-Cx3Bz6gM.js";import{q as L,h as Q,w as A,j as B,S as D,t as M,v as S}from"./vendor-firebase-CGQGHW05.js";import{u as P,g as R,o as T,p as I,d as C,a as E}from"./main-BR99q4qQ.js";import{E as k,a as $,b as F}from"./auditLog-3WtQT3Vp.js";const p=s=>(Number(s)||0).toLocaleString();function _(){const{profile:s}=P(),{company:o}=R(),[c,v]=l.useState([]),[h,g]=l.useState(!0),[m,b]=l.useState(null),[d,j]=l.useState(""),[u,i]=l.useState(""),[f,r]=l.useState(null),a=async()=>{g(!0),b(null);try{const t=L(Q(C,k.Inventory),A("company","==",o.key)),n=await B(t);v(n.docs.map(x=>({id:x.id,...x.data()})))}catch(t){console.error(t),b((t==null?void 0:t.message)||"データ取得に失敗しました")}finally{g(!1)}};l.useEffect(()=>{a()},[o.key]);const N=l.useMemo(()=>[...new Set(c.map(t=>t.warehouseId).filter(Boolean))].sort(),[c]),y=l.useMemo(()=>{let t=c;if(d&&(t=t.filter(n=>n.warehouseId===d)),u){const n=u.toLowerCase();t=t.filter(x=>(x.productId||"").toLowerCase().includes(n)||(x.lotNumber||"").toLowerCase().includes(n))}return t.sort((n,x)=>(n.productId||"").localeCompare(x.productId||""))},[c,d,u]),w=T(s),q=I(s);return w?e.jsxs("div",{className:"mx-auto max-w-7xl space-y-5",children:[e.jsxs("div",{className:"flex flex-wrap items-center justify-between gap-3",children:[e.jsxs("div",{children:[e.jsx("h1",{className:"text-xl font-bold text-gray-900",children:"在庫(ERP)"}),e.jsxs("p",{className:"text-xs text-gray-500",children:[o.name,"(",o.key,")— ",y.length," 件 / 全 ",c.length," 件"]})]}),e.jsx("button",{onClick:a,className:"rounded-lg border border-gray-300 bg-white px-3 py-1.5 text-xs text-gray-700 hover:bg-gray-50",children:"🔄 再取得"})]}),e.jsx("div",{className:"rounded-xl border border-amber-200 bg-amber-50 p-3 text-xs text-amber-900",children:"⚠️ 在庫の手動調整は楽観ロック未実装(Phase 2 で transaction 化予定)。 複数ユーザーが同時に同じロットを調整すると、最後の書き込みが勝ちます。 通常は入庫・出荷画面経由で自動更新されます。"}),e.jsx("div",{className:"rounded-2xl border border-gray-200 bg-white p-4",children:e.jsxs("div",{className:"flex flex-wrap items-center gap-3",children:[e.jsxs("select",{value:d,onChange:t=>j(t.target.value),className:"rounded-lg border border-gray-300 px-3 py-2 text-sm",children:[e.jsx("option",{value:"",children:"全倉庫"}),N.map(t=>e.jsx("option",{value:t,children:t},t))]}),e.jsx("input",{value:u,onChange:t=>i(t.target.value),placeholder:"商品ID / ロット番号で検索",className:"flex-1 min-w-[200px] rounded-lg border border-gray-300 px-3 py-2 text-sm"})]})}),m&&e.jsx("div",{className:"rounded-xl border border-red-300 bg-red-50 p-4 text-sm text-red-800",children:m}),h?e.jsx("div",{className:"py-20 text-center text-sm text-gray-400",children:"読み込み中..."}):y.length===0?e.jsx("div",{className:"rounded-xl border border-dashed border-gray-300 bg-white py-12 text-center text-sm text-gray-400",children:"在庫データがありません"}):e.jsx("div",{className:"overflow-hidden rounded-2xl border border-gray-200 bg-white",children:e.jsx("div",{className:"overflow-x-auto",children:e.jsxs("table",{className:"min-w-full text-sm",children:[e.jsx("thead",{className:"bg-gray-50 text-xs text-gray-500",children:e.jsxs("tr",{children:[e.jsx("th",{className:"px-3 py-2 text-left",children:"商品ID"}),e.jsx("th",{className:"px-3 py-2 text-left",children:"ロット"}),e.jsx("th",{className:"px-3 py-2 text-left",children:"倉庫"}),e.jsx("th",{className:"px-3 py-2 text-right",children:"在庫数"}),e.jsx("th",{className:"px-3 py-2 text-right",children:"引当中"}),e.jsx("th",{className:"px-3 py-2 text-right",children:"利用可能"}),e.jsx("th",{className:"px-3 py-2"})]})}),e.jsx("tbody",{className:"divide-y divide-gray-100",children:y.map(t=>{const n=(t.qty||0)-(t.reservedQty||0);return e.jsxs("tr",{className:"hover:bg-gray-50",children:[e.jsx("td",{className:"px-3 py-2 font-mono text-xs",children:t.productId}),e.jsx("td",{className:"px-3 py-2 text-xs text-gray-500",children:t.lotNumber||"—"}),e.jsx("td",{className:"px-3 py-2",children:t.warehouseId}),e.jsx("td",{className:"px-3 py-2 text-right font-medium",children:p(t.qty)}),e.jsx("td",{className:"px-3 py-2 text-right text-gray-500",children:p(t.reservedQty)}),e.jsx("td",{className:`px-3 py-2 text-right font-medium ${n<0?"text-red-600":"text-emerald-700"}`,children:p(n)}),e.jsx("td",{className:"px-3 py-2 text-right",children:q?e.jsx("button",{onClick:()=>r(t),className:"text-xs text-indigo-600 hover:underline",children:"調整"}):e.jsx("span",{className:"text-xs text-gray-300",children:"—"})})]},t.id)})})]})})}),f&&e.jsx(K,{inv:f,profile:s,onClose:()=>r(null),onSaved:()=>{r(null),a()}})]}):e.jsx("div",{className:"mx-auto max-w-3xl rounded-xl border border-amber-300 bg-amber-50 p-6 text-sm text-amber-900",children:"この画面は admin / internal 権限のみ閲覧できます。"})}function K({inv:s,profile:o,onClose:c,onSaved:v}){const[h,g]=l.useState(""),[m,b]=l.useState(""),[d,j]=l.useState(!1);l.useEffect(()=>{if(!d)return;const r=a=>{a.key==="Escape"&&a.stopPropagation()};return window.addEventListener("keydown",r,!0),()=>window.removeEventListener("keydown",r,!0)},[d]);const u=()=>{d||c()},i=(Number(s.qty)||0)+(Number(h)||0),f=async()=>
1{if(d)return;try{E(I,o,{userMessage:"在庫調整権限がありません"})}catch(a){alert(a.message);return}const r=Number(h);if(!Number.isFinite(r)||r===0){alert("増減数(非ゼロ)を入力してください");return}if(i<0){alert("調整後の在庫数が負になります");return}if(!m.trim()){alert("調整理由は必須です");return}j(!0);try{E(I,o,{userMessage:"在庫調整権限がありません"});const a=D(C),N=M(C,k.Inventory,s.id),y={qty:s.qty||0,reservedQty:s.reservedQty||0,version:s.version||1},w={qty:i,availableQty:i-(s.reservedQty||0),lastMovementAt:S(),updatedAt:S(),updatedBy:o.uid,version:(s.version||1)+1};a.update(N,w),$(a,{collection:k.Inventory,docId:s.id,action:"update",before:y,after:{qty:i,reservedQty:s.reservedQty||0,version:(s.version||1)+1},profile:o,reason:`手動調整 (${r>=0?"+":""}${r}): ${m.trim()}`}),await a.commit(),v()}catch(a){console.error(a),alert(F(a))}finally{j(!1)}};return e.jsx("div",{className:"fixed inset-0 z-50 flex items-center justify-center bg-black/40 p-4",onClick:u,children:e.jsxs("div",{onClick:r=>r.stopPropagation(),className:"w-full max-w-md rounded-2xl bg-white p-6 shadow-xl",children:[e.jsxs("div",{className:"mb-4 flex items-center justify-between",children:[e.jsx("h2",{className:"text-lg font-bold text-gray-900",children:"在庫調整"}),e.jsx("button",{onClick:c,disabled:d,className:"text-gray-400 hover:text-gray-600 disabled:opacity-40",children:"✕"})]}),e.jsxs("div",{className:"space-y-3 text-sm",children:[e.jsxs("div",{className:"rounded-lg bg-gray-50 p-3 text-xs",children:[e.jsxs("div",{children:["商品ID: ",e.jsx("span",{className:"font-mono",children:s.productId})]}),e.jsxs("div",{children:["ロット: ",s.lotNumber||"—"]}),e.jsxs("div",{children:["倉庫: ",s.warehouseId]}),e.jsxs("div",{children:["現在庫数: ",e.jsx("span",{className:"font-bold",children:p(s.qty)})]})]}),e.jsxs("div",{children:[e.jsx("label",{className:"text-xs font-medium text-gray-700",children:"増減数(+/- 可)"}),e.jsx("input",{type:"number",value:h,onChange:r=>g(r.target.value),placeholder:"例: -10 または 5",className:"mt-1 w-full rounded-lg border border-gray-300 px-3 py-2 text-sm"}),e.jsxs("div",{className:"mt-1 text-xs text-gray-500",children:["調整後 → ",e.jsx("span",{className:i<0?"text-red-600":"font-medium text-emerald-700",children:p(i)})]})]}),e.jsxs("div",{children:[e.jsx("label",{className:"text-xs font-medium text-gray-700",children:"調整理由 *(必須)"}),e.jsx("textarea",{value:m,onChange:r=>b(r.target.value),rows:2,placeholder:"例: 棚卸差異、破損、ロス調整",className:"mt-1 w-full rounded-lg border border-gray-300 px-3 py-2 text-sm"})]})]}),e.jsxs("div",{className:"mt-6 flex justify-end gap-2",children:[e.jsx("button",{onClick:c,disabled:d,className:"rounded-lg border border-gray-300 px-4 py-2 text-sm text-gray-700 hover:bg-gray-50",children:"キャンセル"}),e.jsx("button",{onClick:f,disabled:d,className:"rounded-lg bg-indigo-600 px-4 py-2 text-sm font-medium text-white hover:bg-indigo-700 disabled:opacity-50",children:d?"保存中...":"調整を保存"})]})]})})}export{_ as default};

Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.