From 89e854c74d78062248c8cf5811e0526d2761e39c Mon Sep 17 00:00:00 2001 From: xtaodada Date: Tue, 15 Aug 2023 15:40:26 +0800 Subject: [PATCH] :sparkles: Support query pay --- cqwu/client.py | 5 +- cqwu/methods/__init__.py | 2 + cqwu/methods/pay/__init__.py | 29 +++++++++++ cqwu/methods/pay/get_pay_project_detail.py | 29 +++++++++++ cqwu/methods/pay/get_pay_projects.py | 27 ++++++++++ cqwu/methods/pay/get_pay_user.py | 27 ++++++++++ cqwu/types/__init__.py | 1 + cqwu/types/pay.py | 58 ++++++++++++++++++++++ requirements.txt | 2 +- setup.py | 2 +- 10 files changed, 178 insertions(+), 4 deletions(-) create mode 100644 cqwu/methods/pay/__init__.py create mode 100644 cqwu/methods/pay/get_pay_project_detail.py create mode 100644 cqwu/methods/pay/get_pay_projects.py create mode 100644 cqwu/methods/pay/get_pay_user.py create mode 100644 cqwu/types/pay.py diff --git a/cqwu/client.py b/cqwu/client.py index 5817252..b5704bb 100644 --- a/cqwu/client.py +++ b/cqwu/client.py @@ -29,10 +29,11 @@ class Client(Methods): self.loop = asyncio.get_event_loop() self.me: Optional[User] = None self._use_password_login = False - self.xue_nian = 2022 + self.xue_nian = 2023 """ 学年 """ - self.xue_qi = 1 + self.xue_qi = 0 """ 学期,0 为第一学期,1 为第二学期 """ + self._pay_x_token = "" @staticmethod def get_input(word: str = "", is_int: bool = False): diff --git a/cqwu/methods/__init__.py b/cqwu/methods/__init__.py index beb007d..8cde462 100644 --- a/cqwu/methods/__init__.py +++ b/cqwu/methods/__init__.py @@ -1,5 +1,6 @@ from .auth import Auth from .epay import EPay +from .pay import Pay from .users import Users from .webvpn import WebVPN from .xg import XG @@ -8,6 +9,7 @@ from .xg import XG class Methods( Auth, EPay, + Pay, Users, WebVPN, XG, diff --git a/cqwu/methods/pay/__init__.py b/cqwu/methods/pay/__init__.py new file mode 100644 index 0000000..c08a204 --- /dev/null +++ b/cqwu/methods/pay/__init__.py @@ -0,0 +1,29 @@ +from typing import Dict + +import cqwu + +from .get_pay_project_detail import GetPayProjectDetail +from .get_pay_projects import GetPayProjects +from .get_pay_user import GetPayUser + + +class Pay( + GetPayProjectDetail, + GetPayProjects, + GetPayUser, +): + async def _oauth_pay( + self: "cqwu.Client", + ): + url = f"https://pay.cqwu.edu.cn/api/pay/web/dlyscas/casLogin/{self.username}/2" + html = await self.request.get(url, follow_redirects=False) + if html.status_code == 302: + location = html.headers["location"] + params = {i.split("=")[0]: i.split("=")[1] for i in location.split("?")[1].split("&")} + self._pay_x_token = params["token"] + + @property + def pay_headers(self) -> Dict[str, str]: + return { + "X-Token": self._pay_x_token, + } diff --git a/cqwu/methods/pay/get_pay_project_detail.py b/cqwu/methods/pay/get_pay_project_detail.py new file mode 100644 index 0000000..7c5b209 --- /dev/null +++ b/cqwu/methods/pay/get_pay_project_detail.py @@ -0,0 +1,29 @@ +from typing import Optional, List + +import cqwu +from cqwu.errors.auth import CookieError +from cqwu.types import PayProjectDetail + + +class GetPayProjectDetail: + async def get_pay_project_detail( + self: "cqwu.Client", + project_id: str, + ) -> List[Optional[PayProjectDetail]]: + """ + 获取缴费项目详情 + + Returns: + List[Optional[PayProjectDetail]]: 缴费项目详情列表 + """ + if not self._pay_x_token: + await self._oauth_pay() + url = (f"https://pay.cqwu.edu.cn/api/pay/web/tuitionAndDorm/getTuitionAndDormList/" + f"{self.username}/{project_id}") + html = await self.request.get(url, headers=self.pay_headers) + if html.status_code != 200: + raise CookieError() + data = html.json().get("data", []) + if not data: + return [] + return [PayProjectDetail(**i) for i in data] diff --git a/cqwu/methods/pay/get_pay_projects.py b/cqwu/methods/pay/get_pay_projects.py new file mode 100644 index 0000000..7f98e9f --- /dev/null +++ b/cqwu/methods/pay/get_pay_projects.py @@ -0,0 +1,27 @@ +from typing import Optional, List + +import cqwu +from cqwu.errors.auth import CookieError +from cqwu.types import PayProject + + +class GetPayProjects: + async def get_pay_projects( + self: "cqwu.Client", + ) -> List[Optional[PayProject]]: + """ + 获取缴费项目 + + Returns: + List[Optional[PayProject]]: 缴费项目列表 + """ + if not self._pay_x_token: + await self._oauth_pay() + url = "https://pay.cqwu.edu.cn/api/pay/project/getAllProjectList" + html = await self.request.get(url, headers=self.pay_headers) + if html.status_code != 200: + raise CookieError() + data = html.json().get("data", []) + if not data: + return [] + return [PayProject(**i) for i in data] diff --git a/cqwu/methods/pay/get_pay_user.py b/cqwu/methods/pay/get_pay_user.py new file mode 100644 index 0000000..bd231e7 --- /dev/null +++ b/cqwu/methods/pay/get_pay_user.py @@ -0,0 +1,27 @@ +from typing import Optional, List + +import cqwu +from cqwu.errors.auth import CookieError +from cqwu.types import PayUser + + +class GetPayUser: + async def get_pay_user( + self: "cqwu.Client", + ) -> Optional[PayUser]: + """ + 获取缴费用户信息 + + Returns: + List[Optional[PayUser]]: 缴费用户信息列表 + """ + if not self._pay_x_token: + await self._oauth_pay() + url = f"https://pay.cqwu.edu.cn/api/pay/queryUserInfo/{self._pay_x_token}" + html = await self.request.get(url, headers=self.pay_headers) + if html.status_code != 200: + raise CookieError() + data = html.json().get("data") + if not data: + return None + return PayUser(**data) diff --git a/cqwu/types/__init__.py b/cqwu/types/__init__.py index 98260ce..569f229 100644 --- a/cqwu/types/__init__.py +++ b/cqwu/types/__init__.py @@ -2,5 +2,6 @@ from .calendar import AiCourse from .cp import CP, PublicCPRaw, CPGS from .epay import PayBill, PayBillPage from .exam import AiExam +from .pay import PayProject, PayProjectDetail, PayUser from .score import Score from .user import User diff --git a/cqwu/types/pay.py b/cqwu/types/pay.py new file mode 100644 index 0000000..04504d0 --- /dev/null +++ b/cqwu/types/pay.py @@ -0,0 +1,58 @@ +from datetime import datetime +from typing import Optional + +from pydantic import BaseModel, validator + + +class PayProject(BaseModel): + id: str + createDate: datetime + createBy: str + updateDate: datetime + updateBy: str + projectType: str + projectCode: str + projectName: str + """ 项目名称 """ + imgUrl: Optional[str] + + +class PayProjectDetail(BaseModel): + id: Optional[str] + xh: Optional[int] + """ 学号 """ + executespanname: Optional[str] + financingname: Optional[str] + """ 名称 """ + taxname: Optional[str] + """ 税务名称 """ + ysje: Optional[float] + """ 应收金额 """ + sfje: Optional[float] + """ 已收金额 """ + qfje: Optional[float] + """ 欠费金额 """ + jmje: Optional[float] + """ 减免金额 """ + tfje: Optional[float] + """ 退费金额 """ + + @validator("ysje", "sfje", "qfje", "jmje", "tfje", pre=True) + def _float(cls, v): + if v == "": + return 0.0 + return float(v) / 100.0 + + +class PayUser(BaseModel): + id: str + createDate: datetime + createBy: str + updateDate: datetime + updateBy: str + idserial: Optional[int] + name: Optional[str] + idNum: Optional[int] + """ 身份证号 """ + phone: Optional[int] + """ 手机号 """ diff --git a/requirements.txt b/requirements.txt index 17e4d3f..a7eefb4 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,5 +1,5 @@ httpx==0.24.1 -lxml==4.9.2 +lxml==4.9.3 PyExecJS2==1.6.1 beautifulsoup4==4.12.2 qrcode==7.4.2 diff --git a/setup.py b/setup.py index a5365a2..078c75f 100644 --- a/setup.py +++ b/setup.py @@ -5,7 +5,7 @@ with open("README.md", "r", encoding="utf-8") as fh: setuptools.setup( name="cqwu", # 用自己的名替换其中的YOUR_USERNAME_ - version="0.0.13", # 包版本号,便于维护版本 + version="0.0.14", # 包版本号,便于维护版本 author="omg-xtao", # 作者,可以写自己的姓名 author_email="xtao@xtaolink.cn", # 作者联系方式,可写自己的邮箱地址 description="A cqwu ehall client.", # 包的简述