From b99630ba00fe81dfda1aad4a73b217a8d6b636d6 Mon Sep 17 00:00:00 2001 From: "Efrain (Helgen)" Date: Wed, 21 Oct 2026 11:33:31 -0600 Subject: [PATCH] Resumen de cobranza: ordenar por moneda antes que por saldo; prueba en PRUEBAS completa (CLAUDE.md) Co-Authored-By: Claude Opus 5.5 --- CLAUDE.md | 18 ++++++++++++------ Code.js | 5 +++-- tests/cobranza.test.js | 5 +++++ 3 files changed, 20 insertions(+), 8 deletions(-) diff --git a/CLAUDE.md b/CLAUDE.md index dd66057..c9947d1 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -478,8 +478,8 @@ Compras: `ROL_COMPRAS` (correos separados por coma: efrain@, tania@, leo@; cread - **Cancelar pago:** rol de cobranza, con motivo; el pago queda como Cancelado (nunca se borra) y deja de contar. - **Resumen de cobranza** (construido 21/10/2026; decisiones del usuario): pantalla inicial de la pestaña Cobranza. Totales por moneda (nunca MXN + USD): contratado con IVA, cobrado, por cobrar, avance, proyectos con saldo y margen sin IVA. Tabla por - proyecto: contratado, cobrado, saldo, avance, siguiente etapa por cobrar, último pago, costo de órdenes y margen; firmados del - mayor saldo al menor y luego los **"Por firmar"** (aceptada sin firmar: se muestran pero **no suman** a los totales). Los + proyecto: contratado, cobrado, saldo, avance, siguiente etapa por cobrar, último pago, costo de órdenes y margen; firmados por + moneda (MXN, USD) y del mayor saldo al menor (nunca se comparan saldos de monedas distintas) y luego los **"Por firmar"** (aceptada sin firmar: se muestran pero **no suman** a los totales). Los proyectos **Cancelados no aparecen** (no deberían tener contrato; si lo tienen, se excluyen). Filtros (búsqueda, moneda, línea, solo con saldo) solo para la tabla; los totales son de todos. **Descargar CSV** de la tabla filtrada (UTF-8 con BOM para Excel; texto que empiece con `= + - @` con apóstrofo). Solo lee: no escribe en ningún libro. @@ -627,10 +627,16 @@ El commit y el push no publican nada: el equipo sigue usando la versión anterio **Revisión en el cotizador real (21/10/2026, Claude in Chrome, sin crear nada):** sesión sin errores, pestañas Cobranza y Compras visibles con los dos roles, Compras sin proyectos ("No hay proyectos activos con contrato firmado": en la hoja real ningún contrato está firmado), vista de cobranza de `PRY-2026-0001` (Cancelado) carga con `margen: null`. Libro de compras vacío. -- **Resumen de cobranza: construido el 21/10/2026, SIN PUBLICAR** (código y pruebas en Node; revisado en local con datos de - ejemplo). Falta: prueba en PRUEBAS (`PRY-2026-0003`/`0004` tienen pagos y órdenes; tú sin cobranza = `pruebasComprasSinCobranza()`), - `clasp push` + comprobar, `clasp deploy` (@9), `wrangler deploy` y revisión en el cotizador real. Solo lee: no requiere respaldo - ni permisos nuevos de Google. +- **Resumen de cobranza: construido el 21/10/2026, SIN PUBLICAR.** Probado en PRUEBAS el 21/10/2026 (Claude in Chrome, sesión del + usuario; deployment de prueba `AKfycbz3DZuN…`, ya **retirado**, 404). R1 (con cobranza): totales MXN 11,600 / 8,000 / 3,600 (69 %), + margen 5,150 (51.5 %); USD 5,800 / 1,100 / 4,700 (19 %), margen 4,900 (98 %); cada renglón igual a la vista de su proyecto; pago + cancelado excluido; clic en renglón, "← Resumen", filtros y texto del CSV correctos. Se encontró y corrigió el orden (comparaba + saldos de MXN y USD; prueba en `cobranza.test.js`). El botón "Descargar CSV" no lo usó Claude (descargar pide permiso del + usuario). R2 (`pruebasComprasSinCobranza()`, efrain@ sin cobranza): sin pestaña y `resumenCobranzaGeneral` → `PERMISO`. + PRUEBAS quedó en la ronda C2 (efrain@ con compras, sin cobranza). Falta: `clasp push` + comprobar, `clasp deploy` (@9), + `wrangler deploy` y revisión en el cotizador real. Solo lee: no requiere respaldo ni permisos nuevos de Google. +- Al probar con Claude in Chrome, un clic por `ref` en la pestaña Cobranza no se aplicó (la página siguió en Nueva cotización); + por coordenadas sí. Si una acción "no responde", revisar primero qué pestaña está visible antes de buscar un error en el código. - Tania y Leo (rol de compras) no se han probado con sus cuentas reales; la primera orden real será también la primera prueba de PDF en la carpeta real. - Subcarpetas "Órdenes de compra" de los proyectos viejos: quedan vacías y sin uso. Si el usuario lo pide, comprobar con el diff --git a/Code.js b/Code.js index 4fa1ae9..76fa3e7 100644 --- a/Code.js +++ b/Code.js @@ -2484,7 +2484,7 @@ function costosDeOrdenes(ordenes, monedaContrato) { * proyectos, ordenes}. Los proyectos Cancelados no aparecen. Un renglón por contrato: "Firmado" o "Por firmar" (aceptada sin * firmar: se muestra pero no suma a los totales). Pagado y saldo salen de resumenCobranza (lo mismo que la vista del proyecto); * margen = contratado sin IVA − órdenes de compra no canceladas. Totales por moneda, solo de contratos firmados: nunca se suman - * MXN y USD. Renglones: firmados primero, del mayor saldo al menor; luego los por firmar. + * MXN y USD. Renglones: firmados primero (por moneda y del mayor saldo al menor); luego los por firmar. */ function resumenGeneralCobranza(d) { const may = s => String(s || '').trim().toUpperCase(); @@ -2526,8 +2526,9 @@ function resumenGeneralCobranza(d) { margenPorcentaje: margen ? margen.porcentaje : null, margenError: margenError, }); }); + // Saldos de monedas distintas no se comparan entre sí: primero por moneda (MXN, USD), luego del mayor saldo al menor renglones.sort((a, b) => (a.estadoContrato === b.estadoContrato ? 0 : a.estadoContrato === 'Firmado' ? -1 : 1) || - b.saldo - a.saldo || (a.folio < b.folio ? -1 : 1)); + (a.moneda === b.moneda ? 0 : a.moneda < b.moneda ? -1 : 1) || b.saldo - a.saldo || (a.folio < b.folio ? -1 : 1)); // Totales por moneda (en centavos para no acumular errores de redondeo) const tot = {}; diff --git a/tests/cobranza.test.js b/tests/cobranza.test.js index fd3d81b..c3a6f4e 100644 --- a/tests/cobranza.test.js +++ b/tests/cobranza.test.js @@ -385,4 +385,9 @@ const pu=P.resumenGeneralCobranza({contratos:[{proyectoFolio:'PRY-1',estado:'Fir ordenes:[{proyectoFolio:'PRY-1',estado:'Emitida',monedaProyecto:'USD',subtotalProyecto:5}]}); assert.deepEqual([pu.proyectos[0].siguienteEtapa,pu.proyectos[0].saldo,pu.proyectos[0].margen,!!pu.proyectos[0].margenError,pu.totales[0].margen], ['Total',116,null,true,null],'cerrado sí aparece; margen con monedas mezcladas se marca'); +// Orden: no compara saldos de monedas distintas (MXN primero, luego USD; dentro de cada una del mayor saldo al menor) +const ct=(f,m,t)=>({proyectoFolio:f,estado:'Firmado',moneda:m,marca:'helgen',total:t,subtotal:t}); +const po=P.resumenGeneralCobranza({contratos:[ct('A','USD',4700),ct('B','MXN',3600),ct('C','MXN',9000),{...ct('D','MXN',99999),estado:'Aceptada'}],esquemas:[],pagos:[], + proyectos:['A','B','C','D'].map(f=>({folio:f,estado:'Activo',nombre:f,cliente:f})),ordenes:[]}); +assert.deepEqual(po.proyectos.map(x=>x.folio),['C','B','A','D']); console.log('OK cobranza');