{"ok":true,"app":"Laravel","hint":"ERP transfer: POST \/api\/transfer (Bearer); GET \/api\/transfer\/next-number; confirm = POST \/api\/transfer\/{id}\/confirm (TO_TRANSFER). Lists: GET \/api\/transfers (optional status=…), GET \/api\/transfers\/to-transfer (TO_TRANSFER), GET \/api\/transfers\/in-transit (IN_TRANSIT), GET \/api\/transfers\/history\/{from_terminal} (inquiry: in_process + per-receipt rows). Gatepass: GET \/api\/gatepass\/next-number; GET \/api\/gatepass\/history (from and\/or to; optional completion; each row items[] itemno\/qty\/unit\/description); POST \/api\/gatepass requires from_branch and to_branch (optional gatepass_no); POST \/api\/gatepass\/{id}\/transfers; POST ...\/dispatch. Receive: GET \/api\/receive\/incoming\/{branch}, GET \/api\/receive\/outstanding\/{branch} (incomplete remaining qty + last_received_at), GET \/api\/receive\/items\/{branch} (line items; require from_date+to_date or received_by or received_by_name; optional itemno), GET \/api\/receive\/history\/{branch} (POSTED receipts; optional transfer_no, from_date, to_date, include_items), GET \/api\/receive\/search\/preview, POST \/api\/receive. Partial receive: items[{received_qty, pending_item_id | itemno}; optional transfer_no on row when itemno is ambiguous across transfers]; received_qty is capped to remaining when higher. Response: total_remaining_to_receive, receive_completion, incomplete_delivery. Lines: POST \/api\/transfer\/{id}\/lines (itemno+qty or {}).","transfer_api":{"iteration":"phase_a_documentation","integration":{"single_endpoint_for_add_line_and_process_pending":"POST \/api\/transfer\/{id}\/lines","behavior":"Body with non-empty itemno: same as POST ...\/add-item. Empty JSON {}: same as POST ...\/process.","new_integrations":"Call \/lines only; \/add-item and \/process are optional backward-compatible aliases.","repair_add_item":"POST \/api\/repair-orders-transfer\/{id}\/add-item (or \/lines). Preferred body matches table columns: { itemno: <parts_repair>, job_no: <RO>, merge: false }. Optional exact bind: parts_job_id (= MIN(j.id), not a DB column) or numeric itemno as j.id. Stored transfer_items.itemno remains repair stock key; binding is parts_job_id= in remarks."},"stakeholder_decision":{"partial_fifo_when_short_stock":false,"note":"Phase B (partial line processing) not enabled; full requested qty required to process a line."},"physical_schema":{"header_table":"transfers_header","line_table":"transfer_items","batch_breakdown_table":"transfer_batch_details","spec_alias_transfer_item_batches":"transfer_batch_details (per-batch qty + unit price per row)","header_branch_fields":"from_warehouse_id, to_branch_id (resolved from API from_branch \/ to_branch slugs)","line_qty_field":"requested_qty (not qty_requested)","gatepass_manifest":"dbo.gatepass (manifest: gatepass_no, branch_from\/to, vehicle, status); transfer linkage is only in dbo.gatepass_transfers (gatepass_id, transfer_no, transfer_id)."},"transfer_no_format":"TRF-{from_code}-{YYYYMMDD}-{seq4} (see TransferNumberFormatter; not TRF-YYYY-XXXX)","gatepass_no_format":"GP-{from_code}-{YYYYMMDD}-{seq4} (4-digit zero-padded seq; same from_code\/date\/next_seq parts as GET \/api\/gatepass\/next-number)","gatepass_create":{"POST \/api\/gatepass":"Requires from_branch|from AND to_branch|to (whitelist slugs; both resolve to branch_from \/ branch_to on manifest). gatepass_no optional; omit or blank to auto-assign GP-{from_code}-{YYYYMMDD}-{seq4} (same numbering parts as GET \/api\/gatepass\/next-number for from_slug). Optional: vehicle_no, driver_name, issued_by, issued_date. Response data: created gatepass row (toArray); no number_auto_assigned — use returned gatepass_no or GET \/api\/gatepass\/next-number to preview before create.","GET \/api\/gatepass\/next-number":"Preview next gatepass_no parts (Bearer); query from_branch, optional date — same as transfer\/next-number pattern."},"header_status_vs_spec":{"PENDING":"Document created; lines may be added.","ONGOING":"Spec \"PROCESSING\": at least one line FIFO-processed; stock allocated (transfer_batch_details) but not deducted until confirm.","TO_TRANSFER":"After POST \/api\/transfer\/{id}\/confirm (auto-FIFOs PENDING lines first): source parts_* \/ parts_repair_* deducted, ready for gatepass. Attach + dispatch via POST \/api\/gatepass\/{id}\/dispatch (transfer_no\/transfer_nos, vehicle, bearer, driver_name) → IN_TRANSIT; legacy attach-only POST \/api\/gatepass\/{id}\/transfers still supported.","CANCELLED":"Cancelled; stock restored for processed lines where applicable."},"line_status":{"PENDING":"Line added; not yet FIFO processed.","PROCESSED":"FIFO done; transfer_batch_details rows hold per-batch qty and price.","PARTIAL":"Reserved for legacy\/partial-cancel flows; full-line partial allocation (Phase B) not enabled.","CANCELLED":"Line cancelled."},"merged_add_and_process":{"canonical":"POST \/api\/transfer\/{id}\/lines","canonical_rules":"Non-empty itemno: same as add-item (default process_immediately true). Empty body {}: same as process (FIFO all PENDING).","aliases":{"POST \/api\/transfer\/{id}\/add-item":"Add line; default runs FIFO for every PENDING line on the document (not only the new line)","POST \/api\/transfer\/{id}\/process":"FIFO all PENDING lines without adding a line (staging flush, retry)"},"legacy_endpoint":"POST \/api\/transfer\/{id}\/add-item","default":"process_immediately true (omit or null): insert line, then processFifo — runs FIFO for all PENDING lines on that transfer (including any previously staged with process_immediately false), ordered by line id.","fallback":"POST \/api\/transfer\/{id}\/process or POST \/api\/transfer\/{id}\/lines with {} processes all PENDING lines when you did not add a line in the same request. Prefer POST \/api\/transfer\/{id}\/confirm which auto-runs FIFO then confirms in one call."},"merged_process_and_confirm":{"canonical":"POST \/api\/transfer\/{id}\/confirm (also POST \/api\/repair-orders-transfer\/{id}\/confirm)","behavior":"If any line is PENDING, runs processFifo first, then confirms to TO_TRANSFER. Already-PROCESSED docs confirm only. Response may include processed[] and fifo_processed_before_confirm=true.","optional_aliases":{"POST \/api\/transfer\/{id}\/process":"Process-only (no confirm)","POST \/api\/transfer\/{id}\/lines with {}":"Process-only (no confirm)","POST \/api\/repair-orders-transfer\/{id}\/process":"Process-only (no confirm)"}},"fifo_and_price":{"ordering":"stock_batching_* ordered by configured FIFO column (date) ascending.","price_tracking":"Each FIFO slice inserts one transfer_batch_details row with qty and price."},"cancel":{"endpoint":"POST \/api\/transfer\/{id}\/cancel","cancel_item":"POST \/api\/transfer\/cancel-item — body transfer_no + item_id; parts full-line or repair per-line (parts_repair_* \/ parts_job.consumption restore when stock_deducted_at set).","cancel_detail":"POST \/api\/transfer\/cancel-detail — body detail_id + cancel_qty; parts FIFO partial qty only (repair lines: 400, use cancel-item).","repair_cancel_item":"POST \/api\/repair-orders-transfer\/{id}\/cancel-item — body item_id; same as transfer cancel-item for RO documents.","restores":["stock_batching_* qty_onhand","parts_* totqty_onhand","parts_repair_* totqty_onhand (repair)","parts_job.consumption=0 (repair post-confirm)"],"allowed_header_status":["PENDING","ONGOING","TO_TRANSFER"],"response_data":{"total_quantity_restored":"Sum of qty returned to source batches\/parts for this cancel (0 if idempotent cancel or PENDING-only lines).","parts_restored":"Per distinct transfer line key (same string as transfer_items.itemno, may be partno or itemno): itemno, partno, quantity_restored, totqty_onhand_after (from parts_* after commit; null if row not found)."}},"inquiry":{"transfer":{"GET \/api\/transfers":"Paginated headers; filters transfer_no, from_branch\/to_branch (AND), involves_branch (OR), status, date_from\/date_to.","GET \/api\/transfers\/to-transfer":"Forces status=TO_TRANSFER.","GET \/api\/transfers\/in-transit":"Forces status=IN_TRANSIT.","GET \/api\/transfers\/history\/{from_terminal}":"Outbound inquiry grouped by transfer; phase=all|in_process|received; items[] include phase and receipt fields.","GET \/api\/transfer\/{transfer_no}":"Single document + nested lines."},"gatepass":{"GET \/api\/gatepass\/history":"Paginated manifests; requires from and\/or to (aliases from_branch\/to_branch); optional completion=pending|completed; nested items[]."},"receive":{"GET \/api\/receive\/incoming\/{branch}":"IN_TRANSIT gatepasses at destination with lines[].","GET \/api\/receive\/outstanding\/{branch}":"Pending lines with remaining qty + last_received_at.","GET \/api\/receive\/history\/{branch}":"POSTED receipts; optional include_items.","GET \/api\/receive\/items\/{branch}":"Flat receipt lines; requires from_date+to_date or receiver.","GET \/api\/receive\/search\/preview":"Prep payload by gatepass_no or transfer_no (transfer_nos[], transfers[], lines[], total_remaining_to_receive). Canonical preview route — not \/api\/receive\/search or \/api\/receive\/preview.","RO aliases":"Same shapes under \/api\/repair-orders-receive\/* (incoming, outstanding, history, items, search\/preview), scoped to repair-order transfers."}},"key_endpoints":{"GET \/api\/transfers":"List transfers (Bearer). transfer_no. from_branch and to_branch: optional; may be used together — both apply as AND (lane from source to destination; whitelist slugs → from_warehouse_id \/ to_branch_id). location_from aliases from_branch. involves_branch or branch: OR (header matches branch as source OR destination); mutually exclusive with from_branch, location_from, to_branch. status: comma-separated uppercase header statuses (OR); omit = no status filter. Examples: status=RECEIVED (completed at destination); status=PENDING; status=RECEIVED,PENDING; status=IN_TRANSIT,PARTIAL (dispatched and\/or partially received at destination). date_from, date_to, per_page, page. GET \/api\/transfers\/to-transfer forces status=TO_TRANSFER. GET \/api\/transfers\/in-transit forces status=IN_TRANSIT. GET \/api\/transfers\/history\/{from_terminal} outbound inquiry grouped by transfer: transfers[] { id, transfer_no, status, transfer_date, from_branch, to_branch, transferred_by, total_amount, items[] { phase, itemno, partno, description, category, unit_mes, price, qty, amount, remarks, line_status, received_by, received_date, receipt_no, pending_item_id, receipt_item_id } }; phase=all|in_process|received; pagination is per transfer document.","GET \/api\/transfer?from_branch=&date=":"Preview next transfer_no (Bearer)","POST \/api\/transfer":"Create header (Bearer)","POST \/api\/transfer\/{id}\/lines":"Add line (itemno+…); default FIFOs all PENDING on doc. Or {} = process-only.","POST \/api\/transfer\/{id}\/add-item":"Alias: add line; default FIFOs all PENDING on document","POST \/api\/transfer\/{id}\/process":"Alias: FIFO all PENDING without adding a line","POST \/api\/transfer\/{id}\/confirm":"Combined process+confirm (same as POST \/api\/repair-orders-transfer\/{id}\/confirm). Auto-runs processFifo when any line is still PENDING, then confirms: pending execution lines ONGOING→TO_TRANSFER; deducts parts_* + stock_batching_* (FIFO from transfer_batch_details) or parts_repair_* for repair-order transfers when stock_deducted_at is null. Sets stock_deducted_at. Also inserts one row per PROCESSED line into source branch inventory dbo.transfer (legacy ledger) when BRANCH_TRANSFER_LEDGER_ENABLED; confirm fails if branch insert fails; skips lines already on branch (idempotent). When auto-FIFO ran, response includes processed[] and fifo_processed_before_confirm=true. Response data may include branch_ledger { branch, rows_inserted, rows_skipped, connection, skipped } and stock_deduction { stock_deducted, already_deducted, parts_deducted, repair_rows_deducted, stock_deducted_at }. Standalone POST ...\/process and POST ...\/lines {} remain optional process-only aliases.","transfer:backfill-branch-ledger":"Artisan: backfill missing dbo.transfer on source branch for existing MAIN documents (any non-CANCELLED status). Options: --from-warehouse=1,2 --transfer-no= --dry-run. Uses MAIN header status on branch row. Idempotent: skips complete documents and existing itemnos.","GET \/api\/gatepass\/next-number?from_branch=&date=":"Preview next gatepass_no parts (Bearer)","GET \/api\/gatepass\/history":"List gatepass manifests (Bearer); query from and\/or to (whitelist slugs; aliases from_branch, to_branch — prefer from\/to when set). At least one of from or to required. Optional completion=pending|completed; omit completion for all statuses. per_page. Each row includes items[]: transfer_no, transfer_date, itemno, qty (requested_qty), unit (parts_<dest>.unit_mes if column exists), description (parts_<dest> by itemno; branch_to must be set).","POST \/api\/gatepass":"Create OPEN gatepass; requires from_branch+to_branch (or from+to); gatepass_no optional (auto from from_slug when blank); vehicle\/driver\/issued fields optional","POST \/api\/gatepass\/{id}\/transfers":"Legacy attach-only: link one or more TO_TRANSFER documents; junction gatepass_transfers; response data.transfers[] includes transfer_no and transfer_date per linked header. Prefer POST \/api\/gatepass\/{id}\/dispatch with transfer_nos for combined attach+dispatch.","POST \/api\/gatepass\/{id}\/dispatch":"Combined attach + dispatch (Bearer). Body optional: transfer_no\/transfer_nos (attach when not yet linked), vehicle_no\/vehicle, bearer→issued_by, driver_name. Empty body dispatches already-linked transfers. OPEN\/ISSUED→IN_TRANSIT; linked headers IN_TRANSIT. Response data includes attach { linked, skipped }, vehicle_no, issued_by, driver_name, receive_guide, header_statuses[] with transfer_no, transfer_date, status","GET \/api\/receive\/incoming\/{branch}":"List IN_TRANSIT\/PARTIAL (+ optional TO_TRANSFER); each row includes lines[] with transfer_no, transfer_date, pending line fields (id as pending_item_id, itemno, quantity, remaining_to_receive, status, price)","GET \/api\/receive\/outstanding\/{branch}":"Incomplete deliveries at destination only: IN_TRANSIT or PARTIAL headers with at least one non-cancelled pending line where COALESCE(remaining_to_receive, quantity) > 0; each row includes transfer_date + last_received_at (max POSTED transfer_receipts.received_date per transfer_no); per_page","GET \/api\/receive\/search\/preview":"Gatepass\/transfer receive prep payload: transfer_nos[], transfers[] { transfer_no, transfer_date }, lines[] (pending items with transfer_date), total_remaining_to_receive. Query: gatepass_no or transfer_no.","GET \/api\/receive\/history\/{branch}":"POSTED transfer_receipts for destination branch; optional transfer_no, from_date, to_date, include_items=1.","GET \/api\/receive\/items\/{branch}":"Flat receipt line items; requires from_date+to_date or received_by\/received_by_name; optional itemno.","POST \/api\/receive":"Post receive; body: gatepass_no OR transfer_no (not both). transfer_no-only: allowed for TO_TRANSFER, PARTIAL, or IN_TRANSIT; if linked to an OPEN gatepass, 400 until dispatch; if linked to an IN_TRANSIT gatepass, receive behaves like gatepass path (receipt gatepass_no set, gatepass aggregate RECEIVED when all linked transfers complete). Multiple receipts when gatepass payload has multiple transfers. Parts: items[] with received_qty less than remaining_to_receive → PARTIAL (repeat until zero); omit items → full remaining for parts lines. Repair (parts_job_id=): received_qty must be 1 (400 otherwise); on mixed gatepasses omit items does NOT auto-receive repair — repair stays TO_TRANSFER until listed with received_qty:1; repair-only gatepass omit items still receives all repair lines. Unlisted lines stay pending. batches_used_json must cover requested qty or 400; PARTIAL_RECEIVE notification includes Sender branch \/ Receiver branch slugs (when resolvable), transfer_no, guidance to repeat POST \/api\/receive (same gatepass_no or transfer_no) and not duplicate outbound transfers, plus Remaining (itemno=qty): …; when any affected header is not RECEIVED, response data includes follow_up { mode: repeat_receive_same_gatepass|repeat_receive_same_transfer, note, gatepass_no?, transfers[], pending_lines[] }; response data.transfers[] includes transfer_no and transfer_date per linked header","POST \/api\/transfer\/{id}\/cancel":"Cancel + restore stock"},"delivery_state_labels":{"header":"API-only: received | partially_received | in_transit | pending_dispatch | other (derived from transfers_header.status)","pending_line":"API-only: received | partially_received | pending_delivery (from remaining_to_receive and line status)","db_status_PARTIAL":"Same as partially_received \/ pending complete delivery at destination"},"phase_b_future":{"dba_script_stub":"database\/scripts\/transfer_partial_processing_phase_b_stub.sql","summary":"Would add qty_processed \/ partial line rules and relax insufficient-stock to allocate up to on-hand."}}}