//! 账户 API 处理器 use axum::{ extract::{Path, Query, State}, Json, }; use crate::api::AppState; use crate::application::dto::*; use crate::domain::account::{CreatePhysicalAccountRequest, CreateVirtualSubAccountRequest, AccountType}; use crate::error::Result; /// 创建实体账户 pub async fn create_physical_account( State(state): State, Json(dto): Json, ) -> Result>> { let service = state.account_service(); let request = CreatePhysicalAccountRequest { account_no: dto.account_no, bank_code: dto.bank_code, bank_name: dto.bank_name, consistency_mode: dto.consistency_mode, outbound_control: dto.outbound_control, }; let account = service.create_physical_account(request).await?; Ok(Json(SuccessResponse::new(PhysicalAccountResponse { id: account.id, account_no: account.account_no, bank_code: account.bank_code, bank_name: account.bank_name, consistency_mode: account.consistency_mode, outbound_control: account.outbound_control, status: account.status, created_at: account.created_at, personal_balance: None, labor_balance: None, frozen_balance: None, bank_balance: None, transit_amount: None, available_balance: None, }))) } /// 账户列表查询参数 #[derive(serde::Deserialize)] pub struct ListAccountsQuery { pub status: Option, pub keyword: Option, pub page: Option, pub page_size: Option, } /// 获取实体账户列表 pub async fn list_physical_accounts( State(state): State, Query(query): Query, ) -> Result>>> { let service = state.account_service(); let ledger_service = state.ledger_service(); let mut accounts = service.list_physical_accounts().await?; // 筛选:按状态 if let Some(status_str) = &query.status { if let Ok(status) = status_str.parse::() { accounts.retain(|a| a.status == status); } } // 筛选:按关键词(账号或银行名称) if let Some(keyword) = &query.keyword { let keyword_lower = keyword.to_lowercase(); accounts.retain(|a| { a.account_no.to_lowercase().contains(&keyword_lower) || a.bank_name.as_ref().map(|n| n.to_lowercase().contains(&keyword_lower)).unwrap_or(false) }); } // 分页 let page = query.page.unwrap_or(1).max(1); let page_size = query.page_size.unwrap_or(10).max(1).min(100); let total = accounts.len() as i64; let start = ((page - 1) * page_size) as usize; let end = (start + page_size as usize).min(accounts.len()); let paged_accounts = if start < accounts.len() { accounts[start..end].to_vec() } else { Vec::new() }; // 转换为响应并获取余额信息 let mut responses = Vec::new(); for account in paged_accounts { // 获取余额信息 let balance = ledger_service .get_balance(account.id, AccountType::Physical) .await .ok(); responses.push(PhysicalAccountResponse { id: account.id, account_no: account.account_no, bank_code: account.bank_code, bank_name: account.bank_name, consistency_mode: account.consistency_mode, outbound_control: account.outbound_control, status: account.status, created_at: account.created_at, personal_balance: balance.as_ref().map(|b| b.personal_balance), labor_balance: balance.as_ref().map(|b| b.labor_balance), frozen_balance: balance.as_ref().map(|b| b.frozen_balance), bank_balance: balance.as_ref().map(|b| b.bank_balance), transit_amount: balance.as_ref().map(|b| b.transit_amount), available_balance: balance.as_ref().map(|b| b.available_balance), }); } Ok(Json(SuccessResponse::new(PageResponse::new( responses, total, page as i64, page_size as i64, )))) } /// 获取实体账户 pub async fn get_physical_account( State(state): State, Path(id): Path, ) -> Result>> { let service = state.account_service(); let ledger_service = state.ledger_service(); let account = service.get_physical_account(id).await?; // 获取余额信息 let balance = ledger_service .get_balance(id, AccountType::Physical) .await .ok(); Ok(Json(SuccessResponse::new(PhysicalAccountResponse { id: account.id, account_no: account.account_no, bank_code: account.bank_code, bank_name: account.bank_name, consistency_mode: account.consistency_mode, outbound_control: account.outbound_control, status: account.status, created_at: account.created_at, personal_balance: balance.as_ref().map(|b| b.personal_balance), labor_balance: balance.as_ref().map(|b| b.labor_balance), frozen_balance: balance.as_ref().map(|b| b.frozen_balance), bank_balance: balance.as_ref().map(|b| b.bank_balance), transit_amount: balance.as_ref().map(|b| b.transit_amount), available_balance: balance.as_ref().map(|b| b.available_balance), }))) } /// 冻结实体账户余额 pub async fn freeze_physical_account( State(state): State, Path(id): Path, Json(dto): Json, ) -> Result>> { let ledger_service = state.ledger_service(); ledger_service.freeze_amount(id, AccountType::Physical, dto.amount).await?; Ok(Json(SuccessResponse::new(format!("已冻结金额 {}", dto.amount)))) } /// 解冻实体账户余额 pub async fn unfreeze_physical_account( State(state): State, Path(id): Path, Json(dto): Json, ) -> Result>> { let ledger_service = state.ledger_service(); ledger_service.unfreeze_amount(id, AccountType::Physical, dto.amount).await?; Ok(Json(SuccessResponse::new(format!("已解冻金额 {}", dto.amount)))) } /// 创建虚拟子账户 pub async fn create_sub_account( State(state): State, Json(dto): Json, ) -> Result>> { let service = state.account_service(); let request = CreateVirtualSubAccountRequest { physical_account_id: dto.physical_account_id, account_code: dto.account_code, account_type: dto.account_type, valid_from: dto.valid_from, valid_to: dto.valid_to, }; let account = service.create_virtual_sub_account(request).await?; Ok(Json(SuccessResponse::new(VirtualSubAccountResponse { id: account.id, physical_account_id: account.physical_account_id, account_code: account.account_code, account_type: account.account_type, valid_from: account.valid_from, valid_to: account.valid_to, status: account.status, balance: None, created_at: account.created_at, }))) } /// 获取虚拟子账户 pub async fn get_sub_account( State(state): State, Path(id): Path, ) -> Result>> { let account_service = state.account_service(); let ledger_service = state.ledger_service(); let account = account_service.get_virtual_sub_account(id).await?; let balance = ledger_service.get_balance(id, AccountType::Virtual).await?; Ok(Json(SuccessResponse::new(VirtualSubAccountResponse { id: account.id, physical_account_id: account.physical_account_id, account_code: account.account_code, account_type: account.account_type, valid_from: account.valid_from, valid_to: account.valid_to, status: account.status, balance: Some(BalanceResponse { system_balance: balance.system_balance, bank_balance: balance.bank_balance, available_balance: balance.available_balance, frozen_amount: balance.frozen_amount, transit_amount: balance.transit_amount, }), created_at: account.created_at, }))) } /// 获取子账户余额 pub async fn get_sub_account_balance( State(state): State, Path(id): Path, ) -> Result>> { let ledger_service = state.ledger_service(); let balance = ledger_service.get_balance(id, AccountType::Virtual).await?; Ok(Json(SuccessResponse::new(BalanceResponse { system_balance: balance.system_balance, bank_balance: balance.bank_balance, available_balance: balance.available_balance, frozen_amount: balance.frozen_amount, transit_amount: balance.transit_amount, }))) } /// 冻结子账户余额 pub async fn freeze_sub_account( State(state): State, Path(id): Path, Json(dto): Json, ) -> Result>> { let ledger_service = state.ledger_service(); ledger_service.freeze_amount(id, AccountType::Virtual, dto.amount).await?; Ok(Json(SuccessResponse::new(format!("已冻结金额 {}", dto.amount)))) } /// 解冻子账户余额 pub async fn unfreeze_sub_account( State(state): State, Path(id): Path, Json(dto): Json, ) -> Result>> { let ledger_service = state.ledger_service(); ledger_service.unfreeze_amount(id, AccountType::Virtual, dto.amount).await?; Ok(Json(SuccessResponse::new(format!("已解冻金额 {}", dto.amount)))) } /// 销户 pub async fn close_sub_account( State(state): State, Path(id): Path, ) -> Result>> { let service = state.account_service(); service.close_sub_account(id).await?; Ok(Json(SuccessResponse::new("子账户已销户".to_string()))) } /// 获取实体账户下的子账户列表 pub async fn list_sub_accounts( State(state): State, Path(physical_account_id): Path, ) -> Result>>> { let service = state.account_service(); let accounts = service.list_sub_accounts(physical_account_id).await?; let responses: Vec = accounts .into_iter() .map(|a| VirtualSubAccountResponse { id: a.id, physical_account_id: a.physical_account_id, account_code: a.account_code, account_type: a.account_type, valid_from: a.valid_from, valid_to: a.valid_to, status: a.status, balance: None, created_at: a.created_at, }) .collect(); Ok(Json(SuccessResponse::new(responses))) }