Una integración con QuickBooks que no borra campos
QuickBooks Online reemplaza el objeto entero en una actualización si no le dices lo contrario, y cada registro lleva una versión que hay que devolver. Las dos cosas caen en el formulario.
Una integración con QuickBooks Online entra en producción. Una semana después un cliente nota que a un proveedor le faltan la dirección de facturación, las condiciones de pago y el código fiscal. Nadie los borró. Alguien cambió el correo de ese proveedor desde un formulario de tu aplicación.
Eso es lo primero que hay que saber de esta API, y es lo que llega más adentro del front end.
Una actualización es un reemplazo
La mayoría de las APIs tratan el cuerpo de una petición como los campos que quieres cambiar. QuickBooks Online, por defecto, lo trata como el objeto en el que quieres que se convierta el registro. Lo que omites no queda igual - queda vacío.
Un formulario en una aplicación Next.js es exactamente lo que cae en esto. La pantalla de edición conoce tres campos porque tres campos son los que hay que cambiar. La Server Action recibe tres campos y envía tres campos. La contabilidad tiene ahora un proveedor con tres campos.
Hay dos defensas y conviene tener las dos. La petición puede declarar que es una actualización parcial, que es un parámetro de la llamada y no nada ingenioso. Y el handler puede leer el registro actual, aplicar el cambio sobre él y devolverlo entero, de modo que la carga esté completa independientemente de cómo la API decida interpretarla.
La segunda cuesta un viaje de ida y vuelta. También significa que el comportamiento no depende de que alguien recuerde un parámetro, que es el tipo de intercambio que conviene hacer en código que toca la contabilidad de alguien.
La versión pertenece al formulario
Cada registro de QuickBooks Online lleva una versión. Una actualización tiene que enviar la versión sobre la que se basó, y si el registro cambió desde entonces, la actualización se rechaza.
Eso es correcto y es el comportamiento que quieres. Es además un requisito que cae en el formulario y no en el cliente de la API, y ahí es donde los equipos se equivocan.
La página carga un registro en la versión 7 y renderiza un formulario. La persona escribe durante cuatro minutos. Mientras, alguien de contabilidad edita el mismo registro en QuickBooks y pasa a la versión 8. El formulario envía la versión 7 y se rechaza.
La reacción equivocada es capturarlo, pedir la versión actual y reenviar - porque eso descarta en silencio el cambio de contabilidad. La correcta es decirle a la persona qué ha pasado y mostrarle qué cambió. Eso significa que la versión tiene que formar parte del estado del formulario, viajar por la Server Action, y que el conflicto sea un resultado visible y no una excepción en un log.
Que es, convenientemente, el mismo patrón de concurrencia optimista que necesita cualquier formulario multiusuario. La API contable solo lo hace obligatorio.
Dónde vive cada pieza de la integración
La pregunta de arquitectura es la misma que en cualquier integración contable, y las respuestas merecen repetirse aquí porque QuickBooks añade un detalle.
El callback de autorización es un Route Handler. Junto con el código de
autorización, QuickBooks devuelve el identificador de la empresa autorizada, y
ambos hay que capturarlos en esa única petición - el código es inútil si no sabes
a qué empresa pertenece. El parámetro state hay que verificarlo y no solo
leerlo, porque es lo que evita que la autorización de otra persona acabe atada a
la cuenta de tu usuario.
Los tokens van a una tabla cuya clave es ese identificador de empresa. No en el usuario, no en una cookie, no en nada que pueda alcanzar un componente de cliente. Una persona puede autorizar varias empresas, así que la conexión es el registro y el usuario una referencia en él.
Las lecturas y escrituras ordinarias van en Server Actions y componentes de servidor, donde están las credenciales y el navegador no las ve nunca.
El trabajo largo no. Una Server Action es una petición con un timeout, y una importación inicial, una conciliación o un recálculo no son una petición. Eso va a una cola: la Server Action crea un registro de trabajo, vuelve enseguida, y la página muestra el progreso. Es el error estructural más común en estas integraciones y es invisible en desarrollo, donde la empresa de prueba tiene once facturas.
Los webhooks dan el identificador y nada más
Un webhook de QuickBooks llega a un Route Handler, viene firmado, y dice que una entidad de un tipo y un identificador concretos ha cambiado. No dice qué cambió ni qué contiene el registro ahora.
Así que el handler verifica la firma, anota la notificación, vuelve rápido, y un trabajo pide el registro después. Hacer esa petición en línea significa que el tiempo de respuesta de tu endpoint es una función del tiempo de respuesta de la API contable, y una API lenta se convierte en entregas fallidas.
La notificación también puede llegar dos veces, y puede llegar en orden inverso respecto al cambio que acabas de hacer tú. Las dos cosas son normales. Que el handler se pueda ejecutar dos veces sin daño - e ignore una notificación de una versión que ya tiene - es la diferencia entre una sincronización que converge y una que oscila.
Casar los clientes es el proyecto
El trabajo técnico de arriba son dos semanas. El resto del tiempo se va a un sitio que no parece desarrollo.
QuickBooks exige que el nombre visible de un cliente sea único dentro de una empresa, lo que significa que «Acme S.L.» en tu aplicación y «Acme SL» en la contabilidad son dos clientes distintos y lo seguirán siendo hasta que alguien decida cuál es cuál. Multiplica eso por dos mil registros y una década de introducción de datos inconsistente.
Ese ejercicio de emparejamiento - qué lado es dueño de un nombre, qué pasa con los casi duplicados, qué campo es la clave - es una conversación con el equipo financiero, no una estimación de ingeniería. Los equipos que lo tratan como un problema de importación lo descubren tres semanas antes del lanzamiento.
Cuándo no construir esto
Si el requisito es que las facturas aparezcan en QuickBooks y nada vuelva, y el volumen son decenas al mes, un conector gestionado lo hace esta tarde por una cuota. Una integración en dos sentidos merece la pena cuando el mapeo es específico de tu negocio, cuando el volumen hace caro corregir a mano, o cuando los datos tienen que estar en tu propio sistema para servir de algo.
No merece la pena para ahorrar una cuota mensual pequeña. El tiempo se va en las reglas de conciliación, y esas no se abaratan porque hayas escrito tú el cliente de la API.
