ledger entries wip

This commit is contained in:
Brandon Thomas committed 2025-09-12 01:00:04 -04:00
1 parent 6177782946
commit f272dbf401
8 files changed
+109 -40

No files matched your search

@@ -0,0 +1,25 @@
use crate::queries::wallet_ledger_entries::internal_insert_wallet_ledger_entry::InsertWalletLedgerEntry;
use enums::by_table::wallet_ledger_entries::wallet_ledger_entry_type::WalletLedgerEntryType;
use errors::AnyhowResult;
use sqlx::MySql;
use tokens::tokens::wallets::WalletToken;
pub (crate) async fn internal_insert_wallet_created_ledger_entry(
wallet_token: &WalletToken,
transaction: &mut sqlx::Transaction<'_, MySql>,
) -> AnyhowResult<()> {
let record = InsertWalletLedgerEntry {
wallet_token,
entry_type: WalletLedgerEntryType::Create,
maybe_entity_ref: None,
banked_credits_before: 0,
banked_credits_after: 0,
monthly_credits_before: 0,
monthly_credits_after: 0,
};
record.upsert_with_transaction(transaction).await?;
Ok(())
}
@@ -10,7 +10,7 @@ use tokens::tokens::wallets::WalletToken;
// TODO: Make a trait (eg. `InsertableRecord`, `UpsertableRecord`) with default impls to handle common query concerns.
pub struct InsertWalletLedgerEntry<'a> {
pub (crate) struct InsertWalletLedgerEntry<'a> {
/// The wallet
pub wallet_token: &'a WalletToken,
@@ -1 +1,2 @@
pub (crate) mod internal_insert_wallet_ledger_entry;
pub (crate) mod internal_insert_wallet_ledger_entry;
pub mod internal_insert_wallet_created_ledger_entry;
@@ -1,5 +1,7 @@
use crate::queries::wallet_ledger_entries::internal_insert_wallet_ledger_entry::InsertWalletLedgerEntry;
use crate::queries::wallets::internal_select_wallet_balance_for_update::internal_select_wallet_balance_for_update;
use crate::queries::wallets::wallet_update_summary::WalletUpdateSummary;
use enums::by_table::wallet_ledger_entries::wallet_ledger_entry_type::WalletLedgerEntryType;
use sqlx::MySql;
use tokens::tokens::wallets::WalletToken;
@@ -15,9 +17,9 @@ pub async fn add_durable_banked_balance_to_wallet(
transaction
).await?;
let existing_balance = wallet.banked_credits;
let new_balance = existing_balance.saturating_add(amount_to_add);
let existing_banked_balance = wallet.banked_credits;
let new_banked_balance = existing_banked_balance.saturating_add(amount_to_add);
// TODO: Insert ledger event.
let result = sqlx::query!(
@@ -29,17 +31,38 @@ pub async fn add_durable_banked_balance_to_wallet(
WHERE token = ?
LIMIT 1
"#,
new_balance,
new_banked_balance,
wallet_token.as_str(),
).execute(&mut **transaction)
.await?;
let record = InsertWalletLedgerEntry {
wallet_token,
entry_type: WalletLedgerEntryType::CreditBanked,
maybe_entity_ref: None, // TODO
// Updated banked credits
banked_credits_before: existing_banked_balance,
banked_credits_after: new_banked_balance,
// Unchanged monthly credits
monthly_credits_before: wallet.monthly_credits,
monthly_credits_after: wallet.monthly_credits,
};
record.upsert_with_transaction(transaction).await?;
Ok(WalletUpdateSummary {
token: wallet.token,
owner_user_token: wallet.owner_user_token,
banked_credits_now: new_balance,
// Updated banked credits
banked_credits_before: existing_banked_balance,
banked_credits_now: new_banked_balance,
// Unchanged monthly credits
monthly_credits_now: wallet.monthly_credits,
banked_credits_before: wallet.banked_credits,
monthly_credits_before: wallet.monthly_credits,
})
}
@@ -1,3 +1,4 @@
use crate::queries::wallet_ledger_entries::internal_insert_wallet_created_ledger_entry::internal_insert_wallet_created_ledger_entry;
use errors::AnyhowResult;
use sqlx::MySql;
use tokens::tokens::users::UserToken;
@@ -26,8 +27,11 @@ SET
.execute(&mut **transaction)
.await;
match result {
Ok(_) => Ok(token),
Err(e) => Err(anyhow::anyhow!("Database query error when creating wallet: {}", e)),
if let Err(err) = result {
return Err(anyhow::anyhow!("Database query error when creating wallet: {}", err));
}
internal_insert_wallet_created_ledger_entry(&token, transaction).await?;
Ok(token)
}
@@ -1,5 +1,7 @@
use crate::queries::wallet_ledger_entries::internal_insert_wallet_ledger_entry::InsertWalletLedgerEntry;
use crate::queries::wallets::internal_select_wallet_balance_for_update::internal_select_wallet_balance_for_update;
use crate::queries::wallets::wallet_update_summary::WalletUpdateSummary;
use enums::by_table::wallet_ledger_entries::wallet_ledger_entry_type::WalletLedgerEntryType;
use sqlx::MySql;
use tokens::tokens::wallets::WalletToken;
@@ -15,10 +17,8 @@ pub async fn refill_monthly_credits_balance_on_wallet(
transaction
).await?;
let existing_balance = wallet.monthly_credits;
let new_balance = monthly_amount;
// TODO: Insert ledger event.
let existing_monthly_balance = wallet.monthly_credits;
let new_monthly_balance = monthly_amount;
let result = sqlx::query!(
r#"
@@ -29,21 +29,37 @@ pub async fn refill_monthly_credits_balance_on_wallet(
WHERE token = ?
LIMIT 1
"#,
new_balance,
new_monthly_balance,
wallet_token.as_str(),
).execute(&mut **transaction)
.await?;
let record = InsertWalletLedgerEntry {
wallet_token,
entry_type: WalletLedgerEntryType::CreditMonthly,
maybe_entity_ref: None, // TODO
monthly_credits_before: existing_monthly_balance,
monthly_credits_after: new_monthly_balance,
// Unchanged
banked_credits_before: wallet.banked_credits,
banked_credits_after: wallet.banked_credits,
};
record.upsert_with_transaction(transaction).await?;
Ok(WalletUpdateSummary {
token: wallet.token,
owner_user_token: wallet.owner_user_token,
// We updated monthly credits
monthly_credits_now: new_balance,
monthly_credits_before: wallet.monthly_credits,
monthly_credits_before: existing_monthly_balance,
monthly_credits_now: new_monthly_balance,
// Banked credits not touched
banked_credits_now: wallet.banked_credits,
banked_credits_before: wallet.banked_credits,
banked_credits_now: wallet.banked_credits,
})
}
@@ -7,7 +7,7 @@ pub struct WalletUpdateSummary {
pub banked_credits_now: u64,
pub monthly_credits_now: u64,
pub banked_credits_before: u64,
pub monthly_credits_before: u64,
}
@@ -17,9 +17,9 @@ pub enum WalletLedgerEntryType {
#[serde(rename = "create")]
Create,
/// Credit durable balance
#[serde(rename = "credit_durable")]
CreditDurable,
/// Credit durable banked balance
#[serde(rename = "credit_banked")]
CreditBanked,
/// Credit monthly refill
#[serde(rename = "credit_monthly")]
@@ -29,9 +29,9 @@ pub enum WalletLedgerEntryType {
#[serde(rename = "deduct_mixed")]
DeductMixed,
/// Deduct durable credits
#[serde(rename = "deduct_durable")]
DeductDurable,
/// Deduct durable banked credits
#[serde(rename = "deduct_banked")]
DeductBanked,
/// Deduct monthly credits
#[serde(rename = "deduct_monthly")]
@@ -48,10 +48,10 @@ impl WalletLedgerEntryType {
pub fn to_str(&self) -> &'static str {
match self {
Self::Create => "create",
Self::CreditDurable => "credit_durable",
Self::CreditBanked => "credit_banked",
Self::CreditMonthly => "credit_monthly",
Self::DeductMixed => "deduct_mixed",
Self::DeductDurable => "deduct_durable",
Self::DeductBanked => "deduct_banked",
Self::DeductMonthly => "deduct_monthly",
}
}
@@ -59,10 +59,10 @@ impl WalletLedgerEntryType {
pub fn from_str(value: &str) -> Result<Self, String> {
match value {
"create" => Ok(Self::Create),
"credit_durable" => Ok(Self::CreditDurable),
"credit_banked" => Ok(Self::CreditBanked),
"credit_monthly" => Ok(Self::CreditMonthly),
"deduct_mixed" => Ok(Self::DeductMixed),
"deduct_durable" => Ok(Self::DeductDurable),
"deduct_banked" => Ok(Self::DeductBanked),
"deduct_monthly" => Ok(Self::DeductMonthly),
_ => Err(format!("invalid value: {:?}", value)),
}
@@ -73,10 +73,10 @@ impl WalletLedgerEntryType {
// NB: BTreeSet::from() isn't const, but not worth using LazyStatic, etc.
BTreeSet::from([
Self::Create,
Self::CreditDurable,
Self::CreditBanked,
Self::CreditMonthly,
Self::DeductMixed,
Self::DeductDurable,
Self::DeductBanked,
Self::DeductMonthly,
])
}
@@ -93,10 +93,10 @@ mod tests {
#[test]
fn test_serialization() {
assert_serialization(WalletLedgerEntryType::Create, "create");
assert_serialization(WalletLedgerEntryType::CreditDurable, "credit_durable");
assert_serialization(WalletLedgerEntryType::CreditBanked, "credit_banked");
assert_serialization(WalletLedgerEntryType::CreditMonthly, "credit_monthly");
assert_serialization(WalletLedgerEntryType::DeductMixed, "deduct_mixed");
assert_serialization(WalletLedgerEntryType::DeductDurable, "deduct_durable");
assert_serialization(WalletLedgerEntryType::DeductBanked, "deduct_banked");
assert_serialization(WalletLedgerEntryType::DeductMonthly, "deduct_monthly");
}
}
@@ -107,20 +107,20 @@ mod tests {
#[test]
fn to_str() {
assert_eq!(WalletLedgerEntryType::Create.to_str(), "create");
assert_eq!(WalletLedgerEntryType::CreditDurable.to_str(), "credit_durable");
assert_eq!(WalletLedgerEntryType::CreditBanked.to_str(), "credit_banked");
assert_eq!(WalletLedgerEntryType::CreditMonthly.to_str(), "credit_monthly");
assert_eq!(WalletLedgerEntryType::DeductMixed.to_str(), "deduct_mixed");
assert_eq!(WalletLedgerEntryType::DeductDurable.to_str(), "deduct_durable");
assert_eq!(WalletLedgerEntryType::DeductBanked.to_str(), "deduct_banked");
assert_eq!(WalletLedgerEntryType::DeductMonthly.to_str(), "deduct_monthly");
}
#[test]
fn from_str() {
assert_eq!(WalletLedgerEntryType::from_str("create").unwrap(), WalletLedgerEntryType::Create);
assert_eq!(WalletLedgerEntryType::from_str("credit_durable").unwrap(), WalletLedgerEntryType::CreditDurable);
assert_eq!(WalletLedgerEntryType::from_str("credit_banked").unwrap(), WalletLedgerEntryType::CreditBanked);
assert_eq!(WalletLedgerEntryType::from_str("credit_monthly").unwrap(), WalletLedgerEntryType::CreditMonthly);
assert_eq!(WalletLedgerEntryType::from_str("deduct_mixed").unwrap(), WalletLedgerEntryType::DeductMixed);
assert_eq!(WalletLedgerEntryType::from_str("deduct_durable").unwrap(), WalletLedgerEntryType::DeductDurable);
assert_eq!(WalletLedgerEntryType::from_str("deduct_banked").unwrap(), WalletLedgerEntryType::DeductBanked);
assert_eq!(WalletLedgerEntryType::from_str("deduct_monthly").unwrap(), WalletLedgerEntryType::DeductMonthly);
assert!(WalletLedgerEntryType::from_str("foo").is_err());
}
@@ -134,10 +134,10 @@ mod tests {
let mut variants = WalletLedgerEntryType::all_variants();
assert_eq!(variants.len(), 6);
assert_eq!(variants.pop_first(), Some(WalletLedgerEntryType::Create));
assert_eq!(variants.pop_first(), Some(WalletLedgerEntryType::CreditDurable));
assert_eq!(variants.pop_first(), Some(WalletLedgerEntryType::CreditBanked));
assert_eq!(variants.pop_first(), Some(WalletLedgerEntryType::CreditMonthly));
assert_eq!(variants.pop_first(), Some(WalletLedgerEntryType::DeductMixed));
assert_eq!(variants.pop_first(), Some(WalletLedgerEntryType::DeductDurable));
assert_eq!(variants.pop_first(), Some(WalletLedgerEntryType::DeductBanked));
assert_eq!(variants.pop_first(), Some(WalletLedgerEntryType::DeductMonthly));
assert_eq!(variants.pop_first(), None);
}