Metadata-Version: 2.5
Name: py-wisharetec-toolkit
Version: 4.0.2
Summary: Wisharetec Python Toolkit / 善数 Python 工具包
Project-URL: HomePage, https://gitee.com/guolei19850528/py_wisharetec_toolkit
Project-URL: Repository, https://gitee.com/guolei19850528/py_wisharetec_toolkit
Author-email: 郭磊 <174000902@qq.com>
License: MIT
License-File: LICENSE
Keywords: api,python,toolkit,wisharetec,善数,物业管理
Classifier: Development Status :: 4 - Beta
Classifier: Intended Audience :: Developers
Classifier: License :: OSI Approved :: MIT License
Classifier: Operating System :: OS Independent
Classifier: Programming Language :: Python
Classifier: Programming Language :: Python :: 3
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: Topic :: Software Development :: Libraries :: Python Modules
Classifier: Typing :: Typed
Requires-Python: >=3.9
Requires-Dist: diskcache>=5.6.0
Requires-Dist: httpx<1.0,>=0.24.0
Requires-Dist: pydantic<3.0,>=2.0.0
Requires-Dist: redis>=5.0.0
Provides-Extra: all
Requires-Dist: mkdocs-material>=9.0.0; extra == 'all'
Requires-Dist: mkdocs>=1.5.0; extra == 'all'
Requires-Dist: mypy>=1.10.0; extra == 'all'
Requires-Dist: pre-commit>=3.7.0; extra == 'all'
Requires-Dist: pytest-asyncio>=0.23.0; extra == 'all'
Requires-Dist: pytest-cov>=5.0.0; extra == 'all'
Requires-Dist: pytest>=8.0.0; extra == 'all'
Requires-Dist: python-dotenv>=1.0.0; extra == 'all'
Requires-Dist: respx>=0.21.0; extra == 'all'
Requires-Dist: ruff>=0.8.0; extra == 'all'
Provides-Extra: dev
Requires-Dist: mypy>=1.10.0; extra == 'dev'
Requires-Dist: pre-commit>=3.7.0; extra == 'dev'
Requires-Dist: python-dotenv>=1.0.0; extra == 'dev'
Requires-Dist: ruff>=0.8.0; extra == 'dev'
Provides-Extra: docs
Requires-Dist: mkdocs-material>=9.0.0; extra == 'docs'
Requires-Dist: mkdocs>=1.5.0; extra == 'docs'
Provides-Extra: test
Requires-Dist: pytest-asyncio>=0.23.0; extra == 'test'
Requires-Dist: pytest-cov>=5.0.0; extra == 'test'
Requires-Dist: pytest>=8.0.0; extra == 'test'
Requires-Dist: python-dotenv>=1.0.0; extra == 'test'
Requires-Dist: respx>=0.21.0; extra == 'test'
Description-Content-Type: text/markdown

# py-wisharetec-toolkit

[![License: MIT](https://img.shields.io/badge/license-MIT-blue.svg)](LICENSE)

中文 | [English](./README_EN.md)

文档：
- [httpx](https://pypi.org/project/httpx/)
- [pydantic](https://pypi.org/project/pydantic/)
- [diskcache](https://pypi.org/project/diskcache/)
- [redis](https://pypi.org/project/redis/)

## 项目介绍

**py-wisharetec-toolkit** 是善数（Wisharetec / 善数）开放平台的 Python SDK 工具包，提供同步与异步客户端，支持 access_token 获取与缓存，以及社区、楼栋/房源、车辆、车位、居民、业主、工单、审批、商城订单、服务订单、车场等接口的分页查询与详情查询。

## 软件架构

```
py_wisharetec_toolkit/
├── shanshu/
│   ├── __init__.py
│   ├── client.py           # Client（同步）与 AsyncClient（异步）客户端
│   ├── cache.py            # 缓存抽象类及内存/diskcache/Redis 实现
│   ├── exception.py        # ConfigError 与 NetworkError 异常
│   ├── request.py          # QueryWithPaginatorPayload 分页请求参数模型
│   └── response.py         # 各接口响应 Pydantic 模型
```

### 主要类与方法

| 类 | 说明 |
|------|----------|
| `Client` | 同步客户端，支持 `get_authorization()` 及各 `query_*` 接口 |
| `AsyncClient` | 异步客户端，支持 `get_authorization()` 及各 `query_*` 接口 |
| `AuthorizationCache` | 缓存抽象基类，可扩展自定义缓存 |
| `AuthorizationMemoryCache` | 内存缓存实现，无第三方依赖 |
| `AuthorizationDiskcacheCache` | 基于 diskcache 的缓存实现（默认） |
| `AuthorizationRedisCache` | 基于 redis 的缓存实现 |

### 支持的接口

| 模块 | 分页查询方法 | 详情查询方法 |
|------|-------------|-------------|
| 社区 | `query_community_with_paginator` | `query_community_detail` |
| 楼栋/房源 | `query_building_with_paginator` | `query_property_detail` |
| 空间楼栋 | `query_space_building_with_paginator` | `query_space_building_detail` |
| 车辆 | `query_car_with_paginator` | `query_car_detail` |
| 车位 | `query_parking_space_with_paginator` | `query_parking_space_detail` |
| 居民 | `query_resident_with_paginator` | `query_resident_info` |
| 业主 | `query_owner_with_paginator` | `query_owner_detail_sensitive` |
| 工单 | `query_work_order_with_paginator`、`query_work_order_list_with_status` | `query_work_order_detail` |
| 工单回访 | `query_work_order_revisit_with_paginator` | `query_work_order_revisit_detail` |
| 商城订单 | `query_mall_order_with_paginator` | `query_mall_order_detail` |
| 服务订单 | `query_service_order_with_paginator` | `query_service_order_detail` |
| 审批 | `query_approval_with_paginator` | `query_approval_detail` |
| 车场 | `query_yard_archive_page` | `query_yard_archive_detail` |

## 安装方式

推荐使用 **uv** 安装：

```bash
# 使用 uv 安装（推荐）
uv pip install py-wisharetec-toolkit

# 或使用 pip 安装
pip install py-wisharetec-toolkit

# 安装开发/测试依赖（uv）
uv pip install "py-wisharetec-toolkit[dev,test]"

# 安装开发/测试依赖（pip）
pip install "py-wisharetec-toolkit[dev,test]"
```

## 使用说明

### 1. 环境变量配置

将 `examples/shanshu/.env.example` 复制为 `.env` 并填写真实账号密码：

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

`.env` 示例：

```ini
ACCOUNT=your_account
PASSWORD=your_password
BASE_URL=https://saas.wisharetec.com/
TIMEOUT=30.0
```

### 2. 获取 authorization（同步）

```python
from py_wisharetec_toolkit.shanshu.client import Client

client = Client(
    account="your_account",
    password="your_password",
)

token = client.get_authorization()
print(token)

client.close()
```

或使用上下文管理器自动关闭：

```python
from py_wisharetec_toolkit.shanshu.client import Client

with Client(account="your_account", password="your_password") as client:
    token = client.get_authorization()
    print(token)
```

### 3. 获取 authorization（异步）

```python
import asyncio
from py_wisharetec_toolkit.shanshu.client import AsyncClient


async def main():
    async with AsyncClient(
        account="your_account",
        password="your_password",
    ) as client:
        token = await client.get_authorization()
        print(token)


asyncio.run(main())
```

### 4. 查询社区分页列表（同步）

```python
from py_wisharetec_toolkit.shanshu.client import Client

client = Client(
    account="your_account",
    password="your_password",
)

payload = {
    "conditions": {
        "fields": [
            {"map": {}, "method": 1, "name": "scene", "value": 1},
            {"map": {}, "method": 1, "name": "spaceTreeId", "value": "73"},
            {"map": {}, "method": 1, "name": "flag", "value": 0},
        ]
    },
    "count": True,
    "last": True,
    "orderBy": [],
    "pageNum": 1,
    "pageSize": 20,
}

resp = client.query_community_with_paginator(payload=payload)
print(resp.model_dump())

# 取第一条记录的 id 查询社区详情
records = resp.model_dump().get("records", [])
if records:
    community_id = records[0]["id"]
    detail = client.query_community_detail(id=community_id)
    print(detail.model_dump())

client.close()
```

### 5. 查询车辆分页列表（同步）

```python
payload = {
    "conditions": {
        "fields": [
            {"map": {}, "method": 1, "name": "owner_type", "value": "1"},
            {"map": {}, "method": 1, "name": "spaceTreeId", "value": "73"},
            {"map": {}, "method": 1, "name": "flag", "value": 0},
        ]
    },
    "count": True,
    "last": True,
    "orderBy": [],
    "pageNum": 1,
    "pageSize": 20,
}

resp = client.query_car_with_paginator(payload=payload)
print(resp.model_dump())

if records := resp.model_dump().get("records", []):
    car_id = records[0]["id"]
    detail = client.query_car_detail(id=car_id)
    print(detail.model_dump())
```

### 6. 查询业主敏感详情（同步）

```python
resp = client.query_owner_with_paginator(payload=payload)
records = resp.model_dump().get("records", [])
if records:
    detail_id = records[0]["id"]
    community_id = records[0].get("communityId") or records[0].get("community_id")
    space_id = records[0].get("spaceId") or records[0].get("space_id")
    detail = client.query_owner_detail_sensitive(
        user_id=detail_id,
        community_id=community_id,
        space_id=space_id,
    )
    print(detail.model_dump())
```

### 7. 查询工单回访分页列表与详情（异步）

```python
import asyncio
from py_wisharetec_toolkit.shanshu.client import AsyncClient

payload = {
    "conditions": {
        "fields": [
            {"map": {}, "method": 1, "name": "appCode", "value": "WORK_ORDER_REVISIT"},
        ]
    },
    "count": False,
    "last": False,
    "orderBy": [],
    "pageNum": 1,
    "pageSize": 20,
}


async def main():
    async with AsyncClient(
        account="your_account",
        password="your_password",
    ) as client:
        resp = await client.query_work_order_revisit_with_paginator(
            payload=payload
        )
        print(resp.model_dump())

        records = resp.model_dump().get("records", [])
        if records:
            proc_inst_id = records[0].get("procInstId")
            if proc_inst_id:
                detail = await client.query_work_order_revisit_detail(
                    proc_inst_id=proc_inst_id
                )
                print(detail.model_dump())


asyncio.run(main())
```

### 8. 更多示例

`examples/shanshu/` 目录下提供了所有接口的完整示例代码，可直接运行：

| 示例文件 | 对应接口 |
|----------|----------|
| `get_authorization.py` | 获取 authorization |
| `query_approval.py` | 审批分页列表 / 审批详情 |
| `query_building.py` | 楼栋/房源分页列表 / 楼栋/房源详情 |
| `query_car.py` | 车辆分页列表 / 车辆详情 |
| `query_community.py` | 社区分页列表 / 社区详情 |
| `query_mall_order.py` | 商城订单分页列表 / 商城订单详情 |
| `query_owner.py` | 业主分页列表 / 业主敏感详情 |
| `query_parking_space.py` | 车位分页列表 / 车位详情 |
| `query_resident.py` | 居民分页列表 / 居民详情 |
| `query_service_order.py` | 服务订单分页列表 / 服务订单详情 |
| `query_space_building.py` | 空间楼栋分页列表 / 空间楼栋详情 |
| `query_work_order.py` | 工单分页列表 / 工单动态列表 |
| `query_work_order_revisit.py` | 工单回访分页列表 / 工单回访详情 |
| `query_yard_archive.py` | 车场分页列表 / 车场详情 |

运行示例前，请先配置好 `examples/shanshu/.env` 文件中的 `ACCOUNT` 与 `PASSWORD`。

## 贡献指南

欢迎参与贡献！贡献流程如下：

1. Fork 本仓库到你的个人账号
2. 创建特性分支：`git checkout -b feature/your-feature`
3. 提交你的修改：`git commit -m "feat: add your feature"`
4. 推送到分支：`git push origin feature/your-feature`
5. 提交合并请求（Merge Request）

提交前请确保：
- 代码通过 `ruff` 代码规范检查
- 代码通过 `mypy` 类型检查
- 单元测试通过：`pytest`
- 遵循现有代码风格与注释规范

## 作者信息

- 作者：郭磊
- 邮箱：174000902@qq.com

## 许可证

[MIT License](LICENSE)
