ddclient 0.1.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- ddclient-0.1.0/PKG-INFO +61 -0
- ddclient-0.1.0/README.md +49 -0
- ddclient-0.1.0/pyproject.toml +23 -0
- ddclient-0.1.0/src/ddclient/__init__.py +9 -0
- ddclient-0.1.0/src/ddclient/contact.py +60 -0
- ddclient-0.1.0/src/ddclient/core.py +126 -0
- ddclient-0.1.0/src/ddclient/py.typed +0 -0
- ddclient-0.1.0/src/ddclient/yida.py +175 -0
ddclient-0.1.0/PKG-INFO
ADDED
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
Metadata-Version: 2.3
|
|
2
|
+
Name: ddclient
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: 钉钉开放平台服务端接口调用客户端
|
|
5
|
+
Author: luyifo
|
|
6
|
+
Author-email: luyifo <luyifo@163.com>
|
|
7
|
+
Requires-Dist: httpx>=0.28.1
|
|
8
|
+
Requires-Dist: pydantic>=2.12.5
|
|
9
|
+
Requires-Dist: pydantic-settings>=2.12.0
|
|
10
|
+
Requires-Python: >=3.12
|
|
11
|
+
Description-Content-Type: text/markdown
|
|
12
|
+
|
|
13
|
+
# 使用指导
|
|
14
|
+
## Step 1
|
|
15
|
+
```bash
|
|
16
|
+
pip install ddapi
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
## Step 2
|
|
20
|
+
在项目根目录下新建.env文件
|
|
21
|
+
配置环境变量
|
|
22
|
+
```toml
|
|
23
|
+
DINGTALK_APP_KEY="xxxxxxxx"
|
|
24
|
+
DINGTALK_APP_SECRET="xxxxxxxx"
|
|
25
|
+
```
|
|
26
|
+
用你能想到的方法加载.env中的配置好的环境变量
|
|
27
|
+
|
|
28
|
+
## Step 3
|
|
29
|
+
|
|
30
|
+
```python
|
|
31
|
+
from ddapi import default_client as client
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
## 宜搭
|
|
35
|
+
配置环境变量
|
|
36
|
+
```toml
|
|
37
|
+
DINGTALK_APP_KEY="xxxxxxxx"
|
|
38
|
+
DINGTALK_APP_SECRET="xxxxxxxx"
|
|
39
|
+
DINGTALK_YIDA_APP_TYPE="xxxxxx"
|
|
40
|
+
DINGTALK_YIDA_SYSTEM_TOKEN="xxxxxx"
|
|
41
|
+
DINGTALK_USER_ID="xxxxxx"
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
### 默认使用
|
|
45
|
+
```python
|
|
46
|
+
from ddapi import default_client as client
|
|
47
|
+
|
|
48
|
+
form_instance = client.yida.get_form_inst("FINST-XXXXXXX")
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
### 多应用
|
|
52
|
+
```python
|
|
53
|
+
from ddapi import default_client as client,YiDa,YiDaConfig
|
|
54
|
+
|
|
55
|
+
yida1 = YiDa(client,YiDaConfig(app_type="app_type1",system_token="system_token1",user_id="user_id1"))
|
|
56
|
+
form_inst1 = yida1.get_form_inst("INST_ID")
|
|
57
|
+
|
|
58
|
+
yida2 = YiDa(client,YiDaConfig(app_type="app_type2",system_token="system_token2",user_id="user_id2"))
|
|
59
|
+
form_inst2 = yida2.get_form_inst("INST_ID")
|
|
60
|
+
|
|
61
|
+
```
|
ddclient-0.1.0/README.md
ADDED
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
# 使用指导
|
|
2
|
+
## Step 1
|
|
3
|
+
```bash
|
|
4
|
+
pip install ddapi
|
|
5
|
+
```
|
|
6
|
+
|
|
7
|
+
## Step 2
|
|
8
|
+
在项目根目录下新建.env文件
|
|
9
|
+
配置环境变量
|
|
10
|
+
```toml
|
|
11
|
+
DINGTALK_APP_KEY="xxxxxxxx"
|
|
12
|
+
DINGTALK_APP_SECRET="xxxxxxxx"
|
|
13
|
+
```
|
|
14
|
+
用你能想到的方法加载.env中的配置好的环境变量
|
|
15
|
+
|
|
16
|
+
## Step 3
|
|
17
|
+
|
|
18
|
+
```python
|
|
19
|
+
from ddapi import default_client as client
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
## 宜搭
|
|
23
|
+
配置环境变量
|
|
24
|
+
```toml
|
|
25
|
+
DINGTALK_APP_KEY="xxxxxxxx"
|
|
26
|
+
DINGTALK_APP_SECRET="xxxxxxxx"
|
|
27
|
+
DINGTALK_YIDA_APP_TYPE="xxxxxx"
|
|
28
|
+
DINGTALK_YIDA_SYSTEM_TOKEN="xxxxxx"
|
|
29
|
+
DINGTALK_USER_ID="xxxxxx"
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
### 默认使用
|
|
33
|
+
```python
|
|
34
|
+
from ddapi import default_client as client
|
|
35
|
+
|
|
36
|
+
form_instance = client.yida.get_form_inst("FINST-XXXXXXX")
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
### 多应用
|
|
40
|
+
```python
|
|
41
|
+
from ddapi import default_client as client,YiDa,YiDaConfig
|
|
42
|
+
|
|
43
|
+
yida1 = YiDa(client,YiDaConfig(app_type="app_type1",system_token="system_token1",user_id="user_id1"))
|
|
44
|
+
form_inst1 = yida1.get_form_inst("INST_ID")
|
|
45
|
+
|
|
46
|
+
yida2 = YiDa(client,YiDaConfig(app_type="app_type2",system_token="system_token2",user_id="user_id2"))
|
|
47
|
+
form_inst2 = yida2.get_form_inst("INST_ID")
|
|
48
|
+
|
|
49
|
+
```
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
[project]
|
|
2
|
+
name = "ddclient"
|
|
3
|
+
version = "0.1.0"
|
|
4
|
+
description = "钉钉开放平台服务端接口调用客户端"
|
|
5
|
+
readme = "README.md"
|
|
6
|
+
authors = [
|
|
7
|
+
{ name = "luyifo", email = "luyifo@163.com" }
|
|
8
|
+
]
|
|
9
|
+
requires-python = ">=3.12"
|
|
10
|
+
dependencies = [
|
|
11
|
+
"httpx>=0.28.1",
|
|
12
|
+
"pydantic>=2.12.5",
|
|
13
|
+
"pydantic-settings>=2.12.0",
|
|
14
|
+
]
|
|
15
|
+
|
|
16
|
+
[build-system]
|
|
17
|
+
requires = ["uv_build>=0.9.18,<0.10.0"]
|
|
18
|
+
build-backend = "uv_build"
|
|
19
|
+
|
|
20
|
+
[dependency-groups]
|
|
21
|
+
dev = [
|
|
22
|
+
"pytest>=9.0.2",
|
|
23
|
+
]
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
from .core import DingTalkClient, DingTalkConfig
|
|
2
|
+
from .yida import YiDa,YiDaConfig
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
_default_config = DingTalkConfig()
|
|
6
|
+
|
|
7
|
+
default_client = DingTalkClient(_default_config)
|
|
8
|
+
|
|
9
|
+
__all__ = ["DingTalkClient", "DingTalkConfig", "default_client","YiDa","YiDaConfig"]
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
from typing import TYPE_CHECKING, Any
|
|
4
|
+
|
|
5
|
+
if TYPE_CHECKING:
|
|
6
|
+
from .core import DingTalkClient
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
class Contact:
|
|
10
|
+
def __init__(self, client: DingTalkClient) -> None:
|
|
11
|
+
self.client = client
|
|
12
|
+
|
|
13
|
+
def get_dept_list(self, dept_id: int = 1, lang: str = "zh_CN") -> dict[str, Any]:
|
|
14
|
+
"""
|
|
15
|
+
获取部门列表
|
|
16
|
+
https://open.dingtalk.com/document/development/user-management-acquires-the-list-departments
|
|
17
|
+
|
|
18
|
+
:param dept_id: 部门ID
|
|
19
|
+
:param lang: 语言 zh_CN en_US
|
|
20
|
+
:return {"errcode":0,"errmsg":"ok","result":[{"auto_add_user":true,"create_dept_group":true,"dept_id":37xxxx95,"name":"市场部","parent_id":1}],"request_id":"5um7ykyaalsj"}:
|
|
21
|
+
"""
|
|
22
|
+
url = "https://oapi.dingtalk.com/topapi/v2/department/listsub"
|
|
23
|
+
return self.client._request(
|
|
24
|
+
url, "POST", json={"dept_id": dept_id, "language": lang}
|
|
25
|
+
)
|
|
26
|
+
|
|
27
|
+
def get_det_detail(self, dept_id: int, lang: str = "zh_CN") -> dict[str, Any]:
|
|
28
|
+
"""
|
|
29
|
+
获取部门详情
|
|
30
|
+
https://open.dingtalk.com/document/development/query-department-details0-v2
|
|
31
|
+
|
|
32
|
+
:param dept_id: 部门ID
|
|
33
|
+
:param lang: 语言 zh_CN en_US
|
|
34
|
+
:return {"errcode":0,"errmsg":"ok","result":{"dept_permits":[3,4,5],"outer_permit_users":["user123","1234"],"dept_manager_userid_list":["1020302901-431772414"],"org_dept_owner":"manager9153","outer_dept":false,"dept_group_chat_id":"chat1fccdb4b921f2bde18c26xxxx","group_contain_sub_dept":true,"auto_add_user":true,"hide_dept":false,"name":"测试","outer_permit_depts":[500,600],"user_permits":[],"dept_id":1,"create_dept_group":true,"order":0,"code":"100","union_dept_ext":{"corp_id":"test","dept_id":1234567}},"request_id":"4e7ljtq91rgo"}:
|
|
35
|
+
"""
|
|
36
|
+
url = "https://oapi.dingtalk.com/topapi/v2/department/get"
|
|
37
|
+
return self.client._request(
|
|
38
|
+
url, "POST", json={"dept_id": dept_id, "language": lang}
|
|
39
|
+
)
|
|
40
|
+
|
|
41
|
+
def search_dept(self,query_word:str,offset:int = 0,size:int = 10):
|
|
42
|
+
"""
|
|
43
|
+
搜索部门ID
|
|
44
|
+
https://open.dingtalk.com/document/development/address-book-search-department-id
|
|
45
|
+
|
|
46
|
+
:param query_word: 部门名称或者部门名称拼音
|
|
47
|
+
:param offset: 分页页码
|
|
48
|
+
:param size: 分页大小
|
|
49
|
+
:return {"hasMore":false,"totalCount":2,"list":[220141953,220207936]}:
|
|
50
|
+
"""
|
|
51
|
+
|
|
52
|
+
url = "https://api.dingtalk.com/v1.0/contact/departments/search"
|
|
53
|
+
return self.client._request(url,"POST",json={
|
|
54
|
+
"queryWord":query_word,
|
|
55
|
+
"offset":offset,
|
|
56
|
+
"size":size
|
|
57
|
+
})
|
|
58
|
+
|
|
59
|
+
|
|
60
|
+
|
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
import time
|
|
4
|
+
import httpx
|
|
5
|
+
import atexit
|
|
6
|
+
from typing_extensions import Self
|
|
7
|
+
from pydantic import BaseModel
|
|
8
|
+
from pydantic_settings import BaseSettings, SettingsConfigDict
|
|
9
|
+
from typing import Literal, TYPE_CHECKING
|
|
10
|
+
from functools import cached_property
|
|
11
|
+
|
|
12
|
+
if TYPE_CHECKING:
|
|
13
|
+
from .yida import YiDa
|
|
14
|
+
|
|
15
|
+
HttpMethod = Literal["GET", "PUT", "POST", "DELETE"]
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
class DingTalkConfig(BaseSettings):
|
|
19
|
+
app_key: str = ""
|
|
20
|
+
app_secret: str = ""
|
|
21
|
+
|
|
22
|
+
model_config = SettingsConfigDict(
|
|
23
|
+
env_prefix="DINGTALK_",
|
|
24
|
+
env_file=".env",
|
|
25
|
+
env_file_encoding="utf-8",
|
|
26
|
+
extra="allow",
|
|
27
|
+
)
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
class Token(BaseModel):
|
|
31
|
+
access_token: str
|
|
32
|
+
expire_at: float
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
class TokenManager:
|
|
36
|
+
_instance = None
|
|
37
|
+
_tokens: dict[str, Token] = {}
|
|
38
|
+
|
|
39
|
+
def __new__(cls) -> Self:
|
|
40
|
+
if cls._instance is None:
|
|
41
|
+
cls._instance = super(TokenManager, cls).__new__(cls)
|
|
42
|
+
|
|
43
|
+
return cls._instance
|
|
44
|
+
|
|
45
|
+
def get_token(self, app_key: str, app_secret: str) -> str:
|
|
46
|
+
token = self._tokens.get(app_key)
|
|
47
|
+
|
|
48
|
+
if not token or token.expire_at < time.time():
|
|
49
|
+
token = self._refresh_token(app_key, app_secret)
|
|
50
|
+
|
|
51
|
+
return token.access_token
|
|
52
|
+
|
|
53
|
+
def _refresh_token(self, app_key: str, app_secret: str) -> Token:
|
|
54
|
+
url = "https://api.dingtalk.com/v1.0/oauth2/accessToken"
|
|
55
|
+
body = {"appKey": app_key, "appSecret": app_secret}
|
|
56
|
+
|
|
57
|
+
with httpx.Client() as client:
|
|
58
|
+
res = client.post(url, json=body)
|
|
59
|
+
|
|
60
|
+
try:
|
|
61
|
+
res.raise_for_status()
|
|
62
|
+
except httpx.HTTPStatusError as ex:
|
|
63
|
+
raise Exception(ex.response.text)
|
|
64
|
+
|
|
65
|
+
data = res.json()
|
|
66
|
+
|
|
67
|
+
self._tokens[app_key] = Token(
|
|
68
|
+
access_token=data["accessToken"], expire_at=time.time() + 3600
|
|
69
|
+
)
|
|
70
|
+
|
|
71
|
+
return self._tokens[app_key]
|
|
72
|
+
|
|
73
|
+
|
|
74
|
+
class DingTalkClient:
|
|
75
|
+
def __init__(self, config: DingTalkConfig):
|
|
76
|
+
self.config = config
|
|
77
|
+
self.token_manager = TokenManager()
|
|
78
|
+
self.http_client = httpx.Client(
|
|
79
|
+
transport=httpx.HTTPTransport(retries=3), timeout=30.0
|
|
80
|
+
)
|
|
81
|
+
|
|
82
|
+
atexit.register(self.close)
|
|
83
|
+
|
|
84
|
+
@property
|
|
85
|
+
def acccess_token(self):
|
|
86
|
+
return self.token_manager.get_token(self.config.app_key, self.config.app_secret)
|
|
87
|
+
|
|
88
|
+
def _request(self, url: str, method: HttpMethod, **kwargs) -> dict:
|
|
89
|
+
if "oapi.dingtalk.com" in url:
|
|
90
|
+
params = kwargs.get("params", {})
|
|
91
|
+
params["access_token"] = self.acccess_token
|
|
92
|
+
kwargs["params"] = params
|
|
93
|
+
else:
|
|
94
|
+
headers = kwargs.get("headers", {})
|
|
95
|
+
headers.setdefault("x-acs-dingtalk-access-token", self.acccess_token)
|
|
96
|
+
kwargs["headers"] = headers
|
|
97
|
+
|
|
98
|
+
res = self.http_client.request(method, url, **kwargs)
|
|
99
|
+
try:
|
|
100
|
+
res.raise_for_status()
|
|
101
|
+
data = res.json()
|
|
102
|
+
except httpx.HTTPStatusError as ex:
|
|
103
|
+
try:
|
|
104
|
+
error_detail = ex.response.json()
|
|
105
|
+
except: # noqa: E722
|
|
106
|
+
error_detail = ex.response.text
|
|
107
|
+
|
|
108
|
+
raise Exception(
|
|
109
|
+
f"Http Error:{ex.response.status_code}, Detail:{error_detail}"
|
|
110
|
+
)
|
|
111
|
+
|
|
112
|
+
if "errcode" in data and data["errcode"] != 0:
|
|
113
|
+
raise Exception(
|
|
114
|
+
f"dingtalk api err: {data.get('errmsg', 'unknown')} code:{data.get['errcode']}"
|
|
115
|
+
)
|
|
116
|
+
return data
|
|
117
|
+
|
|
118
|
+
def close(self):
|
|
119
|
+
if hasattr(self, "http_client"):
|
|
120
|
+
self.http_client.close()
|
|
121
|
+
|
|
122
|
+
@cached_property
|
|
123
|
+
def yida(self) -> YiDa:
|
|
124
|
+
from .yida import YiDa, YiDaConfig
|
|
125
|
+
|
|
126
|
+
return YiDa(self, YiDaConfig())
|
|
File without changes
|
|
@@ -0,0 +1,175 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
from typing import TYPE_CHECKING, Any
|
|
3
|
+
from pydantic_settings import BaseSettings, SettingsConfigDict
|
|
4
|
+
import json
|
|
5
|
+
|
|
6
|
+
if TYPE_CHECKING:
|
|
7
|
+
from .core import DingTalkClient
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
class YiDaConfig(BaseSettings):
|
|
11
|
+
app_type: str | None = None
|
|
12
|
+
system_token: str | None = None
|
|
13
|
+
user_id: str | None = None
|
|
14
|
+
|
|
15
|
+
model_config = SettingsConfigDict(
|
|
16
|
+
env_file=".env",
|
|
17
|
+
env_prefix="DINGTALK_YIDA_",
|
|
18
|
+
env_file_encoding="utf-8",
|
|
19
|
+
extra="allow",
|
|
20
|
+
)
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
class YiDa:
|
|
24
|
+
def __init__(self, client: DingTalkClient, config: YiDaConfig) -> None:
|
|
25
|
+
self.client = client
|
|
26
|
+
self.config = config
|
|
27
|
+
|
|
28
|
+
@property
|
|
29
|
+
def _common_params(self):
|
|
30
|
+
return {
|
|
31
|
+
"appType": self.config.app_type,
|
|
32
|
+
"systemToken": self.config.system_token,
|
|
33
|
+
"userId": self.config.user_id,
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
def _prepare_params(
|
|
37
|
+
self, base_params: dict[str, Any], use_alias: bool, form_uuid: str | None
|
|
38
|
+
):
|
|
39
|
+
params = {**base_params, "useAlias": use_alias}
|
|
40
|
+
|
|
41
|
+
if use_alias:
|
|
42
|
+
if form_uuid is None:
|
|
43
|
+
raise ValueError(
|
|
44
|
+
"when the 'use_alias' is true,the 'form_uuid' cannot be empty"
|
|
45
|
+
)
|
|
46
|
+
|
|
47
|
+
params["formUuid"] = form_uuid
|
|
48
|
+
return params
|
|
49
|
+
|
|
50
|
+
def get_form_inst(
|
|
51
|
+
self, inst_id: str, use_alias=False, form_uuid: str | None = None
|
|
52
|
+
) -> dict[str, Any]:
|
|
53
|
+
"""
|
|
54
|
+
获取表单实例
|
|
55
|
+
|
|
56
|
+
:param inst_id: 表单实例ID
|
|
57
|
+
:param use_alias: 是否使用组件别名
|
|
58
|
+
:param form_uuid: 表单UUID 当使用组件别名时必填
|
|
59
|
+
|
|
60
|
+
:return {"originator":{"userId":"user123","name":{"nameInChinese":"张三","nameInEnglish":"ZhangSan","type":"i18n"},"departmentName":"开发部","email":"abc@alimail.com"},"modifiedTimeGMT":"2021-05-01","formInstId":"FORM_INST_12345"}:
|
|
61
|
+
|
|
62
|
+
"""
|
|
63
|
+
url = f"https://api.dingtalk.com/v2.0/yida/forms/instances/{inst_id}"
|
|
64
|
+
|
|
65
|
+
params = self._prepare_params(self._common_params, use_alias, form_uuid)
|
|
66
|
+
return self.client._request(url, "GET", params=params)
|
|
67
|
+
|
|
68
|
+
def del_form_inst(self, inst_id: str):
|
|
69
|
+
url = "https://api.dingtalk.com/v1.0/yida/forms/instances"
|
|
70
|
+
return self.client._request(
|
|
71
|
+
url,
|
|
72
|
+
"DELETE",
|
|
73
|
+
params={**self._common_params, "formInstanceId": inst_id},
|
|
74
|
+
)
|
|
75
|
+
|
|
76
|
+
def save_form_inst(
|
|
77
|
+
self, form_uuid: str, form_data: dict[str, Any], use_alias: bool = False
|
|
78
|
+
) -> dict[str, str]:
|
|
79
|
+
"""
|
|
80
|
+
新增表单实例
|
|
81
|
+
|
|
82
|
+
:param form_uuid: 表单UUID
|
|
83
|
+
:param form_data: 表单数据
|
|
84
|
+
:param use_alias: 是否使用组件别名
|
|
85
|
+
:return {"result":["FINST-SASNOO39NSIFF780"]}:
|
|
86
|
+
|
|
87
|
+
"""
|
|
88
|
+
url = "https://api.dingtalk.com/v2.0/yida/forms/instances"
|
|
89
|
+
return self.client._request(
|
|
90
|
+
url,
|
|
91
|
+
"POST",
|
|
92
|
+
json={
|
|
93
|
+
**self._common_params,
|
|
94
|
+
"formUuid": form_uuid,
|
|
95
|
+
"formDataJson": json.dumps(form_data),
|
|
96
|
+
"useAlias": use_alias,
|
|
97
|
+
},
|
|
98
|
+
)
|
|
99
|
+
|
|
100
|
+
def update_form_inst(
|
|
101
|
+
self,
|
|
102
|
+
inst_id: str,
|
|
103
|
+
form_data: dict[str, Any],
|
|
104
|
+
use_alias: bool = False,
|
|
105
|
+
form_uuid: str | None = None,
|
|
106
|
+
use_latest_version=False,
|
|
107
|
+
):
|
|
108
|
+
"""
|
|
109
|
+
更新表单实例
|
|
110
|
+
https://open.dingtalk.com/document/development/api-updateformdata-v2
|
|
111
|
+
|
|
112
|
+
:param inst_id: 表单实例ID
|
|
113
|
+
:param form_data: 表单数据
|
|
114
|
+
:param use_alias: 是否使用组件别名
|
|
115
|
+
:param form_uuid: 表单UUID 当使用组件别名时必填
|
|
116
|
+
:param use_latest_version: 是否使用最新表单版本更新
|
|
117
|
+
"""
|
|
118
|
+
|
|
119
|
+
url = "https://api.dingtalk.com/v2.0/yida/forms/instances"
|
|
120
|
+
body = {
|
|
121
|
+
**self._common_params,
|
|
122
|
+
"formInstanceId": inst_id,
|
|
123
|
+
"updateFormDataJson": json.dumps(form_data),
|
|
124
|
+
"useAlias": use_alias,
|
|
125
|
+
"useLatestVersion": use_latest_version,
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
body = self._prepare_params(
|
|
129
|
+
{
|
|
130
|
+
**self._common_params,
|
|
131
|
+
"formInstanceId": inst_id,
|
|
132
|
+
"updateFormDataJson": json.dumps(form_data),
|
|
133
|
+
"useLatestVersion": use_latest_version,
|
|
134
|
+
},
|
|
135
|
+
use_alias,
|
|
136
|
+
form_uuid,
|
|
137
|
+
)
|
|
138
|
+
|
|
139
|
+
self.client._request(url, "PUT", json=body)
|
|
140
|
+
|
|
141
|
+
def save_update_form_inst(
|
|
142
|
+
self,
|
|
143
|
+
form_uuid: str,
|
|
144
|
+
search_condition: dict[str, Any],
|
|
145
|
+
form_data: dict[str, Any],
|
|
146
|
+
use_alias: bool = False,
|
|
147
|
+
execute_expression: bool = True,
|
|
148
|
+
):
|
|
149
|
+
"""
|
|
150
|
+
新增或更新表单实例
|
|
151
|
+
https://open.dingtalk.com/document/development/api-createorupdateformdata-v2
|
|
152
|
+
|
|
153
|
+
:param form_uuid: 表单UUID
|
|
154
|
+
:param search_condition: 检索条件
|
|
155
|
+
:param form_data: 表单数据
|
|
156
|
+
:param use_alias: 是否使用组件别名
|
|
157
|
+
:param execute_expression: 是否触发表单校验规则,关联业务规则和第三方服务回调
|
|
158
|
+
|
|
159
|
+
:return {"result":["FINST-SASNOO39NSIFF780"]}:
|
|
160
|
+
"""
|
|
161
|
+
|
|
162
|
+
url = "https://api.dingtalk.com/v2.0/yida/forms/instances/insertOrUpdate"
|
|
163
|
+
|
|
164
|
+
return self.client._request(
|
|
165
|
+
url,
|
|
166
|
+
"POST",
|
|
167
|
+
json={
|
|
168
|
+
**self._common_params,
|
|
169
|
+
"formUuid": form_uuid,
|
|
170
|
+
"searchCondition": search_condition,
|
|
171
|
+
"formDataJson": json.dumps(form_data),
|
|
172
|
+
"noExecuteExpression": not execute_expression,
|
|
173
|
+
"useAlias": use_alias,
|
|
174
|
+
},
|
|
175
|
+
)
|