Línies de compra mesurades
Les línies de factura de compra registren ja els embalums rebuts, la unitat a la qual s’aplica el cost del proveïdor i la mesura real. El contracte afegeix un bloc de mesura, persisteix el descompte de línia, resol el cost des de l’oferta del proveïdor i duplica una compra des d’un origen autoritzat.
Les factures de compra separen ja la part física d’una compra de la part
facturada. Una línia pot indicar quants embalums han arribat, en quina unitat
s’expressa el cost del proveïdor i la mesura real; el servidor deriva la
quantitat facturada, el factor de conversió a la unitat base i el cost unitari
congelat. Una línia sense el bloc nou conserva la seva semàntica anterior de
quantity × unit_price.
Nous camps de la petició
POST /v1/purchase_invoices i PUT /v1/purchase_invoices/{purchase_invoice}
accepten aquests camps additius. Ometre’ls tots continua sent una petició vàlida.
| Camp | Significat |
|---|---|
source_purchase_invoice_id | UUID d’una factura de compra de la teva empresa les línies històriques de la qual vols duplicar. Només en crear. La key necessita purchase_invoices:read a més de purchase_invoices:write; si no, 403 insufficient_scope. Un origen desconegut o d’una altra empresa retorna 404 purchase_invoice_not_found. |
lines[].purchase_measurement | Objecte tancat amb package_quantity (string decimal o null) i cost_basis (offer_unit, base_unit o presentation_unit). Omès o null conserva el contracte legacy. Els camps derivats de lectura (billing_*, unit_cost) es rebutgen en escriptura, encara que provinguin d’una lectura anterior. |
lines[].discount_percent | Descompte percentual, 0–100 amb fins a quatre decimals, aplicat abans d’impostos. L’API l’acceptava i el descartava en silenci; ara es persisteix i es retorna. |
lines[].source_line_index | Ordinal base zero de la línia al document origen autoritzat. Manté la línia duplicada aparellada amb les seves mesures i el seu cost congelat històrics. Mai una clau interna. |
lines[].price_source | manual o supplier_offer. Nou a l’API pública; canvia com es llegeix unit_price (vegeu més avall). |
metadata.purchase_source_review | Clau reservada: string JSON compacte de 500 caràcters com a màxim amb l’estat de la conciliació OCR (pending, reconciled o accepted_difference), totals d’origen i calculat, diferència i motiu. La metadata continua sent plana; els objectes imbricats es rebutgen. |
Exemple: tres caixes de 2 kg comprades amb una oferta per quilo
El proveïdor cotitza 7,40 per kg. Tres caixes de 2 kg es facturen com a 6 kg; el servidor deriva el mateix import brut, 44,40, triïs la base que triïs.
{
"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 mateixa compra a preu per caixa fa servir "quantity": "3.0000",
"unit_price": "14.8000" i "cost_basis": "presentation_unit" amb cost
manual. Una presentació pesada (mesura variable) exigeix a més
confirmed_base_quantity, encara que s’hi apliqui una oferta.
Com es resol el cost
Canvien dos comportaments a les línies de catàleg (les que porten product_id)
a l’API pública i a MCP, igual que a l’aplicació web:
unit_priceomès significa «cost no confirmat», no zero. El servidor proposa el cost de l’oferta del proveïdor aplicable. Si el proveïdor no té cap oferta activa per al producte o la variant triats, la línia es rebutja amb422 parameter_invalid_valueiparam: unit_price. Abans aquell silenci es desava com a0.00i l’stock entrava valorat a zero. Les línies manuals senseproduct_idcontinuen exigintunit_price.price_source: "supplier_offer"deixa de ser decoratiu. Enviat juntament ambunit_price, l’import es llegeix com l’eco del cost que va resoldre el servidor i es torna a congelar el cost de l’oferta. Per imposar un cost, enviaprice_source: "manual"o omet-lo: l’import que envies es respecta.
El cost supplier_offer s’aplica a la unitat de compra de l’oferta. Una compra
de mesura variable sense confirmed_base_quantity es rebutja fins i tot amb
oferta. Els documents històrics no es recalculen.
Nous camps de la resposta
PurchaseInvoiceLine, retornat en llistar, consultar, crear i actualitzar:
| Camp | Significat |
|---|---|
purchase_measurement | Bloc derivat o null: package_quantity, billing_quantity, billing_unit_code, billing_conversion_factor, unit_cost i cost_basis. |
confirmed_base_quantity | Mesura real en la unitat base com a string decimal; null quan la línia no l’exigeix. |
discount_percent | Aplicat abans d’impostos. subtotal ja n’és net, de manera que unit_price × quantity no és igual a subtotal en una línia amb descompte. |
source_line_index | Ordinal base zero de la línia dins del seu document, en ordre estable de lectura. |
quantity, unit_price | El tipus passa a ser number | string. Una línia mesurada retorna strings de 4 decimals per no perdre precisió; una línia legacy conserva el número que sempre ha publicat. Parseja tots dos. |
Errors
Els errors de mesura són 422 amb code: parameter_invalid_value i
subcode: catalog_line_assembly_invalid; param assenyala el camp que cal
corregir.
param | Causa |
|---|---|
purchase_measurement.cost_basis | La base no és vàlida, falta l’oferta o presentació que requereix, o la unitat de compra i la unitat base són de famílies diferents. |
purchase_measurement.package_quantity | Els embalums han de ser positius, amb quatre decimals com a màxim. |
quantity | La quantitat facturada no coincideix amb els embalums ni amb la mesura confirmada. |
confirmed_base_quantity | Obligatòria en una presentació de mesura variable, o la mesura no es pot expressar amb quatre decimals en la unitat de facturació. |
unit_price | No hi ha cap cost a aplicar: el proveïdor no té oferta activa per a la selecció, o una conversió legacy perdria precisió. |
Un bloc de mesura emmagatzemat que no supera la validació es notifica amb
subcode: catalog_line_snapshot_invalid. Consulta Errors.
MCP
create_purchase_invoice i update_purchase_invoice publiquen el mateix schema
de línia, inclosos purchase_measurement, discount_percent, price_source,
source_line_index i source_purchase_invoice_id, i apliquen la mateixa regla
addicional de purchase_invoices:read en duplicar. get_purchase_invoice
retorna els nous camps de línia. Consulta el
catàleg de tools MCP.
Llegeix Catàleg de productes per a les ofertes de proveïdor i Imports i dates per als camps de línia de compra.
Endpoints actualitzats4
| Endpoint | Descripció |
|---|---|
POST/v1/purchase_invoices | Crea una factura de compra |
PUT/v1/purchase_invoices/{purchase_invoice} | Actualitzar una factura de compra |
GET/v1/purchase_invoices/{purchase_invoice} | Obtenir una factura de compra |
GET/v1/purchase_invoices | Llistar totes les factures de compra |