// ===== Casepoint seed data & domain helpers =====

const DEVICE_TYPES = [
  { id: "celular",  label: "Celular",        icon: "phone"  },
  { id: "laptop",   label: "Laptop / MacBook", icon: "laptop" },
  { id: "tablet",   label: "Tablet / iPad",   icon: "tablet" },
  { id: "reloj",    label: "Smartwatch",      icon: "watch"  },
  { id: "dron",     label: "Dron",            icon: "drone"  },
  { id: "otro",     label: "Otro electrónico", icon: "chip"   },
];

// Order lifecycle. "stage" groups them into the three tabs.
const STATUSES = {
  recibido:    { id: "recibido",    label: "Recibido",      stage: "entrada",   color: "entrada" },
  diagnostico: { id: "diagnostico", label: "Diagnóstico",   stage: "entrada",   color: "entrada" },
  presupuesto: { id: "presupuesto", label: "Presupuesto",   stage: "entrada",   color: "entrada" },
  reparacion:  { id: "reparacion",  label: "En reparación", stage: "reparacion", color: "rep" },
  espera:      { id: "espera",      label: "Espera repuesto", stage: "reparacion", color: "rep" },
  listo:       { id: "listo",       label: "Listo",         stage: "reparacion", color: "listo" },
  entregado:   { id: "entregado",   label: "Entregado",     stage: "salida",    color: "salida" },
};

// Ordered flow used by the detail stepper
const FLOW = ["recibido", "diagnostico", "reparacion", "listo", "entregado"];

const PRIORITIES = {
  baja:    { id: "baja",    label: "Baja" },
  normal:  { id: "normal",  label: "Normal" },
  alta:    { id: "alta",    label: "Alta" },
  urgente: { id: "urgente", label: "Urgente" },
};

const TECHS = [
  { id: "t1", name: "Daniela López",   role: "Técnico sénior", initials: "DL", hue: 256 },
  { id: "t2", name: "Marco Reyes",     role: "Microsoldadura", initials: "MR", hue: 150 },
  { id: "t3", name: "Andrea Salas",    role: "Técnico",        initials: "AS", hue: 70 },
  { id: "t4", name: "Julio Paredes",   role: "Recepción",      initials: "JP", hue: 320 },
];

const CLIENTS = [
  { id: "c1", name: "Ángel Domínguez",  cedula: "0801-1990-04471", phone: "+503 7012-4488", email: "angel.d@correo.com", orders: 4 },
  { id: "c2", name: "Andrés Arias",     cedula: "0801-1985-12290", phone: "+503 7755-1290", email: "aarias@correo.com",  orders: 1 },
  { id: "c3", name: "Lucía Hernández",  cedula: "0102-1992-33321", phone: "+503 7890-3321", email: "lucia.h@correo.com", orders: 7 },
  { id: "c4", name: "Carlos Méndez",    cedula: "0801-1978-90087", phone: "+503 7233-9087", email: "cmendez@correo.com", orders: 2 },
  { id: "c5", name: "Sofía Navarro",    cedula: "0703-1995-77745", phone: "+503 7611-7745", email: "sofia.n@correo.com", orders: 3 },
  { id: "c6", name: "Empresa Vértigo S.A.", cedula: "RUC 0614-0512-001-5", phone: "+503 2225-6600", email: "soporte@vertigo.com", orders: 12 },
];

function daysAgo(n){
  const d = new Date(); d.setDate(d.getDate() - n);
  return d.toISOString();
}

const SEED_ORDERS = [
  {
    id: "o11144", num: "11144", device: "celular", brand: "Apple", model: "iPhone 11",
    serial: "356789102345678", clientId: "c1", techId: "t1", priority: "normal",
    status: "diagnostico", issue: "No carga y se reinicia solo al conectarlo.",
    unlock: { type:"code", code:"4471", pattern:[] },
    diagnosis: "Pendiente de revisión del conector de carga (puerto Lightning).",
    accessories: ["Cargador", "Funda"], estimate: 0, paid: 0,
    createdAt: daysAgo(0),
    log: [
      { t: daysAgo(0), who: "Julio Paredes", text: "Orden creada en recepción." },
      { t: daysAgo(0), who: "Daniela López", text: "Asignada para diagnóstico." },
    ],
  },
  {
    id: "o11142", num: "11142", device: "reloj", brand: "Apple", model: "Watch Series 7 45mm",
    serial: "GX7K8821LMQ", clientId: "c2", techId: "t1", priority: "normal",
    status: "recibido", issue: "Pantalla con líneas verticales tras una caída.",
    unlock: { type:"pattern", code:"", pattern:[0,3,6,7,8] },
    diagnosis: "", accessories: ["Correa deportiva"], estimate: 0, paid: 0,
    createdAt: daysAgo(0),
    log: [{ t: daysAgo(0), who: "Julio Paredes", text: "Orden creada en recepción." }],
  },
  {
    id: "o11139", num: "11139", device: "laptop", brand: "Apple", model: 'MacBook Pro 14" M2',
    serial: "C02FK3QWMD6T", clientId: "c3", techId: "t2", priority: "alta",
    status: "reparacion", issue: "No enciende. Se mojó con líquido.",
    diagnosis: "Corrosión en placa lógica. Limpieza ultrasónica + reemplazo de IC de carga.",
    accessories: ["Cargador MagSafe"], estimate: 285, paid: 100,
    createdAt: daysAgo(2),
    log: [
      { t: daysAgo(2), who: "Julio Paredes", text: "Orden creada en recepción." },
      { t: daysAgo(2), who: "Marco Reyes", text: "Diagnóstico: daño por líquido." },
      { t: daysAgo(1), who: "Marco Reyes", text: "Presupuesto aprobado por el cliente. Anticipo $100." },
      { t: daysAgo(1), who: "Marco Reyes", text: "Inicio de reparación — microsoldadura." },
    ],
  },
  {
    id: "o11135", num: "11135", device: "dron", brand: "DJI", model: "Mavic 3 Pro",
    serial: "1581F5BMC23A09", clientId: "c6", techId: "t2", priority: "alta",
    status: "espera", issue: "Un motor no responde tras impacto. Gimbal descalibrado.",
    diagnosis: "Reemplazo de motor trasero izquierdo y recalibración de gimbal.",
    accessories: ["3 baterías", "Control remoto", "Maletín"], estimate: 190, paid: 190,
    createdAt: daysAgo(4),
    log: [
      { t: daysAgo(4), who: "Julio Paredes", text: "Orden creada — cliente corporativo." },
      { t: daysAgo(3), who: "Marco Reyes", text: "Diagnóstico completo. Repuesto solicitado." },
      { t: daysAgo(1), who: "Marco Reyes", text: "En espera de motor desde proveedor." },
    ],
  },
  {
    id: "o11131", num: "11131", device: "celular", brand: "Samsung", model: "Galaxy S23 Ultra",
    serial: "RZ8N20ABCXY", clientId: "c4", techId: "t3", priority: "normal",
    status: "listo", issue: "Cambio de pantalla rota.",
    diagnosis: "Reemplazo de display OLED original. Prueba de táctil y cámaras OK.",
    accessories: [], estimate: 165, paid: 165,
    createdAt: daysAgo(3),
    log: [
      { t: daysAgo(3), who: "Julio Paredes", text: "Orden creada." },
      { t: daysAgo(2), who: "Andrea Salas", text: "Pantalla reemplazada." },
      { t: daysAgo(2), who: "Andrea Salas", text: "Equipo listo para entrega." },
    ],
  },
  {
    id: "o11128", num: "11128", device: "tablet", brand: "Apple", model: 'iPad Air 5',
    serial: "DMPV4Q9LMNH", clientId: "c5", techId: "t3", priority: "baja",
    status: "listo", issue: "Batería se descarga muy rápido.",
    diagnosis: "Reemplazo de batería. Salud de batería nueva 100%.",
    accessories: ["Apple Pencil"], estimate: 95, paid: 0,
    createdAt: daysAgo(5),
    log: [
      { t: daysAgo(5), who: "Julio Paredes", text: "Orden creada." },
      { t: daysAgo(4), who: "Andrea Salas", text: "Batería reemplazada. Listo." },
    ],
  },
  {
    id: "o11120", num: "11120", device: "celular", brand: "Xiaomi", model: "Redmi Note 12",
    serial: "865432109876543", clientId: "c3", techId: "t1", priority: "normal",
    status: "entregado", issue: "Reemplazo de batería y limpieza.",
    diagnosis: "Batería reemplazada. Equipo entregado y facturado.",
    accessories: ["Cargador"], estimate: 45, paid: 45,
    createdAt: daysAgo(8),
    log: [
      { t: daysAgo(8), who: "Julio Paredes", text: "Orden creada." },
      { t: daysAgo(7), who: "Daniela López", text: "Reparación completa." },
      { t: daysAgo(6), who: "Julio Paredes", text: "Equipo entregado al cliente." },
    ],
  },
  {
    id: "o11118", num: "11118", device: "laptop", brand: "Dell", model: "XPS 13",
    serial: "5CG1234XYZ", clientId: "c6", techId: "t2", priority: "normal",
    status: "entregado", issue: "Teclado no responde.",
    diagnosis: "Reemplazo de teclado. Entregado.",
    accessories: ["Cargador"], estimate: 80, paid: 80,
    createdAt: daysAgo(10),
    log: [
      { t: daysAgo(10), who: "Julio Paredes", text: "Orden creada." },
      { t: daysAgo(9), who: "Marco Reyes", text: "Teclado reemplazado." },
      { t: daysAgo(8), who: "Julio Paredes", text: "Entregado." },
    ],
  },
  {
    id: "o11095", num: "11095", device: "celular", brand: "Motorola", model: "Moto G54",
    serial: "359871002245511", clientId: "c4", techId: "t3", priority: "baja",
    status: "listo", issue: "Cambio de batería y limpieza de puerto.",
    diagnosis: "Batería reemplazada. Equipo listo — cliente no responde para retirar.",
    accessories: ["Cargador"], estimate: 55, paid: 0,
    parts: [{ invId:"b1", name:"Batería Moto G54", sku:"BAT-MG54", qty:1, cost:12, price:35 }],
    createdAt: daysAgo(45),
    log: [
      { t: daysAgo(45), who: "Julio Paredes", text: "Orden creada." },
      { t: daysAgo(44), who: "Andrea Salas", text: "Batería reemplazada. Listo para retirar." },
      { t: daysAgo(38), who: "Julio Paredes", text: "Cliente no contesta. Pendiente de retiro." },
    ],
  },
];

// ===== helpers =====
function fmtMoney(n){ return "US$" + (Number(n)||0).toFixed(2); }

function fmtDate(iso){
  const d = new Date(iso);
  return d.toLocaleDateString("es-ES", { day: "2-digit", month: "short", year: "numeric" });
}
function fmtDateTime(iso){
  const d = new Date(iso);
  return d.toLocaleDateString("es-ES", { day: "2-digit", month: "short" }) + " · " +
    d.toLocaleTimeString("es-ES", { hour: "2-digit", minute: "2-digit" });
}
function relTime(iso){
  const diff = Date.now() - new Date(iso).getTime();
  const h = Math.floor(diff / 3.6e6);
  if(h < 1) return "hace minutos";
  if(h < 24) return `hace ${h} h`;
  const d = Math.floor(h/24);
  return d === 1 ? "ayer" : `hace ${d} días`;
}
function getClient(id){ return CLIENTS.find(c => c.id === id) || { name: "—", phone: "", email: "" }; }
function getTech(id){ return TECHS.find(t => t.id === id) || null; }
function getDevice(id){ return DEVICE_TYPES.find(d => d.id === id) || DEVICE_TYPES[5]; }

// ===== Repair outcomes (desenlace) =====
const OUTCOMES = {
  reparado:     { id:"reparado",     label:"Reparado",                  color:"listo",   icon:"check",   desc:"La falla fue resuelta correctamente." },
  sin_falla:    { id:"sin_falla",    label:"No presentó fallas",        color:"rep",     icon:"eye",     desc:"No se reprodujo el problema reportado." },
  sin_solucion: { id:"sin_solucion", label:"Sin solución",              color:"salida",  icon:"x",       desc:"No fue posible reparar el equipo." },
  no_reparado:  { id:"no_reparado",  label:"No reparado",               color:"entrada", icon:"tools",   desc:"El cliente retira sin reparar." },
  rechazado:    { id:"rechazado",    label:"Cliente no acepta presupuesto", color:"salida", icon:"warning", desc:"El presupuesto fue rechazado." },
  garantia:     { id:"garantia",     label:"Garantía / reingreso",      color:"rep",     icon:"refresh", desc:"Vuelve a ingresar por garantía." },
};

// ===== Inventory: parts & supplies =====
const INV_CATEGORIES = [
  { id:"pantallas", label:"Pantallas", icon:"phone" },
  { id:"baterias",  label:"Baterías", icon:"chip" },
  { id:"componentes", label:"Componentes / IC", icon:"chip" },
  { id:"conectores", label:"Conectores / flex", icon:"tools" },
  { id:"insumos",   label:"Insumos / consumibles", icon:"box" },
  { id:"accesorios", label:"Accesorios", icon:"box" },
];

const SEED_INVENTORY = [
  { id:"p1", sku:"PNT-IP11", barcode:"7501031311101", name:'Pantalla iPhone 11 (OLED comp.)', cat:"pantallas", stock:4,  min:2, cost:38,  price:95,  supplier:"MovilParts" },
  { id:"p2", sku:"PNT-S23U", barcode:"7501031322202", name:"Pantalla Galaxy S23 Ultra (OLED orig.)", cat:"pantallas", stock:1, min:2, cost:120, price:165, supplier:"SamParts" },
  { id:"b1", sku:"BAT-IP11", barcode:"7501031344404", name:"Batería iPhone 11", cat:"baterias", stock:6, min:3, cost:9, price:35, supplier:"MovilParts" },
  { id:"b2", sku:"BAT-IPADA5", barcode:"7501031355505", name:"Batería iPad Air 5", cat:"baterias", stock:2, min:2, cost:22, price:60, supplier:"AppleParts SV" },
  { id:"c1", sku:"IC-CARGA-MB", barcode:"7501031366606", name:"IC de carga MacBook (U3100)", cat:"componentes", stock:3, min:2, cost:14, price:45, supplier:"ChipHouse" },
  { id:"c2", sku:"MTR-MAVIC3", barcode:"7501031377707", name:"Motor DJI Mavic 3 (trasero)", cat:"componentes", stock:0, min:1, cost:48, price:90, supplier:"DronTech" },
  { id:"f1", sku:"FLEX-IP-LTG", barcode:"7501031388808", name:"Flex de carga Lightning iPhone", cat:"conectores", stock:8, min:4, cost:5, price:22, supplier:"MovilParts" },
  { id:"k1", sku:"KIT-TORN", barcode:"", name:"Kit tornillería universal", cat:"insumos", stock:12, min:5, cost:3, price:0, supplier:"GenéricoSV" },
  { id:"k2", sku:"PASTA-TER", barcode:"", name:"Pasta térmica (jeringa)", cat:"insumos", stock:9, min:4, cost:4, price:0, supplier:"GenéricoSV" },
  { id:"k3", sku:"ALC-ISO", barcode:"", name:"Alcohol isopropílico 1L", cat:"insumos", stock:5, min:3, cost:6, price:0, supplier:"GenéricoSV" },
  { id:"a1", sku:"VID-TEMP", barcode:"7501099000019", name:"Vidrio templado (genérico)", cat:"accesorios", stock:24, min:10, cost:1.5, price:8, supplier:"GenéricoSV" },
  { id:"a2", sku:"CRG-IP-20W", barcode:"7501099000026", name:"Cargador iPhone 20W USB-C", cat:"accesorios", stock:18, min:6, cost:6, price:18, supplier:"MovilParts" },
  { id:"a3", sku:"CBL-USBC-LTG", barcode:"7501099000033", name:"Cable USB-C a Lightning 1m", cat:"accesorios", stock:30, min:10, cost:3, price:12, supplier:"MovilParts" },
  { id:"a4", sku:"CRG-AND-25W", barcode:"7501099000040", name:"Cargador Android 25W", cat:"accesorios", stock:14, min:6, cost:5, price:16, supplier:"GenericoSV" },
  { id:"a5", sku:"FUN-IP15", barcode:"7501099000057", name:"Funda iPhone 15 (silicona)", cat:"accesorios", stock:22, min:8, cost:2.5, price:14, supplier:"GenericoSV" },
  { id:"a6", sku:"PWB-10K", barcode:"7501099000064", name:"Power Bank 10,000mAh", cat:"accesorios", stock:9, min:4, cost:11, price:28, supplier:"DronTech" },
  { id:"a7", sku:"AUD-BT", barcode:"7501099000071", name:"Audífonos Bluetooth", cat:"accesorios", stock:11, min:4, cost:9, price:25, supplier:"GenericoSV" },
];

// ===== Expenses (compras / gastos) =====
const EXPENSE_CATEGORIES = [
  { id:"repuestos", label:"Compra de repuestos", hue:256 },
  { id:"insumos",   label:"Insumos / consumibles", hue:70 },
  { id:"herramientas", label:"Herramientas / equipo", hue:200 },
  { id:"renta",     label:"Renta del local", hue:320 },
  { id:"servicios", label:"Servicios (luz, internet)", hue:30 },
  { id:"sueldos",   label:"Sueldos", hue:155 },
  { id:"otros",     label:"Otros", hue:0 },
];

const SEED_EXPENSES = [
  { id:"e1", date:daysAgo(2),  cat:"repuestos", concept:"Lote pantallas iPhone (x5)", supplier:"MovilParts", amount:190 },
  { id:"e2", date:daysAgo(5),  cat:"repuestos", concept:"Baterías varias", supplier:"AppleParts SV", amount:132 },
  { id:"e3", date:daysAgo(8),  cat:"insumos",   concept:"Alcohol, pasta térmica, tornillería", supplier:"GenéricoSV", amount:48 },
  { id:"e4", date:daysAgo(12), cat:"renta",     concept:"Renta del local — mes", supplier:"Inmobiliaria", amount:350 },
  { id:"e5", date:daysAgo(14), cat:"servicios", concept:"Luz e internet", supplier:"Compañía", amount:95 },
  { id:"e6", date:daysAgo(20), cat:"herramientas", concept:"Estación de soldadura", supplier:"DronTech", amount:140 },
];

function getOutcome(id){ return OUTCOMES[id] || null; }
function getInvCat(id){ return INV_CATEGORIES.find(c=>c.id===id) || INV_CATEGORIES[4]; }
function getExpCat(id){ return EXPENSE_CATEGORIES.find(c=>c.id===id) || EXPENSE_CATEGORIES[6]; }
function monthKey(iso){ const d=new Date(iso); return d.getFullYear()+"-"+String(d.getMonth()+1).padStart(2,"0"); }
function monthLabel(iso){ return new Date(iso).toLocaleDateString("es-ES",{ month:"long", year:"numeric" }); }

// money helpers for an order
function orderPayments(o){
  if(Array.isArray(o.payments)) return o.payments;
  if(o.paid>0) return [{ t:o.createdAt, amount:o.paid, method:"efectivo", who:"—" }];
  return [];
}
function orderPaid(o){ return orderPayments(o).reduce((s,p)=>s+(+p.amount||0),0); }
function orderParts(o){ return Array.isArray(o.parts)?o.parts:[]; }
function orderPartsCost(o){ return orderParts(o).reduce((s,p)=>s+(+p.cost||0)*(+p.qty||1),0); }
function orderBalance(o){ return Math.max(0, (+o.estimate||0) - orderPaid(o)); }

// ===== Asistencia (clock-in / clock-out) =====
function atTime(dayOffset, h, m){
  const d = new Date(); d.setDate(d.getDate()-dayOffset); d.setHours(h, m, 0, 0);
  return d.toISOString();
}
const SEED_ATTENDANCE = [
  { id:"a1", userId:"t1", in:atTime(0,8,2),  out:null },
  { id:"a2", userId:"t2", in:atTime(0,8,46), out:null },
  { id:"a3", userId:"t4", in:atTime(0,7,58), out:null },
  { id:"a4", userId:"t1", in:atTime(1,8,10), out:atTime(1,17,32) },
  { id:"a5", userId:"t2", in:atTime(1,9,3),  out:atTime(1,18,12) },
  { id:"a6", userId:"t4", in:atTime(1,8,0),  out:atTime(1,16,5) },
  { id:"a7", userId:"t1", in:atTime(2,8,5),  out:atTime(2,17,15) },
  { id:"a8", userId:"t3", in:atTime(2,8,40), out:atTime(2,17,1) },
];

// ===== Notificaciones (plantillas + bitácora) =====
const NOTIF_TEMPLATES = [
  { id:"recibido",  label:"Equipo recibido",   channel:"both",     auto:true,  trigger:"recibido",
    body:"Hola {cliente}, recibimos tu {equipo} (orden #{num}) en Taller Casepoint. Te avisaremos del diagnóstico. ¡Gracias!" },
  { id:"presupuesto", label:"Presupuesto listo", channel:"whatsapp", auto:true,  trigger:"presupuesto",
    body:"Hola {cliente}, el presupuesto de tu {equipo} (orden #{num}) es {presupuesto}. Responde para autorizar la reparación." },
  { id:"listo",     label:"Listo para retirar", channel:"both",     auto:true,  trigger:"listo",
    body:"¡Buenas noticias {cliente}! Tu {equipo} (orden #{num}) está listo para retirar. Saldo pendiente: {saldo}." },
  { id:"entregado", label:"Gracias por tu visita", channel:"email", auto:false, trigger:"entregado",
    body:"Gracias {cliente} por confiar en Taller Casepoint. Tu {equipo} fue entregado. ¡Cuéntanos cómo fue tu experiencia!" },
];
const SEED_NOTIFICATIONS = [
  { id:"n1", orderNum:"11139", clientName:"Lucía Hernández", channel:"whatsapp", template:"presupuesto", t:daysAgo(1), status:"enviado", preview:"Hola Lucía, el presupuesto de tu MacBook Pro 14\" M2 (orden #11139) es US$285.00…" },
  { id:"n2", orderNum:"11131", clientName:"Carlos Méndez", channel:"both", template:"listo", t:daysAgo(2), status:"enviado", preview:"¡Buenas noticias Carlos! Tu Galaxy S23 Ultra (orden #11131) está listo para retirar…" },
  { id:"n3", orderNum:"11120", clientName:"Lucía Hernández", channel:"email", template:"entregado", t:daysAgo(6), status:"enviado", preview:"Gracias Lucía por confiar en Taller Casepoint…" },
];

// attendance helpers
function attHours(rec){
  if(!rec.out) return (Date.now() - new Date(rec.in).getTime())/3.6e6;
  return (new Date(rec.out).getTime() - new Date(rec.in).getTime())/3.6e6;
}
function fmtHours(h){ const t=Math.max(0,h); const hh=Math.floor(t); const mm=Math.round((t-hh)*60); return `${hh}h ${String(mm).padStart(2,"0")}m`; }
function fmtClock(iso){ return new Date(iso).toLocaleTimeString("es-ES",{ hour:"2-digit", minute:"2-digit" }); }
function sameDay(iso, ref=new Date()){ const d=new Date(iso); return d.getFullYear()===ref.getFullYear()&&d.getMonth()===ref.getMonth()&&d.getDate()===ref.getDate(); }

// fill notification template
function fillTemplate(body, ctx){
  return body
    .replace(/{cliente}/g, ctx.cliente||"")
    .replace(/{equipo}/g, ctx.equipo||"")
    .replace(/{num}/g, ctx.num||"")
    .replace(/{presupuesto}/g, ctx.presupuesto||"")
    .replace(/{saldo}/g, ctx.saldo||"");
}

// ===== Ventas (Punto de venta) =====
function saleAt(dayOffset, h, m){ const d=new Date(); d.setDate(d.getDate()-dayOffset); d.setHours(h,m,0,0); return d.toISOString(); }
const SEED_SALES = [
  { id:"v1004", num:"1004", date:saleAt(0,11,20), method:"efectivo", clientName:"Cliente de mostrador", items:[ {sku:"CRG-IP-20W", name:"Cargador iPhone 20W USB-C", qty:1, price:18, cost:6} ], total:18 },
  { id:"v1003", num:"1003", date:saleAt(1,16,5), method:"tarjeta", clientName:"Sofía Navarro", items:[ {sku:"VID-TEMP", name:"Vidrio templado (genérico)", qty:2, price:8, cost:1.5}, {sku:"FUN-IP15", name:"Funda iPhone 15 (silicona)", qty:1, price:14, cost:2.5} ], total:30 },
  { id:"v1002", num:"1002", date:saleAt(3,10,40), method:"efectivo", clientName:"Cliente de mostrador", items:[ {sku:"PWB-10K", name:"Power Bank 10,000mAh", qty:1, price:28, cost:11} ], total:28 },
  { id:"v1001", num:"1001", date:saleAt(6,12,15), method:"transferencia", clientName:"Empresa Vértigo S.A.", items:[ {sku:"CBL-USBC-LTG", name:"Cable USB-C a Lightning 1m", qty:5, price:12, cost:3} ], total:60 },
];
function saleProfit(sale){ return sale.items.reduce((s,it)=> s + (it.price-(it.cost||0))*it.qty, 0); }

Object.assign(window, {
  DEVICE_TYPES, STATUSES, FLOW, PRIORITIES, TECHS, CLIENTS, SEED_ORDERS,
  OUTCOMES, INV_CATEGORIES, SEED_INVENTORY, EXPENSE_CATEGORIES, SEED_EXPENSES,
  SEED_ATTENDANCE, NOTIF_TEMPLATES, SEED_NOTIFICATIONS, SEED_SALES,
  fmtMoney, fmtDate, fmtDateTime, relTime, getClient, getTech, getDevice, daysAgo,
  getOutcome, getInvCat, getExpCat, monthKey, monthLabel,
  orderPayments, orderPaid, orderParts, orderPartsCost, orderBalance,
  attHours, fmtHours, fmtClock, sameDay, fillTemplate, saleProfit,
});
