mirror of
https://github.com/modrinth/code.git
synced 2026-09-04 22:10:15 +00:00
fix how estimate range is fetched, /calculate route
This commit is contained in:
@@ -21,6 +21,8 @@ struct TestBalance {
|
||||
withdrawn_ytd: Decimal,
|
||||
pending: Decimal,
|
||||
dates: std::collections::HashMap<DateTime<Utc>, Decimal>,
|
||||
estimated_dates: std::collections::HashMap<DateTime<Utc>, Decimal>,
|
||||
actual_dates: std::collections::HashMap<DateTime<Utc>, Decimal>,
|
||||
}
|
||||
|
||||
async fn get_balance(test_env: &TestEnvironment<ApiV3>) -> TestBalance {
|
||||
@@ -33,6 +35,383 @@ async fn get_balance(test_env: &TestEnvironment<ApiV3>) -> TestBalance {
|
||||
test::read_body_json(response).await
|
||||
}
|
||||
|
||||
fn amount_delta(
|
||||
current: &std::collections::HashMap<DateTime<Utc>, Decimal>,
|
||||
initial: &std::collections::HashMap<DateTime<Utc>, Decimal>,
|
||||
date: DateTime<Utc>,
|
||||
) -> Decimal {
|
||||
current.get(&date).copied().unwrap_or_default()
|
||||
- initial.get(&date).copied().unwrap_or_default()
|
||||
}
|
||||
|
||||
async fn insert_succeeded_period(
|
||||
pool: &sqlx::PgPool,
|
||||
period: NaiveDate,
|
||||
run_id: i64,
|
||||
) {
|
||||
sqlx::query!(
|
||||
r#"
|
||||
INSERT INTO payout_periods (
|
||||
period,
|
||||
raw_actual_aditude_revenue_usd,
|
||||
adjustments
|
||||
)
|
||||
VALUES ($1, 100, '[]'::jsonb)
|
||||
"#,
|
||||
period,
|
||||
)
|
||||
.execute(pool)
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
let started_at = Utc.with_ymd_and_hms(2001, 1, 1, 0, 0, 0).unwrap();
|
||||
sqlx::query!(
|
||||
r#"
|
||||
INSERT INTO payout_runs (
|
||||
id,
|
||||
period,
|
||||
payload,
|
||||
status,
|
||||
started_at,
|
||||
started_by,
|
||||
execute_at,
|
||||
processing_started_at,
|
||||
finished_at
|
||||
)
|
||||
VALUES (
|
||||
$1,
|
||||
$2,
|
||||
'{"raw_actual_revenue_usd":100,"adjustments":[]}'::jsonb,
|
||||
'succeeded',
|
||||
$3,
|
||||
$4,
|
||||
$5,
|
||||
$5,
|
||||
$6
|
||||
)
|
||||
"#,
|
||||
run_id,
|
||||
period,
|
||||
started_at,
|
||||
USER_USER_ID_PARSED,
|
||||
started_at + Duration::minutes(2),
|
||||
started_at + Duration::minutes(3),
|
||||
)
|
||||
.execute(pool)
|
||||
.await
|
||||
.unwrap();
|
||||
}
|
||||
|
||||
#[actix_rt::test]
|
||||
async fn estimate_only_period_uses_estimate_as_pending_revenue() {
|
||||
with_test_environment(
|
||||
None,
|
||||
|test_env: TestEnvironment<ApiV3>| async move {
|
||||
let pool = &test_env.db.pool;
|
||||
let project_id =
|
||||
parse_base62(&test_env.dummy.project_alpha.project_id).unwrap()
|
||||
as i64;
|
||||
let now = Utc.timestamp_opt(Utc::now().timestamp(), 0).unwrap();
|
||||
let date_available = now - Duration::days(20);
|
||||
let initial_balance = get_balance(&test_env).await;
|
||||
|
||||
sqlx::query!(
|
||||
r#"
|
||||
INSERT INTO payout_estimates (
|
||||
period,
|
||||
user_id,
|
||||
mod_id,
|
||||
amount,
|
||||
created,
|
||||
date_available
|
||||
)
|
||||
VALUES ($1, $2, $3, 30, $4, $5)
|
||||
"#,
|
||||
NaiveDate::from_ymd_opt(2001, 1, 1).unwrap(),
|
||||
USER_USER_ID_PARSED,
|
||||
project_id,
|
||||
now - Duration::days(50),
|
||||
date_available,
|
||||
)
|
||||
.execute(pool)
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
let balance = get_balance(&test_env).await;
|
||||
assert_eq!(balance.available, initial_balance.available);
|
||||
assert_eq!(
|
||||
balance.pending,
|
||||
initial_balance.pending + Decimal::from(30),
|
||||
);
|
||||
assert_eq!(
|
||||
amount_delta(
|
||||
&balance.dates,
|
||||
&initial_balance.dates,
|
||||
date_available,
|
||||
),
|
||||
Decimal::from(30),
|
||||
);
|
||||
assert_eq!(
|
||||
amount_delta(
|
||||
&balance.estimated_dates,
|
||||
&initial_balance.estimated_dates,
|
||||
date_available,
|
||||
),
|
||||
Decimal::from(30),
|
||||
);
|
||||
assert_eq!(
|
||||
amount_delta(
|
||||
&balance.actual_dates,
|
||||
&initial_balance.actual_dates,
|
||||
date_available,
|
||||
),
|
||||
Decimal::ZERO,
|
||||
);
|
||||
},
|
||||
)
|
||||
.await;
|
||||
}
|
||||
|
||||
#[actix_rt::test]
|
||||
async fn finalized_only_period_uses_actual_as_pending_revenue() {
|
||||
with_test_environment(
|
||||
None,
|
||||
|test_env: TestEnvironment<ApiV3>| async move {
|
||||
let pool = &test_env.db.pool;
|
||||
let project_id =
|
||||
parse_base62(&test_env.dummy.project_alpha.project_id).unwrap()
|
||||
as i64;
|
||||
let now = Utc.timestamp_opt(Utc::now().timestamp(), 0).unwrap();
|
||||
let date_available = now + Duration::days(20);
|
||||
let period = NaiveDate::from_ymd_opt(2001, 2, 1).unwrap();
|
||||
let initial_balance = get_balance(&test_env).await;
|
||||
insert_succeeded_period(pool, period, 20_001).await;
|
||||
|
||||
sqlx::query!(
|
||||
r#"
|
||||
INSERT INTO payouts_values (
|
||||
user_id,
|
||||
mod_id,
|
||||
amount,
|
||||
created,
|
||||
date_available,
|
||||
payout_run_id
|
||||
)
|
||||
VALUES ($1, $2, 40, $3, $4, 20001)
|
||||
"#,
|
||||
USER_USER_ID_PARSED,
|
||||
project_id,
|
||||
now - Duration::days(50),
|
||||
date_available,
|
||||
)
|
||||
.execute(pool)
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
let balance = get_balance(&test_env).await;
|
||||
assert_eq!(balance.available, initial_balance.available);
|
||||
assert_eq!(
|
||||
balance.pending,
|
||||
initial_balance.pending + Decimal::from(40),
|
||||
);
|
||||
assert_eq!(
|
||||
amount_delta(
|
||||
&balance.dates,
|
||||
&initial_balance.dates,
|
||||
date_available,
|
||||
),
|
||||
Decimal::from(40),
|
||||
);
|
||||
assert_eq!(
|
||||
amount_delta(
|
||||
&balance.estimated_dates,
|
||||
&initial_balance.estimated_dates,
|
||||
date_available,
|
||||
),
|
||||
Decimal::ZERO,
|
||||
);
|
||||
assert_eq!(
|
||||
amount_delta(
|
||||
&balance.actual_dates,
|
||||
&initial_balance.actual_dates,
|
||||
date_available,
|
||||
),
|
||||
Decimal::from(40),
|
||||
);
|
||||
},
|
||||
)
|
||||
.await;
|
||||
}
|
||||
|
||||
#[actix_rt::test]
|
||||
async fn finalized_period_retains_estimate_but_uses_actual_balance() {
|
||||
with_test_environment(
|
||||
None,
|
||||
|test_env: TestEnvironment<ApiV3>| async move {
|
||||
let pool = &test_env.db.pool;
|
||||
let project_id =
|
||||
parse_base62(&test_env.dummy.project_alpha.project_id).unwrap()
|
||||
as i64;
|
||||
let now = Utc.timestamp_opt(Utc::now().timestamp(), 0).unwrap();
|
||||
let date_available = now - Duration::days(20);
|
||||
let period = NaiveDate::from_ymd_opt(2001, 3, 1).unwrap();
|
||||
let initial_balance = get_balance(&test_env).await;
|
||||
insert_succeeded_period(pool, period, 20_002).await;
|
||||
|
||||
sqlx::query!(
|
||||
r#"
|
||||
INSERT INTO payout_estimates (
|
||||
period,
|
||||
user_id,
|
||||
mod_id,
|
||||
amount,
|
||||
created,
|
||||
date_available
|
||||
)
|
||||
VALUES ($1, $2, $3, 100, $4, $5)
|
||||
"#,
|
||||
period,
|
||||
USER_USER_ID_PARSED,
|
||||
project_id,
|
||||
now - Duration::days(50),
|
||||
date_available,
|
||||
)
|
||||
.execute(pool)
|
||||
.await
|
||||
.unwrap();
|
||||
sqlx::query!(
|
||||
r#"
|
||||
INSERT INTO payouts_values (
|
||||
user_id,
|
||||
mod_id,
|
||||
amount,
|
||||
created,
|
||||
date_available,
|
||||
payout_run_id
|
||||
)
|
||||
VALUES ($1, $2, 80, $3, $4, 20002)
|
||||
"#,
|
||||
USER_USER_ID_PARSED,
|
||||
project_id,
|
||||
now - Duration::days(50),
|
||||
date_available,
|
||||
)
|
||||
.execute(pool)
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
let balance = get_balance(&test_env).await;
|
||||
assert_eq!(
|
||||
balance.available,
|
||||
initial_balance.available + Decimal::from(80),
|
||||
);
|
||||
assert_eq!(balance.pending, initial_balance.pending);
|
||||
assert_eq!(
|
||||
amount_delta(
|
||||
&balance.dates,
|
||||
&initial_balance.dates,
|
||||
date_available,
|
||||
),
|
||||
Decimal::from(80),
|
||||
);
|
||||
assert_eq!(
|
||||
amount_delta(
|
||||
&balance.estimated_dates,
|
||||
&initial_balance.estimated_dates,
|
||||
date_available,
|
||||
),
|
||||
Decimal::from(100),
|
||||
);
|
||||
assert_eq!(
|
||||
amount_delta(
|
||||
&balance.actual_dates,
|
||||
&initial_balance.actual_dates,
|
||||
date_available,
|
||||
),
|
||||
Decimal::from(80),
|
||||
);
|
||||
},
|
||||
)
|
||||
.await;
|
||||
}
|
||||
|
||||
#[actix_rt::test]
|
||||
async fn legacy_finalized_values_remain_available_and_pending() {
|
||||
with_test_environment(
|
||||
None,
|
||||
|test_env: TestEnvironment<ApiV3>| async move {
|
||||
let pool = &test_env.db.pool;
|
||||
let project_id =
|
||||
parse_base62(&test_env.dummy.project_alpha.project_id).unwrap()
|
||||
as i64;
|
||||
let now = Utc.timestamp_opt(Utc::now().timestamp(), 0).unwrap();
|
||||
let available_at = now - Duration::days(20);
|
||||
let pending_at = now + Duration::days(20);
|
||||
let initial_balance = get_balance(&test_env).await;
|
||||
|
||||
sqlx::query!(
|
||||
r#"
|
||||
INSERT INTO payouts_values (
|
||||
user_id,
|
||||
mod_id,
|
||||
amount,
|
||||
created,
|
||||
date_available
|
||||
)
|
||||
VALUES
|
||||
($1, $2, 70, $3, $4),
|
||||
($1, $2, 30, $5, $6)
|
||||
"#,
|
||||
USER_USER_ID_PARSED,
|
||||
project_id,
|
||||
now - Duration::days(50),
|
||||
available_at,
|
||||
now - Duration::days(10),
|
||||
pending_at,
|
||||
)
|
||||
.execute(pool)
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
let balance = get_balance(&test_env).await;
|
||||
assert_eq!(
|
||||
balance.available,
|
||||
initial_balance.available + Decimal::from(70),
|
||||
);
|
||||
assert_eq!(
|
||||
balance.pending,
|
||||
initial_balance.pending + Decimal::from(30),
|
||||
);
|
||||
for (date, amount) in [
|
||||
(available_at, Decimal::from(70)),
|
||||
(pending_at, Decimal::from(30)),
|
||||
] {
|
||||
assert_eq!(
|
||||
amount_delta(&balance.dates, &initial_balance.dates, date,),
|
||||
amount,
|
||||
);
|
||||
assert_eq!(
|
||||
amount_delta(
|
||||
&balance.actual_dates,
|
||||
&initial_balance.actual_dates,
|
||||
date,
|
||||
),
|
||||
amount,
|
||||
);
|
||||
assert_eq!(
|
||||
amount_delta(
|
||||
&balance.estimated_dates,
|
||||
&initial_balance.estimated_dates,
|
||||
date,
|
||||
),
|
||||
Decimal::ZERO,
|
||||
);
|
||||
}
|
||||
},
|
||||
)
|
||||
.await;
|
||||
}
|
||||
|
||||
#[actix_rt::test]
|
||||
async fn provisional_estimates_only_affect_pending_balance() {
|
||||
with_test_environment(
|
||||
|
||||
Reference in New Issue
Block a user