接入会员周期泥点制度

新增 Starter、Basic、Pro、Ultimate 会员商品配置与权益字段。

拆分会员有效期、周期重置时间、周期限时泥点和永久泥点余额。

实现升级补价补点但不延长有效期或移动重置时间,同级购买只延长有效期。

补齐钱包扣费与退款中的会员周期泥点消耗、重置和流水记录。

同步后台商品配置、前端充值展示、共享契约、SpacetimeDB 迁移与生成绑定。
This commit is contained in:
2026-07-09 14:48:26 +08:00
parent 2cf3953bad
commit 5f6f4d0ba6
369 changed files with 4438 additions and 3114 deletions
+17 -1
View File
@@ -199,7 +199,15 @@ export type ProfileRedeemCodeMode = 'public' | 'unique' | 'private';
export type ProfileTaskCycle = 'daily';
export type TrackingScopeKind = 'site' | 'work' | 'module' | 'user';
export type ProfileRechargeProductKind = 'points' | 'membership';
export type ProfileMembershipTier = 'normal' | 'month' | 'season' | 'year';
export type ProfileMembershipTier =
| 'normal'
| 'month'
| 'season'
| 'year'
| 'starter'
| 'basic'
| 'pro'
| 'ultimate';
export interface AdminTrackingEventListQuery {
eventKey?: string;
@@ -578,6 +586,10 @@ export interface AdminUpsertProfileRechargeProductRequest {
badgeLabel?: string | null;
description?: string | null;
tier: ProfileMembershipTier;
membershipPeriodPoints: number;
membershipPeriodDays: number;
membershipQueueLimit: number;
membershipDiscountBps: number;
enabled: boolean;
sortOrder: number;
}
@@ -661,6 +673,10 @@ export interface ProfileRechargeProductConfigAdminResponse {
badgeLabel: string;
description: string;
tier: ProfileMembershipTier;
membershipPeriodPoints: number;
membershipPeriodDays: number;
membershipQueueLimit: number;
membershipDiscountBps: number;
enabled: boolean;
sortOrder: number;
createdBy: string;
@@ -26,6 +26,10 @@ const productKinds: Array<{value: ProfileRechargeProductKind; label: string}> =
];
const membershipTiers: Array<{value: ProfileMembershipTier; label: string}> = [
{value: 'starter', label: 'Starter'},
{value: 'basic', label: 'Basic'},
{value: 'pro', label: 'Pro'},
{value: 'ultimate', label: 'Ultimate'},
{value: 'month', label: '月卡'},
{value: 'season', label: '季卡'},
{value: 'year', label: '年卡'},
@@ -50,6 +54,10 @@ export function AdminRechargeProductPage({
const [badgeLabel, setBadgeLabel] = useState('首充双倍');
const [description, setDescription] = useState('首充送60泥点');
const [tier, setTier] = useState<ProfileMembershipTier>('normal');
const [membershipPeriodPoints, setMembershipPeriodPoints] = useState('0');
const [membershipPeriodDays, setMembershipPeriodDays] = useState('0');
const [membershipQueueLimit, setMembershipQueueLimit] = useState('0');
const [membershipDiscountBps, setMembershipDiscountBps] = useState('0');
const [enabled, setEnabled] = useState(true);
const [sortOrder, setSortOrder] = useState('0');
const [isLoading, setIsLoading] = useState(false);
@@ -110,6 +118,14 @@ export function AdminRechargeProductPage({
badgeLabel: kind === 'points' ? badgeLabel.trim() : '',
description: description.trim(),
tier: kind === 'membership' ? tier : 'normal',
membershipPeriodPoints:
kind === 'membership' ? parsePositiveInteger(membershipPeriodPoints) : 0,
membershipPeriodDays:
kind === 'membership' ? parsePositiveInteger(membershipPeriodDays) : 0,
membershipQueueLimit:
kind === 'membership' ? parseNonNegativeInteger(membershipQueueLimit) : 0,
membershipDiscountBps:
kind === 'membership' ? parseNonNegativeInteger(membershipDiscountBps) : 0,
enabled,
sortOrder: parseInteger(sortOrder),
});
@@ -141,6 +157,10 @@ export function AdminRechargeProductPage({
setBadgeLabel(entry.badgeLabel);
setDescription(entry.description);
setTier(entry.tier);
setMembershipPeriodPoints(String(entry.membershipPeriodPoints));
setMembershipPeriodDays(String(entry.membershipPeriodDays));
setMembershipQueueLimit(String(entry.membershipQueueLimit));
setMembershipDiscountBps(String(entry.membershipDiscountBps));
setEnabled(entry.enabled);
setSortOrder(String(entry.sortOrder));
}
@@ -200,10 +220,18 @@ export function AdminRechargeProductPage({
if (item.value === 'points') {
setTier('normal');
setDurationDays('0');
setMembershipPeriodPoints('0');
setMembershipPeriodDays('0');
setMembershipQueueLimit('0');
setMembershipDiscountBps('0');
} else {
setBonusPoints('0');
setPointsAmount('0');
setTier(tier === 'normal' ? 'month' : tier);
setTier(tier === 'normal' ? 'starter' : tier);
setDurationDays(durationDays === '0' ? '30' : durationDays);
setMembershipPeriodDays(
membershipPeriodDays === '0' ? '30' : membershipPeriodDays,
);
}
}}
>
@@ -256,32 +284,86 @@ export function AdminRechargeProductPage({
</label>
</div>
) : (
<div className="admin-form-row">
<label className="admin-field">
<span></span>
<select
value={tier}
onChange={(event) =>
setTier(event.target.value as ProfileMembershipTier)
}
>
{membershipTiers.map((item) => (
<option key={item.value} value={item.value}>
{item.label}
</option>
))}
</select>
</label>
<label className="admin-field">
<span></span>
<input
min={1}
step={1}
type="number"
value={durationDays}
onChange={(event) => setDurationDays(event.target.value)}
/>
</label>
<div className="admin-stack">
<div className="admin-form-row">
<label className="admin-field">
<span></span>
<select
value={tier}
onChange={(event) =>
setTier(event.target.value as ProfileMembershipTier)
}
>
{membershipTiers.map((item) => (
<option key={item.value} value={item.value}>
{item.label}
</option>
))}
</select>
</label>
<label className="admin-field">
<span></span>
<input
min={1}
step={1}
type="number"
value={durationDays}
onChange={(event) => setDurationDays(event.target.value)}
/>
</label>
</div>
<div className="admin-form-row">
<label className="admin-field">
<span></span>
<input
min={1}
step={1}
type="number"
value={membershipPeriodPoints}
onChange={(event) =>
setMembershipPeriodPoints(event.target.value)
}
/>
</label>
<label className="admin-field">
<span></span>
<input
min={1}
step={1}
type="number"
value={membershipPeriodDays}
onChange={(event) =>
setMembershipPeriodDays(event.target.value)
}
/>
</label>
</div>
<div className="admin-form-row">
<label className="admin-field">
<span></span>
<input
min={0}
step={1}
type="number"
value={membershipQueueLimit}
onChange={(event) =>
setMembershipQueueLimit(event.target.value)
}
/>
</label>
<label className="admin-field">
<span> bps</span>
<input
min={0}
step={1}
type="number"
value={membershipDiscountBps}
onChange={(event) =>
setMembershipDiscountBps(event.target.value)
}
/>
</label>
</div>
</div>
)}
@@ -409,6 +491,18 @@ function formatProductKind(kind: ProfileRechargeProductKind) {
}
function formatTier(tier: ProfileMembershipTier) {
if (tier === 'starter') {
return 'Starter';
}
if (tier === 'basic') {
return 'Basic';
}
if (tier === 'pro') {
return 'Pro';
}
if (tier === 'ultimate') {
return 'Ultimate';
}
if (tier === 'month') {
return '月卡';
}
@@ -425,7 +519,7 @@ function formatProductContent(entry: ProfileRechargeProductConfigAdminResponse)
if (entry.kind === 'points') {
return `${entry.pointsAmount}+${entry.bonusPoints}`;
}
return `${formatTier(entry.tier)} ${entry.durationDays}`;
return `${formatTier(entry.tier)} ${entry.durationDays} · 每${entry.membershipPeriodDays}${entry.membershipPeriodPoints}泥点`;
}
function formatPrice(priceCents: number) {
@@ -16,6 +16,14 @@
---
## 2026-07-09 会员有效期与周期泥点重置分离
- 背景:账户会员制度新增 Starter / Basic / Pro / Ultimate 四档后,会员有效期、周期限时泥点和普通永久泥点容易被混成同一条时间线;升级场景尤其容易误把“补差额”实现成延长会员或重算 reset time。
- 决策:`profile_membership.expires_at` 只表示会员是否生效,`cycle_resets_at/cycle_period_days` 只表示会员周期限时泥点重置时间。同级会员购买只延长 `expires_at`,不发当前周期额外泥点,不移动 reset time;升级只补齐当前周期应发泥点差额并更新档位,不延长 `expires_at`,不移动 reset time。周期刷新由后端在个人中心、充值中心、任务中心、账单读取和钱包扣费入口执行,先清上周期剩余限时泥点,再发当前档位周期额度;资产操作退款按原消费流水恢复同一周期限时泥点,避免把限时泥点退成永久泥点。
- 影响范围:`profile_membership``profile_recharge_product_config``profile_wallet_ledger`、充值中心、后台充值商品配置、个人资金 ViewModel、钱包扣费入口。
- 验证方式:`npm run spacetime:generate``cargo check -p spacetime-client --manifest-path server-rs/Cargo.toml``cargo check -p api-server --manifest-path server-rs/Cargo.toml``cargo test -p api-server --manifest-path server-rs/Cargo.toml wechat_virtual_pay_params``npm run typecheck`、充值弹窗和资金 ViewModel 定向测试。
- 关联文档:`docs/【后端架构】server-rs与SpacetimeDB数据契约-2026-05-15.md`
## 2026-07-02 图片画布生成抠图背景色使用 screenColor 传递
- 背景:画布角色、图标和 UI 素材生成过去固定要求 `#00FF00` 绿幕,后续 BGfilter 服务需要按生成时背景色做去背景,不能继续把背景色写死在 prompt 或后处理里。
@@ -188,15 +188,18 @@ npm run check:server-rs-ddd
## 账户充值数据契约
1. `profile_recharge_product_config` 是泥点和会员商品配置真相源,默认商品只在表为空时由 SpacetimeDB 播种。`module-runtime` 中的默认商品 helper 只作为空库种子和兼容入口,不再作为运行期业务真相。
2. 后台通过 `/admin/api/profile/recharge-products` 读写充值商品配置;字段覆盖 `productId`、标题、商品类型、金额分、基础泥点、首充赠送泥点、会员天数、徽标、说明、会员层级、启用状态和排序。
2. 后台通过 `/admin/api/profile/recharge-products` 读写充值商品配置;字段覆盖 `productId`、标题、商品类型、金额分、基础泥点、首充赠送泥点、会员天数、徽标、说明、会员层级、会员每周期限时泥点、周期天数、队列上限、折扣率、启用状态和排序。
3. 充值中心、下单校验和支付确认入账都读取 `profile_recharge_product_config`。历史订单保留下单时写入的商品标题、金额、渠道、状态和 provider transaction id,不随配置改动回写。
4. 泥点首充资格按 `user_id + product_id` 的历史 `paid` 订单独立判断。某个档位已支付后,只隐藏该档位的首充赠送;其它未购买档位仍展示和结算首充赠送。
5. `hasPointsRecharged` 只保留为账号是否发生过任一泥点充值的兼容字段,不得驱动所有商品展示隐藏或结算金额计算。前端只渲染后端返回的商品快照。
6. `paymentChannel` 缺失、未知或冒用小程序支付设备时必须拒绝;真实微信渠道只允许 `wechat_mp``wechat_mp_virtual``wechat_jsapi``wechat_h5``wechat_native`,生产配置不得把真实支付静默降级为 `mock`
7. access JWT 只携带最小设备快照 `device.client_type``device.client_runtime``device.client_platform`。充值下单按该快照拦截小程序渠道:小程序只允许 `wechat_mp` / `wechat_mp_virtual`;微信内浏览器使用 `wechat_jsapi`;普通 Web 使用 `wechat_native`,历史普通 Web 登录态若缺少设备快照也允许继续进入 JSAPI / H5 / Native 渠道的后续支付配置校验,但不放宽小程序虚拟支付
8. 所有微信真实渠道都以微信支付通知或服务端查单确认 `SUCCESS` 为到账事实;小程序、H5 跳转和 Native 二维码返回都不能直接发放泥点或会员
9. 微信 Native 下单显式传 `time_expire`,当前有效期为 5 分钟,并通过 `wechatNativePayment.expiresAt` 下发给前端二维码弹窗展示
10. 普通微信支付渠道的新建 pending 充值订单会写入 `profile_recharge_order_expiration_schedule`。到期处理由 `api-server` 后台 worker claim 调度行后调用微信查单;只有微信返回 `SUCCESS` 才补确认入账,返回 `NOTPAY` / `CLOSED` / `REVOKED` / `PAYERROR` 才关闭本地订单,查询失败或 `USERPAYING` 保留租约等待重试。SpacetimeDB module 不直接发起微信 HTTP 请求
6. 默认会员商品为空库播种时使用 `Starter / Basic / Pro / Ultimate` 四档,默认有效期均为 30 天,每周期限时泥点分别为 `200 / 800 / 2500 / 6000`,队列上限分别为 `2 / 2 / 5 / 10`
7. 会员有效期和周期重置时间是两条独立时间线。`expires_at` 只决定会员是否生效;`cycle_resets_at` 只决定当前周期限时泥点何时重置。会员升级只更新档位并补齐当前周期限时泥点差额,不延长 `expires_at`,不移动 `cycle_resets_at` 和周期天数。同级会员购买只从当前 `expires_at` 延长有效期,不发放额外当前周期泥点,也不移动重置时间
8. 会员周期刷新发生在个人中心、充值中心、任务中心、账单读取和钱包扣费入口:到达 `cycle_resets_at` 时先清除上周期剩余限时泥点,再发放当前会员档位周期额度;会员过期时清除剩余限时泥点并把状态降为普通。周期发放和重置流水分别使用 `membership_period_grant``membership_period_reset`
9. `paymentChannel` 缺失、未知或冒用小程序支付设备时必须拒绝;真实微信渠道只允许 `wechat_mp``wechat_mp_virtual``wechat_jsapi``wechat_h5``wechat_native`,生产配置不得把真实支付静默降级为 `mock`
10. access JWT 只携带最小设备快照 `device.client_type``device.client_runtime``device.client_platform`。充值下单按该快照拦截小程序渠道:小程序只允许 `wechat_mp` / `wechat_mp_virtual`;微信内浏览器使用 `wechat_jsapi`;普通 Web 使用 `wechat_native`,历史普通 Web 登录态若缺少设备快照也允许继续进入 JSAPI / H5 / Native 渠道的后续支付配置校验,但不放宽小程序虚拟支付
11. 所有微信真实渠道都以微信支付通知或服务端查单确认 `SUCCESS` 为到账事实;小程序、H5 跳转和 Native 二维码返回都不能直接发放泥点或会员。
12. 微信 Native 下单显式传 `time_expire`,当前有效期为 5 分钟,并通过 `wechatNativePayment.expiresAt` 下发给前端二维码弹窗展示。
13. 普通微信支付渠道的新建 pending 充值订单会写入 `profile_recharge_order_expiration_schedule`。到期处理由 `api-server` 后台 worker claim 调度行后调用微信查单;只有微信返回 `SUCCESS` 才补确认入账,返回 `NOTPAY` / `CLOSED` / `REVOKED` / `PAYERROR` 才关闭本地订单,查询失败或 `USERPAYING` 保留租约等待重试。SpacetimeDB module 不直接发起微信 HTTP 请求。
## 创作入口泥点扣费契约
@@ -211,10 +214,12 @@ npm run check:server-rs-ddd
## 用户钱包与编辑器生成扣费契约
1. 新用户账号完成注册并成功同步正式认证表后,注册赠送金额读取 `profile_wallet_config.initial_mud_points`;后台通过 `/admin/api/profile/wallet-config` 维护“账号初始泥点数”。未写入配置时默认仍为 `100` 泥点。流水原因仍使用 `new_user_registration_reward`,流水 ID 继续保持幂等,重复发放请求不得叠加余额。
2. 编辑器画板所有会调用外部生成 provider 的入口都不从前端请求接收 `priceMudPoints`;实际扣费真相以后端运行时模型定价配置为准,前端按钮泥点只作为展示
3. 编辑器图片生成 / 图片修改 / 图标 spritesheet / UI 设计图提取素材 / 视频 / 角色动作 / 音效 / 背景音乐必须在后端计算模型价格后使用 `execute_billable_asset_operation_with_cost` 预扣泥点;预扣失败必须 fail-closed,不得继续提交 VectorEngine、Ark、Suno 或 Vidu 上游任务
4. 音频生成的编辑器链路虽然任务提交和结果发布分离,仍必须把提交时后端计算出的模型价格写入 `AudioAssetBindingTarget.billing_points_cost`,最终发布落资产时按该价格扣费;创作音频目标未提供该字段时才使用旧的创作音频固定成本
5. 编辑器图片生成图片修改图标 spritesheet UI 设计图提取素材的参考图可以提交 Data URL 或已登记的 generated objectKeyobjectKey 必须归属于当前账号的 `editor_project_resource``editor_asset``asset_object`,后端通过归属校验后才签名读取 OSS。图标素材和 UI 素材提取的额外参考图必须真正传入 provider,不得只写入 `generationInputs` 展示快照;图片快速编辑当前不开放额外参考图,只提交原图或红框序号标注图作为 `sourceImageSrc`。UI 素材提取额外参考图上限为 5 张,普通图片生成上限 5 张,图标素材上限 8 张额外参考图
2. 用户钱包余额对外仍暴露为一个总余额,但后端扣费时优先消耗 `profile_membership.cycle_remaining_points` 中的会员周期限时泥点,再消耗普通永久泥点;扣费流水 `metadata_json` 会记录 `membershipPeriodPointsDelta``permanentPointsDelta` 和限时泥点所属 `cycleResetsAtMicros`,退款会按原消费流水优先恢复同一周期的限时泥点,前端不得自行决定扣费桶
3. 每日免费泥点当前由每日任务体系发放,流水来源为 `daily_task_reward`,任务进度和可领取状态按北京时间每日刷新;它不参与会员 `cycle_resets_at`,也不由前端合并进会员周期泥点
4. 编辑器画板所有会调用外部生成 provider 的入口都不从前端请求接收 `priceMudPoints`;实际扣费真相以后端运行时模型定价配置为准,前端按钮泥点只作为展示
5. 编辑器图片生成 / 图片修改 / 图标 spritesheet / UI 设计图提取素材 / 视频 / 角色动作 / 音效 / 背景音乐必须在后端计算模型价格后使用 `execute_billable_asset_operation_with_cost` 预扣泥点;预扣失败必须 fail-closed,不得继续提交 VectorEngine、Ark、Suno 或 Vidu 上游任务
6. 音频生成的编辑器链路虽然任务提交和结果发布分离,仍必须把提交时后端计算出的模型价格写入 `AudioAssetBindingTarget.billing_points_cost`,最终发布落资产时按该价格扣费;创作音频目标未提供该字段时才使用旧的创作音频固定成本。
7. 编辑器图片生成、图片修改、图标 spritesheet 和 UI 设计图提取素材的参考图可以提交 Data URL 或已登记的 generated objectKeyobjectKey 必须归属于当前账号的 `editor_project_resource``editor_asset``asset_object`,后端通过归属校验后才签名读取 OSS。图标素材和 UI 素材提取的额外参考图必须真正传入 provider,不得只写入 `generationInputs` 展示快照;图片快速编辑当前不开放额外参考图,只提交原图或红框序号标注图作为 `sourceImageSrc`。UI 素材提取额外参考图上限为 5 张,普通图片生成上限 5 张,图标素材上限 8 张额外参考图。
## 外部服务与资产
@@ -680,12 +685,14 @@ npm run check:server-rs-ddd
- Rust 结构体:`ProfileMembership`
- 源码:`server-rs/crates/spacetime-module/src/runtime/profile.rs`
- 作用:会员有效期和当前周期限时泥点事实源。`started_at/expires_at` 表示会员有效期,`cycle_started_at/cycle_resets_at/cycle_period_days` 表示当前周期,`cycle_granted_points/cycle_remaining_points` 表示当前周期已发放和剩余限时泥点。
### `profile_recharge_product_config`
- Rust 结构体:`ProfileRechargeProductConfig`
- 源码:`server-rs/crates/spacetime-module/src/runtime/profile.rs`
- 作用:泥点和会员充值商品配置真相源,供充值中心展示、下单校验、支付确认和后台“充值商品”页维护。
- 字段补充:会员商品追加 `membership_period_points``membership_period_days``membership_queue_limit``membership_discount_bps`;泥点商品这些字段必须为 `0`
### `profile_played_world`
+24 -1
View File
@@ -63,6 +63,8 @@ export type ProfileWalletLedgerEntry = {
| 'invite_inviter_reward'
| 'invite_invitee_reward'
| 'points_recharge'
| 'membership_period_grant'
| 'membership_period_reset'
| 'asset_operation_consume'
| 'asset_operation_refund'
| 'redeem_code_reward'
@@ -101,7 +103,15 @@ export type ExternalApiKeyMutationResponse = {
export type ProfileRechargeProductKind = 'points' | 'membership';
export type ProfileMembershipStatus = 'normal' | 'active';
export type ProfileMembershipTier = 'normal' | 'month' | 'season' | 'year';
export type ProfileMembershipTier =
| 'normal'
| 'month'
| 'season'
| 'year'
| 'starter'
| 'basic'
| 'pro'
| 'ultimate';
export type ProfileRechargeOrderStatus =
| 'pending'
| 'paid'
@@ -120,6 +130,10 @@ export type ProfileRechargeProduct = {
badgeLabel: string;
description: string;
tier: ProfileMembershipTier;
membershipPeriodPoints: number;
membershipPeriodDays: number;
membershipQueueLimit: number;
membershipDiscountBps: number;
};
export type ProfileMembershipBenefit = {
@@ -128,6 +142,10 @@ export type ProfileMembershipBenefit = {
monthValue: string;
seasonValue: string;
yearValue: string;
starterValue: string;
basicValue: string;
proValue: string;
ultimateValue: string;
};
export type ProfileMembership = {
@@ -136,6 +154,11 @@ export type ProfileMembership = {
startedAt: string | null;
expiresAt: string | null;
updatedAt: string | null;
cycleStartedAt: string | null;
cycleResetsAt: string | null;
cycleGrantedPoints: number;
cycleRemainingPoints: number;
cyclePeriodDays: number;
};
export type ProfileRechargeOrder = {
@@ -39,15 +39,19 @@ use shared_contracts::runtime::{
AnalyticsBucketMetricResponse, AnalyticsMetricQueryResponse, ClaimProfileTaskRewardResponse,
ConfirmWechatProfileRechargeOrderResponse, CreateProfileRechargeOrderRequest,
CreateProfileRechargeOrderResponse, PROFILE_FEEDBACK_STATUS_OPEN,
PROFILE_MEMBERSHIP_TIER_MONTH, PROFILE_MEMBERSHIP_TIER_NORMAL, PROFILE_MEMBERSHIP_TIER_SEASON,
PROFILE_MEMBERSHIP_TIER_YEAR, PROFILE_RECHARGE_PRODUCT_KIND_MEMBERSHIP,
PROFILE_RECHARGE_PRODUCT_KIND_POINTS, PROFILE_TASK_CYCLE_DAILY, PROFILE_TASK_STATUS_CLAIMABLE,
PROFILE_TASK_STATUS_CLAIMED, PROFILE_TASK_STATUS_DISABLED, PROFILE_TASK_STATUS_INCOMPLETE,
PROFILE_MEMBERSHIP_TIER_BASIC, PROFILE_MEMBERSHIP_TIER_MONTH, PROFILE_MEMBERSHIP_TIER_NORMAL,
PROFILE_MEMBERSHIP_TIER_PRO, PROFILE_MEMBERSHIP_TIER_SEASON, PROFILE_MEMBERSHIP_TIER_STARTER,
PROFILE_MEMBERSHIP_TIER_ULTIMATE, PROFILE_MEMBERSHIP_TIER_YEAR,
PROFILE_RECHARGE_PRODUCT_KIND_MEMBERSHIP, PROFILE_RECHARGE_PRODUCT_KIND_POINTS,
PROFILE_TASK_CYCLE_DAILY, PROFILE_TASK_STATUS_CLAIMABLE, PROFILE_TASK_STATUS_CLAIMED,
PROFILE_TASK_STATUS_DISABLED, PROFILE_TASK_STATUS_INCOMPLETE,
PROFILE_WALLET_LEDGER_SOURCE_TYPE_ASSET_OPERATION_CONSUME,
PROFILE_WALLET_LEDGER_SOURCE_TYPE_ASSET_OPERATION_REFUND,
PROFILE_WALLET_LEDGER_SOURCE_TYPE_DAILY_TASK_REWARD,
PROFILE_WALLET_LEDGER_SOURCE_TYPE_INVITE_INVITEE_REWARD,
PROFILE_WALLET_LEDGER_SOURCE_TYPE_INVITE_INVITER_REWARD,
PROFILE_WALLET_LEDGER_SOURCE_TYPE_MEMBERSHIP_PERIOD_GRANT,
PROFILE_WALLET_LEDGER_SOURCE_TYPE_MEMBERSHIP_PERIOD_RESET,
PROFILE_WALLET_LEDGER_SOURCE_TYPE_NEW_USER_REGISTRATION_REWARD,
PROFILE_WALLET_LEDGER_SOURCE_TYPE_POINTS_RECHARGE,
PROFILE_WALLET_LEDGER_SOURCE_TYPE_PUZZLE_AUTHOR_INCENTIVE_CLAIM,
@@ -166,6 +170,12 @@ fn format_profile_wallet_ledger_source_type(
RuntimeProfileWalletLedgerSourceType::PointsRecharge => {
PROFILE_WALLET_LEDGER_SOURCE_TYPE_POINTS_RECHARGE
}
RuntimeProfileWalletLedgerSourceType::MembershipPeriodGrant => {
PROFILE_WALLET_LEDGER_SOURCE_TYPE_MEMBERSHIP_PERIOD_GRANT
}
RuntimeProfileWalletLedgerSourceType::MembershipPeriodReset => {
PROFILE_WALLET_LEDGER_SOURCE_TYPE_MEMBERSHIP_PERIOD_RESET
}
RuntimeProfileWalletLedgerSourceType::AssetOperationConsume => {
PROFILE_WALLET_LEDGER_SOURCE_TYPE_ASSET_OPERATION_CONSUME
}
@@ -938,6 +948,10 @@ pub async fn admin_upsert_profile_recharge_product(
payload.badge_label.unwrap_or_default(),
payload.description.unwrap_or_default(),
tier,
payload.membership_period_points,
payload.membership_period_days,
payload.membership_queue_limit,
payload.membership_discount_bps,
payload.enabled,
payload.sort_order.unwrap_or(10),
updated_at_micros as i64,
@@ -1596,6 +1610,11 @@ fn build_profile_recharge_center_response(
started_at: record.membership.started_at,
expires_at: record.membership.expires_at,
updated_at: record.membership.updated_at,
cycle_started_at: record.membership.cycle_started_at,
cycle_resets_at: record.membership.cycle_resets_at,
cycle_granted_points: record.membership.cycle_granted_points,
cycle_remaining_points: record.membership.cycle_remaining_points,
cycle_period_days: record.membership.cycle_period_days,
},
point_products: record
.point_products
@@ -1633,6 +1652,10 @@ fn build_profile_recharge_product_response(
badge_label: record.badge_label,
description: record.description,
tier: record.tier.as_str().to_string(),
membership_period_points: record.membership_period_points,
membership_period_days: record.membership_period_days,
membership_queue_limit: record.membership_queue_limit,
membership_discount_bps: record.membership_discount_bps,
}
}
@@ -1645,6 +1668,10 @@ fn build_profile_membership_benefit_response(
month_value: record.month_value,
season_value: record.season_value,
year_value: record.year_value,
starter_value: record.starter_value,
basic_value: record.basic_value,
pro_value: record.pro_value,
ultimate_value: record.ultimate_value,
}
}
@@ -1858,6 +1885,10 @@ fn build_profile_recharge_product_config_admin_response(
badge_label: record.badge_label,
description: record.description,
tier: format_profile_membership_tier(record.tier).to_string(),
membership_period_points: record.membership_period_points,
membership_period_days: record.membership_period_days,
membership_queue_limit: record.membership_queue_limit,
membership_discount_bps: record.membership_discount_bps,
enabled: record.enabled,
sort_order: record.sort_order,
created_by: record.created_by,
@@ -1959,6 +1990,10 @@ fn parse_profile_membership_tier(raw: &str) -> Result<RuntimeProfileMembershipTi
PROFILE_MEMBERSHIP_TIER_MONTH => Ok(RuntimeProfileMembershipTier::Month),
PROFILE_MEMBERSHIP_TIER_SEASON => Ok(RuntimeProfileMembershipTier::Season),
PROFILE_MEMBERSHIP_TIER_YEAR => Ok(RuntimeProfileMembershipTier::Year),
PROFILE_MEMBERSHIP_TIER_STARTER => Ok(RuntimeProfileMembershipTier::Starter),
PROFILE_MEMBERSHIP_TIER_BASIC => Ok(RuntimeProfileMembershipTier::Basic),
PROFILE_MEMBERSHIP_TIER_PRO => Ok(RuntimeProfileMembershipTier::Pro),
PROFILE_MEMBERSHIP_TIER_ULTIMATE => Ok(RuntimeProfileMembershipTier::Ultimate),
_ => Err("会员档位无效".to_string()),
}
}
@@ -2012,6 +2047,10 @@ fn format_profile_membership_tier(tier: RuntimeProfileMembershipTier) -> &'stati
RuntimeProfileMembershipTier::Month => PROFILE_MEMBERSHIP_TIER_MONTH,
RuntimeProfileMembershipTier::Season => PROFILE_MEMBERSHIP_TIER_SEASON,
RuntimeProfileMembershipTier::Year => PROFILE_MEMBERSHIP_TIER_YEAR,
RuntimeProfileMembershipTier::Starter => PROFILE_MEMBERSHIP_TIER_STARTER,
RuntimeProfileMembershipTier::Basic => PROFILE_MEMBERSHIP_TIER_BASIC,
RuntimeProfileMembershipTier::Pro => PROFILE_MEMBERSHIP_TIER_PRO,
RuntimeProfileMembershipTier::Ultimate => PROFILE_MEMBERSHIP_TIER_ULTIMATE,
}
}
@@ -2871,6 +2910,13 @@ mod tests {
expires_at_micros: None,
updated_at: None,
updated_at_micros: None,
cycle_started_at: None,
cycle_started_at_micros: None,
cycle_resets_at: None,
cycle_resets_at_micros: None,
cycle_granted_points: 0,
cycle_remaining_points: 0,
cycle_period_days: 30,
},
point_products: vec![],
membership_products: vec![RuntimeProfileRechargeProductRecord {
@@ -2884,6 +2930,10 @@ mod tests {
badge_label: String::new(),
description: "30天会员".to_string(),
tier: RuntimeProfileMembershipTier::Month,
membership_period_points: 0,
membership_period_days: 30,
membership_queue_limit: 0,
membership_discount_bps: 0,
}],
benefits: vec![],
latest_order: None,
@@ -2969,6 +3019,13 @@ mod tests {
expires_at_micros: None,
updated_at: None,
updated_at_micros: None,
cycle_started_at: None,
cycle_started_at_micros: None,
cycle_resets_at: None,
cycle_resets_at_micros: None,
cycle_granted_points: 0,
cycle_remaining_points: 0,
cycle_period_days: 30,
},
point_products: vec![RuntimeProfileRechargeProductRecord {
product_id: "points_60".to_string(),
@@ -2981,6 +3038,10 @@ mod tests {
badge_label: "首充双倍".to_string(),
description: "60+60泥点".to_string(),
tier: RuntimeProfileMembershipTier::Normal,
membership_period_points: 0,
membership_period_days: 0,
membership_queue_limit: 0,
membership_discount_bps: 0,
}],
membership_products: vec![],
benefits: vec![],
@@ -3065,6 +3126,13 @@ mod tests {
expires_at_micros: None,
updated_at: None,
updated_at_micros: None,
cycle_started_at: None,
cycle_started_at_micros: None,
cycle_resets_at: None,
cycle_resets_at_micros: None,
cycle_granted_points: 0,
cycle_remaining_points: 0,
cycle_period_days: 30,
},
point_products: vec![],
membership_products: vec![RuntimeProfileRechargeProductRecord {
@@ -3078,6 +3146,10 @@ mod tests {
badge_label: String::new(),
description: "30天会员".to_string(),
tier: RuntimeProfileMembershipTier::Month,
membership_period_points: 0,
membership_period_days: 30,
membership_queue_limit: 0,
membership_discount_bps: 0,
}],
benefits: vec![],
latest_order: None,
@@ -3174,6 +3246,13 @@ mod tests {
expires_at_micros: None,
updated_at: None,
updated_at_micros: None,
cycle_started_at: None,
cycle_started_at_micros: None,
cycle_resets_at: None,
cycle_resets_at_micros: None,
cycle_granted_points: 0,
cycle_remaining_points: 0,
cycle_period_days: 30,
},
point_products: vec![RuntimeProfileRechargeProductRecord {
product_id: "points_60".to_string(),
@@ -3186,6 +3265,10 @@ mod tests {
badge_label: "首充双倍".to_string(),
description: "60+60泥点".to_string(),
tier: RuntimeProfileMembershipTier::Normal,
membership_period_points: 0,
membership_period_days: 0,
membership_queue_limit: 0,
membership_discount_bps: 0,
}],
membership_products: vec![],
benefits: vec![],
@@ -1064,6 +1064,10 @@ pub fn build_runtime_profile_recharge_product_record(
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,
}
}
@@ -1081,6 +1085,10 @@ pub fn build_runtime_profile_recharge_product_config_record(
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,
@@ -1101,6 +1109,10 @@ pub fn build_runtime_profile_membership_benefit_record(
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,
}
}
@@ -1117,6 +1129,13 @@ pub fn build_runtime_profile_membership_record(
expires_at_micros: snapshot.expires_at_micros,
updated_at: snapshot.updated_at_micros.map(format_utc_micros),
updated_at_micros: snapshot.updated_at_micros,
cycle_started_at: snapshot.cycle_started_at_micros.map(format_utc_micros),
cycle_started_at_micros: snapshot.cycle_started_at_micros,
cycle_resets_at: snapshot.cycle_resets_at_micros.map(format_utc_micros),
cycle_resets_at_micros: snapshot.cycle_resets_at_micros,
cycle_granted_points: snapshot.cycle_granted_points,
cycle_remaining_points: snapshot.cycle_remaining_points,
cycle_period_days: snapshot.cycle_period_days,
}
}
@@ -331,6 +331,10 @@ pub fn build_runtime_profile_recharge_product_admin_upsert_input(
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,
@@ -348,7 +352,13 @@ pub fn build_runtime_profile_recharge_product_admin_upsert_input(
if points_amount == 0 {
return Err(RuntimeProfileFieldError::InvalidRechargeProductPoints);
}
if duration_days != 0 || tier != RuntimeProfileMembershipTier::Normal {
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);
}
}
@@ -359,6 +369,8 @@ pub fn build_runtime_profile_recharge_product_admin_upsert_input(
if points_amount != 0
|| bonus_points != 0
|| tier == RuntimeProfileMembershipTier::Normal
|| membership_period_points == 0
|| membership_period_days == 0
{
return Err(RuntimeProfileFieldError::InvalidRechargeProductTier);
}
@@ -377,6 +389,10 @@ pub fn build_runtime_profile_recharge_product_admin_upsert_input(
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,
@@ -1070,6 +1070,8 @@ pub enum RuntimeProfileWalletLedgerSourceType {
InviteInviterReward,
InviteInviteeReward,
PointsRecharge,
MembershipPeriodGrant,
MembershipPeriodReset,
AssetOperationConsume,
AssetOperationRefund,
RedeemCodeReward,
@@ -1085,6 +1087,8 @@ impl RuntimeProfileWalletLedgerSourceType {
Self::InviteInviterReward => "invite_inviter_reward",
Self::InviteInviteeReward => "invite_invitee_reward",
Self::PointsRecharge => "points_recharge",
Self::MembershipPeriodGrant => "membership_period_grant",
Self::MembershipPeriodReset => "membership_period_reset",
Self::AssetOperationConsume => "asset_operation_consume",
Self::AssetOperationRefund => "asset_operation_refund",
Self::RedeemCodeReward => "redeem_code_reward",
@@ -1151,6 +1155,10 @@ pub enum RuntimeProfileMembershipTier {
Month,
Season,
Year,
Starter,
Basic,
Pro,
Ultimate,
}
impl RuntimeProfileMembershipTier {
@@ -1160,6 +1168,10 @@ impl RuntimeProfileMembershipTier {
Self::Month => "month",
Self::Season => "season",
Self::Year => "year",
Self::Starter => "starter",
Self::Basic => "basic",
Self::Pro => "pro",
Self::Ultimate => "ultimate",
}
}
}
@@ -1199,6 +1211,10 @@ pub struct RuntimeProfileRechargeProductSnapshot {
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))]
@@ -1214,6 +1230,10 @@ pub struct RuntimeProfileRechargeProductConfigSnapshot {
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,
@@ -1230,6 +1250,10 @@ pub struct RuntimeProfileMembershipBenefitSnapshot {
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))]
@@ -1241,6 +1265,11 @@ pub struct RuntimeProfileMembershipSnapshot {
pub started_at_micros: Option<i64>,
pub expires_at_micros: Option<i64>,
pub updated_at_micros: Option<i64>,
pub cycle_started_at_micros: Option<i64>,
pub cycle_resets_at_micros: Option<i64>,
pub cycle_granted_points: u64,
pub cycle_remaining_points: u64,
pub cycle_period_days: u32,
}
#[cfg_attr(feature = "spacetime-types", derive(SpacetimeType))]
@@ -1310,6 +1339,10 @@ pub struct RuntimeProfileRechargeProductAdminUpsertInput {
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,
@@ -1803,6 +1836,10 @@ pub struct RuntimeProfileRechargeProductRecord {
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)]
@@ -1817,6 +1854,10 @@ pub struct RuntimeProfileRechargeProductConfigRecord {
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,
@@ -1846,6 +1887,10 @@ pub struct RuntimeProfileMembershipBenefitRecord {
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)]
@@ -1859,6 +1904,13 @@ pub struct RuntimeProfileMembershipRecord {
pub expires_at_micros: Option<i64>,
pub updated_at: Option<String>,
pub updated_at_micros: Option<i64>,
pub cycle_started_at: Option<String>,
pub cycle_started_at_micros: Option<i64>,
pub cycle_resets_at: Option<String>,
pub cycle_resets_at_micros: Option<i64>,
pub cycle_granted_points: u64,
pub cycle_remaining_points: u64,
pub cycle_period_days: u32,
}
#[derive(Clone, Debug, PartialEq)]
+126 -34
View File
@@ -12,6 +12,8 @@ pub use errors::*;
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);
@@ -88,29 +90,78 @@ pub fn runtime_profile_recharge_membership_products() -> Vec<RuntimeProfileRecha
{
vec![
build_membership_recharge_product(
"member_month",
"月卡",
2800,
"member_starter",
"Starter",
1990,
30,
RuntimeProfileMembershipTier::Month,
RuntimeProfileMembershipTier::Starter,
"每月200泥点 用于游戏创作",
),
build_membership_recharge_product(
"member_season",
"季卡",
7800,
90,
RuntimeProfileMembershipTier::Season,
"member_basic",
"Basic",
6990,
30,
RuntimeProfileMembershipTier::Basic,
"每月800泥点 用于游戏创作",
),
build_membership_recharge_product(
"member_year",
"年卡",
24800,
365,
RuntimeProfileMembershipTier::Year,
"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<u8> {
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<RuntimeProfileMembershipBenefitSnapshot> {
vec![
RuntimeProfileMembershipBenefitSnapshot {
@@ -119,27 +170,43 @@ pub fn runtime_profile_membership_benefits() -> Vec<RuntimeProfileMembershipBene
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: "免费".to_string(),
month_value: "¥28".to_string(),
season_value: "¥78".to_string(),
year_value: "¥248".to_string(),
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: "30".to_string(),
month_value: "100".to_string(),
season_value: "100".to_string(),
year_value: "100".to_string(),
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(),
benefit_name: "商业所有权".to_string(),
normal_value: "0%".to_string(),
month_value: "0%".to_string(),
season_value: "+100%".to_string(),
year_value: "+210%".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(),
},
]
}
@@ -180,6 +247,10 @@ fn build_points_recharge_product(
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,
}
}
@@ -189,6 +260,7 @@ fn build_membership_recharge_product(
price_cents: u64,
duration_days: u32,
tier: RuntimeProfileMembershipTier,
description: &str,
) -> RuntimeProfileRechargeProductSnapshot {
RuntimeProfileRechargeProductSnapshot {
product_id: product_id.to_string(),
@@ -199,8 +271,12 @@ fn build_membership_recharge_product(
bonus_points: 0,
duration_days,
badge_label: String::new(),
description: format!("{}天会员", duration_days),
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),
}
}
@@ -821,6 +897,14 @@ mod tests {
RuntimeProfileWalletLedgerSourceType::PointsRecharge.as_str(),
"points_recharge"
);
assert_eq!(
RuntimeProfileWalletLedgerSourceType::MembershipPeriodGrant.as_str(),
"membership_period_grant"
);
assert_eq!(
RuntimeProfileWalletLedgerSourceType::MembershipPeriodReset.as_str(),
"membership_period_reset"
);
assert_eq!(
RuntimeProfileWalletLedgerSourceType::AssetOperationConsume.as_str(),
"asset_operation_consume"
@@ -1031,16 +1115,24 @@ mod tests {
assert_eq!(point_products[5].price_cents, 32800);
assert_eq!(point_products[5].bonus_points, 3280);
assert_eq!(point_products[5].description, "首充送3280泥点");
assert_eq!(membership_products.len(), 3);
assert_eq!(membership_products[0].title, "月卡");
assert_eq!(membership_products[0].price_cents, 2800);
assert_eq!(membership_products[2].duration_days, 365);
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!(
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 == "免泥点回合数")
.any(|benefit| benefit.benefit_name == "每月泥点")
);
}
@@ -7,6 +7,10 @@ pub const PROFILE_WALLET_LEDGER_SOURCE_TYPE_SNAPSHOT_SYNC: &str = "snapshot_sync
pub const PROFILE_WALLET_LEDGER_SOURCE_TYPE_NEW_USER_REGISTRATION_REWARD: &str =
"new_user_registration_reward";
pub const PROFILE_WALLET_LEDGER_SOURCE_TYPE_POINTS_RECHARGE: &str = "points_recharge";
pub const PROFILE_WALLET_LEDGER_SOURCE_TYPE_MEMBERSHIP_PERIOD_GRANT: &str =
"membership_period_grant";
pub const PROFILE_WALLET_LEDGER_SOURCE_TYPE_MEMBERSHIP_PERIOD_RESET: &str =
"membership_period_reset";
pub const PROFILE_WALLET_LEDGER_SOURCE_TYPE_INVITE_INVITER_REWARD: &str = "invite_inviter_reward";
pub const PROFILE_WALLET_LEDGER_SOURCE_TYPE_INVITE_INVITEE_REWARD: &str = "invite_invitee_reward";
pub const PROFILE_WALLET_LEDGER_SOURCE_TYPE_ASSET_OPERATION_CONSUME: &str =
@@ -27,6 +31,10 @@ pub const PROFILE_MEMBERSHIP_TIER_NORMAL: &str = "normal";
pub const PROFILE_MEMBERSHIP_TIER_MONTH: &str = "month";
pub const PROFILE_MEMBERSHIP_TIER_SEASON: &str = "season";
pub const PROFILE_MEMBERSHIP_TIER_YEAR: &str = "year";
pub const PROFILE_MEMBERSHIP_TIER_STARTER: &str = "starter";
pub const PROFILE_MEMBERSHIP_TIER_BASIC: &str = "basic";
pub const PROFILE_MEMBERSHIP_TIER_PRO: &str = "pro";
pub const PROFILE_MEMBERSHIP_TIER_ULTIMATE: &str = "ultimate";
pub const PROFILE_FEEDBACK_STATUS_OPEN: &str = "open";
pub const TRACKING_SCOPE_KIND_SITE: &str = "site";
pub const TRACKING_SCOPE_KIND_WORK: &str = "work";
@@ -196,6 +204,10 @@ pub struct ProfileRechargeProductResponse {
pub badge_label: String,
pub description: String,
pub tier: String,
pub membership_period_points: u64,
pub membership_period_days: u32,
pub membership_queue_limit: u32,
pub membership_discount_bps: u32,
}
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
@@ -206,6 +218,10 @@ pub struct ProfileMembershipBenefitResponse {
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, Serialize, Deserialize, PartialEq)]
@@ -216,6 +232,11 @@ pub struct ProfileMembershipResponse {
pub started_at: Option<String>,
pub expires_at: Option<String>,
pub updated_at: Option<String>,
pub cycle_started_at: Option<String>,
pub cycle_resets_at: Option<String>,
pub cycle_granted_points: u64,
pub cycle_remaining_points: u64,
pub cycle_period_days: u32,
}
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
@@ -503,6 +524,10 @@ pub struct ProfileRechargeProductConfigAdminResponse {
pub badge_label: String,
pub description: String,
pub tier: String,
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,
@@ -585,6 +610,14 @@ pub struct AdminUpsertProfileRechargeProductRequest {
#[serde(default)]
pub description: Option<String>,
pub tier: String,
#[serde(default)]
pub membership_period_points: u64,
#[serde(default)]
pub membership_period_days: u32,
#[serde(default)]
pub membership_queue_limit: u32,
#[serde(default)]
pub membership_discount_bps: u32,
#[serde(default = "default_true")]
pub enabled: bool,
#[serde(default)]
@@ -1413,6 +1446,11 @@ mod tests {
started_at: Some("2026-04-25T10:00:00Z".to_string()),
expires_at: Some("2026-05-25T10:00:00Z".to_string()),
updated_at: Some("2026-04-25T10:00:00Z".to_string()),
cycle_started_at: Some("2026-04-25T10:00:00Z".to_string()),
cycle_resets_at: Some("2026-05-25T10:00:00Z".to_string()),
cycle_granted_points: 800,
cycle_remaining_points: 320,
cycle_period_days: 30,
},
point_products: vec![ProfileRechargeProductResponse {
product_id: "points_60".to_string(),
@@ -1425,6 +1463,10 @@ mod tests {
badge_label: "首充双倍".to_string(),
description: "首充送60泥点".to_string(),
tier: "normal".to_string(),
membership_period_points: 0,
membership_period_days: 0,
membership_queue_limit: 0,
membership_discount_bps: 0,
}],
membership_products: vec![],
benefits: vec![],
@@ -1438,6 +1480,7 @@ mod tests {
payload["membership"]["expiresAt"],
json!("2026-05-25T10:00:00Z")
);
assert_eq!(payload["membership"]["cycleRemainingPoints"], json!(320));
assert_eq!(payload["pointProducts"][0]["productId"], json!("points_60"));
assert_eq!(payload["pointProducts"][0]["title"], json!("60泥点"));
assert_eq!(payload["pointProducts"][0]["priceCents"], json!(600));
@@ -1483,6 +1526,11 @@ mod tests {
started_at: None,
expires_at: None,
updated_at: None,
cycle_started_at: None,
cycle_resets_at: None,
cycle_granted_points: 0,
cycle_remaining_points: 0,
cycle_period_days: 30,
},
point_products: vec![],
membership_products: vec![],
@@ -1542,6 +1590,11 @@ mod tests {
started_at: None,
expires_at: None,
updated_at: None,
cycle_started_at: None,
cycle_resets_at: None,
cycle_granted_points: 0,
cycle_remaining_points: 0,
cycle_period_days: 30,
},
point_products: vec![],
membership_products: vec![],
@@ -278,8 +278,8 @@ pub(crate) use self::runtime::{
build_creation_entry_config_record_from_rows, map_admin_work_visibility_list_procedure_result,
map_admin_work_visibility_procedure_result, map_creation_entry_config_procedure_result,
map_feature_gate_config_procedure_result, map_runtime_setting_procedure_result,
map_runtime_snapshot_delete_procedure_result,
map_runtime_snapshot_procedure_result, map_runtime_snapshot_required_procedure_result,
map_runtime_snapshot_delete_procedure_result, map_runtime_snapshot_procedure_result,
map_runtime_snapshot_required_procedure_result,
map_runtime_tracking_event_batch_procedure_result, map_runtime_tracking_event_procedure_result,
map_runtime_tracking_scope_kind, map_runtime_tracking_scope_kind_back, parse_json_array,
parse_json_string_array, parse_json_value, parse_supported_actions_json,
@@ -588,6 +588,12 @@ pub(crate) fn map_runtime_profile_wallet_ledger_source_type_back(
crate::module_bindings::RuntimeProfileWalletLedgerSourceType::PointsRecharge => {
module_runtime::RuntimeProfileWalletLedgerSourceType::PointsRecharge
}
crate::module_bindings::RuntimeProfileWalletLedgerSourceType::MembershipPeriodGrant => {
module_runtime::RuntimeProfileWalletLedgerSourceType::MembershipPeriodGrant
}
crate::module_bindings::RuntimeProfileWalletLedgerSourceType::MembershipPeriodReset => {
module_runtime::RuntimeProfileWalletLedgerSourceType::MembershipPeriodReset
}
crate::module_bindings::RuntimeProfileWalletLedgerSourceType::AssetOperationConsume => {
module_runtime::RuntimeProfileWalletLedgerSourceType::AssetOperationConsume
}
@@ -270,6 +270,10 @@ impl From<module_runtime::RuntimeProfileRechargeProductAdminUpsertInput>
badge_label: input.badge_label,
description: input.description,
tier: map_runtime_profile_membership_tier(input.tier),
membership_period_points: input.membership_period_points,
membership_period_days: input.membership_period_days,
membership_queue_limit: input.membership_queue_limit,
membership_discount_bps: input.membership_discount_bps,
enabled: input.enabled,
sort_order: input.sort_order,
updated_at_micros: input.updated_at_micros,
@@ -957,6 +961,10 @@ pub(crate) fn map_runtime_profile_recharge_product_snapshot(
badge_label: snapshot.badge_label,
description: snapshot.description,
tier: map_runtime_profile_membership_tier_back(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,
}
}
@@ -974,6 +982,10 @@ pub(crate) fn map_runtime_profile_recharge_product_config_snapshot(
badge_label: snapshot.badge_label,
description: snapshot.description,
tier: map_runtime_profile_membership_tier_back(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,
@@ -992,6 +1004,10 @@ pub(crate) fn map_runtime_profile_membership_benefit_snapshot(
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,
}
}
@@ -1005,6 +1021,11 @@ pub(crate) fn map_runtime_profile_membership_snapshot(
started_at_micros: snapshot.started_at_micros,
expires_at_micros: snapshot.expires_at_micros,
updated_at_micros: snapshot.updated_at_micros,
cycle_started_at_micros: snapshot.cycle_started_at_micros,
cycle_resets_at_micros: snapshot.cycle_resets_at_micros,
cycle_granted_points: snapshot.cycle_granted_points,
cycle_remaining_points: snapshot.cycle_remaining_points,
cycle_period_days: snapshot.cycle_period_days,
}
}
@@ -1380,6 +1401,18 @@ pub(crate) fn map_runtime_profile_membership_tier(
module_runtime::RuntimeProfileMembershipTier::Year => {
crate::module_bindings::RuntimeProfileMembershipTier::Year
}
module_runtime::RuntimeProfileMembershipTier::Starter => {
crate::module_bindings::RuntimeProfileMembershipTier::Starter
}
module_runtime::RuntimeProfileMembershipTier::Basic => {
crate::module_bindings::RuntimeProfileMembershipTier::Basic
}
module_runtime::RuntimeProfileMembershipTier::Pro => {
crate::module_bindings::RuntimeProfileMembershipTier::Pro
}
module_runtime::RuntimeProfileMembershipTier::Ultimate => {
crate::module_bindings::RuntimeProfileMembershipTier::Ultimate
}
}
}
@@ -1412,6 +1445,18 @@ pub(crate) fn map_runtime_profile_membership_tier_back(
crate::module_bindings::RuntimeProfileMembershipTier::Year => {
module_runtime::RuntimeProfileMembershipTier::Year
}
crate::module_bindings::RuntimeProfileMembershipTier::Starter => {
module_runtime::RuntimeProfileMembershipTier::Starter
}
crate::module_bindings::RuntimeProfileMembershipTier::Basic => {
module_runtime::RuntimeProfileMembershipTier::Basic
}
crate::module_bindings::RuntimeProfileMembershipTier::Pro => {
module_runtime::RuntimeProfileMembershipTier::Pro
}
crate::module_bindings::RuntimeProfileMembershipTier::Ultimate => {
module_runtime::RuntimeProfileMembershipTier::Ultimate
}
}
}
@@ -6014,19 +6014,19 @@ impl __sdk::SubscriptionHandle for SubscriptionHandle {
/// either a [`DbConnection`] or an [`EventContext`] and operate on either.
pub trait RemoteDbContext:
__sdk::DbContext<
DbView = RemoteTables,
Reducers = RemoteReducers,
SubscriptionBuilder = __sdk::SubscriptionBuilder<RemoteModule>,
>
DbView = RemoteTables,
Reducers = RemoteReducers,
SubscriptionBuilder = __sdk::SubscriptionBuilder<RemoteModule>,
>
{
}
impl<
Ctx: __sdk::DbContext<
Ctx: __sdk::DbContext<
DbView = RemoteTables,
Reducers = RemoteReducers,
SubscriptionBuilder = __sdk::SubscriptionBuilder<RemoteModule>,
>,
> RemoteDbContext for Ctx
> RemoteDbContext for Ctx
{
}
@@ -47,11 +47,9 @@ pub trait accept_quest {
&self,
input: QuestRecordInput,
callback: impl FnOnce(
&super::ReducerEventContext,
Result<Result<(), String>, __sdk::InternalError>,
) + Send
+ 'static,
callback: impl FnOnce(&super::ReducerEventContext, Result<Result<(), String>, __sdk::InternalError>)
+ Send
+ 'static,
) -> __sdk::Result<()>;
}
@@ -60,11 +58,9 @@ impl accept_quest for super::RemoteReducers {
&self,
input: QuestRecordInput,
callback: impl FnOnce(
&super::ReducerEventContext,
Result<Result<(), String>, __sdk::InternalError>,
) + Send
+ 'static,
callback: impl FnOnce(&super::ReducerEventContext, Result<Result<(), String>, __sdk::InternalError>)
+ Send
+ 'static,
) -> __sdk::Result<()> {
self.imp
.invoke_reducer_with_callback(AcceptQuestArgs { input }, callback)
@@ -34,10 +34,10 @@ pub trait acknowledge_external_generation_jobs_and_return {
input: ExternalGenerationJobAcknowledgeInput,
__callback: impl FnOnce(
&super::ProcedureEventContext,
Result<ExternalGenerationJobProcedureResult, __sdk::InternalError>,
) + Send
+ 'static,
&super::ProcedureEventContext,
Result<ExternalGenerationJobProcedureResult, __sdk::InternalError>,
) + Send
+ 'static,
);
}
@@ -47,10 +47,10 @@ impl acknowledge_external_generation_jobs_and_return for super::RemoteProcedures
input: ExternalGenerationJobAcknowledgeInput,
__callback: impl FnOnce(
&super::ProcedureEventContext,
Result<ExternalGenerationJobProcedureResult, __sdk::InternalError>,
) + Send
+ 'static,
&super::ProcedureEventContext,
Result<ExternalGenerationJobProcedureResult, __sdk::InternalError>,
) + Send
+ 'static,
) {
self.imp
.invoke_procedure_with_callback::<_, ExternalGenerationJobProcedureResult>(
@@ -47,11 +47,9 @@ pub trait acknowledge_quest_completion {
&self,
input: QuestCompletionAckInput,
callback: impl FnOnce(
&super::ReducerEventContext,
Result<Result<(), String>, __sdk::InternalError>,
) + Send
+ 'static,
callback: impl FnOnce(&super::ReducerEventContext, Result<Result<(), String>, __sdk::InternalError>)
+ Send
+ 'static,
) -> __sdk::Result<()>;
}
@@ -60,11 +58,9 @@ impl acknowledge_quest_completion for super::RemoteReducers {
&self,
input: QuestCompletionAckInput,
callback: impl FnOnce(
&super::ReducerEventContext,
Result<Result<(), String>, __sdk::InternalError>,
) + Send
+ 'static,
callback: impl FnOnce(&super::ReducerEventContext, Result<Result<(), String>, __sdk::InternalError>)
+ Send
+ 'static,
) -> __sdk::Result<()> {
self.imp
.invoke_reducer_with_callback(AcknowledgeQuestCompletionArgs { input }, callback)
@@ -31,10 +31,10 @@ pub trait admin_disable_profile_redeem_code {
input: RuntimeProfileRedeemCodeAdminDisableInput,
__callback: impl FnOnce(
&super::ProcedureEventContext,
Result<RuntimeProfileRedeemCodeAdminProcedureResult, __sdk::InternalError>,
) + Send
+ 'static,
&super::ProcedureEventContext,
Result<RuntimeProfileRedeemCodeAdminProcedureResult, __sdk::InternalError>,
) + Send
+ 'static,
);
}
@@ -44,10 +44,10 @@ impl admin_disable_profile_redeem_code for super::RemoteProcedures {
input: RuntimeProfileRedeemCodeAdminDisableInput,
__callback: impl FnOnce(
&super::ProcedureEventContext,
Result<RuntimeProfileRedeemCodeAdminProcedureResult, __sdk::InternalError>,
) + Send
+ 'static,
&super::ProcedureEventContext,
Result<RuntimeProfileRedeemCodeAdminProcedureResult, __sdk::InternalError>,
) + Send
+ 'static,
) {
self.imp
.invoke_procedure_with_callback::<_, RuntimeProfileRedeemCodeAdminProcedureResult>(
@@ -31,10 +31,10 @@ pub trait admin_disable_profile_task_config {
input: RuntimeProfileTaskConfigAdminDisableInput,
__callback: impl FnOnce(
&super::ProcedureEventContext,
Result<RuntimeProfileTaskConfigAdminProcedureResult, __sdk::InternalError>,
) + Send
+ 'static,
&super::ProcedureEventContext,
Result<RuntimeProfileTaskConfigAdminProcedureResult, __sdk::InternalError>,
) + Send
+ 'static,
);
}
@@ -44,10 +44,10 @@ impl admin_disable_profile_task_config for super::RemoteProcedures {
input: RuntimeProfileTaskConfigAdminDisableInput,
__callback: impl FnOnce(
&super::ProcedureEventContext,
Result<RuntimeProfileTaskConfigAdminProcedureResult, __sdk::InternalError>,
) + Send
+ 'static,
&super::ProcedureEventContext,
Result<RuntimeProfileTaskConfigAdminProcedureResult, __sdk::InternalError>,
) + Send
+ 'static,
) {
self.imp
.invoke_procedure_with_callback::<_, RuntimeProfileTaskConfigAdminProcedureResult>(
@@ -31,10 +31,10 @@ pub trait admin_get_profile_wallet_config {
input: RuntimeProfileWalletConfigAdminGetInput,
__callback: impl FnOnce(
&super::ProcedureEventContext,
Result<RuntimeProfileWalletConfigAdminProcedureResult, __sdk::InternalError>,
) + Send
+ 'static,
&super::ProcedureEventContext,
Result<RuntimeProfileWalletConfigAdminProcedureResult, __sdk::InternalError>,
) + Send
+ 'static,
);
}
@@ -44,10 +44,10 @@ impl admin_get_profile_wallet_config for super::RemoteProcedures {
input: RuntimeProfileWalletConfigAdminGetInput,
__callback: impl FnOnce(
&super::ProcedureEventContext,
Result<RuntimeProfileWalletConfigAdminProcedureResult, __sdk::InternalError>,
) + Send
+ 'static,
&super::ProcedureEventContext,
Result<RuntimeProfileWalletConfigAdminProcedureResult, __sdk::InternalError>,
) + Send
+ 'static,
) {
self.imp
.invoke_procedure_with_callback::<_, RuntimeProfileWalletConfigAdminProcedureResult>(
@@ -31,10 +31,10 @@ pub trait admin_list_editor_assets_and_return {
input: AdminEditorAssetListInput,
__callback: impl FnOnce(
&super::ProcedureEventContext,
Result<AdminEditorAssetListProcedureResult, __sdk::InternalError>,
) + Send
+ 'static,
&super::ProcedureEventContext,
Result<AdminEditorAssetListProcedureResult, __sdk::InternalError>,
) + Send
+ 'static,
);
}
@@ -44,10 +44,10 @@ impl admin_list_editor_assets_and_return for super::RemoteProcedures {
input: AdminEditorAssetListInput,
__callback: impl FnOnce(
&super::ProcedureEventContext,
Result<AdminEditorAssetListProcedureResult, __sdk::InternalError>,
) + Send
+ 'static,
&super::ProcedureEventContext,
Result<AdminEditorAssetListProcedureResult, __sdk::InternalError>,
) + Send
+ 'static,
) {
self.imp
.invoke_procedure_with_callback::<_, AdminEditorAssetListProcedureResult>(
@@ -34,10 +34,10 @@ pub trait admin_list_editor_showcase_assets_and_return {
input: EditorShowcaseAssetAdminListInput,
__callback: impl FnOnce(
&super::ProcedureEventContext,
Result<EditorShowcaseAssetListProcedureResult, __sdk::InternalError>,
) + Send
+ 'static,
&super::ProcedureEventContext,
Result<EditorShowcaseAssetListProcedureResult, __sdk::InternalError>,
) + Send
+ 'static,
);
}
@@ -47,10 +47,10 @@ impl admin_list_editor_showcase_assets_and_return for super::RemoteProcedures {
input: EditorShowcaseAssetAdminListInput,
__callback: impl FnOnce(
&super::ProcedureEventContext,
Result<EditorShowcaseAssetListProcedureResult, __sdk::InternalError>,
) + Send
+ 'static,
&super::ProcedureEventContext,
Result<EditorShowcaseAssetListProcedureResult, __sdk::InternalError>,
) + Send
+ 'static,
) {
self.imp
.invoke_procedure_with_callback::<_, EditorShowcaseAssetListProcedureResult>(
@@ -31,10 +31,10 @@ pub trait admin_list_profile_invite_codes {
input: RuntimeProfileInviteCodeAdminListInput,
__callback: impl FnOnce(
&super::ProcedureEventContext,
Result<RuntimeProfileInviteCodeAdminListProcedureResult, __sdk::InternalError>,
) + Send
+ 'static,
&super::ProcedureEventContext,
Result<RuntimeProfileInviteCodeAdminListProcedureResult, __sdk::InternalError>,
) + Send
+ 'static,
);
}
@@ -44,10 +44,10 @@ impl admin_list_profile_invite_codes for super::RemoteProcedures {
input: RuntimeProfileInviteCodeAdminListInput,
__callback: impl FnOnce(
&super::ProcedureEventContext,
Result<RuntimeProfileInviteCodeAdminListProcedureResult, __sdk::InternalError>,
) + Send
+ 'static,
&super::ProcedureEventContext,
Result<RuntimeProfileInviteCodeAdminListProcedureResult, __sdk::InternalError>,
) + Send
+ 'static,
) {
self.imp
.invoke_procedure_with_callback::<_, RuntimeProfileInviteCodeAdminListProcedureResult>(
@@ -34,10 +34,10 @@ pub trait admin_list_profile_recharge_products {
input: RuntimeProfileRechargeProductAdminListInput,
__callback: impl FnOnce(
&super::ProcedureEventContext,
Result<RuntimeProfileRechargeProductAdminListProcedureResult, __sdk::InternalError>,
) + Send
+ 'static,
&super::ProcedureEventContext,
Result<RuntimeProfileRechargeProductAdminListProcedureResult, __sdk::InternalError>,
) + Send
+ 'static,
);
}
@@ -47,10 +47,10 @@ impl admin_list_profile_recharge_products for super::RemoteProcedures {
input: RuntimeProfileRechargeProductAdminListInput,
__callback: impl FnOnce(
&super::ProcedureEventContext,
Result<RuntimeProfileRechargeProductAdminListProcedureResult, __sdk::InternalError>,
) + Send
+ 'static,
&super::ProcedureEventContext,
Result<RuntimeProfileRechargeProductAdminListProcedureResult, __sdk::InternalError>,
) + Send
+ 'static,
) {
self.imp.invoke_procedure_with_callback::<_, RuntimeProfileRechargeProductAdminListProcedureResult>(
"admin_list_profile_recharge_products",

Some files were not shown because too many files have changed in this diff Show More