137 lines
5.2 KiB
Python
137 lines
5.2 KiB
Python
|
|
"""Fixture payloads for ``POST /pc/customer/smsLogsList`` (M4 SMS scraper).
|
||
|
|
|
||
|
|
These records mirror the real field names confirmed by Phase-0 + the data
|
||
|
|
dictionary §4 (短信记录 sms): ``id, customerPhone, sms(全文)/smsSub(预览),
|
||
|
|
sender, direction(0收/1发), userId, senderDepartment/senderDepartmentId,
|
||
|
|
receiveName, createTime(YYYY-MM-DD HH:MM), simPhone/simNumber, source``. Live
|
||
|
|
``dataCount`` is 53.
|
||
|
|
|
||
|
|
The envelope differs from the callLog + wechat shapes: the row list sits under
|
||
|
|
``data.data`` (same) but the declared row count is ``data.dataCount`` (NOT
|
||
|
|
``totalCount`` and NOT ``total``), and there is **no** ``pageCount``::
|
||
|
|
|
||
|
|
{"message":"调用成功","code":"10000","success":true,"traceId":"...",
|
||
|
|
"data":{"data":[...], "dataCount":.., "power":...}}
|
||
|
|
|
||
|
|
Because there is no ``pageCount``, the scraper relies solely on the empty-page
|
||
|
|
stop signal (advance ``pageNum`` until a page comes back with an empty
|
||
|
|
``data.data`` array).
|
||
|
|
|
||
|
|
The cassette ships three records across two pages so a test can drive the
|
||
|
|
page-number paginator across the empty-page stop signal:
|
||
|
|
|
||
|
|
* page 1 -> 2 of the 3 fixture records, ``dataCount=3``
|
||
|
|
* page 2 -> the remaining 1 record, ``dataCount=3``
|
||
|
|
* (page 3 -> empty ``data`` array, served inline by the test)
|
||
|
|
|
||
|
|
Records deliberately exercise the documented mapping edges:
|
||
|
|
|
||
|
|
* ``sms_3001`` — incoming SMS (``direction=0`` 收) with full + preview text.
|
||
|
|
* ``sms_3002`` — outgoing SMS (``direction=1`` 发) to a different customer.
|
||
|
|
* ``sms_3003`` — incoming SMS with an empty preview (exercises the
|
||
|
|
``content_preview`` None path; ``sms`` still carries the full text).
|
||
|
|
|
||
|
|
``createTime`` is a ``YYYY-MM-DD HH:MM`` datetime string (NO seconds — one
|
||
|
|
format precision shorter than the callLog's ``startCallTime``); the scraper
|
||
|
|
parses it to a ms-epoch int treating the missing seconds as ``:00``.
|
||
|
|
"""
|
||
|
|
|
||
|
|
# The module name mirrors the upstream endpoint name (``smsLogsList`` ->
|
||
|
|
# ``smsLogs``); the M4 spec uses this naming family.
|
||
|
|
# ruff: noqa: N999
|
||
|
|
|
||
|
|
from __future__ import annotations
|
||
|
|
|
||
|
|
from typing import Any
|
||
|
|
|
||
|
|
# ---------------------------------------------------------------------------
|
||
|
|
# Capture-shaped SMS records (3 total across 2 pages: page1=2, page2=1).
|
||
|
|
# ---------------------------------------------------------------------------
|
||
|
|
|
||
|
|
SMS_RECORDS: list[dict[str, Any]] = [
|
||
|
|
{
|
||
|
|
# Incoming SMS (0=收) with full + preview text.
|
||
|
|
"id": "sms_3001",
|
||
|
|
"customerPhone": "8613800000001",
|
||
|
|
"sms": "您好,我在网上看到您的产品介绍,想了解一下价格和详情,方便回电吗?",
|
||
|
|
"smsSub": "您好,我在网上看到您的产品介绍...",
|
||
|
|
"sender": "8613800000001",
|
||
|
|
"direction": 0, # 0=收 (incoming)
|
||
|
|
"userId": "staff_user_001",
|
||
|
|
"senderDepartment": "销售一部",
|
||
|
|
"senderDepartmentId": "dept_sales_east",
|
||
|
|
"receiveName": "Alice Wang",
|
||
|
|
"createTime": "2026-01-15 10:30", # YYYY-MM-DD HH:MM (no seconds)
|
||
|
|
"simPhone": "8613800000111",
|
||
|
|
"simNumber": "8986000112345678901",
|
||
|
|
"source": "card",
|
||
|
|
},
|
||
|
|
{
|
||
|
|
# Outgoing SMS (1=发) to a different customer.
|
||
|
|
"id": "sms_3002",
|
||
|
|
"customerPhone": "8613800000002",
|
||
|
|
"sms": "王先生您好,这是您咨询的订单详情,请查收附件。",
|
||
|
|
"smsSub": "王先生您好,这是您咨询的订单详情...",
|
||
|
|
"sender": "system",
|
||
|
|
"direction": 1, # 1=发 (outgoing)
|
||
|
|
"userId": "staff_user_002",
|
||
|
|
"senderDepartment": "销售二部",
|
||
|
|
"senderDepartmentId": "dept_sales_west",
|
||
|
|
"receiveName": "Bob Chen",
|
||
|
|
"createTime": "2026-01-15 11:00",
|
||
|
|
"simPhone": "8613800000222",
|
||
|
|
"simNumber": "8986000223456789012",
|
||
|
|
"source": "manual",
|
||
|
|
},
|
||
|
|
{
|
||
|
|
# Incoming SMS with an EMPTY preview (content_preview None path).
|
||
|
|
"id": "sms_3003",
|
||
|
|
"customerPhone": "8613800000003",
|
||
|
|
"sms": "好的,收到。",
|
||
|
|
"smsSub": "", # empty preview -> content_preview None
|
||
|
|
"sender": "8613800000003",
|
||
|
|
"direction": 0, # incoming
|
||
|
|
"userId": "staff_user_001",
|
||
|
|
"senderDepartment": "销售一部",
|
||
|
|
"senderDepartmentId": "dept_sales_east",
|
||
|
|
"receiveName": "Alice Wang",
|
||
|
|
"createTime": "2026-01-16 09:00",
|
||
|
|
"simPhone": "8613800000111",
|
||
|
|
"simNumber": "8986000112345678901",
|
||
|
|
"source": "reply",
|
||
|
|
},
|
||
|
|
]
|
||
|
|
|
||
|
|
# Default page size for the fixture (and the scraper). dataCount=3 with
|
||
|
|
# page_size=2 fills page 1 (2 records) + page 2 (1 record) + a terminating
|
||
|
|
# empty page.
|
||
|
|
DATA_COUNT = len(SMS_RECORDS)
|
||
|
|
DEFAULT_PAGE_SIZE = 2
|
||
|
|
|
||
|
|
|
||
|
|
def make_sms_logs_response(
|
||
|
|
records: list[dict[str, Any]],
|
||
|
|
*,
|
||
|
|
data_count: int,
|
||
|
|
trace_id: str | None = None,
|
||
|
|
) -> dict[str, Any]:
|
||
|
|
"""Build a capture-shaped ``smsLogsList`` response envelope.
|
||
|
|
|
||
|
|
Shape (row list under ``data.data``; row count on ``data.dataCount``;
|
||
|
|
no ``pageCount`` / ``pageNum``)::
|
||
|
|
|
||
|
|
{"message":"调用成功","code":"10000","success":true,"traceId":"...",
|
||
|
|
"data":{"data":[...], "dataCount":.., "power":true}}
|
||
|
|
"""
|
||
|
|
return {
|
||
|
|
"message": "调用成功",
|
||
|
|
"code": "10000",
|
||
|
|
"success": True,
|
||
|
|
"traceId": trace_id or "trace-1",
|
||
|
|
"data": {
|
||
|
|
"data": list(records),
|
||
|
|
"dataCount": data_count,
|
||
|
|
"power": True,
|
||
|
|
},
|
||
|
|
}
|