RTIX / src /application /services /routing.rs
github-actions
deploy: clean backend production release
7856e60
Raw
History Blame Contribute Delete
1.66 kB
use crate::application::services::pricing::LogisticsZone;
use crate::infrastructure::db::DbPool;
use serde::{Deserialize, Serialize};
#[derive(Debug, Serialize, Deserialize, Clone, sqlx::FromRow)]
pub struct CarrierRecord {
pub carrier_id: String,
pub name: String,
pub service_type: String,
pub base_rate: f64,
pub per_kg_rate: f64,
}
pub struct RoutingService {
pool: DbPool,
}
impl RoutingService {
pub fn new(pool: DbPool) -> Self {
Self { pool }
}
pub async fn select_optimal_carrier(
&self,
zone: LogisticsZone,
weight_grams: f64,
) -> Result<CarrierRecord, sqlx::Error> {
let service_type = match zone {
LogisticsZone::Local => "LOCAL",
LogisticsZone::Regional => "REGIONAL",
LogisticsZone::National => "NATIONAL",
};
let carriers = sqlx::query_as::<_, CarrierRecord>(
"SELECT carrier_id, name, service_type, base_rate, per_kg_rate FROM carrier_registry WHERE service_type = $1 AND is_active = TRUE"
)
.bind(service_type)
.fetch_all(&self.pool)
.await?;
// Simple cost-based selection: base_rate + (kg * per_kg_rate)
let weight_kg = weight_grams / 1000.0;
let best_carrier = carriers.into_iter().min_by(|a, b| {
let cost_a = a.base_rate + (weight_kg * a.per_kg_rate);
let cost_b = b.base_rate + (weight_kg * b.per_kg_rate);
cost_a
.partial_cmp(&cost_b)
.unwrap_or(std::cmp::Ordering::Equal)
});
best_carrier.ok_or_else(|| sqlx::Error::RowNotFound)
}
}