import json from cart_add import KIND_BUSINESS, KIND_OK, KIND_SYSTEM, classify_mall_message from cart_match import CartOffer from cart_yaoex import YAOEX_ADD_URL, add_yaoex_cart from cart_ybm import YBM_ADD_URL, add_ybm_cart class FakeAuth: token = "tok" user_id = "u1" buyer_code = "b1" class FakeResponse: def __init__(self, json_data=None, status_code=200, text=""): self._json = json_data self.status_code = status_code self.text = text or str(json_data) self.headers = {"content-type": "application/json"} def raise_for_status(self): if self.status_code >= 400: raise RuntimeError(f"HTTP {self.status_code}") def json(self): if self._json is None: raise ValueError("not json") return self._json class FakeSession: def __init__(self, response: FakeResponse): self.response = response self.calls: list[dict] = [] def post(self, url, data=None, json=None, headers=None, timeout=None, verify=None, params=None): self.calls.append( { "url": url, "data": data, "json": json, "headers": headers, "params": params, } ) return self.response def close(self): return None def _offer(**overrides) -> CartOffer: extra = overrides.pop( "extra", { "raw": { "spuCode": "SPU66", "frontSellerCode": 8353, "sellerCode": "GD01", } }, ) data = dict( sku_id="SPU66", vendor_raw="广东壹号药业有限公司", vendor_norm="广东壹号药业有限公司", stock=20.0, price=90.0, extra=extra, ) data.update(overrides) return CartOffer(**data) def test_classify_pack_and_stock_and_ok(): pack = classify_mall_message("加入失败,数量须为中包装倍数") assert pack.kind == KIND_BUSINESS assert "中包装" in pack.reason stock = classify_mall_message("库存不足") assert stock.kind == KIND_BUSINESS assert stock.reason == "库存不足" ok = classify_mall_message("加入购物车成功") assert ok.kind == KIND_OK def test_yaoex_add_posts_token_and_qty(): session = FakeSession(FakeResponse({"code": 0, "msg": "成功"})) outcome = add_yaoex_cart(FakeAuth(), _offer(), 7, session=session) assert outcome.kind == KIND_OK assert session.calls[0]["url"] == YAOEX_ADD_URL assert session.calls[0]["params"]["token"] == "tok" payload = session.calls[0]["data"] assert payload["token"] == "tok" assert payload["userToken"] == "tok" assert payload["addType"] == "1" assert payload["sourceType"] == 17052 items = json.loads(payload["itemList"]) assert items[0]["productNum"] == 7 assert items[0]["spuCode"] == "SPU66" assert items[0]["supplyId"] == 8353 # 网关按 cartResponseList 回库存不足时记业务失败。 def test_yaoex_add_stock_message_from_cart_list(): session = FakeSession( FakeResponse( { "rtn_code": "0", "data": { "statusCode": 1, "cartResponseList": [{"message": "库存不足", "spuCode": "SPU66"}], }, } ) ) outcome = add_yaoex_cart(FakeAuth(), _offer(), 1, session=session) assert outcome.kind == KIND_BUSINESS assert outcome.reason == "库存不足" def test_yaoex_add_classifies_pack_error(): session = FakeSession(FakeResponse({"code": 1, "msg": "数量必须是中包装的倍数"})) outcome = add_yaoex_cart(FakeAuth(), _offer(), 7, session=session) assert outcome.kind == KIND_BUSINESS assert "中包装" in outcome.reason def test_ybm_add_posts_sku_and_qty(): session = FakeSession(FakeResponse({"success": True, "code": 200, "msg": "操作成功"})) offer = _offer(sku_id="SKU48", extra={"raw": {"skuId": "SKU48"}}) outcome = add_ybm_cart({"SESSION": "c1"}, offer, 3, session=session) assert outcome.kind == KIND_OK assert session.calls[0]["url"] == YBM_ADD_URL assert YBM_ADD_URL.endswith("/new-front/cart/change-cart") body = session.calls[0]["json"] assert body["skuId"] == "SKU48" assert body["amount"] == 3 assert body["direct"] == 1 # 现行口成功时 data.message 可能带中包装提示,仍按加车成功。 def test_ybm_success_keeps_pack_hint_as_ok(): session = FakeSession( FakeResponse( { "success": True, "code": 200, "msg": "操作成功", "data": {"message": "中包装验证:只能按照500的倍数购买", "qty": 500}, } ) ) outcome = add_ybm_cart({}, _offer(extra={"raw": {"skuId": "X"}}), 5, session=session) assert outcome.kind == KIND_OK def test_ybm_http_error_is_system_fail(): session = FakeSession(FakeResponse(json_data=None, status_code=500, text="bad")) outcome = add_ybm_cart({}, _offer(extra={"raw": {"skuId": "X"}}), 1, session=session) assert outcome.kind == KIND_SYSTEM