Portal de Proveedores · Mis Envíos PEF

Datos PEF por tipo de proveedor
con histórico de envíos

El proveedor entra al portal y carga los parámetros ambientales que le corresponden — fibra, tela o lavandería — desde un único formulario. Cada vez que reenvía sus datos, la versión queda inmutable en el histórico, y al iniciar uno nuevo el sistema pre-fillea desde el último.

✓ 3 tipos soportados ✓ 3 tests E2E verdes 36 campos de spec Histórico ilimitado Pre-fill automático Vista read-only

Overview

El Portal de Proveedores tiene un único punto de entrada para que cada proveedor cargue sus parámetros ambientales: la página Mis Envíos. Se entra desde el sidebar y aterriza ahí por defecto al loguearse.

El formulario que se abre adapta sus campos al tipo de proveedor:

  • Fibra (Textil San Cristóbal): 12 campos sobre cultivo, riego, fertilizantes, energía, transporte.
  • Tela (Textil San Ramón): 13 campos sobre proceso (hilado, tejido, teñido, acabado), químicos REACH, gramaje y transporte.
  • Lavandería (Industrial Tintotex): 11 campos sobre lavado por kg, temperatura, encogimiento, REACH y transporte ida/vuelta.

Cada envío queda registrado. El proveedor puede re-enviar (corregir o actualizar) cuantas veces sea necesario; el histórico se mantiene completo. Al iniciar un nuevo envío, los campos se pre-llenan con los valores del último envío para minimizar el trabajo.

¿Qué se obtiene? Un flujo de carga PEF que respeta la especificación oficial por tipo de proveedor, con trazabilidad completa de los envíos y mínima fricción para repetir el ciclo mes a mes.

Cómo lo ve el proveedor

El recorrido completo, capturado paso a paso por el test automatizado:

Flujo: proveedor de Tela (Textil San Ramón)

1 Login en el dashboard tela
El proveedor accede con su email y password. Tras login aterriza directamente en Mis Envíos.
Login
2 Mis Envíos — un solo card visible (PEF) tela
El card de WFD (Gestión de Residuos) está oculto por ahora. El de PEF muestra el estado actual.
Mis Envíos
3 Click "Iniciar" → formulario con los 13 campos de tela tela
Cada campo trae su unidad y su nota técnica del spec (e.g. "Desglosado por sub-proceso: hilado, tejido, pre-tratamiento, teñido, acabado").
Formulario tela
4 Llenar y enviar tela
El proveedor completa los campos. Click "Enviar datos" → toast de confirmación → redirige a Mis Envíos.
Formulario lleno
5 Mis Envíos con el envío en el histórico tela
Aparece la fila nueva en la sección "Envíos anteriores" con la fecha y un link "Ver detalle".
Histórico
6 Iniciar otro envío → datos pre-cargados tela
Banner teal "Datos pre-cargados desde tu último envío". El proveedor solo ajusta lo que cambió y reenvía.
Pre-fill
7 Ver detalle de un envío histórico tela
Vista read-only con todos los datos enviados, no editable. Banner azul aclara que es histórico.
Read-only

Flujo: Lavandería (Industrial Tintotex)

8 Mis Envíos del proveedor de lavandería lavandería
Mismo layout que el de tela, pero la única diferencia visual está en el formulario.
Mis Envíos lavandería
9 Formulario con los 11 campos de lavandería lavandería
Campos específicos del sector: temperatura de lavado, consumo por kg lavado, encogimiento PEFCR 1.2%, distancia ida + vuelta.
Formulario lavandería
10 Llenar y enviar (lavandería) lavandería
El proveedor completa los 11 campos y envía. Mismo flujo que tela; la única diferencia son los campos.
Formulario lleno lavandería

Flujo: Fibra (Textil San Cristóbal)

11 Mis Envíos del proveedor de fibra fibra
El usuario proveedor@sancristobal.pe (tipo=fibra / tier=TIER_3) ve el mismo card único PEF — el discriminador es el formulario.
Mis Envíos fibra
12 Formulario con los 12 campos de fibra de algodón fibra
Campos del cultivo: tipo de fibra (Pima/Tangüis/orgánico, certificación GOTS/BCI/OCS), país y región, rendimiento (kg/ha), riego (m³/kg), fertilizantes y pesticidas (kg/ha), energía, emisiones directas (kgCO₂eq/kg), transporte a hilandería, peso de lote.
Formulario fibra
13 Llenar los 12 campos fibra
Mismo patrón de UX que tela y lavandería: cada campo trae su unidad y nota técnica del spec PEFCR.
Formulario fibra lleno
14 Enviar y verificar histórico (fibra) fibra
El submit entra al histórico igual que para los otros tipos: el motor es uno solo, el spec por tipo se aplica al renderizado y a la validación.
Histórico fibra

Casos de borde

¿Qué pasa si el proveedor no tiene órdenes asignadas?

No bloquea el flujo. Mis Envíos PEF es org-level (independiente de OPs). Los proveedores que aún no recibieron órdenes pueden cargar sus parámetros ambientales igual.

¿Y si los campos del spec cambian para un tipo de proveedor?

El seeder seed_supplier_form_configs.py centraliza la definición. Cambiar los FIBRA_FIELDS, TELA_FIELDS o LAVANDERIA_FIELDS y re-correrlo incrementa la version y deja la nueva config activa. Submissions previos no se ven afectados (siguen siendo válidos contra la versión con la que fueron enviados).

¿Y los datos de envíos viejos cuando cambia el spec?

Quedan inmutables. La vista read-only los muestra con el formato existente al momento del envío (schema_version en cada submission).

Resumen técnico

El cambio incluye una migration de schema, una refactorización del seeder de form_configs, un endpoint nuevo (con fallback al legacy), tres métodos nuevos de repo (active draft / histórico / latest), y dos páginas Astro adaptadas. El test E2E con Playwright cubre los dos flujos vivos (tela y lavandería) con screenshots por paso.

Decisión clave: el discriminador de campos pasa de supplier_tier (numérico/genérico) a proveedor.tipo (semántico). El tier se mantiene por compat — el lookup nuevo prefiere tipo y cae a tier si no encuentra.

Componentes tecnológicos

Backend · Modelo + Migration
Columna supplier_tipo

Migration 058 agrega supplier_tipo nullable + index a supplier_form_configs.

  • apps/backend/src/domain/models/supplier_form_config.py
  • apps/backend/src/migrations/versions/o1p58d058_*.py
Backend · Seeder
3 specs × 36 campos

Inserta o actualiza las configs fibra / tela / lavanderia con descriptions del spec.

  • apps/backend/src/seeds/seed_supplier_form_configs.py
Backend · Router
Endpoint /me/{form_key}

Resuelve proveedor.tipo del user y devuelve la config correcta. Cae a /tier/form_key si no encuentra.

  • apps/backend/src/api/routers/supplier_portal/form_configs.py
Backend · Repo + Router
Histórico de submissions

Métodos para draft activo, histórico, último submitted. POST idempotente. GET /history nuevo.

  • apps/backend/src/infrastructure/repositories/supplier_env_submission_repo.py
  • apps/backend/src/api/routers/supplier_portal/submissions.py
Frontend · Astro · Mis Envíos
Card único + tabla histórico

WFD comentado. Card PEF muestra estado del draft. Tabla "Envíos anteriores" debajo con fechas y "Ver detalle".

  • apps/app-astro-dashboard/src/pages/supplier-portal/mis-envios.astro
Frontend · Astro · Formulario
Render dinámico + read-only + pre-fill

Llama a /form-configs/me/pef, soporta ?id=... read-only, pre-fill desde el último submitted, redirige tras enviar.

  • apps/app-astro-dashboard/src/pages/supplier-portal/formulario-pef.astro
Frontend · TS · Lib
API client

Métodos getMyFormConfig y listSubmissionHistory. FieldDef agrega description.

  • apps/app-astro-dashboard/src/lib/supplier-portal.ts
DB · PostgreSQL
3 filas en supplier_form_configs

Seedeadas vía script. Las viejas (supplier_tipo IS NULL) quedan como legacy ignoradas por el endpoint nuevo.

  • tipo=fibra · tier=TIER_3 · 12 campos
  • tipo=tela · tier=TIER_2 · 13 campos
  • tipo=lavanderia · tier=TIER_2 · 11 campos
QA · Playwright
Test E2E + screenshots

Login, navegación, validación de campos por tipo, llenado, envío, verificación de histórico y read-only.

  • project management/proveedores-revision/revisor/tests/supplier-portal.spec.ts

Flujo técnico

1 — El navegador entra a Mis Envíos

SSR de Astro renderiza la página y dispara el script de cliente. El script llama a listSubmissions('pef') para el estado del draft y listSubmissionHistory('pef', 50) para el histórico. Ambas llamadas viajan con la cookie ftl_access_token al backend.

2 — Click "Iniciar" → /supplier-portal/formulario-pef

La página formulario-pef llama a GET /api/v1/supplier-portal/form-configs/me/pef. El backend resuelve proveedor.tipo a partir del org_id del user logueado y devuelve la config con los campos correspondientes (12, 13 o 11).

GET /api/v1/supplier-portal/form-configs/me/pef
Cookie: ftl_access_token=<jwt>
3 — El frontend busca draft activo y/o histórico para pre-fill

Si existe un draft con production_order_id IS NULL AND status='draft', se usa. Si no, se consulta listSubmissionHistory(..., limit=1) y se copia su data_json al form como pre-fill, mostrando un banner aclaratorio.

4 — Envío: POST /submissions + /submit

Si no hay draft, POST /submissions con production_order_id=null crea uno (idempotente: si existe, devuelve el existente). Luego PATCH /submissions/<id> guarda los datos. Finalmente POST /submissions/<id>/submit valida campos requeridos y marca como submitted. Tras 1.2s, redirect a Mis Envíos.

5 — Histórico via /submissions/history

El endpoint GET /api/v1/supplier-portal/submissions/history?form_key=pef&limit=50 devuelve sólo las submissions con status='submitted' AND production_order_id IS NULL, ordenadas por submitted_at DESC.

6 — Read-only: /formulario-pef?id=<sub_id>

La página detecta el query param y carga el submission por id (cualquier estado). Renderiza los campos en formato read-only (label + value + unit + description) sin botones.

Spec de campos por tipo

Origen: Requerimientos_datos_proveedores_pef_dpp_v01. Sintetizado:

Fibra (12 campos · TIER_3)
CampoUnidad
Tipo de fibra de algodóntexto · GOTS/BCI/OCS
País y región de cultivotexto
Rendimiento del cultivokg fibra / hectárea
Consumo de agua de riegom³ / kg fibra
Uso de fertilizanteskg / hectárea
Uso de pesticidas / herbicidaskg / hectárea
Consumo energéticokWh / kg fibra
Fuente de energíatexto
Emisiones directas de campokgCO₂eq / kg fibra
Distancia transporte a hilanderíakm
Modo de transportetexto
Peso del lote despachadokg
Tela (13 campos · TIER_2)
CampoUnidad
Consumo eléctrico total por procesokWh / kg tela
Fuente de energía eléctricatexto
Consumo de gas naturalm³ / kg tela
Consumo de agua por procesom³ / kg tela
Productos químicos utilizadoskg / kg tela
Declaración REACHtexto · listado SVHC
Tasa de pérdida / merma% por sub-proceso
Composición de la tela producida% por fibra
Peso de la tela por metrog/m²
Tipo de tejidotexto
Distancia a Trentokm
Modo de transportetexto
Peso del lote despachadokg
Lavandería (11 campos · TIER_2)
CampoUnidad
Consumo eléctrico por kg de tela lavadakWh / kg
Consumo de gas / vapor por kg lavadam³ / kg
Consumo de agua por kg lavadam³ / kg
Temperatura de lavado°C
Productos químicos utilizadoskg / kg prenda
Declaración REACHtexto · listado SVHC
Tasa de pérdida / encogimiento% (PEFCR 1.2%)
Fuente de energíatexto
Distancia Trento → Lavandería → Trentokm (ida + vuelta)
Modo de transportetexto
Peso del lote procesadokg

Configuración

Migración

cd apps/backend
set -a && source ../../.env && set +a
uv run alembic upgrade head

Seeding de form_configs

uv run python -m src.seeds.seed_supplier_form_configs

Idempotente. Devuelve cantidad de filas creadas o actualizadas. Re-ejecutarlo tras cambiar el spec para subir la versión y dejar activa la nueva config.

Usuarios de prueba

EmailTipoTier
proveedor@sancristobal.pefibraTIER_3
proveedor@sanramon.petelaTIER_2
proveedor@tintotex.com.pelavanderiaTIER_2

Sus passwords se sincronizan con el de Jenny (Tr3nt0.2025!) vía uv run python -m scripts.sync_supplier_test_users.

Test E2E (Playwright)

cd "project management/proveedores-revision/revisor"
npm install
npm run install:browsers
cp .env.example .env   # completar DASHBOARD_PASSWORD
npm test               # corre los 2 escenarios y graba screenshots

Salidas:

  • test-results/screenshots/<NN-name>.png — capturas por paso, numeradas.
  • playwright-report/index.html — reporte detallado con steps y traces.

Para refrescar el reporte ejecutivo, copiar el directorio screenshots/ a ../report/screenshots/.

Issues conocidos / Próximos pasos

Endpoint legacy /form-configs/{tier}/{form_key} sigue disponible

Mantengo el endpoint viejo por compat (otros consumidores podrían usarlo). Una vez confirmado que nada lo necesita, conviene marcar deprecated en su decorator y eventualmente retirarlo.

Filas legacy en supplier_form_configs (supplier_tipo IS NULL)

Hay 2 filas viejas (TIER_2/None/pef y TIER_2/None/wfd) que ya no usa el endpoint /me. Pueden borrarse en un próximo cleanup; por ahora quedan intocadas para evitar romper algún consumidor del legacy.

Card de WFD oculto, no eliminado

El bloque del card de Gestión de Residuos quedó comentado en mis-envios.astro. Para reactivarlo cuando vuelva al alcance, quitar los comentadores HTML y ajustar el grid a 2 columnas.

Spec de campos en código, no en BD

Los campos del formulario viven en el seeder Python, no en una UI admin. Cambios al spec requieren un commit + re-seed. Una "Admin: editar form-config" quedaría pendiente para una iteración futura si es necesario.