You've already forked AstralRinth
forked from didirus/AstralRinth
Automatically cancel servers with failed payments older than 30d (#3695)
This commit is contained in:
106
apps/labrinth/.sqlx/query-d4d17b6a06c2f607206373b18a1f4c367f03f076e5e264ec8f5e744877c6d362.json
generated
Normal file
106
apps/labrinth/.sqlx/query-d4d17b6a06c2f607206373b18a1f4c367f03f076e5e264ec8f5e744877c6d362.json
generated
Normal file
@@ -0,0 +1,106 @@
|
|||||||
|
{
|
||||||
|
"db_name": "PostgreSQL",
|
||||||
|
"query": "\n SELECT\n id, user_id, price_id, amount, currency_code, status, due, last_attempt,\n charge_type, subscription_id,\n -- Workaround for https://github.com/launchbadge/sqlx/issues/3336\n subscription_interval AS \"subscription_interval?\",\n payment_platform,\n payment_platform_id AS \"payment_platform_id?\",\n parent_charge_id AS \"parent_charge_id?\",\n net AS \"net?\"\n FROM charges\n \n WHERE\n charge_type = $1 AND\n status = 'failed' AND due < NOW() - INTERVAL '30 days'\n ",
|
||||||
|
"describe": {
|
||||||
|
"columns": [
|
||||||
|
{
|
||||||
|
"ordinal": 0,
|
||||||
|
"name": "id",
|
||||||
|
"type_info": "Int8"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"ordinal": 1,
|
||||||
|
"name": "user_id",
|
||||||
|
"type_info": "Int8"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"ordinal": 2,
|
||||||
|
"name": "price_id",
|
||||||
|
"type_info": "Int8"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"ordinal": 3,
|
||||||
|
"name": "amount",
|
||||||
|
"type_info": "Int8"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"ordinal": 4,
|
||||||
|
"name": "currency_code",
|
||||||
|
"type_info": "Text"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"ordinal": 5,
|
||||||
|
"name": "status",
|
||||||
|
"type_info": "Varchar"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"ordinal": 6,
|
||||||
|
"name": "due",
|
||||||
|
"type_info": "Timestamptz"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"ordinal": 7,
|
||||||
|
"name": "last_attempt",
|
||||||
|
"type_info": "Timestamptz"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"ordinal": 8,
|
||||||
|
"name": "charge_type",
|
||||||
|
"type_info": "Text"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"ordinal": 9,
|
||||||
|
"name": "subscription_id",
|
||||||
|
"type_info": "Int8"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"ordinal": 10,
|
||||||
|
"name": "subscription_interval?",
|
||||||
|
"type_info": "Text"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"ordinal": 11,
|
||||||
|
"name": "payment_platform",
|
||||||
|
"type_info": "Text"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"ordinal": 12,
|
||||||
|
"name": "payment_platform_id?",
|
||||||
|
"type_info": "Text"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"ordinal": 13,
|
||||||
|
"name": "parent_charge_id?",
|
||||||
|
"type_info": "Int8"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"ordinal": 14,
|
||||||
|
"name": "net?",
|
||||||
|
"type_info": "Int8"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"parameters": {
|
||||||
|
"Left": [
|
||||||
|
"Text"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"nullable": [
|
||||||
|
false,
|
||||||
|
false,
|
||||||
|
false,
|
||||||
|
false,
|
||||||
|
false,
|
||||||
|
false,
|
||||||
|
false,
|
||||||
|
true,
|
||||||
|
false,
|
||||||
|
true,
|
||||||
|
true,
|
||||||
|
false,
|
||||||
|
true,
|
||||||
|
true,
|
||||||
|
true
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"hash": "d4d17b6a06c2f607206373b18a1f4c367f03f076e5e264ec8f5e744877c6d362"
|
||||||
|
}
|
||||||
@@ -254,6 +254,27 @@ impl DBCharge {
|
|||||||
.collect::<Result<Vec<_>, serde_json::Error>>()?)
|
.collect::<Result<Vec<_>, serde_json::Error>>()?)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub async fn get_cancellable(
|
||||||
|
exec: impl sqlx::Executor<'_, Database = sqlx::Postgres>,
|
||||||
|
) -> Result<Vec<DBCharge>, DatabaseError> {
|
||||||
|
let charge_type = ChargeType::Subscription.as_str();
|
||||||
|
let res = select_charges_with_predicate!(
|
||||||
|
r#"
|
||||||
|
WHERE
|
||||||
|
charge_type = $1 AND
|
||||||
|
status = 'failed' AND due < NOW() - INTERVAL '30 days'
|
||||||
|
"#,
|
||||||
|
charge_type
|
||||||
|
)
|
||||||
|
.fetch_all(exec)
|
||||||
|
.await?;
|
||||||
|
|
||||||
|
Ok(res
|
||||||
|
.into_iter()
|
||||||
|
.map(|r| r.try_into())
|
||||||
|
.collect::<Result<Vec<_>, serde_json::Error>>()?)
|
||||||
|
}
|
||||||
|
|
||||||
pub async fn remove(
|
pub async fn remove(
|
||||||
id: DBChargeId,
|
id: DBChargeId,
|
||||||
transaction: &mut sqlx::Transaction<'_, sqlx::Postgres>,
|
transaction: &mut sqlx::Transaction<'_, sqlx::Postgres>,
|
||||||
|
|||||||
@@ -2284,12 +2284,19 @@ pub async fn index_billing(
|
|||||||
) {
|
) {
|
||||||
info!("Indexing billing queue");
|
info!("Indexing billing queue");
|
||||||
let res = async {
|
let res = async {
|
||||||
|
// If a charge has continuously failed for more than a month, it should be cancelled
|
||||||
|
let charges_to_cancel = DBCharge::get_cancellable(&pool).await?;
|
||||||
|
|
||||||
|
for mut charge in charges_to_cancel {
|
||||||
|
charge.status = ChargeStatus::Cancelled;
|
||||||
|
|
||||||
|
let mut transaction = pool.begin().await?;
|
||||||
|
charge.upsert(&mut transaction).await?;
|
||||||
|
transaction.commit().await?;
|
||||||
|
}
|
||||||
|
|
||||||
// If a charge is open and due or has been attempted more than two days ago, it should be processed
|
// If a charge is open and due or has been attempted more than two days ago, it should be processed
|
||||||
let charges_to_do =
|
let charges_to_do = DBCharge::get_chargeable(&pool).await?;
|
||||||
crate::database::models::charge_item::DBCharge::get_chargeable(
|
|
||||||
&pool,
|
|
||||||
)
|
|
||||||
.await?;
|
|
||||||
|
|
||||||
let prices = product_item::DBProductPrice::get_many(
|
let prices = product_item::DBProductPrice::get_many(
|
||||||
&charges_to_do
|
&charges_to_do
|
||||||
|
|||||||
Reference in New Issue
Block a user