From e9bde4db76b595037843e203dcc07f02cb40f5fb Mon Sep 17 00:00:00 2001 From: TermiNexus Date: Fri, 7 Aug 2026 00:56:21 +0800 Subject: [PATCH] =?UTF-8?q?"chore(gvsdsdk):=20=E6=B8=85=E7=90=86=E8=BF=87?= =?UTF-8?q?=E6=97=B6=E7=82=B9=E4=B8=8E=E6=AD=BB=E4=BB=A3=E7=A0=81=E5=B9=B6?= =?UTF-8?q?=E4=BF=AE=E5=A4=8D=E8=BF=90=E8=A1=8C=E6=9C=9F=E7=BC=BA=E9=99=B7?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - models: 修正过时文档、UserRole 遗留字段标注废弃、抽象 User 补 IsStaff/IsSuperuser - models: CopyToRole 补 CompanyUUID 默认值,修复 RolePermission 插入必失败缺陷 - form_service: 对齐主项目值转换(Boolean/时区/空值),移除 NullBooleanField 遗留映射 - auth: 删除无引用的 GetDefaultAvatar 与 ShopManager/PositionManager,清理惰性导出 - db_router/model_base/msync: 简化模块集合、移除 typing_extensions 死兜底、复用 GenerateChallenge - 删除残留文件(空测试文件、无源 pyc)" --- __init__.py | 3 +- __pycache__/__init__.cpython-312.pyc | Bin 12407 -> 12353 bytes __pycache__/db_router.cpython-312.pyc | Bin 3953 -> 3779 bytes __pycache__/form_service.cpython-312.pyc | Bin 21496 -> 22094 bytes __pycache__/model_base.cpython-312.pyc | Bin 31046 -> 30923 bytes __pycache__/models.cpython-312.pyc | Bin 41566 -> 42478 bytes auth/__init__.py | 15 +-- auth/__pycache__/__init__.cpython-312.pyc | Bin 1967 -> 1571 bytes auth/__pycache__/elt_auth.cpython-312.pyc | Bin 2402 -> 0 bytes auth/__pycache__/managers.cpython-312.pyc | Bin 14754 -> 6652 bytes auth/cookie.py | 11 -- auth/managers.py | 153 +--------------------- db_router.py | 14 +- form_service.py | 38 ++++-- model_base.py | 7 +- models.py | 39 ++++-- msync/__pycache__/client.cpython-312.pyc | Bin 15831 -> 15454 bytes msync/client.py | 6 - payment/gateways/_test_write.txt | 0 19 files changed, 66 insertions(+), 220 deletions(-) delete mode 100644 auth/__pycache__/elt_auth.cpython-312.pyc delete mode 100644 auth/cookie.py delete mode 100644 payment/gateways/_test_write.txt diff --git a/__init__.py b/__init__.py index b24ecbc..c78c9d5 100644 --- a/__init__.py +++ b/__init__.py @@ -13,11 +13,10 @@ GVSDS 分布式服务间通信 SDK,作为子服务器(如 ATestCServer)和 包结构: gvsdsdk/ ├── auth/ # 用户认证与权限模块 - │ ├── cookie.py # 默认头像等工具 │ ├── crypto.py # 密码哈希 + AES 加密 │ ├── middleware.py # CurrentRoleMiddleware │ ├── permissions.py # RBAC/ABAC 权限 - │ └── managers.py # UserManager + RoleManager + │ └── managers.py # RoleManager(UserManager 在 models.py) ├── msync/ # MSYNC 服务间通信 ├── commission/ # 分佣引擎 │ ├── models.py # 分佣数据模型 diff --git a/__pycache__/__init__.cpython-312.pyc b/__pycache__/__init__.cpython-312.pyc index d4782ed55b393a4e6631cf76d1d2e80fee74e25f..76d35aab4413828918e874b573dafe37f3b3a175 100644 GIT binary patch delta 260 zcmeyKa4>=QG%qg~0}y2GDaqp6$ZNvFczClDOC8hXKWxXeg7R}xeG~H%(^HGy@979F zPA!7+6rRpmp^%%OlA2SjS5WzWPv_>_?2lR0h11K5Q;Jiv_2c6+^D;}~%KtiZk=`iuiz5xo`f!Q^&;UvpJuCH8W$zW@%wfM#lKbt|E8&8i3NDLGEc_xXYqC zd84S~q0e=@g33*(Z> s6C|2ASAx{I!_u?YZS2q0L(30Jpcdz diff --git a/__pycache__/db_router.cpython-312.pyc b/__pycache__/db_router.cpython-312.pyc index a7c918096353cf6d7eb5c903ccf639066aadf6f0..6da9796bf1dbc079b43176fe2c823d7d69cb0e9b 100644 GIT binary patch delta 767 zcmYjOOK4L;6n*pZetDmyi77QUY13A#X^Qz6#7_`igiJT;>^sQbIzT6XE60X8Tx2hx`0uB z>otbv>rhtA1=tzm??r^Cf+JLjEmTCCR05*lNVd2^UJ}j_DzY8u!Ci6IFl@a?D(0PF z+T3|1-WTDv{3xR#%UA1;x9)kgFZz<}G;dIrbwz|!Y8b2Ea&6bXnT6xZS+WQXrA1WO zRgzHy2{g1vrDLF~MUsP(Iz^&zU5%5+&{b#PxgLWL>Liiir+Nf_s0ZMXc2$w6g<5!^ zW#+=T@#R*>cACC|OSkFJI5USdZEv&Xlqu~{ZbfG?zfb(cD3CI|Ggh!}*xV}0czq=;(n(x-Giiy} z_N7j(k>^;TbIfC3lb_6!WEEtqh$d&OrF;VK)AC3s+BNRu>wHkv_Ik@18L(2=0Uy&F z)Lw&M*7QV_6`o-RmakPgy;`LckPOXVV!op;Sa+27d6?~vGRQE5yUB*~~J(B}V zxfc+6!a$73+F$|tq0<&;GE!Qh1^690xR}F(uQWULx~r)KoCs&b M%Y?-K2n;#tKOp+06951J delta 910 zcmYjO&rcIU6rS1cZnr;nrBHMW7Fvi%sVRaL{6QclASA_LERxu08gQ4=+HK8jF_OT+ z1ih#UW)3EL_z#$P^diQDWWC@Y;GuXiHAde|X<)MXX6Ad}``)~_pTgA+?X#+S z5v(nP(l{DyBGXVevMO#SdmcqB}Xx*(&b=Xp)nxxCjt| z1?5x9hl?GXt$jQ2`TE{0?k2`|5@R2|-x4YMPU(XOepm86-Jm8xfGrnc z6-X4ok(TnMifyxD*NqFFv-m1~?TPcW5Z&|qjPq2T$^AE$OO?E3P7qQi+>P`Aeh> z5RXaqJi%DtK8}}9C|jDh%({UDDrkbwr(I3rJM_BRd7>3qa*7#fj*{i_Y?idqCu+}P zn8hLt*kA~2k?>}F*(uJTpTRkREkw9g3nSQDIj~9EX@GT96#|k{?L~TYABkP^FC^;j zFJiE&(Ld@%mFKdwm`sM~6-_^rgo`5=%ekCM>V_A9IV@6BM(RI*l#I~FTK};bjD!1# HAs77z0xH;O diff --git a/__pycache__/form_service.cpython-312.pyc b/__pycache__/form_service.cpython-312.pyc index a8e392b5c1ca06ae158992236aeb964c24250255..48f5de5c77a6d66ab38198186fbf3d6e0ecdfb35 100644 GIT binary patch delta 3532 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 delta 3066 zcmZ{m4Qx}_702)Ov!4??FLB~H{z_u!gT$s8NeKi}AQ19lhmD_fF_&?(=x_*;9YR^hx|+esg!n z_Ly|Q;%C2pl8pQ5GuWTzIK_x}(u3wI>`T9FzQy5Cnp%SxZ=n}*ZsQ*MmawUQl@X!m z(TL%&X~ZDneF21sO~J4c{6?^75V;9XZxMWmjeLxj1_|^Wz^#0+0GRN>{!%h9MfY1PI(f>Fr>JBiIj9b72kJ|_dt%kV* z$8=Hkk<>M3^^CK6x*#ytGM85{X1Q~F9qn=j=~kD69&mX^Ey&?JnLTY^zJRdcopXAg zwPZM^zLK9{aa=T(wl|`Sjin(AdT&K($crwO=Y?v}rIi-O_wA)&4t>yQ4Vk$q9s@1b zkc*pgVxZR=3UX5c46MlyBW`LVX1vVhhn?KzBFq?dE>$VpO<@0^N^ccndj0_~ZE+{^ z?G%d+v53(rx)|Mb((S}nI_KVFUB$){J76{K^n|vpVN&H2srYV*khRd?2zUsv4gdu} zHZZ6;o0G{wDU#5NKsE2yTdJ*#Rm|Nc(nPO#+=WJk6->~oW-k>EX`uh|jFoSO6<&@<7{=;2jTV@+IU#tym=2^Gh~83*Vh zBm~a5GNVptxRBr;4`ke+J^ExX=wi?vnG(>Y;81qP2ilK>;_)4sGSKC^a}}T~k;gyB z{z@w5e9J(%eelPGt8~s?HdkD^(8$J(nKSEAj&Q{KXX{%fk^%3f{l4=01RM}2OA3Lc zlXidu5C(KGsC;B-NJ@yoEbZMRd+9sAGMu1)^)=xW>0VaG5s6FWr*tH+%lr;A%Fh_+OkHvM-vN>5AA!w!Xn*aR%2zB2);rn;z1nGN=lUaPJ`K=Lo!6X}Nd@Z( z=Ie)hjA@l0ijYWLCSGV5_RHi12q8)OqRE69Q)0=4OiG~-?6RM4hHbeQCN{2frg>GQ-7HYS&N(k z7yu0n>~+#!_SMkQ1$Y-Q0Vaoj0)&3vP|^D^bT6fdn4t+@Tx|;i7mT)tYD%SI;wq92 z9WsN;M~TEf3J`aA$)(&NzvL4I|o?-w3ch13w+P3qIWDDt->gQ@ofp~WfF$D67~FMt_7S@*=P zn%S!rQ4~T_%%~dW$nau#iwU2EIgoWN+q%QQhvo+iYSz#`y|l>`^nDNT2Y?UY2fPQc zZUJ5byw9?{g|CM*x(;VV{cAnxpKP=lgg-HJ(4g1ZBt6x<2Jc9J+A zqp;?E;|9YU3@R^5gOVbtM!3L(mc;Mry$KT?iQQQW=U^9i%6TwES#GQv15pTnS@qix;wjhcivfh9B*jY_i2-UgUM zZU80$&oQLnsQjOv`}zDE8hYo=xfR_Qk16&3`=Eya`JVVf|$EH>IB=jDmM|-09sq~jUAp>rq8+xlp zwPh$66~GsOe*l&PRsiY%P{V2tyCalXG%hK7k|NPAT+NsJxiJH?mV6-#(1gU02LR=O zWeAxyqP6t1-VL5AlReXo5npiAP;RQa#W9ruwGgJw+gjOeM1Q<3+};9HwXY6bh_J}L x3xAchKAsd)gHjXunps(iBY6`8`@a&#Hw|`dytSMXtdEAT_koM60`X8uQ6KMbd diff --git a/__pycache__/model_base.cpython-312.pyc b/__pycache__/model_base.cpython-312.pyc index 6cf5b5622139b2070836c9c1bfb75717d5ee42ca..1f0691e1d26028a5fb5785c127094a9fb535a2b7 100644 GIT binary patch delta 1242 zcmY+DdrVVT9LMkX_O_)!X?as#QYe)2syf6d2;(KKydOnVaU0926D){TobKUkBrIlb z!Y?ys&h3vmk_}_BojoF9QKw-s7~ISvTeHOwG{(Kf%^)V*PCG)}&B^EFe(vx0JHK;I z?!+7>??FGQ*M~~tsT|+kJv^j0p>)XVH1M^%g8OkEN)vPc4pV$p&z zELJd%#S11dlVBoC5=>?(f~jnoU|JC~iz%ID2wGUCU>36qW;2^$4$BqHWBGyw%r3Z` ztq@#En~-|oZNvL;C$b7p600l`O)wX$8c^KHVy+f*O0d`UqSuxzUs&hcsGPJ8KflW(LEWMOe#HYF5y- z3KuR?8~!`6$LX=0X&Y4*4>Eh7%C?c8kfT%xrBSslU1{}rxBAs>{e51KUuoOd=kaR; zZ142>)vn&I9ld;BJqy_B2dy1N6dp2(HS}GGA9l`lMG74JCw+vBE&QS3Jg|e#Mb5)V zA4fevKmQ5LfQQ#xn4fiXIkc?n-oTh?Xm1+fv|*V1rH4E-Lhql1MdwAWgWOEhM^h6#Qo zI|-QNBequH8ehoifc8cpV7=-qj^sH$J(!8J9lsFRB(!qZ%zk} z^P3&DT71HDS&4#Q__l4Cz#MTjbZ`5cxWxy(3kocBc;^JH-0AC+kw;^@ zzlECK=-+7!3*20G05$=ejf{I-^zxpm+;>E0Vo19_6Z}IZ>dnb*jKF|App6B;Gzvs{U zPR!xTJ?JO&dL5J37g5D6cLww(xCX4HeqdV0!M$8ctDnPf;Aq$pa35DtYp^32jBB~h zwWc-15dx-SPG7!i8160@bC^8uzFa@zH>_HAp(<9wxS^MEf2WVrWRiMVy<8X8%yg|qCD-r}NfQs14CCRF5&1k)7EwG}GKR-W#&NS`Jhw<%d4i;kCrT#qWXZKW zMKYDANv`AR1gb>j5x!~2a2}3uUg(VAML9AFUeAkr6-T5jH_I~0lWU30)xMH{w8xc7 zSGM9}Jg!{2Eh{e8<0_=vy5izIZku$K&ebij)0owWGI}@3c;vq&u9#<=!UWQjcUbH9aw2agZE6ah zrjynn+L+ReKgER|@wT#?s4ZqMM~- znmzI}YfqzfRY4S8Q$mw=h5jka!(Q50{u`PpZp$BVk)h%?O2k6NIiQ1vw$0-JovIv^ zTa#S%j^?PlhvelR?37%ctvUW=r*^t7)vIomvE1sortkkPG_~32mqQNHbZst9itsu) znb)bQ{u=g)#D?b;oE7~$Vu3;NVPm;BE{X?xaum#or(cW*7Q}PScHp77&|(5KH1^UP zxFZ@|OA2gMz5fc5g{gg?3hU@Z=MCs+SJ!@j_YbN)!3~>)Es1{astak~A=8=)=sdWu zx$T8r&I6s!wvOhP+d61N_m{devQFNt<6F}AtO=~Y#p=Id^|SKOS*Mk-zkC=XL`u(F rNLie1FfbqEJqB2RQY@2-WmYX8mpTGu^m$E@nT?xQ6|Gl~r$h2z5wU^v diff --git a/__pycache__/models.cpython-312.pyc b/__pycache__/models.cpython-312.pyc index 1570c2be4256473be9d6c4274cd13835ca33d31a..37041c846488f9c0db135cb439a027e0fbc08612 100644 GIT binary patch delta 5396 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 G)BgiX<8-tD delta 4481 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

DG{2_C_pYepOkI23R=@TMmIx+eZs zpypuS-n?6Z!3P)aUHHV_&cpKu8C%dV*t@trbQgvzpN4ukD4A*p<&QsjGRadfHhf6* zGh;CGVRwomH9_{rfMj{<7{?FP!x-_w7&&2rT%IP_XQ102RTZxw9wJJP^$M|zLb02G zZ}S!!wG!BDAtJXByl{JXn|N-dYUuVrg>N9}qWJuo37_8{@c5o?=SQwya;0^C6YCYn zpW?GJI{-I+3JQle&GfNWrQDULJN6A>TppJCrgTABfi z%Y6s#aXj+`-(dBDCD6{B^^XVCzjdpL?RdW77j&!*)v}ehoij^}g=K{$tJ3twd_xY| zu=Z>kQ6I<*<-VO{w26KQ^jx~sb7|}Snr-Yiy`^LGy;FY}Y~t^*DV{7DhC()Y-o(3j zSLi+Dq3|Qw{^qyBXPzSEFXXO^c&7VNM8d*-(aZLO<&F-BP$tNNj zYUCmXN|g#-foKs0Jv9ZcXz3706sg#;4@5zckvuy)^WMzck>AdrwmY9(w?&lQ`XHaZ zH(z!3X!qUAC$#)Udv`e{sfYmPaaWvN-_d1l>dX4x~|oZ?yM;XQ45 zt-l(b#7^fXOlf5Q(b%drvTY)}fAsTqL0)So+Encc?FIGR$DR$ij)a+_XoV!v+Uodu(N0A)H|dX)HvXXTsBAL6u+;9S&1V&d1a<%A4bmVBq7X#g zz3SXo?09D+!$$x)ct*vtAPp2=mhKH5o z`%zfBraj+RXjgsWvvNnId}w|w?^%Nfn14gyx;o&Ra%c8Nn)6W-Zo*A<#T^UW#&?}k V`i0#7!7N8RvVJZu(JfljegjI3oNE98 literal 1967 zcmbtUO>7%Q6rSC6yc4hOb)33QLz`?A(_{+?5VcjI6_V40Hc&?qE*zprtBrS?EZHAx zcAa2kOX24b1VTAf3JB#u#i1w?9O2kI7bm@#Rej+nw6{V|?Wr@fYuBg|J#?jg^XAR_ zzBg~)oB1`7hynavTYLM1hY)~2$fWhLp>l8(D_cMV^I!>R%uQyV(b&(xJX_)9Ncm;F zxU}kOuC_9+mc3=^_w^gn-#2dUZ~T1k$M5g`^zom+e6_#*>HTju_iugo*Y=j&=cg{~ z-jse_Et_6$RrOTl$FHdF@|^0rYYx)<Qsaa^L#GbiSMo724cO6sD8=7Y7Ybw%xVaCmAmSMl= z>c|&o+)IvCQte7!w-&J>9Zm~Hr=)9n<3q#td#>rWYI~g~k)S&b={X%)hU*%RO%pRP z*O4$1^_wzWbD>)g{a?6qcP*KAebi zj%#>0d}t^#trFugf`1PG2LRW53siB1S4IIq8I9FA6Ie`*VL+Afx>}f>P|=u+SgSGx zf{CmGG=vddCTB%zECW2DW~u_p#8IYbJ34PhExs1P(IZb|v?#?y zCOJ*P<8`Jp_}a zm?*`h+L#`UNz{0Z;Sa&2D26Wp?_{eoTDl6pWw+U#upd5Q%$fVznw&xp+UQFSRbbu&MJQ74Ci4ciM5z#|LnuuO3FkZmj z9o`jJ=Fkzclp%t=L3ll(lKZLP8@6f`b##nc>45qIoeb!Bpp)UF5zEoarY?#1-I0Fk_FwqpUkzkHjR*jWavk1)e85+DwfZ!s%Ah9}r`}j7@Iw+GH6;0D*| zKS=nBIs{vQvBfsV2-d#wG(Yc^95;h}k;KhGc7$Yz>o5Jd^CgE`Om3&pg9# zqqfJNXu`9N;c>d3v0W%N#Qr+$$07fBu`Wt`ywrrRH%86{+a2D;8x;rYaNusNul~a1 z?K8JW>&M@@6T4cETs^=C2WDl?=M_bBii$!M)ilF%{Q;ntumh5@cmyv7t@$Q;1y9K( cbV;v2;24Ja4NUwSfdaeE9~{jxd4|Fs1BgNelmGw# diff --git a/auth/__pycache__/elt_auth.cpython-312.pyc b/auth/__pycache__/elt_auth.cpython-312.pyc deleted file mode 100644 index d3fd43fb31b1ac8fe0f7d770128d67d7aea2ac48..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2402 zcmcImO>7fK6rSC+y}RBd8*GCeq9hIuI8I5TP@xhEsrWHJEjUymNaV6wvXfxPKVfza zNwkrA;9w*q;7~=CDmAJ&1QDt9RC=l^6;!DgFRo;>lv7W+MWj_Ldg&Y6OGrXnE*;5l z-pqUNn{R&JTmRJ9=ta;@cI;1m=|<>RI&hk+uB`0^WdUhOW724h_H3HTuwyKPSacF; z+;yb6?z1)TF>aQLxmV~Q5o2sQe&)P#Yn@%n020Lqht-`Y8l3&>b^~{$xg5%D1wY?j?xID!HJt- zyAa_RbP>&>YiNeMh^{da`qFkf9_#%ZJ>75T8EZ@snrx8EP4Vf=ID?6rKA)SyS(tH+ z>X@w1+=;O^4_P`odiuC6f-+*LMqUROk1?0bPUKc-I?)JCoz++9OSQe=7SC$ulNk(# z#{9IV8d#Y~;1S##*h!eUH=ZNdG15%81w_C+mUbV(?84_e)WC3P+Zic)7u>U$9UrsM05A6*YRN&{z~NM|V@5857DNZd)3 z13gxt=RsF7&{GP$_b~ch|F`|ck4GQ&mkwUA0v8HmMGD-WDFt#I15c!Z zN?X_BOgTDeMF$^}Vsx++J!-WbEgZX`eYJ`T!0SKm*Pp2qwbqw diff --git a/auth/__pycache__/managers.cpython-312.pyc b/auth/__pycache__/managers.cpython-312.pyc index e8e16901c5bfaaeeebe23ad2aca0c71355b568df..5d42386a0b359aa3ac2faeec8ca0a3a337d0aa83 100644 GIT binary patch delta 1284 zcmaKrOH30{6o%)v(|75ES6dKDc{QWZ2I~ugh!F%dm`W%lC^n5VV(YYpJ1r4i=mK52 zA$M<#D~WN{xG^qFSZYj+2{A)h8bjhjWq~2Yc+M0`(-rpDZ}_8>XO9@)o9 zfHj$X?7MxfPe7?-2pq#d8WSa1%1MH;GEpbns%j*DW^e>ajCDJvLG+{F$DTU2A80*k zqG-eE?2wp1}rJF>}Q9UO}NIOI9HdCy>@*a&}M@bPSRe?07b>XuCk)cuv}3Y z?Z;3(b+9k)X6Smy-9zS>P(20053B#oqNr+)N;Hi+#nJCi5w9lw{}lP+g&Dy}>{Qj! z`LgENMooldn6q}YG`Lr+xz0PKwW6IWpP-hobT#P-5QOm^#+JOKCo$nEK-u>L_vA@k zgxqKE>h?!k=&5&;hCz(g(qO`(chnBA0=w>M3moP{r>F@x_S-7vW6wN3Fz$`#ELmp1 zJt=7AruXV-3q}VKA;fXSX~Y0x2r-7ZjEDkOIU2xsKf-zdE8Fv~cW4{9CfGH{RlAr< zWahG=d@d;~6hCs>z}C(LnZCDvS{t*bFpV1})m?LcIxFU7X@FjX4FW%<74Sn(2-)Cl bn_TD{H~g6!-sHM>tmkzkN`7(LpQiB_C3^!M literal 14754 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 0 - - @staticmethod - def GetShopsForRole(RoleUUID): - """获取角色关联的所有商铺""" - shop_uuids = RoleShop.objects.filter(RoleUUID=RoleUUID).values_list('ShopUUID', flat=True) - return Shop.objects.filter(ShopUUID__in=shop_uuids) - - @staticmethod - def GetRolesForShop(ShopUUID): - """获取商铺关联的所有角色""" - role_uuids = RoleShop.objects.filter(ShopUUID=ShopUUID).values_list('RoleUUID', flat=True) - return Role.objects.filter(RoleUUID__in=role_uuids) - - @staticmethod - def GetMainShopForRole(RoleUUID): - """获取角色的主商铺""" - rs = RoleShop.objects.filter(RoleUUID=RoleUUID, IsMainShop=1).first() - if rs: - return Shop.objects.filter(ShopUUID=rs.ShopUUID).first() - return None - - @staticmethod - def GetShopsForCompany(CompanyUUID): - """获取公司下的所有商铺""" - return Shop.objects.filter(CompanyUUID=CompanyUUID, ShopStatus=1) - - -class PositionManager: - """职务管理器——提供人事职务标签创建、岗位模板管理""" - - @staticmethod - def CreatePosition(Name, TenantUUID, Code='', Level=0, **Kwargs): - """创建人事职务标签""" - position = Position( - PositionUUID=uuid.uuid4().bytes, - TenantUUID=TenantUUID, - PositionName=Name, - PositionCode=Code, - PositionLevel=Level, - PositionStatus=1, - PositionDesc=Kwargs.get('PositionDesc', ''), - CreateTime=_timezone.now(), - UpdateTime=_timezone.now(), - ) - position.save() - return position - - @staticmethod - def GetPositionsForTenant(TenantUUID): - """获取租户下的所有职务""" - return Position.objects.filter(TenantUUID=TenantUUID, PositionStatus=1) - - @staticmethod - def CreatePositionTemplate(Name, TenantUUID, Code='', **Kwargs): - """创建岗位模板""" - template = PositionTemplate( - PositionTemplateUUID=uuid.uuid4().bytes, - TenantUUID=TenantUUID, - TemplateName=Name, - TemplateCode=Code, - TemplateStatus=1, - TemplateDesc=Kwargs.get('TemplateDesc', ''), - CreateTime=_timezone.now(), - UpdateTime=_timezone.now(), - ) - template.save() - return template - - @staticmethod - def AssignPermToTemplate(TemplateUUID, PermUUID): - """为岗位模板关联权限""" - ptp = PositionTemplatePermission( - PTPermUUID=uuid.uuid4().bytes, - PositionTemplateUUID=TemplateUUID, - PermUUID=PermUUID, - CreateTime=_timezone.now(), - ) - ptp.save() - return ptp - - @staticmethod - def RemovePermFromTemplate(TemplateUUID, PermUUID): - """移除岗位模板与权限的关联""" - deleted, _ = PositionTemplatePermission.objects.filter( - PositionTemplateUUID=TemplateUUID, PermUUID=PermUUID - ).delete() - return deleted > 0 - - @staticmethod - def GetPermsForTemplate(TemplateUUID): - """获取岗位模板关联的所有权限""" - perm_uuids = PositionTemplatePermission.objects.filter( - PositionTemplateUUID=TemplateUUID - ).values_list('PermUUID', flat=True) - return Permission.objects.filter(PermUUID__in=perm_uuids, PermStatus=1) - - @staticmethod - def GetTemplatesForTenant(TenantUUID): - """获取租户下的所有岗位模板""" - return PositionTemplate.objects.filter(TenantUUID=TenantUUID, TemplateStatus=1) - - @staticmethod - def CopyTemplateToRole(TemplateUUID, RoleName, TenantUUID): - """从岗位模板复制权限到新角色""" - template = PositionTemplate.objects.get(PositionTemplateUUID=TemplateUUID) - return template.CopyToRole(RoleName, TenantUUID) diff --git a/db_router.py b/db_router.py index b74abed..accf15f 100644 --- a/db_router.py +++ b/db_router.py @@ -35,14 +35,8 @@ class SAASDatabaseRouter: GVSDSDK_SAAS_READ_ONLY = True # 默认 True(子服务器只读) """ - # gvsdsdk 内所有模块前缀 - _GVSDSDK_MODULES = frozenset({ - 'gvsdsdk.models', - 'gvsdsdk.commission.models', - 'gvsdsdk.payment.models', - }) - - # gvsdsdk 内所有 app_label + # gvsdsdk 内所有模块前缀(startswith 判定覆盖全部子模块, + # 无需维护显式模块名清单,避免新增模块时遗漏) _GVSDSDK_APP_LABELS = frozenset({ 'gvsdsdk', }) @@ -57,9 +51,9 @@ class SAASDatabaseRouter: def _is_gvsdsdk_model(self, model): """判断模型是否属于 gvsdsdk""" - # 按模块路径判断 + # 按模块路径判断(gvsdsdk.* 前缀全覆盖) module = getattr(model, '__module__', '') - if module in self._GVSDSDK_MODULES or module.startswith('gvsdsdk.'): + if module.startswith('gvsdsdk.'): return True # 按 app_label 判断 app_label = getattr(model._meta, 'app_label', '') diff --git a/form_service.py b/form_service.py index ea2cb09..c4488fd 100644 --- a/form_service.py +++ b/form_service.py @@ -14,9 +14,8 @@ 'MyModel2': MyModel2, } - # 子服务器 views.py - from gvsdsdk.form_service import FormServiceAPIView - from .form_service import FormService + # 子服务器 views.py 中直接实例化 FormService 使用 + # (FormServiceBase 提供 ORM 能力,视图层由子服务器自行封装) """ import uuid @@ -87,6 +86,17 @@ class FormServiceBase: if val is None or val == '': if getattr(field, 'null', False): return None + # 非空字段:数值类型返回默认值或0,布尔类型返回 False,其他类型返回空字符串 + field_type = field.__class__.__name__ + if field_type in ('SmallIntegerField', 'IntegerField', 'BigIntegerField', + 'PositiveIntegerField', 'PositiveSmallIntegerField', + 'FloatField', 'DecimalField'): + default = getattr(field, 'default', None) + if default is not None: + return default + return 0 + if field_type == 'BooleanField': + return False return val field_type = field.__class__.__name__ if field_type == 'UUIDField' and isinstance(val, str): @@ -115,12 +125,25 @@ class FormServiceBase: return val if field_type == 'DateTimeField' and isinstance(val, str): try: - return datetime.datetime.fromisoformat(val) + dt = datetime.datetime.fromisoformat(val) + # USE_TZ=False + MySQL 不接受 aware datetime: + # 统一转 naive UTC(UTC-0 存储,展示时由前端按用户时区转换) + if dt.tzinfo is not None: + dt = dt.astimezone(datetime.timezone.utc).replace(tzinfo=None) + return dt except (ValueError, TypeError): return val - if hasattr(field, 'max_length') and field.max_length is not None and isinstance(val, str) and len(val) > field.max_length: - logger.warning('字段 %s 值超长(%d > %d),已截断', getattr(field, 'name', '?'), len(val), field.max_length) - val = val[:field.max_length] + if field_type in ('BooleanField', 'NullBooleanField') and isinstance(val, str): + low = val.strip().lower() + if low in ('true', '1', 't', 'yes'): + return True + if low in ('false', '0', 'f', 'no'): + return False + return val + max_length = getattr(field, 'max_length', None) + if max_length and isinstance(val, str) and len(val) > max_length: + logger.warning('字段 %s 值超长(%d > %d),已截断', getattr(field, 'name', '?'), len(val), max_length) + val = val[:max_length] return val @staticmethod @@ -141,7 +164,6 @@ class FormServiceBase: 'FloatField': 'number', 'DecimalField': 'number', 'BooleanField': 'boolean', - 'NullBooleanField': 'boolean', 'DateTimeField': 'datetime', 'DateField': 'date', 'TimeField': 'time', diff --git a/model_base.py b/model_base.py index 3324e1c..c522eda 100644 --- a/model_base.py +++ b/model_base.py @@ -24,12 +24,7 @@ from __future__ import annotations import re -from typing import Any, Callable, Dict, Generic, Optional, Tuple, Type, TypeVar, Union - -try: - from typing import Self -except ImportError: - from typing_extensions import Self +from typing import Any, Callable, Dict, Generic, Optional, Self, Tuple, Type, TypeVar, Union from django.db import models from django.db.models import Q diff --git a/models.py b/models.py index 333e618..5fd6ad0 100644 --- a/models.py +++ b/models.py @@ -7,7 +7,7 @@ 供子服务器直接进行跨服务器 ORM 查询。 权限体系四大分层: - 1. 组织人事层:Tenant → Company → Department,员工通过 UserRole.DeptUUID 归属部门 + 1. 组织人事层:Tenant → Company → Department,员工通过 UserRoleDepartment/UserRoleWorkgroup 关联表归属部门/工作组 2. 岗位模板层:PositionTemplate + PositionTemplatePermission,权限初始化快照 3. 角色权限载体层:Role + RolePermission,运行时鉴权实体 4. 鉴权规则层:操作权限校验(角色汇总)+ 数据权限校验(组织属性) @@ -15,11 +15,13 @@ 使用方式(子服务器): from gvsdsdk.models import Permission, Role, UserRole, RolePermission - # 查询所有启用的用户(需在业务子类中定义具体 User 模型) - users = User.objects.filter(UserAccountLicense=1) + # 查询所有启用的用户(User 为抽象基类,需经 _GetUserModel 获取具体模型) + from gvsdsdk.model_utils import _GetUserModel + UserModel = _GetUserModel() + users = UserModel.objects.filter(UserAccountLicense=1) # 或配置 DatabaseRouter 后直接使用 - users = User.objects.filter(UserAccountLicense=1) + users = UserModel.objects.filter(UserAccountLicense=1) 设计原则: 1. 独立:不依赖 gvsds 内部模块,可在任意 Django 项目中独立使用 @@ -29,8 +31,7 @@ 5. 租户隔离:所有权限相关数据依附于独立租户空间,不同租户互相不可见 注意:User 为抽象基类,仅包含 SAAS 主库标准字段。 - 业务子类应继承 User 并在单独文件中添加业务字段和方法。 - 参见 gvsdsdk/business_models.py。 + 业务子类应继承 User 并添加业务字段与方法(如 gvsds.apps.core.models.User)。 """ import uuid as _uuid @@ -186,8 +187,7 @@ class User(QModel): """用户表——系统核心身份模型(抽象基类,映射 SAAS 主库 User 表标准字段) 本类为抽象基类,仅包含 SAAS 主库 User 表的标准字段和方法。 - 业务子类应继承本类,在单独文件中添加业务字段和方法。 - 参见 gvsdsdk/business_models.py。 + 业务子类应继承本类并添加业务字段与方法(如 gvsds.apps.core.models.User)。 """ UserUUID = UUIDField(primary_key=True, db_column='UserUUID', verbose_name='用户UUID', default=_uuid.uuid4) @@ -202,6 +202,8 @@ class User(QModel): UserTele = models.CharField(max_length=16, null=True, blank=True, db_column='UserTele', verbose_name='电话') UserCreateTime = models.DateTimeField(default=_UtcNow, db_column='UserCreateTime', verbose_name='创建时间') UserLastLoginDate = models.DateTimeField(default=_UtcNow, db_column='UserLastLoginDate', verbose_name='最后登录') + IsStaff = models.BooleanField(default=False, db_column='IsStaff', verbose_name='是否员工') + IsSuperuser = models.BooleanField(default=False, db_column='IsSuperuser', verbose_name='是否超级用户') # Django auth 框架必需(由具体子类覆盖) USERNAME_FIELD = 'UserName' @@ -537,11 +539,13 @@ class UserRole(QModel): 通过 CompanyUUID 标识该用户-角色关联所属的公司, 用于菜单按公司差异化显示、数据权限按公司过滤等场景。 同一用户在不同公司下可绑定不同角色。 - DeptUUID、WorkgroupUUID 为可选字段,用于将关联进一步限定到部门或工作组。 RoleType 标识该用户在部门/工作组中的角色类型:0=普通成员/部门员工,1=组长/部门负责人。 RoleName 为可选的角色名覆盖:非空时前端展示用此名,为空时回退到 Role.RoleName。 这避免了为每个用户单独建角色,又能让同角色在不同用户视角下显示差异化名称。 + 注意:DeptUUID、WorkgroupUUID 为遗留字段(已废弃)——部门/工作组归属已迁移到 + UserRoleDepartment/UserRoleWorkgroup 关联表,字段仅保留兼容存量数据,禁止再次写入。 + 注意:UserUUID/RoleUUID/CompanyUUID/DeptUUID/WorkgroupUUID 在 gvsds 中是 ForeignKey, 但此处改为 UUIDField 以保持独立性(不支持 select_related 和关联属性访问)。 """ @@ -719,14 +723,24 @@ class PositionTemplate(QModel): ).values_list('PermUUID', flat=True) return Permission.objects.filter(PermUUID__in=perm_uuids, PermStatus=1) - def CopyToRole(self, RoleName, TenantUUID): - """从模板复制权限到新角色(一次性复制,后续模板变更不影响已有角色)""" + def CopyToRole(self, RoleName, TenantUUID, CompanyUUID=None): + """从模板复制权限到新角色(一次性复制,后续模板变更不影响已有角色) + + Args: + RoleName: 新角色名称 + TenantUUID: 新角色所属租户 + CompanyUUID: 复制出的 RolePermission 所属公司。 + 缺省用系统公司 UUID(与主项目 RolePermission 创建一致), + RolePermission.CompanyUUID 为非空字段,漏传会导致插入失败。 + """ with transaction.atomic(): role = Role.objects.create( RoleUUID=_uuid.uuid4().bytes, TenantUUID=TenantUUID, RoleName=RoleName, ) + if CompanyUUID is None: + CompanyUUID = _uuid.UUID('00000000-0000-0000-0000-000000000001') template_perms = PositionTemplatePermission.objects.filter( PositionTemplateUUID=self.PositionTemplateUUID ) @@ -734,6 +748,7 @@ class PositionTemplate(QModel): RolePermission( RolePermUUID=_uuid.uuid4().bytes, RoleUUID=role.RoleUUID, + CompanyUUID=CompanyUUID, PermUUID=tp.PermUUID, ) for tp in template_perms @@ -793,4 +808,4 @@ class Position(QModel): def __str__(self): return self.PositionName -# (UserDept 表已废弃——员工部门关联改走 UserRole.DeptUUID,不再用独立表) +# (UserDept 表已废弃——员工部门归属已迁移到 UserRoleDepartment 关联表,不再用独立表) diff --git a/msync/__pycache__/client.cpython-312.pyc b/msync/__pycache__/client.cpython-312.pyc index 78db8b919925f2d97d5b90177c61cc24a0891e10..f0ffc981411deef5b4918a1fca22570513ece497 100644 GIT binary patch delta 2287 zcmaKuZA?>F7{_}`p)F9VKwClRi({6HSg;j&Rfh~M8c?B{$fh@yUZDfqa(e5eqRh8B zH@3w*$@YEkghVtoBXKiXvVB;xm_V|`tRK`Z(dozOJ}k>(cAn>gAWPN{znuHr|9Q?i z&-1_c_RguhCoMl&EcrU|JNT{oM%@)l8JoM}g&lg`E?uPHf-X|1*r#*wzE0Qgpr}Pe zi>CDpu{9L4irA{>v9d9}v^t|_g9c;W@#I)+pbiqbS@^+tFV7{WaW_nvoXiP7n%ry) zJT`gtPjygi_K8rt*;f9N&?K3_E8Kzd@82EEPf}G48`eeh3$AF6+cRMFMZ>?psUlSl#nh z_ngViU(nZS`lkh3%DPtQJ@Z!2oXPW|ev_uZR9MZr;aZ{1fIEk}d^_ALjIN1!6p(T`o|iWu8U?cE&Xb8KSCZ{2Z-!k(wJZc` z(Z;p*7Z zy1W^+ZHVoNc7dsdl+>{rj3Q8zJScEM_lsfO6S!*Kul276Ce39T=c>{iRsn$$|6Wv! zl~wFqQZi^K4T>PgTJzlkNrQk}{Fe3F-ly;r(E+7nB&x*J=iN@hjgtDsI@sY^Noz5k zRnPZeHrl!$_LOd8r{LXEC;6fbhHZg$%Vkt(Kdy{!Tv)aN95!d=1V)Pm$S@y{Umm|> z_0C(pb0#mD;J?YRVSHt>M)=O=V&~z$ZLQeDKemZHGP@tn+MC!VxM}xNI9&eVo!N&U zU3>7^^+z{8m-L*hxF9|3@D)vB@;(H4?3u@&nQ;VjSrGoJxWxwH>&ngjNAUJ@@9=GS ziBBO@t)~v6b z7{Xx`@xO=RBSIoMv|dy47|w|!Xu$-IMiCs5M4-d6j_$rgJsooUflyHH?cCYh*%y@e zwTFT{g_4OA$Ttxu5o3sP#A(DC#3{sT#M1eVnw!sI^gQAMf{t(zN0$VWMgcUp_-X#e z9;eqX_xCDc@LuJZc;JWV4fjo^!+S>WAF@97PZcto0vZ??c*ORp-Kh zTOd^;@MvcC;q`NxMO)m#P-vf9s^ssXhFlkf+y1JFrA}ZIvbjgcR3*tRs9MnwD)~~e zWt321sS8y5G{(pjSoW+T8ao!(N`S8<`fx}kRQzmSw<3-jfkeQzz8S^Fka*|DQ);$= zE2Hv|5{@W5$=}9#T905l;9(cxcA%>Q4U)DkZ-wgXRYp@vQhl89Z;l(-FnrQfW5UEz z9^VZ=H~CCBNy-t{&u{Kz)v&L*S9>A--gwhT_52hCENh5`#moN-T*AVY!Dv$DV=Y|l zhkv=4?t_-HiYalya}ZRl#q1ae!uKtmtQO3zeG~Znb8>{Cr>BP=9%=Q8H$2~gA}68) zLC&Ebk#l-6b^t;4AtO;6aZNsrm_fXXp!FO$+KI?ThT(qeX*b=$OQ~F2kXqj=0$D>U z6^+1nTR9trkK5|Y=>tShj*3YxBfdghg-`XTz# delta 2510 zcmaKteN0nV6u^7iS6XNbQBEZP3RESp>ZFwOzuV&YkZgxUfPYhjZ&Lv7fq291k*5qw&RsxNRc=OWHkqez; z$A(6S4%`{)8SDS-R{!8w&wzX7%B73$4E0i6OI5qhS-kN+aZ5r}2>V-W+R4?PV5MdS~O=E;(HtT$m4Q8`nD4(HI^RqDNhxp_Jn|e3xX+B&yY{@>n z<#@`68SiGiXS-^jb;UkwSac1W3WtTldrV&gB{8>S^4Ne%AQ>hTRs@4c=7Hbf&{8`b zG&q^)vcZ~xvvb!Axoi3?+8{jen;|vE&R+-2Mh}@jZ9-Lzk~-LXdx~5a+^hs@!$GPz zW!WF_hh@1OXskr+;EbDN$z@s+p~X0n8-9u{N?(Ta#4~hit|ug4O%Sgnh{Hyah4q+z ziK-upD^9O|O5c7Z!9HxXKdC=g)i;>(NG%kYtO7<3XN{>KoBU}!2%Q>4CTh-6)vufK z$%|ky7qDRGn;RUcM=|S?p5k)pbBF~D(b)3st$wP6O2f1izB1>NdicXUW5UfUGc7_@ zv}McevE+5E$Ds$olgL9b(-|mmB4#o~4YKSDHpnthX4Ke9gRKe;w>|PpOHsEBu^3Uo zaN@y~*eldEf#=yEw2Gly^P@23F3gNyp_b1DW@Gxm(fAY{$%Vm0S0S1(&tWWFND|bQ zVwUN0#0rKG?ktf#YF9WQJt>pyfZ0g}6Dv-IjwDYKUzL{DpdAm=4c{cqCtYAlp3EB{ z9d0KVPI+97r__x;2>MVRJO_uF!K>g+Nse_~NpK7s9lXB(HOFGmr_C2YX-YQfW#*a8 z>&}#p7~aQj&|2q^ec-V=xY(O9+H-#F&5uWqpBo>1U(!Oetig`QMHTju8^0427fWeR?N*cY@MUvandN}Uj%{)F|DY*a)IJ%T41(@U4bm$pK( z0{*mBk{~R}%1h#TiKKrZZgM0>;N@uCvE}jl zuSS_0XkG;wflGM{h<)I%ylO)lrc=^IEv4)V2vUE$H|!4vs298i)3ev34bQS4M?C!$ zN1GANaI)Yf0uVPVXQp}xGifB5Vf^g*v2(lC{&R~Jb#=={DU0@@5pSt#ST`%D<5AYP zvM*8nhPJR0q88NJhS-j1L-340O7=#S@x<~f@Z5Kzj5h$LJu3JE8-r>J@GRkHy_C$8 zAC0M0*iwB5UDm0ksB5TW7gI12j+&^lMQ&2OK81$pUNlon1Rj^2?16Qzr8W$w-TGu9 zYLqPzB^16h@P#WV5DKo6X-1q_ilHmOSK>6Hk)&f?{&q<@al-YI8ufVDR(#RP(|H0F zNK^=TTNHWmVxP&>DrxZth1wH