bocai-cli-core 0.2.0__py3-none-any.whl

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.
Files changed (42) hide show
  1. bocai_cli/__init__.py +3 -0
  2. bocai_cli/api/__init__.py +29 -0
  3. bocai_cli/api/auth_client.py +57 -0
  4. bocai_cli/api/card_client.py +222 -0
  5. bocai_cli/api/center_client.py +55 -0
  6. bocai_cli/api/checkin_client.py +29 -0
  7. bocai_cli/api/course_client.py +85 -0
  8. bocai_cli/api/facade.py +40 -0
  9. bocai_cli/api/guanyuan_client.py +50 -0
  10. bocai_cli/api/member_client.py +97 -0
  11. bocai_cli/api/month_dashboard_client.py +130 -0
  12. bocai_cli/api/qywx_client.py +28 -0
  13. bocai_cli/api/report_client.py +41 -0
  14. bocai_cli/api/reservation_client.py +29 -0
  15. bocai_cli/api/transport.py +166 -0
  16. bocai_cli/app.py +12 -0
  17. bocai_cli/client.py +69 -0
  18. bocai_cli/command_utils.py +28 -0
  19. bocai_cli/commands/__init__.py +8 -0
  20. bocai_cli/commands/auth.py +211 -0
  21. bocai_cli/commands/card.py +653 -0
  22. bocai_cli/commands/center.py +138 -0
  23. bocai_cli/commands/checkin.py +71 -0
  24. bocai_cli/commands/course.py +260 -0
  25. bocai_cli/commands/customreport.py +77 -0
  26. bocai_cli/commands/guanyuan.py +94 -0
  27. bocai_cli/commands/member.py +288 -0
  28. bocai_cli/commands/month_dashboard.py +235 -0
  29. bocai_cli/commands/qywx.py +112 -0
  30. bocai_cli/commands/registry.py +70 -0
  31. bocai_cli/commands/report.py +93 -0
  32. bocai_cli/commands/reservation.py +71 -0
  33. bocai_cli/config.py +121 -0
  34. bocai_cli/date_range_validation.py +65 -0
  35. bocai_cli/errors.py +22 -0
  36. bocai_cli/main.py +8 -0
  37. bocai_cli/output.py +28 -0
  38. bocai_cli/product.py +10 -0
  39. bocai_cli_core-0.2.0.dist-info/METADATA +138 -0
  40. bocai_cli_core-0.2.0.dist-info/RECORD +42 -0
  41. bocai_cli_core-0.2.0.dist-info/WHEEL +4 -0
  42. bocai_cli_core-0.2.0.dist-info/licenses/LICENSE +19 -0
bocai_cli/__init__.py ADDED
@@ -0,0 +1,3 @@
1
+ __all__ = ["__version__"]
2
+
3
+ __version__ = "0.2.0"
@@ -0,0 +1,29 @@
1
+ from bocai_cli.api.auth_client import AuthClient
2
+ from bocai_cli.api.card_client import CardClient
3
+ from bocai_cli.api.center_client import CenterClient
4
+ from bocai_cli.api.checkin_client import CheckinClient
5
+ from bocai_cli.api.course_client import CourseClient
6
+ from bocai_cli.api.facade import ApiFacade
7
+ from bocai_cli.api.guanyuan_client import GuanyuanClient
8
+ from bocai_cli.api.member_client import MemberClient
9
+ from bocai_cli.api.month_dashboard_client import MonthDashboardClient
10
+ from bocai_cli.api.qywx_client import QywxClient
11
+ from bocai_cli.api.report_client import ReportClient
12
+ from bocai_cli.api.reservation_client import ReservationClient
13
+ from bocai_cli.api.transport import ApiTransport
14
+
15
+ __all__ = [
16
+ "ApiFacade",
17
+ "ApiTransport",
18
+ "AuthClient",
19
+ "CardClient",
20
+ "CenterClient",
21
+ "CheckinClient",
22
+ "CourseClient",
23
+ "GuanyuanClient",
24
+ "MemberClient",
25
+ "MonthDashboardClient",
26
+ "QywxClient",
27
+ "ReservationClient",
28
+ "ReportClient",
29
+ ]
@@ -0,0 +1,57 @@
1
+ from __future__ import annotations
2
+
3
+ from typing import Any
4
+
5
+ from bocai_cli.api.transport import ApiTransport
6
+ from bocai_cli.errors import ApiRequestError
7
+
8
+
9
+ def _extract_access_token(payload: object) -> str | None:
10
+ if isinstance(payload, dict):
11
+ for field in ("accessToken", "access_token"):
12
+ value = payload.get(field)
13
+ if isinstance(value, str) and value.strip():
14
+ return value.strip()
15
+ return None
16
+
17
+
18
+ class AuthClient:
19
+ def __init__(self, transport: ApiTransport) -> None:
20
+ self._transport = transport
21
+
22
+ def start(self) -> Any:
23
+ return self._transport.request(
24
+ "POST",
25
+ "/api/auth/start",
26
+ auth_required=False,
27
+ )
28
+
29
+ def check_status(self, *, auth_code: str) -> Any:
30
+ return self._transport.request(
31
+ "GET",
32
+ "/api/auth/status",
33
+ params={"auth_code": auth_code},
34
+ auth_required=False,
35
+ )
36
+
37
+ def refresh_user_token(self, *, access_token: str, refresh_token: str) -> Any:
38
+ return self._transport.request(
39
+ "POST",
40
+ "/api/auth/refreshUserToken",
41
+ json_body={"accessToken": access_token, "refreshToken": refresh_token},
42
+ auth_required=False,
43
+ )
44
+
45
+ def fetch_access_token(self, *, token_url: str, app_id: str, secret: str) -> str:
46
+ payload = self._transport.request(
47
+ "POST",
48
+ token_url,
49
+ json_body={"appId": app_id, "appSecret": secret},
50
+ absolute_url=True,
51
+ auth_required=False,
52
+ )
53
+ value = _extract_access_token(payload)
54
+ if value is not None:
55
+ return value
56
+
57
+ raise ApiRequestError("token 接口响应缺少 accessToken 或 access_token。")
@@ -0,0 +1,222 @@
1
+ from __future__ import annotations
2
+
3
+ from typing import Any
4
+
5
+ from bocai_cli.api.transport import ApiTransport
6
+
7
+
8
+ class CardClient:
9
+ def __init__(self, transport: ApiTransport) -> None:
10
+ self._transport = transport
11
+
12
+ def sale_performance(
13
+ self,
14
+ *,
15
+ start_date: str,
16
+ end_date: str,
17
+ page_num: int,
18
+ page_size: int,
19
+ type_: int,
20
+ center_id: str | None = None,
21
+ ) -> Any:
22
+ params: dict[str, Any] = {
23
+ "startDate": start_date,
24
+ "endDate": end_date,
25
+ "pageNum": page_num,
26
+ "pageSize": page_size,
27
+ "type": type_,
28
+ }
29
+ if center_id is not None:
30
+ params["centerId"] = center_id
31
+ return self._transport.request("GET", "/api/bocai/card/sale", params=params)
32
+
33
+ def performance_clear(
34
+ self,
35
+ *,
36
+ transaction_ids: list[str],
37
+ phone: str,
38
+ center_id: str | None = None,
39
+ ) -> Any:
40
+ params: dict[str, Any] | None = None
41
+ if center_id is not None:
42
+ params = {"centerId": center_id}
43
+
44
+ return self._transport.request(
45
+ "POST",
46
+ "/api/bocai/course/performance/clear",
47
+ params=params,
48
+ json_body={"transactionIds": transaction_ids, "phone": phone},
49
+ )
50
+
51
+ def performance_update(
52
+ self,
53
+ *,
54
+ phone: str,
55
+ transactions: list[dict[str, Any]],
56
+ center_id: str | None = None,
57
+ ) -> Any:
58
+ params: dict[str, Any] | None = None
59
+ if center_id is not None:
60
+ params = {"centerId": center_id}
61
+
62
+ return self._transport.request(
63
+ "POST",
64
+ "/api/bocai/course/performance/update",
65
+ params=params,
66
+ json_body={"phone": phone, "transactions": transactions},
67
+ )
68
+
69
+ def performance_new(
70
+ self,
71
+ *,
72
+ type_: int,
73
+ payload: dict[str, Any],
74
+ center_id: str | None = None,
75
+ ) -> Any:
76
+ params: dict[str, Any] = {"type": type_}
77
+ if center_id is not None:
78
+ params["centerId"] = center_id
79
+
80
+ return self._transport.request(
81
+ "POST",
82
+ "/api/bocai/card/performance/new",
83
+ params=params,
84
+ json_body=payload,
85
+ )
86
+
87
+ def studio_contract_list(
88
+ self,
89
+ *,
90
+ center_id: str,
91
+ page_num: int,
92
+ page_size: int,
93
+ type_: int,
94
+ card_type: int = -1,
95
+ card_ids: list[int] | None = None,
96
+ status: int = 99,
97
+ remain_start: int | None = None,
98
+ remain_end: int | None = None,
99
+ sale_type: int = -1,
100
+ contract_status: int = -1,
101
+ seller_id: int = -1,
102
+ tag_id: int = -1,
103
+ card_create_start_date: str = "",
104
+ card_create_end_date: str = "",
105
+ card_activate_start_date: str = "",
106
+ card_activate_end_date: str = "",
107
+ card_expire_start_date: str = "",
108
+ card_expire_end_date: str = "",
109
+ course_start_date: str = "",
110
+ course_end_date: str = "",
111
+ ) -> Any:
112
+ json_body: dict[str, Any] = {
113
+ "pageNum": page_num,
114
+ "pageSize": page_size,
115
+ "keyword": "",
116
+ "displayCenter": False,
117
+ "cardType": card_type,
118
+ "cardIds": card_ids or [],
119
+ "status": status,
120
+ "consultantId": seller_id,
121
+ "followUpConsultantId": -1,
122
+ "saleType": sale_type,
123
+ "cardCreateTimeStart": card_create_start_date,
124
+ "cardCreateTimeEnd": card_create_end_date,
125
+ "cardActiveTimeStart": card_activate_start_date,
126
+ "cardActiveTimeEnd": card_activate_end_date,
127
+ "expireTimeStart": card_expire_start_date,
128
+ "expireTimeEnd": card_expire_end_date,
129
+ "electronicContractStatus": str(contract_status),
130
+ "isPrimary": -1,
131
+ "tagId": tag_id,
132
+ "courseStartTime": course_start_date,
133
+ "courseEndTime": course_end_date,
134
+ "searchRemain": remain_start is not None or remain_end is not None,
135
+ "remainStart": "" if remain_start is None else str(remain_start),
136
+ "remainEnd": "" if remain_end is None else remain_end,
137
+ }
138
+ if type_ == 1:
139
+ json_body["isCourseCard"] = False
140
+ elif type_ == 2:
141
+ json_body["isCourseCard"] = True
142
+
143
+ return self._transport.request(
144
+ "POST",
145
+ "/api/bocai/card/studio_contract_list",
146
+ params={
147
+ "centerId": center_id,
148
+ "pageNum": page_num,
149
+ "pageSize": page_size,
150
+ },
151
+ json_body=json_body,
152
+ )
153
+
154
+ def contract_detail(self, *, center_id: str, contract_id: str) -> Any:
155
+ return self._transport.request(
156
+ "GET",
157
+ "/api/bocai/card/contract_detail",
158
+ params={"centerId": center_id, "contractId": contract_id},
159
+ )
160
+
161
+ def studio_sale(
162
+ self,
163
+ *,
164
+ center_id: str,
165
+ start_date: str,
166
+ end_date: str,
167
+ type_: int,
168
+ seller_id: int = -1,
169
+ card_ids: list[int] | None = None,
170
+ tag_ids: list[int] | None = None,
171
+ page_num: int = 0,
172
+ page_size: int = 20,
173
+ ) -> Any:
174
+ json_body: dict[str, Any] = {
175
+ "startDate": start_date,
176
+ "endDate": end_date,
177
+ "tagIds": tag_ids or [],
178
+ "cardIds": card_ids or [],
179
+ }
180
+ if type_ == 1:
181
+ json_body["isCourseCard"] = False
182
+ elif type_ == 2:
183
+ json_body["isCourseCard"] = True
184
+
185
+ return self._transport.request(
186
+ "POST",
187
+ "/api/bocai/card/studio_sale",
188
+ params={
189
+ "centerId": center_id,
190
+ "consultantId": seller_id,
191
+ "pageNum": page_num,
192
+ "pageSize": page_size,
193
+ },
194
+ json_body=json_body,
195
+ )
196
+
197
+ def studio_private_consume_performance(
198
+ self,
199
+ *,
200
+ center_id: str,
201
+ start_date: str,
202
+ end_date: str,
203
+ trainer_id: int = -1,
204
+ teach_mode: int = -1,
205
+ page_num: int = 0,
206
+ page_size: int = 20,
207
+ ) -> Any:
208
+ return self._transport.request(
209
+ "POST",
210
+ "/api/bocai/card/studio_private_consume_performance",
211
+ params={
212
+ "centerId": center_id,
213
+ "pageNum": page_num,
214
+ "pageSize": page_size,
215
+ },
216
+ json_body={
217
+ "trainerId": trainer_id,
218
+ "startDate": start_date,
219
+ "endDate": end_date,
220
+ "teachMode": teach_mode,
221
+ },
222
+ )
@@ -0,0 +1,55 @@
1
+ from __future__ import annotations
2
+
3
+ from typing import Any
4
+
5
+ from bocai_cli.api.transport import ApiTransport
6
+
7
+
8
+ class CenterClient:
9
+ def __init__(self, transport: ApiTransport) -> None:
10
+ self._transport = transport
11
+
12
+ def list(self) -> Any:
13
+ return self._transport.request("GET", "/api/bocai/centers")
14
+
15
+ def manager_phone(self, *, center_id: str) -> Any:
16
+ return self._transport.request(
17
+ "GET",
18
+ "/api/bocai/managerPhones",
19
+ params={"centerId": center_id},
20
+ )
21
+
22
+ def card_list(self, *, center_id: str, type_: int) -> Any:
23
+ return self._transport.request(
24
+ "GET",
25
+ "/api/bocai/center/card/list",
26
+ params={"centerId": center_id, "type": type_},
27
+ )
28
+
29
+ def source_list(self, *, center_id: str) -> Any:
30
+ return self._transport.request(
31
+ "GET",
32
+ "/api/bocai/center/source/list",
33
+ params={"centerId": center_id},
34
+ )
35
+
36
+ def studio_seller_list(self, *, center_id: str) -> Any:
37
+ return self._transport.request(
38
+ "GET",
39
+ "/api/bocai/center/consultant/list",
40
+ params={"centerId": center_id},
41
+ )
42
+
43
+ def studio_trainer_list(self, *, center_id: str) -> Any:
44
+ return self._transport.request(
45
+ "GET",
46
+ "/api/bocai/center/trainer/list",
47
+ params={"centerId": center_id},
48
+ )
49
+
50
+ def tag_list(self, *, center_id: str, type_: int) -> Any:
51
+ return self._transport.request(
52
+ "GET",
53
+ "/api/bocai/center/tag/list",
54
+ params={"centerId": center_id, "type": type_},
55
+ )
@@ -0,0 +1,29 @@
1
+ from __future__ import annotations
2
+
3
+ from typing import Any
4
+
5
+ from bocai_cli.api.transport import ApiTransport
6
+
7
+
8
+ class CheckinClient:
9
+ def __init__(self, transport: ApiTransport) -> None:
10
+ self._transport = transport
11
+
12
+ def list(
13
+ self,
14
+ *,
15
+ start_date: str,
16
+ end_date: str,
17
+ page_num: int,
18
+ page_size: int,
19
+ center_id: str | None = None,
20
+ ) -> Any:
21
+ params: dict[str, Any] = {
22
+ "startDate": start_date,
23
+ "endDate": end_date,
24
+ "pageNum": page_num,
25
+ "pageSize": page_size,
26
+ }
27
+ if center_id is not None:
28
+ params["centerId"] = center_id
29
+ return self._transport.request("GET", "/api/bocai/checkin", params=params)
@@ -0,0 +1,85 @@
1
+ from __future__ import annotations
2
+
3
+ from typing import Any
4
+
5
+ from bocai_cli.api.transport import ApiTransport
6
+
7
+
8
+ class CourseClient:
9
+ def __init__(self, transport: ApiTransport) -> None:
10
+ self._transport = transport
11
+
12
+ def sale_performance(
13
+ self,
14
+ *,
15
+ start_date: str,
16
+ end_date: str,
17
+ page_num: int,
18
+ page_size: int,
19
+ type_: int,
20
+ center_id: str | None = None,
21
+ ) -> Any:
22
+ params: dict[str, Any] = {
23
+ "startDate": start_date,
24
+ "endDate": end_date,
25
+ "pageNum": page_num,
26
+ "pageSize": page_size,
27
+ "type": type_,
28
+ }
29
+ if center_id is not None:
30
+ params["centerId"] = center_id
31
+ return self._transport.request("GET", "/api/bocai/course/sale", params=params)
32
+
33
+ def performance_clear(
34
+ self,
35
+ *,
36
+ transaction_ids: list[str],
37
+ phone: str,
38
+ center_id: str | None = None,
39
+ ) -> Any:
40
+ params: dict[str, Any] | None = None
41
+ if center_id is not None:
42
+ params = {"centerId": center_id}
43
+
44
+ return self._transport.request(
45
+ "POST",
46
+ "/api/bocai/course/performance/clear",
47
+ params=params,
48
+ json_body={"transactionIds": transaction_ids, "phone": phone},
49
+ )
50
+
51
+ def performance_update(
52
+ self,
53
+ *,
54
+ phone: str,
55
+ transactions: list[dict[str, Any]],
56
+ center_id: str | None = None,
57
+ ) -> Any:
58
+ params: dict[str, Any] | None = None
59
+ if center_id is not None:
60
+ params = {"centerId": center_id}
61
+
62
+ return self._transport.request(
63
+ "POST",
64
+ "/api/bocai/course/performance/update",
65
+ params=params,
66
+ json_body={"phone": phone, "transactions": transactions},
67
+ )
68
+
69
+ def performance_new(
70
+ self,
71
+ *,
72
+ type_: int,
73
+ payload: dict[str, Any],
74
+ center_id: str | None = None,
75
+ ) -> Any:
76
+ params: dict[str, Any] = {"type": type_}
77
+ if center_id is not None:
78
+ params["centerId"] = center_id
79
+
80
+ return self._transport.request(
81
+ "POST",
82
+ "/api/bocai/course/performance/new",
83
+ params=params,
84
+ json_body=payload,
85
+ )
@@ -0,0 +1,40 @@
1
+ from __future__ import annotations
2
+
3
+ from bocai_cli.api.auth_client import AuthClient
4
+ from bocai_cli.api.card_client import CardClient
5
+ from bocai_cli.api.center_client import CenterClient
6
+ from bocai_cli.api.checkin_client import CheckinClient
7
+ from bocai_cli.api.course_client import CourseClient
8
+ from bocai_cli.api.guanyuan_client import GuanyuanClient
9
+ from bocai_cli.api.member_client import MemberClient
10
+ from bocai_cli.api.month_dashboard_client import MonthDashboardClient
11
+ from bocai_cli.api.qywx_client import QywxClient
12
+ from bocai_cli.api.report_client import ReportClient
13
+ from bocai_cli.api.reservation_client import ReservationClient
14
+ from bocai_cli.api.transport import ApiTransport
15
+
16
+
17
+ class ApiFacade:
18
+ def __init__(
19
+ self,
20
+ *,
21
+ base_url: str | None,
22
+ token: str | None,
23
+ timeout_seconds: float = 30.0,
24
+ ) -> None:
25
+ self.transport = ApiTransport(
26
+ base_url=base_url,
27
+ token=token,
28
+ timeout_seconds=timeout_seconds,
29
+ )
30
+ self.auth = AuthClient(self.transport)
31
+ self.card = CardClient(self.transport)
32
+ self.center = CenterClient(self.transport)
33
+ self.checkin = CheckinClient(self.transport)
34
+ self.course = CourseClient(self.transport)
35
+ self.guanyuan = GuanyuanClient(self.transport)
36
+ self.member = MemberClient(self.transport)
37
+ self.monthdashboard = MonthDashboardClient(self.transport)
38
+ self.qywx = QywxClient(self.transport)
39
+ self.reservation = ReservationClient(self.transport)
40
+ self.report = ReportClient(self.transport)
@@ -0,0 +1,50 @@
1
+ from __future__ import annotations
2
+
3
+ from typing import Any
4
+
5
+ from bocai_cli.api.transport import ApiTransport
6
+
7
+
8
+ class GuanyuanClient:
9
+ def __init__(self, transport: ApiTransport) -> None:
10
+ self._transport = transport
11
+
12
+ def absence_statistics(self, *, center_id: str, type_: int = 1) -> Any:
13
+ return self._transport.request(
14
+ "GET",
15
+ "/api/bocai/guanyuan/absence/statistics",
16
+ params={"centerId": center_id, "type": type_},
17
+ )
18
+
19
+ def absence_detail(self, *, center_id: str, type_: int = 1) -> Any:
20
+ return self._transport.request(
21
+ "GET",
22
+ "/api/bocai/guanyuan/absence/detail",
23
+ params={"centerId": center_id, "type": type_},
24
+ )
25
+
26
+ def ds_list(self, *, center_id: str) -> Any:
27
+ return self._transport.request(
28
+ "GET",
29
+ "/api/bocai/guanyuan/ds/list",
30
+ params={"centerId": center_id},
31
+ )
32
+
33
+ def ds_data(
34
+ self,
35
+ *,
36
+ center_id: str,
37
+ ds_id: str,
38
+ start_date: str,
39
+ end_date: str,
40
+ ) -> Any:
41
+ return self._transport.request(
42
+ "GET",
43
+ "/api/bocai/guanyuan/ds/data",
44
+ params={
45
+ "centerId": center_id,
46
+ "dsId": ds_id,
47
+ "startDate": start_date,
48
+ "endDate": end_date,
49
+ },
50
+ )
@@ -0,0 +1,97 @@
1
+ from __future__ import annotations
2
+
3
+ from typing import Any
4
+
5
+ from bocai_cli.api.transport import ApiTransport
6
+
7
+
8
+ class MemberClient:
9
+ def __init__(self, transport: ApiTransport) -> None:
10
+ self._transport = transport
11
+
12
+ def studio_proposed_list(
13
+ self,
14
+ *,
15
+ center_id: str,
16
+ page_num: int,
17
+ page_size: int,
18
+ consultant_id: int = -1,
19
+ source: int = -1,
20
+ tag_id: int = -1,
21
+ follow_status: int = -1,
22
+ attend_start_date: str = "",
23
+ attend_end_date: str = "",
24
+ ) -> Any:
25
+ return self._transport.request(
26
+ "POST",
27
+ "/api/bocai/member/studio_proposed_list",
28
+ params={
29
+ "centerId": center_id,
30
+ "pageNum": page_num,
31
+ "pageSize": page_size,
32
+ },
33
+ json_body={
34
+ "consultantId": consultant_id,
35
+ "source": source,
36
+ "tagId": tag_id,
37
+ "followupStatus": str(follow_status),
38
+ "attendStartDate": attend_start_date,
39
+ "attendEndDate": attend_end_date,
40
+ },
41
+ )
42
+
43
+ def studio_member_list(
44
+ self,
45
+ *,
46
+ center_id: str,
47
+ page_num: int,
48
+ page_size: int,
49
+ consultant_id: int = -1,
50
+ source: int = -1,
51
+ tag_id: int = -1,
52
+ member_type: int = -1,
53
+ status: int = -1,
54
+ follow_status: int = -1,
55
+ expire_start_date: str = "",
56
+ expire_end_date: str = "",
57
+ birthday_start_date: str = "",
58
+ birthday_end_date: str = "",
59
+ check_in_status: bool = True,
60
+ last_checkin_start_date: str = "",
61
+ last_checkin_end_date: str = "",
62
+ course_start_date: str = "",
63
+ course_end_date: str = "",
64
+ ) -> Any:
65
+ return self._transport.request(
66
+ "POST",
67
+ "/api/bocai/member/studio_member_list",
68
+ params={
69
+ "centerId": center_id,
70
+ "pageNum": page_num,
71
+ "pageSize": page_size,
72
+ },
73
+ json_body={
74
+ "consultantId": consultant_id,
75
+ "status": status,
76
+ "birthdayStart": birthday_start_date,
77
+ "birthDayEnd": birthday_end_date,
78
+ "lastCheckInStartTs": last_checkin_start_date,
79
+ "lastCheckInEndTs": last_checkin_end_date,
80
+ "checkInStatus": check_in_status,
81
+ "expireStartTime": expire_start_date,
82
+ "expireEndTime": expire_end_date,
83
+ "memberType": None if member_type == -1 else member_type,
84
+ "source": source,
85
+ "tagId": tag_id,
86
+ "followupStatus": None if follow_status == -1 else follow_status,
87
+ "courseStartTime": course_start_date,
88
+ "courseEndTime": course_end_date,
89
+ },
90
+ )
91
+
92
+ def detail(self, *, center_id: str, member_id: str) -> Any:
93
+ return self._transport.request(
94
+ "GET",
95
+ "/api/bocai/member/detail",
96
+ params={"centerId": center_id, "traineeId": member_id},
97
+ )