Skip to content

fix(pharmacy): disponibilidad por producto, marca «sin stock» en gestión, catálogo oficial sin 500 y capas de inventario - #1147

Merged
Leonardolv21 merged 4 commits into
devfrom
itzan/far-cierre-farmacia-dev
Oct 30, 2026
Merged

Leonardolv21 merged 4 commits into
devfrom
itzan/far-cierre-farmacia-dev

Conversation

@Jsaldias39

@Jsaldias39 Jsaldias39 commented Oct 30, 2026 •

Copy link
Copy Markdown
Collaborator

Resumen

Cierre de FAR-05 y FAR-06 en la API. Cuatro cambios.

1. Disponibilidad por producto, no por sede (D-06-3, arreglo de fondo). siteProductAvailabilitySql pasaba la sede entera al libro de inventario en cuanto tenía una posición, y desde ahí un producto publicado después no aparecía en esa sede hasta que alguien le escribiera una. SiteStockWriter lo tapaba rellenando, en la primera escritura, la posición de cada producto con lo que declaraba el catálogo, lo que además congelaba en la sede el conteo de ese día.

Ahora la regla decide cada par (sede, producto): con posición en la sede manda el libro; sin posición, lo declarado en el catálogo. «No tengo» de la farmacia y los borradores siguen sin ofrecerse nunca. El relleno se quita (findProductsWithoutPositionInSite, siteKeepsLedger e initialSiteQuantity quedan sin uso y se borran): «Lo tengo / No lo tengo» y la sincronización escriben solo los productos que tocan. Las tres lecturas que usan la regla (receta entre sucursales, buscador por sede, catálogo público) la toman sin cambios propios.

2. La marca «sin stock en catálogo» en la lectura de gestión. GET /pharmacy/products?managed=true y la respuesta del PATCH de producto sirven outOfStockDeclared. El front la deducía de inStock: false con conteo distinto de cero, que con conteo 0 no se podía distinguir. La lectura pública no la expone.

3. La búsqueda del catálogo oficial respondía 500. MedicineCatalogRepository pasaba arreglos a any(?::text[]) y array_position(?::text[], …); el driver los expande como lista y Postgres respondía con un error de sintaxis. Sin esa búsqueda no se podía dar de alta un producto desde el modal «Nuevo producto». Ahora va un marcador por valor, como reactions.repository.ts.

4. Capas de pharmacy_inventory. integration-read.service.ts (de FAR-07, ya en dev) importaba el tipo PharmacyIntegrationConnections de pharmacy/entities desde la capa de aplicación, y architecture/module-layering.spec.ts fallaba: era el único rojo de la suite completa. El tipo sale ahora del repositorio de lectura.

Commits: 3686ec2d6 (regla y marca), c8c32c837 (catálogo oficial), a697afaf7 (contrato), 2c06bf2b8 (capas).

Decisiones tomadas

  • Se quita el relleno de posiciones en vez de dejarlo junto a la regla nueva: con la regla por producto ya no evita nada, y dejarlo fijaba en cada sede el conteo que el catálogo tenía el día del primer cambio.
  • El contrato se actualiza solo en el campo nuevo. Regenerar openapi/ completo trae además 27 rutas y 48 esquemas de otros cambios que todavía no están en el documento; el campo se escribió tal como lo genera generate-openapi.mjs.
  • El inventario generado (docs/inventario, inventario/) no se regenera en este PR. Regenerarlo toca unos 300 archivos ajenos: la base ya estaba desfasada (números de línea de app.module.ts) y el generador hoy no encuentra el límite de 1 MB del cuerpo en src/main.ts (lo escribe como «no determinado»). Ningún endpoint ni tabla cambia acá.
  • La prueba de integración A1 se corrió contra una base local propia, nunca contra las compartidas.

Casilla documental (obligatoria)

Este PR cambia:

  • Rutas HTTP, DTO o controllers → PharmacyProductReadDto.outOfStockDeclared en openapi/openapi.{json,yaml}; yarn docs:openapi:lint válido (10 avisos).
  • Entidades o el modelo de datos.
  • Eventos de dominio.
  • Permisos, roles o el mecanismo de autorización.
  • Un README de módulo → yarn docs:modules:sync no produjo cambios.
  • Una decisión arquitectónica nueva.
  • Nada de lo anterior.

Verificación

  • yarn build: verde.
  • yarn test src/modules/pharmacy_inventory src/modules/pharmacy src/modules/public: 66 suites, 714 pruebas, verde.
  • yarn typecheck: verde (también después del commit de capas). eslint sobre los archivos tocados: verde.
  • yarn test:integration test/integration/a1-existencias-por-sede.int-spec.ts contra Postgres local: 4/4. La tabla del escenario suma la sede que lleva lotes de unos productos y sigue el catálogo en los demás.
  • Suite completa con cobertura (yarn test:cov) antes del commit de capas: 1124 suites pasan, 1 falla (module-layering.spec.ts, la violación que corrige 2c06bf2b8), 1 omitida; 16 254 pruebas pasan. Después del arreglo, module-layering e inventory-sync 38/38. Cobertura global: 80 % sentencias, 74,31 % ramas, 67,28 % funciones, 80,97 % líneas.
  • Lint completo por grupos: 0 errores; 2 avisos en archivos ajenos a este PR (src/orm/catalog/schemas.catalog.ts, ignorado por patrón, y admissions-expire-sweep.job.spec.ts). yarn lint no usa --max-warnings.
  • yarn docs:validate / yarn docs:build: no se corrieron.

Contra la API levantada en local, con cuentas @alovida.test:

Paso Resultado
Casa central y Sur 2 llevan stock propio (311 y 310 posiciones) —
POST /pharmacies/:id/products de un producto nuevo, publicado y sin conteo 201
GET /pharmacy-inventory/availability del producto nuevo aparece en las cinco sedes, Casa central incluida, sin escribirle posición
PUT …/sites/<Sur 2>/products/<nuevo>/availability {available:false} 200; Sur 2 pasa de 310 a 311 posiciones (solo ese producto)
availability del producto nuevo cuatro sedes, sin Sur 2
GET /pharmacy/products?managed=true FAR06-D stock=4 inStock=false outOfStockDeclared=true; el resto false
GET /pharmacy/products sin managed sin outOfStockDeclared
GET /pharmacy/catalog-products?search=paracetamol antes 500 (error de sintaxis en Postgres), ahora 200

En el navegador (front, mdavila-2001/mantra-core-health#1691): el producto nuevo sale en Casa central como «Como en el catálogo», «Lo tengo» con cantidad y el rechazo 422 en su fila funcionan contra esta API.

…ck» en la lectura de gestión

La regla de existencias por sede pasaba la sede entera al libro en cuanto
tenía una posición: desde ahí, un producto publicado después no aparecía en
esa sede hasta que alguien le escribiera una. El escritor de stock por sede
lo tapaba rellenando la posición de cada producto en la primera escritura,
lo que además congelaba en la sede el conteo que el catálogo tenía ese día.

Ahora decide cada par (sede, producto): con posición en la sede manda el
libro; sin posición, lo declarado en el catálogo. El relleno ya no hace
falta y se quita: «Lo tengo / No lo tengo» y la sincronización escriben solo
los productos que tocan. La prueba de integración A1 cubre la sede que lleva
lotes de unos productos y sigue el catálogo en los demás.

La lectura de gestión (managed=true) y la respuesta del PATCH de producto
sirven `outOfStockDeclared`: el front ya no tiene que deducir la marca de
`inStock: false` con un conteo distinto de cero, que con conteo 0 no se
podía distinguir.
…ndía 500

`MedicineCatalogRepository` pasaba arreglos de JavaScript a `any(?::text[])`
y a `array_position(?::text[], …)`. El driver no los convierte en arreglos
de Postgres: llegaban como una lista separada por comas y la consulta
fallaba con un error de sintaxis. Sin esa búsqueda no se podía dar de alta
un producto desde el modal «Nuevo producto».

Ahora va un marcador por valor (`in (?, ?, …)` y `array[?, …]`), como ya
hace `reactions.repository.ts`; los valores siguen como parámetros. Las
pruebas exigían el arreglo como parámetro: ahora exigen que ningún arreglo
llegue al driver y que haya un valor por marcador.
El campo que suma la lectura con managed=true y la respuesta del PATCH de producto, tal como lo escribe el generador. Solo ese campo: regenerar el contrato entero arrastraría rutas y esquemas de otros cambios que todavía no están en el documento.
…es de pharmacy

integration-read.service.ts (capa de aplicación) importaba el tipo PharmacyIntegrationConnections de pharmacy/entities, y architecture/module-layering.spec.ts lo marcaba: sólo infrastructure/ habla con otros contextos. El tipo sale ahora del repositorio de lectura. Era el único rojo de la suite completa en dev.
@Jsaldias39 Jsaldias39 changed the title fix(pharmacy): disponibilidad por producto, marca «sin stock» en gestión y catálogo oficial sin 500 fix(pharmacy): disponibilidad por producto, marca «sin stock» en gestión, catálogo oficial sin 500 y capas de inventario Oct 30, 2026
@Leonardolv21
Leonardolv21 merged commit 0d9d407 into dev Oct 30, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants