feat(wanfa): 新增路线详情参考价格配置及展示功能
- 新增数据库迁移脚本,为详情表添加四个价格相关字段 - 完善后端schema校验、序列化逻辑,增加价格相关的数据清理与验证规则 - 新增价格配置校验逻辑,设置起售价时必须选择对应的计价单位 - 在Admin UI详情编辑器中新增价格配置模块,支持配置起售价、计价单位、适用人数范围和价格说明 - 更新小程序端详情页面,支持展示配置的参考价格信息 - 补充相关测试用例,更新API文档与类型定义
This commit is contained in:
1 parent
f18971a430
commit
feec6ab80f
20 files changed
+351
-17
No files matched your search
@@ -0,0 +1,28 @@
|
||||
from importlib.util import module_from_spec, spec_from_file_location
|
||||
from pathlib import Path
|
||||
|
||||
|
||||
MIGRATION_PATH = Path(__file__).parents[1] / "alembic" / "versions" / "0037_detail_price_config.py"
|
||||
SPEC = spec_from_file_location("detail_price_config_migration", MIGRATION_PATH)
|
||||
assert SPEC and SPEC.loader
|
||||
MIGRATION = module_from_spec(SPEC)
|
||||
SPEC.loader.exec_module(MIGRATION)
|
||||
|
||||
|
||||
def test_price_columns_are_added_only_when_missing():
|
||||
assert MIGRATION.missing_price_columns(set()) == {
|
||||
"priceStartingValue",
|
||||
"priceUnit",
|
||||
"pricePeopleRange",
|
||||
"priceDescription",
|
||||
}
|
||||
assert MIGRATION.missing_price_columns({"priceStartingValue", "priceUnit"}) == {
|
||||
"pricePeopleRange",
|
||||
"priceDescription",
|
||||
}
|
||||
assert MIGRATION.missing_price_columns({
|
||||
"priceStartingValue",
|
||||
"priceUnit",
|
||||
"pricePeopleRange",
|
||||
"priceDescription",
|
||||
}) == set()
|
||||
@@ -77,6 +77,10 @@ def make_detail(**overrides):
|
||||
"excluded": ["往返大交通"],
|
||||
"notes": ["请准备轻便雨具。"],
|
||||
"gallery": ["https://example.test/family-water.jpg"],
|
||||
"priceStartingValue": 1.68,
|
||||
"priceUnit": "person",
|
||||
"pricePeopleRange": "2-4人",
|
||||
"priceDescription": "价格以最终确认方案为准。",
|
||||
"isActive": True,
|
||||
"sortOrder": 0,
|
||||
"conciergeAdvisorId": None,
|
||||
@@ -124,11 +128,33 @@ def test_detail_schema_trims_text_and_array_items():
|
||||
excluded=[" 往返大交通 "],
|
||||
notes=[" 请准备雨具。 "],
|
||||
gallery=[" https://example.test/family-water.jpg "],
|
||||
priceStartingValue=1.68,
|
||||
priceUnit="person",
|
||||
pricePeopleRange=" 2-4人 ",
|
||||
priceDescription=" 价格以最终确认方案为准。 ",
|
||||
)
|
||||
|
||||
assert detail.key == "family-water"
|
||||
assert detail.highlights == ["核心景观串联", "小团出行"]
|
||||
assert detail.gallery == ["https://example.test/family-water.jpg"]
|
||||
assert detail.priceStartingValue == 1.68
|
||||
assert detail.priceUnit == "person"
|
||||
assert detail.pricePeopleRange == "2-4人"
|
||||
assert detail.priceDescription == "价格以最终确认方案为准。"
|
||||
|
||||
|
||||
def test_detail_schema_rejects_unknown_price_unit():
|
||||
with pytest.raises(ValidationError):
|
||||
DetailCreate(
|
||||
key="family-water",
|
||||
eyebrow="玩法推荐",
|
||||
duration="5天4晚",
|
||||
title="亲子玩水",
|
||||
subtitle="贵州路线",
|
||||
intro="介绍",
|
||||
priceStartingValue=1.68,
|
||||
priceUnit="month",
|
||||
)
|
||||
|
||||
|
||||
def test_detail_schema_rejects_invalid_gallery_url():
|
||||
@@ -188,6 +214,10 @@ def test_public_detail_returns_frontend_contract_without_auth():
|
||||
"excluded": ["往返大交通"],
|
||||
"notes": ["请准备轻便雨具。"],
|
||||
"gallery": ["https://example.test/family-water.jpg"],
|
||||
"priceStartingValue": 1.68,
|
||||
"priceUnit": "person",
|
||||
"pricePeopleRange": "2-4人",
|
||||
"priceDescription": "价格以最终确认方案为准。",
|
||||
"conciergeAdvisor": None,
|
||||
},
|
||||
}
|
||||
@@ -294,6 +324,10 @@ def test_admin_detail_create_normalizes_key_and_appends():
|
||||
"excluded": [],
|
||||
"notes": [],
|
||||
"gallery": ["https://example.test/family-water.jpg"],
|
||||
"priceStartingValue": 1.68,
|
||||
"priceUnit": "person",
|
||||
"pricePeopleRange": "2-4人",
|
||||
"priceDescription": "价格以最终确认方案为准。",
|
||||
},
|
||||
)
|
||||
finally:
|
||||
@@ -301,6 +335,8 @@ def test_admin_detail_create_normalizes_key_and_appends():
|
||||
|
||||
assert response.status_code == 201
|
||||
assert response.json()["data"]["key"] == "family-water"
|
||||
assert fake_db.added[0].priceStartingValue == 1.68
|
||||
assert fake_db.added[0].priceUnit == "person"
|
||||
assert fake_db.added[0].sortOrder == 3
|
||||
|
||||
|
||||
|
||||
Reference in new issue
Block a user