diff --git a/apps/companies/src/handlers/admin.rs b/apps/companies/src/handlers/admin.rs index a45e335..d14acaf 100644 --- a/apps/companies/src/handlers/admin.rs +++ b/apps/companies/src/handlers/admin.rs @@ -186,12 +186,12 @@ async fn approve_company( State(state): State, Path(id): Path, ) -> Result { - sqlx::query("UPDATE company_profiles SET status = 'ACTIVE', updated_at = NOW() WHERE id = $1") + sqlx::query("UPDATE company_profiles SET status = 'APPROVED', updated_at = NOW() WHERE id = $1") .bind(id) .execute(&state.pool) .await .map_err(|e| (StatusCode::INTERNAL_SERVER_ERROR, format!("DB error: {e}")))?; - Ok(Json(serde_json::json!({ "status": "ACTIVE" }))) + Ok(Json(serde_json::json!({ "status": "APPROVED" }))) } async fn reject_company( diff --git a/apps/users/src/handlers/auth.rs b/apps/users/src/handlers/auth.rs index 8408631..8266817 100644 --- a/apps/users/src/handlers/auth.rs +++ b/apps/users/src/handlers/auth.rs @@ -165,6 +165,13 @@ fn resolve_signup_role_candidates(intent: Option<&str>, profession: Option<&str> vec![] } +fn is_dummy_account_email(email: &str) -> bool { + email.ends_with("@demo.com") + || email == "paymentgateway@demo.com" + || email.contains("+dummy@") + || email.starts_with("dummy+") +} + fn role_display_name_from_code(code: &str) -> String { code .split('_') @@ -297,7 +304,7 @@ async fn register( })?; // Check if this is a demo account (payment gateway integration) - let is_demo_account = email.ends_with("@demo.com") || email == "paymentgateway@demo.com"; + let is_demo_account = is_dummy_account_email(&email); // Assign signup role immediately (intent-driven). Email verification is still required for login. let role_candidates = resolve_signup_role_candidates( @@ -334,6 +341,7 @@ async fn register( .bind(user.id) .bind(role_id) .bind(status) + .execute(&state.pool) .await; break; } @@ -416,7 +424,7 @@ async fn login( } // Allow demo accounts to login without email verification - let is_demo_account = email.ends_with("@demo.com") || email == "paymentgateway@demo.com"; + let is_demo_account = is_dummy_account_email(&email); if !user.email_verified && !is_demo_account { return Err(err(StatusCode::UNAUTHORIZED, "Email not verified. Check your inbox.", "EMAIL_NOT_VERIFIED")); } diff --git a/apps/users/src/handlers/profile.rs b/apps/users/src/handlers/profile.rs index f87ca72..6613934 100644 --- a/apps/users/src/handlers/profile.rs +++ b/apps/users/src/handlers/profile.rs @@ -69,6 +69,13 @@ fn role_to_table(role_key: &str) -> Option<&'static str> { } } +fn is_dummy_account_email(email: &str) -> bool { + email.ends_with("@demo.com") + || email == "paymentgateway@demo.com" + || email.contains("+dummy@") + || email.starts_with("dummy+") +} + fn extract_documents(profile_data: &serde_json::Value) -> serde_json::Value { let doc_keys = [ "aadhar_doc", @@ -310,7 +317,7 @@ async fn submit_for_verification( .bind(auth.user_id) .fetch_one(&state.pool) .await - .map(|email| email.ends_with("@demo.com") || email == "paymentgateway@demo.com") + .map(|email| is_dummy_account_email(&email)) .unwrap_or(false); // For demo accounts: auto-approve verification diff --git a/crates/db/src/models/company.rs b/crates/db/src/models/company.rs index 728c374..49fea34 100644 --- a/crates/db/src/models/company.rs +++ b/crates/db/src/models/company.rs @@ -52,6 +52,20 @@ pub struct UpsertCompanyProfilePayload { pub struct CompanyRepository; impl CompanyRepository { + async fn is_dummy_account(pool: &PgPool, user_id: Uuid) -> Result { + let email = sqlx::query_scalar::<_, String>("SELECT email FROM users WHERE id = $1") + .bind(user_id) + .fetch_one(pool) + .await?; + + Ok( + email.ends_with("@demo.com") + || email == "paymentgateway@demo.com" + || email.contains("+dummy@") + || email.starts_with("dummy+"), + ) + } + pub async fn get_by_user_id( pool: &PgPool, user_id: Uuid, @@ -81,6 +95,9 @@ impl CompanyRepository { user_id: Uuid, payload: UpsertCompanyProfilePayload, ) -> Result { + let is_dummy_account = Self::is_dummy_account(pool, user_id).await?; + let default_status = if is_dummy_account { "APPROVED" } else { "PENDING" }; + let profile = sqlx::query_as::<_, CompanyProfile>( r#" INSERT INTO company_profiles ( @@ -88,7 +105,7 @@ impl CompanyRepository { employee_count, business_type, gst_number, contact_name, contact_email, contact_phone, address_line1, city, state, postal_code, status ) - VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13, $14, $15, 'PENDING') + VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13, $14, $15, $16) ON CONFLICT (user_id) DO UPDATE SET company_name = EXCLUDED.company_name, registration_number = EXCLUDED.registration_number, @@ -105,6 +122,7 @@ impl CompanyRepository { state = EXCLUDED.state, postal_code = EXCLUDED.postal_code, status = CASE + WHEN $17 THEN 'APPROVED' WHEN company_profiles.status = 'APPROVED' THEN 'APPROVED' ELSE 'PENDING' END, @@ -133,6 +151,8 @@ impl CompanyRepository { .bind(payload.city) .bind(payload.state) .bind(payload.postal_code) + .bind(default_status) + .bind(is_dummy_account) .fetch_one(pool) .await?; @@ -143,10 +163,13 @@ impl CompanyRepository { pool: &PgPool, user_id: Uuid, ) -> Result { + let is_dummy_account = Self::is_dummy_account(pool, user_id).await?; + let next_status = if is_dummy_account { "APPROVED" } else { "PENDING_REVIEW" }; + let profile = sqlx::query_as::<_, CompanyProfile>( r#" UPDATE company_profiles - SET status = 'PENDING_REVIEW', updated_at = NOW() + SET status = $2, updated_at = NOW() WHERE user_id = $1 RETURNING id, user_id, company_name, registration_number, industry, @@ -158,6 +181,7 @@ impl CompanyRepository { "#, ) .bind(user_id) + .bind(next_status) .fetch_one(pool) .await?;