diff --git a/server-rs/crates/module-runtime/src/application.rs b/server-rs/crates/module-runtime/src/application.rs index 4779ec1fa..19de95527 100644 --- a/server-rs/crates/module-runtime/src/application.rs +++ b/server-rs/crates/module-runtime/src/application.rs @@ -1052,7 +1052,16 @@ pub fn build_runtime_profile_recharge_center_record( .into_iter() .map(build_runtime_profile_recharge_product_record) .collect(), - membership_plans: snapshot.membership_plans, + membership_products: snapshot + .membership_products + .into_iter() + .map(build_runtime_profile_recharge_product_record) + .collect(), + benefits: snapshot + .benefits + .into_iter() + .map(build_runtime_profile_membership_benefit_record) + .collect(), latest_order: snapshot .latest_order .map(build_runtime_profile_recharge_order_record), @@ -1076,6 +1085,11 @@ pub fn build_runtime_profile_recharge_product_record( duration_days: snapshot.duration_days, badge_label: snapshot.badge_label, description: snapshot.description, + tier: snapshot.tier, + membership_period_points: snapshot.membership_period_points, + membership_period_days: snapshot.membership_period_days, + membership_queue_limit: snapshot.membership_queue_limit, + membership_discount_bps: snapshot.membership_discount_bps, } } @@ -1092,6 +1106,11 @@ pub fn build_runtime_profile_recharge_product_config_record( duration_days: snapshot.duration_days, badge_label: snapshot.badge_label, description: snapshot.description, + tier: snapshot.tier, + membership_period_points: snapshot.membership_period_points, + membership_period_days: snapshot.membership_period_days, + membership_queue_limit: snapshot.membership_queue_limit, + membership_discount_bps: snapshot.membership_discount_bps, enabled: snapshot.enabled, sort_order: snapshot.sort_order, created_by: snapshot.created_by, @@ -1103,13 +1122,29 @@ pub fn build_runtime_profile_recharge_product_config_record( } } +pub fn build_runtime_profile_membership_benefit_record( + snapshot: RuntimeProfileMembershipBenefitSnapshot, +) -> RuntimeProfileMembershipBenefitRecord { + RuntimeProfileMembershipBenefitRecord { + benefit_name: snapshot.benefit_name, + normal_value: snapshot.normal_value, + month_value: snapshot.month_value, + season_value: snapshot.season_value, + year_value: snapshot.year_value, + starter_value: snapshot.starter_value, + basic_value: snapshot.basic_value, + pro_value: snapshot.pro_value, + ultimate_value: snapshot.ultimate_value, + } +} + pub fn build_runtime_profile_membership_record( snapshot: RuntimeProfileMembershipSnapshot, ) -> RuntimeProfileMembershipRecord { RuntimeProfileMembershipRecord { user_id: snapshot.user_id, status: snapshot.status, - plan: snapshot.plan, + tier: snapshot.tier, started_at: snapshot.started_at_micros.map(format_utc_micros), started_at_micros: snapshot.started_at_micros, expires_at: snapshot.expires_at_micros.map(format_utc_micros), @@ -1122,9 +1157,7 @@ pub fn build_runtime_profile_membership_record( cycle_resets_at_micros: snapshot.cycle_resets_at_micros, cycle_granted_points: snapshot.cycle_granted_points, cycle_remaining_points: snapshot.cycle_remaining_points, - cycle_index: snapshot.cycle_index, - cycle_count: snapshot.cycle_count, - cycle_kind: snapshot.cycle_kind, + cycle_period_days: snapshot.cycle_period_days, } } diff --git a/server-rs/crates/module-runtime/src/commands.rs b/server-rs/crates/module-runtime/src/commands.rs index bab1dff70..138bb2cf3 100644 --- a/server-rs/crates/module-runtime/src/commands.rs +++ b/server-rs/crates/module-runtime/src/commands.rs @@ -392,6 +392,11 @@ pub fn build_runtime_profile_recharge_product_admin_upsert_input( duration_days: u32, badge_label: String, description: String, + tier: RuntimeProfileMembershipTier, + membership_period_points: u64, + membership_period_days: u32, + membership_queue_limit: u32, + membership_discount_bps: u32, enabled: bool, sort_order: i32, updated_at_micros: i64, @@ -409,13 +414,28 @@ pub fn build_runtime_profile_recharge_product_admin_upsert_input( if points_amount == 0 { return Err(RuntimeProfileFieldError::InvalidRechargeProductPoints); } - if duration_days != 0 || bonus_points != 0 { + if duration_days != 0 + || tier != RuntimeProfileMembershipTier::Normal + || membership_period_points != 0 + || membership_period_days != 0 + || membership_queue_limit != 0 + || membership_discount_bps != 0 + { return Err(RuntimeProfileFieldError::InvalidRechargeProductTier); } } - // 中文注释:会员商品已迁移到 profile_membership_plan 目录,这里只保留泥点商品。 RuntimeProfileRechargeProductKind::Membership => { - return Err(RuntimeProfileFieldError::InvalidRechargeProductTier); + if duration_days == 0 { + return Err(RuntimeProfileFieldError::InvalidRechargeProductDuration); + } + if points_amount != 0 + || bonus_points != 0 + || tier == RuntimeProfileMembershipTier::Normal + || membership_period_points == 0 + || membership_period_days == 0 + { + return Err(RuntimeProfileFieldError::InvalidRechargeProductTier); + } } } @@ -430,6 +450,11 @@ pub fn build_runtime_profile_recharge_product_admin_upsert_input( duration_days, badge_label: normalize_optional_string(Some(badge_label)).unwrap_or_default(), description: normalize_optional_string(Some(description)).unwrap_or_default(), + tier, + membership_period_points, + membership_period_days, + membership_queue_limit, + membership_discount_bps, enabled, sort_order, updated_at_micros, diff --git a/server-rs/crates/module-runtime/src/domain.rs b/server-rs/crates/module-runtime/src/domain.rs index 267ff368e..be3856223 100644 --- a/server-rs/crates/module-runtime/src/domain.rs +++ b/server-rs/crates/module-runtime/src/domain.rs @@ -4,8 +4,6 @@ //! 纯领域事实与值对象;SpacetimeDB client 与 HTTP response 不进入本文件。 use serde::{Deserialize, Serialize}; - -use crate::RuntimeProfileMembershipPlanSnapshot; #[cfg(any())] use serde_json::Value; @@ -1231,10 +1229,37 @@ impl RuntimeProfileMembershipStatus { } } +#[cfg_attr(feature = "spacetime-types", derive(SpacetimeType))] +#[derive(Clone, Copy, Debug, PartialEq, Eq, Serialize, Deserialize)] +pub enum RuntimeProfileMembershipTier { + Normal, + Month, + Season, + Year, + Starter, + Basic, + Pro, + Ultimate, +} + +impl RuntimeProfileMembershipTier { + pub fn as_str(&self) -> &'static str { + match self { + Self::Normal => "normal", + Self::Month => "month", + Self::Season => "season", + Self::Year => "year", + Self::Starter => "starter", + Self::Basic => "basic", + Self::Pro => "pro", + Self::Ultimate => "ultimate", + } + } +} + /// 会员档位身份。取代旧的 `RuntimeProfileMembershipTier`,作为唯一权威档位标识。 /// -/// 变体顺序即排序基准(`Normal < Starter < Plus < Pro < Max`)。对外 wire 只用 -/// [`RuntimeProfileMembershipPlan::as_str`] 产出的枚举 token。 +/// 变体顺序即排序基准(`Normal < Starter < Plus < Pro < Max`),升级比较不再依赖旧枚举别名。 #[cfg_attr(feature = "spacetime-types", derive(SpacetimeType))] #[derive(Clone, Copy, Debug, PartialEq, Eq, Serialize, Deserialize)] pub enum RuntimeProfileMembershipPlan { @@ -1489,6 +1514,11 @@ pub struct RuntimeProfileRechargeProductSnapshot { pub duration_days: u32, pub badge_label: String, pub description: String, + pub tier: RuntimeProfileMembershipTier, + pub membership_period_points: u64, + pub membership_period_days: u32, + pub membership_queue_limit: u32, + pub membership_discount_bps: u32, } #[cfg_attr(feature = "spacetime-types", derive(SpacetimeType))] @@ -1503,6 +1533,11 @@ pub struct RuntimeProfileRechargeProductConfigSnapshot { pub duration_days: u32, pub badge_label: String, pub description: String, + pub tier: RuntimeProfileMembershipTier, + pub membership_period_points: u64, + pub membership_period_days: u32, + pub membership_queue_limit: u32, + pub membership_discount_bps: u32, pub enabled: bool, pub sort_order: i32, pub created_by: String, @@ -1511,12 +1546,26 @@ pub struct RuntimeProfileRechargeProductConfigSnapshot { pub updated_at_micros: i64, } +#[cfg_attr(feature = "spacetime-types", derive(SpacetimeType))] +#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)] +pub struct RuntimeProfileMembershipBenefitSnapshot { + pub benefit_name: String, + pub normal_value: String, + pub month_value: String, + pub season_value: String, + pub year_value: String, + pub starter_value: String, + pub basic_value: String, + pub pro_value: String, + pub ultimate_value: String, +} + #[cfg_attr(feature = "spacetime-types", derive(SpacetimeType))] #[derive(Clone, Debug, PartialEq, Serialize, Deserialize)] pub struct RuntimeProfileMembershipSnapshot { pub user_id: String, pub status: RuntimeProfileMembershipStatus, - pub plan: RuntimeProfileMembershipPlan, + pub tier: RuntimeProfileMembershipTier, pub started_at_micros: Option, pub expires_at_micros: Option, pub updated_at_micros: Option, @@ -1524,9 +1573,7 @@ pub struct RuntimeProfileMembershipSnapshot { pub cycle_resets_at_micros: Option, pub cycle_granted_points: u64, pub cycle_remaining_points: u64, - pub cycle_index: u32, - pub cycle_count: u32, - pub cycle_kind: RuntimeProfileMembershipCycleKind, + pub cycle_period_days: u32, } #[cfg_attr(feature = "spacetime-types", derive(SpacetimeType))] @@ -1718,7 +1765,8 @@ pub struct RuntimeProfileRechargeCenterSnapshot { pub wallet_balance: u64, pub membership: RuntimeProfileMembershipSnapshot, pub point_products: Vec, - pub membership_plans: Vec, + pub membership_products: Vec, + pub benefits: Vec, pub latest_order: Option, pub has_points_recharged: bool, pub daily_free_points: RuntimeProfileDailyFreePointsSnapshot, @@ -1759,6 +1807,11 @@ pub struct RuntimeProfileRechargeProductAdminUpsertInput { pub duration_days: u32, pub badge_label: String, pub description: String, + pub tier: RuntimeProfileMembershipTier, + pub membership_period_points: u64, + pub membership_period_days: u32, + pub membership_queue_limit: u32, + pub membership_discount_bps: u32, pub enabled: bool, pub sort_order: i32, pub updated_at_micros: i64, @@ -2575,6 +2628,11 @@ pub struct RuntimeProfileRechargeProductRecord { pub duration_days: u32, pub badge_label: String, pub description: String, + pub tier: RuntimeProfileMembershipTier, + pub membership_period_points: u64, + pub membership_period_days: u32, + pub membership_queue_limit: u32, + pub membership_discount_bps: u32, } #[derive(Clone, Debug, PartialEq)] @@ -2588,6 +2646,11 @@ pub struct RuntimeProfileRechargeProductConfigRecord { pub duration_days: u32, pub badge_label: String, pub description: String, + pub tier: RuntimeProfileMembershipTier, + pub membership_period_points: u64, + pub membership_period_days: u32, + pub membership_queue_limit: u32, + pub membership_discount_bps: u32, pub enabled: bool, pub sort_order: i32, pub created_by: String, @@ -2611,11 +2674,24 @@ pub struct RuntimeProfileWalletConfigRecord { pub daily_free_points_per_day: u64, } +#[derive(Clone, Debug, PartialEq)] +pub struct RuntimeProfileMembershipBenefitRecord { + pub benefit_name: String, + pub normal_value: String, + pub month_value: String, + pub season_value: String, + pub year_value: String, + pub starter_value: String, + pub basic_value: String, + pub pro_value: String, + pub ultimate_value: String, +} + #[derive(Clone, Debug, PartialEq)] pub struct RuntimeProfileMembershipRecord { pub user_id: String, pub status: RuntimeProfileMembershipStatus, - pub plan: RuntimeProfileMembershipPlan, + pub tier: RuntimeProfileMembershipTier, pub started_at: Option, pub started_at_micros: Option, pub expires_at: Option, @@ -2628,9 +2704,7 @@ pub struct RuntimeProfileMembershipRecord { pub cycle_resets_at_micros: Option, pub cycle_granted_points: u64, pub cycle_remaining_points: u64, - pub cycle_index: u32, - pub cycle_count: u32, - pub cycle_kind: RuntimeProfileMembershipCycleKind, + pub cycle_period_days: u32, } #[derive(Clone, Debug, PartialEq)] @@ -2665,7 +2739,8 @@ pub struct RuntimeProfileRechargeCenterRecord { pub wallet_balance: u64, pub membership: RuntimeProfileMembershipRecord, pub point_products: Vec, - pub membership_plans: Vec, + pub membership_products: Vec, + pub benefits: Vec, pub latest_order: Option, pub has_points_recharged: bool, pub daily_free_points: RuntimeProfileDailyFreePointsRecord, diff --git a/server-rs/crates/module-runtime/src/lib.rs b/server-rs/crates/module-runtime/src/lib.rs index ce5c04494..8c0ddb80a 100644 --- a/server-rs/crates/module-runtime/src/lib.rs +++ b/server-rs/crates/module-runtime/src/lib.rs @@ -21,6 +21,8 @@ pub use membership::*; use shared_kernel::format_rfc3339 as format_shared_rfc3339; use time::OffsetDateTime; +pub const PROFILE_MEMBERSHIP_DEFAULT_PERIOD_DAYS: u32 = 30; + pub fn format_utc_micros(micros: i64) -> String { let timestamp = OffsetDateTime::from_unix_timestamp_nanos(i128::from(micros) * 1_000) .unwrap_or(OffsetDateTime::UNIX_EPOCH); @@ -29,12 +31,166 @@ pub fn format_utc_micros(micros: i64) -> String { pub fn runtime_profile_recharge_point_products() -> Vec { vec![ - build_points_recharge_product("points_60", "60泥点", 600, 60), - build_points_recharge_product("points_180", "180泥点", 1800, 180), - build_points_recharge_product("points_300", "300泥点", 3000, 300), - build_points_recharge_product("points_680", "680泥点", 6800, 680), - build_points_recharge_product("points_1280", "1280泥点", 12800, 1280), - build_points_recharge_product("points_3280", "3280泥点", 32800, 3280), + build_points_recharge_product("points_60", "60泥点", 600, 60, 0, "", "60泥点"), + build_points_recharge_product( + "points_180", + "180泥点", + 1800, + 180, + 90, + "首充加赠", + "首充加赠90泥点", + ), + build_points_recharge_product( + "points_300", + "300泥点", + 3000, + 300, + 150, + "首充加赠", + "首充加赠150泥点", + ), + build_points_recharge_product( + "points_680", + "680泥点", + 6800, + 680, + 340, + "首充加赠", + "首充加赠340泥点", + ), + ] +} + +/// 中文注释:保留旧展示 helper 的兼容入口;首充资格已改为按商品档位在配置表侧计算。 +pub fn resolve_runtime_profile_recharge_point_products( + _has_points_recharged: bool, +) -> Vec { + runtime_profile_recharge_point_products() +} + +pub fn runtime_profile_recharge_membership_products() -> Vec +{ + vec![ + build_membership_recharge_product( + "member_starter", + "Starter", + 1990, + 30, + RuntimeProfileMembershipTier::Starter, + "每月200泥点 用于游戏创作", + ), + build_membership_recharge_product( + "member_basic", + "Basic", + 6990, + 30, + RuntimeProfileMembershipTier::Basic, + "每月800泥点 用于游戏创作", + ), + build_membership_recharge_product( + "member_pro", + "Pro", + 19990, + 30, + RuntimeProfileMembershipTier::Pro, + "每月2500泥点 用于游戏创作", + ), + build_membership_recharge_product( + "member_ultimate", + "Ultimate", + 41990, + 30, + RuntimeProfileMembershipTier::Ultimate, + "每月6000泥点 用于游戏创作", + ), + ] +} + +pub fn runtime_profile_membership_tier_rank(tier: RuntimeProfileMembershipTier) -> Option { + match tier { + RuntimeProfileMembershipTier::Normal => None, + RuntimeProfileMembershipTier::Month | RuntimeProfileMembershipTier::Starter => Some(1), + RuntimeProfileMembershipTier::Season | RuntimeProfileMembershipTier::Basic => Some(2), + RuntimeProfileMembershipTier::Year | RuntimeProfileMembershipTier::Pro => Some(3), + RuntimeProfileMembershipTier::Ultimate => Some(4), + } +} + +pub fn runtime_profile_membership_period_points(tier: RuntimeProfileMembershipTier) -> u64 { + match tier { + RuntimeProfileMembershipTier::Starter => 200, + RuntimeProfileMembershipTier::Basic => 800, + RuntimeProfileMembershipTier::Pro => 2500, + RuntimeProfileMembershipTier::Ultimate => 6000, + _ => 0, + } +} + +pub fn runtime_profile_membership_queue_limit(tier: RuntimeProfileMembershipTier) -> u32 { + match tier { + RuntimeProfileMembershipTier::Starter | RuntimeProfileMembershipTier::Basic => 2, + RuntimeProfileMembershipTier::Pro => 5, + RuntimeProfileMembershipTier::Ultimate => 10, + _ => 0, + } +} + +pub fn runtime_profile_membership_discount_bps(tier: RuntimeProfileMembershipTier) -> u32 { + match tier { + RuntimeProfileMembershipTier::Basic => 8500, + RuntimeProfileMembershipTier::Pro => 8000, + RuntimeProfileMembershipTier::Ultimate => 7000, + _ => 0, + } +} + +pub fn runtime_profile_membership_benefits() -> Vec { + vec![ + RuntimeProfileMembershipBenefitSnapshot { + benefit_name: "特权名称".to_string(), + normal_value: "普通".to_string(), + month_value: "月卡".to_string(), + season_value: "季卡".to_string(), + year_value: "年卡".to_string(), + starter_value: "Starter".to_string(), + basic_value: "Basic".to_string(), + pro_value: "Pro".to_string(), + ultimate_value: "Ultimate".to_string(), + }, + RuntimeProfileMembershipBenefitSnapshot { + benefit_name: "每月泥点".to_string(), + normal_value: "0".to_string(), + month_value: "0".to_string(), + season_value: "0".to_string(), + year_value: "0".to_string(), + starter_value: "200".to_string(), + basic_value: "800".to_string(), + pro_value: "2500".to_string(), + ultimate_value: "6000".to_string(), + }, + RuntimeProfileMembershipBenefitSnapshot { + benefit_name: "同时排队".to_string(), + normal_value: "1".to_string(), + month_value: "2".to_string(), + season_value: "2".to_string(), + year_value: "2".to_string(), + starter_value: "2".to_string(), + basic_value: "2".to_string(), + pro_value: "5".to_string(), + ultimate_value: "10".to_string(), + }, + RuntimeProfileMembershipBenefitSnapshot { + benefit_name: "商业所有权".to_string(), + normal_value: "0%".to_string(), + month_value: "有".to_string(), + season_value: "有".to_string(), + year_value: "有".to_string(), + starter_value: "有".to_string(), + basic_value: "有".to_string(), + pro_value: "有".to_string(), + ultimate_value: "有".to_string(), + }, ] } @@ -43,6 +199,7 @@ pub fn runtime_profile_recharge_product_by_id( ) -> Option { runtime_profile_recharge_point_products() .into_iter() + .chain(runtime_profile_recharge_membership_products()) .find(|product| product.product_id == product_id) } @@ -58,6 +215,9 @@ fn build_points_recharge_product( title: &str, price_cents: u64, points_amount: u64, + bonus_points: u64, + badge_label: &str, + description: &str, ) -> RuntimeProfileRechargeProductSnapshot { RuntimeProfileRechargeProductSnapshot { product_id: product_id.to_string(), @@ -65,10 +225,41 @@ fn build_points_recharge_product( price_cents, kind: RuntimeProfileRechargeProductKind::Points, points_amount, - bonus_points: 0, + bonus_points, duration_days: 0, + badge_label: badge_label.to_string(), + description: description.to_string(), + tier: RuntimeProfileMembershipTier::Normal, + membership_period_points: 0, + membership_period_days: 0, + membership_queue_limit: 0, + membership_discount_bps: 0, + } +} + +fn build_membership_recharge_product( + product_id: &str, + title: &str, + price_cents: u64, + duration_days: u32, + tier: RuntimeProfileMembershipTier, + description: &str, +) -> RuntimeProfileRechargeProductSnapshot { + RuntimeProfileRechargeProductSnapshot { + product_id: product_id.to_string(), + title: title.to_string(), + price_cents, + kind: RuntimeProfileRechargeProductKind::Membership, + points_amount: 0, + bonus_points: 0, + duration_days, badge_label: String::new(), - description: title.to_string(), + description: description.to_string(), + tier, + membership_period_points: runtime_profile_membership_period_points(tier), + membership_period_days: PROFILE_MEMBERSHIP_DEFAULT_PERIOD_DAYS, + membership_queue_limit: runtime_profile_membership_queue_limit(tier), + membership_discount_bps: runtime_profile_membership_discount_bps(tier), } } @@ -938,46 +1129,59 @@ mod tests { #[test] fn recharge_product_catalog_matches_reference_prices() { let point_products = runtime_profile_recharge_point_products(); + let membership_products = runtime_profile_recharge_membership_products(); - assert_eq!(point_products.len(), 6); - for (product, product_id, price_cents, points_amount) in [ - (&point_products[0], "points_60", 600, 60), - (&point_products[1], "points_180", 1800, 180), - (&point_products[2], "points_300", 3000, 300), - (&point_products[3], "points_680", 6800, 680), - (&point_products[4], "points_1280", 12800, 1280), - (&point_products[5], "points_3280", 32800, 3280), - ] { - assert_eq!(product.product_id, product_id); - assert_eq!(product.price_cents, price_cents); - assert_eq!(product.points_amount, points_amount); - // 中文注释:新方案取消首充赠送,六档充点一律无赠送、无角标。 - assert_eq!(product.bonus_points, 0); - assert_eq!(product.badge_label, ""); - } - - let plans = runtime_profile_membership_plan_catalog(); - assert_eq!(plans.len(), 5); - assert_eq!(plans[0].plan, RuntimeProfileMembershipPlan::Normal); - assert!(!plans[0].enabled); - assert_eq!(plans[0].period_points, 0); - assert_eq!(plans[0].concurrent_job_limit, 1); - assert_eq!(plans[1].plan, RuntimeProfileMembershipPlan::Starter); - assert_eq!(plans[1].month_price_cents, 3_900); - assert_eq!(plans[1].year_price_cents, 39_000); - assert_eq!(plans[1].period_points, 400); - assert_eq!(plans[2].plan, RuntimeProfileMembershipPlan::Plus); - assert_eq!(plans[2].period_points, 1_150); - assert_eq!(plans[3].plan, RuntimeProfileMembershipPlan::Pro); - assert_eq!(plans[3].period_points, 3_650); - assert_eq!(plans[4].plan, RuntimeProfileMembershipPlan::Max); - assert_eq!(plans[4].month_price_cents, 69_900); - assert_eq!(plans[4].year_price_cents, 699_000); - assert_eq!(plans[4].period_points, 8_650); + assert_eq!(point_products.len(), 4); + assert_eq!(point_products[0].product_id, "points_60"); + assert_eq!(point_products[0].title, "60泥点"); + assert_eq!(point_products[0].price_cents, 600); + assert_eq!(point_products[0].bonus_points, 0); + assert_eq!(point_products[0].badge_label, ""); + assert_eq!(point_products[0].description, "60泥点"); + assert_eq!(point_products[1].product_id, "points_180"); + assert_eq!(point_products[1].bonus_points, 90); + assert_eq!(point_products[2].bonus_points, 150); + assert_eq!(point_products[3].product_id, "points_680"); + assert_eq!(point_products[3].price_cents, 6800); + assert_eq!(point_products[3].bonus_points, 340); + assert_eq!(point_products[3].description, "首充加赠340泥点"); + assert_eq!(membership_products.len(), 4); + assert_eq!(membership_products[0].product_id, "member_starter"); + assert_eq!(membership_products[0].title, "Starter"); + assert_eq!(membership_products[0].price_cents, 1990); + assert_eq!(membership_products[0].membership_period_points, 200); assert_eq!( - plans[4].concurrent_job_limit, - MEMBERSHIP_UNLIMITED_CONCURRENCY + membership_products[0].membership_period_days, + PROFILE_MEMBERSHIP_DEFAULT_PERIOD_DAYS ); + assert_eq!(membership_products[3].product_id, "member_ultimate"); + assert_eq!(membership_products[3].membership_period_points, 6000); + assert_eq!(membership_products[3].membership_queue_limit, 10); + + let benefits = runtime_profile_membership_benefits(); + assert!( + benefits + .iter() + .any(|benefit| benefit.benefit_name == "每月泥点") + ); + } + + #[test] + fn recharge_point_products_do_not_hide_all_first_bonus_by_account_flag() { + let first_recharge_products = resolve_runtime_profile_recharge_point_products(false); + assert_eq!(first_recharge_products[0].bonus_points, 0); + assert_eq!(first_recharge_products[0].badge_label, ""); + assert_eq!(first_recharge_products[0].description, "60泥点"); + assert_eq!(first_recharge_products[1].bonus_points, 90); + assert_eq!(first_recharge_products[1].badge_label, "首充加赠"); + assert_eq!(first_recharge_products[1].description, "首充加赠90泥点"); + + let repeated_recharge_products = resolve_runtime_profile_recharge_point_products(true); + assert_eq!(repeated_recharge_products[0].bonus_points, 0); + assert_eq!(repeated_recharge_products[1].bonus_points, 90); + assert_eq!(repeated_recharge_products[3].bonus_points, 340); + assert_eq!(repeated_recharge_products[3].badge_label, "首充加赠"); + assert_eq!(repeated_recharge_products[3].description, "首充加赠340泥点"); } #[test]