Add Create Test Shipment (Email SKU) for testing the return-label flow, plus test-mode/store_id investigation notes
Adds synthetic source="test" tickets (create_test_shipment_order/delete_test_shipments) carrying a company's real emailed-return-label SKU, so Step 1/Step 2 can be exercised against the sandbox without a real JIRA ticket or risking a real customer's. Gated to Test Mode - the same flow against production would create a real paid shipment. CLAUDE.md also captures this session's ShipStation sandbox findings: store_id is schema-optional but empirically required for label visibility, the newer ship15 web UI's URL is NOT the se- store ID (confirmed via direct probe - different failure shape than a wrong-but-well-formed ID), and two separate test stores/carriers are needed per company, mirroring production. Co-Authored-By: Claude Sonnet 5 <[email protected]>
This commit is contained in:
@@ -29,7 +29,10 @@ app/
|
||||
ticket_validation.py SKU validation rules (company mismatch, return/device mismatch)
|
||||
tracking.py suggest_jira_status() from tracking numbers
|
||||
external_links.py JIRA/Google Maps URL builders (View in JIRA, Look Up Address)
|
||||
workers.py QThread workers + save_orders()/load_orders_by_view()/etc.
|
||||
workers.py QThread workers + save_orders()/load_orders_by_view()/etc. -
|
||||
also create_test_shipment_order()/delete_test_shipments()
|
||||
(synthetic source="test" tickets for exercising the
|
||||
Create Return Label flow without a real JIRA ticket)
|
||||
services/
|
||||
base.py NormalizedOrder TypedDict, OrderService ABC
|
||||
jira_service.py JIRA REST API v3 /search/jql, paginated
|
||||
@@ -182,6 +185,59 @@ and copy its store_id into `TEST_SHIPSTATION_SIGNIFY_STORE_ID` /
|
||||
"Return label creation failed" / "invalid store" error on `store_id: 367672` (Oak
|
||||
Street's *production* `se-367672`, prefix stripped in the echoed error per point 8
|
||||
above) - happening because `TEST_SHIPSTATION_OAKSTREET_STORE_ID` was still blank.
|
||||
The fix requires **two separate manual stores in the sandbox account** (one per
|
||||
company), not one shared - mirrors production, which already has two independent
|
||||
store IDs (`SHIPSTATION_SIGNIFY_STORE_ID`/`SHIPSTATION_OAKSTREET_STORE_ID`), and the
|
||||
`TEST_*` settings already have two independent slots for exactly this. There was no
|
||||
way to confirm via API whether one store could technically be shared across
|
||||
companies in the sandbox (still no listing/inspection endpoint) - moot anyway, since
|
||||
per-company stores is the already-intended design.
|
||||
|
||||
**`store_id` is schema-optional, but don't take that as license to drop it**: checked
|
||||
ShipStation's own request schema for `POST /v2/labels` - `shipment.store_id` is NOT
|
||||
in the list of required fields (unlike `shipment.ship_to`), and nothing in the schema
|
||||
ties a store to a specific carrier/warehouse. But this app's own store_id check
|
||||
exists for a real, previously-confirmed reason (see Return Labels point 1 above): a
|
||||
label can come back `status: completed` from the API while being invisible anywhere
|
||||
in ShipStation's own UI. The schema being lenient doesn't mean this account's actual
|
||||
behavior is - keep requiring it. **Confirmed live, 2026-09-18** (three direct
|
||||
`POST /v2/labels` probes against the sandbox key, harmless - sandbox labels, no real
|
||||
cost): omitting `store_id` entirely succeeds cleanly (`200`, `status: "completed"`,
|
||||
real label `se-201075505`) - so it genuinely is optional API-side, exactly as the
|
||||
schema says. Whether that label is actually visible in ShipStation's own UI (the
|
||||
thing that would tell us if the "invisible label" concern really extends to
|
||||
store_id, or was specific to unlinked return labels) still needs a human to check the
|
||||
sandbox account's Orders/Shipments list for `external_shipment_id:
|
||||
STORE-PROBE-no-store-id-at-all`.
|
||||
|
||||
**A separate, unrelated test-mode gap found 2026-09-18**: `TEST_SIGNIFY_RETURN_CARRIER_ID`/
|
||||
`TEST_OAKSTREET_RETURN_CARRIER_ID` were blank (only the `*_SERVICE_CODE` halves had
|
||||
been filled in earlier), producing "No return-label Carrier ID/Service Code
|
||||
configured" on Step 1. Not a new discovery - just the confirmed shared sandbox test
|
||||
carrier (`se-6366092`, UPS) from earlier in this section, re-verified live and filled
|
||||
into both settings. Worth knowing for next time: `TEST_SIGNIFY_RETURN_SERVICE_CODE`/
|
||||
`TEST_OAKSTREET_RETURN_SERVICE_CODE` being set doesn't imply their carrier-ID
|
||||
counterparts are - check both halves of a `TEST_*_RETURN_*` pair, not just one.
|
||||
|
||||
**The newer ShipStation web UI's URL is NOT the `se-` store ID - confirmed, don't
|
||||
reuse it.** Creating a manual store at `ship15.shipstation.com/settings/stores/...`
|
||||
shows a UUID in the URL (e.g. `081cf783-32b2-4b52-b9f8-767531d0ac47`), not an
|
||||
`se-XXXXX` ID. This is ShipStation's newer/redesigned web UI - that UUID is its own
|
||||
internal routing ID, a completely different ID space from the V2 API's store IDs, not
|
||||
just a missing `se-` prefix (the `se-` prefix quirk documented above only ever
|
||||
applies to genuinely `se-`-shaped IDs missing their prefix, not arbitrary UUIDs).
|
||||
Confirmed by direct probe: a known-fake-but-correctly-shaped ID (`se-999999999`)
|
||||
gets the expected clean `400 "invalid store"`, but that UUID (tried both raw and
|
||||
with `se-` prepended) gets a `500 "An unexpected error occurred"` instead - a
|
||||
different failure shape entirely, meaning the API doesn't even recognize it as a
|
||||
candidate ID, let alone a wrong one. **Don't paste that URL UUID into
|
||||
`TEST_SHIPSTATION_*_STORE_ID` and expect it to work.** The real `se-` ID for a
|
||||
store created in this newer UI needs to come from somewhere else - check the store's
|
||||
own settings *page content* (not the URL) for an API/Integration section that
|
||||
displays it as text, or fall back to ShipStation support (their own help docs say
|
||||
this explicitly: "contact our support team and tell them the name of the manual
|
||||
store" is a valid way to get a store_id when the List Stores API isn't an option -
|
||||
see the store_id dead-end note above).
|
||||
|
||||
**Production readiness check, 2026-09-16 (read-only, no labels created, no cost)**:
|
||||
before a first real production test of the return-label flow, ran `GET /v2/carriers`,
|
||||
@@ -201,6 +257,21 @@ production API key and diffed the results against `.env`:
|
||||
check. If it fails, expect the same "invalid store" error shape as the test-mode one;
|
||||
the fix then is re-checking the store_id in ShipStation's own UI, not the code.
|
||||
|
||||
**Testing the emailed-return-label SKU flow without a real ticket**: "Create Test
|
||||
Shipment (Email SKU)..." (Data menu, Test Mode only) creates a synthetic
|
||||
`source="test"` Order carrying that company's configured emailed-return-label SKU
|
||||
(resolved from `EMAILED_LABEL_SKUS` + `COMPANY_SKU_MAP` at creation time, not
|
||||
hardcoded to SH007/OK012) and a placeholder shipping address, then drops it on the
|
||||
Active tab (`status="Created"`) so it can be selected and run through the *real*
|
||||
Create Return Label flow - same code path a JIRA ticket uses, no separate test-only
|
||||
logic to keep in sync. `source="test"` guarantees `save_orders()` (which only ever
|
||||
matches on `source == "jira"`) can never touch or overwrite one of these, so a real
|
||||
Import from JIRA is safe to run with test shipments still sitting on the board.
|
||||
"Delete Test Shipments..." cleans them up by that same `source` marker, real tickets
|
||||
untouched. **Deliberately gated to Test Mode** - the same flow against production
|
||||
settings would create a real, paid UPS shipment to a fake address, not just a
|
||||
sandbox test label.
|
||||
|
||||
**Real limitations of ShipStation's sandbox (confirmed via their own docs, not
|
||||
assumed) that constrain what test mode can actually verify:**
|
||||
- Branded Labels / Branded Tracking Pages are NOT available in sandbox. This directly
|
||||
@@ -289,16 +360,22 @@ change without a deliberate separate conversation about it.
|
||||
|
||||
## Known-pending / not yet built
|
||||
|
||||
- **Immediate next step, as of the last working session**: the warehouse_id issue is
|
||||
now fixed code-side ("Create Test Warehouse(s)..." in the Data menu, see ShipStation
|
||||
Test Mode above) but hasn't been run/confirmed yet - run it, confirm the two
|
||||
`TEST_SHIPSTATION_*_WAREHOUSE_ID` settings got saved. Then a *second*, separate
|
||||
test-mode gap surfaced right after: an "invalid store" error on Oak Street's
|
||||
production store_id, because `TEST_SHIPSTATION_*_STORE_ID` is blank and there is no
|
||||
API-based fix for that one (see ShipStation Test Mode above) - both
|
||||
`TEST_SHIPSTATION_SIGNIFY_STORE_ID` and `TEST_SHIPSTATION_OAKSTREET_STORE_ID` still
|
||||
need to be filled in by hand from the sandbox account's own ShipStation UI before the
|
||||
emailed-return-label flow can be tested end-to-end in test mode.
|
||||
- **Immediate next step, as of the last working session**: the warehouse_id gap is
|
||||
fixed and confirmed (both `TEST_SHIPSTATION_*_WAREHOUSE_ID` settings are populated).
|
||||
The store_id gap is still open and turned out to be more involved than the
|
||||
warehouse one: two manual stores were created in the sandbox account, one per
|
||||
company (see ShipStation Test Mode above for why two, not one), but ShipStation's
|
||||
newer web UI (`ship15.shipstation.com`) only exposes a UUID in the URL, not the
|
||||
`se-XXXXX` ID this app's `TEST_SHIPSTATION_*_STORE_ID` settings need - confirmed via
|
||||
direct API probe that this UUID is not a usable store_id at all (a different,
|
||||
`500`-shaped failure than a genuinely wrong-but-well-formed ID gets). The real
|
||||
`se-` ID for each new store still needs to be found (store settings page content,
|
||||
or ShipStation support) before the emailed-return-label flow can be tested
|
||||
end-to-end in test mode. Also still open: whether a label with NO store_id at all
|
||||
is actually visible in ShipStation's UI - confirmed live that the API accepts a
|
||||
request with the field omitted (see ShipStation Test Mode above), which, if it
|
||||
turns out to be visible too, could make chasing the real store_id unnecessary for
|
||||
test mode specifically.
|
||||
- **EOD JIRA push**: deliberately deferred. `packed`, `serial_numbers`,
|
||||
`tracking_numbers`, `shipping_method`, `assignee` are all captured and ready for it
|
||||
whenever it's prioritized - would need the exact JIRA custom field IDs (outbound
|
||||
|
||||
Reference in New Issue
Block a user