From dd125187863624f6e285a278791f20793492d863 Mon Sep 17 00:00:00 2001 From: nutcas3 Date: Sat, 25 Apr 2026 00:51:15 +0300 Subject: [PATCH] feat: Refactor rating_billing to use async rating plans from Postgres and multiplexed Redis connections - Remove RatingPlan import and update get_rating_plan call to async with await - Update generate_invoice to use get_multiplexed_async_connection instead of get_async_connection - Replace context error handling with map_err for RedisConnection/RedisOperation errors - Add explicit redis::AsyncCommands trait qualification for keys/get/set operations - Update apply_monthly_fees to use async get_rating --- .../src/charging/rating_billing.rs | 36 ++++++++++--------- 1 file changed, 19 insertions(+), 17 deletions(-) diff --git a/apps/charging-engine/src/charging/rating_billing.rs b/apps/charging-engine/src/charging/rating_billing.rs index 81cf805..1de0ed3 100644 --- a/apps/charging-engine/src/charging/rating_billing.rs +++ b/apps/charging-engine/src/charging/rating_billing.rs @@ -1,7 +1,7 @@ use chrono::Utc; use tracing::{info, debug, warn}; -use super::types::{UsageEvent, UsageType, RatingPlan}; +use super::types::{UsageEvent, UsageType}; use crate::errors::{ChargingError, ChargingResult, ErrorContext}; impl super::ChargingEngine { @@ -10,8 +10,10 @@ impl super::ChargingEngine { let account = self.get_subscriber_account(&event.imsi).await?; let account = account.ok_or_else(|| ChargingError::SubscriberNotFound(event.imsi.clone()))?; - // Get rating plan (simplified - in real implementation this would be more complex) - let plan = self.get_rating_plan("basic") // Default to basic plan for now + // Get rating plan from Postgres (simplified - defaults to basic). + let plan = self + .get_rating_plan("basic") + .await? .ok_or_else(|| ChargingError::RatingPlanNotFound("basic".to_string()))?; let cost = match event.usage_type { @@ -126,18 +128,18 @@ impl super::ChargingEngine { pub async fn generate_invoice(&self, imsi: &str, billing_period: &str) -> ChargingResult { // Get all usage events for the billing period - let mut conn = self.redis_client.get_async_connection().await - .context("Failed to get Redis connection")?; + let mut conn = self.redis_client.get_multiplexed_async_connection().await + .map_err(|e| crate::errors::ChargingError::RedisConnection(e.to_string()))?; let pattern = format!("usage:{}:*", imsi); - let keys: Vec = conn.keys(&pattern).await - .context("Failed to get usage keys")?; + let keys: Vec = redis::AsyncCommands::keys(&mut conn, &pattern).await + .map_err(|e| ChargingError::RedisOperation(e.to_string()))?; let mut total_cost = 0.0; let mut usage_count = 0; for key in keys { - if let Ok(Some(event)) = conn.get::<_, Option>(&key).await { + if let Ok(Some(event)) = redis::AsyncCommands::get::<_, Option>(&mut conn, &key).await { // Filter by billing period (simplified) total_cost += event.cost; usage_count += 1; @@ -151,23 +153,23 @@ impl super::ChargingEngine { } pub async fn apply_monthly_fees(&self) -> ChargingResult { - let mut conn = self.redis_client.get_async_connection().await - .context("Failed to get Redis connection")?; + let mut conn = self.redis_client.get_multiplexed_async_connection().await + .map_err(|e| crate::errors::ChargingError::RedisConnection(e.to_string()))?; let pattern = "account:*".to_string(); - let keys: Vec = conn.keys(&pattern).await - .context("Failed to get account keys")?; + let keys: Vec = redis::AsyncCommands::keys(&mut conn, &pattern).await + .map_err(|e| ChargingError::RedisOperation(e.to_string()))?; let mut processed_accounts = 0; for key in keys { - if let Ok(Some(mut account)) = conn.get::<_, Option>(&key).await { - // Get rating plan and apply monthly fee - if let Some(plan) = self.get_rating_plan("basic") { // Simplified + if let Ok(Some(mut account)) = redis::AsyncCommands::get::<_, Option>(&mut conn, &key).await { + // Get rating plan from Postgres and apply monthly fee. + if let Ok(Some(plan)) = self.get_rating_plan("basic").await { account.balance -= (plan.monthly_fee * 100.0) as i64; // Convert to cents account.last_updated = Utc::now(); - - let _: () = conn.set(&key, &account).await.unwrap_or(()); + + let _: () = redis::AsyncCommands::set(&mut conn, &key, &account).await.unwrap_or(()); processed_accounts += 1; } }