Files
kompress_eshop/src/integrations/mod.rs
2026-06-17 18:02:46 +02:00

67 lines
2.5 KiB
Rust

//! Outbound carrier integrations for creating shipments.
//!
//! Shipments are **never created automatically**. An admin reviews an order and,
//! once the goods are physically ready, explicitly triggers
//! [`create_shipment`] from the order page. Only then does the eshop call the
//! carrier's API. `orders::place` (checkout) does not touch any of this.
//!
//! Each delivery option (`shipping_methods.carrier`) maps to one carrier here.
//! "none" means the option is fulfilled manually and has no API.
pub mod dhl;
pub mod dpd;
pub mod packeta;
use loco_rs::prelude::*;
/// Everything a carrier needs to register a parcel, snapshotted from an order.
pub struct ShipmentRequest<'a> {
pub order_number: &'a str,
pub recipient_name: &'a str,
pub email: &'a str,
pub phone: Option<&'a str>,
pub address: Option<&'a str>,
pub city: Option<&'a str>,
pub zip: Option<&'a str>,
pub country: Option<&'a str>,
/// Carrier pickup-point / locker id, when the method requires one.
pub pickup_point_id: Option<&'a str>,
/// Cash-on-delivery amount in cents; `0` when payment is not COD.
pub cod_cents: i64,
pub currency: &'a str,
/// Total order value in cents (for insurance / customs declarations).
pub value_cents: i64,
pub weight_grams: i32,
}
/// What a carrier returns once the parcel is registered.
pub struct ShipmentResult {
/// Carrier-internal shipment/packet id.
pub shipment_id: String,
/// Public tracking number / barcode shown to the customer.
pub tracking_number: String,
/// Direct link to the shipping label PDF, if the carrier returns one.
pub label_url: Option<String>,
}
/// Dispatch to the carrier named by `shipping_methods.carrier`. Returns an error
/// for `"none"` (manual fulfilment) or an unknown carrier.
pub async fn create_shipment(
ctx: &AppContext,
carrier: &str,
req: ShipmentRequest<'_>,
) -> Result<ShipmentResult> {
match carrier {
"packeta" => packeta::create_shipment(ctx, req).await,
"dpd" => dpd::create_shipment(ctx, req).await,
"dhl" => dhl::create_shipment(ctx, req).await,
"none" | "" => Err(Error::BadRequest(
"this delivery option is fulfilled manually (no carrier API)".to_string(),
)),
other => Err(Error::BadRequest(format!("unknown carrier '{other}'"))),
}
}
/// The carrier values offered in the admin UI. `none` is the manual default.
pub const CARRIERS: [&str; 4] = ["none", "packeta", "dpd", "dhl"];