RTIX / src /application /services /pricing.rs
github-actions
deploy: clean backend production release
c33971d
use serde::{Deserialize, Serialize};
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct LogisticsConfig {
pub weight_coefficient: f64,
pub distance_coefficient: f64,
pub complexity_bias: f64,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub enum LogisticsZone {
Local, // Within city (< 50km)
Regional, // Within state (50 - 300km)
National, // Outside state (> 300km)
}
impl Default for LogisticsConfig {
fn default() -> Self {
Self {
weight_coefficient: 0.15, // Adjusted for Indian gram-based pricing
distance_coefficient: 1.0,
complexity_bias: 1.0,
}
}
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct PricingFeatures {
pub distance_km: f64,
pub user_rate_per_km: f64,
pub product_weight: f64,
pub base_charge: f64,
pub config: LogisticsConfig,
}
// ========================================================
// ADVANCED OOPS CONCEPTS: POLYMORPHIC ZONAL PRICING
// ========================================================
/// Strategy trait for calculating regional zone pricing coefficients.
pub trait ZonalPricingStrategy: Send + Sync {
fn multiplier(&self) -> f64;
}
pub struct LocalZoneStrategy;
impl ZonalPricingStrategy for LocalZoneStrategy {
fn multiplier(&self) -> f64 {
1.0
}
}
pub struct RegionalZoneStrategy;
impl ZonalPricingStrategy for RegionalZoneStrategy {
fn multiplier(&self) -> f64 {
1.5
}
}
pub struct NationalZoneStrategy;
impl ZonalPricingStrategy for NationalZoneStrategy {
fn multiplier(&self) -> f64 {
2.5
}
}
/// Factory pattern to retrieve the correct zonal pricing strategy object dynamically.
pub struct ZonalPricingStrategyFactory;
impl ZonalPricingStrategyFactory {
pub fn get_strategy(distance_km: f64) -> Box<dyn ZonalPricingStrategy> {
if distance_km < 50.0 {
Box::new(LocalZoneStrategy)
} else if distance_km < 300.0 {
Box::new(RegionalZoneStrategy)
} else {
Box::new(NationalZoneStrategy)
}
}
}
// ========================================================
// PRICING ENGINE CLASS IMPLEMENTATION
// ========================================================
/// The `PricingEngine` handles the platform's economic logic, including dynamic delivery fees
/// and trust-adjusted platform service charges. Refactored using dynamic strategy patterns.
pub struct PricingEngine;
impl PricingEngine {
/// Estimates the delivery fee using a multi-factor linear estimation model.
///
/// The model accounts for:
/// 1. **Zonal Logic**: Higher multipliers for cross-state shipments (polymorphically resolved).
/// 2. **Volumetric Weight**: Uses a gram-to-kg conversion with configurable coefficients.
/// 3. **Distance Variable**: Direct linear scaling with the merchant's custom rate-per-km.
pub fn estimate_delivery_fee(features: PricingFeatures) -> f64 {
let strategy = ZonalPricingStrategyFactory::get_strategy(features.distance_km);
let zone_multiplier = strategy.multiplier();
// Convert weight from grams to kg for institutional pricing parity
let weight_kg = features.product_weight / 1000.0;
let weight_component = weight_kg * features.config.weight_coefficient * 50.0; // ₹50 per kg baseline
let base_with_zone = features.base_charge * zone_multiplier;
let distance_component = features.distance_km
* (features.user_rate_per_km * features.config.distance_coefficient);
let raw_total = (base_with_zone + distance_component + weight_component)
* features.config.complexity_bias;
// Perform final rounding to match currency precision
(raw_total * 100.0).round() / 100.0
}
/// Calculates the platform's service fee for a transaction.
///
/// This is a **Secure Incentive** model:
/// - Base fees are tiered by transaction value.
/// - **Trust Discount**: High trust scores (0-100) provide a linear discount of up to 50%.
pub fn calculate_platform_fee(_price: f64, _trust_score: f64) -> f64 {
0.0
}
/// Aggregates all price components into a final total consumer charge.
pub fn calculate_total_consumer_price(
product_price: f64,
delivery_fee: f64,
tax_amount: f64,
_trust_score: f64,
) -> f64 {
((product_price + delivery_fee + tax_amount) * 100.0).round() / 100.0
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_zero_distance_pricing() {
let features = PricingFeatures {
distance_km: 0.0,
user_rate_per_km: 15.0,
product_weight: 500.0,
base_charge: 20.0,
config: LogisticsConfig::default(),
};
let fee = PricingEngine::estimate_delivery_fee(features);
// (0 * 15 + 0.5 * 0.15 * 50 + 20 * 1.0) * 1.0 = 23.75
assert_eq!(fee, 23.75);
}
#[test]
fn test_extreme_weight_pricing() {
let features = PricingFeatures {
distance_km: 10.0,
user_rate_per_km: 15.0,
product_weight: 100000.0, // 100kg
base_charge: 20.0,
config: LogisticsConfig::default(),
};
let fee = PricingEngine::estimate_delivery_fee(features);
// (150 + 100 * 0.15 * 50 + 20) = 150 + 750 + 20 = 920.0
assert_eq!(fee, 920.0);
}
}