feat(huya): 统一积分兑换并完善兑换记录
This commit is contained in:
@@ -1142,6 +1142,75 @@ class HuyaHttpClient:
|
||||
self.logger(" createOrderV5: 无响应")
|
||||
return result
|
||||
|
||||
def create_order_v6(
|
||||
self,
|
||||
uid,
|
||||
guid,
|
||||
cookie,
|
||||
pid,
|
||||
items,
|
||||
source_id="yellowcarlist",
|
||||
game_id="0",
|
||||
biz_params=JIFENCENTER_BIZ_PARAMS,
|
||||
):
|
||||
"""积分兑换多商品下单(``shopMiddleUI.createOrderV6``)。
|
||||
|
||||
2026-11-13 HAR:积分足够时官方只发这一单,不再调用
|
||||
``scoreExchangePrize`` 或 ``payOrderSubmitV5``。
|
||||
"""
|
||||
from .shop_structs import (
|
||||
CreateOrderAccountParam,
|
||||
CreateOrderExtraParam,
|
||||
CreateOrderItemReqV6,
|
||||
CreateOrderPromotionParam,
|
||||
CreateOrderReqV6,
|
||||
CreateOrderRspV6,
|
||||
)
|
||||
|
||||
req = CreateOrderReqV6()
|
||||
req.userId = self._build_shop_user(uid, cookie)
|
||||
req.shopAppInfo = self._build_shop_app(source_id, SHOP_APP_SCENE)
|
||||
req.items = []
|
||||
for item in items:
|
||||
row = CreateOrderItemReqV6()
|
||||
row.spuId = str(item.get("spu_id") or "")
|
||||
row.skuId = int(item.get("sku_id") or 0)
|
||||
row.itemCount = int(item.get("item_count") or 1)
|
||||
row.goodsType = int(item.get("goods_type") or 0)
|
||||
row.virtualType = int(item.get("virtual_type") or 0)
|
||||
req.items.append(row)
|
||||
req.pid = int(pid or 0)
|
||||
req.gameId = str(game_id or "0")
|
||||
req.src = 2
|
||||
req.orderType = 6
|
||||
extra = CreateOrderExtraParam()
|
||||
extra.bizParams = biz_params
|
||||
req.extraParam = extra
|
||||
req.sourceId = source_id
|
||||
req.env = self._build_order_env()
|
||||
req.orderScene = 3
|
||||
req.promotionParam = CreateOrderPromotionParam()
|
||||
req.accountParam = CreateOrderAccountParam()
|
||||
|
||||
result: Any = self.call_rpc(
|
||||
"shopMiddleUI",
|
||||
"createOrderV6",
|
||||
req,
|
||||
CreateOrderRspV6,
|
||||
uid,
|
||||
guid,
|
||||
cookie,
|
||||
timeout=15.0,
|
||||
)
|
||||
if result is not None:
|
||||
self.logger(
|
||||
f" createOrderV6: code={result.code} orderId={result.orderId} "
|
||||
f"msg={result.message}"
|
||||
)
|
||||
else:
|
||||
self.logger(" createOrderV6: 无响应")
|
||||
return result
|
||||
|
||||
@staticmethod
|
||||
def _normalize_pay_channel(pay_type) -> str:
|
||||
text = str(pay_type or "").strip()
|
||||
|
||||
@@ -1055,6 +1055,138 @@ class CreateOrderRsp(TafStruct):
|
||||
pass
|
||||
|
||||
|
||||
class CreateOrderItemReqV6(TafStruct):
|
||||
"""``createOrderV6`` 的单个商品项(2026-11-13 积分兑换 HAR)。"""
|
||||
|
||||
def __init__(self):
|
||||
self.spuId: str = "" # tag 0
|
||||
self.skuId: int = 0 # tag 1
|
||||
self.itemCount: int = 0 # tag 2
|
||||
self.groupItemList: list = [] # tag 3 Vector<CreateOrderItemReqV6>
|
||||
self.goodsType: int = 0 # tag 4
|
||||
self.virtualType: int = 0 # tag 5
|
||||
|
||||
def write_to(self, os: TafOutputStream):
|
||||
os.write_string(0, self.spuId)
|
||||
os.write_int64(1, self.skuId)
|
||||
os.write_int32(2, self.itemCount)
|
||||
os.write_list(3, self.groupItemList)
|
||||
os.write_int32(4, self.goodsType)
|
||||
os.write_int32(5, self.virtualType)
|
||||
|
||||
def read_from(self, ins: TafInputStream):
|
||||
self.spuId = ins.read_string(0, default=self.spuId)
|
||||
self.skuId = ins.read_int64(1, default=self.skuId)
|
||||
self.itemCount = ins.read_int32(2, default=self.itemCount)
|
||||
self.groupItemList = ins.read_list(3, item_reader=CreateOrderItemReqV6.read)
|
||||
self.goodsType = ins.read_int32(4, default=self.goodsType)
|
||||
self.virtualType = ins.read_int32(5, default=self.virtualType)
|
||||
|
||||
@staticmethod
|
||||
def read(ins: TafInputStream) -> "CreateOrderItemReqV6":
|
||||
item = CreateOrderItemReqV6()
|
||||
item.read_from(ins)
|
||||
return item
|
||||
|
||||
|
||||
class CreateOrderReqV6(TafStruct):
|
||||
"""积分兑换多商品下单请求 (shopMiddleUI.createOrderV6)。"""
|
||||
|
||||
def __init__(self):
|
||||
self.userId = UserId() # tag 0
|
||||
self.shopAppInfo = ShopAppInfo() # tag 1
|
||||
self.receiveId: int = 0 # tag 2
|
||||
self.items: list[CreateOrderItemReqV6] = [] # tag 3
|
||||
self.pid: int = 0 # tag 4
|
||||
self.remark: str = "" # tag 5
|
||||
self.gameId: str = "" # tag 6
|
||||
self.orderId: int = 0 # tag 7
|
||||
self.src: int = 0 # tag 8
|
||||
self.couponUserIds: list[int] = [] # tag 9
|
||||
self.orderType: int = 0 # tag 10
|
||||
self.extraParam: CreateOrderExtraParam | None = None # tag 11
|
||||
self.scene: int = 0 # tag 12
|
||||
self.promotionItems: list = [] # tag 13
|
||||
self.sourceId: str = "" # tag 14
|
||||
self.env: dict[str, str] = {} # tag 15
|
||||
self.orderScene: int = 0 # tag 16
|
||||
self.watchWord: str = "" # tag 17
|
||||
self.marketingChannel: str = "" # tag 18
|
||||
self.promotionParam: CreateOrderPromotionParam | None = None # tag 19
|
||||
self.externalTraceKey: str = "" # tag 20
|
||||
self.kefuUid: int = 0 # tag 21
|
||||
self.accountParam: CreateOrderAccountParam | None = None # tag 22
|
||||
self.parentOrderId: int = 0 # tag 23
|
||||
self.vendorAccountType: str = "" # tag 24
|
||||
self.vendorAccountVal: str = "" # tag 25
|
||||
self.vendorSubAccountVal: str = "" # tag 26
|
||||
self.vendorSubAccountType: str = "" # tag 27
|
||||
|
||||
def write_to(self, os: TafOutputStream):
|
||||
os.write_struct(0, self.userId)
|
||||
os.write_struct(1, self.shopAppInfo)
|
||||
os.write_int64(2, self.receiveId)
|
||||
os.write_list(3, self.items)
|
||||
os.write_int64(4, self.pid)
|
||||
os.write_string(5, self.remark)
|
||||
os.write_string(6, self.gameId)
|
||||
os.write_int64(7, self.orderId)
|
||||
os.write_int32(8, self.src)
|
||||
os.write_list(9, self.couponUserIds)
|
||||
os.write_int32(10, self.orderType)
|
||||
os.write_struct(11, self.extraParam or CreateOrderExtraParam())
|
||||
os.write_int32(12, self.scene)
|
||||
os.write_list(13, self.promotionItems)
|
||||
os.write_string(14, self.sourceId)
|
||||
os.write_map(15, self.env)
|
||||
os.write_int32(16, self.orderScene)
|
||||
os.write_string(17, self.watchWord)
|
||||
os.write_string(18, self.marketingChannel)
|
||||
os.write_struct(19, self.promotionParam or CreateOrderPromotionParam())
|
||||
os.write_string(20, self.externalTraceKey)
|
||||
os.write_int64(21, self.kefuUid)
|
||||
os.write_struct(22, self.accountParam or CreateOrderAccountParam())
|
||||
os.write_int64(23, self.parentOrderId)
|
||||
os.write_string(24, self.vendorAccountType)
|
||||
os.write_string(25, self.vendorAccountVal)
|
||||
os.write_string(26, self.vendorSubAccountVal)
|
||||
os.write_string(27, self.vendorSubAccountType)
|
||||
|
||||
def read_from(self, ins: TafInputStream):
|
||||
pass
|
||||
|
||||
|
||||
class CreateOrderRspV6(TafStruct):
|
||||
"""积分兑换多商品下单响应 (shopMiddleUI.createOrderV6)。"""
|
||||
|
||||
def __init__(self):
|
||||
self.code: int = 0 # tag 0
|
||||
self.message: str = "" # tag 1
|
||||
self.orderId: int = 0 # tag 2
|
||||
self.subOrderId: int = 0 # tag 3
|
||||
self.orderStatus: int = 0 # tag 4
|
||||
|
||||
def read_from(self, ins: TafInputStream):
|
||||
self.code = ins.read_int32(0, default=self.code)
|
||||
self.message = ins.read_string(1, default=self.message)
|
||||
self.orderId = ins.read_int64(2, default=self.orderId)
|
||||
self.subOrderId = ins.read_int64(3, default=self.subOrderId)
|
||||
self.orderStatus = ins.read_int32(4, default=self.orderStatus)
|
||||
_skip_to_struct_end(ins)
|
||||
|
||||
def write_to(self, os: TafOutputStream):
|
||||
pass
|
||||
|
||||
def to_dict(self) -> dict:
|
||||
return {
|
||||
"code": self.code,
|
||||
"message": self.message,
|
||||
"order_id": self.orderId,
|
||||
"sub_order_id": self.subOrderId,
|
||||
"order_status": self.orderStatus,
|
||||
}
|
||||
|
||||
|
||||
# ============================================================
|
||||
# 支付(payOrderSubmitV5)
|
||||
# ============================================================
|
||||
@@ -1314,6 +1446,28 @@ def extract_points_center_tabs(payload: dict | None) -> list[dict]:
|
||||
return result
|
||||
|
||||
|
||||
def extract_points_center_sid(payload: dict | None) -> int | None:
|
||||
"""从 ``queryAllocation`` 的 ScoreCenterConfig 提取当前兑换活动 SID。
|
||||
|
||||
2026-11-13 HAR:配置位于
|
||||
``payload.tag2[*].tag2_2.tag0.tag7``,当前值为 ``2277``;这个值正是
|
||||
``webActUI.getUserPrizeRecords`` 的 ``tag1``。
|
||||
"""
|
||||
if not isinstance(payload, dict):
|
||||
return None
|
||||
for section in payload.get("tag2") or []:
|
||||
if not isinstance(section, dict):
|
||||
continue
|
||||
config_box = section.get("tag2_2")
|
||||
config = config_box.get("tag0") if isinstance(config_box, dict) else None
|
||||
if not isinstance(config, dict):
|
||||
continue
|
||||
sid = _as_int(config.get("tag7"))
|
||||
if sid and sid > 0:
|
||||
return sid
|
||||
return None
|
||||
|
||||
|
||||
class PlayMallAppInfo(TafStruct):
|
||||
"""PlayMallUI 系接口的应用信息。
|
||||
|
||||
|
||||
+54
-1
@@ -105,7 +105,7 @@ SEQ_ACTIVITY_BIZ = 0x1D000109
|
||||
SEQ_POINTS_BIZ = 0x1D000107
|
||||
SEQ_POINTS_ORDER = 0x1D000108
|
||||
# 积分中心通道里用 0x1d000108 的两帧
|
||||
POINTS_ORDER_METHODS = frozenset({"createOrderV5", "payOrderSubmitV5"})
|
||||
POINTS_ORDER_METHODS = frozenset({"createOrderV5", "createOrderV6", "payOrderSubmitV5"})
|
||||
|
||||
|
||||
class WssCommand:
|
||||
@@ -1309,6 +1309,59 @@ class HuyaWssClient:
|
||||
"shopMiddleUI", "createOrderV5", req, CreateOrderRsp, timeout=15.0
|
||||
)
|
||||
|
||||
async def create_order_v6(
|
||||
self,
|
||||
uid: int,
|
||||
guid: str,
|
||||
cookie: str,
|
||||
pid: int,
|
||||
items,
|
||||
source_id: str = "yellowcarlist",
|
||||
game_id: str = "0",
|
||||
biz_params: str = JIFENCENTER_BIZ_PARAMS,
|
||||
):
|
||||
"""积分兑换多商品下单(``shopMiddleUI.createOrderV6``)。"""
|
||||
from .shop_structs import (
|
||||
CreateOrderAccountParam,
|
||||
CreateOrderExtraParam,
|
||||
CreateOrderItemReqV6,
|
||||
CreateOrderPromotionParam,
|
||||
CreateOrderReqV6,
|
||||
CreateOrderRspV6,
|
||||
)
|
||||
|
||||
req = CreateOrderReqV6()
|
||||
req.userId = self._build_biz_user(uid, cookie)
|
||||
req.shopAppInfo = self._build_shop_app(source_id, SHOP_APP_SCENE)
|
||||
req.items = []
|
||||
for item in items:
|
||||
row = CreateOrderItemReqV6()
|
||||
row.spuId = str(item.get("spu_id") or "")
|
||||
row.skuId = int(item.get("sku_id") or 0)
|
||||
row.itemCount = int(item.get("item_count") or 1)
|
||||
row.goodsType = int(item.get("goods_type") or 0)
|
||||
row.virtualType = int(item.get("virtual_type") or 0)
|
||||
req.items.append(row)
|
||||
req.pid = int(pid or 0)
|
||||
req.gameId = str(game_id or "0")
|
||||
req.src = 2
|
||||
req.orderType = 6
|
||||
extra = CreateOrderExtraParam()
|
||||
extra.bizParams = biz_params
|
||||
req.extraParam = extra
|
||||
req.sourceId = source_id
|
||||
req.env = self._build_order_env()
|
||||
req.orderScene = 3
|
||||
req.promotionParam = CreateOrderPromotionParam()
|
||||
req.accountParam = CreateOrderAccountParam()
|
||||
return await self.call_rpc(
|
||||
"shopMiddleUI",
|
||||
"createOrderV6",
|
||||
req,
|
||||
CreateOrderRspV6,
|
||||
timeout=15.0,
|
||||
)
|
||||
|
||||
async def pay_order_submit(
|
||||
self,
|
||||
uid: int,
|
||||
|
||||
Reference in New Issue
Block a user