Skip to main content

Apply Extraction (Create Bills)

POST 

/api/landed-cost-invoices/ocr/:landed_cost_extraction_id/apply

Accept the reviewed/edited extraction and create one or more Bill records — one per target entity (inbound shipment, purchase order, or warehouse transfer) — each with its own apportionment of the cost lines. Marks the extraction as confirmed and persists Bill rows linked via the polymorphic bills.link_type / link_id columns. Bridges supplier → vendor via VendorRepository::firstOrCreateByName($supplier->name) since Bills require vendor_id.

The extraction must be in pending_review or duplicate_detected status (a duplicate-detected extraction is allowed because the user may confirm it is not actually a duplicate and proceed). Returns 422 otherwise.

When multiple targets are supplied, the invoice number is suffixed per target ({invoice_number}-{type3}-{target_id}) to avoid bills.invoice_number unique constraint violations.

Request body fields:

FieldTypeRequiredNotes
supplier_idintegeryesMust exist in suppliers.
invoice_numberstringyesMax 255 chars.
invoice_datedateyes
currency_codestringyesISO 4217 (size:3).
currency_ratenumericyesMin 0. Conversion rate to base currency.
total_amountnumericyesTotal invoice amount.
cost_linesarrayyesAt least 1 line.
cost_lines[].descriptionstringyesMax 500 chars.
cost_lines[].quantitynumericyes
cost_lines[].unit_pricenumericyes
cost_lines[].line_totalnumericyes
cost_lines[].cost_category_idintegerno (nullable)Must exist in cost_categories. Null = unclassified line.
cost_lines[].ignoredbooleannoSkip persisting this line (audit-only).
targetsarrayyesAt least 1 target. Allocation shares MUST sum to 1.0 ±0.001.
targets[].target_typestringyesOne of: inbound_shipment, purchase_order, warehouse_transfer.
targets[].target_idintegeryesID of target entity.
targets[].proration_strategystringyesFinancialLineProrationStrategyEnum: revenue_based, cost_based, weight_based, volume_based, quantity_based, specific_line, manual.
targets[].allocation_sharenumericyes0–1. Share of the total this target receives.
remember_mappingsbooleannoWhen true, upserts (supplier_id, normalized_description) → cost_category_id mappings into supplier_landed_cost_mappings so future OCR imports auto-tag matching descriptions as cost lines (Tier 0 match).

Response 201:

{
"data": {
"id": 18,
"status": "confirmed",
"extraction_bills": [
{"id": 33, "bill_id": 491, "target_type": "inbound_shipment", "target_id": 142, "allocation_share": 0.6},
{"id": 34, "bill_id": 492, "target_type": "purchase_order", "target_id": 88, "allocation_share": 0.4}
],
"confirmed_at": "2026-05-01T08:30:00.000000Z",
"confirmed_by_user_id": 7
},
"message": "Landed cost invoice applied."
}

Response 422 — wrong status:

{ "message": "Only extractions pending review can be applied." }

Response 422 — allocation shares do not sum to 1.0:

{ "message": "Target allocation shares must sum to 1.0." }

Request

Responses

Successful response