// ─────────────────────────────────────────────────────
// GUT-254 — Necesidades de compra (Operaciones). Vista global de todas las
// líneas de material (bom_lineas) de todos los expedientes y proyectos:
//   Por pedir       pendientes de pedir → se marcan y "Crear pedido" (una OC por proveedor)
//   En camino       pedidas y sin recibir, con la llegada prevista (rojo si se pasa)
//   Lacado externo  material fuera lacándose, con la vuelta prevista; se marcan los lacados →
//                   "Crear orden de lacado" (una por empresa, orden-lacado.jsx) / "Marcar lacado recibido"
// Agrupado por proveedor (o por expediente). Exportar por proveedor para mandarlo
// por email. API: /api/demanda (src/routes/demanda.js).
// GUT-272: columna Stock (Almacén) y, en Por pedir, si la línea queda cubierta por el
// stock (repartido de lo más urgente a lo menos) o cuánto falta; "Solo lo que falta"
// oculta las cubiertas.
// ─────────────────────────────────────────────────────

const NC_VISTAS = [
  { k: 'por_pedir', label: 'Por pedir', count: 'por_pedir' },
  { k: 'en_camino', label: 'En camino', count: 'en_camino' },
  { k: 'lacado', label: 'Lacado externo', count: 'lacado' },
];
const ncHoy = () => new Date().toISOString().slice(0, 10);
const ncFecha = (v) => (v ? String(v).slice(0, 10).split('-').reverse().join('/') : '—');
// INC-023: observación de la línea (bom_lineas.observacion) sin el «Cliente: …» que
// pone la importación del Excel antiguo (ese ya sale en la columna del cliente).
const ncObs = (r) => String(r.observacion || '').replace(/^Cliente: [^·]*(·\s*)?/, '').trim();
// Y ese «Cliente: …» es lo único que va en la columna del cliente cuando la línea no tiene otro.
const ncCliObs = (r) => ((String(r.observacion || '').match(/^Cliente: ([^·]*)/) || [])[1] || '').trim();
const ncLs = (k, def) => { try { return localStorage.getItem(k) || def; } catch { return def; } };

const NecesidadesView = ({ onToast }) => {
  const [vista, setVista] = React.useState(() => ncLs('nc_vista', 'por_pedir'));
  const [agrupar, setAgrupar] = React.useState(() => ncLs('nc_agrupar', 'proveedor'));
  const [prov, setProv] = React.useState('');
  const [search, setSearch] = React.useState('');
  const [q, setQ] = React.useState('');
  const [rows, setRows] = React.useState(null);
  const [resumen, setResumen] = React.useState({});
  const [sel, setSel] = React.useState(() => new Set());
  const [asignar, setAsignar] = React.useState('');
  const [busy, setBusy] = React.useState(false);
  const [verOrdenesLac, setVerOrdenesLac] = React.useState(false); // panel "Órdenes emitidas"
  const [lacCreadas, setLacCreadas] = React.useState([]);          // ids recién creadas, resaltadas
  const provs = window.useMatProveedores();
  const [verTotales, setVerTotales] = React.useState(() => ncLs('nc_totales', '0') === '1'); // GUT-261
  React.useEffect(() => { try { localStorage.setItem('nc_totales', verTotales ? '1' : '0'); } catch {} }, [verTotales]);
  const [soloFalta, setSoloFalta] = React.useState(() => ncLs('nc_solo_falta', '0') === '1'); // GUT-272
  React.useEffect(() => { try { localStorage.setItem('nc_solo_falta', soloFalta ? '1' : '0'); } catch {} }, [soloFalta]);

  React.useEffect(() => { try { localStorage.setItem('nc_vista', vista); localStorage.setItem('nc_agrupar', agrupar); } catch {} }, [vista, agrupar]);
  React.useEffect(() => { const t = setTimeout(() => setQ(search.trim()), 250); return () => clearTimeout(t); }, [search]);

  const params = React.useMemo(() => {
    const u = new URLSearchParams({ vista });
    if (prov) u.set('proveedor_id', prov);
    if (q) u.set('search', q);
    if (vista === 'por_pedir' && soloFalta) u.set('solo_falta', '1');
    return u.toString();
  }, [vista, prov, q, soloFalta]);
  const load = React.useCallback(() => {
    API.get(`/api/demanda?${params}`).then(setRows).catch((e) => { setRows([]); onToast(e.message, true); });
    API.get('/api/demanda/resumen').then(setResumen).catch(() => {});
  }, [params]);
  React.useEffect(() => { load(); }, [load]);
  React.useEffect(() => { setSel(new Set()); }, [vista, prov, q, soloFalta]);

  const exportar = (ext, proveedorId) => {
    const u = new URLSearchParams(params);
    if (proveedorId !== undefined) u.set('proveedor_id', proveedorId ?? 'sin');
    const nombre = `${NC_VISTAS.find((v) => v.k === vista).label.toLowerCase().replace(/ /g, '_')}_${ncHoy()}.${ext === 'excel' ? 'xlsx' : 'pdf'}`;
    API.download(`/api/demanda/export/${ext}?${u}`, nombre).catch((e) => onToast(e.message || 'Error al exportar', true));
  };

  const marcar = (ids, on) => setSel((prev) => { const n = new Set(prev); ids.forEach((id) => (on ? n.add(id) : n.delete(id))); return n; });
  const crearPedido = async (ids) => {
    if (!ids.length || busy) return;
    setBusy(true);
    try {
      const r = await API.post('/api/demanda/pedidos', { lineas: ids });
      onToast(`${r.ordenes.length === 1 ? 'Creada' : 'Creadas'} ${r.ordenes.map((o) => `OC ${o.numero}`).join(', ')}: ${ids.length} línea${ids.length === 1 ? '' : 's'} pasan a Pedido ✓`);
      setSel(new Set()); load();
    } catch (e) { onToast(e.message, true); } finally { setBusy(false); }
  };
  const asignarProveedor = async () => {
    if (!asignar || !sel.size) return;
    setBusy(true);
    try {
      const r = await API.put('/api/demanda/lineas/proveedor', { lineas: [...sel], proveedor_id: asignar });
      onToast(`Proveedor asignado a ${r.actualizadas} línea${r.actualizadas === 1 ? '' : 's'} ✓`);
      setAsignar(''); setSel(new Set()); load();
    } catch (e) { onToast(e.message, true); } finally { setBusy(false); }
  };

  // Lacado externo: se marca el proceso de lacado (r.lacado_id), no la línea.
  const lacMarcable = (r) => r.lacado_estado === 'pendiente' || r.lacado_estado === 'en_curso';
  // Misma clave que el servidor: proveedor o, si no hay, el texto sin mayúsculas ni espacios de más.
  const lacEmpresa = (r) => (r.lacado_proveedor_id ? `p${r.lacado_proveedor_id}` : `t${(r.lacado_empresa || '').trim().toLowerCase()}`);
  const crearOrdenLacado = async (procs) => {
    if (!procs.length || busy) return;
    // Si todo va a una misma empresa sale una sola orden: su PDF se abre ya (la pestaña,
    // en el mismo clic para que no la bloquee el navegador).
    const empresas = new Set((rows || []).filter((r) => procs.includes(r.lacado_id)).map(lacEmpresa));
    const w = empresas.size === 1 ? window.open('', '_blank') : null;
    setBusy(true);
    try {
      const r = await API.post('/api/demanda/lacado/ordenes', { procesos: procs });
      onToast(`${r.ordenes.length === 1 ? 'Creada' : 'Creadas'} ${r.ordenes.map((o) => o.numero).join(', ')}: ${procs.length} lacado${procs.length === 1 ? '' : 's'} pasan a En curso ✓`);
      if (w && r.ordenes.length === 1) window.lacAbrirPdf(r.ordenes[0].id, w).catch((e) => onToast(e.message, true));
      else { if (w) w.close(); setVerOrdenesLac(true); }
      setLacCreadas(r.ordenes.map((o) => o.id));
      setSel(new Set()); load();
    } catch (e) { if (w) w.close(); onToast(e.message, true); } finally { setBusy(false); }
  };
  const lacadoRecibido = async (procs) => {
    if (!procs.length || busy) return;
    setBusy(true);
    try {
      const r = await API.post('/api/demanda/lacado/recibido', { procesos: procs });
      onToast(`${r.recibidos} lacado${r.recibidos === 1 ? '' : 's'} recibido${r.recibidos === 1 ? '' : 's'} ✓ · En cada línea queda decidir si lleva otro proceso o ya está preparada`);
      setSel(new Set()); load();
    } catch (e) { onToast(e.message, true); } finally { setBusy(false); }
  };

  // Grupos: proveedor (o empresa de lacado) o expediente/proyecto.
  const grupos = React.useMemo(() => {
    const g = new Map();
    for (const r of rows || []) {
      let key; let titulo; let sub = ''; let provId;
      if (vista === 'lacado') {
        key = `l${(r.lacado_empresa || '').trim() ? lacEmpresa(r) : 'sin'}`; titulo = (r.lacado_empresa || '').trim() || 'Sin empresa de lacado'; provId = r.lacado_proveedor_id;
      } else if (agrupar === 'expediente') {
        const n = r.numero_expediente ? `Exp. ${r.numero_expediente}` : r.proyecto_numero ? `Proyecto ${r.proyecto_numero}` : null;
        key = `e${r.pedido_id || ''}-${r.proyecto_id || ''}`; titulo = n || 'Sin expediente ni proyecto'; sub = r.cliente || '';
      } else {
        key = `p${r.proveedor_id || 'sin'}`; titulo = r.proveedor_nombre || 'Sin proveedor'; provId = r.proveedor_id;
      }
      if (!g.has(key)) g.set(key, { key, titulo, sub, provId, pedidoId: r.pedido_id, proyectoId: r.proyecto_id, rows: [] });
      g.get(key).rows.push(r);
    }
    return [...g.values()];
  }, [rows, vista, agrupar]);

  // INC-001: sin artículo del catálogo no se pide (primero se crea y se enlaza).
  const pedible = (r) => r.estado === 'pendiente' && !r.de_stock && !r.oc_id && !!r.material_id;
  const hoy = ncHoy();
  const vencida = (f) => f && f < hoy;
  const abrirExp = (r) => r.pedido_id && window.dispatchEvent(new CustomEvent('erp:open-expediente', { detail: { pedidoId: r.pedido_id } }));
  const origen = (r) => (
    <div style={{ minWidth: 140 }}>
      {r.numero_expediente
        ? <a className="mono" style={{ cursor: 'pointer' }} onClick={() => abrirExp(r)}>Exp. {r.numero_expediente}</a>
        : r.proyecto_numero ? <span className="mono">Proy. {r.proyecto_numero}</span> : <span className="muted">—</span>}
      {r.cortina && <span className="muted"> · {r.cortina}</span>}
      <div className="muted" style={{ fontSize: 11 }}>
        {r.cliente ? <ClienteLink nombre={r.cliente} pedidoId={r.pedido_id} proyectoId={r.proyecto_id} /> : ncCliObs(r)}
      </div>
    </div>
  );
  const articulo = (r) => (
    <div style={{ minWidth: 200 }}>
      {r.codigo && <span className="mono">{r.codigo} </span>}{r.nombre}
      {!r.material_id && window.MatSinArticulo && <MatSinArticulo style={{ marginLeft: 6 }} />}
      {r.dimensiones && <div className="muted" style={{ fontSize: 11 }}>{r.dimensiones}</div>}
      {/* INC-023: la observación de la línea de material. */}
      {ncObs(r) && <div style={{ fontSize: 11, color: 'var(--ink-2)', whiteSpace: 'normal', maxWidth: 360 }} title="Observación de la línea de material"><span className="muted">Obs.:</span> {ncObs(r)}</div>}
    </div>
  );
  const cantidad = (r) => (r.cantidad != null ? `${Number(r.cantidad)}${r.unidad ? ` ${r.unidad}` : ''}` : '—');
  // GUT-272: stock del artículo en Almacén y, en Por pedir, si esta línea la cubre el stock.
  const ncNum = (n) => Number(n).toLocaleString('es-ES', { maximumFractionDigits: 3 });
  const stockCelda = (r) => {
    if (r.stock == null) return <span className="muted" title="Sin artículo del catálogo: no hay stock que mirar, se pide">—</span>;
    const u = r.unidad ? ` ${r.unidad}` : '';
    const urg = r.fecha_urgencia ? ` Instalación ${ncFecha(r.fecha_urgencia)}.` : '';
    let estado = null;
    if (vista === 'por_pedir') {
      if (r.stock_cubierto) estado = <span className="pill ok" title={`El stock alcanza para esta línea después de repartirlo entre lo más urgente.${urg}`}><span className="d" />Cubierto por stock</span>;
      else if (r.stock_falta != null && r.cantidad != null && r.stock_falta < r.cantidad) estado = <span className="pill warn" title={`El stock solo cubre una parte.${urg}`}><span className="d" />Faltan {ncNum(r.stock_falta)}{u}</span>;
      else if (r.stock > 0) estado = <span className="muted" style={{ fontSize: 11 }} title={`El stock ya lo cubren líneas más urgentes.${urg}`}>Stock comprometido</span>;
    }
    return (
      <div style={{ whiteSpace: 'nowrap' }}>
        <span style={r.stock < 0 ? { color: 'var(--err)' } : r.stock === 0 ? { color: 'var(--ink-3)' } : undefined}>{ncNum(r.stock)}</span>
        {estado && <div>{estado}</div>}
      </div>
    );
  };

  const cabecera = {
    por_pedir: ['', 'Expediente / cliente', 'Artículo', 'Cant.', 'Stock', 'RAL', agrupar === 'expediente' ? 'Proveedor' : null, 'Días', 'Estado'],
    en_camino: ['Expediente / cliente', 'Artículo', 'Cant.', 'Stock', 'OC', 'Pedido', 'Llega', agrupar === 'expediente' ? 'Proveedor' : null, 'Estado'],
    lacado: ['', 'Expediente / cliente', 'Artículo', 'Color', 'Orden', 'Enviado', 'Vuelta', 'Estado'],
  }[vista].filter((h) => h !== null);

  const fila = (r) => {
    if (vista === 'por_pedir') return (
      <tr key={r.id}>
        <td style={{ width: 26 }}>{pedible(r) && <input type="checkbox" checked={sel.has(r.id)} onChange={(e) => marcar([r.id], e.target.checked)} />}</td>
        <td>{origen(r)}</td><td>{articulo(r)}</td><td className="num">{cantidad(r)}</td><td>{stockCelda(r)}</td><td>{r.ral || '—'}</td>
        {agrupar === 'expediente' && <td>{r.proveedor_nombre || <span className="muted">{r.proveedor_texto ? `⚠ ${r.proveedor_texto}` : 'Sin proveedor'}</span>}</td>}
        <td className="num muted">{r.dias_pendiente}</td>
        <td><MaterialEstado linea={r} onChanged={load} onToast={onToast} /></td>
      </tr>
    );
    if (vista === 'en_camino') return (
      <tr key={r.id}>
        <td>{origen(r)}</td><td>{articulo(r)}</td><td className="num">{cantidad(r)}</td><td>{stockCelda(r)}</td>
        <td>{r.oc_id ? <button className="btn ghost sm" onClick={() => window.dispatchEvent(new CustomEvent('erp:open-orden', { detail: { id: r.oc_id } }))}>OC {r.oc_numero}</button> : '—'}</td>
        <td className="muted">{ncFecha(r.fecha_pedido)}</td>
        <td style={vencida(r.fecha_estimada) ? { color: 'var(--err)', fontWeight: 600 } : undefined} title={vencida(r.fecha_estimada) ? 'Tenía que haber llegado' : ''}>{ncFecha(r.fecha_estimada)}</td>
        {agrupar === 'expediente' && <td>{r.proveedor_nombre}</td>}
        <td><MaterialEstado linea={r} onChanged={load} onToast={onToast} /></td>
      </tr>
    );
    return (
      <tr key={r.id}>
        <td style={{ width: 26 }}>{lacMarcable(r) && <input type="checkbox" checked={sel.has(r.lacado_id)} onChange={(e) => marcar([r.lacado_id], e.target.checked)} />}</td>
        <td>{origen(r)}</td><td>{articulo(r)}</td><td style={{ whiteSpace: 'normal', minWidth: 120, maxWidth: 260 }}>{r.lacado_color || '—'}</td>
        <td>{r.lacado_orden_id ? <OrdenLacadoLink id={r.lacado_orden_id} numero={r.lacado_orden_numero} onToast={onToast} /> : <span className="muted">—</span>}</td>
        <td className="muted">{r.lacado_estado === 'pendiente' ? 'Sin enviar' : ncFecha(r.lacado_inicio)}</td>
        <td style={vencida(r.lacado_vuelta) ? { color: 'var(--err)', fontWeight: 600 } : undefined}>{ncFecha(r.lacado_vuelta)}</td>
        <td><MaterialEstado linea={r} onChanged={load} onToast={onToast} /></td>
      </tr>
    );
  };

  const selIds = [...sel];
  const lacSel = vista === 'lacado' ? (rows || []).filter((r) => sel.has(r.lacado_id)) : [];
  const lacPend = lacSel.filter((r) => r.lacado_estado === 'pendiente').map((r) => r.lacado_id);
  const lacFuera = lacSel.filter((r) => r.lacado_estado === 'en_curso').map((r) => r.lacado_id);
  return (
    <div className="view-wrap">
      <div className="page-h">
        <div>
          <h1>Necesidades de compra</h1>
          <div className="sub">Todo el material de todos los expedientes y proyectos: qué falta por pedir, qué está en camino y qué está fuera lacándose.</div>
        </div>
        <div className="page-h-actions">
          <button className="btn" onClick={() => exportar('excel')} title="Una hoja por proveedor"><Icon name="download" /> Excel</button>
          <button className="btn" onClick={() => exportar('pdf')} title="Una página por proveedor, para mandar por email"><Icon name="download" /> PDF</button>
        </div>
      </div>

      <div className="subnav">
        {NC_VISTAS.map((v) => (
          <button key={v.k} className={vista === v.k ? 'on' : ''} onClick={() => setVista(v.k)}>
            {v.label}{resumen[v.count] != null && <span className="count" style={{ marginLeft: 6 }}>{resumen[v.count]}</span>}
          </button>
        ))}
      </div>

      <div className="toolbar">
        <input className="nc-search" placeholder="Buscar artículo, referencia, cliente, expediente u observación…" value={search} onChange={(e) => setSearch(e.target.value)} />
        <select value={prov} onChange={(e) => setProv(e.target.value)}>
          <option value="">{vista === 'lacado' ? 'Todas las empresas' : 'Todos los proveedores'}</option>
          <option value="sin">— Sin {vista === 'lacado' ? 'empresa' : 'proveedor'} —</option>
          {provs.map((p) => <option key={p.id} value={p.id}>{p.label}</option>)}
        </select>
        {vista !== 'lacado' && (
          <div className="seg">
            <button className={agrupar === 'proveedor' ? 'on' : ''} onClick={() => setAgrupar('proveedor')}>Por proveedor</button>
            <button className={agrupar === 'expediente' ? 'on' : ''} onClick={() => setAgrupar('expediente')}>Por expediente</button>
          </div>
        )}
        {vista === 'por_pedir' && (
          <label className="muted" style={{ fontSize: 12, display: 'inline-flex', alignItems: 'center', gap: 5, cursor: 'pointer' }}
            title="Oculta las líneas que el stock del almacén ya cubre (repartido de lo más urgente a lo menos)">
            <input type="checkbox" checked={soloFalta} onChange={(e) => setSoloFalta(e.target.checked)} /> Solo lo que falta
          </label>
        )}
        <div className="tb-spacer" />
        <button className={`btn sm ${verTotales ? 'primary' : ''}`} onClick={() => setVerTotales((v) => !v)} title="Suma de cantidades por artículo de lo que ves en esta pestaña"><Icon name="layers" /> Totales por artículo</button>
        {vista === 'lacado' && <button className={`btn sm ${verOrdenesLac ? 'primary' : ''}`} onClick={() => setVerOrdenesLac((v) => !v)} title="Órdenes de lacado ya emitidas, para volver a imprimirlas">Órdenes emitidas</button>}
        {vista === 'por_pedir' && resumen.cubiertas_stock > 0 && (
          <span className="pill ok" title={soloFalta ? 'Ocultas por «Solo lo que falta»' : 'Líneas que el stock del almacén ya cubre'}>
            <span className="d" />{resumen.cubiertas_stock} cubierta{resumen.cubiertas_stock === 1 ? '' : 's'} por stock{soloFalta ? ' (ocultas)' : ''}
          </span>
        )}
        {vista === 'por_pedir' && resumen.sin_proveedor > 0 && <span className="pill warn"><span className="d" />{resumen.sin_proveedor} sin proveedor</span>}
        {vista === 'en_camino' && resumen.retrasados > 0 && <span className="pill err"><span className="d" />{resumen.retrasados} retrasado{resumen.retrasados === 1 ? '' : 's'}</span>}
      </div>

      {vista === 'por_pedir' && sel.size > 0 && (
        <div className="nc-bulk">
          <strong>{sel.size} marcada{sel.size === 1 ? '' : 's'}</strong>
          <button className="btn primary sm" disabled={busy} onClick={() => crearPedido(selIds)} title="Crea una orden a proveedor por cada proveedor">Crear pedido</button>
          <span className="muted">o asignar proveedor:</span>
          <select value={asignar} onChange={(e) => setAsignar(e.target.value)}>
            <option value="">— Elegir —</option>
            {provs.map((p) => <option key={p.id} value={p.id}>{p.label}</option>)}
          </select>
          <button className="btn sm" disabled={busy || !asignar} onClick={asignarProveedor}>Asignar</button>
          <button className="btn ghost sm" onClick={() => setSel(new Set())}>Quitar marcas</button>
        </div>
      )}

      {vista === 'lacado' && sel.size > 0 && (
        <div className="nc-bulk">
          <strong>{sel.size} marcado{sel.size === 1 ? '' : 's'}</strong>
          {lacPend.length > 0 && (
            <button className="btn primary sm" disabled={busy} onClick={() => crearOrdenLacado(lacPend)}
              title="Crea una orden de lacado por empresa con los lacados sin enviar, y los pasa a En curso">
              Crear orden de lacado{lacPend.length !== sel.size ? ` (${lacPend.length} sin enviar)` : ''}
            </button>
          )}
          {lacFuera.length > 0 && (
            <button className={`btn sm ${lacPend.length ? '' : 'primary'}`} disabled={busy} onClick={() => lacadoRecibido(lacFuera)}
              title="El material ha vuelto de lacar: completa el lacado">
              Marcar lacado recibido{lacFuera.length !== sel.size ? ` (${lacFuera.length} en lacado)` : ''}
            </button>
          )}
          <button className="btn ghost sm" onClick={() => setSel(new Set())}>Quitar marcas</button>
        </div>
      )}

      {vista === 'lacado' && verOrdenesLac && <OrdenesLacadoPanel proveedorId={prov} version={rows} resaltar={lacCreadas} onToast={onToast} />}

      {verTotales && <MatTotalesPanel url={`/api/demanda/totales?${params}`} version={rows} onToast={onToast} />}

      {rows === null && <p className="muted">Cargando…</p>}
      {rows && rows.length === 0 && (
        <div className="empty-state muted" style={{ padding: 40, textAlign: 'center' }}>
          {vista === 'por_pedir' ? (soloFalta && resumen.cubiertas_stock > 0 ? 'Todo lo pendiente con estos filtros está cubierto por stock.' : 'No queda nada por pedir con estos filtros.') : vista === 'en_camino' ? 'No hay nada en camino.' : 'No hay nada lacándose fuera.'}
        </div>
      )}

      {grupos.map((g) => {
        const pedibles = vista === 'por_pedir' ? g.rows.filter(pedible).map((r) => r.id)
          : vista === 'lacado' ? g.rows.filter(lacMarcable).map((r) => r.lacado_id) : [];
        const todas = pedibles.length > 0 && pedibles.every((id) => sel.has(id));
        const lacSinEnviar = vista === 'lacado' ? g.rows.filter((r) => r.lacado_estado === 'pendiente').map((r) => r.lacado_id) : [];
        const lacMarcados = lacSinEnviar.filter((id) => sel.has(id));
        return (
          <div key={g.key} className="nc-grupo">
            <div className="nc-grupo-h">
              {(vista === 'por_pedir' || vista === 'lacado') && pedibles.length > 0 && (
                <input type="checkbox" checked={todas} onChange={(e) => marcar(pedibles, e.target.checked)} title="Marcar todo el grupo" />
              )}
              <strong>{g.titulo}</strong>
              {g.sub && <span className="muted"><ClienteLink nombre={g.sub} pedidoId={g.pedidoId} proyectoId={g.proyectoId} /></span>}
              <span className="muted">· {g.rows.length} línea{g.rows.length === 1 ? '' : 's'}</span>
              <div className="tb-spacer" />
              {vista === 'por_pedir' && agrupar === 'proveedor' && g.provId && pedibles.length > 0 && (
                <button className="btn primary sm" disabled={busy} onClick={() => crearPedido(pedibles.filter((id) => !sel.size || sel.has(id)))}
                  title={sel.size ? 'Pide solo las marcadas de este proveedor' : 'Pide todas las líneas de este proveedor'}>
                  Crear pedido{sel.size ? ' (marcadas)' : ''}
                </button>
              )}
              {vista === 'lacado' && g.key !== 'lsin' && lacSinEnviar.length > 0 && (
                <button className="btn primary sm" disabled={busy} onClick={() => crearOrdenLacado(lacMarcados.length ? lacMarcados : lacSinEnviar)}
                  title={lacMarcados.length ? 'Orden de lacado con los marcados de esta empresa' : 'Orden de lacado con todo lo que falta por enviar a esta empresa'}>
                  Crear orden de lacado{lacMarcados.length ? ' (marcados)' : ''}
                </button>
              )}
              {vista === 'lacado' && g.key === 'lsin' && <span className="muted" style={{ fontSize: 12 }}>Pon la empresa de lacado en cada línea para poder crear la orden</span>}
              {vista === 'por_pedir' && agrupar === 'proveedor' && !g.provId && <span className="muted" style={{ fontSize: 12 }}>Asigna proveedor para poder pedirlas</span>}
              {agrupar === 'proveedor' || vista === 'lacado' ? (
                <>
                  <button className="btn ghost sm" onClick={() => exportar('excel', g.provId || null)} title="Excel de este proveedor"><Icon name="download" size={12} /> Excel</button>
                  <button className="btn ghost sm" onClick={() => exportar('pdf', g.provId || null)} title="PDF de este proveedor"><Icon name="download" size={12} /> PDF</button>
                </>
              ) : null}
            </div>
            <div className="tbl-wrap"><div className="tbl-scroll">
              <table className="tbl tbl-compact">
                <thead><tr>{cabecera.map((h, i) => <th key={i}>{h}</th>)}</tr></thead>
                <tbody>{g.rows.map(fila)}</tbody>
              </table>
            </div></div>
          </div>
        );
      })}
    </div>
  );
};

window.NecesidadesView = NecesidadesView;
