mirror of
https://github.com/fawney19/Aether.git
synced 2026-10-09 10:57:03 +08:00
feat: add payment gateway and billing plans
This commit is contained in:
@@ -1,6 +1,6 @@
|
||||
use super::super::shared::{
|
||||
admin_wallet_id_from_suffix_path, admin_wallet_operator_id,
|
||||
build_admin_wallet_not_found_response, build_admin_wallet_summary_payload,
|
||||
build_admin_wallet_not_found_response, build_admin_wallet_summary_payload_with_package,
|
||||
build_admin_wallet_transaction_payload, build_admin_wallets_bad_request_response,
|
||||
build_admin_wallets_data_unavailable_response, normalize_admin_wallet_balance_type,
|
||||
normalize_admin_wallet_description, normalize_admin_wallet_non_zero_amount,
|
||||
@@ -79,7 +79,8 @@ pub(in super::super) async fn build_admin_wallet_adjust_response(
|
||||
};
|
||||
};
|
||||
let owner = resolve_admin_wallet_owner_summary(state, &wallet).await?;
|
||||
let wallet_payload = build_admin_wallet_summary_payload(&wallet, &owner);
|
||||
let wallet_payload =
|
||||
build_admin_wallet_summary_payload_with_package(state, &wallet, &owner).await?;
|
||||
let transaction_payload = build_admin_wallet_transaction_payload(
|
||||
&wallet,
|
||||
&owner,
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
use super::super::shared::{
|
||||
admin_wallet_operator_id, admin_wallet_refund_ids_from_suffix_path,
|
||||
build_admin_wallet_not_found_response, build_admin_wallet_refund_not_found_response,
|
||||
build_admin_wallet_refund_payload, build_admin_wallet_summary_payload,
|
||||
build_admin_wallet_refund_payload, build_admin_wallet_summary_payload_with_package,
|
||||
build_admin_wallet_transaction_payload, build_admin_wallets_bad_request_response,
|
||||
build_admin_wallets_data_unavailable_response, normalize_admin_wallet_required_text,
|
||||
resolve_admin_wallet_owner_summary, AdminWalletRefundFailRequest,
|
||||
@@ -62,8 +62,10 @@ pub(in super::super) async fn build_admin_wallet_fail_refund_response(
|
||||
{
|
||||
crate::AdminWalletMutationOutcome::Applied((wallet, refund, transaction)) => {
|
||||
let owner = resolve_admin_wallet_owner_summary(state, &wallet).await?;
|
||||
let wallet_payload =
|
||||
build_admin_wallet_summary_payload_with_package(state, &wallet, &owner).await?;
|
||||
let response = Json(json!({
|
||||
"wallet": build_admin_wallet_summary_payload(&wallet, &owner),
|
||||
"wallet": wallet_payload,
|
||||
"refund": build_admin_wallet_refund_payload(&wallet, &owner, &refund),
|
||||
"transaction": transaction
|
||||
.map(|transaction| {
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
use super::super::shared::{
|
||||
admin_wallet_operator_id, admin_wallet_refund_ids_from_suffix_path,
|
||||
build_admin_wallet_not_found_response, build_admin_wallet_refund_not_found_response,
|
||||
build_admin_wallet_refund_payload, build_admin_wallet_summary_payload,
|
||||
build_admin_wallet_refund_payload, build_admin_wallet_summary_payload_with_package,
|
||||
build_admin_wallet_transaction_payload, build_admin_wallets_bad_request_response,
|
||||
build_admin_wallets_data_unavailable_response, resolve_admin_wallet_owner_summary,
|
||||
ADMIN_WALLETS_API_KEY_REFUND_DETAIL,
|
||||
@@ -49,8 +49,10 @@ pub(in super::super) async fn build_admin_wallet_process_refund_response(
|
||||
{
|
||||
crate::AdminWalletMutationOutcome::Applied((wallet, refund, transaction)) => {
|
||||
let owner = resolve_admin_wallet_owner_summary(state, &wallet).await?;
|
||||
let wallet_payload =
|
||||
build_admin_wallet_summary_payload_with_package(state, &wallet, &owner).await?;
|
||||
let response = Json(json!({
|
||||
"wallet": build_admin_wallet_summary_payload(&wallet, &owner),
|
||||
"wallet": wallet_payload,
|
||||
"refund": build_admin_wallet_refund_payload(&wallet, &owner, &refund),
|
||||
"transaction": build_admin_wallet_transaction_payload(
|
||||
&wallet,
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
use super::super::shared::{
|
||||
admin_wallet_id_from_suffix_path, admin_wallet_operator_id,
|
||||
build_admin_wallet_not_found_response, build_admin_wallet_payment_order_payload,
|
||||
build_admin_wallet_summary_payload, build_admin_wallets_bad_request_response,
|
||||
build_admin_wallet_summary_payload_with_package, build_admin_wallets_bad_request_response,
|
||||
build_admin_wallets_data_unavailable_response, normalize_admin_wallet_description,
|
||||
normalize_admin_wallet_payment_method, normalize_admin_wallet_positive_amount,
|
||||
resolve_admin_wallet_owner_summary, AdminWalletRechargeRequest,
|
||||
@@ -79,8 +79,10 @@ pub(in super::super) async fn build_admin_wallet_recharge_response(
|
||||
};
|
||||
};
|
||||
let owner = resolve_admin_wallet_owner_summary(state, &wallet).await?;
|
||||
let wallet_payload =
|
||||
build_admin_wallet_summary_payload_with_package(state, &wallet, &owner).await?;
|
||||
let response = Json(json!({
|
||||
"wallet": build_admin_wallet_summary_payload(&wallet, &owner),
|
||||
"wallet": wallet_payload,
|
||||
"payment_order": build_admin_wallet_payment_order_payload(
|
||||
payment_order.id,
|
||||
payment_order.order_no,
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
use super::super::shared::{
|
||||
admin_wallet_id_from_detail_path, build_admin_wallet_not_found_response,
|
||||
build_admin_wallet_summary_payload, build_admin_wallets_bad_request_response,
|
||||
build_admin_wallet_summary_payload_with_package, build_admin_wallets_bad_request_response,
|
||||
resolve_admin_wallet_owner_summary,
|
||||
};
|
||||
use crate::handlers::admin::request::{AdminAppState, AdminRequestContext};
|
||||
@@ -29,7 +29,8 @@ pub(in super::super) async fn build_admin_wallet_detail_response(
|
||||
};
|
||||
|
||||
let owner = resolve_admin_wallet_owner_summary(state, &wallet).await?;
|
||||
let mut payload = build_admin_wallet_summary_payload(&wallet, &owner);
|
||||
let mut payload =
|
||||
build_admin_wallet_summary_payload_with_package(state, &wallet, &owner).await?;
|
||||
if let Some(object) = payload.as_object_mut() {
|
||||
object.insert("pending_refund_count".to_string(), serde_json::Value::Null);
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
use super::super::shared::{
|
||||
build_admin_wallets_bad_request_response, parse_admin_wallets_limit,
|
||||
parse_admin_wallets_offset, parse_admin_wallets_owner_type_filter,
|
||||
build_admin_wallets_bad_request_response, enrich_admin_wallet_package_summary,
|
||||
parse_admin_wallets_limit, parse_admin_wallets_offset, parse_admin_wallets_owner_type_filter,
|
||||
wallet_owner_summary_from_fields,
|
||||
};
|
||||
use crate::handlers::admin::request::{AdminAppState, AdminRequestContext};
|
||||
@@ -32,38 +32,48 @@ pub(in super::super) async fn build_admin_wallet_list_response(
|
||||
let (wallets, total) = state
|
||||
.list_admin_wallets(status.as_deref(), owner_type.as_deref(), limit, offset)
|
||||
.await?;
|
||||
let items = wallets
|
||||
.into_iter()
|
||||
.map(|wallet| {
|
||||
let owner = wallet_owner_summary_from_fields(
|
||||
wallet.user_id.as_deref(),
|
||||
wallet.user_name.clone(),
|
||||
wallet.api_key_id.as_deref(),
|
||||
wallet.api_key_name.clone(),
|
||||
);
|
||||
json!({
|
||||
"id": wallet.id,
|
||||
"user_id": wallet.user_id,
|
||||
"api_key_id": wallet.api_key_id,
|
||||
"owner_type": owner.owner_type,
|
||||
"owner_name": owner.owner_name,
|
||||
"balance": wallet.balance + wallet.gift_balance,
|
||||
"recharge_balance": wallet.balance,
|
||||
"gift_balance": wallet.gift_balance,
|
||||
"refundable_balance": wallet.balance,
|
||||
"currency": wallet.currency,
|
||||
"status": wallet.status,
|
||||
"limit_mode": wallet.limit_mode.clone(),
|
||||
"unlimited": wallet.limit_mode.eq_ignore_ascii_case("unlimited"),
|
||||
"total_recharged": wallet.total_recharged,
|
||||
"total_consumed": wallet.total_consumed,
|
||||
"total_refunded": wallet.total_refunded,
|
||||
"total_adjusted": wallet.total_adjusted,
|
||||
"created_at": wallet.created_at_unix_ms.and_then(unix_secs_to_rfc3339),
|
||||
"updated_at": wallet.updated_at_unix_secs.and_then(unix_secs_to_rfc3339),
|
||||
})
|
||||
})
|
||||
.collect::<Vec<_>>();
|
||||
let mut items = Vec::with_capacity(wallets.len());
|
||||
for wallet in wallets {
|
||||
let owner = wallet_owner_summary_from_fields(
|
||||
wallet.user_id.as_deref(),
|
||||
wallet.user_name.clone(),
|
||||
wallet.api_key_id.as_deref(),
|
||||
wallet.api_key_name.clone(),
|
||||
);
|
||||
let user_id = wallet.user_id.clone();
|
||||
let wallet_balance = wallet.balance + wallet.gift_balance;
|
||||
let unlimited = wallet.limit_mode.eq_ignore_ascii_case("unlimited");
|
||||
let mut payload = json!({
|
||||
"id": wallet.id,
|
||||
"user_id": wallet.user_id,
|
||||
"api_key_id": wallet.api_key_id,
|
||||
"owner_type": owner.owner_type,
|
||||
"owner_name": owner.owner_name,
|
||||
"balance": wallet_balance,
|
||||
"recharge_balance": wallet.balance,
|
||||
"gift_balance": wallet.gift_balance,
|
||||
"refundable_balance": wallet.balance,
|
||||
"currency": wallet.currency,
|
||||
"status": wallet.status,
|
||||
"limit_mode": wallet.limit_mode.clone(),
|
||||
"unlimited": unlimited,
|
||||
"total_recharged": wallet.total_recharged,
|
||||
"total_consumed": wallet.total_consumed,
|
||||
"total_refunded": wallet.total_refunded,
|
||||
"total_adjusted": wallet.total_adjusted,
|
||||
"created_at": wallet.created_at_unix_ms.and_then(unix_secs_to_rfc3339),
|
||||
"updated_at": wallet.updated_at_unix_secs.and_then(unix_secs_to_rfc3339),
|
||||
});
|
||||
enrich_admin_wallet_package_summary(
|
||||
state,
|
||||
&mut payload,
|
||||
user_id.as_deref(),
|
||||
wallet_balance,
|
||||
unlimited,
|
||||
)
|
||||
.await?;
|
||||
items.push(payload);
|
||||
}
|
||||
|
||||
Ok(Json(json!({
|
||||
"items": items,
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
use super::super::shared::{
|
||||
admin_wallet_id_from_suffix_path, build_admin_wallet_not_found_response,
|
||||
build_admin_wallet_refund_payload, build_admin_wallet_summary_payload,
|
||||
build_admin_wallet_refund_payload, build_admin_wallet_summary_payload_with_package,
|
||||
build_admin_wallets_bad_request_response, parse_admin_wallets_limit,
|
||||
parse_admin_wallets_offset, resolve_admin_wallet_owner_summary,
|
||||
ADMIN_WALLETS_API_KEY_REFUND_DETAIL,
|
||||
@@ -46,7 +46,8 @@ pub(in super::super) async fn build_admin_wallet_refunds_response(
|
||||
}
|
||||
|
||||
let owner = resolve_admin_wallet_owner_summary(state, &wallet).await?;
|
||||
let wallet_payload = build_admin_wallet_summary_payload(&wallet, &owner);
|
||||
let wallet_payload =
|
||||
build_admin_wallet_summary_payload_with_package(state, &wallet, &owner).await?;
|
||||
let (refunds, total) = state
|
||||
.list_admin_wallet_refunds(&wallet.id, limit, offset)
|
||||
.await?;
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
use super::super::shared::{
|
||||
admin_wallet_id_from_suffix_path, build_admin_wallet_not_found_response,
|
||||
build_admin_wallet_summary_payload, build_admin_wallets_bad_request_response,
|
||||
build_admin_wallet_summary_payload_with_package, build_admin_wallets_bad_request_response,
|
||||
parse_admin_wallets_limit, parse_admin_wallets_offset, resolve_admin_wallet_owner_summary,
|
||||
};
|
||||
use crate::handlers::admin::request::{AdminAppState, AdminRequestContext};
|
||||
@@ -39,7 +39,8 @@ pub(in super::super) async fn build_admin_wallet_transactions_response(
|
||||
return Ok(build_admin_wallet_not_found_response());
|
||||
};
|
||||
let owner = resolve_admin_wallet_owner_summary(state, &wallet).await?;
|
||||
let wallet_payload = build_admin_wallet_summary_payload(&wallet, &owner);
|
||||
let wallet_payload =
|
||||
build_admin_wallet_summary_payload_with_package(state, &wallet, &owner).await?;
|
||||
|
||||
let (transactions, total) = state
|
||||
.list_admin_wallet_transactions(&wallet.id, limit, offset)
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
use crate::handlers::admin::request::AdminAppState;
|
||||
use crate::handlers::admin::shared::unix_secs_to_rfc3339;
|
||||
use crate::handlers::shared::round_to;
|
||||
use crate::GatewayError;
|
||||
use serde_json::json;
|
||||
|
||||
@@ -160,6 +161,79 @@ pub(in super::super) fn build_admin_wallet_summary_payload(
|
||||
})
|
||||
}
|
||||
|
||||
pub(in super::super) async fn build_admin_wallet_summary_payload_with_package(
|
||||
state: &AdminAppState<'_>,
|
||||
wallet: &aether_data::repository::wallet::StoredWalletSnapshot,
|
||||
owner: &AdminWalletOwnerSummary,
|
||||
) -> Result<serde_json::Value, GatewayError> {
|
||||
let mut payload = build_admin_wallet_summary_payload(wallet, owner);
|
||||
enrich_admin_wallet_package_summary(
|
||||
state,
|
||||
&mut payload,
|
||||
wallet.user_id.as_deref(),
|
||||
wallet.balance + wallet.gift_balance,
|
||||
wallet.limit_mode.eq_ignore_ascii_case("unlimited"),
|
||||
)
|
||||
.await?;
|
||||
Ok(payload)
|
||||
}
|
||||
|
||||
pub(in super::super) async fn enrich_admin_wallet_package_summary(
|
||||
state: &AdminAppState<'_>,
|
||||
payload: &mut serde_json::Value,
|
||||
user_id: Option<&str>,
|
||||
wallet_balance: f64,
|
||||
unlimited: bool,
|
||||
) -> Result<(), GatewayError> {
|
||||
let daily_quota = match user_id {
|
||||
Some(user_id) if !user_id.trim().is_empty() => {
|
||||
state
|
||||
.app()
|
||||
.find_user_daily_quota_availability(user_id)
|
||||
.await?
|
||||
}
|
||||
_ => None,
|
||||
};
|
||||
let (has_active_daily_quota, total_quota_usd, used_usd, remaining_usd, allow_wallet_overage) =
|
||||
daily_quota
|
||||
.map(|quota| {
|
||||
(
|
||||
quota.has_active_daily_quota,
|
||||
quota.total_quota_usd,
|
||||
quota.used_usd,
|
||||
quota.remaining_usd,
|
||||
quota.allow_wallet_overage,
|
||||
)
|
||||
})
|
||||
.unwrap_or((false, 0.0, 0.0, 0.0, false));
|
||||
let package_balance = if has_active_daily_quota {
|
||||
remaining_usd.max(0.0)
|
||||
} else {
|
||||
0.0
|
||||
};
|
||||
|
||||
payload["daily_quota"] = json!({
|
||||
"has_active": has_active_daily_quota,
|
||||
"total_usd": round_to(total_quota_usd.max(0.0), 6),
|
||||
"used_usd": round_to(used_usd.max(0.0), 6),
|
||||
"remaining_usd": round_to(package_balance, 6),
|
||||
"allow_wallet_overage": allow_wallet_overage,
|
||||
});
|
||||
payload["package_balance"] = json!(round_to(package_balance, 6));
|
||||
payload["wallet_balance"] = json!(round_to(wallet_balance.max(0.0), 6));
|
||||
payload["total_available_balance"] = if unlimited {
|
||||
serde_json::Value::Null
|
||||
} else {
|
||||
json!(round_to((wallet_balance + package_balance).max(0.0), 6))
|
||||
};
|
||||
payload["deduction_order"] = json!([
|
||||
"package_daily_quota",
|
||||
"wallet_recharge_balance",
|
||||
"wallet_gift_balance"
|
||||
]);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub(in super::super) fn build_admin_wallet_refund_payload(
|
||||
wallet: &aether_data::repository::wallet::StoredWalletSnapshot,
|
||||
owner: &AdminWalletOwnerSummary,
|
||||
|
||||
Reference in New Issue
Block a user