[object Object]

← back to Filemaker Mcp

remove dead lib/invoice-core.js (orphaned from refactor; lib/invoice.js is the single source of truth)

1f3eaf89a67c8a2e31c242102ce0a28a186ddc9e · 2026-06-29 13:42:45 -0700 · Steve

Files touched

Diff

commit 1f3eaf89a67c8a2e31c242102ce0a28a186ddc9e
Author: Steve <steve@designerwallcoverings.com>
Date:   Mon Jun 29 13:42:45 2026 -0700

    remove dead lib/invoice-core.js (orphaned from refactor; lib/invoice.js is the single source of truth)
---
 lib/invoice-core.js | 109 ----------------------------------------------------
 1 file changed, 109 deletions(-)

diff --git a/lib/invoice-core.js b/lib/invoice-core.js
deleted file mode 100644
index 2db49ce..0000000
--- a/lib/invoice-core.js
+++ /dev/null
@@ -1,109 +0,0 @@
-// Build a full FileMaker invoice from a Shopify order, applying Steve's field
-// rules. Called by the sync after the client is ensured. Separate base tables
-// in FileMaker mean some fields are written via different layouts but the SAME
-// recordId only works on its own base table — so header/line fields go via
-// 'Invoice to Client Copy', the middle SKU via 'Layout #47', WC PATTERN via
-// '1-order detail 1 Copy3'.
-import * as fm from '../src/fm-client.js';
-
-const HDR = 'Invoice to Client Copy';   // header + line items (base table that owns the record)
-const SKU_LAY = 'Layout #47';            // has 'JS Easy SKU #' (same base table as HDR)
-const WCP_LAY = '1-order detail 1 Copy3';// has 'wc pattern' (same base table as HDR)
-const RESALE_LAY = 'PROFORMA';           // has 'Resale card lookup' (same base table as HDR)
-
-const today = () => { const d = new Date(); return `${String(d.getMonth()+1).padStart(2,'0')}/${String(d.getDate()).padStart(2,'0')}/${d.getFullYear()}`; };
-const stamp = () => new Date().toLocaleString('en-US', { month:'short', day:'numeric', year:'numeric', hour:'numeric', minute:'2-digit' });
-export const baseSku = (s) => { const m=(s||'').match(/^([A-Za-z]+-?\d+)/); return m?m[1]:(s||''); };
-export const sampleStrip = (s) => (s||'').replace(/-?sample/ig,'').trim();
-function uom(li){
-  const t=`${li.variant_title||''} ${li.name||''} ${li.sku||''}`.toLowerCase();
-  if(/per yard|\/yard|\byard/.test(t)) return 'yards';
-  if(/double roll|per roll|\/roll|\broll/.test(t)) return 'rolls';
-  if(/bolt/.test(t)) return 'bolts';
-  if(/sample|memo|swatch/.test(t)) return 'sample';
-  if(/panel/.test(t)) return 'panels';
-  return 'each';
-}
-function resaleFor(ship){
-  const country=(ship.country_code||'US').toUpperCase();
-  const state=(ship.province_code||'').toUpperCase();
-  if(country!=='US') return 'Out of Country';
-  if(state && state!=='CA') return 'Out of State';
-  return 'On File';
-}
-
-async function nextInvoiceNumber(){
-  const top=await fm.findRecords('invoice',HDR,{'Invoice':'10*'},{limit:25,sort:[{fieldName:'Invoice',sortOrder:'descend'}]});
-  const nums=top.records.map(r=>parseInt((r.fieldData['Invoice']||'').replace(/\D/g,''))).filter(n=>n>100000&&n<200000);
-  return (nums.length?Math.max(...nums):102261)+1;
-}
-
-// Create the invoice. Returns {invoiceNumber, recordId, grandTotal} or {skipped}.
-export async function createInvoiceForOrder(order, accountNumber, { commit=true } = {}){
-  const c=order.customer||{}, s=order.shipping_address||order.billing_address||{};
-  const fullName=((c.first_name||'')+' '+(c.last_name||'')).trim();
-  const shipVia=(order.shipping_lines&&order.shipping_lines[0]&&order.shipping_lines[0].title)||'';
-  const shipping=parseFloat((order.total_shipping_price_set?.shop_money?.amount) ?? (order.shipping_lines?.[0]?.price) ?? 0)||0;
-  const tax=parseFloat(order.total_tax||0)||0;
-  const lines=order.line_items||[];
-
-  if(!commit){
-    return { invoiceNumber:'(next)', would:true, header:{Cust_PO:order.order_number, account:accountNumber, sold:fullName, shipVia, shipping, tax,
-      resale:resaleFor(s)}, lines: lines.map(li=>({sku:li.sku, base:baseSku(li.sku), wcPattern:sampleStrip(li.sku), qty:li.quantity, unit:uom(li), price:li.price, detail:`${baseSku(li.sku)} — ${li.name}`})) };
-  }
-
-  const inv=String(await nextInvoiceNumber());
-  // 1) header
-  const res=await fm.createRecord('invoice',HDR,{
-    'Invoice':inv,'Cust PO':String(order.order_number),'Account #':String(accountNumber||''),
-    'SOLD NAME':fullName,'SOLD COMPANY':s.company||'','SOLD ADDRESS':s.address1||'','SOLD CITY':s.city||'','SOLD STATE':s.province_code||'','SOLD ZIP':s.zip||'','TELEPHONE':s.phone||order.phone||'',
-    'Date':today()
-  },{dryRun:false});
-  const ID=res.recordId;
-  const set=async(lay,k,v)=>{ try{ await fm.updateRecord('invoice',lay,ID,{[k]:v},{dryRun:false}); }catch(e){ /* skip calc/missing */ } };
-
-  // 2) header extras + ship-to
-  for(const [k,v] of Object.entries({
-    'ship name':fullName,'SHIP COMAPNY':s.company||'','SHIP ADDRESS':s.address1||'','SHIP CITY':s.city||'','SHIP STATE':s.province_code||'','SHIP ZIP':s.zip||'',
-    'Resale #':resaleFor(s),'BUYER':fullName,'SALES PERSON':'Otto','SHIP VIA':shipVia,
-    'SHIPPING  HANDLING':shipping,'SALES TAX YN':(tax>0?'Y':'N'),'check Number':today()
-  })) await set(HDR,k,v);
-
-  // 3) line items -> repetitions 1..N
-  for(let i=0;i<lines.length;i++){
-    const li=lines[i], r=i+1, price=parseFloat(li.price||0)||0;
-    await set(HDR,`DETAIL 1(${r})`,`${baseSku(li.sku)} — ${li.name}`);
-    await set(HDR,`Q1(${r})`,li.quantity);
-    await set(HDR,`Unit 1(${r})`,uom(li));
-    await set(HDR,`RETAIL 1(${r})`,price);
-    await set(HDR,`NET 1(${r})`,price);
-    await set(HDR,`Sidemark 1(${r})`,s.company||'');
-  }
-  // 4) middle SKU + WC PATTERN (primary line) + resale card lookup
-  const primary=lines[0]||{};
-  await set(SKU_LAY,'JS Easy SKU #',baseSku(primary.sku));
-  await set(WCP_LAY,'wc pattern',sampleStrip(primary.sku));
-  await set(RESALE_LAY,'Resale card lookup',resaleFor(s));
-
-  // 5) paid-in-full from the computed grand total, then the import stamp
-  let grand=0;
-  try{ grand=parseFloat((await fm.getRecord('invoice',HDR,ID)).fieldData['GRAND TOTAL']||0)||0; }catch{}
-  await set(HDR,'PAID ON ACCOUNT',grand);
-  await set(HDR,'Notes',`Imported by Otto — ${stamp()}`);
-
-  return { invoiceNumber:inv, recordId:ID, grandTotal:grand };
-}
-
-// Post a new-order notification to Slack #general.
-export async function postSlackOrder({ order, invoiceNumber, clientName }){
-  const token=process.env.SLACK_BOT_TOKEN; if(!token) return { ok:false, error:'no SLACK_BOT_TOKEN' };
-  const channel=process.env.SLACK_ORDER_CHANNEL||'#general';
-  const store=process.env.SHOPIFY_STORE;
-  const time=new Date(order.created_at||Date.now()).toLocaleString('en-US',{hour:'numeric',minute:'2-digit'});
-  const link=`https://${store}/admin/orders/${order.id}`;
-  const text=`🧾 *New Order* — *${clientName}*\nInvoice #${invoiceNumber} · ${time} · *$${order.total_price}*\n<${link}|View order #${order.order_number}>`;
-  const r=await fetch('https://slack.com/api/chat.postMessage',{method:'POST',
-    headers:{Authorization:'Bearer '+token,'Content-Type':'application/json'},
-    body:JSON.stringify({channel,text})});
-  return await r.json();
-}

← f9e757d invoice: strip dashes in WC Pattern Number AKA DW SKU; write  ·  back to Filemaker Mcp  ·  fix: fm_find/sort JSON-string coercion (harness stringifies 7b9b08c →