"""Fixture payloads for ``POST /wechatweb/wxUser/list`` (Task 2.1). These records mirror the real field names captured from the live CRM (see the data dictionary §2: ``wechatId, nickName, alias, phone, userId, userName(员工真名), contactsNum, groupNum, sendNum/receiveNum, isOnJob, dbSize, 在线状态, lastUpdate``; total=55). The REQUEST is **form-urlencoded** (NOT JSON): the endpoint binds Spring ``@RequestParam`` from the form body and REQUIRES ``isOnJob`` / ``departmentId`` (the company-root dept id) / ``startdate`` / ``enddate`` or it answers ``code -90000`` ("缺少..."). ``userId`` / ``salesname`` / ``weChatNickName`` are sent empty to mirror the real client. The RESPONSE envelope differs from ``wxFriends/friend_list/es``: there is **no** ``basicResult`` wrapper. The pagination fields sit directly under ``data``:: {"code":"10000","data":{"data":[...], "total":.., "pageNum":.., "pageSize":..}} The cassette ships two pages so a test can drive the page-number paginator across the empty-page stop signal: * page 1 -> 2 of the 4 fixture records, ``total=4`` * page 2 -> the other 2 records, ``total=4`` * (page 3 -> empty ``data`` array, served inline by the test) Records carry every field with a target ``WechatAccount`` column so the test can assert a full mapping end-to-end, plus the embedded ``userId``+``userName`` staff pair (the owning employee) so the embedded-staff repo upsert can be exercised against capture-shaped input. """ # The module name uses camelCase deliberately to mirror the upstream endpoint # name (``wxUser``); the Task 2.1 spec mandates this exact filename. # ruff: noqa: N999 from __future__ import annotations from typing import Any # --------------------------------------------------------------------------- # Capture-shaped WeChat staff-account records (4 total across 2 pages). # --------------------------------------------------------------------------- WXUSER_RECORDS: list[dict[str, Any]] = [ { "wechatId": "wxid_staff_alice01", "nickName": "Alice WeChat", "alias": "alice_wx", "phone": "13800000001", "userId": "staff_user_001", "userName": "Alice Wang", "contactsNum": 312, "groupNum": 18, "sendNum": 1204, "receiveNum": 2387, "isOnJob": 1, "dbSize": 482103, "onlineStatus": "online", "headImageUrl": "https://wx.qlogo.cn/avatar_alice.png", "lastUpdate": 1700000000123, "version": "v1.20260731.alice", }, { "wechatId": "wxid_staff_bob02", "nickName": "Bob WeChat", "alias": "bob_wx", "phone": "13800000002", "userId": "staff_user_002", "userName": "Bob Chen", "contactsNum": 87, "groupNum": 4, "sendNum": 211, "receiveNum": 402, "isOnJob": 1, "dbSize": 91205, "onlineStatus": "offline", "headImageUrl": "https://wx.qlogo.cn/avatar_bob.png", "lastUpdate": 1700000000456, "version": "v1.20260731.bob", }, { "wechatId": "wxid_staff_carol03", "nickName": "Carol We Chat", "alias": "carol_wx", "phone": "13800000003", "userId": "staff_user_003", "userName": "Carol Liu", "contactsNum": 1502, "groupNum": 72, "sendNum": 9034, "receiveNum": 11245, "isOnJob": 0, # departed staff — exercises the falsy isOnJob path "dbSize": 2_100_445, "onlineStatus": "offline", "headImageUrl": "https://wx.qlogo.cn/avatar_carol.png", "lastUpdate": 1700000000789, "version": "v1.20260731.carol", }, { # Account with NO embedded staff (userId missing) — the scraper must # still yield it; the embedded-staff repo upsert must skip it cleanly. "wechatId": "wxid_staff_orphan04", "nickName": "Orphan WeChat", "alias": "orphan_wx", "phone": "13800000004", "userId": None, "userName": None, "contactsNum": 5, "groupNum": 0, "sendNum": 1, "receiveNum": 2, "isOnJob": 0, "dbSize": 1024, "onlineStatus": "offline", "headImageUrl": "https://wx.qlogo.cn/avatar_orphan.png", "lastUpdate": 1700000001000, "version": "v1.20260731.orphan", }, ] # Default page size for the fixture (and the scraper). total=4 means the # fixture fills exactly 2 pages of size 2 plus a terminating empty page. TOTAL = len(WXUSER_RECORDS) DEFAULT_PAGE_SIZE = 2 def make_wxuser_list_response( records: list[dict[str, Any]], *, total: int, page_num: int = 1, page_size: int = DEFAULT_PAGE_SIZE, trace_id: str | None = None, ) -> dict[str, Any]: """Build a capture-shaped ``wxUser/list`` response envelope. Shape (no ``basicResult`` wrapper):: {"message":"调用成功","code":"10000","success":true,"traceId":"...", "data":{"data":[...], "total":.., "pageNum":.., "pageSize":..}} """ return { "message": "调用成功", "code": "10000", "success": True, "traceId": trace_id or f"trace-{page_num}", "data": { "data": list(records), "total": total, "pageNum": page_num, "pageSize": page_size, }, }