bQb+z^#7y3hu;4!
zaMT|i13Ct#76$Tic<8sj0%{KCQ`0+*n!S0{957IGb1pSKIn?Y&)RYASz{wZfQ>$=#
zZgdRj7`T`i!1Vt*-p8TeqhF)Wt168W+4&v29Q_k?c?ZwkkS7lmhp
zFAEO}dxb9uTLqucE8H!t7utlC!e@j!p+>k-xL&wgm?;?eKk*;&Kj%mJAM^jr|1JML
z{@eVU{Biz8{u%zu{Db^n{tNt8$m-dQf4}B_%KbO@uTU&QKjH<1J~H%S6CCz{k%KR*
z`aHJG14|HF=7ME2w#)&G6I*73ME
zv1K|~=3@&cuC4+zAIxcBPBW~7tOz+}hE8JMU~mv~v7v*QrG~Y{Tx4h`rf670%o0Nz
zF|RkY5_6%Ug_zeFRugl9;dWwPYiK6se8X+TyvDGKn8k*b#Jt+jM9g`H6~vrtSWe72
zhGoQ@ZD=IsEW>Asd6nT-Vip-bL(G|mTZma`xS5zU3`>bQ-C!qXfuVtz`34&?ry1&r
znP;dYromt(X0E|P%p8N6n8;uvreKhW$s3Hszy=1G&?&v6(IaJahrj
zPZt1vngxJN7XWU$0LY;W07Mr6LJlkd@&y5!CXap%zuXsL1o$uXFX$i8UqkOdiN1lp
zhQ5NHM2|q<--Yf$0kj$Qpu5mobQ`)AdVV#!0WCnYQ9j~?-$1{Q3jZejK=^CnJHp$-
z3F!4t!(HMJ2)l$~VMyqMKEFkdYC-=~%PfDYVU|BuGs_>UnC0Uo%<}u2nB{ks
z%<|g`X8BDyvwU_EFav!EWcjNEWavcmR~MnmS2d>@_q@k{QP=m`Po8ddG9)A
z`RM{?`N_4+a&|tmj9)`7{D;NN^1;=V&<@R`W^gVw19PakWi~a3W>M3B6*YZD)Et~i
zO>ZGJ2WC)n^K@!@*aD!REdcrw7639^0Jzx#Acrjg5Xys|@&L_cjsaias6RRebPVVi
z&@rH6K*zuph5@{KMM5_xbOR;didwI*;_Jmtg@Np~f{1ZxUU7LjzpEtV?D5LM;b3<-
zCRZ=YeajL>U*+lmnXhTDkl$Eij)s_59d#k+Dag9UXbdkgVHjVr6`u
z!6APjM6~QVoLl8|s&X)(+CJG=s|ue&O%5eGOYIv=K^LFLx7F`)$xIg?=!c1(I33+{
zH2T78<8K^&|MZiE1&bFi7MlVAe?Z(4mIH7kzfW{K0fsXu*NEbBCy=0a(I4omp=4o=
zV{HpihfUjE@=(a*_u0jb;L_aL)ZNt4v8H2_2w$R1-~q@%PcW#4C|3AnXFx2yvD7XG
zhkYUEb{ZC_GMtajewoD`bPkL1c26)QdVFH9$195)SJ=C@`2z!8P^w<%kjLro3ONIP
za;VGYbq0fSuxoI*2dc7izrm7NNe=}ttxC#XtpGws_8ZJPLX>6-2sw)TzkojA(8utj
zKRO0<3|#gYU;+S$NBQ|!L`8u8f9U^22;j0Wyk0;Z16MW%r~m)n>lk1d(9Hjs{^xRZ+~^q4F>obf0Mq|D{KFjoF#mmFmGH!sh=VCr
z=7!HqO8kV#aKyz=@aN}-Z_O)SRL)20spyKUUv_unyJ5BjLicos0-nA;IS_O*(Ua!3
z6-{@FrNLOJ(!zo@ZDOe=Fvy~)Lx7|VTs%NvmNI)^z#kqet!!UrC|H1Wq>?0JF+-jZmd6o0o9^tauqH?wDPe|(VnHOW
zJQ53mFENpQAq9@f2v_}JaV2&=0|PG+H+sobch9gAy3V3@4|xWa#4v>L5NuD$$)TBh
zLTGkV2usgowPN`n(*HRVC;VEtp05DQgij=Rhvtq1E4d1
z-RH6@!0yKCAXj6l?sn;MhFtya0Y6lAFx~zi1zStO)~aKq*ah^sTVVGL?*dAtRi&nL
zxEaEX@4_(K>}FFWxc-VOwNZ+6tRvTurFQJs&7GoU@7V|cKM0*
zoU5`PuDsY)(0MuD@p3LVp3rt(XEz%s?CyF19RoTBE?W!~3jZ69sDB%w+tCtqGg^r5
z68?yufYZPKTlgXRqVOJgZAC?(7w9bfs{eip+QQi1Wr`dSh*~~j(IC+E=>zf4aAJC2
z*m>>cc23~`xwQTed4l{QPo~UWioOZRC|rn2cn|~YCTj!%N>sq(^?`TJd{ikAo4?QF
z^Z0uG0q&uq>(FB2jTbRqf8V^T=Akm;;2(lB3E(m`qXI1?F8H*8Fk=q;!pkeej6(K>
z&l%*Rcexp}n1dVSzkD;NqeUbtCHsZKxo9ED!l3L6=iG>1;R^GW9L>ERRmbz)O>gR)
zGyPh$K*?Y3tgBHu`EYw&q3#f@G78YYb2IZ}rJYr*4uIv<7S6neWdZ2yUQZw9?O~-9
zSIUzR9B191CNa!I37LtmJ+mMZ9J?k
zMbObhM@J7oTQU0F>FDW$_6_i~wys!FNu#f9zpEu}bRtkc_R@i|*G|#UtJ@v7$3shS
zh=68`d#v7^UE550Nz&>JZdt6U0#(rQIYX0slvk|95x;S)?@S))6-{X6^|Af!1JQ2PypOY4}x{5gS
z=$F49{mL^@vZ^`r?vc^Ri4{#N8`rgTZt(b;!VY{2J?xd;ozCDujmHOvFG6g2mK;$W
z-FYgy=e6;jhhV`2dV5U`#?ccmkG=GW(PT8$RU0kU#(Gh*+KrOkXpEp4BoBQTHV=~3
zCe@|Rh0$)bM$mMei#0ON#ZzzKGST(j{x?T=Mi?d>;SFJ@Pm2nAl3PJVQp`kDNOk6h
z6uFS>k`ZXV2vByJKHxH?S6dP|yISnXy@M3_c$L8{}z
zHB6giN|On^_==#si-8KsX0#>s4_YBcSl8nIU%>q%hh9TYG($Kg41gYh@AKP%7x0f+
z83aBBARPq-Tv=^VvAK|w#$G=)cIw$N($DbeE0=!|4w!dS-3vyid(h*9QA4VhOx2Pk
zN;bPyvYSj}Pn?Rr^B9d49XSNdt2WS-T2@YBj(+LDnRgBYVJuG8A9BF}3#M9smg}HGQo;h_Yy8lRYWbfFi`!FzkB9EvNNefRMgTh+_
z_bZoG(#%ocI0`Ym3Gk0Fjh@~a-SaxmpwAx|bb7npo*-s2rp+ZSHI2qf
zEyPPbe(*4G5aYQF_WQSW_j}yw;i+R#c&$9ZD`S~_^w{XgTcbN)ijKUDGfA#U3d-Bl
zXHOM@f+PGt;TQ*Z{dU6r-N!zK?y4uLV_-rII3iaSaK$AHOBNNCnaQx7#OPn%AMg*#
zqGY-Q^dI@R1x4VI(}5f=qloT*Hbx!VAPgSo&5|Qhluf9T-C_o|nja$5jrV?LNu4(EtlGjJ7V*rQexm+bU3H-uIIVv|AInMHi&gs
z!RIc=UC(pT{}n@qMEn0M99kl*=Of%JQ+c3^bo5Q-)_5+01yBLNpfuY}b&-zV%d1e(
z%gm7u`En~1u#!96mrmw3>;Id|1D>8Y9RoTBbPVVi&@pg0Dck|1Wg#
zf8bx_+qvI!FM#toK90zYZ1N~E+Y{E^j>z<^K?TCQ4)&ozIKUBsZNe;ZlnGQ5>>OGg
z5!fiqGE^gA0JaOW2i0n~nCuqdD8q(fHldpE_NgNRn}*qh3dv
zedjVNmR=N&+wJn_;Y)e;?ugx>Lj*+pKCj0|uF+9_R%=ejk*jo6zVtqwAY91e@%x(H
z%H=ePSK@#MZI6#$55#Vnfe`qj8mu5YmAhxi>2?PcaFPj*&_QSl#_M-ELy(-}i!ZFf
zzC8ih+m~aJSPK525{@}g=^w=rpW}nL;1~d9+Hi{w*anBd7hj+wG677nA{YwvV&97L
zvJKT`gVkkjvFtW`S*yLQx4f#{=igRdNpt87hPs_Dd_xU^cHV&G?L(e`tiWh)>ug%p
z)Dg>%5%R3Qum~<=idR9SV>!OS=awNu@!BOkNAG;1H!nHEAwT)X|RVNR8pm2p?lc3#Dqc3LvQ
zdT?7+27dKmpZ<0_GMlR7;Wm;y_nH$ftRugl)^wfFzwu^0D$p_}8mzvSTmFS*s|lD+?P_nZiqS6o}m?^#Eu)d0*ATm5ifB-8JZ
z)P>F3u9@Ud`lu+D;*REl8yw;C%=EWM0)8Q=dvkxOT15lyUc@=DMdeP2TyX9kx(7N{
zOx1+qJTMg8ta8SR9w-=9+lWP?vo!!?p7hGc6^)%uG!AQ%_&&+xILtFKjzT%pKEe|3
z8|>{Kbg7`k^96YBRtADtBG?<67Z8_6u9!LHQY2Y$9>jrecZl=^a&`ZJ40UMHC@yybO=%bXfxa4gzjKXaZHp%)
zH*I$TBM5jpc5x%PGDVN~mna7U{s2T02R*=NQb80eV8Q1f9P-M*tMT}T
z!XcPi7B5~bcJ|9G)}V7(l()mW4gAGkk5?8quCR9jQ8~~B6ML_7$m8^P0qNN%hq_!|
zpf}}U*WfVR8|(>oVJ%W!t7Km%KH1gk9D=*xYPJu0H>FAg(-hvVvY0`a)gXnC05B+f
zWmjlL4@m@HN4#vf4M_1|Vj_N*D;$6YthlWomqOkyyTT!i45vsiO~V7a>>>pz5^{$y
z*Q%JEt<0-L6;V(ns_U{BPRanL;8wgr!ei^k*MJW?YY40$=#|>mF9)EM7$XEUxgEQu
zd3BRmPA&*9D;J$Ucj^F`L!t4fz{OjDzecbSYbq6$Scg>tAdioh@xnKvf~8{E2TVq}
z&mZvI12_k?#+v9-(k3x21Z~L|_IfuhWo-@1ON$#N`2K{Ac&P|%*bt;EEB!+B1TSQ-
ziAi{yi1;bq2+uU%>wY>0bPQbH7{K&Dm&0*r5n6P4msBsEj)C*Tz<+Ehq6h9v#!kI4
zy8i{LCjo1oF-kU2HdAes#PJ7?p859E?D+q_FOEKOjE0q{5#75ddi-1I&*dLKGWO8k
z=);dg2DfY}qBzquX^RSj~!<`UL5sc=FvV-I|zf
zQRB_7DzU-^TnW6Q^#LORG`YZ94tHW$kAg%;IV?bLyb*p_lmU5ITm(MQ^U5p55ROzX
zm5Z_$K;W37>~mL&&LFJRU}J%9Hfxel!C_z$pp+W{TpY;IKou>_7ihfj$!E
zqo9am0qq=$$qC|}S)7*`S(Xr5MU^oh96I&>KeUM)RL!BkMNc3%sz$k&RwL1Kt79M=
z7^o;J$_J%-07{aQm+2BdEN_ymIn%j$Wjs;7SBS-?MxQti%m7%oN8dV{lN^m{lQg60
z+$<$pf8fl?lhOT8jeqmL(UT9M^pONrq@aBE$hXFxIzD#lAn*xIx6uZrn^fji7`hlLGzESO5q
zZo7jJfP0%_1RxfD#RMQWxi2LXfY_Z9fJs8KYG#_4UbuG1833tvE$OJ0VfDeWkB~nQ
z6GLU1+G%B~t=t59r5xex0)->cCYvLaWuWzTslgGX
zE9gn|2-=T!p?gpOZALxlF0>ZihHgc5z$>@`EkLtTKH`Mm2tOC1!oLYW5dK>Dj_|f{
zLU>VlT6k1=K-eV=3qwMmaJR5dXc3kRc0m#|mDC4rW=jmRZDhW+_?2EZ4U&%feP>xvqs-7OZBLYj06k{=;Hs`QU2OoP^LkY6j<0GcbpmTV_*p
zXcjg7S5ebfM9smO)btiob6^HFH&3Ugr+}LM`PA&2M$O(lYRU#`x^tVCEVW#-1qrB?oYf;cwP9Ka71`qI4JBDb_gN352Q!fAhZjsgwF_8RD!NX
zg(ye(SooE2R`^fhhr-_q-xW^7xRKqzoH^WqeCWjj;y>iRNNqW@xd)hS7Pp_-ILLp2
zfN*$@qCO|Dp1+E#05=E^w(G$L;lVZ+Y*%sjgAKqPX3>P<^O_Z+84m`Be3M{0L$Nj#qfEs
ze2+()?Kat)6>VHSxCfkPgQZ~qen
zaDM{Jp8{a{5G;S(0+#o{@`oX?{5OyK{WKE#*ar^(06xDT1j}E6<#%4N{4cQlb^t7I
z@u+Vz3;P=nIJ^ixAN7OfX|R0Q2bM>{@6AP7gIGUg9_y84F+aD1+sBxbcK4|b=_9~$nnTed)v
z2eC8bHc)Vr*6_DzA5V#m0F|mspMp!bM
zfYY8V_@};$9{VRs0ml5(TtF|1$zp;yj_THVQA`#aobaysiy;4(xfNaHJ%CBJ?F+pF
zFv)Ca`Ts`DQN#TI3&Z~#$TGJAl!00uo3jfP-vecGc(Mx=A1G~b^k*4pogLIw_GJ?&
zWYcB`-J-o&23lt~S{!nAftu^>RII(b1FG{vJBJ$3}A;d%Ru2y
zSfc+Et0?Nk`kH`>AjfMlVZr1+H<~upU`<7ezuL>Z38)aPCW?|maQ{U-8u*c26aZ;X
zaHnyWGxbprAi*DNgHn=ngaUB*HAR4xL|YU@#`9Q$zbDvCZV)C^RFYp4R`~=G;l312
zc0ED7^Pk#hEm8iIA`&^1t7NumZ34)Qhy@I#L##!MSh(gUo>TBs5UW9WEKVB4f`4Yj
zvH&r};@LkT;k1Z_xSn82#1fyBh$TL$5er@!5DUH;5exq55Np*UwoY9>@KX@0L3k`q
z8pMKsX2h}pF~rhM*JXs-S9%$QNsCK$^QR^ng7>iZM1^i
z!uAioy~)v;O`tIRTj8=_ha<~CVYjZq(UD!CZ~+-8>|UE?pfIZ%9qri#YJ>~VZH_hB
z1PXhf7TBwDv}G5l1+D-!Ia;#|6tS9eR6fdZjsbga%YP|&T9^?y7BhhY>(MbddR
zJVKJyg=+MptHkl+Uxz!g;c9F$h+>@@3XoL+wnpoaUBK|b{=J}R0iSGX42Syt0X)eL
zhv94unc10KGPtRSW21Jc*38!6rwrAEiK2|6u{f&CCcw-*R09AUAU0HcNaj`GGYrHK
zH$D)jAf&)Q-LxcW%W6{R8T^#8YH$#XlcucTpSi3oK&-65WJpLi?TiFb(@gioC*^cc
zd{R&M;HAMU)-#fjm5i8$_~|eU)GMt$N}_5=QSehRtHF3IP8!UDe`d_G04mIOXedMQ
zPm5aOmy(hqJ}FU4d{UzpyfmoQlBnQY$bFeZoD~ZJ!0q4gXA^ATr2Jv_VDi)LF5;#Y
z6;GS9cu^6^8W)?5guw|MOexN^gfGUYG^Uk4Cj3}6SAuaRkwciBoUHD03IZ$2=7;xWq0N9W%D9DM|8egahW4#Bwtg-Uw$lBp8(^Tr4O46@I@Yv{osG*{n#AUnV$+??j!uWzRhqP8(N(&%
z%ct4YNEt}1z&hr-K)-5NX-qIWCM!$*fF=P?l~U2lD#fE?t=b2ar&15h4oc~P*%@jN
zqQ8{JiAh0&e@q9u#tZ90V4f_U*wMS>II7ck>Nsi%<_cQuN~}+>%h%;=?`T}r+9-lP
zHrdnX>jnYkAe`(D1;R3Tmu}kO^M~N<&Cn2>376e9a0F2_OV%n8-{Sz9yp*HdVgqP^
z^AEt0_2v~#ZJo_4n?Z$y8m4-tCD+eNM%@2%xHmXdE!@TL1Is1wMA}QpMXZH$prb4;
zSvV(gw-_aNmC5ZE!&1bL_lj3FO|Vr=1J+7LQ&N8cw{u{_0Ko%l7;TaE>!(bSY$=Ll
zJLe)POpzK=6sh5yi)4}k+J0eDi4LBR*0YRl$1bp;JiK3hjijg8ps0)7nA6>;6ggG2~U6_Mz26^A8@U84O
zG9BV2gn@3MkSm+d7g5$u89n1Z{?a4k_kY6$o3?(R03Ax<+(^}usaldmpkl0WrKCyg
zPUXyi&2CdeSq?(gvx<0*CQxXVthvU7hyW0v0ZeluK)4MQE`>E2Z!#1D015<<+t84o
z5(ZrLYHFy=WnnpT!oRN0keq+WBy2Jn(Ppkn1=b2#OBI%6tqKva1W_DUWHuw9{j~Wd
z<$x?3ZFr}>SwSlxSdEa0(W(x;nlI#*6z7vB
z9H6k;9rnuZPG@kShAz3-u0wK6adhXY=$_ZccODu&^d`}yXp%-xygc^OBgWX02u_5-
zaWH6H=7^AsbJ0q20a^IUGc*@x-aRrJIl*$V!Q*QRYcoNwm{Ky46frRqX0xd-F%!^V
zKzat`GEDc^!I1*UgtO?OZDx#!3zQ4VM)M#MW$i;)+M+iA6EjwwUehBxeZiVurwfid
z57)H$9iaYU8Mv*Gdp$m)sVt^0+b*{GMI2s)X&u^+6j_Y&xmyp(l?X$Qv84)@
zy>&HK8F+$gpIF6>wdI6L2o;Q{-~=@cpTCsmfhq7GiM{v!H5j
z30W|Ip2s<;O_hT~&!x^mo1f+(0RbR*Ov5Lpo*n^4tnOzT`Ul+Ojp$?a5&8w30z89$
zjDAENv4{TX7|=0r31Q&KNEzhzxsmzs`|QX}_%`!>VxQ$z6cWPhQs
z4KA`1IrLT3Ec_CV+uaWoz|-I$f;T+(_Rr$V^7*ntAUCS5Sg(*2{l=j)?;M~6N3L>!
z0;@$^Zp7D%!l4X1{<3fN$lH3IVz09rU-AkUmsY!+0e7`O9c7}1JAUwR^uS}GK2_r7
zByshjkQ^m(eAFVIIQ~*4?hl9DpwS~;s%n5N)!w93sRu1GQc}e$$9SsvOO=7gnsUI6Q_iPV
zTt-qJd-T}o$Xhg!k}!rHPZ)nCCY-ir)!=BF(6a6!?dzidtVdAVX?ziG(1nX=XW?Y+9;MbR^S57SVr2b49vXr!#l_UwOazDD~mFUC!rzs;6?25ttj`1;x
zeya-D0}7i#+{~A*bZV$H>8+bpNwX?FxC@%n`0;O#y>mQINgDWgy`H{!()3%EbTI5o
zUu2-tV<2g|+dL#)+LWqkQ+oAKbkExqs|F=qEawzY6@RJH?D6{t2AzR{3<;}X(u8sU
z&*$nmG=k=W&JGjk{#nHRfZGF38J?DX7*9NH1=UpDAZ>qV-aS70=(pTx@yZx6K&A?O
zwsLX0dRV;=7oUNnmmd^TaCGJC781b$MUep-rdfD8RBAFe`s~s16JK#B0>cw^T4<4J
zyTc@NX51W?vXT9XQ!wPymg|joIdZ`)xmHWn?c$EAs=`;4ReJ`VeHl6iQ(Qy32d%6K
zzdJ;VR*mywrFj|s(t$JY9A{#V)6l_L)=9
zk3AO|d-PdQ7lZ_wCWta9>48<17FOt+u7qkptb_rAZgzr{MJFKh0(KNSiAtj_^9wSRme<}Lv<7@)Ujn%Bn39K(wy^?QL
z(ylPDVbToeV=9m|UEKd?aLYJ!0^N-Yg_D9;xSszz{tJ9H_aEHD;4$ITvTrNNI-yKh
zccZZBSkS8;3ka1w!B{}M8v)100t$|f1-zr!)}V5zeOvmOqir7{t~Av_=OJ9bdycvdi6A|L
z6VxxJme|C`>NgH>-$}Q+!O(efq6UL$qm%$igK?`H3@bDiX-V5)X#c+*_kSmvBm9LB
z6v{vw*9c$FjdG83w@=vpV*yr=;1!T|5|0vkgSHiqx~&k(C1YC|!RsCEB+j6bN!+8V
z2?8u*TWK5N;(25BK-mqn9`CUsf>PAWe{MQD`Vfi@w~Chpj?NS1|kMB1z#k=W{Tf-$Lm
zBtIQU(yunFtA&A_uv(_YK`Nytxun&ySzRqkE;Efwts{AHfJ(IxfV5gRtE+_p%v>!7
z3{P7v6dvhan^o1qz-6qKwvpU;{*(ffNsLyDM_nys-kG3M+D1V6oH8qF0g_7bs4Im4
zoS;ftMlb`DO|!~GL2^i|#G|efn!`*Lg8Tn;O#i=%?g0J2FAMAVKk(1RbM8KhV8AF7e7f}0V+j*;2%>^89WK)53e
z4u2p57c;7fM!H0o&SOV{|&hPXCBc1gTi$%|L^22K>r^)r+t9t
zkut~~8=1;ktrPwXWw8Xw*h#oSm^*`cGHLPGGIB#4mO|2f<-YNkMi?wo)iGE@0U7T$
zrUkcpWN{oEBk3sXh*n3C)Nu^l1l78lbD+>FbjnA!jHYOk2BcBMakTwFM`0tWPs8;DS$3!7U@##R0O`
zM={CrsTmRoCNs^kt49{Z!Limy!BL{erx^<{xJ)F^>XBY`nWHVnryc_^u#Alc
z%m2(ryYVXiW+MOdOY|NZ18u(l4iZ2=fLp=-3jGCo7qo$Y6MY@-2zU`4L5I;H&-{llJ`p@4t0>U$xDB5`%7l!Fa|wx1f+MUcSy+f8oO%0ea2FJvX3{IT#9SOT_Syq}ynCR+
zAeDY>+zMNnfpi$8f*G|KSS?f!hES`HmjaW6!M;*^DVtwL9*XXNwiK%&a)X{I58c|
zlsLRv68@7E4+N1xIM^C-RFdM&$Hi-4RjA$`$xu8t6|2j(hHcRJebDvlyzpc7z|Xcm
z_}S`$pWD0Pr=bgeYkjzwJK!g04gBoHJM?9%;HP;7{FpGK{`9Tz^R1iVr`8TX
zH`(B)3y$`42&?(bHNwxMweaJsfuGx|;pc@Vc>YIRBgZugYtduyajwsOg?Ho?mz4?o
zHpb46;L>(O4d62*ikD_Xgrkwc
zU^hG1k@DW1K^b(B;Pl9uPvwXPzSI})_klw&T3>Q11n1ES5)2vPl7b{0Zo&7jVD3(L
z3U?A-eO$$AjV0FY8H#1l1czJ!3<(Yk2Dr63ewf6hjx&VCXO(DJaF)c|9Q6A@^=c4g
zY?J)hco;{$axTS)Qt%r0i#B=QnxDj+Dea=pEiZ~xg1jdi+(7_vmvjzq+Ey;dwgzr
zdo0%)^l>jT{H<$iUb_yCWVfwox>GET1uiWtSkoqw^ICB?u|gFkW7=w861N|(@+htcc1Se)hr%1Fc(eOm6H@#An
z-jzxweK^R1)oXO)vtA&M3_2U)S2|aTDxDExZ@@p8{&rQkXmeY?9FSF@$pv;;X_i>N
zB@nu&yR2Mv`rN4l0Ov*P9|UQVK__UNs9;&f5|R4-pKCfciBOSB#RtSePY`IzK2brB
zSTX5)NiVea?@4Dwy=Vi?msY!3!uNj_phgZ({rm`h7ad2Bqx;~dug{@&aMT|i13CsW
zV_+s)#ACvISPpjk{DvY_mXAL%qoq42Z=Z$AiFdHyzpc9;B>x4)g|3}I@j(6@w1kAA
z`^IFYls6C6s@>=UW!lw9Vy=Nfrx(^zK|H6x9ekC<8Ms~DG-QsF3U=zl9I#vkB0X%(
z!WCftpMXBXWqcX)|1uX=_ti0=W8kvDz}K#UVtjQ5UjGZ+_c-o*!ZVj{xpuF+3p1UB
zy?t7y6DHPTToe4ky_AOQggsSUC&K2Av%@CGi6nd$qEa>$^@z!-9eI6kO$byfN{qMEYa2^39!(rLztItQ@e%q*pI3X%&EDCa69?7K?&m~Qe
z0l7A@Ixv<_n+wxHSO48X2!UwTZ?NObRXZE*s~
zTq><%J$I0Bbv!u>xAy7;kU66dj*LFN+oA!DqBL@)Fi>t7%Y3U6SC)u?tyd7
zUncEqlJIB@3a@h(fma*v-_bpJ
zES|WZlZX^*YZ1xo5(Vmffl7{(s!=V{gJG8oHks4c4~^C`lVmaujvhN!mmJe~tkh?KJ{!1F>(LT71naV`CBLaQFsZg`lDmu{4vnE
zFsY-z@Y?trM@e(n@SY}WscQPD^SZ>2P6U$3Xruu;@u;rq=<63iUdw<)P)7Cq(YN=E
zef1<&9no-3V>^pUCZId6WpI^gavBvjrLwCw4crMQOB$7qqV4kua^o4!qoVNj8juqr
zmdNE(h`9gr{B92Z_2<*Uzk5S3c!@pabPa&wgp@!A{a7ia#>-5_pJF0m>hdx_<#sAfJSIvO^K;UxtC$EB^CeZG
zQ63!2E)gBV{zJ}COiQqWVE+)7-cqw}Xf7}M`d`KW|GLiq|8xcbJyjh87aap9@*v6M
zpotj-ig_=GY{H+z${))i>(2$kK%_Ef2Isn^n6Nb?xo|izdho6BeP4_2|7tZbK4CQ$
zJ-svf&fXkJUsynSl)$llRs-aLEco7HE&
z{nGfizcu>Y!T;CZwSG5oT=CTk+Zd2l3a*b2hvML-sR3E5hYdJ!2@i)t0tXO}=5b1m
zE!#4VWF!L>Ej^KK9tJx$q=7&~3Tc3pm!X9~423_WpPE_^f9&VcePsW$`5=J
z0$MmL@9fOIckVp)&b>4DB6aNZPl!0SQMEb(`!;q<(bj3)9L?}WWlr4vJ7W(|aR}+`
zpd)eb2t18zUvvao+q&q@{X40TE@iv
zf)J^s90R?9t}U>gz|C>9%kA;j)S411m+wErK~(VUu?EW=VV7$W=g%e(mF5rE6(`T%
zN_BscxOhMQXfQrBki2?Z!>GN1AlqSvUk6pf6gw&mZd62+jQ{x{mVEd`O==DM{Xt5*
zdtFWI+#iMyWl9|RTusETHKdF^>{U~u{*I2&K^p&7VTm9{F!q<^>iFHOicn+dMo1~&
zQ)9$w=66MQzkTY<#HWAJ_S;UG-8&l*ED&xWp%lM8h#yaF
zP4av%l;(+#?*bUQJ<7zdbSFOh6mHT}PmZOYoWmiVII9ak$s+rvA~)jw@#E*nKc4Ih
z?5p_gJEM=zCkBVcj-HmWGKR#5zfKKbK=Be)i{ba3TI}6L(q<+RxXs}mEZ)bEP>`)u9jv*
zO@R$PvkK-2Z+bWzdiQ0rfphHU+2oBYss5h$pYLiJ(9{+tO__PE`N%_s61{`yBPtM3
zDe+Y5MI6WA@aV(KsmC8deXT9PJAq5-WNPkfn1-o)IaVsKsI$0JC+{TA90RVz@PG!k
zoV(F+D1N$swc{Nn1C{ac2fR=qDM(l+jrSjk4_#LZsCoL9d3hQygwn~ruM@XUAQ9CB
zYVzmVH<0+#aH2nkUafr#kcpEw(5`=c>GjH=z5JV>FZo54qki{N)Rm2Yu|%-07O&wa
zf4$Hgh?UR6&~%mZuiEU4ubNhxfE19t`8fSO>uPL`?8E_V5-3ckbS(gGP(vU94k^K`
zZ0N)UKzZO22{-AHL^8h^v^iwj3Ubkw>OG&PttAwKv@~JL;v+1a=%srAqEM2Ptk-5@
zQui$2EUV8TORnYcqtx+h9M;%hKTKSFlqQZ`^!U1>h-1O`WtcM03>0`K7p0He{VR~o
zU_S#sUI5b#4qXNt58&v`!gJ_gghE=#vINs@Yd34N6Si)z?~SPd
zg%1|^CWMs*p=&2$2FA%0Aq
zRO4Gc6`*Dfg#*Yn2zumueR4oCcn`(q;O>oCa6du5{|EQtX8$d2r*`1>kB#*G7lm&G
z;Tv%={(KIv?)vwN%BrfwUJuiEWA3H1$@01K%qQVarlLLbE!Vb_MSd#Ec81eP!5rv>
zw}-Hz@pj3le0g@WW4?RBm@xcmAz2w6QuWDlLhjvs+5^4v@nMcN^FVLUySt0Z7Az2t
z%~tt`4Oqk){0R55Ifi7;D*Q1OPEj$fk{*@?cEU-Ckw@>@mUe|_+6=1top0|VdqE(0
z06}qKvIw{O)uYd3%*cS+6vpvrI7Fd96$S^Zar~zx5ccox40QyWH1>(KdBQ`uu>Fr6
z5euq_G&?L=T)^CI@}2AdY5dQ|haSE?cEbPH4RMz!!Uy=TE!O<^-xWW4B>B%%8@8-%
z!;w5hT6Rz9Q=R|*=fD5Y!uLP7NC}|=!S1{^;eSE_LVpRLS|J0tCyNbORUuZyC|QL-eta5ZcV1UvV4%}~_U
zwGPSakXXn&$l=}^t!!FLK^|SM_htdxT-$=uxr7Y_0ozQ5EzleY!dC1LzZD9$2AUBL
zSq47|=-B!2#9l5eD982>xh?|LMR4;;THc|}>%o(hnjpeTAXIFIYv+$acBN2S{t^QW
zvVn>L)|~TQw|aX62h9_=!;J=kZ`eB14DLH~0e2CCb1pQ2yCRY%RzEy4?n%OKp|ey|Jb9
zP>0Hk6*4O*QE5Te7p-Qn4f7?1#uxp|2fNP{P_Z2vEqUf3Orhc39ZZnMrX$mRgMdc
z7kyN!ken{5VhQ`V3iDD{V=S+8;lCQ#mQRDrD_ocZv39JD&748BY)aE&7X33iP7KoV
zNx`xb8W1y5q(hbx0ih{5B{q*uyLS|dCpF%r%$p7#jJ2a#iBGBF#FC0t9+%1seV8E(
zH@%CsSc#R8AC{2|dgS^bqAGHI5Ydk2oIyk-r(0>Q+%)cmdK{5L&FE1>f9jc`gbM{7
zRbWVs+%<9|!x#*tIiFQ|J?GU3s*~nC$^UTsE8u_r%5&gZ=0Nwh#-g&yO0hSfRYWL`
z=1405^@Z@jP$5CD(n<+DeCLXZiEARLCU8Cz!5&9N!=Y}yWR6gkRE=tZZ8r4(t_d#Y
zpuE^kN-8CnS8)KRk>lidaMxxNtML6F5v&825o@{lH?jU%?gDw*(j0i73G6m`k%4q|
zC8lX;Q-Pg{zot^Vf%ppq^Yx3R_IVIf%Wc{Pl)M;x$_11G{vcaZDb>YVP_6ES)>N#%
zrVA?rd||fMf(WjzwUmXfjL&G{!e1$CEr!!{!DWDRpB?;Mq~J7YQX`xhizSBAbj4(V
zlI(w0>wj?P7c(G^gmUTaKt;
z^_+I6*{rNGT;$Q07F&WyR4zB5QZLY}R4M{JsH@VEpq9~-py_Tp5qkXu`&K#}tG*p>Wx>{qaE
z?O3#MX_ilM?BuA%-bufIat_wR`^R;c4UyA{YzAJk@rJuo_fE)Bx~kJ3ziqQ^Satxn6y^@c36g6@kj5uxiJxi
z$D4u)6xkLV(xyd}%G5eg9@)USh1(aAh54`7*b}J~Wt0tw$|FJ(H1BzT}aNyzy18AgIq?*eK_u<$wB
z2=Li+Fa^!3#`$ZlL;3Xx5TA}b#G^o&iI7y@iSkaK%|L_1
cpYj?s7vQT)87AKU(B*%&LYS)j&s$9TKe6k$!vFvP
delta 5606
zcmeHLdvH|M8NcV8O|p4F5<(y(Y;ve4JKy=v_qhF^7WRKyxTkU+78r(k3#b6d4|Hs=RiIpZ>z*94gPBk6
z0w(k5-mXUU-fIVckLwaX=s$KRH1#fM>J~vWcsn$0w~-@E4*XySl24KvE4jifV#wRT
z%4*)HUA?)&6f*#UE;OTmB6d=+Ze+L`_5QTFqeQ#@15`0j-~^YAbJ#e6pAc+jWXeUWfH8VQBesC~W8(XL#=%SJ?;Hz$o)5mh@Q530#CpOkAqxQuhL
zRY<<}&qj^ig^ieZot&Rnl0&s{OR}i$?(&D>S1-^bKz%@6KPeEZiN02
zkOin1Xb%tp+7EOJXz~Pj`29;D4k!h*0;oT^#!_GY4EzcM?E|6;ei>+ZwBOP{?@-CO
z;beosIBHmPwG|X&8202=v@_&YvWXb*34AXuL@DG$#mt*bd$QE9)+oCQn1wYaQ&REN
zB2O~0va*7=@dEs@JTHk3$-&9a*&u>T5}IVktPog5kj2>`e3K+PWnm_yI!hMbBk}Ir
z`2waC#H}s1h|wOcl+iRWeOOh`#)XPo48Ne=$xeqtCkjDJ}MwwwnyjqD)1z?v~x@$fxID1%a;^VeTxgDj
zw}ygY6+OT1ImNHHPggy(nz{@`K4!?rWDq3pCCSH97MYs%#_u9GQ%~;9|1NTjqVcaA
zM@z=XX;WG<++bLcj||kv?1-
z7C;u!>&fua;9`A%bIa~)8;(Hdif*{(?CWcgp`oIHIh}pgjp!7*4;3+|K@SIwGCOmn
z%thxM5(oR^6Wbb!vm9cX7wji`r2-7K!@R==$zXIzgn2kg5QO
zb}u|}`0THr*VpZcg!LtPrw2aTiz1#^742F5zylETJ1HU-SK{3kxv{q3w@h3AfwV
zMZ)bc?r-zyg-s9mKs>BRa-PQ%z
z80=(%)oW*4l
zW9;l5(Vomyh4lvm0hQWA2G^&r6YmJdrZfwJvDsKi*aE@!?kJoPJbY5GnQc&I+G7ud
z?B0#*vW`s`J3EC0Pt*i~cgn=+uhHW1&x=Rapqy0B@6Z=yGS(nSF>_P7esMI(w-i7@3AiB^}MH^U=x7q}&-bKr)GGU_bK=tEj+ObJ!nwiC-5zKknq{;mCMCoZFD_kHw=
z(hCcA8lChB=a0X1e$U|8-u;=o4)>xh?F7;{p5A&79aTG(V2G|Ecm$W|;(6C<-X&(d
zfVxdvbs39!oCM)q5RNq9q7r(v1Z`%B4R3*er@*@%!RUy_d+{!9)ka)tPCU|}tEh@f
z4~MmtRvG7#Po4eM!E@T-v9~p%@fK961%|LiyLt&%Cr?~9YA1%UF?XtuXE{HB=XAb4ec)29Ilxc1L=GcDS(jtG>7$qEuW3=C>G9%T!6G
zbjLf^C~?K>1NZ4w9#k8aZO}GFP&qY_dAglVgCuL;DC?u_bchk?@zd_4)tozU94f)I
zXp>{DY7aFI5V127rcD3j19h9xIl9l*4-2A}mFIXM2aprU1>^=2fIL7sO;(=gbcGv1
z;Z)~Muit`m3^~kUhB*wT^xT5MO_phaa-cU8C^vmyfl_-|#Pa{6-2Yyb6FKV64DfzI
zcW1j&b2s463u&OLq%RQiplXB9OXLgkA2LopBWKB9$j4B_ogt||`>=%_iDN?pLGUJF
zIc`PmfVx61L7k_6>D0_;prCBz4OEi?zvCg=jv?Ip`fhA66d9Oh45`H}$i*zvN>AfT
zJOx~gv@MU~BiaWdUaBqKiHm>iO59Vb`_@_-2q7}eq5foSXyDww6KQ{ve@%aq&JMEQ
z>VP+ad?CxHMAZP~KpibK(@PG$xsbY&vh+L%T3KV@OSC@>VK(CzIj7_lB&V3Tw?tb%
zh;{#3sqGrX$xK0?uBHTmYIm50OyL=PwXvG&--tFb07jH+voTqz5Q!T$o8Q7N+k
diff --git a/src/main/java/top/lidee/common/constant/InvoiceConstants.java b/src/main/java/top/lidee/common/constant/InvoiceConstants.java
new file mode 100644
index 0000000..2800d88
--- /dev/null
+++ b/src/main/java/top/lidee/common/constant/InvoiceConstants.java
@@ -0,0 +1,13 @@
+package top.lidee.common.constant;
+
+public class InvoiceConstants {
+
+ /** 未处理 */
+ public static final String UNTREATED = "0";
+
+ /** 已处理 但未成功 Processed but not successful*/
+ public static final String PROCESSED_NOT_SUCCESSFUL = "1";
+
+ /** 已成功 */
+ public static final String SUCCESSFUL = "2";
+}
diff --git a/src/main/java/top/lidee/project/monitor/job/task/SuYuanScheduledTask.java b/src/main/java/top/lidee/project/monitor/job/task/SuYuanScheduledTask.java
new file mode 100644
index 0000000..3214d66
--- /dev/null
+++ b/src/main/java/top/lidee/project/monitor/job/task/SuYuanScheduledTask.java
@@ -0,0 +1,203 @@
+package top.lidee.project.monitor.job.task;
+
+/*
+ * 发票引入定时任务
+ * */
+
+import org.apache.shiro.util.CollectionUtils;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.scheduling.annotation.EnableScheduling;
+import org.springframework.scheduling.annotation.Scheduled;
+import org.springframework.stereotype.Component;
+import top.lidee.common.constant.InvoiceConstants;
+import top.lidee.project.monitor.job.util.HttpXml;
+import top.lidee.project.monitor.job.util.InvoiceXmlSy;
+import top.lidee.project.system.record.domain.GrInvoiceRecord;
+import top.lidee.project.system.record.mapper.GrInvoiceRecordMapper;
+
+import javax.annotation.Resource;
+import java.io.BufferedWriter;
+import java.io.FileWriter;
+import java.io.IOException;
+import java.sql.*;
+import java.text.SimpleDateFormat;
+import java.util.*;
+import java.util.Date;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+/**
+ * 发票定时任务(更新发票状态)
+ *
+ */
+
+@Component("suYuanScheduledTask")
+public class SuYuanScheduledTask {
+ private static final Logger log = LoggerFactory.getLogger(SuYuanScheduledTask.class);
+ // 数据库连接信息
+
+ @Value("${invoice.url}")
+ private String URL;
+
+ @Value("${invoice.eiInvWebService}")
+ private String eiInvWebServiceUrl;
+ /**
+ * 数据库用户名
+ */
+ @Value("${invoice.username}")
+ private String USERNAME;
+ /**
+ * 数据库密码
+ */
+ @Value("${invoice.password}")
+ private String PASSWORD;
+ @Value("${invoice.taxId}")
+ private String taxId;
+ @Value("${invoice.authCode}")
+ private String authCode;
+ @Value("${invoice.updateCode}")
+ private String interfaceCode;
+ private static final String fPath = "C:\\log\\fplog.log";
+
+ @Resource
+ private GrInvoiceRecordMapper grInvoiceRecordMapper;
+
+ public void updateInvoice() {
+ GrInvoiceRecord grInvoiceRecord = new GrInvoiceRecord();
+ grInvoiceRecord.setStatus(InvoiceConstants.UNTREATED);
+ List grInvoiceRecords = grInvoiceRecordMapper.selectGrInvoiceRecordList(grInvoiceRecord);
+ if (CollectionUtils.isEmpty(grInvoiceRecords)) {
+ System.out.println("没有待请求数据");
+ return;
+ }
+ try {
+
+ for (GrInvoiceRecord invoiceRecord : grInvoiceRecords) {
+ String key = invoiceRecord.getDjh();
+ String txtCon = "";
+ List billNos = new ArrayList<>();
+ billNos.add(key);
+
+ System.out.println("溯源 Id:" + billNos);
+ txtCon += "溯源 Id:" + billNos + "\n";
+ //封装 请求报文
+ String xmldata = InvoiceXmlSy.generateDwzsXml(billNos);
+
+ // 组装接口需要的请求报文
+ String payload = HttpXml.bulidSoapXML(interfaceCode, taxId, authCode, xmldata, "eiInterface");
+ System.out.println(payload);
+ boolean hasError = false;
+ try {
+ // 调用接口
+ Map res = HttpXml.webServiceExecute(eiInvWebServiceUrl, payload);
+ System.out.println("接口请求状态:" + res.get("httpStatus"));
+ System.out.println("接口返回的原始报文:" + res.get("data"));
+ txtCon += "接口请求状态:" + res.get("httpStatus") + "\n";
+ txtCon += "接口返回的原始报文:" + res.get("data") + "\n";
+ if (200 == (int) res.get("httpStatus")) {
+ try {
+ // 解析接口返回的报文
+ HashMap serviceData = HttpXml.parseResponseXML((String) res.get("data"));
+ System.out.println("业务处理返回代码:" + serviceData.get("returnCode"));
+ System.out.println("业务处理返回提示:" + serviceData.get("returnMessage"));
+ System.out.println("业务处理返回数据:" + serviceData.get("data"));
+
+ txtCon += "业务处理返回代码:" + serviceData.get("returnCode") + "\n";
+ txtCon += "业务处理返回提示:" + serviceData.get("returnMessage") + "\n";
+ txtCon += "业务处理返回数据:" + serviceData.get("data") + "\n";
+// appendToFile(fPath, txtCon);
+ String invNumber = "1";
+ String xml = serviceData.get("data");
+ Pattern pattern = Pattern.compile("(.*?)");
+ Matcher matcher = pattern.matcher(xml);
+ if (matcher.find()) {
+ invNumber = matcher.group(1);
+ }
+
+ // 如果没有被开发票(invNumber 为 1)
+ if (invNumber.equals("1")) {
+ log.error("单据号 " + key + " 还未开票");
+ continue;
+ }
+
+ if (serviceData.get("returnCode").equals("0000")) {
+ //更新数据库
+ Connection conn = null;
+ Statement stmt = null;
+ ResultSet rs = null;
+ try {
+ System.out.println("更新视图开始");
+ // 1. 加载 Oracle JDBC 驱动
+ Class.forName("oracle.jdbc.driver.OracleDriver");
+ // 2. 建立数据库连接
+ conn = DriverManager.getConnection(URL, USERNAME, PASSWORD);
+ // 3. 创建 Statement 对象
+ stmt = conn.createStatement();
+ // 4. 执行查询语句
+ String sql = "update gr_dp_saset_sdhm_v a set a.zxcolumn1 = '" + invNumber + "' where a.sasettleid =" + key;
+ PreparedStatement pstmt = conn.prepareStatement(sql);
+ int rowsA = pstmt.executeUpdate();
+ System.out.println("完成更新视图:" + rowsA);
+ invoiceRecord.setStatus(InvoiceConstants.SUCCESSFUL);
+ SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
+ invoiceRecord.setKpsj(sdf.format(new Date()));
+ invoiceRecord.setInvNumber(invNumber);
+ grInvoiceRecordMapper.updateGrInvoiceRecord(invoiceRecord);
+ } catch (Exception e) {
+ e.printStackTrace();
+ // 发生错误,标记为已尝试但不需要重试
+ hasError = true;
+ // 6. 关闭资源
+ try {
+ if (rs != null) rs.close();
+ if (stmt != null) stmt.close();
+ if (conn != null) conn.close();
+ } catch (SQLException e11) {
+ e11.printStackTrace();
+ }
+ }
+ } else {
+ // 业务处理失败,标记为已尝试但不需要重试
+ hasError = true;
+ log.error("业务处理失败:" + serviceData.get("returnMessage"));
+ }
+ } catch (Exception e) {
+ log.error("解析报文出错的,保持业务为处理中状态,需要检查原因");
+ e.printStackTrace();
+ hasError = true;
+ }
+ } else {
+ // HTTP 请求状态不是 200,标记为已尝试但不需要重试
+ hasError = true;
+ log.error("HTTP 请求失败,状态码:" + res.get("httpStatus"));
+ }
+ } catch (Exception e) {
+ e.printStackTrace();
+ hasError = true;
+ }
+
+ // 如果发生错误,更新状态为 1(已尝试但不需要重试)
+ if (hasError) {
+ invoiceRecord.setStatus(InvoiceConstants.PROCESSED_NOT_SUCCESSFUL);
+ grInvoiceRecordMapper.updateGrInvoiceRecord(invoiceRecord);
+ log.error("单据号 " + key + " 处理失败,标记为已尝试状态");
+ }
+
+ }
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ }
+
+ // 追加写入模式
+ public static void appendToFile(String filePath, String content) throws IOException {
+ try (BufferedWriter writer = new BufferedWriter(new FileWriter(filePath, true))) {
+ writer.newLine(); // 换行后再追加
+ writer.write(content);
+ } catch (IOException e) {
+ throw new RuntimeException(e);
+ }
+ }
+}
diff --git a/src/main/java/top/lidee/project/monitor/job/task/YinEuScheduledTask.java b/src/main/java/top/lidee/project/monitor/job/task/YinEuScheduledTask.java
new file mode 100644
index 0000000..0097707
--- /dev/null
+++ b/src/main/java/top/lidee/project/monitor/job/task/YinEuScheduledTask.java
@@ -0,0 +1,228 @@
+package top.lidee.project.monitor.job.task;
+
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.scheduling.annotation.EnableScheduling;
+import org.springframework.stereotype.Component;
+import top.lidee.common.constant.InvoiceConstants;
+import top.lidee.project.monitor.job.util.HttpXml;
+import top.lidee.project.monitor.job.util.InvoiceXmlGenerator;
+import top.lidee.project.system.record.domain.GrInvoiceRecord;
+import top.lidee.project.system.record.mapper.GrInvoiceRecordMapper;
+
+import javax.annotation.Resource;
+import javax.xml.bind.JAXBException;
+import java.sql.*;
+import java.util.*;
+import java.util.Date;
+
+
+/**
+ * 发票定时任务
+ *
+ */
+@Component("yinEuScheduledTask")
+public class YinEuScheduledTask {
+
+ @Value("${invoice.url}")
+ private String URL;
+ /**
+ * 数据库用户名
+ */
+ @Value("${invoice.username}")
+ private String USERNAME;
+ /**
+ * 数据库密码
+ */
+ @Value("${invoice.password}")
+ private String PASSWORD;
+ @Value("${invoice.taxId}")
+ private String taxId;
+ @Value("${invoice.authCode}")
+ private String authCode;
+ @Value("${invoice.interfaceCode}")
+ private String interfaceCode;
+ @Value("${invoice.iBillInterfaceWebService}")
+ private String iBillInterfaceWebServiceUrl;
+
+
+ @Resource
+ private GrInvoiceRecordMapper grInvoiceRecordMapper;
+
+ // 每隔5秒执行一次
+ public void insertInvoice() {
+
+ System.out.println("单据引入开始执行");
+ //查询是否有待处理数据
+ Connection conn = null;
+ Statement stmt = null;
+ ResultSet rs = null;
+
+ try {
+ // 1. 加载Oracle JDBC驱动
+ Class.forName("oracle.jdbc.driver.OracleDriver");
+ // 2. 建立数据库连接
+ conn = DriverManager.getConnection(URL, USERNAME, PASSWORD);
+ // 3. 创建Statement对象
+ stmt = conn.createStatement();
+ // 4. 执行查询语句
+ String sql = "SELECT g.*,COUNT(*) OVER (PARTITION BY g.SASETTLEID) AS MXS FROM GR_DP_SASET_V g";
+ sql = "SELECT DJH,DJRQ,FPZL,KPLX,GMF_MC,HSBZ,XMMC,GGXH,DW,XMSL,XMDJ,XMJE,SL,ZKJE,CREATE_PERSON_NAME,BZ,SASETTLEID,SASETTLEDTLID,MXS FROM (SELECT t.*,COUNT(*) OVER (PARTITION BY DJH) AS MXS,\n" +
+ "ROW_NUMBER() OVER (PARTITION BY DJH ORDER BY SASETTLEID) AS rn FROM GR_DP_SASET_V t) WHERE rn = 1";
+ rs = stmt.executeQuery(sql);
+ if (!rs.isBeforeFirst()) {
+ System.out.println("警告:查询结果为空,没有待处理的单据数据!");
+ } else {
+ System.out.println("查询成功,开始处理单据数据...");
+ }
+ // 5. 处理查询结果
+ while (rs.next()) {
+ String SASETTLEID = rs.getString("SASETTLEID");
+ // 1. 构造根对象
+ InvoiceXmlGenerator.RequestCommonDjlr request = new InvoiceXmlGenerator.RequestCommonDjlr();
+
+ // 2. 构造发票集合
+ InvoiceXmlGenerator.CommonDjlrFpts fpts = new InvoiceXmlGenerator.CommonDjlrFpts();
+ List fptList = new ArrayList<>();
+
+ // 3. 构造一张发票头
+ InvoiceXmlGenerator.CommonDjlrFpt fpt = new InvoiceXmlGenerator.CommonDjlrFpt();
+ String djh = rs.getString("DJH");
+ String djrq = rs.getString("DJRQ");
+ String fpzl = rs.getString("FPZL");
+ String gmfMc = rs.getString("GMF_MC");
+ GrInvoiceRecord grInvoiceRecord = new GrInvoiceRecord();
+ grInvoiceRecord.setDjh(djh);
+ grInvoiceRecord.setDjrq(djrq);
+ grInvoiceRecord.setFpzl(fpzl);
+ grInvoiceRecord.setGmfMc(gmfMc);
+ grInvoiceRecord.setCreateTime(new Date());
+ fpt.setDjh(djh);
+ fpt.setDjrq(djrq);
+ fpt.setFpzl(fpzl);
+ fpt.setKplx(rs.getString("KPLX"));
+ fpt.setGmfMc(gmfMc);
+ fpt.setHsbz(rs.getString("HSBZ"));
+ fpt.setKpr("方国旭");
+ fpt.setSkr("方国旭");
+ fpt.setFhr("方国旭");
+ fpt.setBz(rs.getString("BZ"));
+ fpt.setZzbm("ORG001");
+// fpt.setCreatePersonName(rs.getString("CREATE_PERSON_NAME"));
+ fpt.setCreatePersonName("陈志");
+
+ // 4. 构造明细集合
+ InvoiceXmlGenerator.CommonDjlrXmxxs xmxxs = new InvoiceXmlGenerator.CommonDjlrXmxxs();
+ List xmxxList = new ArrayList<>();
+ if (rs.getString("MXS").toString().equals("1")) {
+ System.out.println("查询明细数据:1条");
+ InvoiceXmlGenerator.CommonDjlrXmxx xm1 = new InvoiceXmlGenerator.CommonDjlrXmxx();
+ xm1.setXh("1");
+ xm1.setXmmc(rs.getString("XMMC"));
+ xm1.setGgxh(rs.getString("GGXH"));
+ xm1.setDw(rs.getString("DW"));
+ xm1.setXmsl(rs.getString("XMSL"));
+ xm1.setXmje(rs.getString("XMJE"));
+ xm1.setSl(rs.getString("SL"));
+ xm1.setZkje(rs.getString("ZKJE"));
+ xmxxList.add(xm1);
+
+ } else {
+ //多条明细
+ ResultSet rsmx = null;
+ String sqlmx = "SELECT * FROM GR_DP_SASET_V where SASETTLEID=" + rs.getString("SASETTLEID");
+ rsmx = stmt.executeQuery(sqlmx);
+ System.out.println("查询明细数据:" + rsmx.getFetchSize() + "条");
+ int i = 1;
+ while (rsmx.next()) {
+ InvoiceXmlGenerator.CommonDjlrXmxx xm1 = new InvoiceXmlGenerator.CommonDjlrXmxx();
+ xm1.setXh(i + "");
+ xm1.setXmmc(rsmx.getString("XMMC"));
+ xm1.setGgxh(rsmx.getString("GGXH"));
+ xm1.setDw(rsmx.getString("DW"));
+ xm1.setXmsl(rsmx.getString("XMSL"));
+ xm1.setXmje(rsmx.getString("XMJE"));
+ xm1.setSl(rsmx.getString("SL"));
+ xm1.setZkje(rsmx.getString("ZKJE"));
+ xmxxList.add(xm1);
+ i++;
+ }
+ }
+
+ xmxxs.setCommonDjlrXmxxList(xmxxList);
+ fpt.setCommonDjlrXmxxs(xmxxs);
+
+ fptList.add(fpt);
+ fpts.setCommonDjlrFptList(fptList);
+ request.setCommonDjlrFpts(fpts);
+
+ // 5. 生成 XML 字符串
+ String xmldata = InvoiceXmlGenerator.generateXml(request).replace("", "");
+ //封装 请求报文
+ // 组装接口需要的请求报文
+ String payload = HttpXml.bulidSoapXML(interfaceCode, taxId, authCode, xmldata, "impSoHeaderInterface");
+
+ try {
+ // 调用接口
+ Map res = HttpXml.webServiceExecute(iBillInterfaceWebServiceUrl, payload);
+ System.out.println("接口请求状态:" + res.get("httpStatus"));
+ System.out.println("接口返回的原始报文:" + res.get("data"));
+ if (200 == (int) res.get("httpStatus")) {
+ try {
+ // 解析接口返回的报文
+// HashMap serviceData= parseResponseXML((String) res.get("data"));
+// System.out.println("业务处理返回代码:"+serviceData.get("returnCode"));
+// System.out.println("业务处理返回提示:"+serviceData.get("returnMessage"));
+// System.out.println("业务处理返回数据:"+serviceData.get("data"));
+ if (res.get("data").toString().contains("returnCode>0000</returnCode>")) {
+ //更新视图
+ System.out.println("更新视图");
+ String sqlupdate = "update GR_DP_SASET_V a set a.zxcolumn2 = '1' where a.sasettleid =" + SASETTLEID;
+ PreparedStatement pstmt = conn.prepareStatement(sqlupdate);
+ pstmt.execute();
+ System.out.println("完成更新视图");
+ grInvoiceRecord.setStatus(InvoiceConstants.UNTREATED);
+ grInvoiceRecord.setCreateTime(new Date());
+ grInvoiceRecordMapper.insertGrInvoiceRecord(grInvoiceRecord);
+ }
+
+ } catch (Exception e) {
+ System.out.println("解析报文出错的,保持业务为处理中状态,需要检查原因");
+ e.printStackTrace();
+ }
+ }
+ } catch (Exception e) {
+ e.printStackTrace();
+ System.out.println("数据库操作失败");
+ }
+ System.out.println(xmldata);
+ }
+
+ } catch (ClassNotFoundException e) {
+ System.out.println("Oracle JDBC驱动未找到!");
+ e.printStackTrace();
+ } catch (SQLException | JAXBException e) {
+ System.out.println("数据库访问异常!");
+ e.printStackTrace();
+ } finally {
+ // 6. 关闭资源
+ try {
+ if (rs != null) rs.close();
+ if (stmt != null) stmt.close();
+ if (conn != null) conn.close();
+ } catch (SQLException e) {
+ e.printStackTrace();
+ }
+ }
+
+// // 1. XML构造根对象
+// InvoiceXmlGenerator.RequestCommonDjlr request = new InvoiceXmlGenerator.RequestCommonDjlr();
+//
+// // 2. 构造发票集合
+// InvoiceXmlGenerator.CommonDjlrFpts fpts = new InvoiceXmlGenerator.CommonDjlrFpts();
+// List fptList = new ArrayList<>();
+
+
+ System.out.println("定时任务完成");
+ }
+
+}
diff --git a/src/main/java/top/lidee/project/monitor/job/util/HttpXml.java b/src/main/java/top/lidee/project/monitor/job/util/HttpXml.java
new file mode 100644
index 0000000..eb7ba5e
--- /dev/null
+++ b/src/main/java/top/lidee/project/monitor/job/util/HttpXml.java
@@ -0,0 +1,140 @@
+package top.lidee.project.monitor.job.util;
+
+import org.w3c.dom.Document;
+import org.w3c.dom.Element;
+import org.w3c.dom.Node;
+
+import javax.xml.parsers.DocumentBuilder;
+import javax.xml.parsers.DocumentBuilderFactory;
+import java.io.BufferedReader;
+import java.io.ByteArrayInputStream;
+import java.io.InputStreamReader;
+import java.io.OutputStream;
+import java.net.HttpURLConnection;
+import java.net.URL;
+import java.nio.charset.StandardCharsets;
+import java.util.Base64;
+import java.util.HashMap;
+import java.util.Map;
+
+
+public class HttpXml {
+
+ /*
+ * 数据请求
+ * @param requesturl 请求地址
+ * @param soapXML 请求报文
+ * */
+ public static Map webServiceExecute(String requesturl, String soapXML) throws Exception {
+ HttpURLConnection conn = null;
+ OutputStream os = null;
+ Map reslut = new HashMap<>();
+ try {
+ //1创建连接
+ URL url = new URL(requesturl);
+ conn = (HttpURLConnection) url.openConnection();
+ //2设置连接的配置
+ conn.setRequestMethod("POST");
+ conn.setRequestProperty("content-type", "text/xml;charset=utf-8");
+ conn.setDoInput(true);
+ conn.setDoOutput(true);
+ //3打开连接发送数据
+ os = conn.getOutputStream();
+ os.write(soapXML.getBytes());
+
+ String temp = null;
+ //4接收服务端的响应
+ //4.1http的响应码
+ int responseCode = conn.getResponseCode();
+ //4.2获取返回报文
+ BufferedReader br = new BufferedReader(new InputStreamReader(conn.getInputStream(), StandardCharsets.UTF_8));
+ StringBuilder response = new StringBuilder();
+ String responseLine;
+ while ((responseLine = br.readLine()) != null) {
+ response.append(responseLine.trim());
+ }
+ //简单模拟封装返回结果
+ reslut.put("httpStatus", responseCode);
+ reslut.put("data", response.toString());
+
+ } catch (Exception e) {
+ throw new RuntimeException("调用"+requesturl+"webservice出错!", e);
+ } finally {
+ if (conn != null) {
+ conn.disconnect();
+ }
+ }
+ return reslut;
+ }
+
+ /**
+ * 构建Soap请求报文
+ * @param interfaceCode 接口编码
+ * @param taxId 税号
+ * @param authCode 授权码
+ * @param content 内层业务报文的明文
+ */
+ public static String bulidSoapXML(String interfaceCode, String taxId, String authCode, String content, String ffmc) {
+ //数据报文通过base64编码
+ String payload = Base64.getEncoder().encodeToString(content.getBytes(StandardCharsets.UTF_8));
+ return "\n" +
+ "\n" +
+ "\n" +
+ "\n" +
+ "\t \t\n" +
+ "\t \t\t\n" +
+ "\t\t1.0 \t\t\n" +
+ "\t\t" + taxId + " \t\t\n" +
+ "\t\t" + interfaceCode + " \t\t\n" +
+ "\t\t" + authCode + " \t\n" +
+ "\t \t\n" +
+ "\t\t \t\t\n" +
+ "\t\t0000 \t\t\n" +
+ "\t\t \t\n" +
+ "\t \t\n" +
+ "\t \t\t\n" +
+ "\t\t \t\t\t\n" +
+ "\t\t\t0 \t\t\t\n" +
+ "\t\t\t0 \t\t\t\n" +
+ "\t\t\t0 \t\t\n" +
+ "\t\t \t\t\n" +
+ "\t\t" + payload + "\t\n" +
+ "\t\n" +
+ "\t]]>\n" +
+ "\t\n" +
+
+ "\n" +
+ "\n" +
+ "";
+ }
+
+ public static HashMap parseResponseXML(String resData){
+ try {
+ // 获取DocumentBuilderFactory实例
+ DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
+ // 配置安全选项防止XXE攻击
+ factory.setFeature("http://apache.org/xml/features/disallow-doctype-decl", true);
+ // 创建DocumentBuilder
+ DocumentBuilder builder = factory.newDocumentBuilder();
+ // 解析XML文件
+ Document document = builder.parse(new ByteArrayInputStream(resData.getBytes(StandardCharsets.UTF_8)));
+ // 获取根元素
+ Element root = document.getDocumentElement();
+ // 获取out节点
+ Node out = root.getFirstChild().getFirstChild().getFirstChild();
+ Document outXML = builder.parse(new ByteArrayInputStream(out.getTextContent().getBytes(StandardCharsets.UTF_8)));
+ // 解析返回的业务处理结果
+ String returnCode = outXML.getElementsByTagName("returnCode").item(0).getTextContent();
+ String returnMessage = outXML.getElementsByTagName("returnMessage").item(0).getTextContent();
+ String data = outXML.getElementsByTagName("content").item(0).getTextContent();
+ HashMap resMap = new HashMap<>();
+ resMap.put("returnCode", returnCode);
+ resMap.put("returnMessage", new String(Base64.getDecoder().decode(returnMessage)));
+ resMap.put("data", new String(Base64.getDecoder().decode(data)));
+ return resMap;
+ }catch (Exception e){
+ throw new RuntimeException("解析返回报文报错",e);
+ }
+
+ }
+}
diff --git a/src/main/java/top/lidee/project/monitor/job/util/InvoiceXmlGenerator.java b/src/main/java/top/lidee/project/monitor/job/util/InvoiceXmlGenerator.java
new file mode 100644
index 0000000..60035d4
--- /dev/null
+++ b/src/main/java/top/lidee/project/monitor/job/util/InvoiceXmlGenerator.java
@@ -0,0 +1,86 @@
+package top.lidee.project.monitor.job.util;
+
+
+import javax.xml.bind.JAXBContext;
+import javax.xml.bind.JAXBException;
+import javax.xml.bind.Marshaller;
+import javax.xml.bind.annotation.XmlElement;
+import javax.xml.bind.annotation.XmlRootElement;
+import javax.xml.bind.annotation.XmlType;
+import java.io.StringWriter;
+import java.util.List;
+
+public class InvoiceXmlGenerator {
+
+ // ========== XML 映射类 ==========
+ @XmlRootElement(name = "REQUEST_COMMON_DJLR")
+ @XmlType(propOrder = {"commonDjlrFpts"})
+ public static class RequestCommonDjlr {
+ private CommonDjlrFpts commonDjlrFpts;
+ @XmlElement(name = "COMMON_DJLR_FPTS")
+ public CommonDjlrFpts getCommonDjlrFpts() { return commonDjlrFpts; }
+ public void setCommonDjlrFpts(CommonDjlrFpts commonDjlrFpts) { this.commonDjlrFpts = commonDjlrFpts; }
+ }
+
+ @XmlType(propOrder = {"commonDjlrFptList"})
+ public static class CommonDjlrFpts {
+ private List commonDjlrFptList;
+ @XmlElement(name = "COMMON_DJLR_FPT")
+ public List getCommonDjlrFptList() { return commonDjlrFptList; }
+ public void setCommonDjlrFptList(List commonDjlrFptList) { this.commonDjlrFptList = commonDjlrFptList; }
+ }
+
+ @XmlType(propOrder = {"djh", "djrq", "fpzl", "kplx", "gmfMc", "hsbz", "kpr", "skr", "fhr", "bz", "zzbm", "createPersonName", "commonDjlrXmxxs"})
+ public static class CommonDjlrFpt {
+ private String djh, djrq, fpzl, kplx, gmfMc, hsbz, kpr, skr, fhr, bz, zzbm, createPersonName;
+ private CommonDjlrXmxxs commonDjlrXmxxs;
+ // getter/setter (均使用 @XmlElement 指定标签名)
+ @XmlElement(name = "DJH") public String getDjh() { return djh; } public void setDjh(String djh) { this.djh = djh; }
+ @XmlElement(name = "DJRQ") public String getDjrq() { return djrq; } public void setDjrq(String djrq) { this.djrq = djrq; }
+ @XmlElement(name = "FPZL") public String getFpzl() { return fpzl; } public void setFpzl(String fpzl) { this.fpzl = fpzl; }
+ @XmlElement(name = "KPLX") public String getKplx() { return kplx; } public void setKplx(String kplx) { this.kplx = kplx; }
+ @XmlElement(name = "GMF_MC") public String getGmfMc() { return gmfMc; } public void setGmfMc(String gmfMc) { this.gmfMc = gmfMc; }
+ @XmlElement(name = "HSBZ") public String getHsbz() { return hsbz; } public void setHsbz(String hsbz) { this.hsbz = hsbz; }
+ @XmlElement(name = "KPR") public String getKpr() { return kpr; } public void setKpr(String kpr) { this.kpr = kpr; }
+ @XmlElement(name = "SKR") public String getSkr() { return skr; } public void setSkr(String skr) { this.skr = skr; }
+ @XmlElement(name = "FHR") public String getFhr() { return fhr; } public void setFhr(String fhr) { this.fhr = fhr; }
+ @XmlElement(name = "BZ") public String getBz() { return bz; } public void setBz(String bz) { this.bz = bz; }
+ @XmlElement(name = "ZZBM") public String getZzbm() { return zzbm; } public void setZzbm(String zzbm) { this.zzbm = zzbm; }
+ @XmlElement(name = "CREATE_PERSON_NAME") public String getCreatePersonName() { return createPersonName; } public void setCreatePersonName(String createPersonName) { this.createPersonName = createPersonName; }
+ @XmlElement(name = "COMMON_DJLR_XMXXS") public CommonDjlrXmxxs getCommonDjlrXmxxs() { return commonDjlrXmxxs; } public void setCommonDjlrXmxxs(CommonDjlrXmxxs commonDjlrXmxxs) { this.commonDjlrXmxxs = commonDjlrXmxxs; }
+ }
+
+ @XmlType(propOrder = {"commonDjlrXmxxList"})
+ public static class CommonDjlrXmxxs {
+ private List commonDjlrXmxxList;
+ @XmlElement(name = "COMMON_DJLR_XMXX")
+ public List getCommonDjlrXmxxList() { return commonDjlrXmxxList; }
+ public void setCommonDjlrXmxxList(List commonDjlrXmxxList) { this.commonDjlrXmxxList = commonDjlrXmxxList; }
+ }
+
+ @XmlType(propOrder = {"xh", "xmmc", "ggxh", "dw", "xmsl", "xmje", "sl", "zkje"})
+ public static class CommonDjlrXmxx {
+ private String xh, xmmc, ggxh, dw, xmsl, xmje, sl, zkje;
+ @XmlElement(name = "XH") public String getXh() { return xh; } public void setXh(String xh) { this.xh = xh; }
+ @XmlElement(name = "XMMC") public String getXmmc() { return xmmc; } public void setXmmc(String xmmc) { this.xmmc = xmmc; }
+ @XmlElement(name = "GGXH") public String getGgxh() { return ggxh; } public void setGgxh(String ggxh) { this.ggxh = ggxh; }
+ @XmlElement(name = "DW") public String getDw() { return dw; } public void setDw(String dw) { this.dw = dw; }
+ @XmlElement(name = "XMSL") public String getXmsl() { return xmsl; } public void setXmsl(String xmsl) { this.xmsl = xmsl; }
+ @XmlElement(name = "XMJE") public String getXmje() { return xmje; } public void setXmje(String xmje) { this.xmje = xmje; }
+ @XmlElement(name = "SL") public String getSl() { return sl; } public void setSl(String sl) { this.sl = sl; }
+ @XmlElement(name = "ZKJE") public String getZkje() { return zkje; } public void setZkje(String zkje) { this.zkje = zkje; }
+ }
+
+ // ========== 生成 XML 字符串的方法 ==========
+ public static String generateXml(RequestCommonDjlr request) throws JAXBException {
+ JAXBContext context = JAXBContext.newInstance(RequestCommonDjlr.class);
+ Marshaller marshaller = context.createMarshaller();
+ marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, Boolean.TRUE);
+ marshaller.setProperty(Marshaller.JAXB_ENCODING, "UTF-8");
+
+ StringWriter sw = new StringWriter();
+ marshaller.marshal(request, sw);
+ return sw.toString();
+ }
+
+}
\ No newline at end of file
diff --git a/src/main/java/top/lidee/project/monitor/job/util/InvoiceXmlSy.java b/src/main/java/top/lidee/project/monitor/job/util/InvoiceXmlSy.java
new file mode 100644
index 0000000..3f5ed5b
--- /dev/null
+++ b/src/main/java/top/lidee/project/monitor/job/util/InvoiceXmlSy.java
@@ -0,0 +1,68 @@
+package top.lidee.project.monitor.job.util;
+
+import org.w3c.dom.Document;
+import org.w3c.dom.Element;
+
+import javax.xml.parsers.DocumentBuilder;
+import javax.xml.parsers.DocumentBuilderFactory;
+import javax.xml.parsers.ParserConfigurationException;
+import javax.xml.transform.OutputKeys;
+import javax.xml.transform.Transformer;
+import javax.xml.transform.TransformerException;
+import javax.xml.transform.TransformerFactory;
+import javax.xml.transform.dom.DOMSource;
+import javax.xml.transform.stream.StreamResult;
+import java.io.StringWriter;
+import java.util.List;
+
+public class InvoiceXmlSy {
+
+ /**
+ * 生成 XML 字符串
+ * @param billNoList 单据号列表,每个元素将生成一个 节点
+ * @return 格式化的 XML 字符串(不含 XML 声明)
+ * @throws ParserConfigurationException XML 解析器配置异常
+ * @throws TransformerException XML 转换异常
+ */
+ public static String generateDwzsXml(List billNoList) throws ParserConfigurationException, TransformerException {
+ // 1. 创建 Document 对象
+ DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
+ DocumentBuilder builder = factory.newDocumentBuilder();
+ Document doc = builder.newDocument();
+
+ // 2. 创建根元素 REQUEST_COMMON_DWZS,并设置 class 属性
+ Element root = doc.createElement("REQUEST_COMMON_DWZS");
+ root.setAttribute("class", "REQUEST_COMMON_DWZS");
+ doc.appendChild(root);
+
+ // 3. 创建 COMMON_DWZS_HEADERS 元素
+ Element headers = doc.createElement("COMMON_DWZS_HEADERS");
+ root.appendChild(headers);
+
+ // 4. 遍历单据号列表,为每个单据号创建一个 COMMON_DWZS_HEADER
+ for (String billNo : billNoList) {
+ Element header = doc.createElement("COMMON_DWZS_HEADER");
+ header.setAttribute("class", "COMMON_DWZS_HEADER");
+ headers.appendChild(header);
+
+ Element billNoElem = doc.createElement("BILLNO");
+ // 如果单据号为 null,则设为空字符串,避免 null 值导致异常
+ billNoElem.setTextContent(billNo != null ? billNo : "");
+ header.appendChild(billNoElem);
+ }
+
+ // 5. 将 Document 对象转换为格式化的 XML 字符串
+ TransformerFactory tf = TransformerFactory.newInstance();
+ Transformer transformer = tf.newTransformer();
+
+ // 设置输出属性:省略 XML 声明,启用缩进(4空格)
+ transformer.setOutputProperty(OutputKeys.OMIT_XML_DECLARATION, "yes");
+ transformer.setOutputProperty(OutputKeys.INDENT, "yes");
+ transformer.setOutputProperty("{http://xml.apache.org/xslt}indent-amount", "4");
+
+ StringWriter writer = new StringWriter();
+ transformer.transform(new DOMSource(doc), new StreamResult(writer));
+ return writer.toString();
+ }
+
+}
diff --git a/src/main/java/top/lidee/project/system/record/controller/GrInvoiceRecordController.java b/src/main/java/top/lidee/project/system/record/controller/GrInvoiceRecordController.java
new file mode 100644
index 0000000..a849c97
--- /dev/null
+++ b/src/main/java/top/lidee/project/system/record/controller/GrInvoiceRecordController.java
@@ -0,0 +1,136 @@
+package top.lidee.project.system.record.controller;
+
+import java.util.List;
+import org.apache.shiro.authz.annotation.RequiresPermissions;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Controller;
+import org.springframework.ui.ModelMap;
+import org.springframework.web.bind.annotation.*;
+import top.lidee.framework.aspectj.lang.annotation.Log;
+import top.lidee.framework.aspectj.lang.enums.BusinessType;
+import top.lidee.framework.web.controller.BaseController;
+import top.lidee.framework.web.domain.AjaxResult;
+import top.lidee.common.utils.poi.ExcelUtil;
+import top.lidee.framework.web.page.TableDataInfo;
+import top.lidee.project.system.record.domain.GrInvoiceRecord;
+import top.lidee.project.system.record.service.IGrInvoiceRecordService;
+
+/**
+ * 发票Controller
+ *
+ * @author yuheng
+ * @date 2026-04-02
+ */
+@Controller
+@RequestMapping("/system/record")
+public class GrInvoiceRecordController extends BaseController
+{
+ private String prefix = "system/record";
+
+ @Autowired
+ private IGrInvoiceRecordService grInvoiceRecordService;
+
+ @RequiresPermissions("system:record:view")
+ @GetMapping()
+ public String record()
+ {
+ return prefix + "/record";
+ }
+
+ /**
+ * 查询发票列表
+ */
+ @RequiresPermissions("system:record:list")
+ @PostMapping("/list")
+ @ResponseBody
+ public TableDataInfo list(GrInvoiceRecord grInvoiceRecord)
+ {
+ startPage();
+ List list = grInvoiceRecordService.selectGrInvoiceRecordList(grInvoiceRecord);
+ return getDataTable(list);
+ }
+
+ /**
+ * 导出发票列表
+ */
+ @RequiresPermissions("system:record:export")
+ @Log(title = "发票", businessType = BusinessType.EXPORT)
+ @PostMapping("/export")
+ @ResponseBody
+ public AjaxResult export(GrInvoiceRecord grInvoiceRecord)
+ {
+ List list = grInvoiceRecordService.selectGrInvoiceRecordList(grInvoiceRecord);
+ ExcelUtil util = new ExcelUtil(GrInvoiceRecord.class);
+ return util.exportExcel(list, "发票数据");
+ }
+
+ /**
+ * 新增发票
+ */
+ @GetMapping("/add")
+ public String add()
+ {
+ return prefix + "/add";
+ }
+
+ /**
+ * 新增保存发票
+ */
+ @RequiresPermissions("system:record:add")
+ @Log(title = "发票", businessType = BusinessType.INSERT)
+ @PostMapping("/add")
+ @ResponseBody
+ public AjaxResult addSave(GrInvoiceRecord grInvoiceRecord)
+ {
+ return toAjax(grInvoiceRecordService.insertGrInvoiceRecord(grInvoiceRecord));
+ }
+
+ /**
+ * 修改发票
+ */
+ @RequiresPermissions("system:record:edit")
+ @GetMapping("/edit/{id}")
+ public String edit(@PathVariable("id") String id, ModelMap mmap)
+ {
+ GrInvoiceRecord grInvoiceRecord = grInvoiceRecordService.selectGrInvoiceRecordById(id);
+ mmap.put("grInvoiceRecord", grInvoiceRecord);
+ return prefix + "/edit";
+ }
+
+ /**
+ * 修改保存发票
+ */
+ @RequiresPermissions("system:record:edit")
+ @Log(title = "发票", businessType = BusinessType.UPDATE)
+ @PostMapping("/edit")
+ @ResponseBody
+ public AjaxResult editSave(GrInvoiceRecord grInvoiceRecord)
+ {
+ return toAjax(grInvoiceRecordService.updateGrInvoiceRecord(grInvoiceRecord));
+ }
+
+ /**
+ * 删除发票
+ */
+ @RequiresPermissions("system:record:remove")
+ @Log(title = "发票", businessType = BusinessType.DELETE)
+ @PostMapping( "/remove")
+ @ResponseBody
+ public AjaxResult remove(String ids)
+ {
+ return toAjax(grInvoiceRecordService.deleteGrInvoiceRecordByIds(ids));
+ }
+
+ /**
+ * 批量处理发票
+ */
+ @RequiresPermissions("system:record:list")
+ @Log(title = "发票", businessType = BusinessType.UPDATE)
+ @PostMapping("/batchProcess")
+ @ResponseBody
+ public AjaxResult batchProcess(@RequestParam List idList)
+ {
+ return toAjax(grInvoiceRecordService.batchProcess(idList));
+ }
+
+}
diff --git a/src/main/java/top/lidee/project/system/record/domain/GrInvoiceRecord.java b/src/main/java/top/lidee/project/system/record/domain/GrInvoiceRecord.java
new file mode 100644
index 0000000..3c1e6a9
--- /dev/null
+++ b/src/main/java/top/lidee/project/system/record/domain/GrInvoiceRecord.java
@@ -0,0 +1,51 @@
+package top.lidee.project.system.record.domain;
+
+import lombok.Data;
+import org.apache.commons.lang3.builder.ToStringBuilder;
+import org.apache.commons.lang3.builder.ToStringStyle;
+import top.lidee.framework.aspectj.lang.annotation.Excel;
+import top.lidee.framework.web.domain.BaseEntity;
+
+import java.util.List;
+
+/**
+ * 发票对象 gr_invoice_record
+ *
+ * @author yuheng
+ * @date 2026-04-02
+ */
+@Data
+public class GrInvoiceRecord extends BaseEntity {
+ private static final long serialVersionUID = 1L;
+
+ /** */
+ private Long id;
+
+ /**单据号*/
+ @Excel(name = "")
+ private String djh;
+
+ /**单据日期*/
+ @Excel(name = "")
+ private String djrq;
+
+ /**发票种类*/
+ @Excel(name = "")
+ private String fpzl;
+
+ /**开票时间*/
+ @Excel(name = "")
+ private String kpsj;
+
+ /**开票状态*/
+ @Excel(name = "")
+ private String status;
+
+ private List statusList;
+ /**客户名称*/
+ private String gmfMc;
+
+ private String invNumber;
+
+
+}
diff --git a/src/main/java/top/lidee/project/system/record/mapper/GrInvoiceRecordMapper.java b/src/main/java/top/lidee/project/system/record/mapper/GrInvoiceRecordMapper.java
new file mode 100644
index 0000000..e4c7991
--- /dev/null
+++ b/src/main/java/top/lidee/project/system/record/mapper/GrInvoiceRecordMapper.java
@@ -0,0 +1,65 @@
+package top.lidee.project.system.record.mapper;
+
+import java.util.List;
+
+import org.apache.ibatis.annotations.Param;
+import top.lidee.project.system.record.domain.GrInvoiceRecord;
+
+/**
+ * 发票Mapper接口
+ *
+ * @author yuheng
+ * @date 2026-04-02
+ */
+public interface GrInvoiceRecordMapper
+{
+ /**
+ * 查询发票
+ *
+ * @param id 发票主键
+ * @return 发票
+ */
+ public GrInvoiceRecord selectGrInvoiceRecordById(String id);
+
+ /**
+ * 查询发票列表
+ *
+ * @param grInvoiceRecord 发票
+ * @return 发票集合
+ */
+ public List selectGrInvoiceRecordList(GrInvoiceRecord grInvoiceRecord);
+
+ /**
+ * 新增发票
+ *
+ * @param grInvoiceRecord 发票
+ * @return 结果
+ */
+ public int insertGrInvoiceRecord(GrInvoiceRecord grInvoiceRecord);
+
+ /**
+ * 修改发票
+ *
+ * @param grInvoiceRecord 发票
+ * @return 结果
+ */
+ public int updateGrInvoiceRecord(GrInvoiceRecord grInvoiceRecord);
+
+ /**
+ * 删除发票
+ *
+ * @param id 发票主键
+ * @return 结果
+ */
+ public int deleteGrInvoiceRecordById(String id);
+
+ /**
+ * 批量删除发票
+ *
+ * @param ids 需要删除的数据主键集合
+ * @return 结果
+ */
+ public int deleteGrInvoiceRecordByIds(String[] ids);
+
+ List selectGrInvoiceRecordListByIdList(@Param("list") List idList);
+}
diff --git a/src/main/java/top/lidee/project/system/record/service/IGrInvoiceRecordService.java b/src/main/java/top/lidee/project/system/record/service/IGrInvoiceRecordService.java
new file mode 100644
index 0000000..135f08b
--- /dev/null
+++ b/src/main/java/top/lidee/project/system/record/service/IGrInvoiceRecordService.java
@@ -0,0 +1,63 @@
+package top.lidee.project.system.record.service;
+
+import java.util.List;
+import top.lidee.project.system.record.domain.GrInvoiceRecord;
+
+/**
+ * 发票Service接口
+ *
+ * @author yuheng
+ * @date 2026-04-02
+ */
+public interface IGrInvoiceRecordService
+{
+ /**
+ * 查询发票
+ *
+ * @param id 发票主键
+ * @return 发票
+ */
+ public GrInvoiceRecord selectGrInvoiceRecordById(String id);
+
+ /**
+ * 查询发票列表
+ *
+ * @param grInvoiceRecord 发票
+ * @return 发票集合
+ */
+ public List selectGrInvoiceRecordList(GrInvoiceRecord grInvoiceRecord);
+
+ /**
+ * 新增发票
+ *
+ * @param grInvoiceRecord 发票
+ * @return 结果
+ */
+ public int insertGrInvoiceRecord(GrInvoiceRecord grInvoiceRecord);
+
+ /**
+ * 修改发票
+ *
+ * @param grInvoiceRecord 发票
+ * @return 结果
+ */
+ public int updateGrInvoiceRecord(GrInvoiceRecord grInvoiceRecord);
+
+ /**
+ * 批量删除发票
+ *
+ * @param ids 需要删除的发票主键集合
+ * @return 结果
+ */
+ public int deleteGrInvoiceRecordByIds(String ids);
+
+ /**
+ * 删除发票信息
+ *
+ * @param id 发票主键
+ * @return 结果
+ */
+ public int deleteGrInvoiceRecordById(String id);
+
+ int batchProcess(List idList);
+}
diff --git a/src/main/java/top/lidee/project/system/record/service/impl/GrInvoiceRecordServiceImpl.java b/src/main/java/top/lidee/project/system/record/service/impl/GrInvoiceRecordServiceImpl.java
new file mode 100644
index 0000000..1959483
--- /dev/null
+++ b/src/main/java/top/lidee/project/system/record/service/impl/GrInvoiceRecordServiceImpl.java
@@ -0,0 +1,280 @@
+package top.lidee.project.system.record.service.impl;
+
+import java.io.BufferedWriter;
+import java.io.FileWriter;
+import java.io.IOException;
+import java.sql.*;
+import java.text.SimpleDateFormat;
+import java.util.ArrayList;
+import java.util.Date;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+import org.apache.commons.collections.CollectionUtils;
+import org.springframework.beans.factory.annotation.Value;
+import top.lidee.common.constant.InvoiceConstants;
+import top.lidee.common.utils.DateUtils;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+import top.lidee.common.utils.StringUtils;
+import top.lidee.project.monitor.job.util.HttpXml;
+import top.lidee.project.monitor.job.util.InvoiceXmlSy;
+import top.lidee.project.system.record.mapper.GrInvoiceRecordMapper;
+import top.lidee.project.system.record.domain.GrInvoiceRecord;
+import top.lidee.project.system.record.service.IGrInvoiceRecordService;
+import top.lidee.common.utils.text.Convert;
+
+import javax.annotation.Resource;
+
+/**
+ * 发票Service业务层处理
+ *
+ * @author yuheng
+ * @date 2026-04-02
+ */
+@Service
+public class GrInvoiceRecordServiceImpl implements IGrInvoiceRecordService {
+ @Autowired
+ private GrInvoiceRecordMapper grInvoiceRecordMapper;
+
+ @Value("${invoice.url}")
+ private String URL;
+
+ @Value("${invoice.eiInvWebService}")
+ private String eiInvWebServiceUrl;
+ /**
+ * 数据库用户名
+ */
+ @Value("${invoice.username}")
+ private String USERNAME;
+ /**
+ * 数据库密码
+ */
+ @Value("${invoice.password}")
+ private String PASSWORD;
+ @Value("${invoice.taxId}")
+ private String taxId;
+ @Value("${invoice.authCode}")
+ private String authCode;
+ @Value("${invoice.updateCode}")
+ private String interfaceCode;
+ private static final String fPath = "C:\\log\\fplog.log";
+
+
+ /**
+ * 查询发票
+ *
+ * @param id 发票主键
+ * @return 发票
+ */
+ @Override
+ public GrInvoiceRecord selectGrInvoiceRecordById(String id) {
+ return grInvoiceRecordMapper.selectGrInvoiceRecordById(id);
+ }
+
+ /**
+ * 查询发票列表
+ *
+ * @param grInvoiceRecord 发票
+ * @return 发票
+ */
+ @Override
+ public List selectGrInvoiceRecordList(GrInvoiceRecord grInvoiceRecord) {
+ if (StringUtils.isNotBlank(grInvoiceRecord.getStatus()) && InvoiceConstants.UNTREATED.equals(grInvoiceRecord.getStatus())) {
+ List statusList = new ArrayList<>();
+ statusList.add(InvoiceConstants.UNTREATED);
+ statusList.add(InvoiceConstants.PROCESSED_NOT_SUCCESSFUL);
+ grInvoiceRecord.setStatus(null);
+ grInvoiceRecord.setStatusList(statusList);
+ }
+ return grInvoiceRecordMapper.selectGrInvoiceRecordList(grInvoiceRecord);
+ }
+
+ /**
+ * 新增发票
+ *
+ * @param grInvoiceRecord 发票
+ * @return 结果
+ */
+ @Override
+ public int insertGrInvoiceRecord(GrInvoiceRecord grInvoiceRecord) {
+ grInvoiceRecord.setCreateTime(DateUtils.getNowDate());
+ return grInvoiceRecordMapper.insertGrInvoiceRecord(grInvoiceRecord);
+ }
+
+ /**
+ * 修改发票
+ *
+ * @param grInvoiceRecord 发票
+ * @return 结果
+ */
+ @Override
+ public int updateGrInvoiceRecord(GrInvoiceRecord grInvoiceRecord) {
+ grInvoiceRecord.setUpdateTime(DateUtils.getNowDate());
+ return grInvoiceRecordMapper.updateGrInvoiceRecord(grInvoiceRecord);
+ }
+
+ /**
+ * 批量删除发票
+ *
+ * @param ids 需要删除的发票主键
+ * @return 结果
+ */
+ @Override
+ public int deleteGrInvoiceRecordByIds(String ids) {
+ return grInvoiceRecordMapper.deleteGrInvoiceRecordByIds(Convert.toStrArray(ids));
+ }
+
+ /**
+ * 删除发票信息
+ *
+ * @param id 发票主键
+ * @return 结果
+ */
+ @Override
+ public int deleteGrInvoiceRecordById(String id) {
+ return grInvoiceRecordMapper.deleteGrInvoiceRecordById(id);
+ }
+
+ @Override
+ public int batchProcess(List idList) {
+ if (CollectionUtils.isEmpty(idList)) {
+ return 1;
+ }
+ List grInvoiceRecords = grInvoiceRecordMapper.selectGrInvoiceRecordListByIdList(idList);
+ if (CollectionUtils.isEmpty(grInvoiceRecords)) {
+ System.out.println("没有待请求数据");
+ return 1;
+ }
+ try {
+ for (GrInvoiceRecord invoiceRecord : grInvoiceRecords) {
+ String key = invoiceRecord.getDjh();
+ String txtCon = "";
+ List billNos = new ArrayList<>();
+ billNos.add(key);
+
+ System.out.println("溯源 Id:" + billNos);
+ txtCon += "溯源 Id:" + billNos + "\n";
+ //封装 请求报文
+ String xmldata = InvoiceXmlSy.generateDwzsXml(billNos);
+
+ // 组装接口需要的请求报文
+ String payload = HttpXml.bulidSoapXML(interfaceCode, taxId, authCode, xmldata, "eiInterface");
+ System.out.println(payload);
+ boolean hasError = false;
+ try {
+ // 调用接口
+ Map res = HttpXml.webServiceExecute(eiInvWebServiceUrl, payload);
+ System.out.println("接口请求状态:" + res.get("httpStatus"));
+ System.out.println("接口返回的原始报文:" + res.get("data"));
+ txtCon += "接口请求状态:" + res.get("httpStatus") + "\n";
+ txtCon += "接口返回的原始报文:" + res.get("data") + "\n";
+ if (200 == (int) res.get("httpStatus")) {
+ try {
+ // 解析接口返回的报文
+ HashMap serviceData = HttpXml.parseResponseXML((String) res.get("data"));
+ System.out.println("业务处理返回代码:" + serviceData.get("returnCode"));
+ System.out.println("业务处理返回提示:" + serviceData.get("returnMessage"));
+ System.out.println("业务处理返回数据:" + serviceData.get("data"));
+
+ txtCon += "业务处理返回代码:" + serviceData.get("returnCode") + "\n";
+ txtCon += "业务处理返回提示:" + serviceData.get("returnMessage") + "\n";
+ txtCon += "业务处理返回数据:" + serviceData.get("data") + "\n";
+// appendToFile(fPath, txtCon);
+ String invNumber = "1";
+ String xml = serviceData.get("data");
+ Pattern pattern = Pattern.compile("(.*?)");
+ Matcher matcher = pattern.matcher(xml);
+ if (matcher.find()) {
+ invNumber = matcher.group(1);
+ }
+
+ // 如果没有被开发票(invNumber 为 1)
+ if (invNumber.equals("1")) {
+ System.out.println("单据号 " + key + " 还未开票");
+ continue;
+ }
+
+ if (serviceData.get("returnCode").equals("0000")) {
+ //更新数据库
+ Connection conn = null;
+ Statement stmt = null;
+ ResultSet rs = null;
+ try {
+ System.out.println("更新视图开始");
+ // 1. 加载 Oracle JDBC 驱动
+ Class.forName("oracle.jdbc.driver.OracleDriver");
+ // 2. 建立数据库连接
+ conn = DriverManager.getConnection(URL, USERNAME, PASSWORD);
+ // 3. 创建 Statement 对象
+ stmt = conn.createStatement();
+ // 4. 执行查询语句
+ String sql = "update gr_dp_saset_sdhm_v a set a.zxcolumn1 = '" + invNumber + "' where a.sasettleid =" + key;
+ PreparedStatement pstmt = conn.prepareStatement(sql);
+ int rowsA = pstmt.executeUpdate();
+ System.out.println("完成更新视图:" + rowsA);
+ invoiceRecord.setStatus(InvoiceConstants.SUCCESSFUL);
+ SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
+ invoiceRecord.setKpsj(sdf.format(new Date()));
+ invoiceRecord.setInvNumber(invNumber);
+ grInvoiceRecordMapper.updateGrInvoiceRecord(invoiceRecord);
+ } catch (Exception e) {
+ e.printStackTrace();
+ // 发生错误,标记为已尝试但不需要重试
+ hasError = true;
+ // 6. 关闭资源
+ try {
+ if (rs != null) rs.close();
+ if (stmt != null) stmt.close();
+ if (conn != null) conn.close();
+ } catch (SQLException e11) {
+ e11.printStackTrace();
+ }
+ }
+ } else {
+ // 业务处理失败,标记为已尝试但不需要重试
+ hasError = true;
+ System.out.println("业务处理失败:" + serviceData.get("returnMessage"));
+ }
+ } catch (Exception e) {
+ System.out.println("解析报文出错的,保持业务为处理中状态,需要检查原因");
+ e.printStackTrace();
+ hasError = true;
+ }
+ } else {
+ // HTTP 请求状态不是 200,标记为已尝试但不需要重试
+ hasError = true;
+ System.out.println("HTTP 请求失败,状态码:" + res.get("httpStatus"));
+ }
+ } catch (Exception e) {
+ e.printStackTrace();
+ hasError = true;
+ }
+ // 如果发生错误,更新状态为 1(已尝试但不需要重试)
+ if (hasError) {
+ invoiceRecord.setStatus(InvoiceConstants.PROCESSED_NOT_SUCCESSFUL);
+ grInvoiceRecordMapper.updateGrInvoiceRecord(invoiceRecord);
+ System.out.println("单据号 " + key + " 处理失败,标记为已尝试状态");
+ }
+
+ }
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ return 1;
+ }
+
+
+ // 追加写入模式
+ public static void appendToFile(String filePath, String content) throws IOException {
+ try (BufferedWriter writer = new BufferedWriter(new FileWriter(filePath, true))) {
+ writer.newLine(); // 换行后再追加
+ writer.write(content);
+ } catch (IOException e) {
+ throw new RuntimeException(e);
+ }
+ }
+}
diff --git a/src/main/resources/application-druid.yml b/src/main/resources/application-druid.yml
index 3cfe970..6035786 100644
--- a/src/main/resources/application-druid.yml
+++ b/src/main/resources/application-druid.yml
@@ -7,7 +7,8 @@ spring:
druid:
# 主库数据源 root
master:
- url: jdbc:sqlite:D:/uploadPath/SQLite/sqlite3.db?date_string_format=yyyy-MM-dd HH:mm:ss
+# url: jdbc:sqlite:D:/work/gr_fapiao/sql/sqlite3.db?date_string_format=yyyy-MM-dd HH:mm:ss
+ url: jdbc:sqlite:c:/SQLite/sql/sqlite3.db?date_string_format=yyyy-MM-dd HH:mm:ss
username:
password:
# 从库数据源
diff --git a/src/main/resources/application.yml b/src/main/resources/application.yml
index 9470c32..570f94f 100644
--- a/src/main/resources/application.yml
+++ b/src/main/resources/application.yml
@@ -150,4 +150,23 @@ gen:
# 自动去除表前缀,默认是true
autoRemovePre: true
# 表前缀(生成类名不会包含表前缀,多个用逗号分隔)
- tablePrefix: sys_
\ No newline at end of file
+ tablePrefix: sys_
+invoice:
+ # 开票系统地址
+ url: jdbc:oracle:thin:@192.168.1.247:1521:gryy
+ # 开票系统用户名
+ username: GRYYINV
+ # 开票系统密码
+ password: xxb147258368
+
+ taxId: 9134040072334670XN
+
+ authCode: 7G5X2YSSMA
+
+ interfaceCode: DJLR
+
+ updateCode: DWZS
+
+ eiInvWebService: https://csxtqd.nuocity.com/open/services/eiInvWebService?wsdl
+
+ iBillInterfaceWebService: https://csxtqd.nuocity.com/open/services/iBillInterfaceWebService?wsdl
diff --git a/src/main/resources/mybatis/system/GrInvoiceRecordMapper.xml b/src/main/resources/mybatis/system/GrInvoiceRecordMapper.xml
new file mode 100644
index 0000000..68c7e45
--- /dev/null
+++ b/src/main/resources/mybatis/system/GrInvoiceRecordMapper.xml
@@ -0,0 +1,131 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ select id,
+ djh,
+ djrq,
+ fpzl,
+ kpsj,
+ create_by,
+ create_time,
+ update_by,
+ update_time,
+ status,
+ gmf_mc,
+ inv_number
+ from gr_invoice_record
+
+
+
+
+
+
+
+ insert into gr_invoice_record
+
+ id,
+ djh,
+ djrq,
+ fpzl,
+ kpsj,
+ create_by,
+ create_time,
+ update_by,
+ update_time,
+ status,
+ gmf_mc,
+ inv_number,
+
+
+ #{id},
+ #{djh},
+ #{djrq},
+ #{fpzl},
+ #{kpsj},
+ #{createBy},
+ #{createTime},
+ #{updateBy},
+ #{updateTime},
+ #{status},
+ #{gmfMc},
+ #{invNumber},
+
+
+
+
+ update gr_invoice_record
+
+ djh = #{djh},
+ djrq = #{djrq},
+ fpzl = #{fpzl},
+ kpsj = #{kpsj},
+ create_by = #{createBy},
+ create_time = #{createTime},
+ update_by = #{updateBy},
+ update_time = #{updateTime},
+ status = #{status},
+ gmf_mc = #{gmfMc},
+ inv_number = #{invNumber},
+
+ where id = #{id}
+
+
+
+ delete
+ from gr_invoice_record
+ where id = #{id}
+
+
+
+ delete from gr_invoice_record where id in
+
+ #{id}
+
+
+
+
+
+
\ No newline at end of file
diff --git a/src/main/resources/templates/index.html b/src/main/resources/templates/index.html
index 91f74e6..0067c5a 100644
--- a/src/main/resources/templates/index.html
+++ b/src/main/resources/templates/index.html
@@ -26,7 +26,7 @@
- lidee
+ 电票系统