接入会员周期泥点制度
新增 Starter、Basic、Pro、Ultimate 会员商品配置与权益字段。 拆分会员有效期、周期重置时间、周期限时泥点和永久泥点余额。 实现升级补价补点但不延长有效期或移动重置时间,同级购买只延长有效期。 补齐钱包扣费与退款中的会员周期泥点消耗、重置和流水记录。 同步后台商品配置、前端充值展示、共享契约、SpacetimeDB 迁移与生成绑定。
This commit is contained in:
@@ -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 objectKey;objectKey 必须归属于当前账号的 `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 objectKey;objectKey 必须归属于当前账号的 `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`
|
||||
|
||||
|
||||
@@ -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)]
|
||||
|
||||
@@ -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)
|
||||
|
||||
+8
-8
@@ -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>(
|
||||
|
||||
+6
-10
@@ -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)
|
||||
|
||||
+8
-8
@@ -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>(
|
||||
|
||||
+8
-8
@@ -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>(
|
||||
|
||||
+8
-8
@@ -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>(
|
||||
|
||||
+8
-8
@@ -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>(
|
||||
|
||||
+8
-8
@@ -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>(
|
||||
|
||||
+8
-8
@@ -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>(
|
||||
|
||||
+8
-8
@@ -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
Reference in New Issue
Block a user