1import{h as S,r as y,s as p,j as e}from"./index-EB60i8_b.js";import{u as h}from"./useQuery-CD633ads.js";import{u as T}from"./useMutation-B66l_5Oh.js";import{t as B}from"./index-B1qPRzBi.js";import{a as F}from"./brand-picker-gate-CHqvg6gN.js";import{I as N}from"./input-D8MgPrVN.js";import{L as Q}from"./label-B_revbFK.js";import{T as D,a as E,b as x,c as m,d as I,e as i}from"./table-Be4Hp3L0.js";import{f as w}from"./finance-Cn4saD38.js";import"./brand-context-jy_uMzVx.js";import"./use-my-access-profile-eX8ffDWv.js";import"./auth-middleware-BXg-s9l0.js";import"./select-DhyoRdYW.js";import"./index-BdQq_4o_.js";import"./index-ix3cE_J2.js";import"./index--KVnfuxa.js";import"./index-Dl9hlz3A.js";import"./index-BuMx1jGY.js";import"./chevron-down-BpeL8prt.js";import"./check-BfMNAkIe.js";import"./chevron-up-WDwjygZr.js";import"./button-vMBgSq5N.js";import"./index-DPrYYZ34.js";import"./index-CJtd0Bml.js";import"./checkbox-B1zH9sEA.js";import"./globe-IlyhFCCI.js";import"./chevrons-up-down-C8DCFmP4.js";function L(s){return new Date(s.getFullYear(),s.getMonth(),1).toISOString().slice(0,10)}function C(s){return new Date(s.getFullYear(),s.getMonth()+1,0).toISOString().slice(0,10)}function me(){const{brandId:s,picker:g}=F(),v=S(),[b,q]=y.useState(()=>L(new Date).slice(0,7)),d=b+"-01",u=h({queryKey:["coa_budget",s],enabled:!!s,queryFn:async()=>{const{data:t,error:n}=await p.from("erp_chart_accounts").select("id, code, name, account_type").eq("brand_id",s).eq("is_archived",!1).in("account_type",["expense","income"]).order("code");if(n)throw n;return t??[]}}),f=h({queryKey:["budgets",s,d],enabled:!!s,queryFn:async()=>{const{data:t,error:n}=await p.from("erp_budgets").select("id, account_id, month, amount").eq("brand_id",s).eq("month",d);if(n)throw n;return t??[]}}),j=h({queryKey:["budget_actuals",s,d],enabled:!!s,queryFn:async()=>{const t=d,n=C(new Date(d)),{data:a,error:r}=await p.from("erp_journal_lines").select("account_id, debit, credit, erp_journal_entries!inner(brand_id, entry_date, status)").eq("brand_id",s).gte("erp_journal_entries.entry_date",t).lte("erp_journal_entries.entry_date",n).eq("erp_journal_entries.status","posted").limit(1e4);if(r)throw r;const o=new Map;return(a??[]).forEach(c=>{const l=(o.get(c.account_id)??0)+Number(c.debit)-Number(c.credit);o.set(c.account_id,l)}),Array.from(o.entries()).map(([c,l])=>({account_id:c,total:l}))}}),M=T({mutationFn:async({account_id:t,amount:n})=>{const a={brand_id:s,account_id:t,month:d,amount:n},{error:r}=await p.from("erp_budgets").upsert(a,{onConflict:"brand_id,account_id,month"});if(r)throw r},onSuccess:()=>v.invalidateQueries({queryKey:["budgets"]}),onError:t=>B.error(t.message)}),_=y.useMemo(()=>{const t=new Map((f.data??[]).map(a=>[a.account_id,Number(a.amount)])),n=new Map((j.data??[]).map(a=>[a.account_id,Number(a.total)]));return(u.data??[]).map(a=>{const r=t.get(a.id)??0,o=n.get(a.id)??0,c=a.account_type==="income"?-o:o,l=r>0?Math.round(c/r*100):0;return{...a,budget:r,actual:c,pct:l}})},[u.data,f.data,j.data]);return e.jsxs("div",{className:"p-4 md:p-6 space-y-4",children:[g&&e.jsx("div",{className:"flex justify-end -mb-1",children:g}),e.jsxs("header",{className:"flex flex-wrap justify-between items-end gap-3",children:[e.jsxs("div",{children:[e.jsx("h1",{className:"text-2xl font-bold tracking-tight",children:"Budgets"}),e.jsx("p",{className:"text-sm text-muted-foreground",children:"Monthly budget vs actual per account."})]}),e.jsxs("div",{className:"min-w-[180px]",children:[e.jsx(Q,{className:"text-xs",children:"Month"}),e.jsx(N,{type:"month",value:b,onChange:t=>q(t.target.value)})]})]}),e.jsx("div",{className:"rounded-md border bg-card",children:e.jsxs(D,{children:[e.jsx(E,{children:e.jsxs(x,{children:[e.jsx(m,{children:"Account"}),e.jsx(m,{children:"Type"}),e.jsx(m,{className:"text-right",children:"Budget"}),e.jsx(m,{className:"text-right",children:"Actual"}),e.jsx(m,{className:"text-right",children:"Used"}),e.jsx(m,{className:"text-right",children:"Variance"})]})}),e.jsxs(I,{children:[u.isLoading&&e.jsx(x,{children:e.jsx(i,{colSpan:6,className:"text-center py-8 text-muted-foreground",children:"Loadingâ¦"})}),!u.isLoading&&_.length===0&&e.jsx(x,{children:e.jsx(i,{colSpan:6,className:"text-center py-8 text-muted-foreground",children:"No income/expense accounts."})}),_.map(t=>{const n=t.budget-t.actual,a=t.budget>0&&t.actual>t.budget;return e.jsxs(x,{children:[e.jsx(i,{children:e.jsxs("div",{className:"font-medium text-sm",children:[t.code," · ",t.name]})}),e.jsx(i,{children:e.jsx("span",{className:"text-xs text-muted-foreground capitalize",children:t.account_type})}),e.jsx(i,{className:"text-right",children:e.jsx(N,{type:"number",step:"0.01",className:"h-8 text-right font-mono w-32 ml-auto",defaultValue:t.budget||"",onBlur:r=>{const o=Number(r.target.value)||0;o!==t.budget&&M.mutate({account_id:t.id,amount:o})}})}),e.jsx(i,{className:"text-right font-mono",children:w(t.actual)}),e.jsx(i,{className:"text-right",children:t.budget>0?e.jsxs("div",{className:"flex items-center justify-end gap-2",children:[e.jsx("div",{className:"w-20 h-1.5 bg-muted rounded-full overflow-hidden",children:e.jsx("div",{className:`h-full ${a?"bg-red-500":t.pct>80?"bg-amber-500":"bg-emerald-500"}`,style:{width:`${Math.min(100,t.pct)}%`}})}),e.jsxs("span",{className:`text-xs font-mono ${a?"text-red-600 font-semibold":""}`,children:[t.pct,"%"]})]}):e.jsx("span",{className:"text-xs text-muted-foreground",children:"â"})}),e.jsx(i,{className:`text-right font-mono ${n<0?"text-red-600":"text-emerald-600"}`,children:t.budget>0?w(n):"â"})]},t.id)})]})]})})]})}export{me as component};
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.