From b5128aded866b5b416cae56c75f35ec5a9d2b7fb Mon Sep 17 00:00:00 2001 From: jefferyzhao <375696853@qq.com> Date: Wed, 30 Jul 2025 18:43:53 +0800 Subject: [PATCH] =?UTF-8?q?=E5=88=9D=E5=A7=8B=E6=8F=90=E4=BA=A4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .idea/.gitignore | 8 + .idea/enterprise-wechat-payment-push.iml | 18 + .../inspectionProfiles/profiles_settings.xml | 6 + .idea/misc.xml | 4 + .idea/modules.xml | 8 + FuiouPay.py | 67 + __pycache__/FuiouPay.cpython-36.pyc | Bin 0 -> 1996 bytes __pycache__/FuiouPay.cpython-37.pyc | Bin 0 -> 2097 bytes __pycache__/WXPay.cpython-36.pyc | Bin 0 -> 3328 bytes __pycache__/WXPay.cpython-37.pyc | Bin 0 -> 3370 bytes __pycache__/config.cpython-36.pyc | Bin 0 -> 944 bytes __pycache__/config.cpython-37.pyc | Bin 0 -> 995 bytes __pycache__/payapp.cpython-37.pyc | Bin 0 -> 10635 bytes __pycache__/utils.cpython-36.pyc | Bin 0 -> 19701 bytes __pycache__/utils.cpython-37.pyc | Bin 0 -> 25596 bytes app.py | 419 ++++++ config.py | 52 + dg_priv_key.pem | 3 + dg_pub_key.pem | 3 + fws.pem | 28 + logs/payapp.log | 67 + logs/payapp.log.2025-05-07 | 204 +++ logs/payapp.log.2025-05-08 | 2 + priv_key.pem | 3 + pub_key.pem | 3 + test.py | 11 + utils.py | 1286 +++++++++++++++++ 27 files changed, 2192 insertions(+) create mode 100644 .idea/.gitignore create mode 100644 .idea/enterprise-wechat-payment-push.iml create mode 100644 .idea/inspectionProfiles/profiles_settings.xml create mode 100644 .idea/misc.xml create mode 100644 .idea/modules.xml create mode 100644 FuiouPay.py create mode 100644 __pycache__/FuiouPay.cpython-36.pyc create mode 100644 __pycache__/FuiouPay.cpython-37.pyc create mode 100644 __pycache__/WXPay.cpython-36.pyc create mode 100644 __pycache__/WXPay.cpython-37.pyc create mode 100644 __pycache__/config.cpython-36.pyc create mode 100644 __pycache__/config.cpython-37.pyc create mode 100644 __pycache__/payapp.cpython-37.pyc create mode 100644 __pycache__/utils.cpython-36.pyc create mode 100644 __pycache__/utils.cpython-37.pyc create mode 100644 app.py create mode 100644 config.py create mode 100644 dg_priv_key.pem create mode 100644 dg_pub_key.pem create mode 100644 fws.pem create mode 100644 logs/payapp.log create mode 100644 logs/payapp.log.2025-05-07 create mode 100644 logs/payapp.log.2025-05-08 create mode 100644 priv_key.pem create mode 100644 pub_key.pem create mode 100644 test.py create mode 100644 utils.py diff --git a/.idea/.gitignore b/.idea/.gitignore new file mode 100644 index 0000000..081b737 --- /dev/null +++ b/.idea/.gitignore @@ -0,0 +1,8 @@ +# 默认忽略的文件 +/shelf/ +/workspace.xml +# 数据源本地存储已忽略文件 +/dataSources/ +/dataSources.local.xml +# 基于编辑器的 HTTP 客户端请求 +/httpRequests/ diff --git a/.idea/enterprise-wechat-payment-push.iml b/.idea/enterprise-wechat-payment-push.iml new file mode 100644 index 0000000..f936df0 --- /dev/null +++ b/.idea/enterprise-wechat-payment-push.iml @@ -0,0 +1,18 @@ + + + + + + + + + + + + + + \ No newline at end of file diff --git a/.idea/inspectionProfiles/profiles_settings.xml b/.idea/inspectionProfiles/profiles_settings.xml new file mode 100644 index 0000000..105ce2d --- /dev/null +++ b/.idea/inspectionProfiles/profiles_settings.xml @@ -0,0 +1,6 @@ + + + + \ No newline at end of file diff --git a/.idea/misc.xml b/.idea/misc.xml new file mode 100644 index 0000000..a2e120d --- /dev/null +++ b/.idea/misc.xml @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/.idea/modules.xml b/.idea/modules.xml new file mode 100644 index 0000000..4adf23a --- /dev/null +++ b/.idea/modules.xml @@ -0,0 +1,8 @@ + + + + + + + + \ No newline at end of file diff --git a/FuiouPay.py b/FuiouPay.py new file mode 100644 index 0000000..a38dcb0 --- /dev/null +++ b/FuiouPay.py @@ -0,0 +1,67 @@ +import json +from datetime import datetime + +import requests +from Crypto.PublicKey import RSA +import base64 +from Crypto.Cipher import PKCS1_v1_5 +import logging + +logger = logging.getLogger(__name__) + +# 使用公钥加密 +def rsa_long_encrypt(msg, length=100): + """ + 单次加密串的长度最大为 (key_size/8)-11 + 1024bit的证书用100, 2048bit的证书用 200 + """ + pub_key = RSA.importKey(open('pub_key.pem').read()) + # pub_key = RSA.importKey(open('E:/YinJian/银建支付对接维护说明/富友/enterprise-wechat-payment-push/pub_key.pem').read()) + pubobj = PKCS1_v1_5.new(pub_key) + res = [] + for i in range(0, len(msg), length): + res.append(pubobj.encrypt(msg[i:i + length].encode('GBK'))) + return base64.b64encode(b"".join(res)).decode('GBK') + + +class H5Main: + def __init__(self, sub_mchnt_cd): + self.mchnt_cd = "0001000F7152279" + self.sub_mchnt_cd = sub_mchnt_cd + self.url = 'https://aggpcpay.fuioupay.com/aggh5Gate.fuiou' + self.notify_url = "http://web.jiyuankeshang.com/api/paymentCallBack" + # self.notify_url = "http://172.16.6.15:3006/paymentCallBack" + + def unified_order(self, order_no, total, description): + if self.sub_mchnt_cd == '0001000F7152279': + param = { + "mchnt_cd": self.mchnt_cd, + "order_date": datetime.now().strftime("%Y%m%d"), + "order_id": order_no, + "order_amt": total, + "page_notify_url": self.notify_url, + "back_notify_url": self.notify_url, + "ver": "4.0.0", + "goods_name": "费税收取", + "goods_detail": description, + "fee_type": "CNY", + } + else: + param = { + "mchnt_cd": self.mchnt_cd, + "sub_mchnt_cd": self.sub_mchnt_cd, + "order_date": datetime.now().strftime("%Y%m%d"), + "order_id": order_no, + "order_amt": total, + "page_notify_url": self.notify_url, + "back_notify_url": self.notify_url, + "ver": "4.0.0", + "goods_name": "费税收取", + "goods_detail": description, + "fee_type": "CNY", + } + logger.info(f"======================发起支付====================",param) + # 加密 + message = json.dumps(param) + encrypted_message = rsa_long_encrypt(message,100) + return json.dumps({"message": encrypted_message}) \ No newline at end of file diff --git a/__pycache__/FuiouPay.cpython-36.pyc b/__pycache__/FuiouPay.cpython-36.pyc new file mode 100644 index 0000000000000000000000000000000000000000..cc9f4f53962825e82fe5fa4877bb09bc9f9abfa7 GIT binary patch literal 1996 zcmah}TaOe)6t3#q^z_cMV7%dVy(}{7&Sl+Qkf=e{fC+I!ZeTo?DGdc=s;>rGLz~F-h7K~#H-bW= z05Xdhq_Bw_<`G0pQrtwOI8+)%f{&x})O9!=t(LJciNh&(0}8zQ`tg@xvW^{HIbOF< z*6pS11k_rJREA*y6@XTN5(dDLhq*%V5PRwn4e>zXnx|(9aB2q)w6_m%gDAX^!CHog z>MQ82Jp(<{JTp_hVumsuK71c~PuYz;i>O05X$WszUw8xYDX&B{Z#vVY%-bPX!E!xa zhl{OQ7^9EQY=8UZ=!0{ki|=n;`r+yqo7d0$KDu&#`|LZTufE>8bY*t$8tvJM+o#q2 z<@tI&-&L>j5>sAxpGK1gwC9>Lxt+Yn&HHtLPUXv zE!K;dNC>ufzl8!Loln(DU3KPQ`1~5_66Dp&L z!0tDQ?S`BGu2s8HK&v$5l*P14yq?&}636zV zuwzebgB(Rk2>|JLDHhi7y?76155j*-3U3UVCI^9%hX5#QV1gh`F;O;ALnSKFVAhBZ zK{SN%>e6eD8{SMUxmQx2T5>r>4voRv2-&-Lru&D?&@C-)4`(L-Ht$;Q{y+ zrfs{S%WYdmCousKHuA4OGj>YlhDJ-KjvTV+r2lj8d;&~{Jn+z(!j^%95|riVX#@%n zJO9UOs3@Ia4 zX1GwCvZ1W9hrzDCF?V7vm?M3Cu~MtlQfc(HA1`0M@bUKPpGT)YYp5%$C(0Ik1mwbs z7@^FT4M><{-X)?q=A3|wnb_%2`(M9`nI;6{R)KnwGGTS1h$MFC1XPs9JfYliePOmK zwRtb5<*EG2aX_Ag%h{ZSJrbUhuvbD^!qXC-k?<@)x(x8*9mnX@r`LY^W&8BStzSRC zlLFIWt0)9CN#Ggq=sX+b%bCn{p@z|hFcZ$&vi-8hq)dkj4Y|;~BnpL2(jZRqIx830 zrfku5c< z97~(N+k%FiH)ysCRK@gUZN-hdl;zzycX58~oh%UM3uD7yl5IcPk(*IcOz;MfYVG(3 DdN&%M literal 0 HcmV?d00001 diff --git a/__pycache__/FuiouPay.cpython-37.pyc b/__pycache__/FuiouPay.cpython-37.pyc new file mode 100644 index 0000000000000000000000000000000000000000..63477b7f0f69050ecd6b5efe679a91579ec07c73 GIT binary patch literal 2097 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 literal 0 HcmV?d00001 diff --git a/__pycache__/WXPay.cpython-37.pyc b/__pycache__/WXPay.cpython-37.pyc new file mode 100644 index 0000000000000000000000000000000000000000..037645cdc4b7babca24ae6d64c3e7142b04f30e8 GIT binary patch literal 3370 zcma)8+ix958QM8a861T*m&asn-s!miJlB|MO>z%RB+Ix04 zvvcD3Xw8cY4_rzmc&JEH*`gKVg@6F!3!_EgzuZRou;h>yP9vl zxzBvx@4K9@)oca6rNIX)AJi1(@7Or_G+^FKcTWLtGqS!<3aYu(YI zRzqV6=V_tYDmf*BydGMuvQw745!$VaQ;|Fgt4@A79Ks^+X|22-mT-#ahO-8_B)Dm;-W$;wEB)htJ|t`l9ENGUV8%XP!{SWC$9j} z-d>!A%1YM#bkrT41m0Y{G&?pqRaf)!^3(*2{FpMyQid!pnw?*)t6YbTa{J1gjm1&- z)~Gw_tGG3MCKLlo14=pvL?}B%sFZAz9c@?HC0nY{cZ^I0P7@|@%1((w3);G{GHs`v z>AN`FrW*7anE^M~7doYtjdUnstz2)5mFbQFba1*};i#m%9JG>{i#OS3uEz+;!N_#BRo6VzA0!v=yy(W0pZs?3;qM>)^!~>W-`~6cyGQSS^pA%R9)17A$M+vR zdjH)Ud-s31_v0VjV3A-v;X%ppWe`&IKhV1iE#Q0&22Q{Fi13)Or6j#YqpoAiY!+>g32MU$| zM;HrE@5b%PvFQen_jdk7sHlvISRGmh2eS6 zUmtZ|o|u{&otmCIbAIIf^lW2ldUkwtWMtyC`O&fQ$+?m7*Df?BrYFwKPt=Xv@RB5; zxd9i0N^A2lx1(4DE1NFz<&^Qj3*9KLYk(sbuJ9K@8vKh$5E%vO11`5*H;4k^x?h3T zz8Xzps#rQ*g|-i-_=r;cs!&klQqX?`CR5g=u-8aNG7#~anyIMSyQ%^KJ$_f+vPCtsw+T^1ZLJG#*_|1gO;7wt z+p35vJ(*S3dhqVs8d0(efTM50u}7!IM<++drY5Iyt+8+&T#q4Q;f1;7w>bxk1(Oz= z33IfoUQ$<`ZU6@3t{(=VUN=abQgaeSyb{+f$4V1ds!noJdrmoRFS`X>joZQnEKvrk z%PW+nJ`WN^6@LMQoSR-NZb!ngQ=dglZkj7Tfg$`5`KX{2OFxiI`F7tHDg4`-Ce$_k zB>1;)DMYymQ30Mu763~oV3)?N-1M7q;4^S2f(OxR-tDD+5V-9mVchpp7yu6wh!g~% z4vpl*{S=b^Q$D*2x4ND1bF+8@ypFDPUMe8ej)IkdQ8(t4@u9O}?0aE)Zs>5y6TEQ8 zxN>=M$?m-PKkO?fFbCuq2EK>V8D2}{=xhDpta!@A%r}=V3{H1WU!8AUnq9gwdwp!M zh#G?sPsTJ4E^iOK&LkFDtb0gv^gu9B4~kk^;!uur(pEJ zz-9*iU$Y&ktDR~i2JZ^4bO`{H*Jj(I8S|hc9|3aJsVBU=)P&H$c-pDWeDbRw;a>n5 z6-F%Kpaw~<0v<*13=l8OQta`X%QB_v0YOaO800y8Krr-Hi!2eL_dFHXS_#3zB^IcWku zk$nm)dF?qo48q*>6(EYL6O~{As;b1)RJBL9NgqU&7l^H?q+hil%Jh)V(a*uvVUT~$ zKm8T<-Fz=2l$?Up=ajOg?(-V(+CHxXuM1@jQUOc@fYTw=14j+;4iMxa5zvbS0lbHq z!7OTG8n9(%5V5H8UEH|@yh2Now_r^PJX2{GJd>~>Z78Eh1OH}URiY7H5tVhD|CuOT zkZ5&!!T(rU<&JVsMgN56NnzwWm21j%B~q^`nT_#qL5ehPb1+of50WP1sI}aX=tY}N zV?Xc&SQ=ufPWVN5{eChM{Ojq{r|sj=@%R@%-@E_4y*nQ~{`L0WhrfCJ;G=*3;b-+4 zw_uES0m;j^#@)sF#@q8tyc^rrTbJkN-HVO4a}cmvFvWJS;D(BLz&$B(0xVAVO+KuyHp%h}MC_A)p} zNH=Br`P|Urfn$@|r_=q3RhPW9DKk<2b-D2}xc#XKnT{6ft`(Dq8WMRDE_r3Y4;SY> x`;Ei%or9id$CmNtn9#|`eV#0G>ue#=a~RuXCTEdnf1xEy?Ezm<@IAU^{TDi>mx=%Y literal 0 HcmV?d00001 diff --git a/__pycache__/config.cpython-36.pyc b/__pycache__/config.cpython-36.pyc new file mode 100644 index 0000000000000000000000000000000000000000..bd864b9fff706706cf01a19a7016d0888266e770 GIT binary patch literal 944 zcmYjQO>g5i5VakD#Lgz!&F-O>0yz~}6t+cDq$p!iWYf9@3S_ZJf-S;}LCsK>99z;_ za$M^l_169!UHdQgR7%OABsepCZ}|9lAUi!Bt^WBt{MKu={%!qlv~7K5SAK5;wp0t- zs*N4h!6S8qUDd^&>S15?ai9ixtd4Q0hB#6qJW(eWdxfvmDW0k`JX7a*u3lU04Zc?TT}Wg*_2JGyyP>7UVgqAU47gYQM#Ss;p?dU zJ}QbVpG~Lx{eH5F4?CSanmp3Uasuf_UF`QjJrR1^VXg;^I6?WNT-~j_`LE=6@tKt6 zFXn4`^Cyf6xbrWpxc}{N%@6C#J($~TPsF_d-SGbh>zO`mA2sP#0tr-L8Nn<^` zRMw2^8<%^Qae2T!7S?Kk7C_kxqeHIS@VU_t>XJeO!<8Z{SyHVy*m z5Lbc#qH8rTlv>i-f$+2s#-+vy06=pJ0R+rfmy!l+vX1iQs*KRr(e=ZVzWMa!V*(Ek zw~xWRb|NH4&W&(5sht?q$eB~CYRMgB0R#Ig5FvL-U}*U1{kv+gSYQf^MKug`ZWfs? zqN)$+HjA<9-_3u%o!?gjy);Q-f#DNdykMO;s|J}qEOeGtCtCw1elobQO=r6V()HRv z@v^VG&=fje=QTgn0O_u%%YIZg=X*BWZ7*uj(bniZO`7Ju&f-UNsQTgVxzpwt)p@bi zNv@%YpZor5ZQt3y(S&c4X_Riv)LJ&%Y#Zlhyf+Z(Vr-3UEIQ71c{GJI3FGA?J5)7sg{sT)p4+#JO literal 0 HcmV?d00001 diff --git a/__pycache__/config.cpython-37.pyc b/__pycache__/config.cpython-37.pyc new file mode 100644 index 0000000000000000000000000000000000000000..431b45c1847230e423ef8fa556444d8633cb5b55 GIT binary patch literal 995 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 literal 0 HcmV?d00001 diff --git a/__pycache__/utils.cpython-37.pyc b/__pycache__/utils.cpython-37.pyc new file mode 100644 index 0000000000000000000000000000000000000000..d976f9e5f5265a1816362c5d756866873b23d55d GIT binary patch literal 25596 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 next_month_start and '补收预收承包金' in i['fukuanshiyou']: + i['flag_m'] = 0 + continue + if pay_amount: + i['flag'] = 1 + if '补收预收承包金' in i['fukuanshiyou'] or i['lydunjiao'] == "趸交": + i['flag_m'] = 0 + continue + if '承包金' in i['fukuanshiyou']: + # 承包金实际需要缴纳的 + if pay_amount < i['money'] - i['pay']: + # 修改 i['pay'] 充值金额,推送修改 + i['pay'] += pay_amount + i['no_money'] = i['money'] - i['pay'] + i['flag_m'] = pay_amount + pay_amount = 0 + + else: + pay_amount -= (i['money'] - i['pay']) + i['flag_m'] = (i['money'] - i['pay']) + i['pay'] = i['money'] + i['no_money'] = 0 + + else: + if i['money'] != i['pay']: + # 根据未支付的金额,扣除总金额 + df = i['money'] - i['pay'] + if pay_amount < df: + # 修改 i['pay'] 充值金额,推送修改 + i['pay'] += pay_amount + i['no_money'] = i['money'] - i['pay'] + i['flag_m'] = pay_amount + pay_amount = 0 + + else: + pay_amount -= df + i['pay'] = i['money'] + i['no_money'] = 0 + i['flag_m'] = df + # 根据抵扣规则,更新未支付的数据,将清缴数据新增至已收付明细 + else: + is_specialized = 1 + # 初始化结果字典 + result = {} + # 处理每个项目 + for item in data['paymentdetails']: + # 分割类型和日期 + expense_type = item[:-7] + date = item[-7:] + + # 更新专项收取字典 + if date not in result: + result[date] = [] + result[date].append(expense_type) + # 创建一个新的字典来存储过滤后的专项收取数据 + filtered_details = {} + # 遍历未收付数据 + for month, value in details.items(): + # 跳过非月份的键(如'amount') + if month not in result: + continue + + # 初始化一个列表来存储满足条件的data项 + filtered_data = [item for item in value['data'] if item['fukuanshiyou'] in result[month]] + + # 如果filtered_data非空,则添加到filtered_details中,并可以选择性地包含其他字段 + if filtered_data: + # 注意:这里我们保留了'data'和其他可能需要的字段(如'de', '_th_amount', 'hz') + filtered_details[month] = {k: v for k, v in value.items() if k in ['data', 'de', '_th_amount', 'hz']} + # 但是,'data'字段已经被更新为filtered_data + filtered_details[month]['data'] = filtered_data + dates = [month for month in dates if month in result] + if next_month in dates: + # _tmp = filtered_details[next_month]['data'] + _tmp = filtered_details.get(next_month, {}).get('data', []) + if _tmp: + _tmp = sorted(_tmp, key=lambda x: x['sort']) + for i in _tmp: + if pay_amount: + i['flag'] = 1 + if i['money'] != i['pay']: + # 根据未支付的金额,扣除总金额 + df = i['money'] - i['pay'] + if pay_amount < df: + # 修改 i['pay'] 充值金额,推送修改 + i['pay'] += pay_amount + i['no_money'] = i['money'] - i['pay'] + i['flag_m'] = pay_amount + pay_amount = 0 + else: + pay_amount -= df + i['pay'] = i['money'] + i['no_money'] = 0 + i['flag_m'] = df + if now_month in dates: + _tmp = filtered_details[now_month]['data'] + _tmp = sorted(_tmp, key=lambda x: x['sort']) + for i in _tmp: + if pay_amount: + i['flag'] = 1 + if i['money'] != i['pay']: + # 根据未支付的金额,扣除总金额 + df = i['money'] - i['pay'] + if pay_amount < df: + # 修改 i['pay'] 充值金额,推送修改 + i['pay'] += pay_amount + i['no_money'] = i['money'] - i['pay'] + i['flag_m'] = pay_amount + pay_amount = 0 + else: + pay_amount -= df + i['pay'] = i['money'] + i['no_money'] = 0 + i['flag_m'] = df + for i in dates: + if i == next_month or i == now_month: + continue + _tmp = filtered_details[i]['data'] + _tmp = sorted(_tmp, key=lambda x: x['sort']) + for i in _tmp: + if pay_amount: + i['flag'] = 1 + if i['money'] != i['pay']: + # 根据未支付的金额,扣除总金额 + df = i['money'] - i['pay'] + if pay_amount < df: + # 修改 i['pay'] 充值金额,推送修改 + i['pay'] += pay_amount + i['no_money'] = i['money'] - i['pay'] + i['flag_m'] = pay_amount + pay_amount = 0 + else: + pay_amount -= df + i['pay'] = i['money'] + i['no_money'] = 0 + i['flag_m'] = df + # 根据抵扣规则,更新未支付的数据,将清缴数据新增至已收付明细 + logger.info(f"更新未收付{details,is_specialized}") + update_unpay(details,is_specialized) + # 未收付更新完后,更新个人账户余额update_info + logger.info(f"更新个人账户余额update_info") + update_info(data['pay_amount'], pay_amount, balance['balance'], data) + lock.release() + logger.info(f"结束========") + +def rsa_long_decrypt(priv_key, msg, length=256): + """ + 1024bit的证书用128,2048bit证书用256位 + """ + try: + privobj = PKCS1_v1_5.new(priv_key) + res = [] + b64_msg = base64.b64decode(msg) + for i in range(0, len(b64_msg), length): + chunk = b64_msg[i:i + length] + decrypted_chunk = privobj.decrypt(chunk, 'xyz').decode('GBK') + res.append(decrypted_chunk) + except Exception as e: + logger.error(f"解密回调失败:{e}") + return None + return "".join(res) + +def decode_notify_data(res_json): + try: + ciphertext = res_json['resource']['ciphertext'] + nonce = res_json['resource']['nonce'] + associated_data = res_json['resource']['associated_data'] + cipher = AES.new(v3_SECRET.encode(), AES.MODE_GCM, nonce=nonce.encode()) + cipher.update(associated_data.encode()) + en_data = b64decode(ciphertext.encode('utf-8')) + auth_tag = en_data[-16:] + _en_data = en_data[:-16] + plaintext = cipher.decrypt_and_verify(_en_data, auth_tag) + decodejson = json.loads(plaintext.decode()) + except Exception as e: + logger.error(f"解密回调失败:{e}") + return None + return decodejson + +def get_wx_token(): + url = f'https://qyapi.weixin.qq.com/cgi-bin/gettoken?corpid={corpid}&corpsecret={SECRET}' + res = req_tool_vx(url, flag=1) + # print("==========================获取企微TOKEN============================",res) + return res['access_token'] + + +def query_wx_fj_info(id): + """查询企微中的附加信息""" + token = get_wx_token() + url = f'https://qyapi.weixin.qq.com/cgi-bin/user/get?access_token={token}&userid={id}' + res = req_tool_vx(url, flag=1) + # print("==========================获取企微附加信息============================", res) + val = "" + logger.info(f"query_wx_fj_info{res},{id}") + for i in res['extattr']['attrs']: + if i['name'] == '附加信息': + val = i['value'] + return val + + +def query_wx_userid(code): + """查询企微中的userid""" + token = get_wx_token() + url = f'https://qyapi.weixin.qq.com/cgi-bin/auth/getuserinfo?access_token={token}&code={code}' + res = req_tool_vx(url, flag=1) + # print("==========================获取企微userid============================", res) + return res['userid'] + +def find_pay_details(id, paymentdetails): + # 查询某人未收付明细 + can_submit = 0 + for item in paymentdetails: + url = f'{base_path}/api/v5/app/entry/data/list' + month = item[-7:] + logger.info(f"month{month}") + filter_data = { + "app_id": cw_app, + "entry_id": uncollected_id, + "limit": 100, + "filter": { + "rel": "and", + "cond": [ + { + "field": "id_card", + "method": "eq", + "value": [id] + }, + { + "field": "month1", + "method": "eq", + "value": [month] + }, + { + "field": "fukuanshiyou", + "method": "eq", + "value": ["安全统筹"] + } + ] + } + } + + logger.info(f"发起安全统筹支付前开始查询未收付{filter_data}") + uncollected_data = turn_page(url, filter_data) + if uncollected_data == []: + logger.info(f"未查询到安全统筹未收付{uncollected_data}") + return 0 + else: + logger.info(f"查询到安全统筹未收付{uncollected_data}") + return 1 \ No newline at end of file