This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
spree_shipstation is a Spree e-commerce extension (gem) that integrates Spree stores with ShipStation. It exposes an XML endpoint that ShipStation polls for shipments, and a webhook endpoint that ShipStation POSTs to when a label is created (updating the Spree shipment with a tracking number and marking it shipped).
This gem targets Spree 5.x and uses the spree_extension framework for integration registration.
bundle exec rakeThe default Rake task automatically generates a dummy Rails app under spec/dummy/ if it doesn't exist, then runs the full spec suite.
bundle exec rake test_appbundle exec rspec spec/controllers/spree/shipstation_controller_spec.rbbundle exec standardrbbundle exec standardrb --fixThe extension registers itself with Spree's integration framework via config/initializers/spree.rb, which appends Spree::Integrations::Shipstation to spree.integrations. The integration model (app/models/spree/integrations/shipstation.rb) extends Spree::Integration and stores credentials as Spree preferences (preferred_username, preferred_password) with validations.
Export (GET /shipstation) — ShipStation polls this endpoint to fetch shipments ready to process:
Spree::ShipstationController#exportauthenticates via HTTP Basic Auth using credentials stored on the active store integration.- Queries
current_store.shipments.exportable— a scope added bySpree::ShipmentDecoratorthat filters forstate: "ready"on complete orders. - Filters by
start_date/end_dateparams (matching either shipment or orderupdated_at). If both params are absent or invalid, all exportable shipments are returned with no date filter. - Renders
app/views/spree/shipstation/export.xml.builderusing thebuildergem. XML structure is validated againstspec/fixtures/shipstation_xml_schema.xsdin tests. - Results are paginated at 50 per page.
Shipnotify (POST /shipstation) — ShipStation calls this when a label is created:
Spree::ShipstationController#shipnotifypassesorder_numberandtracking_numberparams toSpreeShipstation::ShipmentNotice.from_payload.ShipmentNotice#applylooks up theSpree::Shipmentby number, sets the tracking number, saves, then callsship!unless already shipped.- Errors from
SpreeShipstation::Errorsubclasses return HTTP 400; successes return HTTP 200.
Note on naming: ShipStation's webhook param is called
order_numberbut its value is actually the shipment number — it mirrors the<OrderNumber>field from the export XML, which is set toshipment.number.
| File | Purpose |
|---|---|
app/controllers/spree/shipstation_controller.rb |
Both endpoints; auth (constant-time secure_compare) + integration guard |
app/models/spree/integrations/shipstation.rb |
Integration model with credential preferences and validations |
app/models/spree/shipment_decorator.rb |
Adds :exportable and :between scopes to Spree::Shipment |
lib/spree_shipstation/shipment_notice.rb |
Plain Ruby object that applies a ship notification |
lib/spree_shipstation/errors.rb |
Custom error hierarchy (ShipmentNotFoundError, PaymentError, OrderNotPaidError) |
app/helpers/spree_shipstation/export_helper.rb |
Helper methods for building address XML nodes |
app/views/spree/shipstation/export.xml.builder |
XML template for ShipStation export |
app/views/spree/admin/integrations/forms/_shipstation.html.erb |
Admin UI partial for configuring credentials |
spec/support/auth_helper.rb— providesstub_basic_auth(username, password)for controller specs.spec/support/xsd.rb— provides thepass_validation(xsd_path)RSpec matcher for XML schema validation.spec/support/shipment_helper.rb— shipment-related test helpers.lib/spree_shipstation/testing_support/factories/shipstation_integration.rb— FactoryBot factory forSpree::Integrations::Shipstation.
| ShipStation status | Spree shipment state |
|---|---|
unpaid |
pending |
paid |
ready |
shipped |
shipped |
cancelled |
cancelled |
on-hold |
pending |