# DPD integration

DPD offers **home/business delivery** and **DPD Pickup parcelshops & lockers**.
Unlike Packeta, **nothing DPD-specific is scaffolded yet** in this repo, so this
is a full integration: an optional pickup widget plus the shipment-creation API.

---

## 1. Get a DPD account & API access

1. You need a **business contract** with DPD in your country (e.g. DPD SK:
   <https://www.dpd.com/sk>). Ask your account manager for **API access**.
2. DPD exposes a few different APIs depending on country/era — confirm which one
   your contract uses:
   - **REST Shipping API** (modern; JSON) — most new integrations.
   - **SOAP "Login/Shipment" web services** (older; still common in CEE).
   - Some markets use the **DPD Geodata / Shop Finder API** for parcelshops.
3. You'll receive: an **API base URL**, a **delisId / login**, and a
   **password** (the SOAP `login` call returns a short-lived **auth token** you
   reuse on subsequent calls). REST variants use an API key/token directly.
4. Note your **sender address** and **DPD customer number** — required on every
   shipment.

---

## 2. Decide which DPD services you offer

Create one delivery option per service at **`/admin/shipping`** → "Add delivery
option":

| Option | "Requires pickup point" | Notes |
|---|---|---|
| `DPD Home` (classic) | ❌ off | delivered to the address on the order |
| `DPD Pickup` (parcelshop/locker) | ✅ on | customer must choose a shop/locker |

For `DPD Pickup` you need a **point picker** (section 3). For `DPD Home` you can
skip straight to the API (section 4).

---

## 3. (Pickup only) Add the DPD parcelshop picker at checkout

The checkout already has the generic pickup machinery: when the selected method
has `requires_pickup_point = true`, the block with hidden `pickup_point_id` /
`pickup_point_name` shows (`assets/views/shop/checkout.html`, the `x-show=
"requiresPoint"` block). Today that block only renders the **Packeta** widget
(guarded by `{% if packeta_api_key %}`) or a text fallback.

To support DPD you make that block carrier-aware:

1. Pass a `dpd_enabled` / map-widget key flag into the checkout context from
   `src/controllers/checkout.rs` (like `packeta_api_key` is passed today).
2. In the pickup block, branch on the chosen `carrier` (the Alpine `carrier`
   variable already holds the method `code`) and render DPD's parcelshop map
   widget when a DPD pickup method is selected. DPD provides an embeddable
   **map/widget** (or you query their **Shop Finder API** and render your own
   list); on selection, write the shop id into `pointId` and a human label into
   `pointName` — exactly what the existing hidden inputs expect.

No new order fields are needed — `pickup_point_id` / `pickup_point_name` already
carry the DPD shop id + name.

---

## 4. Create shipments via the DPD API

Do the [shared groundwork](README.md#shared-groundwork-do-this-once-before-any-carriers-api-step)
first. Set `shipping_methods.carrier = "dpd"` for your DPD options.

### Auth (SOAP-style, common in CEE)

```bash
DPD_API_BASE=https://api.dpd.sk        # from your account manager
DPD_LOGIN=your_delis_login
DPD_PASSWORD=your_password
DPD_CUSTOMER_NUMBER=your_customer_no
```
Add matching lines under `settings:` in `config/*.yaml`:
```yaml
  dpd_api_base:        {{ get_env(name="DPD_API_BASE", default="") }}
  dpd_login:           {{ get_env(name="DPD_LOGIN", default="") }}
  dpd_password:        {{ get_env(name="DPD_PASSWORD", default="") }}
  dpd_customer_number: {{ get_env(name="DPD_CUSTOMER_NUMBER", default="") }}
```

### Flow

1. **Login** → `LoginService.getAuth(delisId, password)` returns an **auth
   token** (valid for a while; cache it).
2. **Create shipment** → `ShipmentService.storeOrders(...)` with the auth token,
   recipient address (or parcelshop id for Pickup), parcel weight, references
   (your `order_number`), and COD amount if cash-on-delivery. Returns a
   **parcel number (MPS id)** = your tracking number, plus label data.
3. **Label** → the same call (or `getParcelLabels`) returns a **PDF/ZPL label**;
   store or print it.

### Client sketch (`src/integrations/dpd.rs`)

```rust
use loco_rs::prelude::*;
use crate::shared::settings;

async fn auth_token(ctx: &AppContext) -> Result<String> {
    let base  = settings::get(ctx, "dpd_api_base").unwrap_or_default();
    let login = settings::get(ctx, "dpd_login").unwrap_or_default();
    let pass  = settings::get(ctx, "dpd_password").unwrap_or_default();
    // POST login → parse token from response. Cache it (e.g. in-memory w/ expiry).
    todo!()
}

pub async fn create_shipment(ctx: &AppContext, req: super::ShipmentRequest<'_>)
    -> Result<super::ShipmentResult>
{
    let token = auth_token(ctx).await?;
    let customer = settings::get(ctx, "dpd_customer_number").unwrap_or_default();
    // Build storeOrders payload:
    //  - product: "CL" (classic/home) or "Pickup" + parcelShopId = req.pickup_point_id
    //  - recipient: req.recipient_name / address / city / zip / country / phone
    //  - cod: req.cod_cents (set cash-on-delivery service if > 0)
    //  - reference: req.order_number
    // POST to {base}/shipment ... with `token`.
    todo!("parse parcel number + label into ShipmentResult")
}
```

Wire it into the admin "Create shipment" action for `carrier == "dpd"` orders.

---

## 5. Testing

- DPD provides a **test/integration environment** (separate base URL +
  credentials) — get it from your account manager. Validate login + one
  shipment there first.
- Confirm the returned parcel number tracks on
  `https://tracking.dpd.de/...` / your local DPD tracking site.

## 6. Go-live checklist

- [ ] DPD business contract + API credentials obtained
- [ ] `DPD_*` env vars set; matching `settings:` lines added to `config/production.yaml`
- [ ] Delivery option(s) created in `/admin/shipping` (`DPD Home` and/or `DPD Pickup`)
- [ ] `carrier = "dpd"` set on those methods (via the shared `carrier` column)
- [ ] (Pickup) parcelshop picker rendered in checkout for DPD methods
- [ ] `src/integrations/dpd.rs` implemented; login token caching working
- [ ] Test shipment in DPD test env → tracking number stored on order
- [ ] Switched base URL/credentials from test to production
