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 { 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) } }