Repository navigation
feat: [TESIS-139] show integration status and link products to sales channels - #59
Conversation
- new integrations feature: providers grouped by type with their status, connect/configure form built out of the fields each template declares, test the connection, activate/deactivate and disconnect with confirmation - the connect form shows the field errors of a 422 next to each input, keeps loaded secrets when left blank and never prefills them - product detail gets a sales channels card: linked publications, link by publication id or by the product SKU, unlink with confirmation; only for tenants with the integrations feature - the integrations listing moves to shared/ (dashboard, integrations and inventory read it) and is translated to the domain in camelCase - the HTTP client keeps the field errors of an API rejection Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The OneStock team now loads each company's credentials from the backoffice, so the screen only shows which providers are connected, their status and the connected account. The connection form, the test/activate/disconnect actions and the per-field API errors go away. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
TomasMartin2004
left a comment
There was a problem hiding this comment.
Aprobado, y lo mergeo después de proyecto-api#98 como pedís en el cuerpo. Verificado en local sobre la rama, no de lectura.
| Check | Resultado |
|---|---|
npm run test |
683 pruebas · 74 archivos · 0 fallas |
npm run lint |
0 advertencias |
npm run build |
limpio |
| CI | en verde |
Lo que fui a buscar primero
Que no quede ninguna llamada al contrato que la API elimina. Es el riesgo real de este par de PRs: el back borra PUT /integrations/:service_id, el DELETE y el POST .../test. Grepeé client.put y client.delete contra todo lo que toque integraciones: ninguna. La pantalla quedó de sólo lectura de verdad, no «sin el botón pero con el código».
Que shared/ no importe de features/. La Regla de Dos justifica subir el listado a shared/, pero subirlo mal rompe la regla de dependencia de la arquitectura. Verificado: cero imports de features dentro de shared/.
Dientes. Saqué el filtro integration.isActive de linkableChannels y se puso en rojo offers only the connected, active sales channels where the product is not published, y sólo ése. La regla está sostenida por un test, no por el orden de los &&.
Lo que me gustó
- El comentario de
shared/api/integrations.tssobre el nombre. «El endpoint NO devuelvecompany_integrations, devuelve las plantillas conectables con el estado encima, por eso el identificador esservice_id». Esa confusión es exactamente la que iba a tener el próximo que abra el archivo. lastSyncedAtcableado y opcional, con el motivo escrito: el back todavía no tiene la columna, y el widget ya queda listo para encenderse solo. Es la forma correcta de dejar algo a medias — declarado, no olvidado.- Sacar el formulario de conexión en el segundo commit cuando se tomó la decisión del ADR-018, y contarlo en el cuerpo del PR. Tirar código propio porque cambió la decisión es lo más difícil de hacer y lo más barato de revisar.
linkableChannelsexcluye los canales donde el producto ya está publicado. Un producto, una publicación por canal: la regla del dominio resuelta en el selector en vez de esperar el 409.
⚪ Una sola observación
linkErrorMessage traduce 422 → «no existe en el canal o el SKU es ambiguo». Fui a ver si el 422 está sobrecargado del lado de la API, porque ese endpoint también responde 422 ante un RecordNotSaved (falta la integración) y ante una validación de modelo (el precio externo fuera de rango).
Conclusión: no es un problema hoy, y por una razón concreta — el formulario manda sólo company_integration_id y, opcionalmente, external_product_id. Nunca manda precio, y la integración siempre va. Así que el único 422 que esta pantalla puede producir es el que el texto describe.
Lo dejo anotado porque es frágil ante un cambio chico: el día que el formulario sume el precio externo, un precio inválido va a decirle al usuario que su publicación no existe. Si en ese momento el back distingue con un código de error en el cuerpo, se resuelve solo.
Orden de merge
Este va segundo. Mergeo primero proyecto-api#98 —que ya aprobé— y después este, para que la pantalla no quede pidiéndole a la API una forma de GET /integrations que todavía no existe.
🔗 Link
📝 Descripción
Agrega la pantalla de Integraciones y la tarjeta Canales de venta del detalle de producto. Con la primera, la empresa ve qué proveedores tiene conectados, en qué estado y con qué cuenta. Con la segunda, vincula cada producto con su publicación en un canal (por id o por SKU) y lo desvincula, sin Postman ni backoffice.
Conectar un proveedor no es parte de la pantalla: las credenciales las carga el equipo de OneStock desde el backoffice (ADR-018 del back). La primera versión de esta rama tenía un formulario de conexión armado con los campos de la plantilla, y se sacó en el segundo commit cuando se tomó esa decisión.
Depende de TESIS-138 (proyecto-api#98) (API):
GET /integrationscambia de forma yPOST /products/:id/mappingsbusca por SKU. Mergear la API primero.🛠️ Cambios realizados
shared/api/integrations.tsyshared/hooks/useIntegrations.ts. El listado de integraciones sube ashared/por la Regla de Dos (lo leen el panel, integraciones e inventario) y se traduce al dominio en camelCase. Ya no se usanurinihttp_methoduseInfraHealth(panel de salud de nodos) pasa a leer del hook compartido, sin cambios visiblesfeatures/integrations:IntegrationsPagede sólo lectura, con los proveedores agrupados en Canales de venta y Operadores logísticosIntegrationCardmuestra el estado (Conectado / Inactivo / No conectado) y la cuenta («Cuenta: onestock-norte»)/integrationscarga el feature nuevo y sigue detrás del flagintegrationsdel tenant. Se borrafeatures/dashboard/pages/IntegrationsPage.tsxSalesChannelsCardenProductDetailPage:warnings(SKU distinto)integrationsinventory/api.ts(/products/:id/mappings),useProductMappings,utils/channels.tsy sus tiposdocs/design/README.mdanota que las dos pantallas se hicieron sin maqueta, con componentes del DS, para la revisión de diseño🧪 Cómo probarlo (Opcional)
Precondición: API en la rama
TESIS-138-shopify-integrationconbin/rails db:migrate && bin/rails db:seed, y Shopify conectado para Norte (casos 1 y 3 del PR de la API). Front connpm run devyVITE_API_URLapuntando a esa API.Caso 1: estado de las integraciones
admin@norte.com(contraseña de las seeds) → Integraciones.→ Shopify aparece Conectado con «Cuenta: onestock-norte». Mercado Libre y Tiendanube aparecen Inactivo, y los couriers en su grupo.
→ No hay ningún botón para conectar, probar, activar ni desconectar.
Caso 2: vincular por SKU y desvincular
→ Aparece la publicación vinculada, y en el admin de Shopify el stock de NOR-001 pasa a ser el del OMS.
→ Shopify ya no se ofrece como canal para ese producto: está vinculado.
Caso 3: una venta de Shopify se ve en el front
Precondición: el webhook de ventas registrado y una compra hecha en la tienda (caso 4 del PR de la API).
Caso 4: tenant sin integraciones
admin@sur.com(?tenant=sur).→ No aparece Integraciones en el menú ni la tarjeta Canales de venta en el detalle de producto.
Checks
npm run lint,npm run test(683 tests) ynpm run builden verde.📸 Evidencia (Opcional)
🤖 Generated with Claude Code