Metadata-Version: 2.4
Name: py_wisharetec_toolkit
Version: 3.0.3
Summary: 浙江慧享科技有限公司 - 善数・慧享云运营平台 Python 扩展包，提供接口调用封装
Author-email: guolei <174000902@qq.com>
License: MIT
Project-URL: Homepage, https://gitee.com/guolei19850528/py_wisharetec_toolkit
Keywords: wisharetec,wisharetec_toolkit,shanshu,saas.wisharetec.com,saas toolkit
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.8
Classifier: Programming Language :: Python :: 3.9
Classifier: Programming Language :: Python :: 3.10
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Programming Language :: Python :: 3.13
Classifier: License :: OSI Approved :: MIT License
Classifier: Operating System :: OS Independent
Classifier: Intended Audience :: Developers
Classifier: Topic :: Software Development :: Libraries :: Python Modules
Requires-Python: >=3.8
Description-Content-Type: text/markdown
Requires-Dist: httpx>=0.24.0
Requires-Dist: pydantic>=2.0
Provides-Extra: dev
Requires-Dist: pytest>=7.0; extra == "dev"
Requires-Dist: pytest-asyncio>=0.23.0; extra == "dev"
Requires-Dist: black; extra == "dev"
Requires-Dist: ruff; extra == "dev"
Requires-Dist: python-dotenv>=1.0.0; extra == "dev"
Provides-Extra: cache
Requires-Dist: diskcache>=5.0; extra == "cache"
Requires-Dist: redis>=5.0; extra == "cache"

# py_wisharetec_toolkit

浙江慧享科技有限公司 - 善数・慧享云运营平台 Python 扩展包。

本包封装了善数・慧享云运营平台 (https://saas.wisharetec.com/) 的各类 API 接口，提供同步客户端 `ShanshuClient` 和异步客户端 `AsyncShanshuClient`，供他人调用。

**作者**：guolei <174000902@qq.com>  
**项目主页**：https://gitee.com/guolei19850528/py_wisharetec_toolkit

## 安装

### 推荐使用 uv 安装（推荐）

```bash
uv pip install py_wisharetec_toolkit
```

或从本地源码安装（开发模式）：

```bash
uv pip install -e .
```

带缓存依赖安装（diskcache / redis）：

```bash
uv pip install py_wisharetec_toolkit[cache]
```

或从本地源码安装（开发模式，带缓存依赖）：

```bash
uv pip install -e ".[cache]"
```

### 或者使用 pip 安装

```bash
pip install py_wisharetec_toolkit
```

或从本地源码安装（开发模式）：

```bash
pip install -e .
```

带缓存依赖安装（diskcache / redis）：

```bash
pip install py_wisharetec_toolkit[cache]
```

或从本地源码安装（开发模式，带缓存依赖）：

```bash
pip install -e ".[cache]"
```

## 配置

账号、密码等敏感信息统一通过环境变量（`.env` 文件）配置，请勿写入代码。

下文示例使用 `python-dotenv` 读取 `.env`，如未安装可执行：

```bash
pip install python-dotenv
```

在项目根目录创建 `.env` 文件并填写真实信息：

```dotenv
SHANSHU_BASE_URL=https://saas.wisharetec.com/
SHANSHU_ACCOUNT=your_account_here
SHANSHU_PASSWORD=your_password_here

# 空间树 ID（对应登录返回的 orgIds，可按需修改）
SHANSHU_SPACE_TREE_ID=73
```

## 快速开始

### 同步客户端

```python
import os
from pathlib import Path

from dotenv import load_dotenv

from py_wisharetec_toolkit.shanshu.auth import ShanshuDiskCacheTokenCache
from py_wisharetec_toolkit.shanshu.client import ShanshuClient
from py_wisharetec_toolkit.shanshu.models import ShanshuPageQueryParams

# 从本地 .env 文件读取账号和密码（不建议在代码中硬编码）
load_dotenv(dotenv_path=Path(__file__).parent / ".env")

base_url = os.environ.get(
    "SHANSHU_BASE_URL", "https://saas.wisharetec.com/"
)
account = os.environ["SHANSHU_ACCOUNT"]
password = os.environ["SHANSHU_PASSWORD"]
space_tree_id = os.environ.get("SHANSHU_SPACE_TREE_ID", "73")

# 创建客户端（token 自动缓存到 diskcache）
token_cache = ShanshuDiskCacheTokenCache(cache_dir=".runtime/cache/diskcache")
client = ShanshuClient(
    base_url=base_url,
    account=account,
    password=password,
    token_cache=token_cache,
)

# 登录
client.login(account, password)

# 查询园区档案
params = ShanshuPageQueryParams(
    conditions={
        "fields": [
            {"map": {}, "method": 1, "name": "spaceTreeId", "value": space_tree_id},
            {"map": {}, "method": 1, "name": "flag", "value": 0},
        ]
    },
    page_num=1,
    page_size=20,
)
resp = client.query_community_with_paginator(params=params)
print(resp.ok, resp.total, len(resp.records or []))

client.close()
```

### 异步客户端

```python
import asyncio
import os
from pathlib import Path

from dotenv import load_dotenv

from py_wisharetec_toolkit.shanshu.auth import ShanshuDiskCacheTokenCache
from py_wisharetec_toolkit.shanshu.client import AsyncShanshuClient
from py_wisharetec_toolkit.shanshu.models import ShanshuPageQueryParams


async def main() -> None:
    # 从本地 .env 文件读取账号和密码
    load_dotenv(dotenv_path=Path(__file__).parent / ".env")

    base_url = os.environ.get(
        "SHANSHU_BASE_URL", "https://saas.wisharetec.com/"
    )
    account = os.environ["SHANSHU_ACCOUNT"]
    password = os.environ["SHANSHU_PASSWORD"]
    space_tree_id = os.environ.get("SHANSHU_SPACE_TREE_ID", "73")

    token_cache = ShanshuDiskCacheTokenCache(cache_dir=".runtime/cache/diskcache")
    client = AsyncShanshuClient(
        base_url=base_url,
        account=account,
        password=password,
        token_cache=token_cache,
    )
    try:
        await client.async_login(account, password)

        params = ShanshuPageQueryParams(
            conditions={
                "fields": [
                    {"map": {}, "method": 1, "name": "spaceTreeId", "value": space_tree_id},
                    {"map": {}, "method": 1, "name": "flag", "value": 0},
                ]
            },
            page_num=1,
            page_size=20,
        )
        resp = await client.async_query_community_with_paginator(params=params)
        print(resp.ok, resp.total, len(resp.records or []))
    finally:
        await client.async_close()


asyncio.run(main())
```

## 已实现的接口

| 接口 | 方法 | 路径 | 返回模型 |
|------|------|------|----------|
| 登录 | `login` / `async_login` | `/api/user/loginInteractive` | `ShanshuLoginResponse` |
| 园区档案 | `query_community_with_paginator` / `async_query_community_with_paginator` | `/api/space/community/v2/frontPage` | `ShanshuCommunityPageResponse` |
| 房产档案 | `query_property_with_paginator` / `async_query_property_with_paginator` | `/api/space/property/propertyPage` | `ShanshuPropertyPageResponse` |
| 车场档案 | `query_yard_archive_with_paginator` / `async_query_yard_archive_with_paginator` | `/api/space/space/yardArchivePage` | `ShanshuYardArchivePageResponse` |
| 楼幢档案 | `query_building_with_paginator` / `async_query_building_with_paginator` | `/api/space/property/getSpaceBuildingPage` | `ShanshuBuildingPageResponse` |
| 住户档案 | `query_resident_with_paginator` / `async_query_resident_with_paginator` | `/api/user/residentInfo/getResidentPage` | `ShanshuResidentPageResponse` |
| 业主档案 | `query_archive_with_paginator` / `async_query_archive_with_paginator` | `/api/space/archive/examine/page` | `ShanshuArchivePageResponse` |
| 车辆档案 | `query_car_manage_with_paginator` / `async_query_car_manage_with_paginator` | `/api/space/carManage/pageCarManage` | `ShanshuCarManagePageResponse` |
| 车位档案 | `query_parking_with_paginator` / `async_query_parking_with_paginator` | `/api/space/parking/parkingPage` | `ShanshuParkingPageResponse` |
| 工单档案 | `query_work_order_with_paginator` / `async_query_work_order_with_paginator` | `/api/woreport/task/query/page` | `ShanshuWorkOrderPageResponse` |
| 商城订单 | `query_mall_order_with_paginator` / `async_query_mall_order_with_paginator` | `/api/retailmall/order/pageFront` | `ShanshuMallOrderPageResponse` |
| 服务订单 | `query_service_order_with_paginator` / `async_query_service_order_with_paginator` | `/api/houseserve/order/pageFront` | `ShanshuServiceOrderPageResponse` |
| 审批数据 | `query_approval_with_paginator` / `async_query_approval_with_paginator` | `/api/bpm/process/approval` | `ShanshuApprovalPageResponse` |
| 审批详情 | `query_approval_detail` / `async_query_approval_detail` | `/api/bpm/process/progress/{instance_id}/node_433279443693` | `ShanshuApprovalDetailRecord` |
| 业主详情 | `query_owner_detail` / `async_query_owner_detail` | `/api/space/archive/archive/detailSensitive` | `ShanshuOwnerDetailRecord` |

所有分页接口均使用 `ShanshuPageQueryParams` 模型封装查询参数，包含 `conditions`、`count`、`last`、`order_by`、`page_num`、`page_size` 字段。

### 接口注意事项

- 园区、房产、楼幢、车场、业主、车辆、车位、审批等接口的 `conditions` 需携带 `spaceTreeId` 与 `flag`。
- 住户档案接口需传入空条件：`conditions={}`；商城订单、服务订单接口需传入 `conditions={"fields": []}`（不能携带 `spaceTreeId`、`flag`，否则后端返回“系统内部报错”）。
- 工单档案接口要求 `conditions` 中额外携带 `appCode=WORK_ORDER`。
- 审批详情需先通过审批列表接口获取 `procInstId`，节点 ID 固定为 `node_433279443693`；业主详情需先获取 `userId` / `communityId` / `spaceId`，再调用详情接口。

## 示例代码

完整可运行示例位于 `examples/shanshu/`，覆盖全部接口的同步与异步调用，命名规则为 `example_*.py`（同步）与 `example_async_*.py`（异步）。

1. 复制模板并填写真实账号：

```bash
cp examples/shanshu/.env.example examples/shanshu/.env
```

2. 运行示例（以园区档案为例）：

```bash
python examples/shanshu/example_community_page.py
python examples/shanshu/example_async_community_page.py
```

公共配置与查询条件集中在 `examples/shanshu/example_common.py`，统一从 `examples/shanshu/.env` 读取 `SHANSHU_*` 变量。

## 运行测试

测试用例位于 `tests/shanshu/`，基于 pytest + pytest-asyncio，统一从 `tests/shanshu/.env` 读取配置，公共夹具定义在 `tests/shanshu/conftest.py`。

1. 复制模板并填写真实账号（也可以直接导出 `SHANSHU_*` 环境变量）：

```bash
cp tests/shanshu/.env.example tests/shanshu/.env
```

2. 安装测试依赖并运行：

```bash
uv pip install -e ".[dev,cache]"
pytest tests/shanshu -q
```

未配置 `SHANSHU_ACCOUNT` / `SHANSHU_PASSWORD` 时，测试会自动跳过。

## Token 缓存

客户端支持三种 Token 缓存后端：

- `ShanshuMemoryTokenCache`：进程内内存缓存（默认，无需额外依赖）
- `ShanshuDiskCacheTokenCache`：基于 diskcache 的持久化缓存（需安装 `[cache]` 依赖）
- `ShanshuRedisTokenCache`：基于 redis 的缓存（需安装 `[cache]` 依赖）

缓存 key 格式：`py_wisharetec_toolkit:shanshu:authorization:{account}`，便于缓存不同用户的登录 token。

## 目录结构

```text
src/py_wisharetec_toolkit/
├── __init__.py          # 顶层包
├── py.typed             # PEP 561 类型标记
└── shanshu/             # 子包，供他人调用
    ├── __init__.py
    ├── client.py        # 同步客户端 ShanshuClient 与异步客户端 AsyncShanshuClient
    ├── auth.py          # Token 缓存与认证
    └── models.py        # pydantic 响应模型

tests/
└── shanshu/
    ├── conftest.py      # 公共夹具（客户端、登录、查询条件）
    ├── .env.example     # 测试配置模板
    └── test_*.py        # 各接口的同步 / 异步测试用例

examples/
└── shanshu/
    ├── example_common.py     # 示例公共辅助（读取配置、构造客户端、查询条件）
    ├── .env.example          # 示例配置模板
    ├── example_*.py          # 各接口同步示例
    └── example_async_*.py    # 各接口异步示例
```

## 参数说明

所有分页查询接口均使用 `ShanshuPageQueryParams` 模型：

| 参数 | 类型 | 默认值 | 说明 |
|------|------|--------|------|
| conditions | dict\|None | None | 查询条件 |
| count | bool | True | 是否返回总记录数 |
| last | bool | True | 是否返回 last 标志 |
| order_by | list\|None | None | 排序字段列表 |
| page_num | int | 1 | 页码 |
| page_size | int | 20 | 每页大小 |

## 许可证

MIT License
