mirror of
https://github.com/fawney19/Aether.git
synced 2026-10-07 01:47:47 +08:00
Merge origin/main into main
Integrate upstream updates while preserving the local analytics dashboards and schema-only migration changes. Combine user account analysis with upstream user/group usage statistics in separate tabs, retain all migration versions, and keep the deleted audit document removed. Validation: gateway all-target cargo check, frontend type check and 57 focused tests, 48 migration tests, schema composition checks, and diff whitespace checks.
This commit is contained in:
@@ -344,3 +344,17 @@ CREATE INDEX IF NOT EXISTS idx_redeem_codes_status ON public.redeem_codes USING
|
||||
CREATE INDEX IF NOT EXISTS idx_redeem_codes_redeemed_user ON public.redeem_codes USING btree (redeemed_by_user_id, redeemed_at);
|
||||
CREATE INDEX IF NOT EXISTS idx_redeem_codes_redeemed_order ON public.redeem_codes USING btree (redeemed_payment_order_id);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS public.admin_user_wallet_balance_batches (
|
||||
admin_user_id character varying(64) NOT NULL,
|
||||
idempotency_key character varying(128) NOT NULL,
|
||||
request_fingerprint character varying(64) NOT NULL,
|
||||
target_user_ids jsonb NOT NULL,
|
||||
missing_user_ids jsonb NOT NULL,
|
||||
warnings jsonb NOT NULL,
|
||||
user_outcomes jsonb NOT NULL,
|
||||
created_at_unix_secs bigint NOT NULL,
|
||||
updated_at_unix_secs bigint NOT NULL
|
||||
);
|
||||
|
||||
ALTER TABLE ONLY public.admin_user_wallet_balance_batches ADD CONSTRAINT admin_user_wallet_balance_batches_pkey PRIMARY KEY (admin_user_id, idempotency_key);
|
||||
|
||||
|
||||
@@ -1370,3 +1370,47 @@ columns = ["redeemed_by_user_id", "redeemed_at"]
|
||||
[[table.redeem_codes.indexes]]
|
||||
name = "idx_redeem_codes_redeemed_order"
|
||||
columns = ["redeemed_payment_order_id"]
|
||||
|
||||
[table.admin_user_wallet_balance_batches]
|
||||
domain = "wallet_billing"
|
||||
order = 110
|
||||
primary_key = ["admin_user_id", "idempotency_key"]
|
||||
|
||||
[[table.admin_user_wallet_balance_batches.columns]]
|
||||
name = "admin_user_id"
|
||||
type = "text_id"
|
||||
length = 64
|
||||
|
||||
[[table.admin_user_wallet_balance_batches.columns]]
|
||||
name = "idempotency_key"
|
||||
type = "text"
|
||||
length = 128
|
||||
|
||||
[[table.admin_user_wallet_balance_batches.columns]]
|
||||
name = "request_fingerprint"
|
||||
type = "text"
|
||||
length = 64
|
||||
|
||||
[[table.admin_user_wallet_balance_batches.columns]]
|
||||
name = "target_user_ids"
|
||||
type = "json"
|
||||
|
||||
[[table.admin_user_wallet_balance_batches.columns]]
|
||||
name = "missing_user_ids"
|
||||
type = "json"
|
||||
|
||||
[[table.admin_user_wallet_balance_batches.columns]]
|
||||
name = "warnings"
|
||||
type = "json"
|
||||
|
||||
[[table.admin_user_wallet_balance_batches.columns]]
|
||||
name = "user_outcomes"
|
||||
type = "json"
|
||||
|
||||
[[table.admin_user_wallet_balance_batches.columns]]
|
||||
name = "created_at_unix_secs"
|
||||
type = "unix_seconds"
|
||||
|
||||
[[table.admin_user_wallet_balance_batches.columns]]
|
||||
name = "updated_at_unix_secs"
|
||||
type = "unix_seconds"
|
||||
|
||||
@@ -1592,6 +1592,7 @@ fn pending_migrations_from_applied_skips_versions_already_applied() {
|
||||
20260921010000,
|
||||
20260921020000,
|
||||
20260921020100,
|
||||
20260923000000,
|
||||
20261001000000,
|
||||
]
|
||||
);
|
||||
@@ -2563,12 +2564,14 @@ INSERT INTO public.stats_daily_api_key (
|
||||
.expect("API key daily aggregate fixtures should be inserted");
|
||||
|
||||
let leaderboard_query = UsageLeaderboardQuery {
|
||||
provider_names: None,
|
||||
created_from_unix_secs: u64::try_from(stats_day.timestamp())
|
||||
.expect("historical stats day should be nonnegative"),
|
||||
created_until_unix_secs: u64::try_from((stats_day + chrono::Duration::days(1)).timestamp())
|
||||
.expect("historical stats end should be nonnegative"),
|
||||
group_by: UsageLeaderboardGroupBy::ApiKey,
|
||||
user_id: Some("leaderboard-owner".to_string()),
|
||||
user_ids: None,
|
||||
provider_name: None,
|
||||
model: None,
|
||||
};
|
||||
|
||||
@@ -107,7 +107,14 @@ WHERE version=20260919000000;
|
||||
.iter()
|
||||
.map(|migration| migration.version)
|
||||
.collect::<Vec<_>>(),
|
||||
vec![DIRTY_EVENTS, 20260921010000, 20260921020000, 20260921020100, 20261001000000]
|
||||
vec![
|
||||
DIRTY_EVENTS,
|
||||
20260921010000,
|
||||
20260921020000,
|
||||
20260921020100,
|
||||
20260923000000,
|
||||
20261001000000,
|
||||
]
|
||||
);
|
||||
assert_eq!(
|
||||
rows_snapshot(&pool, "_sqlx_migrations").await,
|
||||
|
||||
@@ -346,6 +346,16 @@ fn key_auth_channel_matches(row: &StoredMinimalCandidateSelectionRow, api_format
|
||||
"openai:chat" | "openai:responses" | "claude:messages" | "openai:image"
|
||||
)
|
||||
}
|
||||
"xai" => {
|
||||
matches!(auth_type.as_str(), "oauth" | "bearer" | "api_key")
|
||||
&& matches!(
|
||||
api_format.as_str(),
|
||||
"openai:responses"
|
||||
| "openai:responses:compact"
|
||||
| "openai:image"
|
||||
| "openai:video"
|
||||
)
|
||||
}
|
||||
"windsurf" => {
|
||||
matches!(auth_type.as_str(), "oauth" | "api_key" | "bearer")
|
||||
&& api_format == "openai:chat"
|
||||
@@ -591,6 +601,59 @@ mod tests {
|
||||
assert_eq!(rows[0].global_model_name, "grok-4.20-0309-non-reasoning");
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn includes_xai_oauth_rows_for_responses_models() {
|
||||
let mut row = sample_row("provider-xai", "openai:responses", "grok-4", 10);
|
||||
row.provider_type = "xai".to_string();
|
||||
row.provider_name = "xai".to_string();
|
||||
row.key_auth_type = "oauth".to_string();
|
||||
row.key_api_formats = Some(vec![
|
||||
"openai:responses".to_string(),
|
||||
"openai:responses:compact".to_string(),
|
||||
]);
|
||||
let repository = InMemoryMinimalCandidateSelectionReadRepository::seed(vec![row]);
|
||||
|
||||
let rows = repository
|
||||
.list_for_exact_api_format("openai:responses")
|
||||
.await
|
||||
.expect("list should succeed");
|
||||
|
||||
assert_eq!(rows.len(), 1);
|
||||
assert_eq!(rows[0].provider_type, "xai");
|
||||
assert_eq!(rows[0].global_model_name, "grok-4");
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn includes_xai_oauth_rows_for_image_and_video_models() {
|
||||
let mut image = sample_row("provider-xai", "openai:image", "grok-imagine-image", 10);
|
||||
image.provider_type = "xai".to_string();
|
||||
image.provider_name = "xai".to_string();
|
||||
image.key_auth_type = "oauth".to_string();
|
||||
image.key_api_formats = Some(vec!["openai:image".to_string(), "openai:video".to_string()]);
|
||||
|
||||
let mut video = image.clone();
|
||||
video.endpoint_id = "endpoint-video".to_string();
|
||||
video.endpoint_api_format = "openai:video".to_string();
|
||||
video.global_model_name = "grok-imagine-video".to_string();
|
||||
video.model_provider_model_name = "grok-imagine-video".to_string();
|
||||
|
||||
let repository = InMemoryMinimalCandidateSelectionReadRepository::seed(vec![image, video]);
|
||||
|
||||
let image_rows = repository
|
||||
.list_for_exact_api_format("openai:image")
|
||||
.await
|
||||
.expect("list should succeed");
|
||||
assert_eq!(image_rows.len(), 1);
|
||||
assert_eq!(image_rows[0].global_model_name, "grok-imagine-image");
|
||||
|
||||
let video_rows = repository
|
||||
.list_for_exact_api_format("openai:video")
|
||||
.await
|
||||
.expect("list should succeed");
|
||||
assert_eq!(video_rows.len(), 1);
|
||||
assert_eq!(video_rows[0].global_model_name, "grok-imagine-video");
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn requested_model_filter_respects_endpoint_scoped_default_mapping() {
|
||||
let mut selected = sample_row("provider-1", "openai:chat", "deepseek-v4-pro", 10);
|
||||
|
||||
@@ -600,6 +600,22 @@ fn usage_matches_summary_query(
|
||||
return false;
|
||||
}
|
||||
}
|
||||
if let Some(user_ids) = query.user_ids.as_deref() {
|
||||
if !item
|
||||
.user_id
|
||||
.as_ref()
|
||||
.is_some_and(|user_id| user_ids.contains(user_id))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
if query
|
||||
.provider_names
|
||||
.as_ref()
|
||||
.is_some_and(|names| !names.contains(&item.provider_name))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
if let Some(provider_name) = query.provider_name.as_deref() {
|
||||
if item.provider_name != provider_name {
|
||||
return false;
|
||||
@@ -627,6 +643,22 @@ fn usage_matches_time_series_query(
|
||||
return false;
|
||||
}
|
||||
}
|
||||
if let Some(user_ids) = query.user_ids.as_deref() {
|
||||
if !item
|
||||
.user_id
|
||||
.as_ref()
|
||||
.is_some_and(|user_id| user_ids.contains(user_id))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
if query
|
||||
.provider_names
|
||||
.as_ref()
|
||||
.is_some_and(|names| !names.contains(&item.provider_name))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
if let Some(provider_name) = query.provider_name.as_deref() {
|
||||
if item.provider_name != provider_name {
|
||||
return false;
|
||||
@@ -998,6 +1030,22 @@ fn usage_matches_leaderboard_query(
|
||||
return false;
|
||||
}
|
||||
}
|
||||
if let Some(user_ids) = query.user_ids.as_deref() {
|
||||
if !item
|
||||
.user_id
|
||||
.as_ref()
|
||||
.is_some_and(|user_id| user_ids.contains(user_id))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
if query
|
||||
.provider_names
|
||||
.as_ref()
|
||||
.is_some_and(|names| !names.contains(&item.provider_name))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
if let Some(provider_name) = query.provider_name.as_deref() {
|
||||
if item.provider_name != provider_name {
|
||||
return false;
|
||||
|
||||
@@ -18,7 +18,7 @@ use aether_data_contracts::repository::usage::{
|
||||
UsageAuditAggregationQuery, UsageAuditKeywordSearchQuery, UsageAuditListQuery,
|
||||
UsageAuditSummaryQuery, UsageBodyCaptureState, UsageBodyField, UsageDashboardSummaryQuery,
|
||||
UsageLeaderboardGroupBy, UsageLeaderboardQuery, UsageProviderPerformanceQuery,
|
||||
UsageTimeSeriesGranularity,
|
||||
UsageTimeSeriesGranularity, UsageTimeSeriesQuery,
|
||||
};
|
||||
use serde_json::json;
|
||||
|
||||
@@ -937,6 +937,7 @@ async fn unmetered_session_audit_counts_lifecycle_without_token_or_cost_contribu
|
||||
|
||||
let summary = repository
|
||||
.summarize_usage_audits(&UsageAuditSummaryQuery {
|
||||
provider_names: None,
|
||||
created_from_unix_secs: 0,
|
||||
created_until_unix_secs: 1_000,
|
||||
..UsageAuditSummaryQuery::default()
|
||||
@@ -2693,10 +2694,12 @@ async fn dashboard_and_leaderboard_total_tokens_use_effective_cache_aware_tokens
|
||||
|
||||
let leaderboard = repository
|
||||
.summarize_usage_leaderboard(&UsageLeaderboardQuery {
|
||||
provider_names: None,
|
||||
created_from_unix_secs: 1_711_000_000,
|
||||
created_until_unix_secs: 1_711_000_001,
|
||||
group_by: UsageLeaderboardGroupBy::User,
|
||||
user_id: None,
|
||||
user_ids: None,
|
||||
provider_name: None,
|
||||
model: None,
|
||||
})
|
||||
@@ -2706,6 +2709,140 @@ async fn dashboard_and_leaderboard_total_tokens_use_effective_cache_aware_tokens
|
||||
assert_eq!(leaderboard[0].total_tokens, 120);
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn usage_analytics_filters_by_multiple_user_ids() {
|
||||
let user_one = sample_usage("req-user-1", 1_711_000_000);
|
||||
let mut user_two = sample_usage("req-user-2", 1_711_000_000);
|
||||
user_two.user_id = Some("user-2".to_string());
|
||||
let mut user_three = sample_usage("req-user-3", 1_711_000_000);
|
||||
user_three.user_id = Some("user-3".to_string());
|
||||
let repository = InMemoryUsageReadRepository::seed(vec![user_one, user_two, user_three]);
|
||||
let scoped_user_ids = vec!["user-1".to_string(), "user-2".to_string()];
|
||||
|
||||
let summary = repository
|
||||
.summarize_usage_audits(&UsageAuditSummaryQuery {
|
||||
provider_names: None,
|
||||
created_from_unix_secs: 1_711_000_000,
|
||||
created_until_unix_secs: 1_711_000_001,
|
||||
user_ids: Some(scoped_user_ids.clone()),
|
||||
..Default::default()
|
||||
})
|
||||
.await
|
||||
.expect("summary should filter by multiple users");
|
||||
assert_eq!(summary.total_requests, 2);
|
||||
|
||||
let buckets = repository
|
||||
.summarize_usage_time_series(&UsageTimeSeriesQuery {
|
||||
provider_names: None,
|
||||
created_from_unix_secs: 1_711_000_000,
|
||||
created_until_unix_secs: 1_711_000_001,
|
||||
granularity: UsageTimeSeriesGranularity::Day,
|
||||
tz_offset_minutes: 0,
|
||||
user_id: None,
|
||||
user_ids: Some(scoped_user_ids.clone()),
|
||||
provider_name: None,
|
||||
model: None,
|
||||
})
|
||||
.await
|
||||
.expect("time series should filter by multiple users");
|
||||
assert_eq!(
|
||||
buckets
|
||||
.iter()
|
||||
.map(|bucket| bucket.total_requests)
|
||||
.sum::<u64>(),
|
||||
2
|
||||
);
|
||||
|
||||
let leaderboard = repository
|
||||
.summarize_usage_leaderboard(&UsageLeaderboardQuery {
|
||||
provider_names: None,
|
||||
created_from_unix_secs: 1_711_000_000,
|
||||
created_until_unix_secs: 1_711_000_001,
|
||||
group_by: UsageLeaderboardGroupBy::User,
|
||||
user_id: None,
|
||||
user_ids: Some(scoped_user_ids),
|
||||
provider_name: None,
|
||||
model: None,
|
||||
})
|
||||
.await
|
||||
.expect("leaderboard should filter by multiple users");
|
||||
assert_eq!(leaderboard.len(), 2);
|
||||
assert!(leaderboard.iter().all(|item| item.group_key != "user-3"));
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn usage_analytics_intersects_provider_allowlist_and_user_scope() {
|
||||
let mut a = sample_usage("allowed", 1_711_000_000);
|
||||
a.provider_name = "Gemini".to_string();
|
||||
a.user_id = Some("user-1".to_string());
|
||||
let mut b = a.clone();
|
||||
b.request_id = "other-provider".to_string();
|
||||
b.provider_name = "Other".to_string();
|
||||
let mut c = a.clone();
|
||||
c.request_id = "other-user".to_string();
|
||||
c.user_id = Some("user-2".to_string());
|
||||
let repository = InMemoryUsageReadRepository::seed(vec![a, b, c]);
|
||||
for (names, provider, count) in [
|
||||
(
|
||||
Some(vec!["Gemini".to_string(), "Gemini".to_string()]),
|
||||
None,
|
||||
1,
|
||||
),
|
||||
(Some(vec![]), None, 0),
|
||||
(
|
||||
Some(vec!["Gemini".to_string()]),
|
||||
Some("Other".to_string()),
|
||||
0,
|
||||
),
|
||||
(None, None, 2),
|
||||
] {
|
||||
let summary = repository
|
||||
.summarize_usage_audits(&UsageAuditSummaryQuery {
|
||||
created_from_unix_secs: 1_711_000_000,
|
||||
created_until_unix_secs: 1_711_000_001,
|
||||
user_ids: Some(vec!["user-1".to_string()]),
|
||||
provider_names: names.clone(),
|
||||
provider_name: provider.clone(),
|
||||
..Default::default()
|
||||
})
|
||||
.await
|
||||
.unwrap();
|
||||
assert_eq!(summary.total_requests, count);
|
||||
let buckets = repository
|
||||
.summarize_usage_time_series(&UsageTimeSeriesQuery {
|
||||
created_from_unix_secs: 1_711_000_000,
|
||||
created_until_unix_secs: 1_711_000_001,
|
||||
user_id: None,
|
||||
user_ids: Some(vec!["user-1".to_string()]),
|
||||
provider_names: names.clone(),
|
||||
provider_name: provider.clone(),
|
||||
model: None,
|
||||
granularity: UsageTimeSeriesGranularity::Day,
|
||||
tz_offset_minutes: 0,
|
||||
})
|
||||
.await
|
||||
.unwrap();
|
||||
assert_eq!(
|
||||
buckets.iter().map(|row| row.total_requests).sum::<u64>(),
|
||||
count
|
||||
);
|
||||
let rows = repository
|
||||
.summarize_usage_leaderboard(&UsageLeaderboardQuery {
|
||||
created_from_unix_secs: 1_711_000_000,
|
||||
created_until_unix_secs: 1_711_000_001,
|
||||
user_id: None,
|
||||
user_ids: Some(vec!["user-1".to_string()]),
|
||||
provider_names: names,
|
||||
provider_name: provider,
|
||||
model: None,
|
||||
group_by: UsageLeaderboardGroupBy::User,
|
||||
})
|
||||
.await
|
||||
.unwrap();
|
||||
assert_eq!(rows.iter().map(|row| row.request_count).sum::<u64>(), count);
|
||||
}
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn summarizes_provider_api_key_last_used_at_in_seconds() {
|
||||
let repository = InMemoryUsageReadRepository::seed(vec![
|
||||
|
||||
@@ -2328,8 +2328,13 @@ impl WalletWriteRepository for InMemoryWalletRepository {
|
||||
async fn adjust_wallet_balance(
|
||||
&self,
|
||||
_input: AdjustWalletBalanceInput,
|
||||
) -> Result<Option<(StoredWalletSnapshot, super::StoredAdminWalletTransaction)>, DataLayerError>
|
||||
{
|
||||
) -> Result<
|
||||
Option<(
|
||||
StoredWalletSnapshot,
|
||||
Option<super::StoredAdminWalletTransaction>,
|
||||
)>,
|
||||
DataLayerError,
|
||||
> {
|
||||
Ok(None)
|
||||
}
|
||||
|
||||
|
||||
@@ -16,27 +16,30 @@ pub use aether_data_contracts::repository::wallet::{
|
||||
wallet_recharge_order_is_checkout_placeholder,
|
||||
wallet_recharge_order_is_reclaimable_placeholder, wallet_recharge_replay_matches,
|
||||
wallet_recharge_response_is_checkout_placeholder, wallet_refund_proof_is_success,
|
||||
AdjustWalletBalanceInput, AdminPaymentCallbackRecord, AdminPaymentOrderListQuery,
|
||||
AdminRedeemCodeBatchListQuery, AdminRedeemCodeListQuery, AdminWalletLedgerQuery,
|
||||
AdminWalletListQuery, AdminWalletPaymentOrderRecord, AdminWalletRefundRecord,
|
||||
AdminWalletRefundRequestListQuery, AdminWalletTransactionRecord, CanonicalWalletRefundFields,
|
||||
CompareAndSwapPaymentOrderStripeClientSecretInput, CompleteAdminWalletRefundInput,
|
||||
CreateAdminRedeemCodeBatchInput, CreateAdminRedeemCodeBatchResult,
|
||||
CreateManualWalletRechargeInput, CreatePlanPurchaseOrderInput, CreatePlanPurchaseOrderOutcome,
|
||||
CreateWalletRechargeOrderInput, CreateWalletRechargeOrderOutcome,
|
||||
CreateWalletRefundRequestInput, CreateWalletRefundRequestOutcome,
|
||||
CreatedAdminRedeemCodePlaintext, CreditAdminPaymentOrderInput, DeleteAdminRedeemCodeBatchInput,
|
||||
AdjustWalletBalanceInBatchInput, AdjustWalletBalanceInput, AdminPaymentCallbackRecord,
|
||||
AdminPaymentOrderListQuery, AdminRedeemCodeBatchListQuery, AdminRedeemCodeListQuery,
|
||||
AdminUserWalletBalanceBatchContext, AdminUserWalletBalanceBatchUserOutcome,
|
||||
AdminWalletLedgerQuery, AdminWalletListQuery, AdminWalletPaymentOrderRecord,
|
||||
AdminWalletRefundRecord, AdminWalletRefundRequestListQuery, AdminWalletTransactionRecord,
|
||||
CanonicalWalletRefundFields, CompareAndSwapPaymentOrderStripeClientSecretInput,
|
||||
CompleteAdminWalletRefundInput, CreateAdminRedeemCodeBatchInput,
|
||||
CreateAdminRedeemCodeBatchResult, CreateManualWalletRechargeInput,
|
||||
CreatePlanPurchaseOrderInput, CreatePlanPurchaseOrderOutcome, CreateWalletRechargeOrderInput,
|
||||
CreateWalletRechargeOrderOutcome, CreateWalletRefundRequestInput,
|
||||
CreateWalletRefundRequestOutcome, CreatedAdminRedeemCodePlaintext,
|
||||
CreditAdminPaymentOrderInput, DeleteAdminRedeemCodeBatchInput,
|
||||
DisableAdminRedeemCodeBatchInput, DisableAdminRedeemCodeInput, FailAdminWalletRefundInput,
|
||||
FailWalletRechargeCheckoutInput, InitializeAuthWalletOutcome, ProcessAdminWalletRefundInput,
|
||||
ProcessPaymentCallbackInput, ProcessPaymentCallbackOutcome, ReclaimWalletRechargeCheckoutInput,
|
||||
RedeemWalletCodeInput, RedeemWalletCodeOutcome, StoredAdminPaymentCallback,
|
||||
StoredAdminPaymentCallbackPage, StoredAdminPaymentOrder, StoredAdminPaymentOrderPage,
|
||||
StoredAdminRedeemCode, StoredAdminRedeemCodeBatch, StoredAdminRedeemCodeBatchPage,
|
||||
StoredAdminRedeemCodePage, StoredAdminWalletLedgerItem, StoredAdminWalletLedgerPage,
|
||||
StoredAdminWalletListItem, StoredAdminWalletListPage, StoredAdminWalletRefund,
|
||||
StoredAdminWalletRefundPage, StoredAdminWalletRefundRequestItem,
|
||||
StoredAdminWalletRefundRequestPage, StoredAdminWalletTransaction,
|
||||
StoredAdminWalletTransactionPage, StoredWalletDailyUsageLedger,
|
||||
FailWalletRechargeCheckoutInput, InitializeAuthWalletOutcome,
|
||||
PrepareAdminUserWalletBalanceBatchInput, PrepareAdminUserWalletBalanceBatchOutcome,
|
||||
ProcessAdminWalletRefundInput, ProcessPaymentCallbackInput, ProcessPaymentCallbackOutcome,
|
||||
ReclaimWalletRechargeCheckoutInput, RedeemWalletCodeInput, RedeemWalletCodeOutcome,
|
||||
StoredAdminPaymentCallback, StoredAdminPaymentCallbackPage, StoredAdminPaymentOrder,
|
||||
StoredAdminPaymentOrderPage, StoredAdminRedeemCode, StoredAdminRedeemCodeBatch,
|
||||
StoredAdminRedeemCodeBatchPage, StoredAdminRedeemCodePage, StoredAdminUserWalletBalanceBatch,
|
||||
StoredAdminWalletLedgerItem, StoredAdminWalletLedgerPage, StoredAdminWalletListItem,
|
||||
StoredAdminWalletListPage, StoredAdminWalletRefund, StoredAdminWalletRefundPage,
|
||||
StoredAdminWalletRefundRequestItem, StoredAdminWalletRefundRequestPage,
|
||||
StoredAdminWalletTransaction, StoredAdminWalletTransactionPage, StoredWalletDailyUsageLedger,
|
||||
StoredWalletDailyUsageLedgerPage, StoredWalletSnapshot, UpdateAdminWalletRefundGatewayInput,
|
||||
UpdateWalletRechargeCheckoutInput, WalletLookupKey, WalletMutationOutcome,
|
||||
WalletReadRepository, WalletReadSeed, WalletReadSnapshot, WalletRepository,
|
||||
|
||||
Reference in New Issue
Block a user