PageSourceSearch

https://tire-track-loyalty-3a0d7f0a.base44.app/assets/ShopEditOrderSheet-BnPXGGUo.js

js tire-track-loyalty-3a0d7f0a.base44.app collected 2026-10-03 03:13:37 UTC 17,521 bytes, 1 lines download raw bytes

1import{r as l,b as se,t as h,j as e}from"./index-DdU35jPJ.js";import{S as Ne,a as fe,b as ye,c as ve,d as je}from"./sheet-BXj4TthU.js";import{B as re}from"./button-BfxMpK8P.js";import{I as M}from"./input-cpzcpc5y.js";import{L as b}from"./label-Bnj3FxlL.js";import{S as we,a as $e,b as qe}from"./ShopOrderSummary-X5_sHyOt.js";import{P as ie}from"./pencil-BFgvU9po.js";import{L as ae}from"./loader-circle-B5Ydjp3O.js";import{L as Se}from"./lock-Brnc1X-D.js";import{T as Fe}from"./trash-2-Bi9M4bD6.js";import{T as ne}from"./triangle-alert-l3tEQyle.js";import{P as Me}from"./plus-Bux0BJlB.js";import{P as Te}from"./percent-D18g7D9L.js";import{C as ke}from"./credit-card-BsmBHB--.js";import"./index-BhZ8ej-y.js";import"./index-12QbP6l0.js";import"./index-gN4drEn4.js";import"./index-BsvT06Lq.js";import"./index-9bdZCgcr.js";import"./index-BvvUEucZ.js";import"./index-Bwgqm7vL.js";import"./index-Dp3B9jqt.js";import"./clsx-B-dksMZM.js";import"./utils-DCmAa5as.js";import"./bundle-mjs-BTmSotT-.js";import"./x-DAruoHhn.js";import"./createLucideIcon-DMxicyrC.js";import"./wrench-B9LFfIyi.js";import"./package-DYJogmeO.js";import"./trending-up-D6tLkDJM.js";function lt({open:E,onClose:u,order:g,items:T,actAsCustomerId:D,onSuccess:j}){const[p,B]=l.useState(null),[oe,z]=l.useState(!1),[w,k]=l.useState([]),[$,J]=l.useState([]),[q,H]=l.useState([]),[N,K]=l.useState(!1),[S,U]=l.useState(8.25),[f,V]=l.useState(!1),[F,W]=l.useState(3),[P,X]=l.useState(""),[Q,Y]=l.useState(!1),[Z,le]=l.useState(1),[ce,de]=l.useState("");l.useEffect(()=>{if(!E||!(g!=null&&g.id)){B(null);return}let s=!0;return z(!0),se.entities.ShopCustomerOrder.get(g.id).then(t=>{if(!(!s||!t)){if(t.fulfillment_source==="truck_haters"){h.error("Fulfilled by Truck Haters orders cannot use the Shop Inventory editor."),B(null),u==null||u();return}B(t),le(Number(t.order_revision)||1),de(`edit-${t.id}-${Date.now()}-${Math.random().toString(36).substring(2,8)}`),k((t.items||[]).map((a,_)=>({shop_inventory_item_id:a.shop_inventory_item_id,quantity:Number(a.quantity)||0,selling_price_per_tire:Number(a.selling_price_per_tire)||0,_existing:!0,_lineIndex:_,_label:`${a.brand||""} ${a.model?a.model+" ":""}${a.size||""} ${a.position||""}`.trim(),_origQuantity:Number(a.quantity)||0,_origPrice:Number(a.selling_price_per_tire)||0,_origCostBasis:Number(a.frozen_cost_basis)||0}))),J((t.services||[]).map(a=>({service_type:a.service_type||"other",description:a.description||"",quantity:Number(a.quantity)||1,price_per_unit:Number(a.price_per_unit)||0,cost_per_unit:Number(a.cost_per_unit)||0,total_price:Number(a.total_price)||0}))),H((t.parts||[]).map(a=>({description:a.description||"",quantity:Number(a.quantity)||1,selling_price_per_unit:Number(a.selling_price_per_unit)||0,cost_per_unit:Number(a.cost_per_unit)||0,total_price:Number(a.total_price)||0}))),K(!!t.sales_tax_applied),U(Number(t.sales_tax_percent)||8.25),V((Number(t.transaction_fee_percent)||0)>0),W(Number(t.transaction_fee_percent)||3),X(t.notes||"")}}).catch(()=>h.error("Failed to load the latest order version")).finally(()=>{s&&z(!1)}),()=>{s=!1}},[E,g==null?void 0:g.id]);const ee=l.useMemo(()=>(T||[]).filter(s=>Number(s.quantity_on_hand)>0),[T]),L=l.useMemo(()=>{const s=new Map;for(const t of T||[])s.set(t.id,t);return s},[T]),A=(s,t,a)=>{k(_=>_.map((d,m)=>{if(m!==s)return d;const i={...d,[t]:a};if(t==="shop_inventory_item_id"){const r=ee.find(o=>o.id===a);r&&(i.selling_price_per_tire=Math.round((Number(r.average_cost)||0)*1.3*100)/100,i.quantity=1,i._label=`${r.brand||""} ${r.model?r.model+" ":""}${r.size||""} ${r.position||""}`.trim(),i._origQuantity=0,i._origPrice=0,i._origCostBasis=Number(r.average_cost)||0)}if(t==="quantity"){let r=parseInt(a,10);(isNaN(r)||r<1)&&(r=1);const o=L.get(d.shop_inventory_item_id);if(o){const x=(d._existing?d._origQuantity:0)+(Number(o.quantity_on_hand)||0);r>x&&(r=x,h.warning(`Only ${x} possible — ${Number(o.quantity_on_hand)} in stock plus this order's units`,{id:`clamp-${s}`}))}i.quantity=r}return i}))},me=()=>k(s=>[...s,{shop_inventory_item_id:"",quantity:1,selling_price_per_tire:0,_existing:!1}]),ue=s=>k(t=>t.filter((a,_)=>_!==s)),v=l.useMemo(()=>{let s=0,t=0,a=0;for(const n of w){if(!n.shop_inventory_item_id)continue;const I=Number(n.quantity)||0,_e=Number(n.selling_price_per_tire)||0,xe=n._existing&&Number(n._origQuantity)||0,te=Math.max(0,I-xe),R=L.get(n.shop_inventory_item_id),he=n._existing&&Number(n._origCostBasis)||0,be=Number(R==null?void 0:R.average_cost)||0,ge=(I-te)*he+te*be;s+=_e*I,t+=ge,a+=I}let _=0,d=0;for(const n of $)_+=Number(n.total_price)||0,d+=(Number(n.cost_per_unit)||0)*(Number(n.quantity)||0);let m=0,i=0;for(const n of q)m+=(Number(n.selling_price_per_unit)||0)*(Number(n.quantity)||0),i+=(Number(n.cost_per_unit)||0)*(Number(n.quantity)||0);const r=Math.round((s+_+m)*100)/100,o=Math.round((t+d+i)*100)/100,x=Math.round((r-o
1)*100)/100,O=N?Math.round(r*(Number(S)||0))/100:0,G=f?Math.round(r*(Number(F)||0))/100:0,C=Math.round((r+O+G)*100)/100;return{tire_revenue:Math.round(s*100)/100,services_revenue:Math.round(_*100)/100,parts_revenue:Math.round(m*100)/100,total_revenue:r,total_cogs:o,total_gp:x,total_tires:a,tax_applied:N,sales_tax_amount:O,fee_applied:f,transaction_fee_amount:G,grand_total:C}},[w,$,q,N,S,f,F,L]),c=l.useMemo(()=>{if(!p)return null;let s=0,t=0;for(const r of w){const o=r._existing&&Number(r._origQuantity)||0,x=(Number(r.quantity)||0)-o;x>0&&(s+=x),x<0&&(t+=-x)}const a=Number(p.grand_total)||0,_=Number(p.total_gp)||0,d=Number(p.amount_paid)||0,m=Math.max(0,Math.round((v.grand_total-d)*100)/100),i=Math.max(0,Math.round((d-v.grand_total)*100)/100);return{additional:s,returned:t,oldGrand:a,newGrand:v.grand_total,oldGp:_,newGp:v.total_gp,oldBalance:Number(p.balance_due)||0,newBalance:m,amountPaid:d,overpayment:i}},[p,w,v]);l.useMemo(()=>{if(!p||!c)return!1;const s=c;return s.additional>0||s.returned>0||s.oldGrand!==s.newGrand||s.oldGp!==s.newGp||JSON.stringify($.map(t=>[t.service_type,t.description,t.quantity,t.price_per_unit,t.cost_per_unit]))!==JSON.stringify((p.services||[]).map(t=>[t.service_type,t.description,t.quantity,t.price_per_unit,t.cost_per_unit]))||JSON.stringify(q.map(t=>[t.description,t.quantity,t.selling_price_per_unit,t.cost_per_unit]))!==JSON.stringify((p.parts||[]).map(t=>[t.description,t.quantity,t.selling_price_per_unit,t.cost_per_unit]))||(p.notes||"").trim()!==P.trim()},[p,c,$,q,P]);const pe=async()=>{var d,m;if(!p)return;if(p.fulfillment_source==="truck_haters"){h.error("Fulfilled by Truck Haters orders cannot use the Shop Inventory editor."),u==null||u();return}const s=w.filter(i=>i.shop_inventory_item_id&&Number(i.quantity)>0),t=$.filter(i=>Number(i.quantity)>0&&Number(i.price_per_unit)>=0),a=q.filter(i=>(i.description||"").trim()&&Number(i.quantity)>0&&Number(i.selling_price_per_unit)>=0);if(s.length===0&&t.length===0&&a.length===0){h.error("Keep at least one tire, service, or part line");return}if(t.find(i=>i.service_type==="other"&&!(i.description||"").trim())){h.error('Add a description for the "Other" service line');return}Y(!0);try{const i=await se.functions.invoke("editShopCustomerOrder",{order_id:p.id,expected_revision:Z,idempotency_key:ce,edit:{items:s.map(o=>({shop_inventory_item_id:o.shop_inventory_item_id,quantity:Number(o.quantity),selling_price_per_tire:Number(o.selling_price_per_tire)})),services:t.map(o=>({service_type:o.service_type,description:(o.description||"").trim(),quantity:Number(o.quantity),price_per_unit:Number(o.price_per_unit),cost_per_unit:Number(o.cost_per_unit)||0})),parts:a.map(o=>({description:(o.description||"").trim(),quantity:Number(o.quantity),selling_price_per_unit:Number(o.selling_price_per_unit),cost_per_unit:Number(o.cost_per_unit)||0})),sales_tax_applied:N,sales_tax_percent:Number(S),transaction_fee_applied:f,transaction_fee_percent:Number(F),notes:P.trim()},...D?{act_as_customer_id:D}:{}}),r=(i==null?void 0:i.data)??i;if(r!=null&&r.no_changes){h.info("No changes detected — nothing was applied");return}if(r!=null&&r.idempotent){h.info("This edit was already applied — no duplicates created"),j==null||j(r.order),u==null||u();return}h.success((r==null?void 0:r.message)||"Order revised"),Number(r==null?void 0:r.overpayment_amount)>0&&h.warning(`Customer overpayment: $${Number(r.overpayment_amount).toFixed(2)} — payment history preserved`),j==null||j(r.order),u==null||u()}catch(i){const r=((m=(d=i==null?void 0:i.response)==null?void 0:d.data)==null?void 0:m.error)||(i==null?void 0:i.message)||"Failed to save changes";h.error(r)}finally{Y(!1)}};if(!g)return null;const y=p;return e.jsx(Ne,{open:!!g,onOpenChange:s=>!s&&(u==null?void 0:u()),children:e.jsxs(fe,{side:"right",className:"w-full sm:max-w-lg overflow-y-auto",children:[e.jsxs(ye,{children:[e.jsxs(ve,{className:"flex items-center gap-2",children:[e.jsx(ie,{className:"w-5 h-5 text-blue-600"})," Edit Order"]}),e.jsx(je,{children:y?`${y.source_order_number||y.id} · Revision ${Z}`:"Loading latest version…"})]}),oe||!y?e.jsx("div",{className:"flex items-center justify-center py-16",children:e.jsx(ae,{className:"w-6 h-6 animate-spin text-blue-600"})}):e.jsxs("div",{className:"space-y-4 px-4 pb-8",children:[e.jsxs("div",{className:"rounded-lg border border-slate-200 bg-slate-50 p-3",children:[e.jsxs("div",{className:"flex items-center justify-between",children:[e.jsx("div",{className:"text-xs font-semibold text-slate-500 uppercase tracking-wide",children:"Customer"}),e.jsxs("span",{className:"flex items-center gap-1 text-[11px] text-slate-400",children:[e.jsx(Se,{className:"w-3 h-3"})," Locked on existing orders"]})]}),e.jsx("p",{className:"font-semibold text-slate-900 mt-1",children:y.customer_company||y.customer_name}),e.jsxs("p",{className:"text-sm text-slate-600",children:[y.customer_name,y.customer_phone?` · ${y.customer_phone}`:""]})]}),e.jsxs("div",{className:"space-y-3",children:[e.jsx(b,{className:"text-sm font-semibold text-slate-700",children:"Tire Line Items"}),w.map((s,t)=>{const a=Number(s.quantity)||0,_=Number(s.selling_price_per_tire)||0,d=s._existing&&Number(s._origQuantity)||0,m=Math.max(0,a-d),i=L.get(s.shop_inventory_item_id),r=s._existing&&Number(s._origCostBasis)||0,o=Number(i==null?void 0:i.average_cost)||0,x=(a-m)*r+m*o,O=a>0?x/a:0,G=s._existing&&m>0&&Math.abs(r-o)>=.005,C=Math.round((_*a-x)*100)/100;return e.jsxs("div",{className:"rounded-lg border border-slate-200 p-3 space-y-2 bg-slate-50",children:[e.jsxs("div",{className:"flex items-center justify-between",children:[e.jsxs("span",{className:"text-xs font-medium text-slate-500",children:["Line ",t+1,s._existing?"":" (new)"]}),e.jsx("button",{onClick:()=>ue(t),className:"text-red-500 hover:text-red-700",children:e.jsx(Fe,{className:"w-4 h-4"})})]}),s._existing?e.jsx("div",{className:"text-sm font-medium text-slate-900 truncate",children:s._label}):e.jsxs("select",{value:s.shop_inventory_item_id,onChange:n=>A(t,"shop_inventory_item_id",n.target.value),className:"w-full rounded-lg border border-slate-200 bg-white px-3 py-2 text-sm",children:[e.jsx("option",{value:"",children:"Select tire…"}),ee.map(n=>e.jsxs("option",{value:n.id,children:[n.brand," ",n.model||""," ",n.size," ",n.position||""," (",n.quantity_on_hand," in stock)"]},n.id))]}),e.jsxs("div",{className:"grid grid-cols-3 gap-2",children:[e.jsxs("div",{children:[e.jsx(b,{className:"text-xs text-slate-500",children:"Qty"}
1),e.jsx(M,{type:"number",min:"1",value:s.quantity,onChange:n=>A(t,"quantity",n.target.value),className:"h-9"})]}),e.jsxs("div",{children:[e.jsx(b,{className:"text-xs text-slate-500",children:"Sell $/tire"}),e.jsx(M,{type:"number",min:"0",step:"0.01",value:s.selling_price_per_tire,onChange:n=>A(t,"selling_price_per_tire",n.target.value),className:"h-9"})]}),e.jsxs("div",{children:[e.jsx(b,{className:"text-xs text-slate-500",children:"Cost $/tire"}),e.jsxs("div",{className:"h-9 flex items-center px-3 rounded-lg bg-slate-100 text-sm text-slate-600",children:["$",O.toFixed(2)]})]})]}),G&&e.jsxs("p",{className:"text-[11px] text-amber-700 flex items-center gap-1",children:[e.jsx(ne,{className:"w-3 h-3 shrink-0"}),"Mixed cost basis: ",a-m," @ $",r.toFixed(2)," + ",m," @ $",o.toFixed(2)]}),e.jsxs("div",{className:"flex items-center justify-between text-xs",children:[e.jsx("span",{className:i?"text-blue-600 font-medium":"text-slate-400",children:i?`${Number(i.quantity_on_hand)} in stock now`:"Item no longer in inventory list"}),e.jsxs("span",{className:C>=0?"text-green-600 font-medium":"text-red-600 font-medium",children:["Line GP: $",C.toFixed(2)]})]})]},t)}),e.jsxs(re,{onClick:me,variant:"outline",className:"w-full border-blue-300 text-blue-600 hover:bg-blue-50",children:[e.jsx(Me,{className:"w-4 h-4 mr-1.5"})," Add Tire"]})]}),e.jsx(we,{services:$,onChange:J}),e.jsx($e,{parts:q,onChange:H}),e.jsxs("div",{className:"rounded-lg border border-slate-200 p-3 space-y-2 bg-white",children:[e.jsxs("div",{className:"flex items-center justify-between",children:[e.jsxs(b,{className:"text-sm font-semibold text-slate-700 flex items-center gap-1.5",children:[e.jsx(Te,{className:"w-4 h-4 text-blue-500"})," Sales Tax"]}),e.jsx("button",{onClick:()=>K(!N),className:`relative w-11 h-6 rounded-full transition-colors ${N?"bg-blue-600":"bg-slate-300"}`,"aria-label":N?"Turn sales tax off":"Turn sales tax on",children:e.jsx("span",{className:`absolute top-0.5 left-0.5 w-5 h-5 rounded-full bg-white shadow transition-transform ${N?"translate-x-5":""}`})})]}),N&&e.jsxs("div",{className:"grid grid-cols-2 gap-3 pt-1",children:[e.jsxs("div",{children:[e.jsx(b,{className:"text-xs text-slate-500",children:"Tax %"}),e.jsx(M,{type:"number",min:"0",step:"0.01",value:S,onChange:s=>U(s.target.value),className:"h-9"})]}),e.jsxs("div",{children:[e.jsx(b,{className:"text-xs text-slate-500",children:"Tax Amount"}),e.jsxs("div",{className:"h-9 flex items-center px-3 rounded-lg bg-slate-100 text-sm text-slate-600",children:["$",v.sales_tax_amount.toFixed(2)]})]})]})]}),e.jsxs("div",{className:"rounded-lg border border-slate-200 p-3 space-y-2 bg-white",children:[e.jsxs("div",{className:"flex items-center justify-between",children:[e.jsxs(b,{className:"text-sm font-semibold text-slate-700 flex items-center gap-1.5",children:[e.jsx(ke,{className:"w-4 h-4 text-indigo-500"})," Transaction Fee"]}),e.jsx("button",{onClick:()=>V(!f),className:`relative w-11 h-6 rounded-full transition-colors ${f?"bg-blue-600":"bg-slate-300"}`,"aria-label":f?"Turn transaction fee off":"Turn transaction fee on",children:e.jsx("span",{className:`absolute top-0.5 left-0.5 w-5 h-5 rounded-full bg-white shadow transition-transform ${f?"translate-x-5":""}`})})]}),f&&e.jsxs("div",{className:"grid grid-cols-2 gap-3 pt-1",children:[e.jsxs("div",{children:[e.jsx(b,{className:"text-xs text-slate-500",children:"Fee %"}),e.jsx(M,{type:"number",min:"0",step:"0.01",value:F,onChange:s=>W(s.target.value),className:"h-9"})]}),e.jsxs("div",{children:[e.jsx(b,{className:"text-xs text-slate-500",children:"Fee Amount"}),e.jsxs("div",{className:"h-9 flex items-center px-3 rounded-lg bg-slate-100 text-sm text-slate-600",children:["$",v.transaction_fee_amount.toFixed(2)]})]})]})]}),e.jsxs("div",{children:[e.jsx(b,{htmlFor:"edit-notes",children:"Notes"}),e.jsx(M,{id:"edit-notes",value:P,onChange:s=>X(s.target.value),placeholder:"Optional order notes"})]}),e.jsx(qe,{preview:v,salesTaxPercent:S,transactionFeePercent:F}),c&&e.jsxs("div",{className:"rounded-xl border border-blue-200 bg-blue-50/60 p-4 space-y-2",children:[e.jsx("div",{className:"text-xs font-semibold text-blue-900 uppercase tracking-wide",children:"Changes Summary"}),e.jsxs("div",{className:"space-y-1 text-sm",children:[e.jsxs("div",{className:"flex justify-between",children:[e.jsx("span",{className:"text-slate-600",children:"Inventory"}),e.jsx("span",{className:"font-medium text-slate-900",children:c.returned>0||c.additional>0?`${c.returned} returned / ${c.additional} additional sold`:"No inventory changes"})]}),e.jsxs("div",{className:"flex justify-between",children:[e.jsx("span",{className:"text-slate-600",children:"Grand Total"}),e.jsxs("span",{className:"font-medium text-slate-900",children:["$",c.oldGrand.toFixed(2)," → $",c.newGrand.toFixed(2)]})]}),e.jsxs("div",{className:"flex justify-between",children:[e.jsx("span",{className:"text-slate-600",children:"Gross Profit"}),e.jsxs("span",{className:"font-medium text-slate-900",children:["$",c.oldGp.toFixed(2)," → $",c.newGp.toFixed(2)]})]}),e.jsxs("div",{className:"flex justify-between",children:[e.jsx("span",{className:"text-slate-600",children:"Balance Due"}),e.jsxs("span",{className:"font-medium text-slate-900",children:["$",c.oldBalance.toFixed(2)," → $",c.newBalance.toFixed(2)]})]}),c.overpayment>0&&e.jsxs("div",{className:"flex justify-between pt-1 border-t border-amber-200",children:[e.jsx("span",{className:"text-amber-700 font-medium",children:"Customer Overpayment"}),e.jsxs("span",{className:"font-bold text-amber-700",children:["$",c.overpayment.toFixed(2)]})]})]}),c.amountPaid>0&&e.jsxs("p",{className:"text-xs text-amber-700 bg-amber-50 border border-amber-200 rounded-md px-2 py-1.5 flex items-start gap-1.5",children:[e.jsx(ne,{className:"w-3.5 h-3.5 shrink-0 mt-0.5"}),"This order already has payments. Existing payment history will remain and the balance will be recalculated."]})]}),e.jsxs(re,{onClick:pe,disabled:Q,className:"w-full bg-blue-600 hover:bg-blue-700 text-white",children:[Q?e.jsx(ae,{className:"w-4 h-4 mr-2 animate-spin"}):e.jsx(ie,{className:"w-4 h-4 mr-2"}),Q?"Saving…":"Save Order Changes"]})]})]})})}export{lt 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.