Fix pricing handler field name compatibility with admin UI

- Accept 'role' alias for 'role_key' and 'tracecoin_amount' alias for 'tracecoins_amount'
- Expose both field names in PackageDto so admin UI and user frontend both work

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
Ashwin Kumar 2026-04-02 18:15:42 +02:00
parent 2312f5dfdc
commit 73629fa935

View file

@ -37,8 +37,12 @@ struct PackageDto {
id: Uuid, id: Uuid,
name: String, name: String,
role_key: String, role_key: String,
// Also expose as 'role' for admin UI compatibility
role: String,
package_type: String, package_type: String,
tracecoins_amount: i32, tracecoins_amount: i32,
// Also expose as 'tracecoin_amount' for admin UI compatibility
tracecoin_amount: i32,
price_inr: i32, price_inr: i32,
description: Option<String>, description: Option<String>,
is_active: bool, is_active: bool,
@ -47,9 +51,13 @@ struct PackageDto {
#[derive(Deserialize)] #[derive(Deserialize)]
struct CreatePackageBody { struct CreatePackageBody {
name: String, name: String,
role_key: String, // Accept either role_key or role
role_key: Option<String>,
role: Option<String>,
package_type: Option<String>, package_type: Option<String>,
// Accept either tracecoins_amount or tracecoin_amount
tracecoins_amount: Option<i32>, tracecoins_amount: Option<i32>,
tracecoin_amount: Option<i32>,
price_inr: i32, price_inr: i32,
description: Option<String>, description: Option<String>,
} }
@ -58,8 +66,10 @@ struct CreatePackageBody {
struct PatchPackageBody { struct PatchPackageBody {
name: Option<String>, name: Option<String>,
role_key: Option<String>, role_key: Option<String>,
role: Option<String>,
package_type: Option<String>, package_type: Option<String>,
tracecoins_amount: Option<i32>, tracecoins_amount: Option<i32>,
tracecoin_amount: Option<i32>,
price_inr: Option<i32>, price_inr: Option<i32>,
description: Option<String>, description: Option<String>,
is_active: Option<bool>, is_active: Option<bool>,
@ -115,10 +125,12 @@ async fn public_list_packages(
.into_iter() .into_iter()
.map(|r| PackageDto { .map(|r| PackageDto {
id: r.id, id: r.id,
name: r.name, name: r.name.clone(),
role_key: r.role_key, role_key: r.role_key.clone(),
role: r.role_key.clone(),
package_type: r.package_type, package_type: r.package_type,
tracecoins_amount: r.tracecoins_amount, tracecoins_amount: r.tracecoins_amount,
tracecoin_amount: r.tracecoins_amount,
price_inr: r.price_inr, price_inr: r.price_inr,
description: r.description, description: r.description,
is_active: r.is_active, is_active: r.is_active,
@ -153,10 +165,12 @@ async fn list_packages(
.into_iter() .into_iter()
.map(|r| PackageDto { .map(|r| PackageDto {
id: r.id, id: r.id,
name: r.name, name: r.name.clone(),
role_key: r.role_key, role_key: r.role_key.clone(),
role: r.role_key.clone(),
package_type: r.package_type, package_type: r.package_type,
tracecoins_amount: r.tracecoins_amount, tracecoins_amount: r.tracecoins_amount,
tracecoin_amount: r.tracecoins_amount,
price_inr: r.price_inr, price_inr: r.price_inr,
description: r.description, description: r.description,
is_active: r.is_active, is_active: r.is_active,
@ -177,7 +191,10 @@ async fn create_package(
Json(body): Json<CreatePackageBody>, Json(body): Json<CreatePackageBody>,
) -> impl IntoResponse { ) -> impl IntoResponse {
let package_type = body.package_type.unwrap_or_else(|| "TRACECOIN_BUNDLE".to_string()); let package_type = body.package_type.unwrap_or_else(|| "TRACECOIN_BUNDLE".to_string());
let tracecoins_amount = body.tracecoins_amount.unwrap_or(0); // Accept tracecoin_amount (admin UI) or tracecoins_amount
let tracecoins_amount = body.tracecoins_amount.or(body.tracecoin_amount).unwrap_or(0);
// Accept role (admin UI) or role_key
let role_key = body.role_key.or(body.role).unwrap_or_else(|| "ALL".to_string());
let row = sqlx::query!( let row = sqlx::query!(
r#" r#"
@ -186,7 +203,7 @@ async fn create_package(
RETURNING id, name, role_key, package_type, tracecoins_amount, price_inr, description, is_active RETURNING id, name, role_key, package_type, tracecoins_amount, price_inr, description, is_active
"#, "#,
body.name, body.name,
body.role_key, role_key,
package_type, package_type,
tracecoins_amount, tracecoins_amount,
body.price_inr, body.price_inr,
@ -199,10 +216,12 @@ async fn create_package(
Ok(r) => { Ok(r) => {
let dto = PackageDto { let dto = PackageDto {
id: r.id, id: r.id,
name: r.name, name: r.name.clone(),
role_key: r.role_key, role_key: r.role_key.clone(),
role: r.role_key.clone(),
package_type: r.package_type, package_type: r.package_type,
tracecoins_amount: r.tracecoins_amount, tracecoins_amount: r.tracecoins_amount,
tracecoin_amount: r.tracecoins_amount,
price_inr: r.price_inr, price_inr: r.price_inr,
description: r.description, description: r.description,
is_active: r.is_active, is_active: r.is_active,
@ -239,9 +258,9 @@ async fn update_package(
}; };
let name = body.name.unwrap_or(existing.name); let name = body.name.unwrap_or(existing.name);
let role_key = body.role_key.unwrap_or(existing.role_key); let role_key = body.role_key.or(body.role).unwrap_or(existing.role_key);
let package_type = body.package_type.unwrap_or(existing.package_type); let package_type = body.package_type.unwrap_or(existing.package_type);
let tracecoins_amount = body.tracecoins_amount.unwrap_or(existing.tracecoins_amount); let tracecoins_amount = body.tracecoins_amount.or(body.tracecoin_amount).unwrap_or(existing.tracecoins_amount);
let price_inr = body.price_inr.unwrap_or(existing.price_inr); let price_inr = body.price_inr.unwrap_or(existing.price_inr);
let description = body.description.or(existing.description); let description = body.description.or(existing.description);
let is_active = body.is_active.unwrap_or(existing.is_active); let is_active = body.is_active.unwrap_or(existing.is_active);