2023-07-10 06:13:03 +03:00
|
|
|
use crate::errors::Web3ProxyResult;
|
2023-07-10 05:23:32 +03:00
|
|
|
use fstrings::{f, format_args_f};
|
2023-07-10 06:13:03 +03:00
|
|
|
use migration::sea_orm;
|
|
|
|
use migration::sea_orm::prelude::Decimal;
|
|
|
|
use migration::sea_orm::{DbBackend, DbConn, FromQueryResult, Statement};
|
2023-07-10 05:23:32 +03:00
|
|
|
use serde::{Deserialize, Serialize};
|
|
|
|
|
|
|
|
/// Implements the balance getter
|
|
|
|
#[derive(Clone, Debug, Default, Serialize, Deserialize, FromQueryResult)]
|
|
|
|
pub struct Balance {
|
|
|
|
pub user_id: u64,
|
|
|
|
pub total_spent_paid_credits: Decimal,
|
|
|
|
pub total_spent: Decimal,
|
|
|
|
pub total_deposits: Decimal,
|
|
|
|
}
|
|
|
|
|
|
|
|
impl Balance {
|
2023-07-10 07:37:50 +03:00
|
|
|
pub fn active_premium(&self) -> bool {
|
|
|
|
self.was_ever_premium() && self.total_deposits > self.total_spent_paid_credits
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn was_ever_premium(&self) -> bool {
|
|
|
|
self.user_id != 0 && self.total_deposits >= Decimal::from(10)
|
|
|
|
}
|
|
|
|
|
2023-07-10 05:23:32 +03:00
|
|
|
pub fn remaining(&self) -> Decimal {
|
|
|
|
self.total_deposits - self.total_spent_paid_credits
|
|
|
|
}
|
|
|
|
|
2023-07-10 06:13:03 +03:00
|
|
|
pub async fn try_from_db(db_conn: &DbConn, user_id: u64) -> Web3ProxyResult<Option<Self>> {
|
|
|
|
// Return early if user_id == 0
|
|
|
|
if user_id == 0 {
|
|
|
|
return Ok(None);
|
|
|
|
}
|
2023-07-10 05:23:32 +03:00
|
|
|
|
2023-07-10 06:13:03 +03:00
|
|
|
// Injecting the variable directly, should be fine because Rust is typesafe, especially with primitives
|
|
|
|
let raw_sql = f!(r#"
|
|
|
|
SELECT
|
|
|
|
user.id AS user_id,
|
|
|
|
COALESCE(SUM(admin_receipt.amount), 0) + COALESCE(SUM(chain_receipt.amount), 0) + COALESCE(SUM(stripe_receipt.amount), 0) + COALESCE(SUM(referee.one_time_bonus_applied_for_referee), 0) + COALESCE(referrer_bonus.total_bonus, 0) AS total_deposits,
|
|
|
|
COALESCE(SUM(accounting.sum_credits_used), 0) AS total_spent_paid_credits,
|
|
|
|
COALESCE(SUM(accounting.sum_incl_free_credits_used), 0) AS total_spent
|
|
|
|
FROM
|
|
|
|
user
|
|
|
|
LEFT JOIN
|
|
|
|
admin_increase_balance_receipt AS admin_receipt ON user.id = admin_receipt.deposit_to_user_id
|
|
|
|
LEFT JOIN
|
|
|
|
increase_on_chain_balance_receipt AS chain_receipt ON user.id = chain_receipt.deposit_to_user_id
|
|
|
|
LEFT JOIN
|
|
|
|
stripe_increase_balance_receipt AS stripe_receipt ON user.id = stripe_receipt.deposit_to_user_id
|
|
|
|
LEFT JOIN
|
|
|
|
referee ON user.id = referee.user_id
|
|
|
|
LEFT JOIN
|
|
|
|
(SELECT referrer.user_id, SUM(referee.credits_applied_for_referrer) AS total_bonus
|
|
|
|
FROM referrer
|
|
|
|
JOIN referee ON referrer.id = referee.used_referral_code
|
|
|
|
GROUP BY referrer.user_id) AS referrer_bonus ON user.id = referrer_bonus.user_id
|
|
|
|
LEFT JOIN
|
|
|
|
rpc_key ON user.id = rpc_key.user_id
|
|
|
|
LEFT JOIN
|
|
|
|
rpc_accounting_v2 AS accounting ON rpc_key.id = accounting.rpc_key_id
|
|
|
|
LEFT JOIN
|
|
|
|
user_tier ON user.user_tier_id = user_tier.id
|
|
|
|
WHERE
|
|
|
|
user.id = {user_id};
|
|
|
|
"#);
|
2023-07-10 05:23:32 +03:00
|
|
|
|
2023-07-10 06:13:03 +03:00
|
|
|
let balance: Balance = match Self::find_by_statement(Statement::from_string(
|
|
|
|
DbBackend::MySql,
|
|
|
|
raw_sql,
|
|
|
|
// [.into()],
|
|
|
|
))
|
|
|
|
.one(db_conn)
|
|
|
|
.await?
|
|
|
|
{
|
|
|
|
None => return Ok(None),
|
|
|
|
Some(x) => x,
|
|
|
|
};
|
2023-07-10 05:23:32 +03:00
|
|
|
|
2023-07-10 06:13:03 +03:00
|
|
|
// Return None if there is no entry
|
|
|
|
Ok(Some(balance))
|
|
|
|
}
|
2023-07-10 05:23:32 +03:00
|
|
|
}
|