Factuarea APIDevelopers
Contrato

Líneas de compra medidas

Las líneas de factura de compra registran ya los bultos recibidos, la unidad a la que se aplica el coste del proveedor y la medida real. El contrato añade un bloque de medida, persiste el descuento de línea, resuelve el coste desde la oferta del proveedor y duplica una compra desde un origen autorizado.

Las facturas de compra separan ya la parte física de una compra de la parte facturada. Una línea puede indicar cuántos bultos llegaron, en qué unidad se expresa el coste del proveedor y la medida real; el servidor deriva la cantidad facturada, el factor de conversión a la unidad base y el coste unitario congelado. Una línea sin el bloque nuevo conserva su semántica anterior de quantity × unit_price.

Nuevos campos de la petición

POST /v1/purchase_invoices y PUT /v1/purchase_invoices/{purchase_invoice} aceptan estos campos aditivos. Omitirlos todos sigue siendo una petición válida.

CampoSignificado
source_purchase_invoice_idUUID de una factura de compra de tu empresa cuyas líneas históricas quieres duplicar. Solo al crear. La key necesita purchase_invoices:read además de purchase_invoices:write; si no, 403 insufficient_scope. Un origen desconocido o de otra empresa devuelve 404 purchase_invoice_not_found.
lines[].purchase_measurementObjeto cerrado con package_quantity (string decimal o null) y cost_basis (offer_unit, base_unit o presentation_unit). Omitido o null conserva el contrato legacy. Los campos derivados de lectura (billing_*, unit_cost) se rechazan en escritura, aunque procedan de una lectura anterior.
lines[].discount_percentDescuento porcentual, 0–100 con hasta cuatro decimales, aplicado antes de impuestos. La API lo aceptaba y lo descartaba en silencio; ahora se persiste y se devuelve.
lines[].source_line_indexOrdinal base cero de la línea en el documento origen autorizado. Mantiene la línea duplicada emparejada con sus medidas y su coste congelado históricos. Nunca una clave interna.
lines[].price_sourcemanual o supplier_offer. Nuevo en la API pública; cambia cómo se lee unit_price (ver más abajo).
metadata.purchase_source_reviewClave reservada: string JSON compacto de 500 caracteres como máximo con el estado de la conciliación OCR (pending, reconciled o accepted_difference), totales de origen y calculado, diferencia y motivo. La metadata sigue siendo plana; los objetos anidados se rechazan.

Ejemplo: tres cajas de 2 kg compradas con una oferta por kilo

El proveedor cotiza 7,40 por kg. Tres cajas de 2 kg se facturan como 6 kg; el servidor deriva el mismo importe bruto, 44,40, elijas la base que elijas.

{
  "external_invoice_number": "F-2026-0918",
  "issued_on": "2026-09-18",
  "supplier_id": "01931b3e-7c4a-7f2e-9a8b-3c5d6e7f8a10",
  "lines": [
    {
      "product_id": "01931b3e-7c4a-7f2e-9a8b-3c5d6e7f8a01",
      "presentation_id": "01931b3e-7c4a-7f2e-9a8b-3c5d6e7f8a02",
      "supplier_offer_id": "01931b3e-7c4a-7f2e-9a8b-3c5d6e7f8a03",
      "quantity": "6.0000",
      "unit_price": "7.4000",
      "price_source": "supplier_offer",
      "tax_rate": 10,
      "purchase_measurement": { "package_quantity": "3.0000", "cost_basis": "offer_unit" }
    }
  ]
}

La misma compra a precio por caja usa "quantity": "3.0000", "unit_price": "14.8000" y "cost_basis": "presentation_unit" con coste manual. Una presentación pesada (medida variable) exige además confirmed_base_quantity, aunque aplique una oferta.

Cómo se resuelve el coste

Cambian dos comportamientos en las líneas de catálogo (las que llevan product_id) en la API pública y en MCP, igual que en la aplicación web:

  • unit_price omitido significa «coste no confirmado», no cero. El servidor propone el coste de la oferta del proveedor aplicable. Si el proveedor no tiene una oferta activa para el producto o la variante elegidos, la línea se rechaza con 422 parameter_invalid_value y param: unit_price. Antes ese silencio se guardaba como 0.00 y el stock entraba valorado a cero. Las líneas manuales sin product_id siguen exigiendo unit_price.
  • price_source: "supplier_offer" deja de ser decorativo. Enviado junto a unit_price, el importe se lee como el eco del coste que resolvió el servidor y se vuelve a congelar el coste de la oferta. Para imponer un coste, envía price_source: "manual" u omítelo: el importe que envías se respeta.

El coste supplier_offer se aplica a la unidad de compra de la oferta. Una compra de medida variable sin confirmed_base_quantity se rechaza incluso con oferta. Los documentos históricos no se recalculan.

Nuevos campos de la respuesta

PurchaseInvoiceLine, devuelto al listar, consultar, crear y actualizar:

CampoSignificado
purchase_measurementBloque derivado o null: package_quantity, billing_quantity, billing_unit_code, billing_conversion_factor, unit_cost y cost_basis.
confirmed_base_quantityMedida real en la unidad base como string decimal; null cuando la línea no la exige.
discount_percentAplicado antes de impuestos. subtotal ya es neto de él, así que unit_price × quantity no es igual a subtotal en una línea con descuento.
source_line_indexOrdinal base cero de la línea dentro de su documento, en orden estable de lectura.
quantity, unit_priceEl tipo pasa a ser number | string. Una línea medida devuelve strings de 4 decimales para no perder precisión; una línea legacy conserva el número que siempre ha publicado. Parsea ambos.

Errores

Los errores de medida son 422 con code: parameter_invalid_value y subcode: catalog_line_assembly_invalid; param señala el campo que corregir.

paramCausa
purchase_measurement.cost_basisLa base no es válida, falta la oferta o presentación que requiere, o la unidad de compra y la unidad base son de familias distintas.
purchase_measurement.package_quantityLos bultos deben ser positivos, con cuatro decimales como máximo.
quantityLa cantidad facturada no coincide con los bultos ni con la medida confirmada.
confirmed_base_quantityObligatoria en una presentación de medida variable, o la medida no puede expresarse con cuatro decimales en la unidad de facturación.
unit_priceNo hay coste que aplicar: el proveedor no tiene oferta activa para la selección, o una conversión legacy perdería precisión.

Un bloque de medida almacenado que no supera la validación se notifica con subcode: catalog_line_snapshot_invalid. Consulta Errores.

MCP

create_purchase_invoice y update_purchase_invoice publican el mismo schema de línea, incluidos purchase_measurement, discount_percent, price_source, source_line_index y source_purchase_invoice_id, y aplican la misma regla adicional de purchase_invoices:read al duplicar. get_purchase_invoice devuelve los nuevos campos de línea. Consulta el catálogo de tools MCP.

Lee Catálogo de productos para las ofertas de proveedor e Importes y fechas para los campos de línea de compra.

Endpoints actualizados4

EndpointDescripción
POST/v1/purchase_invoicesCrea una factura de compra
PUT/v1/purchase_invoices/{purchase_invoice}Actualizar una factura de compra
GET/v1/purchase_invoices/{purchase_invoice}Obtener una factura de compra
GET/v1/purchase_invoicesListar todas las facturas de compra

En esta página

¿Te echamos una mano?Contactar con soporte