# Go-Parts Ship — Supplier Onboarding Checklist

Steps to integrate a new supplier/warehouse into Go-Parts Ship (GPS).
Target: automate as much of this as possible.

## Starting point (inputs we have)
- **GATE — suppliers exist first.** Onboarding assumes the supplier already
  exists in `suppliers`. The yard must map to finalised **Supplier ID(s) +
  Supplier Code(s)** (one per warehouse/location) before any step below runs.
  The GPS account can exist independently, but our flow starts from the supplier
  mapping.
- Per supplier: **Supplier ID**, **Supplier Code** (e.g. `WAM-D`), **Location** (city/ZIP)
- Locations may later be used to create the GPS accounts themselves

## A. GPS-side data to obtain / create (from `shipdev` DB — it IS production)
- [ ] GPS account exists per vendor → `warehouse_api_credentials` (one `user_id`, `warehouse_code` = `USER-<id>`, looked up by `<vendor>@go-parts.com` email)
- [ ] API credential (apikey:apisecret) → encode as `Basic base64(apikey:apisecret)`
- [ ] Ship-from ZIP per location
- [ ] GPS `ship_from_locations.id` per location (map by ZIP) → needed for the supplier→location mapping
- [ ] SHIP_NOTIFY webhook row in `webhook_configurations` for the account → `https://central.go-parts.com/shipstation/webhook`, `account_code = USER-<id>` (GPS-side; without it, tracking won't return)

### A1. GPS account & location provisioning (in GPS, per account)
Note: ops often exposes GPS to a yard **before their feed is imported** — ask the yard for an email, create the account, and send them access to **one account to play around** with. Full multi-location/sub-user provisioning below happens once the vendor replies with the staff **emails** to create + which **locations** each should access.
- [ ] **Early access / playground**: create the account from the vendor's email and send login so they can explore before integration is finished
- [ ] **Seed sample orders for the vendor to play with** → create test orders under their account so they can practice creating labels. Either insert into shipdev `orders` (+ `order_items` + ship-to) with `user_id` = account, a valid `ship_from_location_id`, `order_status_ss = 'awaiting_shipment'`, OR call the same GPS `Orders/CreateOrder` API Central uses (`GoPartsShipService`) with the account credential. Flag clearly as test data + clean up afterward.
- [ ] **Locations configured within the account** → one `ship_from_locations` row per physical warehouse (`user_id` = the parent account, e.g. PartsBox = user 24). This is the master list the supplier→location mapping (B) points at.
- [ ] **Sub-user accounts created** from vendor-provided emails → `users` rows, `role = sub-user` (the parent account itself is `role = User` and holds the credential)
- [ ] **Assign-to-location decision per email** → `sub_user_locations` rows (sub-user `user_id` → `ship_from_location_id`). Two patterns (both in PartsBox):
  - manager/owner email → assigned to **all** locations (PartsBox: `daniel@partsboxonline.com`)
  - per-warehouse worker email → assigned to **one** location (PartsBox: one remote email per Venice/Englewood/Belton/Anderson)
  - "don't assign" = create the sub-user but add no `sub_user_locations` rows

## B. Central config / code
- [ ] `config/gopartsship.php` — one operator warehouse entry per location (shared credential, own `postalCode`, `exclusive` flag) + one `USER-<id>` webhook-account entry
- [ ] `app/Helpers/WarehouseHelper.php` — `$warehouseNames` + `$warehousePostalCodes` for operator codes (NOT the `USER-<id>` entry) → drives Filament bulk dropdown
- [ ] `app/Http/Controllers/ShipmentController.php::getWarehouses()` — add operator codes to the legacy single-ship form dropdown (hardcoded list)
- [ ] Migration: `supplier_external_ship_locations` (supplier_id → GPS location id) — only for multi-location accounts

## C. Fulfillment page (`/old-fulfillment`)
- [ ] `suppliers.can_autofulfill = 1` for the new supplier IDs → shows them in Create B2C Order dropdown (visibility flag only; no auto-ship job exists)
- [ ] **Block from Create B2B Order dropdown** (these GPS used-parts yards are B2C only, like Counselman/OEM Garage) → add supplier IDs to the B2B exclusion in `OldFulfillmentResource::getB2BSuppliers()`
- [ ] Per-vendor "Export Fulfillment Order" button:
  - `FulfillmentOrder` CSV + filename methods (standard "manager" template if no `recycler_stock` data; recycler-specific template if it does)
  - export action in `ListOldFulfillments`
  - button in `old-order-fulfillment.blade.php`

## D. Cross-cutting / decisions
- [ ] Exclusive (GPS-only, `exclusive: true`) vs dual (also ShipStation)
- [ ] Single-location vs multi-location-one-account (PartsBox/WAM pattern)
- [ ] HAZMAT: confirm whether the new supplier IDs need adding to the description-based HAZMAT derivation (`OrderItem::isHazmat()` + the order-items payload in `routes/web.php`; currently Counselman 75-78, PartsBox 79-82)
- [ ] GPS used-parts ship extras (`UsedPartsShipInfoResolver`): supplier→recycler_id map + per-supplier field sourcing (buyPrice / alternatePartNumber / etc.)

## E. Verify
- [ ] New codes appear in: bulk shipping (Filament + legacy) and single ship form
- [ ] B2C dropdown shows all the vendor's warehouses
- [ ] Export buttons download correct, vendor-scoped CSVs
- [ ] HAZMAT order is blocked from GPS
- [ ] (after GPS webhook live) tracking flows back to Central

---
_Reference: this session onboarded Wheels America (USER-47), Spalding (USER-49), OEM Garages (USER-48)._
