mirror of
https://github.com/fawney19/Aether.git
synced 2026-09-02 09:20:22 +08:00
Merge latest origin/main into codex/gemini-embedding-batch
# Conflicts: # apps/aether-gateway/src/ai_serving/planner/standard/openai/mod.rs # apps/aether-gateway/src/execution_runtime/fallback.rs
This commit is contained in:
@@ -0,0 +1 @@
|
||||
ALTER TABLE oauth_providers ADD COLUMN icon_url VARCHAR(500);
|
||||
@@ -0,0 +1 @@
|
||||
ALTER TABLE public.oauth_providers ADD COLUMN IF NOT EXISTS icon_url VARCHAR(500);
|
||||
@@ -0,0 +1 @@
|
||||
ALTER TABLE oauth_providers ADD COLUMN icon_url TEXT;
|
||||
@@ -416,6 +416,7 @@ CREATE TABLE IF NOT EXISTS public.oauth_providers (
|
||||
frontend_callback_url character varying(500) NOT NULL,
|
||||
attribute_mapping json,
|
||||
extra_config json,
|
||||
icon_url character varying(500),
|
||||
is_enabled boolean DEFAULT false NOT NULL,
|
||||
created_at timestamp with time zone DEFAULT CURRENT_TIMESTAMP NOT NULL,
|
||||
updated_at timestamp with time zone DEFAULT CURRENT_TIMESTAMP NOT NULL
|
||||
|
||||
@@ -36,6 +36,7 @@ CREATE TABLE IF NOT EXISTS oauth_providers (
|
||||
`frontend_callback_url` VARCHAR(500) NOT NULL,
|
||||
`attribute_mapping` JSON,
|
||||
`extra_config` JSON,
|
||||
`icon_url` VARCHAR(500),
|
||||
`is_enabled` TINYINT(1) NOT NULL DEFAULT 0,
|
||||
`created_at` BIGINT NOT NULL,
|
||||
`updated_at` BIGINT NOT NULL,
|
||||
|
||||
@@ -38,6 +38,7 @@ CREATE TABLE IF NOT EXISTS public.oauth_providers (
|
||||
frontend_callback_url character varying(500) NOT NULL,
|
||||
attribute_mapping jsonb,
|
||||
extra_config jsonb,
|
||||
icon_url character varying(500),
|
||||
is_enabled boolean DEFAULT false NOT NULL,
|
||||
created_at bigint NOT NULL,
|
||||
updated_at bigint NOT NULL
|
||||
|
||||
@@ -34,6 +34,7 @@ CREATE TABLE IF NOT EXISTS oauth_providers (
|
||||
frontend_callback_url TEXT NOT NULL,
|
||||
attribute_mapping TEXT,
|
||||
extra_config TEXT,
|
||||
icon_url TEXT,
|
||||
is_enabled INTEGER NOT NULL DEFAULT 0,
|
||||
created_at INTEGER NOT NULL,
|
||||
updated_at INTEGER NOT NULL
|
||||
|
||||
@@ -137,6 +137,12 @@ name = "extra_config"
|
||||
type = "json"
|
||||
nullable = true
|
||||
|
||||
[[table.oauth_providers.columns]]
|
||||
name = "icon_url"
|
||||
type = "text"
|
||||
length = 500
|
||||
nullable = true
|
||||
|
||||
[[table.oauth_providers.columns]]
|
||||
name = "is_enabled"
|
||||
type = "bool"
|
||||
|
||||
@@ -7,7 +7,7 @@ use tracing::info;
|
||||
// Generated by build.rs from schema/bootstrap/postgres.
|
||||
pub(crate) static EMPTY_DATABASE_SNAPSHOT_SQL: &str =
|
||||
include_str!(concat!(env!("OUT_DIR"), "/empty_database_snapshot.sql"));
|
||||
pub(crate) const EMPTY_DATABASE_SNAPSHOT_CUTOFF_VERSION: i64 = 20260519000000;
|
||||
pub(crate) const EMPTY_DATABASE_SNAPSHOT_CUTOFF_VERSION: i64 = 20260519120000;
|
||||
|
||||
const PUBLIC_BASE_TABLE_COUNT_SQL: &str = r#"
|
||||
SELECT COUNT(*)::BIGINT
|
||||
|
||||
@@ -308,6 +308,7 @@ fn empty_database_snapshot_covers_current_cutoff_versions() {
|
||||
20260516000000,
|
||||
20260518000000,
|
||||
20260519000000,
|
||||
20260519120000,
|
||||
]
|
||||
);
|
||||
}
|
||||
@@ -598,7 +599,9 @@ fn mysql_and_sqlite_migrations_include_enabled_incrementals() {
|
||||
20260512090000,
|
||||
20260512110000,
|
||||
20260516000000,
|
||||
20260518000000,
|
||||
20260519000000,
|
||||
20260519120000,
|
||||
]
|
||||
);
|
||||
assert_eq!(
|
||||
@@ -616,7 +619,9 @@ fn mysql_and_sqlite_migrations_include_enabled_incrementals() {
|
||||
20260512090000,
|
||||
20260512110000,
|
||||
20260516000000,
|
||||
20260518000000,
|
||||
20260519000000,
|
||||
20260519120000,
|
||||
]
|
||||
);
|
||||
}
|
||||
@@ -1136,6 +1141,7 @@ fn pending_migrations_from_applied_skips_versions_already_applied() {
|
||||
20260516000000,
|
||||
20260518000000,
|
||||
20260519000000,
|
||||
20260519120000,
|
||||
]
|
||||
);
|
||||
}
|
||||
|
||||
@@ -100,6 +100,7 @@ impl OAuthProviderWriteRepository for InMemoryOAuthProviderRepository {
|
||||
record.scopes.clone(),
|
||||
record.attribute_mapping.clone(),
|
||||
record.extra_config.clone(),
|
||||
record.icon_url.clone(),
|
||||
record.is_enabled,
|
||||
)
|
||||
.with_timestamps(created_at, now);
|
||||
@@ -150,6 +151,7 @@ mod tests {
|
||||
frontend_callback_url: "https://frontend.example.com/auth/callback".to_string(),
|
||||
attribute_mapping: Some(serde_json::json!({"email": "email"})),
|
||||
extra_config: Some(serde_json::json!({"team": true})),
|
||||
icon_url: None,
|
||||
is_enabled: true,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -46,6 +46,7 @@ SELECT
|
||||
frontend_callback_url,
|
||||
attribute_mapping,
|
||||
extra_config,
|
||||
icon_url,
|
||||
is_enabled,
|
||||
created_at AS created_at_unix_ms,
|
||||
updated_at AS updated_at_unix_secs
|
||||
@@ -67,6 +68,7 @@ SELECT
|
||||
frontend_callback_url,
|
||||
attribute_mapping,
|
||||
extra_config,
|
||||
icon_url,
|
||||
is_enabled,
|
||||
created_at AS created_at_unix_ms,
|
||||
updated_at AS updated_at_unix_secs
|
||||
@@ -176,13 +178,14 @@ INSERT INTO oauth_providers (
|
||||
frontend_callback_url,
|
||||
attribute_mapping,
|
||||
extra_config,
|
||||
icon_url,
|
||||
is_enabled,
|
||||
created_at,
|
||||
updated_at
|
||||
) VALUES (
|
||||
?, ?, ?,
|
||||
CASE ? WHEN 'set' THEN ? WHEN 'clear' THEN NULL ELSE NULL END,
|
||||
?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?
|
||||
?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?
|
||||
)
|
||||
ON DUPLICATE KEY UPDATE
|
||||
display_name = VALUES(display_name),
|
||||
@@ -200,6 +203,7 @@ ON DUPLICATE KEY UPDATE
|
||||
frontend_callback_url = VALUES(frontend_callback_url),
|
||||
attribute_mapping = VALUES(attribute_mapping),
|
||||
extra_config = VALUES(extra_config),
|
||||
icon_url = VALUES(icon_url),
|
||||
is_enabled = VALUES(is_enabled),
|
||||
updated_at = VALUES(updated_at)
|
||||
"#,
|
||||
@@ -217,6 +221,7 @@ ON DUPLICATE KEY UPDATE
|
||||
.bind(&record.frontend_callback_url)
|
||||
.bind(json_to_string(record.attribute_mapping.as_ref())?)
|
||||
.bind(json_to_string(record.extra_config.as_ref())?)
|
||||
.bind(record.icon_url.as_deref())
|
||||
.bind(record.is_enabled)
|
||||
.bind(now as i64)
|
||||
.bind(now as i64)
|
||||
@@ -361,6 +366,7 @@ fn map_oauth_provider_row(row: &MySqlRow) -> Result<StoredOAuthProviderConfig, D
|
||||
row.try_get("extra_config").map_sql_err()?,
|
||||
"oauth_providers.extra_config",
|
||||
)?,
|
||||
row.try_get("icon_url").map_sql_err()?,
|
||||
row.try_get("is_enabled").map_sql_err()?,
|
||||
)
|
||||
.with_timestamps(
|
||||
|
||||
@@ -22,6 +22,7 @@ SELECT
|
||||
frontend_callback_url,
|
||||
attribute_mapping,
|
||||
extra_config,
|
||||
icon_url,
|
||||
is_enabled,
|
||||
EXTRACT(EPOCH FROM created_at)::bigint AS created_at_unix_ms,
|
||||
EXTRACT(EPOCH FROM updated_at)::bigint AS updated_at_unix_secs
|
||||
@@ -77,6 +78,7 @@ INSERT INTO oauth_providers (
|
||||
frontend_callback_url,
|
||||
attribute_mapping,
|
||||
extra_config,
|
||||
icon_url,
|
||||
is_enabled,
|
||||
created_at,
|
||||
updated_at
|
||||
@@ -99,6 +101,7 @@ VALUES (
|
||||
$12,
|
||||
$13,
|
||||
$14,
|
||||
$15,
|
||||
NOW(),
|
||||
NOW()
|
||||
)
|
||||
@@ -118,6 +121,7 @@ SET display_name = EXCLUDED.display_name,
|
||||
frontend_callback_url = EXCLUDED.frontend_callback_url,
|
||||
attribute_mapping = EXCLUDED.attribute_mapping,
|
||||
extra_config = EXCLUDED.extra_config,
|
||||
icon_url = EXCLUDED.icon_url,
|
||||
is_enabled = EXCLUDED.is_enabled,
|
||||
updated_at = NOW()
|
||||
RETURNING
|
||||
@@ -133,6 +137,7 @@ RETURNING
|
||||
frontend_callback_url,
|
||||
attribute_mapping,
|
||||
extra_config,
|
||||
icon_url,
|
||||
is_enabled,
|
||||
EXTRACT(EPOCH FROM created_at)::bigint AS created_at_unix_ms,
|
||||
EXTRACT(EPOCH FROM updated_at)::bigint AS updated_at_unix_secs
|
||||
@@ -230,6 +235,7 @@ impl OAuthProviderWriteRepository for SqlxOAuthProviderRepository {
|
||||
.bind(&record.frontend_callback_url)
|
||||
.bind(record.attribute_mapping.as_ref())
|
||||
.bind(record.extra_config.as_ref())
|
||||
.bind(record.icon_url.as_deref())
|
||||
.bind(record.is_enabled)
|
||||
.fetch_one(&self.pool)
|
||||
.await
|
||||
@@ -330,6 +336,7 @@ fn map_oauth_provider_row(row: &PgRow) -> Result<StoredOAuthProviderConfig, Data
|
||||
parse_scopes(row.try_get("scopes").map_postgres_err()?)?,
|
||||
row.try_get("attribute_mapping").map_postgres_err()?,
|
||||
row.try_get("extra_config").map_postgres_err()?,
|
||||
row.try_get("icon_url").map_postgres_err()?,
|
||||
row.try_get("is_enabled").map_postgres_err()?,
|
||||
)
|
||||
.with_timestamps(
|
||||
|
||||
@@ -56,6 +56,7 @@ SELECT
|
||||
frontend_callback_url,
|
||||
attribute_mapping,
|
||||
extra_config,
|
||||
icon_url,
|
||||
is_enabled,
|
||||
created_at AS created_at_unix_ms,
|
||||
updated_at AS updated_at_unix_secs
|
||||
@@ -162,13 +163,14 @@ INSERT INTO oauth_providers (
|
||||
frontend_callback_url,
|
||||
attribute_mapping,
|
||||
extra_config,
|
||||
icon_url,
|
||||
is_enabled,
|
||||
created_at,
|
||||
updated_at
|
||||
) VALUES (
|
||||
?, ?, ?,
|
||||
CASE ? WHEN 'set' THEN ? WHEN 'clear' THEN NULL ELSE NULL END,
|
||||
?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?
|
||||
?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?
|
||||
)
|
||||
ON CONFLICT(provider_type) DO UPDATE SET
|
||||
display_name = excluded.display_name,
|
||||
@@ -186,6 +188,7 @@ ON CONFLICT(provider_type) DO UPDATE SET
|
||||
frontend_callback_url = excluded.frontend_callback_url,
|
||||
attribute_mapping = excluded.attribute_mapping,
|
||||
extra_config = excluded.extra_config,
|
||||
icon_url = excluded.icon_url,
|
||||
is_enabled = excluded.is_enabled,
|
||||
updated_at = excluded.updated_at
|
||||
"#,
|
||||
@@ -203,6 +206,7 @@ ON CONFLICT(provider_type) DO UPDATE SET
|
||||
.bind(&record.frontend_callback_url)
|
||||
.bind(json_to_string(record.attribute_mapping.as_ref())?)
|
||||
.bind(json_to_string(record.extra_config.as_ref())?)
|
||||
.bind(record.icon_url.as_deref())
|
||||
.bind(record.is_enabled)
|
||||
.bind(now as i64)
|
||||
.bind(now as i64)
|
||||
@@ -350,6 +354,7 @@ fn map_oauth_provider_row(row: &SqliteRow) -> Result<StoredOAuthProviderConfig,
|
||||
row.try_get("extra_config").map_sql_err()?,
|
||||
"oauth_providers.extra_config",
|
||||
)?,
|
||||
row.try_get("icon_url").map_sql_err()?,
|
||||
row.try_get("is_enabled").map_sql_err()?,
|
||||
)
|
||||
.with_timestamps(
|
||||
@@ -381,6 +386,7 @@ mod tests {
|
||||
frontend_callback_url: "https://frontend.example.com/auth/callback".to_string(),
|
||||
attribute_mapping: Some(serde_json::json!({"email": "email"})),
|
||||
extra_config: Some(serde_json::json!({"team": true})),
|
||||
icon_url: None,
|
||||
is_enabled: true,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -14,6 +14,7 @@ pub struct StoredOAuthProviderConfig {
|
||||
pub frontend_callback_url: String,
|
||||
pub attribute_mapping: Option<serde_json::Value>,
|
||||
pub extra_config: Option<serde_json::Value>,
|
||||
pub icon_url: Option<String>,
|
||||
pub is_enabled: bool,
|
||||
pub created_at_unix_ms: Option<u64>,
|
||||
pub updated_at_unix_secs: Option<u64>,
|
||||
@@ -66,6 +67,7 @@ impl StoredOAuthProviderConfig {
|
||||
frontend_callback_url,
|
||||
attribute_mapping: None,
|
||||
extra_config: None,
|
||||
icon_url: None,
|
||||
is_enabled: false,
|
||||
created_at_unix_ms: None,
|
||||
updated_at_unix_secs: None,
|
||||
@@ -82,6 +84,7 @@ impl StoredOAuthProviderConfig {
|
||||
scopes: Option<Vec<String>>,
|
||||
attribute_mapping: Option<serde_json::Value>,
|
||||
extra_config: Option<serde_json::Value>,
|
||||
icon_url: Option<String>,
|
||||
is_enabled: bool,
|
||||
) -> Self {
|
||||
self.client_secret_encrypted = client_secret_encrypted;
|
||||
@@ -91,6 +94,7 @@ impl StoredOAuthProviderConfig {
|
||||
self.scopes = scopes;
|
||||
self.attribute_mapping = attribute_mapping;
|
||||
self.extra_config = extra_config;
|
||||
self.icon_url = icon_url;
|
||||
self.is_enabled = is_enabled;
|
||||
self
|
||||
}
|
||||
@@ -145,6 +149,7 @@ pub struct UpsertOAuthProviderConfigRecord {
|
||||
pub frontend_callback_url: String,
|
||||
pub attribute_mapping: Option<serde_json::Value>,
|
||||
pub extra_config: Option<serde_json::Value>,
|
||||
pub icon_url: Option<String>,
|
||||
pub is_enabled: bool,
|
||||
}
|
||||
|
||||
|
||||
@@ -4,8 +4,8 @@ use std::sync::{Arc, RwLock};
|
||||
use async_trait::async_trait;
|
||||
|
||||
use super::{
|
||||
plan_finite_wallet_debit, SettlementWriteRepository, StoredUsageSettlement,
|
||||
UsageSettlementInput, SETTLEMENT_EPSILON_USD,
|
||||
plan_finite_wallet_debit, settlement_billing_status_for_usage_status,
|
||||
SettlementWriteRepository, StoredUsageSettlement, UsageSettlementInput, SETTLEMENT_EPSILON_USD,
|
||||
};
|
||||
use crate::repository::wallet::{InMemoryWalletRepository, StoredWalletSnapshot};
|
||||
use crate::DataLayerError;
|
||||
@@ -102,11 +102,8 @@ impl SettlementWriteRepository for InMemorySettlementRepository {
|
||||
})));
|
||||
}
|
||||
|
||||
let mut final_billing_status = if input.status == "completed" {
|
||||
"settled".to_string()
|
||||
} else {
|
||||
"void".to_string()
|
||||
};
|
||||
let mut final_billing_status =
|
||||
settlement_billing_status_for_usage_status(&input.status).to_string();
|
||||
let mut settlement = self.wallets.with_mut(|wallets| {
|
||||
let wallet_id = input
|
||||
.api_key_id
|
||||
@@ -306,6 +303,32 @@ mod tests {
|
||||
assert_eq!(settlement.wallet_balance_after, Some(9.0));
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn settles_cancelled_usage_against_wallet_and_provider_quota() {
|
||||
let repository = InMemorySettlementRepository::seed(vec![sample_wallet()]);
|
||||
let settlement = repository
|
||||
.settle_usage(UsageSettlementInput {
|
||||
request_id: "req-cancelled".to_string(),
|
||||
user_id: Some("user-1".to_string()),
|
||||
api_key_id: Some("key-1".to_string()),
|
||||
api_key_is_standalone: false,
|
||||
provider_id: Some("provider-1".to_string()),
|
||||
status: "cancelled".to_string(),
|
||||
billing_status: "pending".to_string(),
|
||||
total_cost_usd: 3.0,
|
||||
actual_total_cost_usd: 1.5,
|
||||
finalized_at_unix_secs: Some(200),
|
||||
})
|
||||
.await
|
||||
.expect("settlement should succeed")
|
||||
.expect("settlement should exist");
|
||||
|
||||
assert_eq!(settlement.billing_status, "settled");
|
||||
assert_eq!(settlement.wallet_balance_before, Some(12.0));
|
||||
assert_eq!(settlement.wallet_balance_after, Some(9.0));
|
||||
assert_eq!(settlement.provider_monthly_used_usd, Some(1.5));
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn standalone_key_settlement_never_falls_back_to_owner_wallet() {
|
||||
let repository = InMemorySettlementRepository::seed(vec![sample_user_wallet(
|
||||
|
||||
@@ -36,6 +36,31 @@ fn plan_finite_wallet_debit(
|
||||
}
|
||||
}
|
||||
|
||||
fn settlement_billing_status_for_usage_status(status: &str) -> &'static str {
|
||||
match status {
|
||||
"completed" | "cancelled" => "settled",
|
||||
_ => "void",
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::settlement_billing_status_for_usage_status;
|
||||
|
||||
#[test]
|
||||
fn cancelled_usage_status_is_billable() {
|
||||
assert_eq!(
|
||||
settlement_billing_status_for_usage_status("completed"),
|
||||
"settled"
|
||||
);
|
||||
assert_eq!(
|
||||
settlement_billing_status_for_usage_status("cancelled"),
|
||||
"settled"
|
||||
);
|
||||
assert_eq!(settlement_billing_status_for_usage_status("failed"), "void");
|
||||
}
|
||||
}
|
||||
|
||||
#[allow(unused_imports)]
|
||||
pub(crate) use aether_data_contracts::repository::settlement::{
|
||||
SettlementRepository, SettlementWriteRepository, StoredUsageSettlement, UsageSettlementInput,
|
||||
|
||||
@@ -2,8 +2,9 @@ use async_trait::async_trait;
|
||||
use sqlx::{mysql::MySqlRow, Row};
|
||||
|
||||
use super::{
|
||||
finite_wallet_available_usd, plan_finite_wallet_debit, SettlementWriteRepository,
|
||||
StoredUsageSettlement, UsageSettlementInput, SETTLEMENT_EPSILON_USD,
|
||||
finite_wallet_available_usd, plan_finite_wallet_debit,
|
||||
settlement_billing_status_for_usage_status, SettlementWriteRepository, StoredUsageSettlement,
|
||||
UsageSettlementInput, SETTLEMENT_EPSILON_USD,
|
||||
};
|
||||
use crate::driver::mysql::MysqlPool;
|
||||
use crate::error::SqlResultExt;
|
||||
@@ -364,11 +365,8 @@ impl SettlementWriteRepository for MysqlSettlementRepository {
|
||||
return Ok(Some(settlement));
|
||||
}
|
||||
|
||||
let mut final_billing_status = if input.status == "completed" {
|
||||
"settled".to_string()
|
||||
} else {
|
||||
"void".to_string()
|
||||
};
|
||||
let mut final_billing_status =
|
||||
settlement_billing_status_for_usage_status(&input.status).to_string();
|
||||
let mut settlement = StoredUsageSettlement {
|
||||
request_id: input.request_id.clone(),
|
||||
wallet_id: None,
|
||||
|
||||
@@ -2,8 +2,9 @@ use async_trait::async_trait;
|
||||
use sqlx::{PgPool, Row};
|
||||
|
||||
use super::{
|
||||
finite_wallet_available_usd, plan_finite_wallet_debit, SettlementWriteRepository,
|
||||
StoredUsageSettlement, UsageSettlementInput, SETTLEMENT_EPSILON_USD,
|
||||
finite_wallet_available_usd, plan_finite_wallet_debit,
|
||||
settlement_billing_status_for_usage_status, SettlementWriteRepository, StoredUsageSettlement,
|
||||
UsageSettlementInput, SETTLEMENT_EPSILON_USD,
|
||||
};
|
||||
use crate::driver::postgres::PostgresTransactionRunner;
|
||||
use crate::error::SqlxResultExt;
|
||||
@@ -455,11 +456,8 @@ impl SettlementWriteRepository for SqlxSettlementRepository {
|
||||
return settlement_from_row(&usage_row).map(Some);
|
||||
}
|
||||
|
||||
let mut final_billing_status = if input.status == "completed" {
|
||||
"settled".to_string()
|
||||
} else {
|
||||
"void".to_string()
|
||||
};
|
||||
let mut final_billing_status =
|
||||
settlement_billing_status_for_usage_status(&input.status).to_string();
|
||||
let finalized_at =
|
||||
i64::try_from(input.finalized_at_unix_secs.unwrap_or_else(|| {
|
||||
std::time::SystemTime::now()
|
||||
|
||||
@@ -2,8 +2,9 @@ use async_trait::async_trait;
|
||||
use sqlx::{sqlite::SqliteRow, Row};
|
||||
|
||||
use super::{
|
||||
finite_wallet_available_usd, plan_finite_wallet_debit, SettlementWriteRepository,
|
||||
StoredUsageSettlement, UsageSettlementInput, SETTLEMENT_EPSILON_USD,
|
||||
finite_wallet_available_usd, plan_finite_wallet_debit,
|
||||
settlement_billing_status_for_usage_status, SettlementWriteRepository, StoredUsageSettlement,
|
||||
UsageSettlementInput, SETTLEMENT_EPSILON_USD,
|
||||
};
|
||||
use crate::driver::sqlite::{sqlite_optional_real, sqlite_real, SqlitePool};
|
||||
use crate::error::SqlResultExt;
|
||||
@@ -377,11 +378,8 @@ impl SettlementWriteRepository for SqliteSettlementRepository {
|
||||
return Ok(Some(settlement));
|
||||
}
|
||||
|
||||
let mut final_billing_status = if input.status == "completed" {
|
||||
"settled".to_string()
|
||||
} else {
|
||||
"void".to_string()
|
||||
};
|
||||
let mut final_billing_status =
|
||||
settlement_billing_status_for_usage_status(&input.status).to_string();
|
||||
let mut settlement = StoredUsageSettlement {
|
||||
request_id: input.request_id.clone(),
|
||||
wallet_id: None,
|
||||
|
||||
@@ -336,8 +336,11 @@ SELECT
|
||||
users.role::text AS role,
|
||||
users.auth_source::text AS auth_source,
|
||||
users.allowed_providers,
|
||||
users.allowed_providers_mode,
|
||||
users.allowed_api_formats,
|
||||
users.allowed_api_formats_mode,
|
||||
users.allowed_models,
|
||||
users.allowed_models_mode,
|
||||
users.is_active,
|
||||
users.is_deleted,
|
||||
users.created_at,
|
||||
@@ -353,7 +356,7 @@ const TOUCH_OAUTH_LINK_SQL: &str = r#"
|
||||
UPDATE user_oauth_links
|
||||
SET provider_username = COALESCE($3, provider_username),
|
||||
provider_email = COALESCE($4, provider_email),
|
||||
extra_data = COALESCE($5, extra_data),
|
||||
extra_data = COALESCE($5::json, extra_data),
|
||||
last_login_at = $6
|
||||
WHERE provider_type = $1
|
||||
AND provider_user_id = $2
|
||||
|
||||
Reference in New Issue
Block a user