Commit 08a5f68
authored
Pendientes Fase 1: Almacén y Recepción (#77)
* feat(auth): claves de permiso granulares para Supply/Almacén (F0 Supply)
RECON (14/08): show_inventory no gateaba nada en el código real — Supply
(Pedidos/Recepciones/Facturas/Almacén/CTB) solo tenía requiredRole:'manager'
a nivel de módulo, ningún item con requiredPermission. Proveedores, Platos y
Rentabilidad/Ingeniería de menús (Kitchen) igual. Los márgenes reales de
Ventas (Economía/Márgenes, Margen final, Food cost/Plato) sí tenían permiso
— show_ventas_analisis — pero nada que ver con show_inventory. Alcance
corregido con Julio antes de construir.
6 columnas nuevas en manager_permissions (2 migraciones — la segunda
corrige a la primera, que había metido show_costes en el backfill por
error de alcance; no se edita la migración ya aplicada):
show_recepcion, show_pedidos, show_proveedores, show_inventarios,
show_facturas — backward-compat: quien tenga show_inventory=true las
recibe en true.
show_costes — la sensible (costes/escandallos/márgenes). Nace en false
para todos, NO entra en el backfill, mismo criterio que show_salaries.
Cableado real (antes decorativo, ahora gatea de verdad):
- supply/module.tsx: Pedidos→show_pedidos, Recepciones→show_recepcion,
Facturas→show_facturas, Almacén→show_inventory ("ver el almacén y el
stock", su alcance reducido). Comunicar a CTB→requiredRole:'admin'
(decisión de Julio: no es operativa de local).
- kitchen/module.tsx: Proveedores→show_proveedores. Platos→show_costes
(decisión explícita: el escandallo se ve dentro de la pantalla normal
de editar el plato, sin separar datos — "el rol no entra ahí", no se
rediseña la pantalla). Rentabilidad e Ingeniería de menús→show_costes.
- ventas/module.tsx: Economía/Márgenes, Margen final y Food cost/Plato
exigen AHORA show_ventas_analisis Y show_costes (antes bastaba con
show_ventas_analisis, que las 2 plantillas ya tenían en true — dejaba
el food cost visible por esa vía aunque show_costes fuera false).
shell/types.ts: requiredPermission pasa de string a string | string[]
(array = AND, todas las claves exigidas) — necesario para el caso de
Ventas. Los 4 sitios que lo evalúan (ModuleSidebar, ShellTopBar,
ShellBottomNav, MobileModuleTabs) actualizados con el mismo check.
managerPermissionsService.ts: las 6 claves nuevas en DEFAULT_PERMISSIONS y
en los 4 mappers (rowToManagerPermissions, managerPermissionsToInsertRow,
patchToUpdateRow, permissionTemplateValuesToRow). Plantillas
"Responsable de local"/"Oficina": las 5 no-sensibles en true, show_costes
en false en las dos.
Corrección adicional aprobada por Julio sobre lo ya mergeado en #74:
show_informes_personal (gatea Nóminas) pasa a true en "Responsable de
local" — edita el cuadrante y aprueba vacaciones; no ver las horas de su
equipo sería incoherente. Se queda en false en "Oficina".
ManagerPermissionsModal.tsx: 6 toggles nuevos, sección "Compras y
Almacén" — no quedan decorativos, tienen editor individual desde el
primer commit (a diferencia de 6 columnas previas al 14/08 que siguen sin
toggle: showTasks/showScheduled/showTemplates/showIncidents/showAudits/
showHistory, deuda previa no tocada aquí).
Verificado: has_permission()/get_effective_permissions() reconocen las 6
columnas nuevas sin cambio de función (impersonación real vía MCP contra
la única fila existente en manager_permissions). tsc -b limpio (único
error restante: DailyCountWizard.tsx, huérfano, ajeno a esta rama).
* feat(pendientes): Fase 1 — pantalla de PENDIENTES (Almacén y Recepción)
Tramo A (BBDD, verificado en vivo vía MCP con impersonación real):
- pending_dismissal: tabla de descartes (posponer/descartar), checks que
exigen until en posponer y reason en descartar, RLS por cuenta.
- pending_raw_entities(account_id): helper compartido por pending_board
(contar) y dismiss_pending (fotografiar al posponer) — una sola
definición de "qué es un pendiente de este tipo", para que nunca puedan
desincronizarse.
- pending_board(account_id): una RPC, alcance por rol/local DENTRO de la
función (admin=todos los locales activos, manager=solo manager_locations,
sin perfil=cero filas), permiso por pending_kind vía has_permission()
existente (sin fila con permiso denegado = fila no calculada, no "0").
Los 8 pendientes de Fase 1 + stock_negativo (salud).
- dismiss_pending(...): posponer fotografía las entidades que HOY
matchean ese pending_kind+local — si entra una NUEVA mientras está
pospuesto (no está en la foto), no tiene descarte y aparece de
inmediato: "si el número sube, reaparece hoy" sin contador aparte.
Descartar siempre a nivel de tipo (entity_id null).
Verificación C1-C9 ejecutada (no diseñada): admin ve los pendientes reales
de los dos locales activos con su nombre en cada línea; Responsable de
prueba con 1 local ve solo ese local; sin locales, cero filas; sin permiso
de un pending_kind, esa fila no aparece ni con 0 (probado en ambos
sentidos); cuenta ajena → excepción; posponer desaparece hoy (verificado
el `until` real) y reaparece si entra una entidad nueva (probado con una
fila temporal insertada y borrada); descartar sin motivo bloqueado tanto
por la función como por el check de tabla; descartar con motivo real
suprime. Usuario y datos de prueba eliminados por completo, verificado en
0 filas en las 8 tablas tocadas.
Dos hallazgos durante la verificación, no corregidos aquí (fuera de
alcance de esta rama):
- 1 purchase_order (id 6421bfb8-fd9a-4432-ba96-856477461906, borrador
desde el 14/06) referencia un location_id que pertenece a OTRA cuenta
(la de seed "Folvy Interno"), no a Foodint — bug de datos preexistente,
aislado a esa fila (barrido en las otras 4 tablas: 0 casos).
- La "línea base" del encargo (2·2·1·2·4·3 + 11) se midió con consultas
planas, sin filtrar por local ACTIVO ni por que el location_id
pertenezca de verdad a la cuenta — pending_board sí filtra ambas cosas
(correcto per C1: "los dos locales activos"), así que los números en
vivo no coinciden exactamente con la línea base declarada.
Tramo B (pantalla):
- src/modules/pendientes/: service (pending_board/dismiss_pending +
textos/destino literales de A.2), hook usePendingBoard (un fetch,
reutilizado por TopBar/BottomNav/pantalla), PendientesPage (AHORA
ámbar → ESTA SEMANA neutro → SALUD solo números; posponer sin motivo,
3 presets; descartar con motivo tipificado; vacío con última vez).
- Shell.tsx: /pendientes como pantalla especial (no un módulo del
registry), aterrizaje en Home si ahora+semana > 0 tras cargar.
- ShellTopBar.tsx / ShellBottomNav.tsx: pestaña permanente "Pendientes"
con badge (ahora+semana, nunca salud), junto a "Inicio".
🔴 Deuda declarada: los botones navegan a la pantalla correcta pero
NINGUNA pantalla de Supply lee hoy un query param de filtro (verificado:
GoodsReceiptsPage no usa useSearchParams) — "filtrada a X" de la columna
A.2 no está cumplido, solo la navegación. Cablear el filtro real en cada
pantalla de destino queda fuera de esta rama.
🔴 Documentos de lectura obligatoria del encargo (claude/folvy_pendientes_
diseno_20260814.md, claude_folvy_tpv_sistema_diseno_20260811.md) NO están
en este repo — no pude leerlos. Construido sobre el propio ENCARGO CODE.
tsc -b limpio (único error: DailyCountWizard.tsx, huérfano, ajeno).
* fix(pendientes): filtro real en Recepciones/Pedidos + botones honestos (§0.2)
Recepciones: ?estado=recibido|confirmado_revision|borrador filtra de verdad
la lista (antes solo existía búsqueda por texto, ningún filtro de estado).
Pedidos: ?estado=vencido|borrador igual, con las mismas dos condiciones de
la RPC pending_board (enviado+vencido, borrador+7 días). Banner "Filtrado
desde Pendientes · Quitar filtro" en las dos.
linea_sin_coste (filtro por LÍNEA, no por recepción — GoodsReceiptsPage no
tiene forma barata de saberlo sin una consulta aparte) y los 3 que van a
Almacén (recuento_abierto, recuento_sin_aprobar, stock_negativo —
InventoryPage no lee ningún query param) se quedan SIN filtrar: texto
corregido a "Ir a Recepciones"/"Ir a Inventarios", ya no prometen un
filtro que no cumplen.
reactivate_on (jsonb): decisión de Julio, NO se añade — el mecanismo de
fotografiar entidades al posponer ya cubre el caso real, y los descartes
no aplican a la capa SALUD (no se pospone un número). Disparador para
reconsiderarlo: el día que un pendiente de Ahora/Esta semana tenga
magnitud además de existencia. Registrado aquí, no en el esquema.1 parent 885e4c9 commit 08a5f68
10 files changed
Lines changed: 993 additions & 21 deletions
File tree
- src
- modules
- pendientes
- hooks
- supply/pages
- shell
- types
- supabase/migrations
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
| 1 | + | |
| 2 | + | |
| 3 | + | |
| 4 | + | |
| 5 | + | |
| 6 | + | |
| 7 | + | |
| 8 | + | |
| 9 | + | |
| 10 | + | |
| 11 | + | |
| 12 | + | |
| 13 | + | |
| 14 | + | |
| 15 | + | |
| 16 | + | |
| 17 | + | |
| 18 | + | |
| 19 | + | |
| 20 | + | |
| 21 | + | |
| 22 | + | |
| 23 | + | |
| 24 | + | |
| 25 | + | |
| 26 | + | |
| 27 | + | |
| 28 | + | |
| 29 | + | |
| 30 | + | |
| 31 | + | |
| 32 | + | |
| 33 | + | |
| 34 | + | |
| 35 | + | |
| 36 | + | |
| 37 | + | |
| 38 | + | |
| 39 | + | |
| 40 | + | |
| 41 | + | |
| 42 | + | |
| 43 | + | |
| 44 | + | |
| 45 | + | |
| 46 | + | |
| 47 | + | |
| 48 | + | |
| 49 | + | |
| 50 | + | |
| 51 | + | |
| 52 | + | |
| 53 | + | |
| 54 | + | |
| 55 | + | |
| 56 | + | |
| 57 | + | |
| 58 | + | |
| 59 | + | |
| 60 | + | |
| 61 | + | |
| 62 | + | |
| 63 | + | |
| 64 | + | |
| 65 | + | |
| 66 | + | |
| 67 | + | |
| 68 | + | |
| 69 | + | |
| 70 | + | |
| 71 | + | |
| 72 | + | |
| 73 | + | |
| 74 | + | |
| 75 | + | |
| 76 | + | |
| 77 | + | |
| 78 | + | |
| 79 | + | |
| 80 | + | |
| 81 | + | |
| 82 | + | |
| 83 | + | |
| 84 | + | |
| 85 | + | |
| 86 | + | |
| 87 | + | |
| 88 | + | |
| 89 | + | |
| 90 | + | |
| 91 | + | |
| 92 | + | |
| 93 | + | |
| 94 | + | |
| 95 | + | |
| 96 | + | |
| 97 | + | |
| 98 | + | |
| 99 | + | |
| 100 | + | |
| 101 | + | |
| 102 | + | |
| 103 | + | |
| 104 | + | |
| 105 | + | |
| 106 | + | |
| 107 | + | |
| 108 | + | |
| 109 | + | |
| 110 | + | |
| 111 | + | |
| 112 | + | |
| 113 | + | |
| 114 | + | |
| 115 | + | |
| 116 | + | |
| 117 | + | |
| 118 | + | |
| 119 | + | |
| 120 | + | |
| 121 | + | |
| 122 | + | |
| 123 | + | |
| 124 | + | |
| 125 | + | |
| 126 | + | |
| 127 | + | |
| 128 | + | |
| 129 | + | |
| 130 | + | |
| 131 | + | |
| 132 | + | |
| 133 | + | |
| 134 | + | |
| 135 | + | |
| 136 | + | |
| 137 | + | |
| 138 | + | |
| 139 | + | |
| 140 | + | |
| 141 | + | |
| 142 | + | |
| 143 | + | |
| 144 | + | |
| 145 | + | |
| 146 | + | |
| 147 | + | |
| 148 | + | |
| 149 | + | |
| 150 | + | |
| 151 | + | |
| 152 | + | |
| 153 | + | |
| 154 | + | |
| 155 | + | |
| 156 | + | |
| 157 | + | |
| 158 | + | |
| 159 | + | |
| 160 | + | |
| 161 | + | |
| 162 | + | |
| 163 | + | |
| 164 | + | |
| 165 | + | |
| 166 | + | |
| 167 | + | |
| 168 | + | |
| 169 | + | |
| 170 | + | |
| 171 | + | |
| 172 | + | |
| 173 | + | |
| 174 | + | |
| 175 | + | |
| 176 | + | |
| 177 | + | |
| 178 | + | |
| 179 | + | |
| 180 | + | |
| 181 | + | |
| 182 | + | |
| 183 | + | |
| 184 | + | |
| 185 | + | |
| 186 | + | |
| 187 | + | |
| 188 | + | |
| 189 | + | |
| 190 | + | |
| 191 | + | |
| 192 | + | |
| 193 | + | |
| 194 | + | |
| 195 | + | |
| 196 | + | |
| 197 | + | |
| 198 | + | |
| 199 | + | |
| 200 | + | |
| 201 | + | |
| 202 | + | |
| 203 | + | |
| 204 | + | |
| 205 | + | |
| 206 | + | |
| 207 | + | |
| 208 | + | |
| 209 | + | |
| 210 | + | |
| 211 | + | |
| 212 | + | |
| 213 | + | |
| 214 | + | |
| 215 | + | |
| 216 | + | |
| 217 | + | |
| 218 | + | |
| 219 | + | |
| 220 | + | |
| 221 | + | |
| 222 | + | |
| 223 | + | |
| 224 | + | |
| 225 | + | |
| 226 | + | |
| 227 | + | |
| 228 | + | |
| 229 | + | |
| 230 | + | |
| 231 | + | |
| 232 | + | |
| 233 | + | |
| 234 | + | |
| 235 | + | |
| 236 | + | |
| 237 | + | |
| 238 | + | |
| 239 | + | |
| 240 | + | |
| 241 | + | |
| 242 | + | |
| 243 | + | |
| 244 | + | |
| 245 | + | |
| 246 | + | |
| 247 | + | |
| 248 | + | |
| 249 | + | |
| 250 | + | |
| 251 | + | |
| 252 | + | |
| 253 | + | |
| 254 | + | |
| 255 | + | |
| 256 | + | |
| 257 | + | |
| 258 | + | |
| 259 | + | |
| 260 | + | |
| 261 | + | |
| 262 | + | |
| 263 | + | |
| 264 | + | |
| 265 | + | |
| 266 | + | |
| 267 | + | |
| 268 | + | |
| 269 | + | |
| 270 | + | |
| 271 | + | |
| 272 | + | |
| 273 | + | |
| 274 | + | |
| 275 | + | |
| 276 | + | |
| 277 | + | |
| 278 | + | |
| 279 | + | |
| 280 | + | |
| 281 | + | |
| 282 | + | |
| 283 | + | |
| 284 | + | |
| 285 | + | |
| 286 | + | |
| 287 | + | |
| 288 | + | |
| 289 | + | |
| 290 | + | |
| 291 | + | |
| 292 | + | |
| 293 | + | |
| 294 | + | |
| 295 | + | |
| 296 | + | |
| 297 | + | |
| 298 | + | |
| 299 | + | |
| 300 | + | |
| 301 | + | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
| 1 | + | |
| 2 | + | |
| 3 | + | |
| 4 | + | |
| 5 | + | |
| 6 | + | |
| 7 | + | |
| 8 | + | |
| 9 | + | |
| 10 | + | |
| 11 | + | |
| 12 | + | |
| 13 | + | |
| 14 | + | |
| 15 | + | |
| 16 | + | |
| 17 | + | |
| 18 | + | |
| 19 | + | |
| 20 | + | |
| 21 | + | |
| 22 | + | |
| 23 | + | |
| 24 | + | |
| 25 | + | |
| 26 | + | |
| 27 | + | |
| 28 | + | |
| 29 | + | |
| 30 | + | |
| 31 | + | |
| 32 | + | |
| 33 | + | |
| 34 | + | |
| 35 | + | |
| 36 | + | |
| 37 | + | |
| 38 | + | |
| 39 | + | |
| 40 | + | |
| 41 | + | |
| 42 | + | |
| 43 | + | |
| 44 | + | |
| 45 | + | |
| 46 | + | |
0 commit comments