//! 股息分配系统 //! //! 实现证券型资产的股息计算、分配和记录功能 use std::collections::HashMap; use serde::{Serialize, Deserialize}; /// 股息分配记录 #[derive(Debug, Clone, Serialize, Deserialize)] pub struct DividendRecord { /// 分配ID pub id: String, /// 证券分区ID pub security_id: [u8; 32], /// 分配时间戳 pub timestamp: u64, /// 每股股息金额 pub amount_per_share: u64, /// 总分配金额 pub total_amount: u64, /// 受益人数量 pub beneficiary_count: usize, /// 分配状态 pub status: DividendStatus, /// 税率(百分比,例如15表示15%) pub tax_rate: u8, } /// 股息分配状态 #[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)] pub enum DividendStatus { /// 待分配 Pending, /// 分配中 Distributing, /// 已完成 Completed, /// 已取消 Cancelled, } /// 个人股息记录 #[derive(Debug, Clone, Serialize, Deserialize)] pub struct PersonalDividend { /// 分配ID pub dividend_id: String, /// 账户地址 pub account: String, /// 持股数量 pub shares: u64, /// 税前金额 pub gross_amount: u64, /// 税额 pub tax_amount: u64, /// 税后金额(实际到账) pub net_amount: u64, /// 领取状态 pub claimed: bool, /// 领取时间 pub claim_time: Option, } /// 股息分配引擎 #[derive(Debug)] pub struct DividendEngine { /// 股息分配记录 records: HashMap, /// 个人股息记录 personal_dividends: HashMap>, /// 下一个分配ID next_id: u64, } impl DividendEngine { /// 创建新的股息分配引擎 pub fn new() -> Self { Self { records: HashMap::new(), personal_dividends: HashMap::new(), next_id: 1, } } /// 声明股息分配 /// /// # 参数 /// - security_id: 证券分区ID /// - amount_per_share: 每股股息金额 /// - tax_rate: 税率(百分比) /// - holders: 持有人及其持股数量 pub fn declare_dividend( &mut self, security_id: [u8; 32], amount_per_share: u64, tax_rate: u8, holders: &HashMap, ) -> Result { // 验证参数 if amount_per_share == 0 { return Err("Amount per share must be greater than zero".to_string()); } if tax_rate > 100 { return Err("Tax rate must be between 0 and 100".to_string()); } if holders.is_empty() { return Err("No holders specified".to_string()); } // 生成分配ID let dividend_id = format!("DIV-{:08}", self.next_id); self.next_id += 1; // 计算总金额 let total_shares: u64 = holders.values().sum(); let total_amount = total_shares * amount_per_share; // 创建分配记录 let record = DividendRecord { id: dividend_id.clone(), security_id, timestamp: Self::current_timestamp(), amount_per_share, total_amount, beneficiary_count: holders.len(), status: DividendStatus::Pending, tax_rate, }; self.records.insert(dividend_id.clone(), record); // 为每个持有人创建个人股息记录 for (account, shares) in holders { let gross_amount = shares * amount_per_share; let tax_amount = (gross_amount * tax_rate as u64) / 100; let net_amount = gross_amount - tax_amount; let personal_dividend = PersonalDividend { dividend_id: dividend_id.clone(), account: account.clone(), shares: *shares, gross_amount, tax_amount, net_amount, claimed: false, claim_time: None, }; self.personal_dividends .entry(account.clone()) .or_insert_with(Vec::new) .push(personal_dividend); } Ok(dividend_id) } /// 执行股息分配 pub fn distribute_dividend(&mut self, dividend_id: &str) -> Result<(), String> { let record = self.records.get_mut(dividend_id) .ok_or_else(|| "Dividend not found".to_string())?; if record.status != DividendStatus::Pending { return Err(format!("Dividend is not in pending status: {:?}", record.status)); } // 更新状态为分配中 record.status = DividendStatus::Distributing; // 实际分配逻辑(这里简化为标记为已分配) // 在真实实现中,这里会调用转账功能将资金分配给持有人 // 更新状态为已完成 record.status = DividendStatus::Completed; Ok(()) } /// 领取股息 pub fn claim_dividend(&mut self, account: &str, dividend_id: &str) -> Result { let personal_dividends = self.personal_dividends.get_mut(account) .ok_or_else(|| "No dividends for this account".to_string())?; let dividend = personal_dividends.iter_mut() .find(|d| d.dividend_id == dividend_id) .ok_or_else(|| "Dividend not found for this account".to_string())?; if dividend.claimed { return Err("Dividend already claimed".to_string()); } // 检查分配记录状态 let record = self.records.get(dividend_id) .ok_or_else(|| "Dividend record not found".to_string())?; if record.status != DividendStatus::Completed { return Err("Dividend distribution not completed yet".to_string()); } // 标记为已领取 dividend.claimed = true; dividend.claim_time = Some(Self::current_timestamp()); Ok(dividend.net_amount) } /// 获取账户的所有股息记录 pub fn get_dividends(&self, account: &str) -> Vec { self.personal_dividends .get(account) .cloned() .unwrap_or_default() } /// 获取账户的未领取股息 pub fn get_unclaimed_dividends(&self, account: &str) -> Vec { self.get_dividends(account) .into_iter() .filter(|d| !d.claimed) .collect() } /// 获取账户的总未领取股息金额 pub fn get_total_unclaimed_amount(&self, account: &str) -> u64 { self.get_unclaimed_dividends(account) .iter() .map(|d| d.net_amount) .sum() } /// 获取分配记录 pub fn get_dividend_record(&self, dividend_id: &str) -> Option<&DividendRecord> { self.records.get(dividend_id) } /// 取消股息分配 pub fn cancel_dividend(&mut self, dividend_id: &str) -> Result<(), String> { let record = self.records.get_mut(dividend_id) .ok_or_else(|| "Dividend not found".to_string())?; if record.status != DividendStatus::Pending { return Err("Can only cancel pending dividends".to_string()); } record.status = DividendStatus::Cancelled; Ok(()) } /// 获取证券的所有股息记录 pub fn get_security_dividends(&self, security_id: &[u8; 32]) -> Vec { self.records .values() .filter(|r| &r.security_id == security_id) .cloned() .collect() } /// 计算账户的累计股息收入 pub fn calculate_total_dividend_income(&self, account: &str) -> (u64, u64, u64) { let dividends = self.get_dividends(account); let total_gross: u64 = dividends.iter().map(|d| d.gross_amount).sum(); let total_tax: u64 = dividends.iter().map(|d| d.tax_amount).sum(); let total_net: u64 = dividends.iter().map(|d| d.net_amount).sum(); (total_gross, total_tax, total_net) } /// 获取当前时间戳 fn current_timestamp() -> u64 { std::time::SystemTime::now() .duration_since(std::time::UNIX_EPOCH) .unwrap() .as_secs() } } impl Default for DividendEngine { fn default() -> Self { Self::new() } } #[cfg(test)] mod tests { use super::*; #[test] fn test_declare_dividend() { let mut engine = DividendEngine::new(); let security_id = [1u8; 32]; let mut holders = HashMap::new(); holders.insert("investor1".to_string(), 1000); holders.insert("investor2".to_string(), 500); let result = engine.declare_dividend(security_id, 10, 15, &holders); assert!(result.is_ok()); let dividend_id = result.unwrap(); let record = engine.get_dividend_record(÷nd_id).unwrap(); assert_eq!(record.amount_per_share, 10); assert_eq!(record.total_amount, 15000); // (1000 + 500) * 10 assert_eq!(record.beneficiary_count, 2); assert_eq!(record.tax_rate, 15); } #[test] fn test_distribute_and_claim_dividend() { let mut engine = DividendEngine::new(); let security_id = [1u8; 32]; let mut holders = HashMap::new(); holders.insert("investor1".to_string(), 1000); let dividend_id = engine.declare_dividend(security_id, 10, 15, &holders).unwrap(); // 分配股息 engine.distribute_dividend(÷nd_id).unwrap(); // 领取股息 let amount = engine.claim_dividend("investor1", ÷nd_id).unwrap(); // 税前: 1000 * 10 = 10000 // 税额: 10000 * 15% = 1500 // 税后: 10000 - 1500 = 8500 assert_eq!(amount, 8500); // 再次领取应该失败 let result = engine.claim_dividend("investor1", ÷nd_id); assert!(result.is_err()); } #[test] fn test_unclaimed_dividends() { let mut engine = DividendEngine::new(); let security_id = [1u8; 32]; let mut holders = HashMap::new(); holders.insert("investor1".to_string(), 1000); let dividend_id = engine.declare_dividend(security_id, 10, 15, &holders).unwrap(); engine.distribute_dividend(÷nd_id).unwrap(); let unclaimed = engine.get_unclaimed_dividends("investor1"); assert_eq!(unclaimed.len(), 1); assert_eq!(unclaimed[0].net_amount, 8500); let total = engine.get_total_unclaimed_amount("investor1"); assert_eq!(total, 8500); // 领取后应该没有未领取股息 engine.claim_dividend("investor1", ÷nd_id).unwrap(); let unclaimed = engine.get_unclaimed_dividends("investor1"); assert_eq!(unclaimed.len(), 0); } #[test] fn test_cancel_dividend() { let mut engine = DividendEngine::new(); let security_id = [1u8; 32]; let mut holders = HashMap::new(); holders.insert("investor1".to_string(), 1000); let dividend_id = engine.declare_dividend(security_id, 10, 15, &holders).unwrap(); // 取消分配 engine.cancel_dividend(÷nd_id).unwrap(); let record = engine.get_dividend_record(÷nd_id).unwrap(); assert_eq!(record.status, DividendStatus::Cancelled); // 已取消的分配不能执行 let result = engine.distribute_dividend(÷nd_id); assert!(result.is_err()); } #[test] fn test_total_dividend_income() { let mut engine = DividendEngine::new(); let security_id = [1u8; 32]; let mut holders = HashMap::new(); holders.insert("investor1".to_string(), 1000); // 第一次分配 let div1 = engine.declare_dividend(security_id, 10, 15, &holders).unwrap(); engine.distribute_dividend(&div1).unwrap(); engine.claim_dividend("investor1", &div1).unwrap(); // 第二次分配 let div2 = engine.declare_dividend(security_id, 20, 15, &holders).unwrap(); engine.distribute_dividend(&div2).unwrap(); engine.claim_dividend("investor1", &div2).unwrap(); let (gross, tax, net) = engine.calculate_total_dividend_income("investor1"); // 第一次: 10000税前, 1500税, 8500税后 // 第二次: 20000税前, 3000税, 17000税后 // 总计: 30000税前, 4500税, 25500税后 assert_eq!(gross, 30000); assert_eq!(tax, 4500); assert_eq!(net, 25500); } }