From 5ccff4d2fcf7ce347050424cef85c71e31c053f8 Mon Sep 17 00:00:00 2001 From: unknown <1043974142@qq.com> Date: Thu, 30 May 2024 16:30:32 +0800 Subject: [PATCH] third commit --- customer/__init__.py | 0 customer/__pycache__/__init__.cpython-312.pyc | Bin 0 -> 163 bytes customer/__pycache__/__init__.cpython-39.pyc | Bin 0 -> 161 bytes customer/__pycache__/admin.cpython-312.pyc | Bin 0 -> 207 bytes customer/__pycache__/admin.cpython-39.pyc | Bin 0 -> 202 bytes customer/__pycache__/apps.cpython-312.pyc | Bin 0 -> 473 bytes customer/__pycache__/apps.cpython-39.pyc | Bin 0 -> 442 bytes customer/__pycache__/models.cpython-312.pyc | Bin 0 -> 8661 bytes customer/__pycache__/models.cpython-39.pyc | Bin 0 -> 5058 bytes customer/__pycache__/urls.cpython-312.pyc | Bin 0 -> 2248 bytes customer/__pycache__/urls.cpython-39.pyc | Bin 0 -> 1448 bytes customer/__pycache__/views.cpython-312.pyc | Bin 0 -> 16585 bytes customer/__pycache__/views.cpython-39.pyc | Bin 0 -> 8690 bytes customer/admin.py | 3 + customer/apps.py | 6 + customer/migrations/0001_initial.py | 139 ++++++ customer/migrations/__init__.py | 0 .../__pycache__/0001_initial.cpython-312.pyc | Bin 0 -> 7777 bytes .../__pycache__/__init__.cpython-312.pyc | Bin 0 -> 174 bytes .../__pycache__/__init__.cpython-39.pyc | Bin 0 -> 172 bytes customer/models.py | 171 +++++++ customer/tests.py | 3 + customer/urls.py | 35 ++ customer/views.py | 456 ++++++++++++++++++ report/__init__.py | 0 report/__pycache__/__init__.cpython-312.pyc | Bin 0 -> 161 bytes report/__pycache__/__init__.cpython-39.pyc | Bin 0 -> 159 bytes report/__pycache__/admin.cpython-312.pyc | Bin 0 -> 205 bytes report/__pycache__/admin.cpython-39.pyc | Bin 0 -> 200 bytes report/__pycache__/apps.cpython-312.pyc | Bin 0 -> 467 bytes report/__pycache__/apps.cpython-39.pyc | Bin 0 -> 436 bytes report/__pycache__/models.cpython-312.pyc | Bin 0 -> 202 bytes report/__pycache__/models.cpython-39.pyc | Bin 0 -> 197 bytes report/__pycache__/urls.cpython-312.pyc | Bin 0 -> 859 bytes report/__pycache__/urls.cpython-39.pyc | Bin 0 -> 587 bytes report/__pycache__/views.cpython-312.pyc | Bin 0 -> 4077 bytes report/__pycache__/views.cpython-39.pyc | Bin 0 -> 2525 bytes report/admin.py | 3 + report/apps.py | 6 + report/migrations/__init__.py | 0 .../__pycache__/__init__.cpython-312.pyc | Bin 0 -> 172 bytes .../__pycache__/__init__.cpython-39.pyc | Bin 0 -> 170 bytes report/models.py | 3 + report/tests.py | 3 + report/urls.py | 14 + report/views.py | 99 ++++ 46 files changed, 941 insertions(+) create mode 100644 customer/__init__.py create mode 100644 customer/__pycache__/__init__.cpython-312.pyc create mode 100644 customer/__pycache__/__init__.cpython-39.pyc create mode 100644 customer/__pycache__/admin.cpython-312.pyc create mode 100644 customer/__pycache__/admin.cpython-39.pyc create mode 100644 customer/__pycache__/apps.cpython-312.pyc create mode 100644 customer/__pycache__/apps.cpython-39.pyc create mode 100644 customer/__pycache__/models.cpython-312.pyc create mode 100644 customer/__pycache__/models.cpython-39.pyc create mode 100644 customer/__pycache__/urls.cpython-312.pyc create mode 100644 customer/__pycache__/urls.cpython-39.pyc create mode 100644 customer/__pycache__/views.cpython-312.pyc create mode 100644 customer/__pycache__/views.cpython-39.pyc create mode 100644 customer/admin.py create mode 100644 customer/apps.py create mode 100644 customer/migrations/0001_initial.py create mode 100644 customer/migrations/__init__.py create mode 100644 customer/migrations/__pycache__/0001_initial.cpython-312.pyc create mode 100644 customer/migrations/__pycache__/__init__.cpython-312.pyc create mode 100644 customer/migrations/__pycache__/__init__.cpython-39.pyc create mode 100644 customer/models.py create mode 100644 customer/tests.py create mode 100644 customer/urls.py create mode 100644 customer/views.py create mode 100644 report/__init__.py create mode 100644 report/__pycache__/__init__.cpython-312.pyc create mode 100644 report/__pycache__/__init__.cpython-39.pyc create mode 100644 report/__pycache__/admin.cpython-312.pyc create mode 100644 report/__pycache__/admin.cpython-39.pyc create mode 100644 report/__pycache__/apps.cpython-312.pyc create mode 100644 report/__pycache__/apps.cpython-39.pyc create mode 100644 report/__pycache__/models.cpython-312.pyc create mode 100644 report/__pycache__/models.cpython-39.pyc create mode 100644 report/__pycache__/urls.cpython-312.pyc create mode 100644 report/__pycache__/urls.cpython-39.pyc create mode 100644 report/__pycache__/views.cpython-312.pyc create mode 100644 report/__pycache__/views.cpython-39.pyc create mode 100644 report/admin.py create mode 100644 report/apps.py create mode 100644 report/migrations/__init__.py create mode 100644 report/migrations/__pycache__/__init__.cpython-312.pyc create mode 100644 report/migrations/__pycache__/__init__.cpython-39.pyc create mode 100644 report/models.py create mode 100644 report/tests.py create mode 100644 report/urls.py create mode 100644 report/views.py diff --git a/customer/__init__.py b/customer/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/customer/__pycache__/__init__.cpython-312.pyc b/customer/__pycache__/__init__.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..8ca9451d176d179aca6add6b12c68825c34d7b3d GIT binary patch literal 163 zcmX@j%ge<81SjV8rGV(iAOanHW&w&!XQ*V*Wb|9fP{ah}eFmxd<>YJ?6Iz^FR2-9$ zl@;TXTAW>yUl8Mxm6(^FAMYIG8y{R*T#}lro0|xviei#Wi%arzfsFY0%)HE!_;|g7 i%3mBdx%nxjIjMFg`kf)n%lQb6=$5P=LBfgA@QE@lA|DGb33nv8xc8Hzx{2;!HUvsFxJacWU< zjG>XGp+SsGetBL_equ^-j7wHxUV47KbC7R*aAk2xYOZc>B9JPINiHoe$m}#sl@w(r6)^)9tYr8MQuoW=*(xTqIJKxaCL=2=#wE2l zyClCL#s#b)-Z{uOKDe^DBsEtzHxWn`#Uz&&m*nRH8DPWp3Mzkb*yQG?l;)(`6>$K~ WV+7)25aRg`kf)n%lQtW~BV-N=!FabFZKwK;UBvKes7;_kM8KW2(8B&;n88n$+0!0}# z8E>&BrsQVk`Drpm@ug%X=B4NBCFkdr6lEqAfecv5P{a(Rz{D?SXRDad;?$zz7(*jV zLxUKX{PMh<{KS;v7#Fb4c;_JB_~6RolGI$?+(aN%6q8(9T#}y)WPokaE2zB1VUwGm QQks)$#|Sj{GY~TX0G5(7Qvd(} literal 0 HcmV?d00001 diff --git a/customer/__pycache__/apps.cpython-312.pyc b/customer/__pycache__/apps.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..e677e2e6d5261a0d50cf8ba073d9e9cc59c46a4e GIT binary patch literal 473 zcmXv~ze~eF6n>YaQu_-LEjT#12pP;QB88fwlN}TXL*O`j*V>vi@h%zSCUh1Dp_{w- zj|eV~CE(=bCRCSB-X-Z9-uu3LKkmKnykNbB_u#-;iJm3>-wk(I|3ssyRlY zn?~BOV-W>D<9YwxHXV`iAh76_QUz1d+D3pRfIzs3Zc79hh)O@`B0~xZee<%!l>Hq)$ literal 0 HcmV?d00001 diff --git a/customer/__pycache__/apps.cpython-39.pyc b/customer/__pycache__/apps.cpython-39.pyc new file mode 100644 index 0000000000000000000000000000000000000000..939e0c25fbca15c078ab1544a4aa7cfb06ab6da9 GIT binary patch literal 442 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 Zoogs=Kjq_NOP6k3xqjt892Dtn{|hE9^Sl56 literal 0 HcmV?d00001 diff --git a/customer/__pycache__/models.cpython-39.pyc b/customer/__pycache__/models.cpython-39.pyc new file mode 100644 index 0000000000000000000000000000000000000000..ec80d0116321d58a5373cbedf08f6e9544cc0454 GIT binary patch literal 5058 zcmb`LTW=f37035Ra(NRkx;sv4Cuv#&ty>4ZByAcfm0-t>MWwdehk<~_iZhZZFS+XM zG8TnC)dBqEe1N71oW3c@Q(yYl=YEEHEfR!Zp$~2UXJ#p_E`bm?BzAb_?Ck99?C<=~ z48wZ8V&U`8Pd?(KCCmC3Rq`JXl@%PxM<}?(?Z_I~%(kuD7I(P&p~YQc?>UcM=ECFg z0z3tHJa`K56nP1rQsybbV%*27`A zBV^Ccbwf7wL`SlKBDGTckJe-7ne(Z&=Tcu!ZR(>tp{5v5sh|8ljQYIesX{W^7gEx- zsT;F zxfVYfMsdiK&9%L7xDyAf_tt~^<0KV>9}YtN$j#m;N#g+wGaWbf$FhX`7H}jE3d=rR z&Ohai{CGMAMf%$%|U>>{Tb_MSSdl+_APZRY3fvbF&l_tC17)u>f9 zXV-FeUE5_&ZDzC$1ohPoU90IcO>Mi{ZfUy?4Cx;2tVY+*=333=?D?F%kh2$a_EOGX z&e>OBzrY*3iTR=XzLXV*Wq*vsOT#}<1PL9@u0 z5Hw4V9rj(m3_`Cce>G#|0l2H~%l;sg z!o_wtic;nGli&l28A(u}=NIrJuc5##r3h0Ia1_}IRSQRH91P<}LCCqPj`r!KZgCDW zy3-1dq={k*8Mm3s9SYjR`gBTetcx^c6%0C?qwbL>XK;~hP(ha~ACH=bTam~?ukk17 zl}A0i1#3!u2X?pf+L>M?1*0mzgGad47ZF!ZpR4lfZYXt?c@KAovGOS5lo#URRRu%J zq)8Pb@qvh#I~a539*nsvVG5*366VvCuVThkVShIs3g&Ky2dsoSrzvNp@%ZrYu(zw6 zZOOdD-r*kehU2lI`;B+0Jltgkp71^V?9h*@-5I6=dT54ONK(wQBt22}HJA_j17S{8 z%sV2ds+hN-?b3AAZWu*I1xxYPp6I2Cq{+Ex8YS^k#*w^%!gp%U4324eVi_;hkH7Ye z{`z*&(Y>65;aGA0jIO6JAd1c^4iXvS%P0<%1#vi49ABR?n&WcPkg4XlNMuwa)$yPw zNMfjw?vQR!G&@>t>b#ZJ8ls6vZ6Q(--H6m#L~5JQ0n2$+y4xQ<#O$deMO>dF3Ux?O zoU(F+lUl6h71Ss6SaK1CDjx3kABjGz#oOEco(MDul7dfOr$V=UnXFe(Jdm%F`5KCI zQ*~L~)UpAZuxX!!O+bT#M0Dl%sPmKTa2zQ5)pv37bezmy6esd0XvYeeggadRfNY=o z?;<#un}`FsLcXeb-1iB4^Rz^%{23KLr-D$@{K;RE^|kC#^uB{bCwj04p6EFFf-Gut zZo24xD|F#sQRK-I1#W|ZB322mCdx-f^FS0a1e$1xlre-H1fnX()Kqo586s)NVU(Mi zqQPfyE#;#oD58ES8~MDM^+Wl{2VthyIWZ5y7ETeim=QL!n(5qz64j#*h7B#@eDJ$dK}%e&NMfQp{O z_h|}QU8`;|og4}W`BN%1;ok^u0{cEa*fkWs>@C0!K}Bs= z%mMFt;Ee?m1hfqSUEs42&^cAx&{(e_CHJE##aLhb8jmGuL%=FKamch%R1)sJunP zrI#shqfiBX4VG#jJ*H1I|$b_w~kLDz{}U;BDF@JgZ`1{bEu8_#<3k#IjCPqGN#w} z#o3h49S}nldKra8Xb~h)+K1wi2BJob#hNCth8huwWKWAn)Mi8jlr=$F_U{KMgZ6>4 zmTFGl(>(!Y!j6EIG!=b*tK;gGqN?j{*)U0E*dL~H6@!$&MWIRqOx8#W!=qNSZ*N&R ze|BI7qS;*jmD!Ll0qHZE+EXC4F9b>J8@(W{Z>$EEbkZeMOn!YpCw1a{P6@k*4xZsi zXlvrz*k2%V=J25N-A)xdVg29C4ZfxKc=Ap7&90}Q|9H_$1igMVf=rU9*^<=5MN4Jn dzh(Z3dD}*dgtntKw_Rwz(Qdb|wwKz={{wOMMhXA` literal 0 HcmV?d00001 diff --git a/customer/__pycache__/urls.cpython-312.pyc b/customer/__pycache__/urls.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..a834fad7624704fd9829e362792af31a162241f6 GIT binary patch literal 2248 zcma)-&2Jk;7{=G}_#<(?Z8x@)*p8{|I3#g}NK;Xhh@=gwL?BQQ!m?x>&yZ~J+Scs4 zZ43vv<%Du0CzN9mAn|7)aoLqtTCq|E6{p^cdh3aIW_KNDwL$FR-FKe(%`@}v&d&Zm zHZ~%__1h2M;a`G+@HcBX*EKtNiTr}_y?_PmYYLLD;`6b5s5vD0D}D)85VZXmH3L$x z5`;WZ2@MIvkAoz5H0hXK+;QmV@K4~#F3t@DH*K{CBOY;a5#VBjgq7n_7dHl+v-SZT zkGr@D;1UCXo#IIsHw9eEgPV47QQ+o0xR{HJ1DE#TuDQ4w;IbZE!o?+l%Xx4q7dH#s zbq{XN#mxhE!-Gq^xD0TM9$ePNEdaOV!R1`sYrrjgaMxX29=KHx?uLsi0C&@aTXb-2DA+gnHb}@PGv%4RP_$&7i)y-b6Wx< zf82KwaW885V4~E;reim4*;%6PYH1}Kw9MxR&21X&`DpNtG~2T5c#g1!?ZtC@fs?ie z?`F2WX+G@oil%t?r3FPfMoEW?+fEJ+9*1@3YU1@p&8V))yj`O6IKX!&KOMa=Ud=$@|4wa~vPlTL?EgWhSYUq$8fAg~ z18AHDcFNNk7T7sXlPs{4n$AKnBQQ05o(iEY`A6X;NW!a)?YF9*$b`z(!=t0>T_S&} zv^&+ieEqfUk9KPhj%9^ND^eY9wCa3VRaV7n=lE5)EVXgBNj4}uN!jNve+BV{-{X5(PPf#&$~upM=R{8yN5awfjdc_-ZNrFEml--zN4cpCZ*5fMsi6@ zF8w-hO>i=Q7BCWJEdl-w9bxXDJ`Wh#+gkRvy7@pyA9Mftv#ycZ(lT4>eaD{;mU2et)-qJF+)VKF^^dUFn6KrbPO?9WPqkYb0&f~_y znzpc}mfzFSF6Vgh>soGI-S|L9d;eEsm1fTJM(U21x}$E@boBX)^|^_mZzGib`u+uy C9a^*i literal 0 HcmV?d00001 diff --git a/customer/__pycache__/urls.cpython-39.pyc b/customer/__pycache__/urls.cpython-39.pyc new file mode 100644 index 0000000000000000000000000000000000000000..13f3fce2c9bd425469a3da4d64c4452df3a094a8 GIT binary patch literal 1448 zcmaKs%Wl(95Qgoomiisw5!kcf zJ$MFh5sSV8D`t+zp{XdA{QG<}xO}W2yu>ry(=`n= z&|S^bN4ieqoSXCVqr7K~4CFi*?vhs+6>z*XDvCT5MB$_aMJRpFBP}B>Lz$_9RE8>3 z4XFZkrUp_KnoKRE8nl@@NOkBk^^h8{!nBIigf*rqu?5!L)(Yfla0@q%LeT z-9+laEvDN@D{zPDF48L8W4e#D1`n8qNPT!nble^d;L$s6xN|}8a;PUuHh7Ld%q7Ou zjy@(u$Dg<}5EuATRr=HsXJJyB%)%(}gp3Q058{)V)U$}C0_bG;wkP6VC|og#ta;jX z!pKaz{|d)j6DjOSSb?-=Q=rlOwyAwA%w+Tb1@Yk8yqWZ`&BaB)Nk-`3NC)%B#??TA zkR~@-QIvKVr(mZ2Y;r%UfI`;M`P{{UxRd&Th-}Br?Aoba8f4crW^!R_zH!-{tI=NF zjouYE2*b>?Ou$}h%oA*~hf0%e+*Y?O&Zwo*3lr+7GAX9g5vPLP`s|j4savYU*>o4{ zv*j_bRDrm+Se1SneE8ijwULM!gUHzW(x|(|KB=A2t(le8F_Ms>)y)f|q zcJgMpp48#Q_K$;Iydjd#k<8&PNGcqhNjH>vj7WpRn#A9dmXz%2)S{&?OO&FYmaLFe zNopi@k_JhWq(#yu>5z0udL;BqldB|aBz=+rN>af`CIVcOFKhNKjj5g8>3LFm?gcP&#S7Z< a;SNewZ|c>YVbt|{PMxV{lwNg}`Sk}W4aMyM literal 0 HcmV?d00001 diff --git a/customer/__pycache__/views.cpython-312.pyc b/customer/__pycache__/views.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..0effebe2a4ed51829145f458d5a7f9c9b52eae76 GIT binary patch literal 16585 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 literal 0 HcmV?d00001 diff --git a/customer/admin.py b/customer/admin.py new file mode 100644 index 0000000..8c38f3f --- /dev/null +++ b/customer/admin.py @@ -0,0 +1,3 @@ +from django.contrib import admin + +# Register your models here. diff --git a/customer/apps.py b/customer/apps.py new file mode 100644 index 0000000..ac9e398 --- /dev/null +++ b/customer/apps.py @@ -0,0 +1,6 @@ +from django.apps import AppConfig + + +class CustomerConfig(AppConfig): + default_auto_field = 'django.db.models.BigAutoField' + name = 'customer' diff --git a/customer/migrations/0001_initial.py b/customer/migrations/0001_initial.py new file mode 100644 index 0000000..5c53755 --- /dev/null +++ b/customer/migrations/0001_initial.py @@ -0,0 +1,139 @@ +# Generated by Django 3.2.9 on 2024-05-29 16:44 + +from django.db import migrations, models +import django.db.models.deletion +import django.db.models.manager + + +class Migration(migrations.Migration): + + initial = True + + dependencies = [ + ] + + operations = [ + migrations.CreateModel( + name='Customer', + fields=[ + ('id', models.AutoField(primary_key=True, serialize=False)), + ('khno', models.CharField(max_length=20, unique=True)), + ('name', models.CharField(max_length=20)), + ('area', models.CharField(max_length=20)), + ('cusManager', models.CharField(db_column='cus_manager', max_length=30)), + ('level', models.CharField(max_length=30)), + ('myd', models.CharField(max_length=30)), + ('xyd', models.CharField(max_length=30)), + ('address', models.CharField(max_length=100)), + ('postCode', models.CharField(db_column='post_code', max_length=10)), + ('phone', models.CharField(max_length=18)), + ('fax', models.CharField(max_length=20)), + ('website', models.CharField(db_column='web_site', max_length=50)), + ('yyzzzch', models.CharField(max_length=50)), + ('fr', models.CharField(max_length=20)), + ('zczj', models.CharField(max_length=20)), + ('nyye', models.CharField(max_length=20)), + ('khyh', models.CharField(max_length=20)), + ('khzh', models.CharField(max_length=20)), + ('dsdjh', models.CharField(max_length=20)), + ('gsdjh', models.CharField(max_length=20)), + ('state', models.IntegerField(default=0)), + ('isValid', models.IntegerField(db_column='is_valid', default=1)), + ('createDate', models.DateTimeField(auto_now_add=True, db_column='create_date')), + ('updateDate', models.DateTimeField(auto_now_add=True, db_column='update_date')), + ], + options={ + 'db_table': 't_customer', + }, + managers=[ + ('all', django.db.models.manager.Manager()), + ], + ), + migrations.CreateModel( + name='CustomerLoss', + fields=[ + ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('cusNo', models.CharField(db_column='cus_no', max_length=40)), + ('cusName', models.CharField(db_column='cus_name', max_length=20)), + ('cusManager', models.CharField(db_column='cus_manager', max_length=20)), + ('lastOrderTime', models.DateTimeField(db_column='last_order_time')), + ('confirmLossTime', models.DateTimeField(db_column='confirm_loss_time')), + ('state', models.IntegerField()), + ('lossReason', models.CharField(db_column='loss_reason', max_length=1000)), + ('isValid', models.IntegerField(db_column='is_valid', default=1)), + ('createDate', models.DateTimeField(auto_now_add=True, db_column='create_date')), + ('updateDate', models.DateTimeField(auto_now_add=True, db_column='update_date')), + ], + options={ + 'db_table': 't_customer_loss', + }, + ), + migrations.CreateModel( + name='CustomerOrders', + fields=[ + ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('orderNo', models.DateTimeField(db_column='order_no')), + ('orderDate', models.DateTimeField(auto_now_add=True, db_column='order_date')), + ('address', models.CharField(db_column='address', max_length=120)), + ('totalPrice', models.FloatField(db_column='total_price')), + ('state', models.IntegerField(choices=[(0, '未回款'), (1, '已回款')])), + ('isValid', models.IntegerField(db_column='is_valid')), + ('createDate', models.DateTimeField(auto_now_add=True, db_column='create_date')), + ('updateDate', models.DateTimeField(auto_now_add=True, db_column='update_date')), + ('customer', models.ForeignKey(db_column='cus_id', on_delete=django.db.models.deletion.DO_NOTHING, to='customer.customer')), + ], + options={ + 'db_table': 't_customer_order', + }, + ), + migrations.CreateModel( + name='LinkMan', + fields=[ + ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('cusId', models.IntegerField(db_column='cus_id')), + ('linkName', models.CharField(db_column='link_name', max_length=20)), + ('sex', models.CharField(max_length=4)), + ('zhiwei', models.CharField(db_column='zhiwei', max_length=20)), + ('officePhone', models.CharField(db_column='office_phone', max_length=20)), + ('phone', models.CharField(db_column='phone', max_length=20)), + ('isValid', models.IntegerField(db_column='is_valid', default=1)), + ('createDate', models.DateTimeField(auto_now_add=True, db_column='create_date')), + ('updateDate', models.DateTimeField(auto_now_add=True, db_column='update_date')), + ], + options={ + 'db_table': 't_customer_linkman', + }, + ), + migrations.CreateModel( + name='OrdersDetail', + fields=[ + ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('goodsName', models.CharField(db_column='goods_name', max_length=100)), + ('goodsNum', models.IntegerField(db_column='goods_num')), + ('unit', models.CharField(db_column='unit', max_length=10)), + ('price', models.FloatField(db_column='price')), + ('sum', models.FloatField(db_column='sum')), + ('isValid', models.IntegerField(db_column='is_valid')), + ('createDate', models.DateTimeField(auto_now_add=True, db_column='create_date')), + ('updateDate', models.DateTimeField(auto_now_add=True, db_column='update_date')), + ('order', models.ForeignKey(db_column='order_id', on_delete=django.db.models.deletion.DO_NOTHING, to='customer.customerorders')), + ], + options={ + 'db_table': 't_order_details', + }, + ), + migrations.CreateModel( + name='CustomerReprieve', + fields=[ + ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('measure', models.CharField(db_column='measure', max_length=1000)), + ('isValid', models.IntegerField(db_column='is_valid', default=1)), + ('createDate', models.DateTimeField(auto_now_add=True, db_column='create_date')), + ('updateDate', models.DateTimeField(auto_now_add=True, db_column='update_date')), + ('customerLoss', models.ForeignKey(db_column='loss_id', db_constraint=False, on_delete=django.db.models.deletion.DO_NOTHING, to='customer.customerloss')), + ], + options={ + 'db_table': 't_customer_reprieve', + }, + ), + ] diff --git a/customer/migrations/__init__.py b/customer/migrations/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/customer/migrations/__pycache__/0001_initial.cpython-312.pyc b/customer/migrations/__pycache__/0001_initial.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..65c75dadc5a6a8ee71bb3a5dd0eaa84b29cd8229 GIT binary patch literal 7777 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 t49PQ~LSDG++F6$U+R3ot&zR27n9y_Qh>dlA z%8GGGEzT~&ryk0@&FAkgB{FKt1RJ$Tppy`Z2Tnu7-WM*V!EMf+-06zLI0{{R3 literal 0 HcmV?d00001 diff --git a/customer/migrations/__pycache__/__init__.cpython-39.pyc b/customer/migrations/__pycache__/__init__.cpython-39.pyc new file mode 100644 index 0000000000000000000000000000000000000000..b0ea99f04bf1a783a9f8c1be811244d1ca794863 GIT binary patch literal 172 zcmYe~<>g`kg2d&vX(0MBh(HF6K#l_t7qb9~6oz01O-8?!3`HPe1o11-*(xTqIJKxa z#?Z*p&>+SozdSD|KQW~^#w9B;FFilrImkCYxU#q;HCHz`5l9uqB$pPK-0Pb>fc literal 0 HcmV?d00001 diff --git a/customer/models.py b/customer/models.py new file mode 100644 index 0000000..4901c31 --- /dev/null +++ b/customer/models.py @@ -0,0 +1,171 @@ +from django.db import models + + +class ModelManager(models.Manager): + def get_queryset(self): + return super(ModelManager, self).get_queryset().filter(isValid=1) + + +class Customer(models.Model): + # 主键 + id = models.AutoField(primary_key=True) + # 客户编号 KH + 日期 + khno = models.CharField(max_length=20, unique=True) + # 客户名称 + name = models.CharField(max_length=20) + # 客户所在地区 + area = models.CharField(max_length=20) + # 客户经理 + cusManager = models.CharField(max_length=30, db_column='cus_manager') + # 客户等级 + level = models.CharField(max_length=30) + # 满意度 + myd = models.CharField(max_length=30) + # 信用度 + xyd = models.CharField(max_length=30) + # 地址 + address = models.CharField(max_length=100) + # 邮编 + postCode = models.CharField(max_length=10, db_column='post_code') + # 联系电话 + phone = models.CharField(max_length=18) + # 传真 + fax = models.CharField(max_length=20) + # 网址 + website = models.CharField(max_length=50, db_column='web_site') + # 营业注册号 + yyzzzch = models.CharField(max_length=50) + # 法人 + fr = models.CharField(max_length=20) + # 注册资金 + zczj = models.CharField(max_length=20) + # 年营业额 + nyye = models.CharField(max_length=20) + # 开户银行 + khyh = models.CharField(max_length=20) + # 开户账号 + khzh = models.CharField(max_length=20) + # 地税 + dsdjh = models.CharField(max_length=20) + # 国税 + gsdjh = models.CharField(max_length=20) + # 状态0=正常 1=暂时流失 2=真正流失 + state = models.IntegerField(default=0) + isValid = models.IntegerField(db_column='is_valid', default=1) + createDate = models.DateTimeField(db_column='create_date', auto_now_add=True) + updateDate = models.DateTimeField(db_column='update_date', auto_now_add=True) + all = models.Manager() + objects = ModelManager() + + class Meta: + db_table = 't_customer' + + +# 客户联系人 +class LinkMan(models.Model): + # 客户id,外键 + cusId = models.IntegerField(db_column='cus_id') + linkName = models.CharField(max_length=20, db_column='link_name') + sex = models.CharField(max_length=4) + zhiwei = models.CharField(max_length=20, db_column='zhiwei') + officePhone = models.CharField(max_length=20, db_column='office_phone') + phone = models.CharField(max_length=20, db_column='phone') + isValid = models.IntegerField(db_column='is_valid', default=1) + createDate = models.DateTimeField(db_column='create_date', auto_now_add=True) + updateDate = models.DateTimeField(db_column='update_date', auto_now_add=True) + objects = ModelManager() + + class Meta: + db_table = 't_customer_linkman' + + +# 客户订单 +class CustomerOrders(models.Model): + # 关联的客户 + customer = models.ForeignKey(Customer, db_column='cus_id', + on_delete=models.DO_NOTHING) + # 订单编号 + orderNo = models.DateTimeField(db_column='order_no') + # 下单日期 + orderDate = models.DateTimeField(db_column='order_date', auto_now_add=True) + # 收货地址 + address = models.CharField(max_length=120, db_column='address') + # 订单总金额 + totalPrice = models.FloatField(db_column='total_price') + # 0=未回款 1=已回款 + state_choices = [ + (0, '未回款'), + (1, '已回款') + ] + state = models.IntegerField(choices=state_choices) + isValid = models.IntegerField(db_column='is_valid') + createDate = models.DateTimeField(db_column='create_date', auto_now_add=True) + updateDate = models.DateTimeField(db_column='update_date', auto_now_add=True) + objects = ModelManager() + + class Meta: + db_table = 't_customer_order' + + +# 订单详情表 +class OrdersDetail(models.Model): + # 关联订单 + order = models.ForeignKey(CustomerOrders, db_column='order_id', + on_delete=models.DO_NOTHING) + # 商品名称 + goodsName = models.CharField(max_length=100, db_column='goods_name') + # 商品数量 + goodsNum = models.IntegerField(db_column='goods_num') + # 单位 + unit = models.CharField(max_length=10, db_column='unit') + # 单价 + price = models.FloatField(db_column='price') + # 总价 + sum = models.FloatField(db_column='sum') + isValid = models.IntegerField(db_column='is_valid') + createDate = models.DateTimeField(db_column='create_date', auto_now_add=True) + updateDate = models.DateTimeField(db_column='update_date', auto_now_add=True) + objects = ModelManager() + + class Meta: + db_table = 't_order_details' + + +# 客户流失表 +class CustomerLoss(models.Model): + # 客户编号 + cusNo = models.CharField(max_length=40, db_column='cus_no') + # 客户名称 + cusName = models.CharField(max_length=20, db_column='cus_name') + # 客户经理 + cusManager = models.CharField(max_length=20, db_column='cus_manager') + # 上次下单日期 + lastOrderTime = models.DateTimeField(db_column='last_order_time') + # 确认流失日期 + confirmLossTime = models.DateTimeField(db_column='confirm_loss_time') + # 状态 0=暂缓流失 1=确认流失 + state = models.IntegerField() + # 流失原因 + lossReason = models.CharField(max_length=1000, db_column='loss_reason') + isValid = models.IntegerField(db_column='is_valid', default=1) + createDate = models.DateTimeField(db_column='create_date', auto_now_add=True) + updateDate = models.DateTimeField(db_column='update_date', auto_now_add=True) + objects = ModelManager() + + class Meta: + db_table = 't_customer_loss' + + +# 流失暂缓措施 +class CustomerReprieve(models.Model): + customerLoss = models.ForeignKey(CustomerLoss, db_column='loss_id', + db_constraint=False, on_delete=models.DO_NOTHING) + # 采取措施 + measure = models.CharField(max_length=1000, db_column='measure') + isValid = models.IntegerField(db_column='is_valid', default=1) + createDate = models.DateTimeField(db_column='create_date', auto_now_add=True) + updateDate = models.DateTimeField(db_column='update_date', auto_now_add=True) + objects = ModelManager() + + class Meta: + db_table = 't_customer_reprieve' diff --git a/customer/tests.py b/customer/tests.py new file mode 100644 index 0000000..7ce503c --- /dev/null +++ b/customer/tests.py @@ -0,0 +1,3 @@ +from django.test import TestCase + +# Create your tests here. diff --git a/customer/urls.py b/customer/urls.py new file mode 100644 index 0000000..822db1c --- /dev/null +++ b/customer/urls.py @@ -0,0 +1,35 @@ +from django.contrib import admin +from django.urls import path, include +from . import views + +app_name = 'customer' + +urlpatterns = [ + # 首页 + path('index/', views.customer_index, name='customer_index'), + path('select_customer_list/', views.select_customer_list, name='select_customer_list'), + + path('create_or_update_customer_page/', views.create_or_update_customer_page, name='create_or_update_customer_page'), + path('create_or_update_customer/', views.create_or_update_customer, name='create_or_update_customer'), + + path('delete/', views.delete_customer, name='delete_customer'), + + path('order/index/', views.order_index, name='order_index'), + path('order/list/', views.select_orderlist_by_customerid, name='select_orderlist_by_customerid'), + + path('order/detail/index/', views.order_detail_index, name='order_detail_index'), + path('order/detail/list/', views.select_orderdetail_by_orderid, name='select_orderdetail_by_orderid'), + + path('loss/index/', views.loss_index, name='loss_index'), + path('loss/list/', views.select_loss_list, name='select_loss_list'), + + path('loss/detail/index/', views.loss_detail_index, name='loss_detail_index'), + path('loss/reprieve/list/', views.select_reprieve_by_lossid, name='select_reprieve_by_lossid'), + + path('loss/reprieve/index/', views.reprieve_index, name='reprieve_index'), + path('loss/reprieve/create/', views.create_reprieve, name='create_reprieve'), + path('loss/reprieve/update/', views.update_reprieve, name='update_reprieve'), + path('loss/reprieve/delete/', views.delete_reprieve, name='delete_reprieve'), + + path('loss/confirm/', views.update_lossreason_by_lossid, name='update_lossreason_by_lossid'), +] diff --git a/customer/views.py b/customer/views.py new file mode 100644 index 0000000..07e09df --- /dev/null +++ b/customer/views.py @@ -0,0 +1,456 @@ +from datetime import datetime + +from apscheduler.schedulers.background import BackgroundScheduler +from django.core.paginator import Paginator +from django.db import connection +from django.http import JsonResponse +from django.shortcuts import render +from django.views.decorators.clickjacking import xframe_options_exempt +from django.views.decorators.csrf import csrf_exempt +from django.views.decorators.http import require_GET + +from customer.models import Customer, CustomerOrders, OrdersDetail, CustomerLoss, CustomerReprieve + + +# Create your views here. +@xframe_options_exempt +def customer_index(request): + return render(request, 'customer/customer.html') + + +@require_GET +def select_customer_list(request): + try: + page_num = request.GET.get('page') # 页号 + page_size = request.GET.get('limit') # 页容量 + + users = Customer.objects.filter(isValid=1).values() + paginator = Paginator(users, page_size) + count = paginator.count + users_list = paginator.page(page_num).object_list + + user_response = { + 'code': 0, + 'msg': '', + 'count': count, + 'data': list(users_list) + } + + return JsonResponse(user_response) + + except Exception as e: + return JsonResponse({'code': 400, 'msg': "error"}) + + +@csrf_exempt +@xframe_options_exempt +def create_or_update_customer_page(request): + # 获取需要编辑客户的id并发送,修改客户信息时需要使用 + id = request.GET.get('id') + # 如果查询不到 id 就是添加客户操作,反之就是修改操作 + if id is not None and id != '': + customer = Customer.objects.values().filter(id=id) # 根据id查找数据库客户信息 + return render(request, 'customer/customer_add_update.html', customer[0]) # 修改操作,需要发送id,便于修改时定位客户 + else: + return render(request, 'customer/customer_add_update.html') # 新建操作,无需id + + +def create_or_update_customer(request): + try: # 接收参数 + name = request.GET.get('name') + area = request.GET.get('area') + cusManager = request.GET.get('cusManager') + level = request.GET.get('level') + xyd = request.GET.get('xyd') + postCode = request.GET.get('postCode') + phone = request.GET.get('phone') + fax = request.GET.get('fax') + website = request.GET.get('website') + address = request.GET.get('address') + fr = request.GET.get('fr') + zczj = request.GET.get('zczj') + nyye = request.GET.get('nyye') + khyh = request.GET.get('khyh') + khzh = request.GET.get('khzh') + dsdjh = request.GET.get('dsdjh') + gsdjh = request.GET.get('gsdjh') + + id = request.GET.get('id') + c = None + + # 如果id为空 说明无此用户,故为新建客户操作 + if not id: + # KH + 时间 + khno = 'KH' + datetime.now().strftime('%Y%m%d%H%M%S') + # 添加数据 + Customer.objects.create(khno=khno, name=name, area=area, + cusManager=cusManager, level=level, + xyd=xyd, postCode=postCode, phone=phone, + fax=fax, website=website, + address=address, fr=fr, zczj=zczj, nyye=nyye, + khyh=khyh, + khzh=khzh, dsdjh=dsdjh, gsdjh=gsdjh) + # 如果id有值 说明已经有此用户,故对其进行修改操作 + else: + # 修改数据 + Customer.objects.filter(id=id).update(name=name, area=area, + cusManager=cusManager, level=level, + xyd=xyd, postCode=postCode, + phone=phone, fax=fax, + website=website, + address=address, fr=fr, + zczj=zczj, nyye=nyye, khyh=khyh, + khzh=khzh, dsdjh=dsdjh, + gsdjh=gsdjh, + updateDate=datetime.now()) + # 返回提示信息 + return JsonResponse({'code': 200, 'msg': '保存成功'}) + + except Exception as es: + return JsonResponse({'code': 400, 'msg': '保存失败'}) + + +@csrf_exempt +@require_GET +def delete_customer(request): + """根据主键删除客户信息""" + try: + # 接收参数 + id = request.GET.get('id') + # 逻辑删除 + # Customer.objects.filter(pk=id).update(isValid=0, updateDate=datetime.now()) + Customer.objects.get(pk=id).delete() + return JsonResponse({'code': 200, 'msg': '删除成功'}) + except Exception as e: + return JsonResponse({'code': 400, 'msg': '删除失败'}) + + +@xframe_options_exempt +@require_GET +def order_index(request): + """跳转订单查看页面""" + # 接收参数 + id = request.GET.get('id') + # 查询客户信息 + customer = Customer.objects.get(pk=id) + context = { + 'id': id, + 'khno': customer.khno, + 'name': customer.name, + 'fr': customer.fr, + 'address': customer.address, + 'phone': customer.phone + } + return render(request, 'customer/customer_order.html', context) + + +@xframe_options_exempt +@require_GET +def select_orderlist_by_customerid(request): + """根据客户主键查询订单""" + try: + # 获取第几页 + page_num = request.GET.get('page') + # 获取每页多少条 + page_size = request.GET.get('limit') + # 获取客户主键 + id = request.GET.get('id') + # 查询订单列表 + order_list = CustomerOrders.objects.values().filter(customer=id) + # 初始化分页对象 + p = Paginator(order_list, page_size) + # 获取指定页数的数据 + data = p.page(page_num).object_list + # 返回总条数 + count = p.count + # 返回数据,按照 layuimini 要求格式构建 + context = { + 'code': 0, + 'msg': '', + 'count': count, + 'data': list(data) + } + return JsonResponse(context) + except Exception as e: + return JsonResponse({'code': 400, 'msg': 'error'}) + + +@xframe_options_exempt +@require_GET +def order_detail_index(request): + """跳转订单详情页面""" + # 接收参数 + id = request.GET.get('id') + # 查询订单信息 + o = CustomerOrders.objects.get(pk=id) + context = { + 'id': id, + 'orderNo': o.orderNo, + 'totalPrice': o.totalPrice, + 'address': o.address, + 'state': o.get_state_display() + } + return render(request, 'customer/customer_order_detail.html', context) + + +@require_GET +def select_orderdetail_by_orderid(request): + """根据订单主题查询订单详情""" + try: + # 获取第几页 + page_num = request.GET.get('page') + # 获取每页多少条 + page_size = request.GET.get('limit') + # 获取订单主键 + id = request.GET.get('id') + # 查询订单详情 + orderdetail_list = OrdersDetail.objects.values().filter(order=id) + # 初始化分页对象 + p = Paginator(orderdetail_list, page_size) + # 获取指定页数的数据 + data = p.page(page_num).object_list + # 返回总条数 + count = p.count + # 返回数据,按照 layuimini 要求格式构建 + context = { + 'code': 0, + 'msg': '', + 'count': count, + 'data': list(data) + } + return JsonResponse(context) + except Exception as e: + return JsonResponse({'code': 400, 'msg': 'error'}) + + +# def create_customer_loss(): +# """添加暂缓流失客户""" +# try: +# # 创建游标对象 +# cursor = connection.cursor() +# # 编写 SQL +# sql = ''' +# SELECT +# c.id id, +# c.khno cusNo, +# c.NAME cusName,c.cus_manager cusManager, +# max( co.order_date ) lastOrderTime +# FROM +# t_customer c +# LEFT JOIN t_customer_order co ON c.id = co.cus_id +# WHERE +# c.is_valid = 1 +# AND c.state = 0 +# AND NOW() > DATE_ADD( c.create_date, INTERVAL 6 MONTH ) +# AND NOT EXISTS ( +# SELECT DISTINCT +# o.cus_id +# FROM +# t_customer_order o +# WHERE +# o.is_valid = 1 +# AND NOW() < DATE_ADD( o.order_date, INTERVAL 6 MONTH ) +# AND c.id = o.cus_id +# ) +# GROUP BY +# c.id; +# ''' +# # 执行sql +# cursor.execute(sql) +# # 返回多条结果行 +# customer_loss_tuple = cursor.fetchall() # 查询当前sql执行后所有的记录,返回元组 +# # 关闭游标 +# cursor.close() +# # 将元组转为列表 +# customer_loss_id = [] # 暂缓流失客户 id 列表 +# customer_loss_list = [] # 暂缓流失客户列表 +# for cl in customer_loss_tuple: +# customer_loss_id.append(cl[0]) +# customer_loss_list.append(CustomerLoss(cusNo=cl[1], +# cusName=cl[2], +# cusManager=cl[3], +# lastOrderTime=cl[4], +# state=0)) # 暂缓流失 +# # 批量插入客户流失表 +# CustomerLoss.objects.bulk_create(customer_loss_list) +# # 修改这些数据客户表中的状态为 1 暂时流失 +# Customer.objects.filter(id__in=customer_loss_id).update(state=1, +# updateDate=datetime.now()) +# except Exception as e: +# print(e) +# finally: +# connection.close() +# +# +# scheduler = BackgroundScheduler() # 创建一个调度器对象 +# scheduler.add_job(create_customer_loss, 'interval', minutes=1) # 创建一个任务 +# scheduler.start() # 启动任务 +@xframe_options_exempt +@require_GET +def loss_index(request): + return render(request, 'customer/customer_loss.html') + + +@require_GET +def select_loss_list(request): + try: + # 获取第几页 + page_num = request.GET.get('page') + # 获取每页多少条 + page_size = request.GET.get('limit') + # 获取客户编号 + cusNo = request.GET.get('cusNo') + # 获取客户名称 + cusName = request.GET.get('cusName') + # 获取客户状态 + state = request.GET.get('state') + # 查询所有 + loss_list = CustomerLoss.objects.values().all().order_by('-lastOrderTime') + # 如果有条件参数,带条件查询 + if cusNo: + loss_list = loss_list.filter(cusNo__icontains=cusNo) + if cusName: + loss_list = loss_list.filter(cusName__icontains=cusName) + if state: + loss_list = loss_list.filter(state=state) + # 初始化分页对象 + p = Paginator(loss_list, page_size) + # 获取指定页数的数据 + data = p.page(page_num).object_list + # 返回总条数 + count = p.count + # 返回数据,按照 layuimini 要求格式构建 + context = { + 'code': 0, + 'msg': '', + 'count': count, + 'data': list(data) + } + return JsonResponse(context) + except Exception as e: + return JsonResponse({'code': 400, 'msg': 'error'}) + + +@xframe_options_exempt +@require_GET +def loss_detail_index(request): + try: + # 获取客户流失主键 + id = request.GET.get('id') + # 查询客户流失信息 + cl = CustomerLoss.objects.get(pk=id) + context = {'cl': cl} + return render(request, 'customer/customer_reprieve.html', context) + except CustomerLoss.DoesNotExist as e: + pass + + +@require_GET +def select_reprieve_by_lossid(request): + """根据客户流失主键查询流失措施""" + try: + page_num = request.GET.get('page') + page_size = request.GET.get('limit') + id = request.GET.get('id') + + cp_list = CustomerReprieve.objects.values().filter(customerLoss=id).order_by('-id') + + p = Paginator(cp_list, page_size) + + data = p.page(page_num).object_list + + count = p.count + + context = {'code': 0, 'msg': '', 'count': count, 'data': list(data)} + + return JsonResponse(context) + + except Exception as e: + + return JsonResponse({'code': 400, 'msg': 'error'}) + + +@xframe_options_exempt +@require_GET +def reprieve_index(request): + """添加客户暂缓页面""" + lossId = request.GET.get('lossId') + context = {'lossId': lossId} + + id = request.GET.get('id') + + if id: + cp = CustomerReprieve.objects.get(pk=id) + context['id'] = id + context['cp'] = cp + return render(request, 'customer/customer_reprieve_add_update.html', context) + + +@csrf_exempt +@require_GET +def create_reprieve(request): + """添加客户暂缓""" + # 获取客户流失主键 + lossId = request.GET.get('lossId') + # 获取客户暂缓措施 + measure = request.GET.get('measure') + # 查询流失客户数据 + cl = CustomerLoss.objects.get(pk=lossId) + data = { + 'customerLoss': cl, + 'measure': measure + } + # 添加 + CustomerReprieve.objects.create(**data) + return JsonResponse({'code': 200, 'msg': '添加成功'}) + + +@csrf_exempt +@require_GET +def update_reprieve(request): + """修改客户暂缓""" + # 获取客户暂缓主键 + id = request.GET.get('id') + # 获取客户暂缓措施 + measure = request.GET.get('measure') + data = { + 'measure': measure, + 'updateDate': datetime.now() + } + # 修改 + CustomerReprieve.objects.filter(pk=id).update(**data) + return JsonResponse({'code': 200, 'msg': '修改成功'}) + + +@csrf_exempt +@require_GET +def delete_reprieve(request): + """删除客户暂缓""" + # 获取客户暂缓主键 + id = request.GET.get('id') + # 逻辑删除 + CustomerReprieve.objects.filter(pk=id).update(isValid=0, + updateDate=datetime.now()) + return JsonResponse({'code': 200, 'msg': '删除成功'}) + + +@csrf_exempt +@require_GET +def update_lossreason_by_lossid(request): + """确认流失""" + # 获取客户流失主键 + lossId = request.GET.get('lossId') + # 获取流失原因 + lossReason = request.GET.get('lossReason') + # 根据客户流失主键查询 + cl = CustomerLoss.objects.get(pk=lossId) + # 重新赋值 + cl.lossReason = lossReason + cl.state = 1 + cl.confirmLossTime = datetime.now() + # 保存 + cl.save() + # 修改客户表状态 + Customer.objects.filter(khno=cl.cusNo).update(state=2, + updateDate=datetime.now()) + return JsonResponse({'code': 200, 'msg': '保存成功'}) diff --git a/report/__init__.py b/report/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/report/__pycache__/__init__.cpython-312.pyc b/report/__pycache__/__init__.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..c7d0059fd6e54fa8ebcb7a3deea894fdf2a4cfd9 GIT binary patch literal 161 zcmX@j%ge<81SjV8rGV(iAOanHW&w&!XQ*V*Wb|9fP{ah}eFmxd<=|`;6Iz^FR2-9$ zl@;TXTAW>yUl8Mxm6(^FAMYIG8y{R*T#}lro0|xvieidV3-XIfV&da7^D;}~g`kf)n%lQb6=$5P=LBfgA@QE@lA|DGb33nv8xc8Hzx{2;!HEvsFxJacWU< zjG>XGp+SsGetBL_equ^-j7wHxUV47KbC7R*aAk2xYOZc>B9JPIDM~HKFDi+NkI&4@ bEQycTE2zB1VUwGmQks)$2QvLL5HkP(un{LQ literal 0 HcmV?d00001 diff --git a/report/__pycache__/admin.cpython-312.pyc b/report/__pycache__/admin.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..ed503c9db0340a915af80f9505dec6a2281bc1d1 GIT binary patch literal 205 zcmX@j%ge<81SjV8rPu@M#~=<2FhLog1%Qm{3@HpLj5!Rsj8Tk?43$ip%r8OGnvAzt z6H{_C^ZYcKZtm}#sl@w(r6)^)9tYr8MQuoW&*(xTqIJKxaCL=2=#wE2l zyClCL#s#b)-Z{uOKDe^DBsEtzHxWn`#T2C$g`kf)n%lQtW~BV-N=!FabFZKwK;UBvKes7;_kM8KW2(8B&;n88n$+0!0}# z8E>&BrsQVk`Drpm@ug%X=B4NBCFkdr6lEqAfecv5P{a(Rz{D>{XRDad;?$zz7(*jV zLxUKX{PMh<{KS;v7#Fb4c;_JB_~6RolGI$?+(aN%6jPL1kY7|11GYo2pz;=nO>TZl PX-=vgBhb{(K+FIDDC{zO literal 0 HcmV?d00001 diff --git a/report/__pycache__/apps.cpython-312.pyc b/report/__pycache__/apps.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..4fbab9cd6308f79569c957c10da63bd16c6beee1 GIT binary patch literal 467 zcmXv~ze~eF6n>YaQu{+hi{RkkB4jYLN)c*{PIjocguron*V>vi@h%zSCUll=-Q2~0 zL~wB|0VgLnp}KVP?h@bd-uK=6aqoR^^?C)Qy*@qCsf?eB{9CC2i#-WuK!GA30^}kD z2AlykCO}PwUd+7CHB!qieJNt2Y_%0d?Qq;54zBZb?omM&4GCtzz(o{XgCf_YhHIs! zZDq9{i$Wgf-S<0mM8<>Ap;t~2QsxWiWH@LgadxP1PtS>g0ZYk ze1&Tm-zCH^G8>fjN#e(t$O*WwM_4NN3=6f|ve`cJE(PPlyBUqV4imR=7{)y$QM qd3#MEUAQLEvfRv1Ip*twK|V-uue7P)vrXb{~x-2?c_$X~G~#LSV=ey539{+LR5$ z^8q}Fe5qr&i!%*U+4yp`995;hT1f?N$JF3y)N*akbCF5TU59hTR?5dc&L1nGHl00? z3sI?(3uNGnnj-YQPh$KnYV$iBpQX1}8k-JIP6x;7L_g(93$W>=UWSinH+;UfrOb{p zfzG7O8mTA>8y9QCkjr1sdef#Mtt-=rx$fpa9%%wU(qsRJH&GXBu6^G8;=*6edTfvV E0k7?CnE(I) literal 0 HcmV?d00001 diff --git a/report/__pycache__/models.cpython-312.pyc b/report/__pycache__/models.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..5da762566d2a02d6cfe56a2ffd24e1eee088af00 GIT binary patch literal 202 zcmX@j%ge<81SjV8rC0*##~=<2FhLog1%Qm{3@HpLj5!Rsj8Tk?43$ip%r8OGnvA#D za`RJCbBg^mnQn2WWF_XM=j){;6)^)PS2BDCsrhB+Y!wq)oLW>IlaZAbg`kf)n%lQY?Y=V-N=!FabFZKwK;UBvKes7;_kM8KW2(8B&;n88n$+0!0}# z8E>)W=BK3Q6#Hp1-QrBiO3X{o*Gow%0%=~!P{abHz{D>nXRDad;?$zz7(*jVLxUKX z{PMh<{KS;v7#Fanc;_JB_~6RolGI$?+(aN%6jPL1kY7|112JE(pz;=n4Uk=$lWNBZ KH1;zPGXMahaxuRE literal 0 HcmV?d00001 diff --git a/report/__pycache__/urls.cpython-312.pyc b/report/__pycache__/urls.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..5b1469f01914dc885d9801e507d9cb8e1c5e0178 GIT binary patch literal 859 zcmZvZ&ubGw6vtYgG5JhUprA1L}4~mzt5Z3I_Zo0pinN+iQ z(3@VQH+vF~75xMJ69g|=2m}`jil^Qxz4heGCTS&P4sYiB-sjDGy!RuU%>a77e|&F= zDFFU3F*!+uii<@KfDga|7Uuw$YjPa0QWo!|T)xTEx6l+)0CJWH`OYL~@&~;w>FeAV ze&k3vnR4oX!1!sUr??E|=4Wuq6sJ-yKZDCoar2Zb%;0iUT%K}^Gq{CoZcl0|y+TDh zV_1cYg}@~HXLL+Vh=(?Ofny25z(*u3)-gew1iFD^64=mf&w?-YSRI91iDX}RrVB%* z?Rx~-&$|Tb@dAbpY?IctFI3yU8~E5Jw(se2;R?8Nh7yM8kS43+SRzBk@iCs1&M+}5 z942qwu`$u({5T~EGuLiKjTNh7dVBtQ7daTQHO2sm?2^qOXtAcz9F-`|3|l`^m|+V> zS!!a1X43Hxh&=omTu>LdtZ!`^&uC}Z*za_VZHNzu9~j$7rPkJyoz~MHrW32WCcTg` z8kNCXSPy!aa^3Zijbm|G(xZ~zzw>bHx_Mk2E^kE38~wYF2f_}cN=LVcS~=3nC%XgT-tS4? lT2xv)c{LE~j9EGA4wtIYQng>ZKM)?A=j2@Kje<1V%|CVU+VTJZ literal 0 HcmV?d00001 diff --git a/report/__pycache__/urls.cpython-39.pyc b/report/__pycache__/urls.cpython-39.pyc new file mode 100644 index 0000000000000000000000000000000000000000..f82a6bc48845bea5622f8a07df4c3e3b34e8a0c7 GIT binary patch literal 587 zcmYk3O-{ow5QXg|4QZ1CE#eSe&;UCSs*qp{3lN(sQWQE?33B4dcA?E3;0Wxw31{$@ z6-R&-<23v@%Co+R(kIu0T47XB~mp5m*PC_sR6QqU=-1RQX=Q@B$X z&)(Ey6gtek?|=^*PcBk`cUn_+ekeaSepCO5Qf)ewDW=0 z$%q=S%Jkg_T|?&~XOGJGl2t;%v#>5)H|Ln= zO2=lqO=)Z!x*SC&g!`4)&9C@mO+^flAJslIhviMS8tbIJ&(e!%ZgZnI*QD dakVnRNg-gt*~Cs>4N)Q*Ii9;oo5w-@{07sfsT2SJ literal 0 HcmV?d00001 diff --git a/report/__pycache__/views.cpython-312.pyc b/report/__pycache__/views.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..5b61cf2cfeccbc1c2dfebe0617f53163477b8896 GIT binary patch literal 4077 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 literal 0 HcmV?d00001 diff --git a/report/__pycache__/views.cpython-39.pyc b/report/__pycache__/views.cpython-39.pyc new file mode 100644 index 0000000000000000000000000000000000000000..4731e206c08eb4f5625e02975395940ab45e15af GIT binary patch literal 2525 zcmZ`)OK%*<5uWaO?CkFBgQQ5ymSZG=jCf&*mSi7d$1xI6b^rqw3{i=a0fE72yG6}v z9_#L2nk068p%1bWCPD!DBuHEXHmpPF7;umvx&=Ap=yP8KQsh4f0$FlZ?~*2EXa-YL z{Z+r}>#FLwR;yU>{O9%`+1EA8`Y$#PJ`OZ~0iXOg2xc*oS{VrmL7k>FvqRhHcIsqq z=w@E%Wu>r``Jtbc!?LkCX(g+MRihsq@1{Xk3u^}V(t6ei8%8gs&1@o^FuI>kW>evm z(aY(PY&x9IX2Ka_@fvTi3afr-t&uenJ_W6S)vy&F1-;H1Mt>UgCYvz&Gi-9+YEA8e zC)Qn}J;8IvMT_Y2yYXU@$Epx5SKITwOuKVMFIU=`izV02#Vb75?r-9>$Dw!dwk-1V zTy~3GVtab|vWPPt6>wFLJ7CarP96v2hv#a zyOx*&+y8$#_u9g*B^Pqx^qE&rpISIuyq~8<%;dt^PMj|m(cJlWqWKjG<4$HV{KUd& ziG`(vzb|LID>@hfBM+M}sWd)S#5Cw_0%Gr}f`Tz={5uYo)&KRaj1mH&i-!%9nn;zpw0G|Q;Uk0CMPvJVM+_(F5 zjSjrNw^8YnA?Z{HrM}k*2DsMIzOQP1-1pPBoIzRD`{gxq(VB;2R*f5EbKzad)k#F1AZfsq@({i-aE*RH#CKt8a9wjS_ReY}1)HdXswime)P|+-1 zDlT;(ouu}bFoUJ`<2)}E#J6zK?i+`rODo#DoWQ<>!1NL`XseFKMwo@-Cx|#kH5``T zTyArd^sTCxFjFDfQ4TDXjV6;-9@h2<8_n_qocuZLO}gR*Y?ygV$RA%;nsAeJBXI=# zO^oXS_7KUXp5i!%d;^4K({i2GNu79)JW3xrZa^Fo(17@)dEg6Zg$C5KDZ$r!;CU6W zi=V;_hm!A5ahV0HvN~jgG7MQ;ISfiIqmW!KA_Jm4Rq7)K$+(Wi$L$@3K?lQd`}T)$ zX4^Oay1l*$5y+Q#3i0H{8J^i&cZqgne3`d=b5`O-7%fhqIElhTf!h#BxHt`>MGe*B zRRpj)9Uy9QpQx-`$OOyryU;^o_*iy;91;4+q2lMz{+{1HfTrjyfO6PxSd>vbnR@M-ojp!|Fecv^e+yGc3|^$Y3E^3PNU8UY=g)>oJVz{DXE-+uSChW_l&My literal 0 HcmV?d00001 diff --git a/report/admin.py b/report/admin.py new file mode 100644 index 0000000..8c38f3f --- /dev/null +++ b/report/admin.py @@ -0,0 +1,3 @@ +from django.contrib import admin + +# Register your models here. diff --git a/report/apps.py b/report/apps.py new file mode 100644 index 0000000..1ed8809 --- /dev/null +++ b/report/apps.py @@ -0,0 +1,6 @@ +from django.apps import AppConfig + + +class ReportConfig(AppConfig): + default_auto_field = 'django.db.models.BigAutoField' + name = 'report' diff --git a/report/migrations/__init__.py b/report/migrations/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/report/migrations/__pycache__/__init__.cpython-312.pyc b/report/migrations/__pycache__/__init__.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..7625b3fa888cba5be995f42dcad3c9827144804d GIT binary patch literal 172 zcmX@j%ge<81WC(n(?IlN5P=Rpvj9b=GgLBYGWxA#C}INgK7-W!@^-e02`x@7Dvrs> z%8GGGEzT~g`kg2d&vX(0MBh(HF6K#l_t7qb9~6oz01O-8?!3`HPe1o6w?*(xTqIJKxa z#?Z*p&>+SozdSD|KQW~^#w9B;FFilrImkCYxU#q;HCHz`5l9uq6r~pA7nQ{1W~LV< lmSpDV701NKXXa&=#K-FuRNmsS$<0qG%}KQbS@ao*82~r`D<}W} literal 0 HcmV?d00001 diff --git a/report/models.py b/report/models.py new file mode 100644 index 0000000..71a8362 --- /dev/null +++ b/report/models.py @@ -0,0 +1,3 @@ +from django.db import models + +# Create your models here. diff --git a/report/tests.py b/report/tests.py new file mode 100644 index 0000000..7ce503c --- /dev/null +++ b/report/tests.py @@ -0,0 +1,3 @@ +from django.test import TestCase + +# Create your tests here. diff --git a/report/urls.py b/report/urls.py new file mode 100644 index 0000000..543d71e --- /dev/null +++ b/report/urls.py @@ -0,0 +1,14 @@ +from django.urls import path +from . import views + +app_name = 'report' + +urlpatterns = [ + path('/index/', views.report_index, name='report_index'), + path('contribute/', views.select_contribute, name='select_contribute'), + path('composition/', views.select_composition, name='select_composition'), + path('serve/', views.select_serve, name='select_serve'), + + path('loss/index/', views.loss_index, name='loss_index'), + path('loss/list/', views.select_loss_list, name='select_loss_list'), +] diff --git a/report/views.py b/report/views.py new file mode 100644 index 0000000..b317184 --- /dev/null +++ b/report/views.py @@ -0,0 +1,99 @@ +from django.shortcuts import render +from django.core.paginator import Paginator +from django.db.models import Sum, Count, Case, When, Value +from django.http import JsonResponse +from django.shortcuts import render +from django.views.decorators.clickjacking import xframe_options_exempt +from django.views.decorators.http import require_GET +from customer.models import Customer +from serve.models import CustomerServe + +from customer.views import loss_index, select_loss_list + + +# Create your views here. + +@xframe_options_exempt +@require_GET +def report_index(request, template): + """统计报表子菜单首页""" + ''' + contribute 客户贡献分析首页 + composition 客户构成分析首页 + serve 客户服务分析首页 + loss 客户流失分析首页 + ''' + return render(request, 'report/%s.html' % template) + + +@require_GET +def select_contribute(request): + """查询客户贡献""" + try: + + # """ + # SELECT c.id, c.name, sum(od.sum) sum FROM t_customer c + # LEFT JOIN t_customer_order co ON c.id = co.cus_id + # LEFT JOIN t_order_details od ON co.id = od.order_id + # WHERE c.is_valid = 1 AND c.id = 1 GROUP BY c.id, c.name; + # """ + # 获取第几页 + page_num = request.GET.get('page', 1) # 添加默认值,防止没有参数导致的异常错误 + # 获取每页多少条 + page_size = request.GET.get('limit', 10) # 添加默认值,防止没有参数导致的异常错误 + customer_list = Customer.objects.values('id', 'name') \ + .annotate(sum=Sum('customerorders__ordersdetail__sum')) \ + .order_by('-sum') + # 按条件查询 + # 客户名称 + customerName = request.GET.get('customerName') + if customerName: + customer_list = customer_list.filter(name__icontains=customerName) + # 金额区间 + type = request.GET.get('type') + if type == '1': + customer_list = customer_list.filter(sum__gte=0, sum__lte=1000) + elif type == '2': + customer_list = customer_list.filter(sum__gt=1000, sum__lte=3000) + elif type == '3': + customer_list = customer_list.filter(sum__gt=3000, sum__lte=5000) + elif type == '4': + customer_list = customer_list.filter(sum__gt=5000) + # 初始化分页对象 + p = Paginator(customer_list, page_size) + # 获取指定页数的数据 + data = p.page(page_num).object_list + # 返回总条数 + count = p.count + # 返回数据,按照 layuimini 要求格式构建 + context = { + 'code': 0, + 'msg': '查询成功', + 'count': count, + 'data': list(data) + } + return JsonResponse(context) + except Exception as e: + pass + + +@require_GET +def select_composition(request): + """查询客户构成数据""" + level = Customer.objects.values('level') \ + .annotate(amount=Count('level')).order_by('level') + return JsonResponse(list(level), safe=False) + + +@require_GET +def select_serve(request): + """查询客户服务类型数据""" + serve = CustomerServe.objects.values('serveType') \ + .annotate(type=Case(When(serveType=6, then=Value("咨询")), + When(serveType=7, then=Value("建议")), + When(serveType=8, then=Value("投诉"))), amount=Count('serveType')) \ + .order_by('serveType') + return JsonResponse(list(serve), safe=False) + + +