This commit is contained in:
2026-08-13 09:38:36 +08:00
124 changed files with 11236 additions and 5549 deletions
@@ -0,0 +1,25 @@
"""merge changes from remote
Revision ID: 1a4d1f095fa1
Revises: 20260811_20260811, 8a6d2f4c9b10
Create Date: 2026-08-11 10:30:10.431672
"""
from typing import Sequence, Union
from alembic import op
import sqlalchemy as sa
# revision identifiers, used by Alembic.
revision: str = '1a4d1f095fa1'
down_revision: Union[str, None] = ('20260811_20260811', '8a6d2f4c9b10')
branch_labels: Union[str, Sequence[str], None] = None
depends_on: Union[str, Sequence[str], None] = None
def upgrade() -> None:
pass
def downgrade() -> None:
pass
@@ -0,0 +1,650 @@
"""add credit product renewal enabled
Revision ID: 8a6d2f4c9b10
Revises: 7f3c8a2d9e41
Create Date: 2026-08-06 17:20:00
"""
from __future__ import annotations
from datetime import datetime
from decimal import Decimal
from alembic import op
import sqlalchemy as sa
revision = "8a6d2f4c9b10"
down_revision = "7f3c8a2d9e41"
branch_labels = None
depends_on = None
_PRODUCT_UPSERT_SQL = sa.text(
"""
INSERT INTO credit_products (
id,
product_code,
product_type,
name,
description,
features_json,
tier_code,
tier_rank,
billing_cycle,
monthly_grant_credits,
first_purchase_price,
regular_price,
activity_price,
activity_start_at,
activity_end_at,
grant_credits,
validity_months,
price,
credit_level,
currency,
is_active,
sort_order,
created_at,
updated_at,
renewal_enabled
) VALUES (
:id,
:product_code,
:product_type,
:name,
:description,
CAST(:features_json AS JSON),
:tier_code,
:tier_rank,
:billing_cycle,
:monthly_grant_credits,
:first_purchase_price,
:regular_price,
:activity_price,
:activity_start_at,
:activity_end_at,
:grant_credits,
:validity_months,
:price,
:credit_level,
:currency,
:is_active,
:sort_order,
:created_at,
:updated_at,
:renewal_enabled
)
ON CONFLICT (product_code) DO UPDATE SET
product_type = EXCLUDED.product_type,
name = EXCLUDED.name,
description = EXCLUDED.description,
features_json = EXCLUDED.features_json,
tier_code = EXCLUDED.tier_code,
tier_rank = EXCLUDED.tier_rank,
billing_cycle = EXCLUDED.billing_cycle,
monthly_grant_credits = EXCLUDED.monthly_grant_credits,
first_purchase_price = EXCLUDED.first_purchase_price,
regular_price = EXCLUDED.regular_price,
activity_price = EXCLUDED.activity_price,
activity_start_at = EXCLUDED.activity_start_at,
activity_end_at = EXCLUDED.activity_end_at,
grant_credits = EXCLUDED.grant_credits,
validity_months = EXCLUDED.validity_months,
price = EXCLUDED.price,
credit_level = EXCLUDED.credit_level,
currency = EXCLUDED.currency,
is_active = EXCLUDED.is_active,
sort_order = EXCLUDED.sort_order,
updated_at = EXCLUDED.updated_at,
renewal_enabled = EXCLUDED.renewal_enabled
"""
)
_POLICY_UPSERT_SQL = sa.text(
"""
INSERT INTO llm_billing_policies (
id,
scene_code,
scene_name,
pre_deduct_credits,
is_active,
version,
created_by,
updated_by,
created_at,
updated_at
) VALUES (
:id,
:scene_code,
:scene_name,
:pre_deduct_credits,
:is_active,
:version,
:created_by,
:updated_by,
:created_at,
:updated_at
)
ON CONFLICT (scene_code) DO UPDATE SET
scene_name = EXCLUDED.scene_name,
pre_deduct_credits = EXCLUDED.pre_deduct_credits,
is_active = EXCLUDED.is_active,
version = EXCLUDED.version,
updated_by = EXCLUDED.updated_by,
updated_at = EXCLUDED.updated_at
"""
)
def _dt(value: str) -> datetime:
return datetime.fromisoformat(value)
def _seed_credit_products() -> None:
rows = [
{
"id": "0019fd653e4680767ab",
"product_code": "1",
"product_type": "subscription",
"name": "入门",
"description": None,
"features_json": "[]",
"tier_code": "入门",
"tier_rank": 1,
"billing_cycle": "monthly",
"monthly_grant_credits": Decimal("1000.00"),
"first_purchase_price": Decimal("79.00"),
"regular_price": Decimal("122.00"),
"activity_price": None,
"activity_start_at": None,
"activity_end_at": None,
"grant_credits": None,
"validity_months": None,
"price": Decimal("122.00"),
"credit_level": "general",
"currency": "CNY",
"is_active": True,
"sort_order": 1,
"created_at": _dt("2026-08-06T09:07:30.020043+08:00"),
"updated_at": _dt("2026-08-06T09:52:15.579827+08:00"),
"renewal_enabled": False,
},
{
"id": "0019fd67e8a786dda0e",
"product_code": "2",
"product_type": "subscription",
"name": "标准",
"description": None,
"features_json": "[]",
"tier_code": "标准",
"tier_rank": 2,
"billing_cycle": "monthly",
"monthly_grant_credits": Decimal("2000.00"),
"first_purchase_price": Decimal("154.00"),
"regular_price": Decimal("239.00"),
"activity_price": None,
"activity_start_at": None,
"activity_end_at": None,
"grant_credits": None,
"validity_months": None,
"price": Decimal("239.00"),
"credit_level": "general",
"currency": "CNY",
"is_active": True,
"sort_order": 2,
"created_at": _dt("2026-08-06T09:54:05.049302+08:00"),
"updated_at": _dt("2026-08-06T09:54:05.049302+08:00"),
"renewal_enabled": True,
},
{
"id": "0019fd67f4c8bf75dd1",
"product_code": "3",
"product_type": "subscription",
"name": "高级",
"description": None,
"features_json": "[]",
"tier_code": "高级",
"tier_rank": 3,
"billing_cycle": "monthly",
"monthly_grant_credits": Decimal("3000.00"),
"first_purchase_price": Decimal("221.00"),
"regular_price": Decimal("353.00"),
"activity_price": None,
"activity_start_at": None,
"activity_end_at": None,
"grant_credits": None,
"validity_months": None,
"price": Decimal("353.00"),
"credit_level": "general",
"currency": "CNY",
"is_active": True,
"sort_order": 3,
"created_at": _dt("2026-08-06T09:54:54.768868+08:00"),
"updated_at": _dt("2026-08-06T09:55:10.408471+08:00"),
"renewal_enabled": True,
},
{
"id": "0019fd680784c16dd15",
"product_code": "4",
"product_type": "subscription",
"name": "超级",
"description": None,
"features_json": "[]",
"tier_code": "超级",
"tier_rank": 4,
"billing_cycle": "monthly",
"monthly_grant_credits": Decimal("4000.00"),
"first_purchase_price": Decimal("280.00"),
"regular_price": Decimal("476.00"),
"activity_price": None,
"activity_start_at": None,
"activity_end_at": None,
"grant_credits": None,
"validity_months": None,
"price": Decimal("476.00"),
"credit_level": "general",
"currency": "CNY",
"is_active": True,
"sort_order": 4,
"created_at": _dt("2026-08-06T09:56:11.442596+08:00"),
"updated_at": _dt("2026-08-06T09:56:11.442596+08:00"),
"renewal_enabled": True,
},
{
"id": "0019fd68270abc3dcbd",
"product_code": "5",
"product_type": "subscription",
"name": "标准",
"description": None,
"features_json": "[]",
"tier_code": "标准",
"tier_rank": 2,
"billing_cycle": "quarterly",
"monthly_grant_credits": Decimal("5000.00"),
"first_purchase_price": Decimal("1029.00"),
"regular_price": Decimal("1499.00"),
"activity_price": None,
"activity_start_at": None,
"activity_end_at": None,
"grant_credits": None,
"validity_months": None,
"price": Decimal("1499.00"),
"credit_level": "general",
"currency": "CNY",
"is_active": True,
"sort_order": 5,
"created_at": _dt("2026-08-06T09:58:20.601505+08:00"),
"updated_at": _dt("2026-08-06T09:58:20.601505+08:00"),
"renewal_enabled": True,
},
{
"id": "0019fd68373d24dbab0",
"product_code": "6",
"product_type": "subscription",
"name": "高级",
"description": None,
"features_json": "[]",
"tier_code": "高级",
"tier_rank": 3,
"billing_cycle": "quarterly",
"monthly_grant_credits": Decimal("6000.00"),
"first_purchase_price": Decimal("1197.00"),
"regular_price": Decimal("1791.00"),
"activity_price": None,
"activity_start_at": None,
"activity_end_at": None,
"grant_credits": None,
"validity_months": None,
"price": Decimal("1791.00"),
"credit_level": "general",
"currency": "CNY",
"is_active": True,
"sort_order": 6,
"created_at": _dt("2026-08-06T09:59:26.972669+08:00"),
"updated_at": _dt("2026-08-06T09:59:26.972669+08:00"),
"renewal_enabled": True,
},
{
"id": "0019fd68469706aa522",
"product_code": "7",
"product_type": "subscription",
"name": "超级",
"description": None,
"features_json": "[]",
"tier_code": "超级",
"tier_rank": 4,
"billing_cycle": "quarterly",
"monthly_grant_credits": Decimal("7000.00"),
"first_purchase_price": Decimal("1367.00"),
"regular_price": Decimal("2079.00"),
"activity_price": None,
"activity_start_at": None,
"activity_end_at": None,
"grant_credits": None,
"validity_months": None,
"price": Decimal("2079.00"),
"credit_level": "general",
"currency": "CNY",
"is_active": True,
"sort_order": 7,
"created_at": _dt("2026-08-06T10:00:29.843562+08:00"),
"updated_at": _dt("2026-08-06T10:00:29.843562+08:00"),
"renewal_enabled": True,
},
{
"id": "0019fd6904f72f59505",
"product_code": "8",
"product_type": "subscription",
"name": "标准",
"description": None,
"features_json": "[]",
"tier_code": "标准",
"tier_rank": 2,
"billing_cycle": "yearly",
"monthly_grant_credits": Decimal("10000.00"),
"first_purchase_price": Decimal("7308.00"),
"regular_price": Decimal("8399.00"),
"activity_price": None,
"activity_start_at": None,
"activity_end_at": None,
"grant_credits": None,
"validity_months": None,
"price": Decimal("8399.00"),
"credit_level": "general",
"currency": "CNY",
"is_active": True,
"sort_order": 8,
"created_at": _dt("2026-08-06T10:13:29.614018+08:00"),
"updated_at": _dt("2026-08-06T10:13:29.614018+08:00"),
"renewal_enabled": True,
},
{
"id": "0019fd692bc5e42b8be",
"product_code": "9",
"product_type": "subscription",
"name": "高级",
"description": None,
"features_json": "[]",
"tier_code": "高级",
"tier_rank": 3,
"billing_cycle": "yearly",
"monthly_grant_credits": Decimal("15000.00"),
"first_purchase_price": Decimal("10710.00"),
"regular_price": Decimal("12586.00"),
"activity_price": None,
"activity_start_at": None,
"activity_end_at": None,
"grant_credits": None,
"validity_months": None,
"price": Decimal("12586.00"),
"credit_level": "general",
"currency": "CNY",
"is_active": True,
"sort_order": 9,
"created_at": _dt("2026-08-06T10:16:08.545547+08:00"),
"updated_at": _dt("2026-08-06T10:16:08.545547+08:00"),
"renewal_enabled": True,
},
{
"id": "0019fd69417fabda8c6",
"product_code": "10",
"product_type": "subscription",
"name": "超级",
"description": None,
"features_json": "[]",
"tier_code": "超级",
"tier_rank": 4,
"billing_cycle": "yearly",
"monthly_grant_credits": Decimal("20000.00"),
"first_purchase_price": Decimal("13440.00"),
"regular_price": Decimal("16685.00"),
"activity_price": None,
"activity_start_at": None,
"activity_end_at": None,
"grant_credits": None,
"validity_months": None,
"price": Decimal("16685.00"),
"credit_level": "general",
"currency": "CNY",
"is_active": True,
"sort_order": 10,
"created_at": _dt("2026-08-06T10:17:37.548293+08:00"),
"updated_at": _dt("2026-08-06T10:17:37.548293+08:00"),
"renewal_enabled": True,
},
{
"id": "0019fd69a07e363c7b5",
"product_code": "ZLB-A",
"product_type": "credit_addon",
"name": "增量包A",
"description": None,
"features_json": "[]",
"tier_code": None,
"tier_rank": None,
"billing_cycle": None,
"monthly_grant_credits": None,
"first_purchase_price": None,
"regular_price": None,
"activity_price": None,
"activity_start_at": None,
"activity_end_at": None,
"grant_credits": Decimal("500.00"),
"validity_months": 1,
"price": Decimal("0.01"),
"credit_level": "general",
"currency": "CNY",
"is_active": True,
"sort_order": 1,
"created_at": _dt("2026-08-06T10:24:06.646673+08:00"),
"updated_at": _dt("2026-08-06T10:24:06.646673+08:00"),
"renewal_enabled": False,
},
{
"id": "0019fd69a640d7ccc92",
"product_code": "ZLB-B",
"product_type": "credit_addon",
"name": "增量包B",
"description": None,
"features_json": "[]",
"tier_code": None,
"tier_rank": None,
"billing_cycle": None,
"monthly_grant_credits": None,
"first_purchase_price": None,
"regular_price": None,
"activity_price": None,
"activity_start_at": None,
"activity_end_at": None,
"grant_credits": Decimal("1000.00"),
"validity_months": 1,
"price": Decimal("0.02"),
"credit_level": "general",
"currency": "CNY",
"is_active": True,
"sort_order": 2,
"created_at": _dt("2026-08-06T10:24:30.256294+08:00"),
"updated_at": _dt("2026-08-06T10:24:35.878389+08:00"),
"renewal_enabled": False,
},
{
"id": "0019fd69ae039d3ba69",
"product_code": "ZLB-C",
"product_type": "credit_addon",
"name": "增量包C",
"description": None,
"features_json": "[]",
"tier_code": None,
"tier_rank": None,
"billing_cycle": None,
"monthly_grant_credits": None,
"first_purchase_price": None,
"regular_price": None,
"activity_price": None,
"activity_start_at": None,
"activity_end_at": None,
"grant_credits": Decimal("1500.00"),
"validity_months": 1,
"price": Decimal("0.03"),
"credit_level": "general",
"currency": "CNY",
"is_active": True,
"sort_order": 3,
"created_at": _dt("2026-08-06T10:25:02.043620+08:00"),
"updated_at": _dt("2026-08-06T10:25:02.043620+08:00"),
"renewal_enabled": False,
},
{
"id": "0019fd69b3166a6a71c",
"product_code": "ZLB-D",
"product_type": "credit_addon",
"name": "增量包D",
"description": None,
"features_json": "[]",
"tier_code": None,
"tier_rank": None,
"billing_cycle": None,
"monthly_grant_credits": None,
"first_purchase_price": None,
"regular_price": None,
"activity_price": None,
"activity_start_at": None,
"activity_end_at": None,
"grant_credits": Decimal("2000.00"),
"validity_months": 1,
"price": Decimal("0.04"),
"credit_level": "general",
"currency": "CNY",
"is_active": True,
"sort_order": 4,
"created_at": _dt("2026-08-06T10:25:22.811498+08:00"),
"updated_at": _dt("2026-08-06T10:25:29.647103+08:00"),
"renewal_enabled": False,
},
]
connection = op.get_bind()
for row in rows:
connection.execute(_PRODUCT_UPSERT_SQL, row)
def _seed_llm_billing_policies() -> None:
admin_user_id = "0019e0a44895b6d837d"
rows = [
{
"id": "0019fd6aa5084a85a96",
"scene_code": "generation_record_text_prompt_optimize",
"scene_name": "AI创作-提示词优化",
"pre_deduct_credits": Decimal("5.00"),
"is_active": True,
"version": 1,
"created_by": admin_user_id,
"updated_by": admin_user_id,
"created_at": _dt("2026-08-06T10:41:53.809940+08:00"),
"updated_at": _dt("2026-08-06T10:41:53.809940+08:00"),
},
{
"id": "0019fd6aa834169f61d",
"scene_code": "hot_opening_image_prompt_optimize",
"scene_name": "爆款开头复刻-图片提示词优化",
"pre_deduct_credits": Decimal("5.00"),
"is_active": True,
"version": 1,
"created_by": admin_user_id,
"updated_by": admin_user_id,
"created_at": _dt("2026-08-06T10:42:06.818840+08:00"),
"updated_at": _dt("2026-08-06T10:42:06.818840+08:00"),
},
{
"id": "0019fd6aac862f821ca",
"scene_code": "shot_image_prompt_optimize",
"scene_name": "拆镜复刻-图片提示词优化",
"pre_deduct_credits": Decimal("5.00"),
"is_active": True,
"version": 1,
"created_by": admin_user_id,
"updated_by": admin_user_id,
"created_at": _dt("2026-08-06T10:42:24.496938+08:00"),
"updated_at": _dt("2026-08-06T10:42:24.496938+08:00"),
},
{
"id": "0019fd6aaf2fcae0765",
"scene_code": "shot_video_prompt_optimize",
"scene_name": "拆镜复刻-视频提示词优化",
"pre_deduct_credits": Decimal("20.00"),
"is_active": True,
"version": 1,
"created_by": admin_user_id,
"updated_by": admin_user_id,
"created_at": _dt("2026-08-06T10:42:35.404414+08:00"),
"updated_at": _dt("2026-08-06T10:42:35.404414+08:00"),
},
{
"id": "0019fd6aaaf31d7c7c7",
"scene_code": "hot_opening_video_prompt_optimize",
"scene_name": "爆款开头复刻-视频提示词优化",
"pre_deduct_credits": Decimal("20.00"),
"is_active": True,
"version": 1,
"created_by": admin_user_id,
"updated_by": admin_user_id,
"created_at": _dt("2026-08-06T10:42:18.003357+08:00"),
"updated_at": _dt("2026-08-06T10:42:39.440194+08:00"),
},
{
"id": "0019fd6abba149ef7e9",
"scene_code": "shot_original_video_analysis",
"scene_name": "拆镜复刻-原视频AI分析",
"pre_deduct_credits": Decimal("20.00"),
"is_active": True,
"version": 1,
"created_by": admin_user_id,
"updated_by": admin_user_id,
"created_at": _dt("2026-08-06T10:43:26.390337+08:00"),
"updated_at": _dt("2026-08-06T10:43:26.390337+08:00"),
},
{
"id": "0019fd6abdbc4182c17",
"scene_code": "shot_segment_video_analysis",
"scene_name": "拆镜复刻-片段视频AI分析",
"pre_deduct_credits": Decimal("10.00"),
"is_active": True,
"version": 1,
"created_by": admin_user_id,
"updated_by": admin_user_id,
"created_at": _dt("2026-08-06T10:43:35.017213+08:00"),
"updated_at": _dt("2026-08-06T10:43:35.017213+08:00"),
},
]
connection = op.get_bind()
for row in rows:
connection.execute(_POLICY_UPSERT_SQL, row)
def upgrade() -> None:
op.add_column(
"credit_products",
sa.Column(
"renewal_enabled",
sa.Boolean(),
nullable=False,
server_default=sa.text("true"),
),
)
# 积分增值包不参与订阅续费,统一标记为关闭;已有订阅套餐默认保持开启。
op.execute(
"UPDATE credit_products "
"SET renewal_enabled = false "
"WHERE product_type = 'credit_addon'"
)
_seed_credit_products()
_seed_llm_billing_policies()
def downgrade() -> None:
# 产品和计费策略属于运营配置,降级仅撤销本次新增字段,不主动删除业务配置数据。
op.drop_column("credit_products", "renewal_enabled")
@@ -0,0 +1,75 @@
"""expand credit addon validity months to 1-36
Revision ID: b7e2c4d91a63
Revises: 1a4d1f095fa1
Create Date: 2026-08-11 13:15:00
"""
from alembic import op
revision = "b7e2c4d91a63"
down_revision = "1a4d1f095fa1"
branch_labels = None
depends_on = None
CONSTRAINT_NAME = "ck_credit_products_type_required_fields"
def _drop_type_constraint_if_exists() -> None:
op.execute(
f"""
DO $$
BEGIN
IF EXISTS (
SELECT 1
FROM pg_constraint c
JOIN pg_class t ON t.oid = c.conrelid
JOIN pg_namespace n ON n.oid = t.relnamespace
WHERE n.nspname = current_schema()
AND t.relname = 'credit_products'
AND c.conname = '{CONSTRAINT_NAME}'
) THEN
ALTER TABLE credit_products DROP CONSTRAINT {CONSTRAINT_NAME};
END IF;
END
$$;
"""
)
def _create_type_constraint(*, addon_condition: str) -> None:
op.create_check_constraint(
CONSTRAINT_NAME,
"credit_products",
"(product_type = 'subscription' AND tier_code IS NOT NULL AND tier_rank IS NOT NULL "
"AND billing_cycle IS NOT NULL AND monthly_grant_credits IS NOT NULL "
"AND first_purchase_price IS NOT NULL AND regular_price IS NOT NULL "
"AND grant_credits IS NULL AND validity_months IS NULL) "
"OR (product_type = 'credit_addon' AND grant_credits IS NOT NULL "
f"AND {addon_condition} AND tier_code IS NULL AND tier_rank IS NULL "
"AND billing_cycle IS NULL AND monthly_grant_credits IS NULL "
"AND first_purchase_price IS NULL AND regular_price IS NULL "
"AND activity_price IS NULL AND activity_start_at IS NULL AND activity_end_at IS NULL)",
)
def upgrade() -> None:
# 当前版本中增值包被旧约束固定为 validity_months = 1。
# 先移除旧约束,再开放为1-36个自然月;不修改任何现有商品数据。
_drop_type_constraint_if_exists()
_create_type_constraint(addon_condition="validity_months BETWEEN 1 AND 36")
def downgrade() -> None:
# 回退到旧版本时,旧约束只允许1个月。为保证 downgrade 可执行,
# 将现有增值包有效期恢复为旧版本唯一合法值1个月。
_drop_type_constraint_if_exists()
op.execute(
"UPDATE credit_products "
"SET validity_months = 1 "
"WHERE product_type = 'credit_addon' "
"AND validity_months IS DISTINCT FROM 1"
)
_create_type_constraint(addon_condition="validity_months = 1")