Skip to content

Commit 47020f3

Browse files
authored
Tax compliance adjustments (#4414)
* tax compliance adjustments * chore: query cache, clippy, fmt
1 parent 5c00cb0 commit 47020f3

7 files changed

+96
-47
lines changed

apps/labrinth/.sqlx/query-23fed658506cab399009f2e9ff8d092020ac9a06582a2c183c1b430b5919c6ce.json

Lines changed: 6 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.
Lines changed: 4 additions & 3 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

apps/labrinth/.sqlx/query-8ad3460f73020decc59106f28cdc3313ca0dc8aaf8c7b4e0f2e3a6f87ba4104b.json

Lines changed: 0 additions & 30 deletions
This file was deleted.

apps/labrinth/.sqlx/query-afca60d223bee04c7e4bdfa6a4f2771f9b9c5b3fce475085e1482d751bbc7675.json

Lines changed: 31 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
ALTER TABLE users_compliance ADD COLUMN requires_manual_review BOOLEAN NOT NULL DEFAULT FALSE;
2+
ALTER TABLE users_compliance ALTER COLUMN form_type DROP NOT NULL;

apps/labrinth/src/database/models/users_compliance.rs

Lines changed: 18 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -60,7 +60,8 @@ pub struct UserCompliance {
6060
pub last_checked: DateTime<Utc>,
6161
pub external_request_id: String,
6262
pub reference_id: String,
63-
pub form_type: FormType,
63+
pub form_type: Option<FormType>,
64+
pub requires_manual_review: bool,
6465
}
6566

6667
impl UserCompliance {
@@ -87,13 +88,18 @@ impl UserCompliance {
8788
last_checked: row.last_checked,
8889
external_request_id: row.external_request_id,
8990
reference_id: row.reference_id,
90-
form_type: FormType::from_str_or_default(&row.form_type),
91+
form_type: row
92+
.form_type
93+
.as_deref()
94+
.map(FormType::from_str_or_default),
95+
requires_manual_review: row.requires_manual_review,
9196
});
9297

9398
Ok(maybe_compliance)
9499
}
95100

96-
pub async fn upsert<'a, E>(&mut self, exec: E) -> sqlx::Result<()>
101+
/// This either inserts the row into the table or updates the row, *except the requires_manual_review* column.
102+
pub async fn upsert_partial<'a, E>(&mut self, exec: E) -> sqlx::Result<()>
97103
where
98104
E: sqlx::PgExecutor<'a>,
99105
{
@@ -109,9 +115,10 @@ impl UserCompliance {
109115
last_checked,
110116
external_request_id,
111117
reference_id,
112-
form_type
118+
form_type,
119+
requires_manual_review
113120
)
114-
VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9)
121+
VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10)
115122
ON CONFLICT (user_id)
116123
DO UPDATE SET
117124
requested = EXCLUDED.requested,
@@ -132,7 +139,8 @@ impl UserCompliance {
132139
self.last_checked,
133140
self.external_request_id,
134141
self.reference_id,
135-
self.form_type.as_str(),
142+
self.form_type.map(|s| s.as_str()),
143+
self.requires_manual_review,
136144
)
137145
.fetch_one(exec)
138146
.await?;
@@ -157,7 +165,8 @@ impl UserCompliance {
157165
last_checked = $6,
158166
external_request_id = $7,
159167
reference_id = $8,
160-
form_type = $9
168+
form_type = $9,
169+
requires_manual_review = $10
161170
WHERE id = $1
162171
"#,
163172
self.id,
@@ -168,7 +177,8 @@ impl UserCompliance {
168177
self.last_checked,
169178
self.external_request_id,
170179
self.reference_id,
171-
self.form_type.as_str(),
180+
self.form_type.map(|s| s.as_str()),
181+
self.requires_manual_review,
172182
)
173183
.execute(exec)
174184
.await?;

apps/labrinth/src/routes/v3/payouts.rs

Lines changed: 35 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -84,7 +84,8 @@ pub async fn post_compliance_form(
8484
reference_id: String::new(),
8585
e_delivery_consented: false,
8686
tin_matched: false,
87-
form_type: body.0.form_type,
87+
form_type: Some(body.0.form_type),
88+
requires_manual_review: false,
8889
},
8990
};
9091

@@ -108,10 +109,10 @@ pub async fn post_compliance_form(
108109
compliance.e_delivery_consented = false;
109110
compliance.tin_matched = false;
110111
compliance.signed = None;
111-
compliance.form_type = body.0.form_type;
112+
compliance.form_type = Some(body.0.form_type);
112113
compliance.last_checked = Utc::now() - COMPLIANCE_CHECK_DEBOUNCE;
113114

114-
compliance.upsert(&mut *txn).await?;
115+
compliance.upsert_partial(&mut *txn).await?;
115116
txn.commit().await?;
116117

117118
Ok(HttpResponse::Ok().json(toplevel))
@@ -489,6 +490,8 @@ pub async fn create_payout(
489490
));
490491
}
491492

493+
let requires_manual_review;
494+
492495
if let Some(threshold) = tax_compliance_payout_threshold() {
493496
let maybe_compliance = update_compliance_status(&pool, user.id).await?;
494497

@@ -501,9 +504,14 @@ pub async fn create_payout(
501504
let tin = model.tin_matched;
502505
let signed = model.signed.is_some();
503506

507+
requires_manual_review = Some(model.requires_manual_review);
508+
504509
(tin, signed, true, compliance_api_check_failed)
505510
}
506-
None => (false, false, false, false),
511+
None => {
512+
requires_manual_review = None;
513+
(false, false, false, false)
514+
}
507515
};
508516

509517
if !(tin_matched && signed)
@@ -526,6 +534,22 @@ pub async fn create_payout(
526534
_ => "Tax compliance form is required to withdraw more!",
527535
}.to_owned()));
528536
}
537+
} else {
538+
requires_manual_review = None;
539+
}
540+
541+
let requires_manual_review = if let Some(r) = requires_manual_review {
542+
r
543+
} else {
544+
users_compliance::UserCompliance::get_by_user_id(&**pool, user.id)
545+
.await?
546+
.is_some_and(|x| x.requires_manual_review)
547+
};
548+
549+
if requires_manual_review {
550+
return Err(ApiError::InvalidInput(
551+
"More information is required to proceed. Please contact support (https://support.modrinth.com, support@modrinth.com)".to_string(),
552+
));
529553
}
530554

531555
let payout_method = payouts_queue
@@ -953,8 +977,9 @@ pub async fn get_balance(
953977
form_completion_status = Some(
954978
update_compliance_status(&pool, user.id.into())
955979
.await?
980+
.filter(|x| x.model.form_type.is_some())
956981
.map_or(FormCompletionStatus::Unrequested, |compliance| {
957-
requested_form_type = Some(compliance.model.form_type);
982+
requested_form_type = compliance.model.form_type;
958983

959984
if compliance.compliance_api_check_failed {
960985
FormCompletionStatus::Unknown
@@ -1060,6 +1085,7 @@ async fn update_compliance_status(
10601085
if (compliance.signed.is_some() && compliance.tin_matched)
10611086
|| Utc::now().signed_duration_since(compliance.last_checked)
10621087
< COMPLIANCE_CHECK_DEBOUNCE
1088+
|| compliance.form_type.is_none()
10631089
{
10641090
Ok(Some(ComplianceCheck {
10651091
model: compliance,
@@ -1087,7 +1113,10 @@ async fn update_compliance_status(
10871113
compliance.e_delivery_consented =
10881114
attributes.e_delivery_consented_at.is_some();
10891115

1090-
if compliance.form_type.requires_domestic_tin_match() {
1116+
if compliance
1117+
.form_type
1118+
.is_some_and(|x| x.requires_domestic_tin_match())
1119+
{
10911120
compliance.tin_matched = attributes
10921121
.tin_match_status
10931122
.as_ref()

0 commit comments

Comments
 (0)