151 lines
6.2 KiB
Markdown
151 lines
6.2 KiB
Markdown
# DHL integration
|
|
|
|
DHL is best for **home delivery and international/express** shipments. Like DPD,
|
|
**nothing DHL-specific is scaffolded** here. DHL is mostly an **address (home)
|
|
delivery** carrier — pickup points exist (DHL ServicePoint / Packstation, mostly
|
|
DE) but most shops use DHL for door-to-door, so you can usually skip the pickup
|
|
widget entirely.
|
|
|
|
> DHL has **several separate APIs** behind one developer portal
|
|
> (<https://developer.dhl.com>). Pick the one that matches your service:
|
|
> - **DHL Parcel DE (Post & Parcel Germany) — Shipping API** for German domestic
|
|
> parcels / Packstation.
|
|
> - **DHL eCommerce (Parcel) APIs** for various countries.
|
|
> - **DHL Express — MyDHL API** for international express.
|
|
> Confirm which your contract covers before coding.
|
|
|
|
---
|
|
|
|
## 1. Get DHL API access
|
|
|
|
1. Create an account on the **DHL Developer Portal**: <https://developer.dhl.com>.
|
|
2. Create an **app** and subscribe it to the specific API you need (e.g.
|
|
"Shipping API" or "MyDHL API"). You receive an **API key (client id) +
|
|
secret**.
|
|
3. Separately you need a **DHL business/customer account** (EKP / account
|
|
number, billing number) — the developer key alone can't bill shipments. Link
|
|
your business account credentials to the app.
|
|
4. Most DHL APIs use **OAuth2 client-credentials**: you exchange key+secret for a
|
|
short-lived **Bearer token**, then call the shipping endpoints with it. (Some
|
|
older endpoints use Basic auth — check your API's docs.)
|
|
|
|
---
|
|
|
|
## 2. Create the delivery option
|
|
|
|
At **`/admin/shipping`** → "Add delivery option":
|
|
- **Name**: e.g. `DHL` or `DHL Express (international)`
|
|
- **Price**: your fee
|
|
- **Requires pickup point**: ❌ off for normal home delivery
|
|
(turn ✅ on *only* if you specifically offer DHL Packstation/ServicePoint and
|
|
build a picker — see section 4)
|
|
- ✅ **Active**
|
|
|
|
With the option active, customers can already choose DHL and you can create the
|
|
label manually in DHL Business Customer Portal. The API (section 3) automates
|
|
that.
|
|
|
|
---
|
|
|
|
## 3. Create shipments via the DHL API
|
|
|
|
Do the [shared groundwork](README.md#shared-groundwork-do-this-once-before-any-carriers-api-step)
|
|
first. Set `shipping_methods.carrier = "dhl"` for your DHL options.
|
|
|
|
### Credentials
|
|
|
|
```bash
|
|
DHL_API_KEY=your_client_id
|
|
DHL_API_SECRET=your_client_secret
|
|
DHL_ACCOUNT_NUMBER=your_ekp_or_billing_number
|
|
DHL_API_BASE=https://api-eu.dhl.com # depends on the specific API
|
|
```
|
|
Add matching lines under `settings:` in `config/*.yaml`:
|
|
```yaml
|
|
dhl_api_key: {{ get_env(name="DHL_API_KEY", default="") }}
|
|
dhl_api_secret: {{ get_env(name="DHL_API_SECRET", default="") }}
|
|
dhl_account_number: {{ get_env(name="DHL_ACCOUNT_NUMBER", default="") }}
|
|
dhl_api_base: {{ get_env(name="DHL_API_BASE", default="") }}
|
|
```
|
|
|
|
### Flow (OAuth2 + create shipment)
|
|
|
|
1. **Token** → `POST {base}/.../token` with `grant_type=client_credentials` +
|
|
key/secret → `access_token` (Bearer; cache until it expires).
|
|
2. **Create shipment** → `POST` the shipment-orders endpoint with the Bearer
|
|
token: shipper (your account/EKP), consignee (recipient from the order),
|
|
product code (domestic vs international/express), weight, customs data for
|
|
non-EU, and references (`order_number`). COD is a value-added service if you
|
|
offer it.
|
|
3. **Label** → the response includes a **tracking/shipment number** and a
|
|
**label** (PDF/base64). Store/print it.
|
|
|
|
### Client sketch (`src/integrations/dhl.rs`)
|
|
|
|
```rust
|
|
use loco_rs::prelude::*;
|
|
use crate::shared::settings;
|
|
|
|
async fn bearer(ctx: &AppContext) -> Result<String> {
|
|
let base = settings::get(ctx, "dhl_api_base").unwrap_or_default();
|
|
let key = settings::get(ctx, "dhl_api_key").unwrap_or_default();
|
|
let secret = settings::get(ctx, "dhl_api_secret").unwrap_or_default();
|
|
// POST client_credentials → access_token; cache with expiry.
|
|
todo!()
|
|
}
|
|
|
|
pub async fn create_shipment(ctx: &AppContext, req: super::ShipmentRequest<'_>)
|
|
-> Result<super::ShipmentResult>
|
|
{
|
|
let token = bearer(ctx).await?;
|
|
let account = settings::get(ctx, "dhl_account_number").unwrap_or_default();
|
|
// Build shipment JSON:
|
|
// - shipper: your account address (account = EKP/billing number)
|
|
// - consignee: req.recipient_name / address / city / zip / country
|
|
// - details: weight, product code (domestic / express), currency
|
|
// - refs: req.order_number
|
|
// - for international: customs (HS codes, declared value, contents)
|
|
// POST {base}/.../shipments with Authorization: Bearer {token}
|
|
todo!("parse tracking number + label into ShipmentResult")
|
|
}
|
|
```
|
|
|
|
Wire into the admin "Create shipment" action for `carrier == "dhl"` orders.
|
|
|
|
> 🌍 **International note:** for shipments outside the EU customs union you must
|
|
> send **customs/commodity data** (HS codes, declared value, item descriptions).
|
|
> Your `order_items` only store name + price today — if you ship internationally
|
|
> you'll likely add a customs description/HS-code field to products.
|
|
|
|
---
|
|
|
|
## 4. (Optional) DHL pickup points
|
|
|
|
If you offer **Packstation / ServicePoint**, set "Requires pickup point" ✅ on
|
|
that delivery option and render DHL's **Location Finder** (a separate DHL API)
|
|
in the checkout pickup block (the `x-show="requiresPoint"` section of
|
|
`assets/views/shop/checkout.html`), writing the chosen locker id into the
|
|
existing hidden `pickup_point_id` / `pickup_point_name` fields. For Packstation
|
|
you also need the recipient's **DHL post number** — an extra field most shops
|
|
avoid unless targeting Germany.
|
|
|
|
---
|
|
|
|
## 5. Testing
|
|
|
|
- DHL provides a **sandbox** environment per API (separate base URL + test
|
|
credentials) on the developer portal. Get a token and create one test
|
|
shipment there before production.
|
|
- Validate the tracking number on <https://www.dhl.com/track>.
|
|
|
|
## 6. Go-live checklist
|
|
|
|
- [ ] DHL developer app created + subscribed to the right API
|
|
- [ ] DHL business account (EKP/billing number) linked
|
|
- [ ] `DHL_*` env vars set; matching `settings:` lines added to `config/production.yaml`
|
|
- [ ] Delivery option created in `/admin/shipping`; `carrier = "dhl"` set
|
|
- [ ] `src/integrations/dhl.rs` implemented; OAuth token caching working
|
|
- [ ] (International) customs data available on products/items
|
|
- [ ] Test shipment in DHL sandbox → tracking number stored on order
|
|
- [ ] Switched from sandbox to production base URL/credentials
|