Weave Code
Weaver
Helps Laravel developers discover, compare, and choose open-source packages. See popularity, security, maintainers, and scores at a glance to make better decisions.
Feedback
Share your thoughts, report bugs, or suggest improvements.
Subject
Message

Logistics Laravel Package

finecho/logistics

finecho/logistics is a Laravel package for express and logistics tracking, with a driver-based API for querying shipment status through popular courier services. Configure credentials, send tracking requests, and handle responses cleanly in PHP.

Deep Wiki
Context7

Getting Started

This is a small Laravel wrapper around Chinese carrier-tracking aggregators (快递100 / 快递鸟-style APIs) — it takes a tracking number plus a carrier code and returns the tracking timeline. Treat it as a thin HTTP adapter, not a logistics platform.

Minimal setup:

  1. composer require finecho/logistics
  2. Check composer.json → extra.laravel for auto-discovery. Given the 2021 last release, it likely targets Laravel 8/9; you may need a fork or --ignore-platform-reqs on Laravel 10/11 (see Gotchas).
  3. Publish the config: php artisan vendor:publish --provider="Finecho\Logistics\LogisticsServiceProvider" (or --tag=logistics).
  4. Put vendor credentials in .env — the config will expect a customer/customer id and an API key for whichever aggregator driver is the default.
  5. First use case: an order-detail "查看物流" panel. Resolve the facade (Finecho\Logistics\Facades\Logistics), pass tracking number + carrier code, render the returned trace array as a vertical timeline.

Where to look first: read src/ end-to-end — it's small enough to finish in 15 minutes, which is the cheapest way to confirm the actual method names, the driver contract, and the response shape before you write anything on top of it. Then look at config/logistics.php for the driver list and credential keys, and the service provider for bindings/facade alias.

Implementation Patterns

Never call the package directly from controllers. Wrap it in App\Services\LogisticsTracker (or an action class) that exposes track(Shipment $shipment): TrackingResult. Given the package's age, this is the single highest-leverage decision you'll make — it makes the eventual swap to AfterShip/17track/your own HTTP client a one-file change.

Persist, don't proxy. Create shipments and shipment_events tables. On each query, upsert events keyed by (shipment_id, occurred_at, description_hash) so re-polling is idempotent. Your UI then reads from your DB and never blocks on a vendor call.

Normalize status codes. Vendor responses use Chinese status strings/numbers (已签收, 派送中, 退回). Map them into your own enum — pending | picked_up | in_transit | out_for_delivery | delivered | exception | returned — inside the wrapper. Everything downstream (notifications, "delivered" triggers, SLA reports) should key off your enum, never off the raw vendor value.

Cache hard and poll on a schedule. These APIs are quota-limited and often billed per query. Cache by logistics:{carrier}:{tracking_no} with a conditional TTL: ~30–60 min while in transit, 24h+ once delivered, and a terminal no-retry state for "no tracking info yet". Then run a queued/scheduled job that refreshes only open shipments, rather than querying on every page view.

Queue the calls. Dispatch a job when a shipment is created and again on a schedule. Set an explicit HTTP timeout and retryUntil/backoff; vendor endpoints routinely hang for 10–30s.

Carrier code mapping is its own table. Your internal courier (sf, zto) does not equal the vendor's code (shunfeng, zhongtong), and codes differ between 快递100 and 快递鸟. Keep a carriers table with internal_code, vendor_code, vendor_driver columns so a driver change doesn't require a code deploy.

Driver failover. If the package exposes a manager (Logistics::driver('x')) with a default config key, use it: primary aggregator in config, secondary as fallback in your wrapper when the first returns a quota or signature error. If push/callback (订阅) mode is supported, prefer it over polling — it cuts query costs dramatically and gives fresher events; mount a signature-verifying route and upsert into shipment_events.

Test against a fake, not the network. Use Http::fake() with recorded vendor payloads (Chinese strings, empty traces, error envelopes) and assert on your normalized DTO. Never assert on the package's raw array shape.

Gotchas and Tips

  • Maintenance risk is the headline. Last release December 2021. Expect illuminate/support version pins to block installation on modern Laravel; fork it, loosen the constraint, and vendor the fork under a VCS repository entry. Don't plan on upstream fixes for changed vendor signing schemes.
  • Auto-discovery may be absent. Older packages omit extra.laravel. If Logistics:: isn't resolvable, register the provider in bootstrap/providers.php (or config/app.php) and add the facade alias manually.
  • HTTP 200 does not mean success. These aggregators commonly return errors in the body with a 200 status — check the result/status/message fields explicitly and translate Chinese error strings into typed exceptions (QuotaExceeded, InvalidSignature, NoTrackingInfo) so your retry logic can distinguish "retry later" from "never retry".
  • Signing is fiddly and version-dependent. 快递100-style APIs MD5 the JSON param plus customer and key (frequently uppercased) and require URL-encoding in a specific order; the "实时查询" and "订阅推送" endpoints have different contracts. If the package only implements one, verify against the vendor's current docs before assuming parity.
  • Chinese-only docs. Budget time for the vendor docs, not the package README. Error codes are the fastest debugging path — log the full raw response (redacted) at debug level on failure.
  • Thundering herd. A status page refreshing a popular shipment will fan out into N vendor calls. Wrap the query in Cache::lock("logistics:{$no}") and serve stale data on lock contention.
  • PII leaks in traces. Vendor payloads often echo recipient phone numbers and full addresses in event descriptions. Strip or mask before persisting — this is a compliance issue, not a cosmetic one.
  • Charset/encoding. Ensure the response is decoded as UTF-8 and your tables/columns are utf8mb4; mangled Chinese in traces is almost always a connection charset issue, not the package.
  • Coverage boundary. This is built around Chinese domestic couriers. If you ship internationally, plan for a second provider from day one rather than stretching this one.
  • Extension point that matters: the driver contract. Implementing your own driver against a different aggregator and registering it in config/logistics.php is cleaner than patching the vendor's — and your LogisticsTracker wrapper means you can do it incrementally, one carrier at a time.
Weaver

How can I help you explore Laravel packages today?

Conversation history is not saved when not logged in.
Prompt
Add packages to context
No packages found.
diephp/sequences
users-au/socialite-provider
twidpay/twid-logger
mrnewport/laravel-plaid
mrnewport/laravel-repo
mrnewport/laravel-docsign
mrnewport/laravel-stow
mrnewport/laravel-flow
mrnewport/laravel-priceable
mrnewport/laravel-nestedterms
fredmeng/laravel-apidoc-generator
itstructure/laravel-multilingual-tools
pdustdar/elasticsearch
markupai/php-sdk
rlacerda83/lumem-microservice-shipment
uni-method/symfony-lib
tacticmedia/scim-server-bundle
neika-ai/symfony-bundle
mattleads/agent-publishing-bundle
glavweb/framework-bundle