{"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."},"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 deducted at source for those lines.","TO_TRANSFER":"After POST \/api\/transfer\/{id}\/confirm: ready for gatepass (no gatepass row yet). Attach via POST \/api\/gatepass\/{id}\/transfers, then POST \/api\/gatepass\/{id}\/dispatch → IN_TRANSIT.","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."},"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","restores":["stock_batching_* qty_onhand","parts_* totqty_onhand"],"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)."}},"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":"TO_TRANSFER only (pending lines ONGOING→TO_TRANSFER); no gatepass. 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). Response data may include branch_ledger { branch, rows_inserted, rows_skipped, connection, skipped }.","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":"Link one or more TO_TRANSFER documents (same route); junction gatepass_transfers; response data.transfers[] includes transfer_no and transfer_date per linked header","POST \/api\/gatepass\/{id}\/dispatch":"OPEN→IN_TRANSIT; all linked headers IN_TRANSIT; response data includes receive_guide (destination_branch, paths.*, post_body_hint) and 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":"Gatepass payload: transfer_nos[], transfers[] { transfer_no, transfer_date }, lines[] (pending items with transfer_date)","GET \/api\/receive\/preview":"Same as GET \/api\/receive\/search?gatepass_no= (alias for post-dispatch receive UI\/agents)","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; partial line receive: items[] with received_qty less than line remaining_to_receive updates remaining (repeat until zero); omit items to receive full remaining per line; 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."}}}