refactor: 拆分 gateway 单体为独立 crate,新增 systemd 部署方案

将 gateway 内部的 model-fetch、provider-transport、scheduler-core、
usage-runtime、video-tasks-core 模块提取为独立 crate;重构 gateway
内部模块结构(state/router/cache/data/query 等);移除大量遗留模块
文件;新增 systemd 二进制部署骨架及相关文档;更新前端 usage 相关
API 和组件。
This commit is contained in:
fawney19
2026-04-05 20:23:16 +08:00
parent cbc811f6ce
commit 763ff03a7b
777 changed files with 42654 additions and 21464 deletions
@@ -0,0 +1,397 @@
use super::{
AdminBillingCollectorRecord, AdminBillingCollectorWriteInput, AdminBillingPresetApplyResult,
AdminBillingRuleRecord, AdminBillingRuleWriteInput, AppState, GatewayError,
LocalMutationOutcome,
};
use crate::query::billing as billing_query;
impl AppState {
pub(crate) async fn admin_billing_enabled_default_value_exists(
&self,
api_format: &str,
task_type: &str,
dimension_name: &str,
existing_id: Option<&str>,
) -> Result<bool, GatewayError> {
#[cfg(test)]
if let Some(store) = self.admin_billing_collector_store.as_ref() {
let exists = store
.lock()
.expect("admin billing collector store should lock")
.values()
.any(|collector| {
collector.api_format == api_format
&& collector.task_type == task_type
&& collector.dimension_name == dimension_name
&& collector.is_enabled
&& collector.default_value.is_some()
&& existing_id.is_none_or(|value| collector.id != value)
});
return Ok(exists);
}
let Some(pool) = self.postgres_pool() else {
return Ok(false);
};
billing_query::admin_billing_enabled_default_value_exists(
&pool,
api_format,
task_type,
dimension_name,
existing_id,
)
.await
}
pub(crate) async fn create_admin_billing_rule(
&self,
input: &AdminBillingRuleWriteInput,
) -> Result<LocalMutationOutcome<AdminBillingRuleRecord>, GatewayError> {
#[cfg(test)]
if let Some(store) = self.admin_billing_rule_store.as_ref() {
let now_unix_secs = chrono::Utc::now().timestamp().max(0) as u64;
let record = AdminBillingRuleRecord {
id: uuid::Uuid::new_v4().to_string(),
name: input.name.clone(),
task_type: input.task_type.clone(),
global_model_id: input.global_model_id.clone(),
model_id: input.model_id.clone(),
expression: input.expression.clone(),
variables: input.variables.clone(),
dimension_mappings: input.dimension_mappings.clone(),
is_enabled: input.is_enabled,
created_at_unix_secs: now_unix_secs,
updated_at_unix_secs: now_unix_secs,
};
store
.lock()
.expect("admin billing rule store should lock")
.insert(record.id.clone(), record.clone());
return Ok(LocalMutationOutcome::Applied(record));
}
let Some(pool) = self.postgres_pool() else {
return Ok(LocalMutationOutcome::Unavailable);
};
billing_query::create_admin_billing_rule(&pool, input).await
}
pub(crate) async fn list_admin_billing_rules(
&self,
task_type: Option<&str>,
is_enabled: Option<bool>,
page: u32,
page_size: u32,
) -> Result<Option<(Vec<AdminBillingRuleRecord>, u64)>, GatewayError> {
#[cfg(test)]
if let Some(store) = self.admin_billing_rule_store.as_ref() {
let mut items = store
.lock()
.expect("admin billing rule store should lock")
.values()
.filter(|record| {
task_type.is_none_or(|expected| record.task_type == expected)
&& is_enabled.is_none_or(|expected| record.is_enabled == expected)
})
.cloned()
.collect::<Vec<_>>();
items.sort_by(|left, right| {
right
.updated_at_unix_secs
.cmp(&left.updated_at_unix_secs)
.then_with(|| right.id.cmp(&left.id))
});
let total = items.len() as u64;
let offset = (page.saturating_sub(1) as usize) * (page_size as usize);
let items = items
.into_iter()
.skip(offset)
.take(page_size as usize)
.collect::<Vec<_>>();
return Ok(Some((items, total)));
}
let Some(pool) = self.postgres_pool() else {
return Ok(None);
};
let (items, total) =
billing_query::list_admin_billing_rules(&pool, task_type, is_enabled, page, page_size)
.await?;
Ok(Some((items, total)))
}
pub(crate) async fn read_admin_billing_rule(
&self,
rule_id: &str,
) -> Result<Option<AdminBillingRuleRecord>, GatewayError> {
#[cfg(test)]
if let Some(store) = self.admin_billing_rule_store.as_ref() {
return Ok(store
.lock()
.expect("admin billing rule store should lock")
.get(rule_id)
.cloned());
}
let Some(pool) = self.postgres_pool() else {
return Ok(None);
};
billing_query::find_admin_billing_rule(&pool, rule_id).await
}
pub(crate) async fn update_admin_billing_rule(
&self,
rule_id: &str,
input: &AdminBillingRuleWriteInput,
) -> Result<LocalMutationOutcome<AdminBillingRuleRecord>, GatewayError> {
#[cfg(test)]
if let Some(store) = self.admin_billing_rule_store.as_ref() {
let mut guard = store.lock().expect("admin billing rule store should lock");
let Some(record) = guard.get_mut(rule_id) else {
return Ok(LocalMutationOutcome::NotFound);
};
record.name = input.name.clone();
record.task_type = input.task_type.clone();
record.global_model_id = input.global_model_id.clone();
record.model_id = input.model_id.clone();
record.expression = input.expression.clone();
record.variables = input.variables.clone();
record.dimension_mappings = input.dimension_mappings.clone();
record.is_enabled = input.is_enabled;
record.updated_at_unix_secs = chrono::Utc::now().timestamp().max(0) as u64;
return Ok(LocalMutationOutcome::Applied(record.clone()));
}
let Some(pool) = self.postgres_pool() else {
return Ok(LocalMutationOutcome::Unavailable);
};
billing_query::update_admin_billing_rule(&pool, rule_id, input).await
}
pub(crate) async fn create_admin_billing_collector(
&self,
input: &AdminBillingCollectorWriteInput,
) -> Result<LocalMutationOutcome<AdminBillingCollectorRecord>, GatewayError> {
#[cfg(test)]
if let Some(store) = self.admin_billing_collector_store.as_ref() {
let now_unix_secs = chrono::Utc::now().timestamp().max(0) as u64;
let record = AdminBillingCollectorRecord {
id: uuid::Uuid::new_v4().to_string(),
api_format: input.api_format.clone(),
task_type: input.task_type.clone(),
dimension_name: input.dimension_name.clone(),
source_type: input.source_type.clone(),
source_path: input.source_path.clone(),
value_type: input.value_type.clone(),
transform_expression: input.transform_expression.clone(),
default_value: input.default_value.clone(),
priority: input.priority,
is_enabled: input.is_enabled,
created_at_unix_secs: now_unix_secs,
updated_at_unix_secs: now_unix_secs,
};
store
.lock()
.expect("admin billing collector store should lock")
.insert(record.id.clone(), record.clone());
return Ok(LocalMutationOutcome::Applied(record));
}
let Some(pool) = self.postgres_pool() else {
return Ok(LocalMutationOutcome::Unavailable);
};
billing_query::create_admin_billing_collector(&pool, input).await
}
pub(crate) async fn list_admin_billing_collectors(
&self,
api_format: Option<&str>,
task_type: Option<&str>,
dimension_name: Option<&str>,
is_enabled: Option<bool>,
page: u32,
page_size: u32,
) -> Result<Option<(Vec<AdminBillingCollectorRecord>, u64)>, GatewayError> {
#[cfg(test)]
if let Some(store) = self.admin_billing_collector_store.as_ref() {
let mut items = store
.lock()
.expect("admin billing collector store should lock")
.values()
.filter(|record| {
api_format.is_none_or(|expected| record.api_format == expected)
&& task_type.is_none_or(|expected| record.task_type == expected)
&& dimension_name.is_none_or(|expected| record.dimension_name == expected)
&& is_enabled.is_none_or(|expected| record.is_enabled == expected)
})
.cloned()
.collect::<Vec<_>>();
items.sort_by(|left, right| {
right
.updated_at_unix_secs
.cmp(&left.updated_at_unix_secs)
.then_with(|| right.priority.cmp(&left.priority))
.then_with(|| right.id.cmp(&left.id))
});
let total = items.len() as u64;
let offset = (page.saturating_sub(1) as usize) * (page_size as usize);
let items = items
.into_iter()
.skip(offset)
.take(page_size as usize)
.collect::<Vec<_>>();
return Ok(Some((items, total)));
}
let Some(pool) = self.postgres_pool() else {
return Ok(None);
};
let (items, total) = billing_query::list_admin_billing_collectors(
&pool,
api_format,
task_type,
dimension_name,
is_enabled,
page,
page_size,
)
.await?;
Ok(Some((items, total)))
}
pub(crate) async fn read_admin_billing_collector(
&self,
collector_id: &str,
) -> Result<Option<AdminBillingCollectorRecord>, GatewayError> {
#[cfg(test)]
if let Some(store) = self.admin_billing_collector_store.as_ref() {
return Ok(store
.lock()
.expect("admin billing collector store should lock")
.get(collector_id)
.cloned());
}
let Some(pool) = self.postgres_pool() else {
return Ok(None);
};
billing_query::find_admin_billing_collector(&pool, collector_id).await
}
pub(crate) async fn update_admin_billing_collector(
&self,
collector_id: &str,
input: &AdminBillingCollectorWriteInput,
) -> Result<LocalMutationOutcome<AdminBillingCollectorRecord>, GatewayError> {
#[cfg(test)]
if let Some(store) = self.admin_billing_collector_store.as_ref() {
let mut guard = store
.lock()
.expect("admin billing collector store should lock");
let Some(record) = guard.get_mut(collector_id) else {
return Ok(LocalMutationOutcome::NotFound);
};
record.api_format = input.api_format.clone();
record.task_type = input.task_type.clone();
record.dimension_name = input.dimension_name.clone();
record.source_type = input.source_type.clone();
record.source_path = input.source_path.clone();
record.value_type = input.value_type.clone();
record.transform_expression = input.transform_expression.clone();
record.default_value = input.default_value.clone();
record.priority = input.priority;
record.is_enabled = input.is_enabled;
record.updated_at_unix_secs = chrono::Utc::now().timestamp().max(0) as u64;
return Ok(LocalMutationOutcome::Applied(record.clone()));
}
let Some(pool) = self.postgres_pool() else {
return Ok(LocalMutationOutcome::Unavailable);
};
billing_query::update_admin_billing_collector(&pool, collector_id, input).await
}
pub(crate) async fn apply_admin_billing_preset(
&self,
preset: &str,
mode: &str,
collectors: &[AdminBillingCollectorWriteInput],
) -> Result<LocalMutationOutcome<AdminBillingPresetApplyResult>, GatewayError> {
#[cfg(test)]
if let Some(store) = self.admin_billing_collector_store.as_ref() {
let mut created = 0_u64;
let mut updated = 0_u64;
let mut skipped = 0_u64;
let now_unix_secs = chrono::Utc::now().timestamp().max(0) as u64;
let mut guard = store
.lock()
.expect("admin billing collector store should lock");
for collector in collectors {
let existing_id = guard
.values()
.find(|record| {
record.api_format == collector.api_format
&& record.task_type == collector.task_type
&& record.dimension_name == collector.dimension_name
&& record.priority == collector.priority
&& record.is_enabled
})
.map(|record| record.id.clone());
match existing_id {
Some(existing_id) if mode == "overwrite" => {
if let Some(record) = guard.get_mut(&existing_id) {
record.source_type = collector.source_type.clone();
record.source_path = collector.source_path.clone();
record.value_type = collector.value_type.clone();
record.transform_expression = collector.transform_expression.clone();
record.default_value = collector.default_value.clone();
record.is_enabled = collector.is_enabled;
record.updated_at_unix_secs = now_unix_secs;
updated += 1;
} else {
skipped += 1;
}
}
Some(_) => {
skipped += 1;
}
None => {
let record = AdminBillingCollectorRecord {
id: uuid::Uuid::new_v4().to_string(),
api_format: collector.api_format.clone(),
task_type: collector.task_type.clone(),
dimension_name: collector.dimension_name.clone(),
source_type: collector.source_type.clone(),
source_path: collector.source_path.clone(),
value_type: collector.value_type.clone(),
transform_expression: collector.transform_expression.clone(),
default_value: collector.default_value.clone(),
priority: collector.priority,
is_enabled: collector.is_enabled,
created_at_unix_secs: now_unix_secs,
updated_at_unix_secs: now_unix_secs,
};
guard.insert(record.id.clone(), record);
created += 1;
}
}
}
return Ok(LocalMutationOutcome::Applied(
AdminBillingPresetApplyResult {
preset: preset.to_string(),
mode: mode.to_string(),
created,
updated,
skipped,
errors: Vec::new(),
},
));
}
let Some(pool) = self.postgres_pool() else {
return Ok(LocalMutationOutcome::Unavailable);
};
billing_query::apply_admin_billing_preset(&pool, preset, mode, collectors).await
}
}
@@ -0,0 +1,464 @@
use aether_data::repository::wallet::{
AdminPaymentOrderListQuery, AdminWalletLedgerQuery, AdminWalletListQuery,
AdminWalletRefundRequestListQuery, StoredAdminPaymentCallback, StoredAdminPaymentOrder,
StoredAdminWalletLedgerItem, StoredAdminWalletListItem, StoredAdminWalletRefund,
StoredAdminWalletRefundRequestItem, StoredAdminWalletTransaction,
};
use crate::state::AdminPaymentCallbackRecord;
use crate::{
AdminWalletMutationOutcome, AdminWalletPaymentOrderRecord, AdminWalletRefundRecord, AppState,
GatewayError,
};
impl AppState {
pub(crate) async fn list_admin_wallets(
&self,
status: Option<&str>,
owner_type: Option<&str>,
limit: usize,
offset: usize,
) -> Result<(Vec<StoredAdminWalletListItem>, u64), GatewayError> {
let page = self
.data
.list_admin_wallets(&AdminWalletListQuery {
status: status.map(ToOwned::to_owned),
owner_type: owner_type.map(ToOwned::to_owned),
limit,
offset,
})
.await
.map_err(|err| GatewayError::Internal(err.to_string()))?;
Ok((page.items, page.total))
}
pub(crate) async fn list_admin_wallet_ledger(
&self,
category: Option<&str>,
reason_code: Option<&str>,
owner_type: Option<&str>,
limit: usize,
offset: usize,
) -> Result<(Vec<StoredAdminWalletLedgerItem>, u64), GatewayError> {
let page = self
.data
.list_admin_wallet_ledger(&AdminWalletLedgerQuery {
category: category.map(ToOwned::to_owned),
reason_code: reason_code.map(ToOwned::to_owned),
owner_type: owner_type.map(ToOwned::to_owned),
limit,
offset,
})
.await
.map_err(|err| GatewayError::Internal(err.to_string()))?;
Ok((page.items, page.total))
}
pub(crate) async fn list_admin_payment_orders(
&self,
status: Option<&str>,
payment_method: Option<&str>,
limit: usize,
offset: usize,
) -> Result<Option<(Vec<AdminWalletPaymentOrderRecord>, u64)>, GatewayError> {
#[cfg(test)]
if let Some(store) = self.admin_wallet_payment_order_store.as_ref() {
let now_unix_secs = chrono::Utc::now().timestamp().max(0) as u64;
let mut items = store
.lock()
.expect("admin wallet payment order store should lock")
.values()
.filter(|order| {
payment_method.is_none_or(|expected| order.payment_method == expected)
&& status.is_none_or(|expected| {
let effective_status = if order.status == "pending"
&& order
.expires_at_unix_secs
.is_some_and(|value| value < now_unix_secs)
{
"expired"
} else {
order.status.as_str()
};
effective_status == expected
})
})
.cloned()
.collect::<Vec<_>>();
items.sort_by(|left, right| {
right
.created_at_unix_secs
.cmp(&left.created_at_unix_secs)
.then_with(|| right.id.cmp(&left.id))
});
let total = items.len() as u64;
let items = items
.into_iter()
.skip(offset)
.take(limit)
.collect::<Vec<_>>();
return Ok(Some((items, total)));
}
let page = self
.data
.list_admin_payment_orders(&AdminPaymentOrderListQuery {
status: status.map(ToOwned::to_owned),
payment_method: payment_method.map(ToOwned::to_owned),
limit,
offset,
})
.await
.map_err(|err| GatewayError::Internal(err.to_string()))?;
Ok(Some((
page.items
.into_iter()
.map(stored_admin_payment_order_to_gateway)
.collect(),
page.total,
)))
}
pub(crate) async fn list_admin_payment_callbacks(
&self,
payment_method: Option<&str>,
limit: usize,
offset: usize,
) -> Result<Option<(Vec<AdminPaymentCallbackRecord>, u64)>, GatewayError> {
#[cfg(test)]
if let Some(store) = self.admin_payment_callback_store.as_ref() {
let mut items = store
.lock()
.expect("admin payment callback store should lock")
.values()
.filter(|callback| {
payment_method.is_none_or(|expected| callback.payment_method == expected)
})
.cloned()
.collect::<Vec<_>>();
items.sort_by(|left, right| {
right
.created_at_unix_secs
.cmp(&left.created_at_unix_secs)
.then_with(|| right.id.cmp(&left.id))
});
let total = items.len() as u64;
let items = items
.into_iter()
.skip(offset)
.take(limit)
.collect::<Vec<_>>();
return Ok(Some((items, total)));
}
let page = self
.data
.list_admin_payment_callbacks(payment_method, limit, offset)
.await
.map_err(|err| GatewayError::Internal(err.to_string()))?;
Ok(Some((
page.items
.into_iter()
.map(stored_admin_payment_callback_to_gateway)
.collect(),
page.total,
)))
}
pub(crate) async fn list_admin_wallet_transactions(
&self,
wallet_id: &str,
limit: usize,
offset: usize,
) -> Result<(Vec<StoredAdminWalletTransaction>, u64), GatewayError> {
#[cfg(test)]
if let Some(store) = self.admin_wallet_transaction_store.as_ref() {
let mut items = store
.lock()
.expect("admin wallet transaction store should lock")
.values()
.filter(|transaction| transaction.wallet_id == wallet_id)
.cloned()
.collect::<Vec<_>>();
items.sort_by(|left, right| {
right
.created_at_unix_secs
.cmp(&left.created_at_unix_secs)
.then_with(|| right.id.cmp(&left.id))
});
let total = items.len() as u64;
let items = items
.into_iter()
.skip(offset)
.take(limit)
.map(|record| StoredAdminWalletTransaction {
id: record.id,
wallet_id: record.wallet_id,
category: record.category,
reason_code: record.reason_code,
amount: record.amount,
balance_before: record.balance_before,
balance_after: record.balance_after,
recharge_balance_before: record.recharge_balance_before,
recharge_balance_after: record.recharge_balance_after,
gift_balance_before: record.gift_balance_before,
gift_balance_after: record.gift_balance_after,
link_type: record.link_type,
link_id: record.link_id,
operator_id: record.operator_id,
operator_name: None,
operator_email: None,
description: record.description,
created_at_unix_secs: Some(record.created_at_unix_secs),
})
.collect::<Vec<_>>();
return Ok((items, total));
}
let page = self
.data
.list_admin_wallet_transactions(wallet_id, limit, offset)
.await
.map_err(|err| GatewayError::Internal(err.to_string()))?;
Ok((page.items, page.total))
}
pub(crate) async fn list_admin_wallet_refunds(
&self,
wallet_id: &str,
limit: usize,
offset: usize,
) -> Result<(Vec<AdminWalletRefundRecord>, u64), GatewayError> {
#[cfg(test)]
if let Some(store) = self.admin_wallet_refund_store.as_ref() {
let mut items = store
.lock()
.expect("admin wallet refund store should lock")
.values()
.filter(|refund| refund.wallet_id == wallet_id)
.cloned()
.collect::<Vec<_>>();
items.sort_by(|left, right| {
right
.created_at_unix_secs
.cmp(&left.created_at_unix_secs)
.then_with(|| right.id.cmp(&left.id))
});
let total = items.len() as u64;
let items = items
.into_iter()
.skip(offset)
.take(limit)
.collect::<Vec<_>>();
return Ok((items, total));
}
let page = self
.data
.list_admin_wallet_refunds(wallet_id, limit, offset)
.await
.map_err(|err| GatewayError::Internal(err.to_string()))?;
Ok((
page.items
.into_iter()
.map(stored_admin_wallet_refund_to_gateway)
.collect(),
page.total,
))
}
pub(crate) async fn list_admin_wallet_refund_requests(
&self,
status: Option<&str>,
limit: usize,
offset: usize,
) -> Result<(Vec<StoredAdminWalletRefundRequestItem>, u64), GatewayError> {
#[cfg(test)]
if let (Some(wallet_store), Some(refund_store)) = (
self.auth_wallet_store.as_ref(),
self.admin_wallet_refund_store.as_ref(),
) {
let wallets = wallet_store
.lock()
.expect("auth wallet store should lock")
.clone();
let mut items = refund_store
.lock()
.expect("admin wallet refund store should lock")
.values()
.filter(|refund| status.is_none_or(|expected| refund.status == expected))
.filter(|refund| {
wallets
.get(&refund.wallet_id)
.is_some_and(|wallet| wallet.user_id.is_some())
})
.cloned()
.collect::<Vec<_>>();
items.sort_by(|left, right| {
right
.created_at_unix_secs
.cmp(&left.created_at_unix_secs)
.then_with(|| right.id.cmp(&left.id))
});
let total = items.len() as u64;
let items = items
.into_iter()
.skip(offset)
.take(limit)
.filter_map(|refund| {
wallets.get(&refund.wallet_id).map(|wallet| {
StoredAdminWalletRefundRequestItem {
id: refund.id,
refund_no: refund.refund_no,
wallet_id: refund.wallet_id,
user_id: refund.user_id,
payment_order_id: refund.payment_order_id,
source_type: refund.source_type,
source_id: refund.source_id,
refund_mode: refund.refund_mode,
amount_usd: refund.amount_usd,
status: refund.status,
reason: refund.reason,
failure_reason: refund.failure_reason,
gateway_refund_id: refund.gateway_refund_id,
payout_method: refund.payout_method,
payout_reference: refund.payout_reference,
payout_proof: refund.payout_proof,
requested_by: refund.requested_by,
approved_by: refund.approved_by,
processed_by: refund.processed_by,
wallet_user_id: wallet.user_id.clone(),
wallet_user_name: None,
wallet_api_key_id: wallet.api_key_id.clone(),
api_key_name: None,
wallet_status: wallet.status.clone(),
created_at_unix_secs: Some(refund.created_at_unix_secs),
updated_at_unix_secs: Some(refund.updated_at_unix_secs),
processed_at_unix_secs: refund.processed_at_unix_secs,
completed_at_unix_secs: refund.completed_at_unix_secs,
}
})
})
.collect::<Vec<_>>();
return Ok((items, total));
}
let page = self
.data
.list_admin_wallet_refund_requests(&AdminWalletRefundRequestListQuery {
status: status.map(ToOwned::to_owned),
limit,
offset,
})
.await
.map_err(|err| GatewayError::Internal(err.to_string()))?;
Ok((page.items, page.total))
}
pub(crate) async fn read_admin_payment_order(
&self,
order_id: &str,
) -> Result<AdminWalletMutationOutcome<AdminWalletPaymentOrderRecord>, GatewayError> {
#[cfg(test)]
if let Some(store) = self.admin_wallet_payment_order_store.as_ref() {
return Ok(store
.lock()
.expect("admin wallet payment order store should lock")
.get(order_id)
.cloned()
.map(AdminWalletMutationOutcome::Applied)
.unwrap_or(AdminWalletMutationOutcome::NotFound));
}
if !self.has_wallet_data_reader() {
return Ok(AdminWalletMutationOutcome::Unavailable);
}
let order = self
.data
.find_admin_payment_order(order_id)
.await
.map_err(|err| GatewayError::Internal(err.to_string()))?;
match order {
Some(record) => Ok(AdminWalletMutationOutcome::Applied(
stored_admin_payment_order_to_gateway(record),
)),
None => Ok(AdminWalletMutationOutcome::NotFound),
}
}
}
fn stored_admin_payment_order_to_gateway(
record: StoredAdminPaymentOrder,
) -> AdminWalletPaymentOrderRecord {
AdminWalletPaymentOrderRecord {
id: record.id,
order_no: record.order_no,
wallet_id: record.wallet_id,
user_id: record.user_id,
amount_usd: record.amount_usd,
pay_amount: record.pay_amount,
pay_currency: record.pay_currency,
exchange_rate: record.exchange_rate,
refunded_amount_usd: record.refunded_amount_usd,
refundable_amount_usd: record.refundable_amount_usd,
payment_method: record.payment_method,
gateway_order_id: record.gateway_order_id,
status: record.status,
gateway_response: record.gateway_response,
created_at_unix_secs: record.created_at_unix_secs,
paid_at_unix_secs: record.paid_at_unix_secs,
credited_at_unix_secs: record.credited_at_unix_secs,
expires_at_unix_secs: record.expires_at_unix_secs,
}
}
fn stored_admin_payment_callback_to_gateway(
record: StoredAdminPaymentCallback,
) -> AdminPaymentCallbackRecord {
AdminPaymentCallbackRecord {
id: record.id,
payment_order_id: record.payment_order_id,
payment_method: record.payment_method,
callback_key: record.callback_key,
order_no: record.order_no,
gateway_order_id: record.gateway_order_id,
payload_hash: record.payload_hash,
signature_valid: record.signature_valid,
status: record.status,
payload: record.payload,
error_message: record.error_message,
created_at_unix_secs: record.created_at_unix_secs,
processed_at_unix_secs: record.processed_at_unix_secs,
}
}
fn stored_admin_wallet_refund_to_gateway(
record: StoredAdminWalletRefund,
) -> AdminWalletRefundRecord {
AdminWalletRefundRecord {
id: record.id,
refund_no: record.refund_no,
wallet_id: record.wallet_id,
user_id: record.user_id,
payment_order_id: record.payment_order_id,
source_type: record.source_type,
source_id: record.source_id,
refund_mode: record.refund_mode,
amount_usd: record.amount_usd,
status: record.status,
reason: record.reason,
failure_reason: record.failure_reason,
gateway_refund_id: record.gateway_refund_id,
payout_method: record.payout_method,
payout_reference: record.payout_reference,
payout_proof: record.payout_proof,
requested_by: record.requested_by,
approved_by: record.approved_by,
processed_by: record.processed_by,
created_at_unix_secs: record.created_at_unix_secs,
updated_at_unix_secs: record.updated_at_unix_secs,
processed_at_unix_secs: record.processed_at_unix_secs,
completed_at_unix_secs: record.completed_at_unix_secs,
}
}
@@ -0,0 +1,8 @@
use super::super::{
AdminBillingCollectorRecord, AdminBillingCollectorWriteInput, AdminBillingPresetApplyResult,
AdminBillingRuleRecord, AdminBillingRuleWriteInput, AppState, GatewayError,
LocalMutationOutcome,
};
mod admin;
mod finance_queries;